neo.mjs 10.0.0-beta.1 → 10.0.0-beta.2

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.
Files changed (138) hide show
  1. package/ServiceWorker.mjs +2 -2
  2. package/apps/colors/view/GridContainer.mjs +1 -1
  3. package/apps/covid/view/AttributionComponent.mjs +1 -1
  4. package/apps/covid/view/HeaderContainer.mjs +6 -6
  5. package/apps/covid/view/MainContainerController.mjs +5 -5
  6. package/apps/covid/view/TableContainerController.mjs +1 -1
  7. package/apps/covid/view/country/Gallery.mjs +13 -13
  8. package/apps/covid/view/country/Helix.mjs +13 -13
  9. package/apps/covid/view/country/HistoricalDataTable.mjs +1 -1
  10. package/apps/email/view/Viewport.mjs +2 -2
  11. package/apps/form/view/SideNavList.mjs +1 -1
  12. package/apps/portal/index.html +1 -1
  13. package/apps/portal/resources/data/examples_dist_esm.json +1 -1
  14. package/apps/portal/resources/data/examples_dist_prod.json +2 -2
  15. package/apps/portal/view/HeaderToolbar.mjs +3 -3
  16. package/apps/portal/view/about/Container.mjs +2 -2
  17. package/apps/portal/view/about/MemberContainer.mjs +3 -3
  18. package/apps/portal/view/blog/List.mjs +7 -7
  19. package/apps/portal/view/examples/List.mjs +4 -4
  20. package/apps/portal/view/home/ContentBox.mjs +2 -2
  21. package/apps/portal/view/home/FeatureSection.mjs +3 -3
  22. package/apps/portal/view/home/FooterContainer.mjs +7 -7
  23. package/apps/portal/view/home/parts/AfterMath.mjs +3 -3
  24. package/apps/portal/view/home/parts/MainNeo.mjs +3 -3
  25. package/apps/portal/view/home/parts/References.mjs +6 -6
  26. package/apps/portal/view/learn/ContentComponent.mjs +3 -3
  27. package/apps/portal/view/learn/PageSectionsContainer.mjs +1 -1
  28. package/apps/portal/view/learn/PageSectionsList.mjs +2 -2
  29. package/apps/portal/view/services/Component.mjs +16 -16
  30. package/apps/realworld/view/FooterComponent.mjs +1 -1
  31. package/apps/realworld/view/HeaderComponent.mjs +8 -8
  32. package/apps/realworld/view/HomeComponent.mjs +6 -6
  33. package/apps/realworld/view/article/CommentComponent.mjs +4 -4
  34. package/apps/realworld/view/article/Component.mjs +14 -14
  35. package/apps/realworld/view/article/CreateCommentComponent.mjs +3 -3
  36. package/apps/realworld/view/article/CreateComponent.mjs +3 -3
  37. package/apps/realworld/view/article/PreviewComponent.mjs +1 -1
  38. package/apps/realworld/view/article/TagListComponent.mjs +2 -2
  39. package/apps/realworld/view/user/ProfileComponent.mjs +8 -8
  40. package/apps/realworld/view/user/SettingsComponent.mjs +4 -4
  41. package/apps/realworld/view/user/SignUpComponent.mjs +4 -4
  42. package/apps/realworld2/view/FooterComponent.mjs +1 -1
  43. package/apps/realworld2/view/HomeContainer.mjs +3 -3
  44. package/apps/realworld2/view/article/DetailsContainer.mjs +1 -1
  45. package/apps/realworld2/view/article/PreviewComponent.mjs +7 -7
  46. package/apps/realworld2/view/article/TagListComponent.mjs +2 -2
  47. package/apps/realworld2/view/user/ProfileContainer.mjs +1 -1
  48. package/apps/route/view/center/CardAdministration.mjs +2 -2
  49. package/apps/route/view/center/CardAdministrationDenied.mjs +1 -1
  50. package/apps/route/view/center/CardContact.mjs +2 -2
  51. package/apps/route/view/center/CardHome.mjs +1 -1
  52. package/apps/route/view/center/CardSection1.mjs +1 -1
  53. package/apps/route/view/center/CardSection2.mjs +1 -1
  54. package/apps/sharedcovid/view/AttributionComponent.mjs +1 -1
  55. package/apps/sharedcovid/view/HeaderContainer.mjs +6 -6
  56. package/apps/sharedcovid/view/MainContainerController.mjs +5 -5
  57. package/apps/sharedcovid/view/TableContainerController.mjs +1 -1
  58. package/apps/sharedcovid/view/country/Gallery.mjs +13 -13
  59. package/apps/sharedcovid/view/country/Helix.mjs +13 -13
  60. package/apps/sharedcovid/view/country/HistoricalDataTable.mjs +1 -1
  61. package/apps/shareddialog/childapps/shareddialog2/view/MainContainer.mjs +1 -1
  62. package/apps/shareddialog/view/MainContainer.mjs +1 -1
  63. package/buildScripts/createApp.mjs +2 -2
  64. package/learn/Glossary.md +261 -0
  65. package/learn/benefits/ConfigSystem.md +536 -26
  66. package/learn/benefits/Effort.md +47 -2
  67. package/learn/benefits/Features.md +50 -32
  68. package/learn/benefits/FormsEngine.md +54 -24
  69. package/learn/benefits/MultiWindow.md +31 -5
  70. package/learn/benefits/Quick.md +45 -12
  71. package/learn/benefits/RPCLayer.md +75 -0
  72. package/learn/benefits/Speed.md +17 -12
  73. package/learn/guides/ConfigSystemDeepDive.md +280 -0
  74. package/learn/guides/DeclarativeComponentTreesVsImperativeVdom.md +17 -17
  75. package/learn/guides/InstanceLifecycle.md +295 -1
  76. package/learn/guides/MainThreadAddons.md +475 -0
  77. package/learn/guides/WorkingWithVDom.md +14 -14
  78. package/learn/tree.json +52 -51
  79. package/package.json +2 -2
  80. package/src/DefaultConfig.mjs +2 -2
  81. package/src/Main.mjs +8 -7
  82. package/src/Neo.mjs +16 -2
  83. package/src/button/Base.mjs +2 -2
  84. package/src/calendar/view/SettingsContainer.mjs +2 -2
  85. package/src/calendar/view/YearComponent.mjs +9 -9
  86. package/src/calendar/view/calendars/ColorsList.mjs +1 -1
  87. package/src/calendar/view/calendars/List.mjs +1 -1
  88. package/src/calendar/view/month/Component.mjs +15 -15
  89. package/src/calendar/view/week/Component.mjs +12 -12
  90. package/src/calendar/view/week/EventDragZone.mjs +4 -4
  91. package/src/calendar/view/week/TimeAxisComponent.mjs +3 -3
  92. package/src/component/Base.mjs +17 -2
  93. package/src/component/Carousel.mjs +2 -2
  94. package/src/component/Chip.mjs +3 -3
  95. package/src/component/Circle.mjs +2 -2
  96. package/src/component/DateSelector.mjs +8 -8
  97. package/src/component/Helix.mjs +1 -1
  98. package/src/component/Label.mjs +3 -18
  99. package/src/component/Legend.mjs +3 -3
  100. package/src/component/MagicMoveText.mjs +6 -14
  101. package/src/component/Process.mjs +3 -3
  102. package/src/component/Progress.mjs +1 -1
  103. package/src/component/StatusBadge.mjs +2 -2
  104. package/src/component/Timer.mjs +2 -2
  105. package/src/component/Toast.mjs +5 -3
  106. package/src/container/AccordionItem.mjs +2 -2
  107. package/src/container/Base.mjs +1 -1
  108. package/src/core/Base.mjs +18 -2
  109. package/src/date/DayViewComponent.mjs +2 -2
  110. package/src/date/SelectorContainer.mjs +1 -1
  111. package/src/form/field/CheckBox.mjs +4 -4
  112. package/src/form/field/FileUpload.mjs +25 -39
  113. package/src/form/field/Range.mjs +1 -1
  114. package/src/form/field/Text.mjs +3 -3
  115. package/src/form/field/TextArea.mjs +2 -3
  116. package/src/grid/Body.mjs +6 -2
  117. package/src/list/Color.mjs +2 -2
  118. package/src/main/DeltaUpdates.mjs +157 -98
  119. package/src/main/addon/AmCharts.mjs +53 -73
  120. package/src/main/addon/Base.mjs +11 -0
  121. package/src/main/addon/MonacoEditor.mjs +31 -58
  122. package/src/manager/ClassHierarchy.mjs +114 -0
  123. package/src/menu/List.mjs +1 -1
  124. package/src/plugin/Popover.mjs +2 -2
  125. package/src/sitemap/Component.mjs +1 -1
  126. package/src/table/Body.mjs +6 -2
  127. package/src/tooltip/Base.mjs +1 -6
  128. package/src/tree/Accordion.mjs +3 -3
  129. package/src/vdom/Helper.mjs +19 -19
  130. package/src/worker/App.mjs +1 -2
  131. package/src/worker/Base.mjs +6 -4
  132. package/src/worker/Canvas.mjs +2 -3
  133. package/src/worker/Data.mjs +5 -7
  134. package/src/worker/Task.mjs +2 -3
  135. package/src/worker/VDom.mjs +3 -4
  136. package/src/worker/mixin/RemoteMethodAccess.mjs +4 -1
  137. package/learn/guides/MainThreadAddonExample.md +0 -15
  138. package/learn/guides/MainThreadAddonIntro.md +0 -44
