@lvce-editor/virtual-dom 9.3.0 → 9.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,9 +1,350 @@
1
- const instances = Object.create(null);
2
- const get$1 = viewletId => {
3
- return instances[viewletId];
1
+ const uidSymbol = Symbol('uid');
2
+
3
+ const getUidTarget = $Element => {
4
+ while ($Element) {
5
+ if ($Element[uidSymbol]) {
6
+ return $Element;
7
+ }
8
+ $Element = $Element.parentNode;
9
+ }
10
+ return undefined;
4
11
  };
5
- const set$1 = (viewletId, instance) => {
6
- instances[viewletId] = instance;
12
+
13
+ const setComponentUid = ($Element, uid) => {
14
+ $Element[uidSymbol] = uid;
15
+ };
16
+ const getComponentUid = $Element => {
17
+ const $Target = getUidTarget($Element);
18
+ if (!$Target) {
19
+ return 0;
20
+ }
21
+ return $Target[uidSymbol];
22
+ };
23
+ const getComponentUidFromEvent = event => {
24
+ const {
25
+ currentTarget,
26
+ target
27
+ } = event;
28
+ return getComponentUid(currentTarget || target);
29
+ };
30
+
31
+ const dragInfos = Object.create(null);
32
+ const setDragInfo = (id, data) => {
33
+ dragInfos[id] = data;
34
+ };
35
+ const getDragInfo = id => {
36
+ return dragInfos[id];
37
+ };
38
+ const removeDragInfo = id => {
39
+ delete dragInfos[id];
40
+ };
41
+ const isDragInfoOld = data => {
42
+ return Array.isArray(data);
43
+ };
44
+
45
+ const setDragImage = (dataTransfer, label) => {
46
+ const dragImage = document.createElement('div');
47
+ dragImage.className = 'DragImage';
48
+ dragImage.textContent = label;
49
+ document.body.append(dragImage);
50
+ dataTransfer.setDragImage(dragImage, -10, -10);
51
+ const handleTimeOut = () => {
52
+ dragImage.remove();
53
+ };
54
+ setTimeout(handleTimeOut, 0);
55
+ };
56
+
57
+ const applyDragInfoMaybe = event => {
58
+ const {
59
+ dataTransfer,
60
+ target
61
+ } = event;
62
+ if (dataTransfer) {
63
+ const uid = getComponentUid(target);
64
+ const dragInfo = getDragInfo(uid);
65
+ if (!dragInfo) {
66
+ return;
67
+ }
68
+ if (isDragInfoOld(dragInfo)) {
69
+ for (const item of dragInfo) {
70
+ dataTransfer.setData(item.type, item.data);
71
+ }
72
+ } else {
73
+ for (const item of dragInfo.items) {
74
+ dataTransfer.items.add(item.data, item.type);
75
+ }
76
+ if (dragInfo.label) {
77
+ setDragImage(dataTransfer, dragInfo.label);
78
+ }
79
+ }
80
+ }
81
+ };
82
+
83
+ const PointerMove = 'pointermove';
84
+ const lostpointercapture = 'lostpointercapture';
85
+
86
+ let ignore = false;
87
+ const startIgnore = () => {
88
+ ignore = true;
89
+ };
90
+ const stopIgnore = () => {
91
+ ignore = false;
92
+ };
93
+ const enabled = () => {
94
+ return ignore;
95
+ };
96
+
97
+ let id = 0;
98
+ const create = () => {
99
+ return ++id;
100
+ };
101
+
102
+ const state$1 = Object.create(null);
103
+ const acquire = id => {
104
+ const promise = state$1[id];
105
+ delete state$1[id];
106
+ return promise;
107
+ };
108
+ const getFileHandles = async ids => {
109
+ const promises = ids.map(acquire);
110
+ const handles = await Promise.all(promises);
111
+ return handles;
112
+ };
113
+ const add$1 = promise => {
114
+ const id = create();
115
+ state$1[id] = promise;
116
+ return id;
117
+ };
118
+ const addFileHandle = fileHandle => {
119
+ const promise = Promise.resolve(fileHandle);
120
+ return add$1(promise);
121
+ };
122
+
123
+ const unwrapItemString = async item => {
124
+ const {
125
+ resolve,
126
+ promise
127
+ } = Promise.withResolvers();
128
+ item.getAsString(resolve);
129
+ const value = await promise;
130
+ return {
131
+ kind: 'string',
132
+ type: item.type,
133
+ value
134
+ };
135
+ };
136
+ const unwrapItemFile = async item => {
137
+ // @ts-ignore
138
+ const file = await item.getAsFileSystemHandle();
139
+ return {
140
+ kind: 'file',
141
+ type: item.type,
142
+ value: file
143
+ };
144
+ };
145
+ const unknownItem = {
146
+ kind: 'unknown',
147
+ type: '',
148
+ value: ''
149
+ };
150
+ const unwrapItem = item => {
151
+ switch (item.kind) {
152
+ case 'file':
153
+ return unwrapItemFile(item);
154
+ case 'string':
155
+ return unwrapItemString(item);
156
+ default:
157
+ return unknownItem;
158
+ }
159
+ };
160
+ const handleDataTransferFiles = event => {
161
+ if (!event.dataTransfer) {
162
+ return [];
163
+ }
164
+ const items = [...event.dataTransfer.items];
165
+ const promises = items.map(unwrapItem);
166
+ const ids = promises.map(promise => add$1(promise));
167
+ return ids;
168
+ };
169
+ const getEventListenerArg = (param, event) => {
170
+ switch (param) {
171
+ case 'event.altKey':
172
+ return event.altKey;
173
+ case 'event.button':
174
+ return event.button;
175
+ case 'event.clientX':
176
+ return event.clientX;
177
+ case 'event.clientY':
178
+ return event.clientY;
179
+ case 'event.ctrlKey':
180
+ return event.ctrlKey;
181
+ case 'event.data':
182
+ return event.data;
183
+ case 'event.dataTransfer.files':
184
+ return event.dataTransfer.files;
185
+ case 'event.dataTransfer.files2':
186
+ return handleDataTransferFiles(event);
187
+ case 'event.defaultPrevented':
188
+ return event.defaultPrevented;
189
+ case 'event.deltaMode':
190
+ return event.deltaMode;
191
+ case 'event.deltaX':
192
+ return event.deltaX;
193
+ case 'event.deltaY':
194
+ return event.deltaY;
195
+ case 'event.detail':
196
+ return event.detail;
197
+ case 'event.inputType':
198
+ return event.inputType;
199
+ case 'event.isTrusted':
200
+ return event.isTrusted;
201
+ case 'event.key':
202
+ return event.key;
203
+ case 'event.shiftKey':
204
+ return event.shiftKey;
205
+ case 'event.target.checked':
206
+ return event.target.checked;
207
+ case 'event.target.className':
208
+ return event.target.className;
209
+ case 'event.target.href':
210
+ return event.target.href;
211
+ case 'event.target.name':
212
+ return event.target.name || '';
213
+ case 'event.target.nodeName':
214
+ return event.target.nodeName;
215
+ case 'event.target.scrollTop':
216
+ return event.target.scrollTop;
217
+ case 'event.target.selectionEnd':
218
+ return event.target.selectionEnd;
219
+ case 'event.target.selectionStart':
220
+ return event.target.selectionStart;
221
+ case 'event.target.src':
222
+ return event.target.src;
223
+ case 'event.target.value':
224
+ return event.target.value;
225
+ case 'event.x':
226
+ return event.x;
227
+ case 'event.y':
228
+ return event.y;
229
+ default:
230
+ if (typeof param === 'string' && param.startsWith('event.currentTarget.')) {
231
+ const rest = param.slice('event.currentTarget.'.length);
232
+ const parts = rest.split('.');
233
+ let current = event.currentTarget;
234
+ for (const part of parts) {
235
+ current = current[part];
236
+ }
237
+ return current;
238
+ }
239
+ if (typeof param === 'string' && param.startsWith('event.target.dataset')) {
240
+ const rest = param.slice('event.target.dataset.'.length);
241
+ return event.target.dataset[rest];
242
+ }
243
+ return param;
244
+ }
245
+ };
246
+
247
+ const getEventListenerArgs = (params, event) => {
248
+ const serialized = [];
249
+ for (const param of params) {
250
+ serialized.push(getEventListenerArg(param, event));
251
+ }
252
+ return serialized;
253
+ };
254
+
255
+ const state = {
256
+ ipc: undefined
257
+ };
258
+ const getIpc = () => {
259
+ return state.ipc;
260
+ };
261
+ const setIpc = value => {
262
+ state.ipc = value;
263
+ };
264
+
265
+ const nameAnonymousFunction = (fn, name) => {
266
+ Object.defineProperty(fn, 'name', {
267
+ value: name
268
+ });
269
+ };
270
+
271
+ const isInputElement = element => {
272
+ return element instanceof HTMLInputElement;
273
+ };
274
+
275
+ const preventEventsMaybe = (info, event) => {
276
+ if (info.preventDefault === 2) {
277
+ if (!isInputElement(event.target)) {
278
+ event.preventDefault();
279
+ }
280
+ } else if (info.preventDefault) {
281
+ event.preventDefault();
282
+ }
283
+ if (info.stopPropagation) {
284
+ event.stopPropagation();
285
+ }
286
+ };
287
+
288
+ const applyPointerTrackMaybe = (info, map, event) => {
289
+ const {
290
+ trackPointerEvents
291
+ } = info;
292
+ if (!trackPointerEvents) {
293
+ return;
294
+ }
295
+ const {
296
+ pointerId,
297
+ target
298
+ } = event;
299
+ target.setPointerCapture(pointerId);
300
+ const [pointerMoveKey, pointerUpKey] = trackPointerEvents;
301
+ target.addEventListener(PointerMove, map[pointerMoveKey]);
302
+ target.addEventListener(lostpointercapture, map[pointerUpKey]);
303
+ };
304
+ const createFn = (info, map) => {
305
+ const fn = event => {
306
+ if (enabled()) {
307
+ return;
308
+ }
309
+ const uid = getComponentUidFromEvent(event);
310
+ const args = getEventListenerArgs(info.params, event);
311
+ preventEventsMaybe(info, event);
312
+ applyDragInfoMaybe(event);
313
+ applyPointerTrackMaybe(info, map, event);
314
+ if (args.length === 0) {
315
+ return;
316
+ }
317
+ const ipc = getIpc();
318
+ ipc.send('Viewlet.executeViewletCommand', uid, ...args);
319
+ };
320
+ nameAnonymousFunction(fn, info.name);
321
+ if (info.passive) {
322
+ // TODO avoid mutating function property, maybe return an object with function and options
323
+ fn.passive = true;
324
+ }
325
+ if (info.capture) {
326
+ // TODO avoid mutating function property, maybe return an object with function and options
327
+ fn.capture = true;
328
+ }
329
+ return fn;
330
+ };
331
+
332
+ const listeners = Object.create(null);
333
+ const registerEventListeners = (id, eventListeners) => {
334
+ const map = Object.create(null);
335
+ for (const info of eventListeners) {
336
+ const fn = createFn(info, map);
337
+ map[info.name] = fn;
338
+ }
339
+ listeners[id] = map;
340
+ };
341
+ const getEventListenerMap = id => {
342
+ const map = listeners[id];
343
+ return map;
344
+ };
345
+
346
+ const clearNode = $Node => {
347
+ $Node.textContent = '';
7
348
  };
8
349
 
9
350
  const Audio$2 = 'audio';
@@ -364,67 +705,35 @@ const ElementTagMap = {
364
705
 
365
706
  const {
366
707
  getElementTag
367
- } = ElementTagMap;
368
-
369
- const getEventListenerOptions = (eventName, value) => {
370
- if (value.passive) {
371
- return {
372
- passive: true
373
- };
374
- }
375
- if (value.capture) {
376
- return {
377
- capture: true
378
- };
379
- }
380
- switch (eventName) {
381
- case 'wheel':
382
- return {
383
- passive: true
384
- };
385
- default:
386
- return undefined;
387
- }
388
- };
389
-
390
- const uidSymbol = Symbol('uid');
391
-
392
- const getUidTarget = $Element => {
393
- while ($Element) {
394
- if ($Element[uidSymbol]) {
395
- return $Element;
396
- }
397
- $Element = $Element.parentNode;
398
- }
399
- return undefined;
400
- };
401
-
402
- const setComponentUid = ($Element, uid) => {
403
- $Element[uidSymbol] = uid;
404
- };
405
- const getComponentUid = $Element => {
406
- const $Target = getUidTarget($Element);
407
- if (!$Target) {
408
- return 0;
409
- }
410
- return $Target[uidSymbol];
411
- };
412
- const getComponentUidFromEvent = event => {
413
- const {
414
- currentTarget,
415
- target
416
- } = event;
417
- return getComponentUid(currentTarget || target);
418
- };
708
+ } = ElementTagMap;
419
709
 
420
- const state$1 = {
421
- ipc: undefined
710
+ const instances = Object.create(null);
711
+ const get$1 = viewletId => {
712
+ return instances[viewletId];
422
713
  };
423
- const getIpc = () => {
424
- return state$1.ipc;
714
+ const set$1 = (viewletId, instance) => {
715
+ instances[viewletId] = instance;
425
716
  };
426
- const setIpc = value => {
427
- state$1.ipc = value;
717
+
718
+ const getEventListenerOptions = (eventName, value) => {
719
+ if (value.passive) {
720
+ return {
721
+ passive: true
722
+ };
723
+ }
724
+ if (value.capture) {
725
+ return {
726
+ capture: true
727
+ };
728
+ }
729
+ switch (eventName) {
730
+ case 'wheel':
731
+ return {
732
+ passive: true
733
+ };
734
+ default:
735
+ return undefined;
736
+ }
428
737
  };
429
738
 
430
739
  const cache = new Map();
@@ -438,12 +747,6 @@ const get = listener => {
438
747
  return cache.get(listener);
439
748
  };
440
749
 
441
- const nameAnonymousFunction = (fn, name) => {
442
- Object.defineProperty(fn, 'name', {
443
- value: name
444
- });
445
- };
446
-
447
750
  const getWrappedListener = (listener, returnValue) => {
448
751
  if (!returnValue) {
449
752
  return listener;
@@ -777,392 +1080,131 @@ const renderDomElement = (element, eventMap, newEventMap) => {
777
1080
  setProps($Element, element, eventMap, newEventMap);
778
1081
  return $Element;
779
1082
  };
780
- const renderReferenceNode = element => {
781
- const instance = get$1(element.uid);
782
- if (!instance || !instance.state) {
783
- return document.createTextNode('Reference node not found');
784
- }
785
- const $Node = instance.state.$Viewlet;
786
- return $Node;
787
- };
788
- const render$1 = (element, eventMap, newEventMap) => {
789
- switch (element.type) {
790
- case Reference:
791
- return renderReferenceNode(element);
792
- case Text:
793
- return renderDomTextNode(element);
794
- default:
795
- return renderDomElement(element, eventMap, newEventMap);
796
- }
797
- };
798
-
799
- const renderInternal = ($Parent, elements, eventMap, newEventMap) => {
800
- const max = elements.length - 1;
801
- let stack = [];
802
- for (let i = max; i >= 0; i--) {
803
- const element = elements[i];
804
- const $Element = render$1(element, eventMap, newEventMap);
805
- if (element.childCount > 0) {
806
- // @ts-expect-error
807
- $Element.append(...stack.slice(0, element.childCount));
808
- stack = stack.slice(element.childCount);
809
- }
810
- stack.unshift($Element);
811
- }
812
- $Parent.append(...stack);
813
- };
814
-
815
- // Map of property names to attribute names for cases where they differ
816
- const propertyToAttribute = {
817
- className: 'class',
818
- htmlFor: 'for',
819
- ariaActivedescendant: 'aria-activedescendant',
820
- ariaControls: 'aria-controls',
821
- ariaLabelledBy: 'aria-labelledby',
822
- ariaOwns: 'aria-owns',
823
- inputType: 'type'
824
- };
825
-
826
- // Style properties that need to be set on element.style
827
- const styleProperties = new Set(['width', 'height', 'top', 'left', 'marginTop', 'paddingLeft', 'paddingRight']);
828
- const removeAttribute = ($Element, key) => {
829
- // Handle style properties
830
- if (styleProperties.has(key)) {
831
- // @ts-ignore - dynamic style property access
832
- $Element.style[key] = '';
833
- return;
834
- }
835
- const attributeName = propertyToAttribute[key] || key;
836
- $Element.removeAttribute(attributeName);
837
- };
838
- const setText = ($Element, value) => {
839
- $Element.nodeValue = value;
840
- };
841
- const removeChild = ($Element, index) => {
842
- const $Child = $Element.childNodes[index];
843
- if ($Child) {
844
- $Child.remove();
845
- }
846
- };
847
- const add$1 = ($Element, nodes, eventMap = {}) => {
848
- renderInternal($Element, nodes, eventMap, eventMap);
849
- };
850
- const replace = ($Element, nodes, eventMap = {}) => {
851
- // Create a temporary container to render the new nodes
852
- const $Temp = document.createElement('div');
853
- renderInternal($Temp, nodes, eventMap, eventMap);
854
- // Replace the current element with the new node(s)
855
- const $NewNode = $Temp.firstChild;
856
- if (!$NewNode) {
857
- // No node was created, just remove the old element
858
- $Element.remove();
859
- return $Element;
860
- }
861
- $Element.replaceWith($NewNode);
862
- return $NewNode;
863
- };
864
-
865
- const SetText = 1;
866
- const Replace = 2;
867
- const SetAttribute = 3;
868
- const RemoveAttribute = 4;
869
- const Add = 6;
870
- const NavigateChild = 7;
871
- const NavigateParent = 8;
872
- const RemoveChild = 9;
873
- const NavigateSibling = 10;
874
- const SetReferenceNodeUid = 11;
875
-
876
- const dragInfos = Object.create(null);
877
- const setDragInfo = (id, data) => {
878
- dragInfos[id] = data;
879
- };
880
- const getDragInfo = id => {
881
- return dragInfos[id];
882
- };
883
- const removeDragInfo = id => {
884
- delete dragInfos[id];
885
- };
886
- const isDragInfoOld = data => {
887
- return Array.isArray(data);
888
- };
889
-
890
- const setDragImage = (dataTransfer, label) => {
891
- const dragImage = document.createElement('div');
892
- dragImage.className = 'DragImage';
893
- dragImage.textContent = label;
894
- document.body.append(dragImage);
895
- dataTransfer.setDragImage(dragImage, -10, -10);
896
- const handleTimeOut = () => {
897
- dragImage.remove();
898
- };
899
- setTimeout(handleTimeOut, 0);
900
- };
901
-
902
- const applyDragInfoMaybe = event => {
903
- const {
904
- dataTransfer,
905
- target
906
- } = event;
907
- if (dataTransfer) {
908
- const uid = getComponentUid(target);
909
- const dragInfo = getDragInfo(uid);
910
- if (!dragInfo) {
911
- return;
912
- }
913
- if (isDragInfoOld(dragInfo)) {
914
- for (const item of dragInfo) {
915
- dataTransfer.setData(item.type, item.data);
916
- }
917
- } else {
918
- for (const item of dragInfo.items) {
919
- dataTransfer.items.add(item.data, item.type);
920
- }
921
- if (dragInfo.label) {
922
- setDragImage(dataTransfer, dragInfo.label);
923
- }
924
- }
925
- }
926
- };
927
-
928
- const PointerMove = 'pointermove';
929
- const lostpointercapture = 'lostpointercapture';
930
-
931
- let ignore = false;
932
- const startIgnore = () => {
933
- ignore = true;
934
- };
935
- const stopIgnore = () => {
936
- ignore = false;
937
- };
938
- const enabled = () => {
939
- return ignore;
940
- };
941
-
942
- let id = 0;
943
- const create = () => {
944
- return ++id;
945
- };
946
-
947
- const state = Object.create(null);
948
- const acquire = id => {
949
- const promise = state[id];
950
- delete state[id];
951
- return promise;
952
- };
953
- const getFileHandles = async ids => {
954
- const promises = ids.map(acquire);
955
- const handles = await Promise.all(promises);
956
- return handles;
957
- };
958
- const add = promise => {
959
- const id = create();
960
- state[id] = promise;
961
- return id;
962
- };
963
- const addFileHandle = fileHandle => {
964
- const promise = Promise.resolve(fileHandle);
965
- return add(promise);
966
- };
967
-
968
- const unwrapItemString = async item => {
969
- const {
970
- resolve,
971
- promise
972
- } = Promise.withResolvers();
973
- item.getAsString(resolve);
974
- const value = await promise;
975
- return {
976
- kind: 'string',
977
- type: item.type,
978
- value
979
- };
980
- };
981
- const unwrapItemFile = async item => {
982
- // @ts-ignore
983
- const file = await item.getAsFileSystemHandle();
984
- return {
985
- kind: 'file',
986
- type: item.type,
987
- value: file
988
- };
989
- };
990
- const unknownItem = {
991
- kind: 'unknown',
992
- type: '',
993
- value: ''
994
- };
995
- const unwrapItem = item => {
996
- switch (item.kind) {
997
- case 'file':
998
- return unwrapItemFile(item);
999
- case 'string':
1000
- return unwrapItemString(item);
1001
- default:
1002
- return unknownItem;
1003
- }
1004
- };
1005
- const handleDataTransferFiles = event => {
1006
- if (!event.dataTransfer) {
1007
- return [];
1083
+ const renderReferenceNode = element => {
1084
+ const instance = get$1(element.uid);
1085
+ if (!instance || !instance.state) {
1086
+ return document.createTextNode('Reference node not found');
1008
1087
  }
1009
- const items = [...event.dataTransfer.items];
1010
- const promises = items.map(unwrapItem);
1011
- const ids = promises.map(promise => add(promise));
1012
- return ids;
1088
+ const $Node = instance.state.$Viewlet;
1089
+ return $Node;
1013
1090
  };
1014
- const getEventListenerArg = (param, event) => {
1015
- switch (param) {
1016
- case 'event.altKey':
1017
- return event.altKey;
1018
- case 'event.button':
1019
- return event.button;
1020
- case 'event.clientX':
1021
- return event.clientX;
1022
- case 'event.clientY':
1023
- return event.clientY;
1024
- case 'event.ctrlKey':
1025
- return event.ctrlKey;
1026
- case 'event.data':
1027
- return event.data;
1028
- case 'event.dataTransfer.files':
1029
- return event.dataTransfer.files;
1030
- case 'event.dataTransfer.files2':
1031
- return handleDataTransferFiles(event);
1032
- case 'event.defaultPrevented':
1033
- return event.defaultPrevented;
1034
- case 'event.deltaMode':
1035
- return event.deltaMode;
1036
- case 'event.deltaX':
1037
- return event.deltaX;
1038
- case 'event.deltaY':
1039
- return event.deltaY;
1040
- case 'event.detail':
1041
- return event.detail;
1042
- case 'event.inputType':
1043
- return event.inputType;
1044
- case 'event.isTrusted':
1045
- return event.isTrusted;
1046
- case 'event.key':
1047
- return event.key;
1048
- case 'event.shiftKey':
1049
- return event.shiftKey;
1050
- case 'event.target.checked':
1051
- return event.target.checked;
1052
- case 'event.target.className':
1053
- return event.target.className;
1054
- case 'event.target.href':
1055
- return event.target.href;
1056
- case 'event.target.name':
1057
- return event.target.name || '';
1058
- case 'event.target.nodeName':
1059
- return event.target.nodeName;
1060
- case 'event.target.scrollTop':
1061
- return event.target.scrollTop;
1062
- case 'event.target.selectionEnd':
1063
- return event.target.selectionEnd;
1064
- case 'event.target.selectionStart':
1065
- return event.target.selectionStart;
1066
- case 'event.target.src':
1067
- return event.target.src;
1068
- case 'event.target.value':
1069
- return event.target.value;
1070
- case 'event.x':
1071
- return event.x;
1072
- case 'event.y':
1073
- return event.y;
1091
+ const render$1 = (element, eventMap, newEventMap) => {
1092
+ switch (element.type) {
1093
+ case Reference:
1094
+ return renderReferenceNode(element);
1095
+ case Text:
1096
+ return renderDomTextNode(element);
1074
1097
  default:
1075
- if (typeof param === 'string' && param.startsWith('event.target.dataset')) {
1076
- const rest = param.slice('event.target.dataset.'.length);
1077
- return event.target.dataset[rest];
1078
- }
1079
- return param;
1098
+ return renderDomElement(element, eventMap, newEventMap);
1080
1099
  }
1081
1100
  };
1082
1101
 
1083
- const getEventListenerArgs = (params, event) => {
1084
- const serialized = [];
1085
- for (const param of params) {
1086
- serialized.push(getEventListenerArg(param, event));
1102
+ const renderInternal = ($Parent, elements, eventMap, newEventMap) => {
1103
+ const max = elements.length - 1;
1104
+ let stack = [];
1105
+ for (let i = max; i >= 0; i--) {
1106
+ const element = elements[i];
1107
+ const $Element = render$1(element, eventMap, newEventMap);
1108
+ if (element.childCount > 0) {
1109
+ // @ts-expect-error
1110
+ $Element.append(...stack.slice(0, element.childCount));
1111
+ stack = stack.slice(element.childCount);
1112
+ }
1113
+ stack.unshift($Element);
1087
1114
  }
1088
- return serialized;
1115
+ $Parent.append(...stack);
1089
1116
  };
1090
1117
 
1091
- const isInputElement = element => {
1092
- return element instanceof HTMLInputElement;
1118
+ const renderInto = ($Parent, dom, eventMap = {}) => {
1119
+ clearNode($Parent);
1120
+ renderInternal($Parent, dom, eventMap);
1093
1121
  };
1094
1122
 
1095
- const preventEventsMaybe = (info, event) => {
1096
- if (info.preventDefault === 2) {
1097
- if (!isInputElement(event.target)) {
1098
- event.preventDefault();
1099
- }
1100
- } else if (info.preventDefault) {
1101
- event.preventDefault();
1102
- }
1103
- if (info.stopPropagation) {
1104
- event.stopPropagation();
1123
+ /**
1124
+ *
1125
+ * @param {any[]} elements
1126
+ * @returns
1127
+ */
1128
+ const render = (elements, eventMap = {}, newEventMap = {}) => {
1129
+ const $Root = document.createElement('div');
1130
+ renderInternal($Root, elements, eventMap, newEventMap);
1131
+ return $Root;
1132
+ };
1133
+
1134
+ const rememberFocus2 = ($Viewlet, dom, eventMap, uid = 0) => {
1135
+ if (uid) {
1136
+ const newEventMap = getEventListenerMap(uid);
1137
+ const $New = render(dom, eventMap, newEventMap).firstChild;
1138
+ setComponentUid($New, uid);
1139
+ $Viewlet.replaceWith($New);
1140
+ $Viewlet = $New;
1141
+ } else {
1142
+ renderInto($Viewlet, dom, eventMap);
1105
1143
  }
1144
+ return $Viewlet;
1106
1145
  };
1107
1146
 
1108
- const applyPointerTrackMaybe = (info, map, event) => {
1109
- const {
1110
- trackPointerEvents
1111
- } = info;
1112
- if (!trackPointerEvents) {
1147
+ // Map of property names to attribute names for cases where they differ
1148
+ const propertyToAttribute = {
1149
+ className: 'class',
1150
+ htmlFor: 'for',
1151
+ ariaActivedescendant: 'aria-activedescendant',
1152
+ ariaControls: 'aria-controls',
1153
+ ariaLabelledBy: 'aria-labelledby',
1154
+ ariaOwns: 'aria-owns',
1155
+ inputType: 'type'
1156
+ };
1157
+
1158
+ // Style properties that need to be set on element.style
1159
+ const styleProperties = new Set(['width', 'height', 'top', 'left', 'marginTop', 'paddingLeft', 'paddingRight']);
1160
+ const removeAttribute = ($Element, key) => {
1161
+ // Handle style properties
1162
+ if (styleProperties.has(key)) {
1163
+ // @ts-ignore - dynamic style property access
1164
+ $Element.style[key] = '';
1113
1165
  return;
1114
1166
  }
1115
- const {
1116
- pointerId,
1117
- target
1118
- } = event;
1119
- target.setPointerCapture(pointerId);
1120
- const [pointerMoveKey, pointerUpKey] = trackPointerEvents;
1121
- target.addEventListener(PointerMove, map[pointerMoveKey]);
1122
- target.addEventListener(lostpointercapture, map[pointerUpKey]);
1167
+ const attributeName = propertyToAttribute[key] || key;
1168
+ $Element.removeAttribute(attributeName);
1123
1169
  };
1124
- const createFn = (info, map) => {
1125
- const fn = event => {
1126
- if (enabled()) {
1127
- return;
1128
- }
1129
- const uid = getComponentUidFromEvent(event);
1130
- const args = getEventListenerArgs(info.params, event);
1131
- preventEventsMaybe(info, event);
1132
- applyDragInfoMaybe(event);
1133
- applyPointerTrackMaybe(info, map, event);
1134
- if (args.length === 0) {
1135
- return;
1136
- }
1137
- const ipc = getIpc();
1138
- ipc.send('Viewlet.executeViewletCommand', uid, ...args);
1139
- };
1140
- nameAnonymousFunction(fn, info.name);
1141
- if (info.passive) {
1142
- // TODO avoid mutating function property, maybe return an object with function and options
1143
- fn.passive = true;
1144
- }
1145
- if (info.capture) {
1146
- // TODO avoid mutating function property, maybe return an object with function and options
1147
- fn.capture = true;
1148
- }
1149
- return fn;
1170
+ const setText = ($Element, value) => {
1171
+ $Element.nodeValue = value;
1150
1172
  };
1151
-
1152
- const listeners = Object.create(null);
1153
- const registerEventListeners = (id, eventListeners) => {
1154
- const map = Object.create(null);
1155
- for (const info of eventListeners) {
1156
- const fn = createFn(info, map);
1157
- map[info.name] = fn;
1173
+ const removeChild = ($Element, index) => {
1174
+ const $Child = $Element.childNodes[index];
1175
+ if ($Child) {
1176
+ $Child.remove();
1158
1177
  }
1159
- listeners[id] = map;
1160
1178
  };
1161
- const getEventListenerMap = id => {
1162
- const map = listeners[id];
1163
- return map;
1179
+ const add = ($Element, nodes, eventMap = {}) => {
1180
+ renderInternal($Element, nodes, eventMap, eventMap);
1181
+ };
1182
+ const replace = ($Element, nodes, eventMap = {}) => {
1183
+ // Create a temporary container to render the new nodes
1184
+ const $Temp = document.createElement('div');
1185
+ renderInternal($Temp, nodes, eventMap, eventMap);
1186
+ // Replace the current element with the new node(s)
1187
+ const $NewNode = $Temp.firstChild;
1188
+ if (!$NewNode) {
1189
+ // No node was created, just remove the old element
1190
+ $Element.remove();
1191
+ return $Element;
1192
+ }
1193
+ $Element.replaceWith($NewNode);
1194
+ return $NewNode;
1164
1195
  };
1165
1196
 
1197
+ const SetText = 1;
1198
+ const Replace = 2;
1199
+ const SetAttribute = 3;
1200
+ const RemoveAttribute = 4;
1201
+ const Add = 6;
1202
+ const NavigateChild = 7;
1203
+ const NavigateParent = 8;
1204
+ const RemoveChild = 9;
1205
+ const NavigateSibling = 10;
1206
+ const SetReferenceNodeUid = 11;
1207
+
1166
1208
  const applyPatch = ($Element, patches, eventMap = {}, id = 0) => {
1167
1209
  const events = getEventListenerMap(id) || eventMap;
1168
1210
  let $Current = $Element;
@@ -1171,7 +1213,7 @@ const applyPatch = ($Element, patches, eventMap = {}, id = 0) => {
1171
1213
  try {
1172
1214
  switch (patch.type) {
1173
1215
  case Add:
1174
- add$1($Current, patch.nodes, events);
1216
+ add($Current, patch.nodes, events);
1175
1217
  break;
1176
1218
  case NavigateChild:
1177
1219
  {
@@ -1287,26 +1329,6 @@ const queryInputs = $Viewlet => {
1287
1329
  return [...$Viewlet.querySelectorAll('input, textarea, select')];
1288
1330
  };
1289
1331
 
1290
- const clearNode = $Node => {
1291
- $Node.textContent = '';
1292
- };
1293
-
1294
- const renderInto = ($Parent, dom, eventMap = {}) => {
1295
- clearNode($Parent);
1296
- renderInternal($Parent, dom, eventMap);
1297
- };
1298
-
1299
- /**
1300
- *
1301
- * @param {any[]} elements
1302
- * @returns
1303
- */
1304
- const render = (elements, eventMap = {}, newEventMap = {}) => {
1305
- const $Root = document.createElement('div');
1306
- renderInternal($Root, elements, eventMap, newEventMap);
1307
- return $Root;
1308
- };
1309
-
1310
1332
  const focusElement = $Element => {
1311
1333
  $Element.focus({
1312
1334
  preventScroll: true
@@ -1385,4 +1407,4 @@ const rememberFocus = ($Viewlet, dom, eventMap, uid = 0) => {
1385
1407
  return $Viewlet;
1386
1408
  };
1387
1409
 
1388
- export { VirtualDomElements, addFileHandle, applyPatch, getComponentUid, getComponentUidFromEvent, getDragInfo, getFileHandles, get$1 as getViewletInstance, registerEventListeners, rememberFocus, removeDragInfo, render, renderInto, setComponentUid, setDragInfo, setIpc, set$1 as setViewletInstance };
1410
+ export { VirtualDomElements, addFileHandle, applyPatch, getComponentUid, getComponentUidFromEvent, getDragInfo, getFileHandles, get$1 as getViewletInstance, registerEventListeners, rememberFocus, rememberFocus2, removeDragInfo, render, renderInto, setComponentUid, setDragInfo, setIpc, set$1 as setViewletInstance };
@@ -1,3 +1,4 @@
1
+ export { rememberFocus2 } from '../RememberFocus2/RememberFocus2.ts';
1
2
  export { applyPatch } from '../ApplyPatch/ApplyPatch.ts';
2
3
  export { getComponentUid, getComponentUidFromEvent, setComponentUid, } from '../ComponentUid/ComponentUid.ts';
3
4
  export { getDragInfo, removeDragInfo, setDragInfo, } from '../DragInfo/DragInfo.ts';
@@ -0,0 +1 @@
1
+ export declare const rememberFocus2: ($Viewlet: HTMLElement, dom: any[], eventMap: any, uid?: number) => any;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/virtual-dom",
3
- "version": "9.3.0",
3
+ "version": "9.5.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/lvce-editor/virtual-dom.git"