@@ -2,24 +2,16 @@ import type {
2
2
LightningElement ,
3
3
LightningElementStyle ,
4
4
} from '@plextv/react-lightning' ;
5
- import {
6
- UPDATE_HEIGHT ,
7
- UPDATE_WIDTH ,
8
- UPDATE_X ,
9
- UPDATE_Y ,
10
- } from './types/UpdateFlags' ;
11
5
import type { YogaOptions } from './types/YogaOptions' ;
6
+ import { SimpleDataView } from './util/SimpleDataView' ;
12
7
import yoga from './yoga' ;
13
8
14
- const DEBOUNCE_DELAY = 1 ;
15
-
16
9
/**
17
- * Manages the lifecycle of Yoga nodes for Lightning elements. This can only be done on the main thread and not the worker thread.
10
+ * Manages the lifecycle of Yoga nodes for Lightning elements. This can only be
11
+ * done on the main thread and not the worker thread.
18
12
*/
19
13
export class LightningManager {
20
14
private _elements = new Map < number , LightningElement > ( ) ;
21
- private _stylesToSend : Record < number , Partial < LightningElementStyle > > = { } ;
22
- private _needsRender : null | number = null ;
23
15
24
16
public async init ( yogaOptions ?: YogaOptions ) {
25
17
await yoga . load ( yogaOptions ) ;
@@ -42,53 +34,51 @@ export class LightningManager {
42
34
}
43
35
44
36
this . _elements . delete ( element . id ) ;
45
- await yoga . instance . removeNode ( element . id ) ;
46
- this . _render ( element . id ) ;
37
+ yoga . instance . removeNode ( element . id ) ;
47
38
} ) ,
48
39
49
40
element . on ( 'childAdded' , async ( child , index ) => {
50
- await yoga . instance . addChildNode ( element . id , child . id , index ) ;
51
-
52
- await this . applyStyle ( element . id , element . props . style ) ;
41
+ yoga . instance . addChildNode ( element . id , child . id , index ) ;
42
+ this . applyStyle ( element . id , element . style ) ;
53
43
} ) ,
54
44
55
45
element . on ( 'childRemoved' , async ( child ) => {
56
- await yoga . instance . removeNode ( child . id ) ;
57
-
58
- this . _render ( element . id ) ;
46
+ // This will remove any pending worker style updates that haven't been sent
47
+ yoga . instance . applyStyle ( child . id , null , true ) ;
48
+ yoga . instance . removeNode ( child . id ) ;
59
49
} ) ,
60
50
61
51
element . on ( 'stylesChanged' , async ( ) => {
62
- await this . applyStyle ( element . id , element . props . style ) ;
52
+ this . applyStyle ( element . id , element . props . style ) ;
63
53
} ) ,
64
54
65
55
element . on ( 'textureLoaded' , async ( node , event ) => {
66
- // Text elements will already have its height and width set on the
67
- // node before loaded event is fired, so we need to set it on the yoga
68
- // node. If there's a maxWidth set, we should clamp the text to that size.
56
+ // Text elements will already have its height and width set on the node
57
+ // before loaded event is fired, so we need to set it on the yoga node.
58
+ // If there's a maxWidth set, we should clamp the text to that size.
69
59
// TODO: Get a proper return type
70
- const computedSize = await yoga . instance . getClampedSize ( element . id ) ;
71
-
72
- if (
73
- computedSize !== null &&
74
- computedSize > 0 &&
75
- event . dimensions . width > computedSize
76
- ) {
77
- node . contain = 'width' ;
78
- node . width = computedSize ;
60
+ if ( element . isTextElement ) {
61
+ const computedSize = await yoga . instance . getClampedSize ( element . id ) ;
62
+
63
+ if (
64
+ computedSize !== null &&
65
+ computedSize > 0 &&
66
+ event . dimensions . width > computedSize
67
+ ) {
68
+ node . contain = 'width' ;
69
+ node . width = computedSize ;
70
+ }
79
71
}
80
72
81
- await this . applyStyle ( element . id , {
73
+ this . applyStyle ( element . id , {
82
74
width : node . width ,
83
75
height : node . height ,
84
76
} ) ;
85
-
86
- this . _render ( element . id ) ;
87
77
} ) ,
88
78
] ;
89
79
}
90
80
91
- public async applyStyle (
81
+ public applyStyle (
92
82
elementId : number ,
93
83
style ?: Partial < LightningElementStyle > | null ,
94
84
skipRender = false ,
@@ -97,55 +87,17 @@ export class LightningManager {
97
87
return ;
98
88
}
99
89
100
- // if (style) {
101
- // this._stylesToSend[elementId] = {
102
- // ...this._stylesToSend[elementId],
103
- // ...style,
104
- // };
105
- // } else {
106
- // delete this._stylesToSend[elementId];
107
- // }
108
-
109
- // if (!skipRender) {
110
- // this._needsRender = elementId;
111
- // }
112
-
113
90
if ( style ) {
114
- await yoga . instance . applyStyle ( elementId , style ) ;
115
- }
116
-
117
- if ( ! skipRender ) {
118
- await this . _render ( elementId ) ;
91
+ yoga . instance . applyStyle ( elementId , style , skipRender ) ;
119
92
}
120
-
121
- // return this._sendStyles();
122
93
}
123
94
124
- private _sendStyles = debounced ( async ( ) : Promise < void > => {
125
- if ( Object . keys ( this . _stylesToSend ) . length === 0 ) {
126
- return ;
127
- }
128
-
129
- await yoga . instance . applyStyles ( this . _stylesToSend ) ;
130
- this . _stylesToSend = { } ;
131
-
132
- if ( this . _needsRender !== null ) {
133
- await this . _render ( this . _needsRender ) ;
134
- this . _needsRender = null ;
135
- }
136
- } , DEBOUNCE_DELAY ) ;
137
-
138
95
private _applyUpdates = ( buffer : ArrayBuffer ) => {
139
- const dataView = new DataView ( buffer ) ;
96
+ const dataView = new SimpleDataView ( buffer ) ;
140
97
141
98
// See YogaManagerWorker.ts for the structure of the updates
142
- const numItems = dataView . getUint32 ( 0 ) ;
143
- let offset = 4 ;
144
-
145
- for ( let i = 0 ; i < numItems ; i ++ ) {
146
- const elementId = dataView . getUint32 ( offset ) ;
147
- offset += 4 ;
148
-
99
+ while ( dataView . hasSpace ( 1 ) ) {
100
+ const elementId = dataView . readUint32 ( ) ;
149
101
const el = this . _elements . get ( elementId ) ;
150
102
151
103
if ( ! el ) {
@@ -168,65 +120,37 @@ export class LightningManager {
168
120
el . style . transform ?. translateY === undefined ;
169
121
}
170
122
171
- const flags = dataView . getUint8 ( offset ) ;
172
- offset += 1 ;
173
-
174
- if ( flags & UPDATE_X ) {
175
- if ( ! skipX ) {
176
- dirty = el . setNodeProp ( 'x' , dataView . getInt16 ( offset ) ) || dirty ;
177
- }
178
-
179
- offset += 2 ;
123
+ if ( ! skipX ) {
124
+ dirty = el . setNodeProp ( 'x' , dataView . readInt16 ( ) ) || dirty ;
125
+ } else {
126
+ // If the x is skipped, we still need to read the value to maintain the
127
+ // correct offset in the data view.
128
+ dataView . moveBy ( 2 ) ;
180
129
}
181
130
182
- if ( flags & UPDATE_Y ) {
183
- if ( ! skipY ) {
184
- dirty = el . setNodeProp ( 'y' , dataView . getInt16 ( offset ) ) || dirty ;
185
- }
186
-
187
- offset += 2 ;
131
+ if ( ! skipY ) {
132
+ dirty = el . setNodeProp ( 'y' , dataView . readInt16 ( ) ) || dirty ;
133
+ } else {
134
+ // Same as above
135
+ dataView . moveBy ( 2 ) ;
188
136
}
189
137
190
- if ( flags & UPDATE_WIDTH ) {
191
- dirty = el . setNodeProp ( 'width' , dataView . getUint16 ( offset ) ) || dirty ;
192
- offset += 2 ;
138
+ const width = dataView . readUint16 ( ) ;
139
+ const height = dataView . readUint16 ( ) ;
140
+
141
+ // If width is 0, we should not set it on the node, as it will cause
142
+ // layout issues.
143
+ if ( width !== 0 ) {
144
+ dirty = el . setNodeProp ( 'width' , width ) || dirty ;
193
145
}
194
146
195
- if ( flags & UPDATE_HEIGHT ) {
196
- dirty = el . setNodeProp ( 'height' , dataView . getUint16 ( offset ) ) || dirty ;
197
- offset += 2 ;
147
+ if ( height !== 0 ) {
148
+ dirty = el . setNodeProp ( 'height' , height ) || dirty ;
198
149
}
199
150
200
151
if ( dirty ) {
201
152
el . emitLayoutEvent ( ) ;
202
153
}
203
154
}
204
155
} ;
205
-
206
- private async _render ( elementId : number ) {
207
- yoga . instance . queueRender ( elementId ) ;
208
- }
209
- }
210
-
211
- function debounced < T extends ( ...args : unknown [ ] ) => void | Promise < void > > (
212
- fn : T ,
213
- delay : number ,
214
- ) : T {
215
- let timeout : ReturnType < typeof setTimeout > | null = null ;
216
- let lastArgs : unknown [ ] ;
217
-
218
- const debouncedFn = function ( this : unknown , ...args : unknown [ ] ) {
219
- lastArgs = args ;
220
-
221
- if ( timeout ) {
222
- clearTimeout ( timeout ) ;
223
- }
224
-
225
- timeout = setTimeout ( ( ) => {
226
- timeout = null ;
227
- fn . apply ( this , lastArgs ) ;
228
- } , delay ) ;
229
- } ;
230
-
231
- return debouncedFn as T ;
232
156
}
0 commit comments