@@ -5,7 +5,13 @@ import {voidAttributes} from '../vdom/domConstants.mjs';
5
5
  const NeoConfig = Neo.config;
6
6
 
7
7
  /**
8
- * Logic to apply the deltas generated by vdom.Helper to the real DOM
8
+ * Manages and applies the Virtual DOM (VDom) delta updates generated by `Neo.vdom.Helper` to the real browser DOM.
9
+ * This class acts as the bridge between the VDom worker's calculated changes and the actual rendering on the main thread.
10
+ * It orchestrates various DOM manipulation operations such as node insertions, removals, moves, attribute updates,
11
+ * and handles dynamic renderer switching based on `Neo.config.useDomApiRenderer`.
12
+ *
13
+ * As a singleton per browser window, it provides a centralized and efficient mechanism for synchronized DOM updates,
14
+ * ensuring the UI accurately reflects the application state.
9
15
  * @class Neo.main.DeltaUpdates
10
16
  * @extends Neo.core.Base
11
17
  * @singleton
@@ -48,19 +54,6 @@ class DeltaUpdates extends Base {
48
54
  * @protected
49
55
  */
50
56
  logDeltasIntervalId = 0
51
- /**
52
- * Private property to store the dynamically loaded renderer module.
53
- * @member {Neo.main.render.DomApiRenderer|Neo.main.render.DomApiRenderer|null} #renderer=null
54
- * @private
55
- */
56
- #renderer = null
57
- /**
58
- * Private property to signal that the renderer module has been loaded.
59
- * This will be a Promise that resolves when the module is ready.
60
- * @private
61
- * @member {Promise<void>|null} #_readyPromise
62
- */
63
- #_readyPromise = null
64
57
 
