1
1
import React from 'react' ;
2
2
import ReactDOM from 'react-dom' ;
3
3
import PropTypes from 'prop-types' ;
4
- import { CompositeDisposable } from 'event-kit' ;
4
+ import { Disposable } from 'event-kit' ;
5
5
6
- import { createItem } from '../helpers' ;
6
+ import { createItem , autobind } from '../helpers' ;
7
7
import { RefHolderPropType } from '../prop-types' ;
8
+ import { TextEditorContext } from './atom-text-editor' ;
9
+ import { MarkerContext } from './marker' ;
10
+ import RefHolder from '../models/ref-holder' ;
8
11
9
- export default class Decoration extends React . Component {
12
+ class WrappedDecoration extends React . Component {
10
13
static propTypes = {
11
- editor : PropTypes . object . isRequired ,
12
- marker : PropTypes . object . isRequired ,
14
+ editorHolder : RefHolderPropType . isRequired ,
15
+ markerHolder : RefHolderPropType . isRequired ,
13
16
type : PropTypes . oneOf ( [ 'line' , 'line-number' , 'highlight' , 'overlay' , 'gutter' , 'block' ] ) . isRequired ,
14
17
position : PropTypes . oneOf ( [ 'head' , 'tail' , 'before' , 'after' ] ) ,
15
18
className : PropTypes . string ,
@@ -26,10 +29,14 @@ export default class Decoration extends React.Component {
26
29
constructor ( props , context ) {
27
30
super ( props , context ) ;
28
31
29
- this . decoration = null ;
30
- this . subscriptions = new CompositeDisposable ( ) ;
32
+ autobind ( this , 'observeParents' ) ;
33
+
34
+ this . decorationHolder = new RefHolder ( ) ;
35
+ this . editorSub = new Disposable ( ) ;
36
+ this . markerSub = new Disposable ( ) ;
31
37
32
38
this . domNode = null ;
39
+ this . item = null ;
33
40
if ( [ 'gutter' , 'overlay' , 'block' ] . includes ( this . props . type ) ) {
34
41
this . domNode = document . createElement ( 'div' ) ;
35
42
this . domNode . className = 'react-atom-decoration' ;
@@ -41,40 +48,20 @@ export default class Decoration extends React.Component {
41
48
}
42
49
43
50
componentDidMount ( ) {
44
- this . setupDecoration ( ) ;
51
+ this . editorSub = this . props . editorHolder . observe ( this . observeParents ) ;
52
+ this . markerSub = this . props . markerHolder . observe ( this . observeParents ) ;
45
53
}
46
54
47
- shouldComponentUpdate ( nextProps ) {
48
- if (
49
- this . props . editor !== nextProps . editor ||
50
- this . props . marker !== nextProps . marker ||
51
- this . props . type !== nextProps . type ||
52
- this . props . position !== nextProps . position ||
53
- this . props . className !== nextProps . className ||
54
- this . props . children !== nextProps . children
55
- ) { return true ; }
56
-
57
- // Compare additional options.
58
- const optionKeys = Object . keys ( this . props . options ) ;
59
- const nextOptionKeys = Object . keys ( nextProps . options ) ;
60
-
61
- if ( optionKeys . length !== nextOptionKeys . length ) {
62
- return true ;
63
- } else {
64
- for ( let i = 0 ; i < optionKeys . length ; i ++ ) {
65
- const key = optionKeys [ i ] ;
66
- if ( this . props . options [ key ] !== nextProps . options [ key ] ) {
67
- return true ;
68
- }
69
- }
55
+ componentDidUpdate ( prevProps ) {
56
+ if ( this . props . editorHolder !== prevProps . editorHolder ) {
57
+ this . editorSub . dispose ( ) ;
58
+ this . editorSub = this . state . editorHolder . observe ( this . observeParents ) ;
70
59
}
71
60
72
- return false ;
73
- }
74
-
75
- componentDidUpdate ( ) {
76
- this . decoration && this . decoration . destroy ( ) ;
77
- this . setupDecoration ( ) ;
61
+ if ( this . props . markerHolder !== prevProps . markerHolder ) {
62
+ this . markerSub . dispose ( ) ;
63
+ this . markerSub = this . state . markerHolder . observe ( this . observeParents ) ;
64
+ }
78
65
}
79
66
80
67
render ( ) {
@@ -88,33 +75,98 @@ export default class Decoration extends React.Component {
88
75
}
89
76
}
90
77
91
- setupDecoration ( ) {
92
- if ( this . decoration ) {
78
+ observeParents ( ) {
79
+ if ( this . props . editorHolder . isEmpty ( ) || this . props . markerHolder . isEmpty ( ) ) {
93
80
return ;
94
81
}
95
82
96
- let item = null ;
97
- if ( this . usesItem ( ) ) {
98
- item = createItem ( this . domNode , this . props . itemHolder ) ;
83
+ this . createDecoration ( ) ;
84
+ }
85
+
86
+ createDecoration ( ) {
87
+ this . decorationHolder . map ( decoration => decoration . destroy ( ) ) ;
88
+
89
+ if ( ! this . item ) {
90
+ this . item = createItem ( this . domNode , this . props . itemHolder ) ;
99
91
}
100
92
101
93
const options = {
102
94
...this . props . options ,
103
95
type : this . props . type ,
104
96
position : this . props . position ,
105
97
class : this . props . className ,
106
- item,
98
+ item : this . item ,
107
99
} ;
108
100
109
- this . decoration = this . props . editor . decorateMarker ( this . props . marker , options ) ;
110
- this . subscriptions . add ( this . decoration . onDidDestroy ( ( ) => {
111
- this . decoration = null ;
112
- this . subscriptions . dispose ( ) ;
113
- } ) ) ;
101
+ const editor = this . props . editorHolder . get ( ) ;
102
+ const marker = this . props . markerHolder . get ( ) ;
103
+
104
+ this . decorationHolder . setter (
105
+ editor . decorateMarker ( marker , options ) ,
106
+ ) ;
114
107
}
115
108
116
109
componentWillUnmount ( ) {
117
- this . decoration && this . decoration . destroy ( ) ;
118
- this . subscriptions . dispose ( ) ;
110
+ this . decorationHolder . map ( decoration => decoration . destroy ( ) ) ;
111
+ this . editorSub . dispose ( ) ;
112
+ this . markerSub . dispose ( ) ;
113
+ }
114
+ }
115
+
116
+ export default class Decoration extends React . Component {
117
+ static propTypes = {
118
+ editor : PropTypes . object ,
119
+ marker : PropTypes . object ,
120
+ }
121
+
122
+ constructor ( props ) {
123
+ super ( props ) ;
124
+
125
+ this . state = {
126
+ editorHolder : RefHolder . on ( this . props . editor ) ,
127
+ markerHolder : RefHolder . on ( this . props . marker ) ,
128
+ } ;
129
+ }
130
+
131
+ static getDerivedStateFromProps ( props , state ) {
132
+ const editorChanged = state . editorHolder . map ( editor => editor !== props . editor ) . getOr ( props . editor !== undefined ) ;
133
+ const markerChanged = state . markerHolder . map ( marker => marker !== props . marker ) . getOr ( props . marker !== undefined ) ;
134
+
135
+ if ( ! editorChanged && ! markerChanged ) {
136
+ return null ;
137
+ }
138
+
139
+ const nextState = { } ;
140
+ if ( editorChanged ) {
141
+ nextState . editorHolder = RefHolder . on ( props . editor ) ;
142
+ }
143
+ if ( markerChanged ) {
144
+ nextState . markerHolder = RefHolder . on ( props . marker ) ;
145
+ }
146
+ return nextState ;
147
+ }
148
+
149
+ render ( ) {
150
+ if ( ! this . state . editorHolder . isEmpty ( ) && ! this . state . markerHolder . isEmpty ( ) ) {
151
+ return (
152
+ < WrappedDecoration
153
+ { ...this . props }
154
+ editorHolder = { this . state . editorHolder }
155
+ markerHolder = { this . state . markerHolder }
156
+ />
157
+ ) ;
158
+ }
159
+
160
+ return (
161
+ < TextEditorContext . Consumer >
162
+ { editorHolder => (
163
+ < MarkerContext . Consumer >
164
+ { markerHolder => (
165
+ < WrappedDecoration { ...this . props } editorHolder = { editorHolder } markerHolder = { markerHolder } />
166
+ ) }
167
+ </ MarkerContext . Consumer >
168
+ ) }
169
+ </ TextEditorContext . Consumer >
170
+ ) ;
119
171
}
120
172
}
0 commit comments