65
58
  /**
66
59
  * @param {Object} config
@@ -68,11 +61,10 @@ class DeltaUpdates extends Base {
68
61
  construct(config) {
69
62
  super.construct(config);
70
63
 
71
- let me = this,
72
- {environment} = NeoConfig;
64
+ let {environment} = NeoConfig;
73
65
 
74
66
  if (NeoConfig.renderCountDeltas) {
75
- me.renderCountDeltas = true
67
+ this.renderCountDeltas = true
76
68
  }
77
69
 
78
70
  // We need different publicPath values for the main thread inside the webpack based dist envs,
@@ -80,24 +72,6 @@ class DeltaUpdates extends Base {
80
72
  if (environment === 'dist/development' || environment === 'dist/production') {
81
73
  __webpack_require__.p = NeoConfig.basePath.substring(6)
82
74
  }
83
-
84
- // Initiate the asynchronous loading of the renderer here.
85
- me.#_readyPromise = (async () => {
86
- try {
87
- let module;
88
-
89
- if (NeoConfig.useDomApiRenderer) {
90
- module = await import('./render/DomApiRenderer.mjs')
91
- } else {
92
- module = await import('./render/StringBasedRenderer.mjs')
93
- }
94
-
95
- me.#renderer = module.default
96
- } catch (err) {
97
- console.error('DeltaUpdates: Failed to load renderer module:', err);
98
- throw err // Re-throw to propagate initialization failures
99
- }
100
- })()
101
75
  }
102
76
 
103
77
  /**
@@ -130,8 +104,13 @@ class DeltaUpdates extends Base {
130
104
  }
131
105
 
132
106
  /**
133
- * @param {HTMLElement} node
134
- * @param {String} nodeName
107
+ * Changes the tag name (nodeName) of an existing HTMLElement in the DOM.
108
+ * This operation is performed by creating a new HTML element with the desired `nodeName`,
109
+ * meticulously copying all attributes and the `innerHTML` from the original `node` to the new one,
110
+ * and then seamlessly replacing the original `node` with the newly created element within its parent.
111
+ *
112
+ * @param {HTMLElement} node The existing DOM HTMLElement whose tag name needs to be changed.
113
+ * @param {String} nodeName The new tag name (e.g., 'div', 'span', 'p') for the element.
135
114
  */
136
115
  changeNodeName(node, nodeName) {
137
116
  let {attributes} = node,
@@ -160,21 +139,49 @@ class DeltaUpdates extends Base {
160
139
  DomAccess.getElement(id)?.focus()
161
140
  }
162
141
 
142
+ /**
143
+ * Imports either (if not already imported):
144
+ * `Neo.main.render.DomApiRenderer` if Neo.config.useDomApiRenderer === true
145
+ * `Neo.main.render.StringBasedRenderer` if Neo.config.useDomApiRenderer === false
146
+ * @returns {Promise<void>}
147
+ * @protected
148
+ */
149
+ async importRenderer() {
150
+ const {render} = Neo.main;
151
+
152
+ if (NeoConfig.useDomApiRenderer) {
153
+ if (!render?.DomApiRenderer) {
154
+ await import('./render/DomApiRenderer.mjs')
155
+ }
156
+ } else {
157
+ if (!render?.StringBasedRenderer) {
158
+ await import('./render/StringBasedRenderer.mjs')
159
+ }
160
+ }
161
+ }
162
+
163
+ /**
164
+ * @returns {Promise<void>}
165
+ */
166
+ async initAsync() {
167
+ super.initAsync();
168
+
169
+ let me = this;
170
+
171
+ // Subscribe to global Neo.config changes for dynamic renderer switching.
172
+ Neo.worker.Manager.on({
173
+ neoConfigChange: me.onNeoConfigChange,
174
+ scope : me
175
+ });
176
+
177
+ await me.importRenderer()
178
+ }
179
+
163
180
  /**
164
181
  * Inserts a new node into the DOM tree based on delta updates.
165
182
  * This method handles both string-based (outerHTML) and direct DOM API (vnode) mounting.
166
183
  * It ensures the node is inserted at the correct index within the parent.
167
- *
168
- * Implementation Details & Considerations:
169
- * - `parentNode.children` contains only element nodes (tags).
170
- * - `parentNode.childNodes` contains all nodes, including text and comment nodes.
171
- * - Since every `vtype:'text'` is wrapped inside a comment block (as an ID),
172
- * calculating a "realIndex" is necessary for string-based insertions to
173
- * correctly account for non-element nodes.
174
- * - `insertAdjacentHTML()` is generally faster than creating a node via template,
175
- * but it's only available for manipulating children (elements), not `childNodes` (all nodes).
176
- * - For performance, in cases where there are no comment nodes (i.e., no wrapped text nodes),
177
- * the method prioritizes `insertAdjacentHTML()` when `useDomApiRenderer` is false.
184
+ * This method is synchronous and *expects* the appropriate renderer (DomApiRenderer or StringBasedRenderer) to be already loaded.
178
185
  *
179
186
  * @param {Object} delta
180
187
  * @param {Boolean} delta.hasLeadingTextChildren Flag to honor leading comments, which require special treatment.
@@ -184,33 +191,47 @@ class DeltaUpdates extends Base {
184
191
  * @param {Neo.vdom.VNode} [delta.vnode] The VNode representation of the new node (for direct DOM API mounting).
185
192
  */
186
193
  insertNode({hasLeadingTextChildren, index, outerHTML, parentId, vnode}) {
187
- let me = this;
188
-
189
- // This method is synchronous and *expects* the renderer to be loaded
190
- if (!me.#renderer) {
191
- console.error('DeltaUpdates renderer not ready during insertNode!');
192
- return
193
- }
194
+ this.checkRendererAvailability();
194
195
 
195
- const parentNode = DomAccess.getElementOrBody(parentId);
196
+ let {render} = Neo.main,
197
+ parentNode = DomAccess.getElementOrBody(parentId);
196
198
 
197
199
  if (parentNode) {
198
200
  if (NeoConfig.useDomApiRenderer) {
199
- me.#renderer.createDomTree({index, isRoot: true, parentNode, vnode})
201
+ render.DomApiRenderer.createDomTree({index, isRoot: true, parentNode, vnode})
200
202
  } else {
201
- me.#renderer.insertNodeAsString({hasLeadingTextChildren, index, outerHTML, parentNode})
203
+ render.StringBasedRenderer.insertNodeAsString({hasLeadingTextChildren, index, outerHTML, parentNode})
204
+ }
205
+ }
206
+ }
207
+
208
+ /**
209
+ *
210
+ */
211
+ checkRendererAvailability() {
212
+ const {render} = Neo.main;
213
+
214
+ if (NeoConfig.useDomApiRenderer) {
215
+ if (!render?.DomApiRenderer) {
216
+ throw new Error('Neo.main.DeltaUpdates: DomApiRenderer is not loaded yet!')
217
+ }
218
+ } else {
219
+ if (!render?.StringBasedRenderer) {
220
+ throw new Error('Neo.main.DeltaUpdates: StringBasedRenderer is not loaded yet!')
202
221
  }
203
222
  }
204
223
  }
205
224
 
206
225
  /**
207
- * Moves an existing DOM node to a new position within its parent
208
- * or to a new parent.
209
- * This method directly manipulates the DOM using the pre-calculated physical index.
226
+ * Moves an existing DOM node to a new position within its parent or to a new parent.
227
+ * This method directly manipulates the DOM using the pre-calculated physical index,
228
+ * accounting for potential text nodes wrapped in comments.
229
+ * It performs a direct sibling swap when an element is immediately followed by its target position,
230
+ * which is necessary to prevent attempting to replace a node with itself.
210
231
  *
211
232
  * @param {Object} delta
212
233
  * @param {String} delta.id The ID of the DOM node to move.
213
- * @param {Number} delta.index The physical index at which to insert the node
234
+ * @param {Number} delta.index The physical index at which to insert the node within the target parent's childNodes.
214
235
  * @param {String} delta.parentId The ID of the target parent DOM node.
215
236
  */
216
237
  moveNode({id, index, parentId}) {
@@ -239,8 +260,25 @@ class DeltaUpdates extends Base {
239
260
  }
240
261
 
241
262
  /**
263
+ * Handler for global Neo.config changes.
264
+ * If the `Neo.config.useDomApiRenderer` value changes, this method dynamically loads the renderer.
265
+ * @param {Object} config
266
+ * @return {Promise<void>}
267
+ */
268
+ async onNeoConfigChange(config) {
269
+ if (Object.hasOwn(config, 'useDomApiRenderer')) {
270
+ await this.importRenderer()
271
+ }
272
+ }
273
+
274
+ /**
275
+ * Clears all child nodes of a given parent DOM node.
276
+ * This is achieved by setting its `innerHTML` property to an empty string,
277
+ * which is generally considered the fastest and most efficient way to remove
278
+ * all children from a DOM element in modern browsers.
279
+ *
242
280
  * @param {Object} delta
243
- * @param {String} delta.parentId
281
+ * @param {String} delta.parentId The ID of the parent DOM node whose children will be removed.
244
282
  */
245
283
  removeAll({parentId}) {
246
284
  let node = DomAccess.getElement(parentId);
@@ -251,9 +289,13 @@ class DeltaUpdates extends Base {
251
289
  }
252
290
 
253
291
  /**
292
+ * Removes a DOM node from its parent.
293
+ * This method handles both standard HTML elements and virtual text nodes,
294
+ * which are typically wrapped within comment nodes in the DOM.
295
+ *
254
296
  * @param {Object} delta
255
- * @param {String} delta.id
256
- * @param {String} delta.parentId
297
+ * @param {String} delta.id The ID of the DOM node to remove.
298
+ * @param {String} delta.parentId The ID of the parent DOM node (required for text node removal).
257
299
  */
258
300
  removeNode({id, parentId}) {
259
301
  const node = DomAccess.getElement(id);
@@ -289,10 +331,17 @@ class DeltaUpdates extends Base {
289
331
  }
290
332
 
291
333
  /**
334
+ * Replaces an existing child DOM node (`fromId`) with a new DOM node (`toId`)
335
+ * within a specified parent DOM node (`parentId`).
336
+ * This operation directly invokes the native `Node.replaceChild()` API,
337
+ * performing an atomic swap of the elements in the DOM tree.
338
+ * It is typically used when a specific DOM element needs to be completely
339
+ * exchanged for a different one at the same position.
340
+ *
292
341
  * @param {Object} delta
293
- * @param {String} delta.fromId
294
- * @param {String} delta.parentId
295
- * @param {String} delta.toId
342
+ * @param {String} delta.fromId The ID of the existing child DOM node to be replaced.
343
+ * @param {String} delta.parentId The ID of the parent DOM node containing the child to be replaced.
344
+ * @param {String} delta.toId The ID of the new DOM node that will replace the old one.
296
345
  */
297
346
  replaceChild({fromId, parentId, toId}) {
298
347
  let node = DomAccess.getElement(parentId);
@@ -301,26 +350,20 @@ class DeltaUpdates extends Base {
301
350
  }
302
351
 
303
352
  /**
353
+ * Updates various properties of an existing DOM node based on the provided delta.
354
+ * This includes updating attributes, class names, inner HTML, node name, and inline styles.
355
+ * It handles specific cases for attribute types (e.g., boolean attributes, 'value')
356
+ * and style properties (e.g., '!important').
357
+ *
304
358
  * @param {Object} delta
305
- * @param {String} [delta.id]
306
- * @param {String} [delta.value
307
- */
308
- setTextContent({id, value}) {
309
- let node = DomAccess.getElement(id);
310
-
311
- if (node) {
312
- node.textContent = value
313
- }
314
- }
315
-
316
- /**
317
- * @param {Object} delta
318
- * @param {Object} [delta.attributes]
319
- * @param {String} [delta.cls]
320
- * @param {String} [delta.id]
321
- * @param {String} [delta.innerHTML]
322
- * @param {String} [delta.outerHTML]
323
- * @param {Object} [delta.style]
359
+ * @param {String} delta.id The ID of the DOM node to update.
360
+ * @param {Object} [delta.attributes] An object containing attribute key-value pairs to update or remove (if value is null/empty).
361
+ * @param {Object} [delta.cls] An object containing 'add' and/or 'remove' arrays for CSS classes.
362
+ * @param {String} [delta.innerHTML] The new inner HTML content for the node.
363
+ * @param {String} [delta.nodeName] The new tag name for the node (will trigger a node replacement).
364
+ * @param {String} [delta.outerHTML] The new outer HTML content for the node (will trigger a node replacement).
365
+ * @param {Object} [delta.style] An object containing CSS style properties to update. Values can include '!important'.
366
+ * @param {String} [delta.textContent] The new text content for the node (replaces innerHTML if present).
324
367
  */
325
368
  updateNode(delta) {
326
369
  let me = this,
@@ -384,16 +427,25 @@ class DeltaUpdates extends Base {
384
427
  })
385
428
  }
386
429
  break
430
+ case 'textContent':
431
+ node.textContent = value;
432
+ break
387
433
  }
388
434
  })
389
435
  }
390
436
  }
391
437
 
392
438
  /**
439
+ * Updates the text content of a virtual text node within the DOM.
440
+ * Virtual text nodes are rendered within the DOM as a pair of HTML comments,
441
+ * with their content embedded between them. This method locates the specific
442
+ * text node by its ID (embedded in the start comment tag) within its parent's
443
+ * innerHTML and replaces its content using a regular expression.
444
+ *
393
445
  * @param {Object} delta
394
- * @param {String} delta.id
395
- * @param {String} delta.parentId
396
- * @param {String} delta.value
446
+ * @param {String} delta.id The unique ID of the virtual text node, which is embedded in its opening comment tag.
447
+ * @param {String} delta.parentId The ID of the parent DOM node whose `innerHTML` contains the virtual text node.
448
+ * @param {String} delta.value The new text content to be applied to the virtual text node.
397
449
  */
398
450
  updateVtext({id, parentId, value}) {
399
451
  let node = DomAccess.getElement(parentId),
@@ -405,17 +457,24 @@ class DeltaUpdates extends Base {
405
457
  }
406
458
 
407
459
  /**
460
+ * Applies a set of VDom delta updates to the real DOM.
461
+ * This method is the core entry point for rendering changes initiated from the VDom worker.
462
+ * It iterates through the provided deltas and dispatches them to specific DOM manipulation
463
+ * methods (e.g., insertNode, removeNode, updateNode) based on their `action` property.
464
+ * This method expects the appropriate renderer (DomApiRenderer or StringBasedRenderer)
465
+ * to be loaded based on `Neo.config.useDomApiRenderer`.
466
+ *
408
467
  * @param {Object} data
409
- * @param {Object|Object[]} data.deltas
410
- * @param {String} data.id
411
- * @param {String} [data.origin='app']
468
+ * @param {Object|Object[]} data.deltas An array of delta objects, or a single delta object,
469
+ * representing changes to be applied to the DOM.
470
+ * Each delta object contains an `action` property
471
+ * (e.g., 'insertNode', 'removeNode', 'updateNode', 'moveNode')
472
+ * and additional properties relevant to the specific action.
473
+ * @param {String} data.id The unique ID of the request, used for sending a reply back to the origin.
474
+ * @param {String} [data.origin='app'] The origin of the message (e.g., 'app'), used for sending replies.
412
475
  */
413
476
  update(data) {
414
- // This method is synchronous and *expects* the renderer to be loaded
415
- if (!this.#renderer) {
416
- console.error('DeltaUpdates renderer not ready during insertNode!');
417
- return
418
- }
477
+ this.checkRendererAvailability();
419
478
 
420
479
  let me = this,
421
480
  {deltas} = data,
@@ -37,6 +37,18 @@ class AmCharts extends Base {
37
37
  * @protected
38
38
  */
39
39
  fallbackPath: 'https://raw.githubusercontent.com/neomjs/pages/main/resources_pub/amCharts/',
40
+ /**
41
+ * List methods which must get cached until the addon reaches its `isReady` state
42
+ * @member {String[]} interceptRemotes
43
+ */
44
+ interceptRemotes: [
45
+ 'callMethod',
46
+ 'create',
47
+ 'destroy',
48
+ 'setProperties',
49
+ 'setProperty',
50
+ 'updateData'
51
+ ],
40
52
  /**
41
53
  * Remote method access for other workers
42
54
  * @member {Object} remote
@@ -91,19 +103,15 @@ class AmCharts extends Base {
91
103
  callMethod(data) {
92
104
  let me = this;
93
105
 
94
- if (!me.isReady) {
95
- return me.cacheMethodCall({fn: 'callMethod', data})
96
- } else {
97
- if (me.hasChart(data.id)) {
98
- let chart = me.charts[data.id],
99
- pathArray = data.path.split('.'),
100
- methodName = pathArray.pop(),
101
- scope = pathArray.length < 1 ? chart: Neo.ns(pathArray.join('.'), false, chart);
106
+ if (me.hasChart(data.id)) {
107
+ let chart = me.charts[data.id],
108
+ pathArray = data.path.split('.'),
109
+ methodName = pathArray.pop(),
110
+ scope = pathArray.length < 1 ? chart: Neo.ns(pathArray.join('.'), false, chart);
102
111
 
103
- scope[methodName].call(scope, ...data.params || [])
104
- } else {
105
- // todo
106
- }
112
+ scope[methodName].call(scope, ...data.params || [])
113
+ } else {
114
+ // todo
107
115
  }
108
116
  }
109
117
 
@@ -137,29 +145,25 @@ class AmCharts extends Base {
137
145
  create(data) {
138
146
  let me = this;
139
147
 
140
- if (!me.isReady) {
141
- return me.cacheMethodCall({fn: 'create', data})
142
- } else {
143
- // todo: check if globalThis[data.package] exists, if not load it and call create afterwards
144
- am4core.useTheme(am4themes_dark);
148
+ // todo: check if globalThis[data.package] exists, if not load it and call create afterwards
149
+ am4core.useTheme(am4themes_dark);
145
150
 
146
- me.charts[data.id] = am4core.createFromConfig(data.config, data.id, globalThis[data.package][data.type || 'XYChart']);
151
+ me.charts[data.id] = am4core.createFromConfig(data.config, data.id, globalThis[data.package][data.type || 'XYChart']);
147
152
 
148
- if (data.combineSeriesTooltip) {
149
- me.combineSeriesTooltip(me.charts[data.id])
150
- }
153
+ if (data.combineSeriesTooltip) {
154
+ me.combineSeriesTooltip(me.charts[data.id])
155
+ }
151
156
 
152
- // in case data has arrived before the chart got created, apply it now
153
- if (data.data) {
154
- me.updateData({
155
- data : data.data,
156
- dataPath: data.dataPath,
157
- id : data.id
158
- })
159
- } else if (me.dataMap[data.id]) {
160
- me.updateData(me.dataMap[data.id]);
161
- delete me.dataMap[data.id]
162
- }
157
+ // in case data has arrived before the chart got created, apply it now
158
+ if (data.data) {
159
+ me.updateData({
160
+ data : data.data,
161
+ dataPath: data.dataPath,
162
+ id : data.id
163
+ })
164
+ } else if (me.dataMap[data.id]) {
165
+ me.updateData(me.dataMap[data.id]);
166
+ delete me.dataMap[data.id]
163
167
  }
164
168
  }
165
169
 
@@ -167,15 +171,9 @@ class AmCharts extends Base {
167
171
  * @param {Object} data
168
172
  * @param {String} data.id
169
173
  */
170
- destroy(data) {
171
- let me = this;
172
-
173
- if (!me.isReady) {
174
- return me.cacheMethodCall({fn: 'destroy', data})
175
- } else {
176
- me.charts[data.id]?.dispose?.();
177
- delete me.charts[data.id]
178
- }
174
+ destroy({id}) {
175
+ this.charts[id]?.dispose?.();
176
+ delete this.charts[id]
179
177
  }
180
178
 
181
179
  /**
@@ -229,20 +227,10 @@ class AmCharts extends Base {
229
227
  * @param {String} data.id
230
228
  * @param {Object} data.properties
231
229
  */
232
- setProperties(data) {
233
- let me = this;
234
-
235
- if (!me.isReady) {
236
- return me.cacheMethodCall({fn: 'setProperties', data})
237
- } else {
238
- Object.entries(data.properties).forEach(([key, value]) => {
239
- me.setProperty({
240
- id : data.id,
241
- path : key,
242
- value
243
- })
244
- })
245
- }
230
+ setProperties({id, properties}) {
231
+ Object.entries(properties).forEach(([key, value]) => {
232
+ this.setProperty({id, path: key, value})
233
+ })
246
234
  }
247
235
 
248
236
  /**
@@ -252,22 +240,16 @@ class AmCharts extends Base {
252
240
  * @param {String} data.path
253
241
  * @param {*} data.value
254
242
  */
255
- setProperty(data) {
256
- let me = this;
257
-
258
- if (!me.isReady) {
259
- return me.cacheMethodCall({fn: 'setProperty', data})
243
+ setProperty({id, isColor=false, path, value}) {
244
+ if (this.hasChart(id)) {
245
+ let chart = this.charts[id],
246
+ pathArray = path.split('.'),
247
+ propertyName = pathArray.pop(),
248
+ scope = Neo.ns(pathArray.join('.'), false, chart);
249
+
250
+ scope[propertyName] = isColor ? am4core.color(value) : value
260
251
  } else {
261
- if (this.hasChart(data.id)) {
262
- let chart = this.charts[data.id],
263
- pathArray = data.path.split('.'),
264
- propertyName = pathArray.pop(),
265
- scope = Neo.ns(pathArray.join('.'), false, chart);
266
-
267
- scope[propertyName] = data.isColor ? am4core.color(data.value) : data.value
268
- } else {
269
- // todo
270
- }
252
+ // todo
271
253
  }
272
254
  }
273
255
 
@@ -280,9 +262,7 @@ class AmCharts extends Base {
280
262
  updateData(data) {
281
263
  let me = this;
282
264
 
283
- if (!me.isReady) {
284
- return me.cacheMethodCall({fn: 'updateData', data})
285
- } else if (!me.hasChart(data.id)) {
265
+ if (!me.hasChart(data.id)) {
286
266
  me.dataMap[data.id] = data
287
267
  } else {
288
268
  let chart = me.charts[data.id];
@@ -179,6 +179,17 @@ class Base extends CoreBase {
179
179
  */
180
180
  async loadFiles() {}
181
181
 
182
+ /**
183
+ * Handles intercepted remote method calls.
184
+ * If the addon is not ready, the call is cached using `cacheMethodCall()`.
185
+ * Otherwise, the original method is executed.
186
+ * @param {Object} msg The remote message object.
187
+ * @returns {Promise<any>} A promise that resolves with the method's return value.
188
+ */
189
+ onInterceptRemotes(msg) {
190
+ return this.cacheMethodCall({fn: msg.remoteMethod, data: msg.data})
191
+ }
192
+
182
193
  /**
183
194
  * Sequentially processes any method calls that were cached while the addon was not ready.
184
195
  * This method is asynchronous to allow awaiting the execution of individual cached methods.