neo.mjs 9.0.0 → 9.0.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.
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='9.0.0'
23
+ * @member {String} version='9.0.2'
24
24
  */
25
- version: '9.0.0'
25
+ version: '9.0.2'
26
26
  }
27
27
 
28
28
  /**
@@ -16,7 +16,7 @@
16
16
  "@type": "Organization",
17
17
  "name": "Neo.mjs"
18
18
  },
19
- "datePublished": "2025-05-03",
19
+ "datePublished": "2025-05-12",
20
20
  "publisher": {
21
21
  "@type": "Organization",
22
22
  "name": "Neo.mjs"
@@ -316,11 +316,10 @@ class ViewportController extends Controller {
316
316
 
317
317
  // enable "fast clicking" on main nav items => do not replace a cube layout with a new instance of cube
318
318
  if (container.layout.ntype !== 'layout-cube') {
319
- container.layout = {ntype: 'cube', activeIndex, fitContainer: true, hideInactiveCardsOnDestroy: true}
319
+ container.layout = {ntype: 'cube', activeIndex, fitContainer: true, hideInactiveCardsOnDestroy: true};
320
+ await me.timeout(200);
320
321
  }
321
322
 
322
- await me.timeout(200);
323
-
324
323
  container.layout.activeIndex = index;
325
324
 
326
325
  await me.timeout(1100);
@@ -107,7 +107,7 @@ class FooterContainer extends Container {
107
107
  }, {
108
108
  module: Component,
109
109
  cls : ['neo-version'],
110
- html : 'v9.0.0'
110
+ html : 'v9.0.2'
111
111
  }]
112
112
  }],
113
113
  /**
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='9.0.0'
23
+ * @member {String} version='9.0.2'
24
24
  */
25
- version: '9.0.0'
25
+ version: '9.0.2'
26
26
  }
27
27
 
28
28
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "9.0.0",
3
+ "version": "9.0.2",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -52,20 +52,20 @@
52
52
  "chalk": "^5.4.1",
53
53
  "clean-webpack-plugin": "^4.0.0",
54
54
  "commander": "^13.1.0",
55
- "cssnano": "^7.0.6",
55
+ "cssnano": "^7.0.7",
56
56
  "envinfo": "^7.14.0",
57
57
  "fs-extra": "^11.3.0",
58
58
  "highlightjs-line-numbers.js": "^2.9.0",
59
- "inquirer": "^12.6.0",
59
+ "inquirer": "^12.6.1",
60
60
  "marked": "^15.0.11",
61
61
  "monaco-editor": "0.50.0",
62
62
  "neo-jsdoc": "1.0.1",
63
63
  "neo-jsdoc-x": "1.0.5",
64
64
  "postcss": "^8.5.3",
65
- "sass": "^1.87.0",
65
+ "sass": "^1.88.0",
66
66
  "siesta-lite": "5.5.2",
67
67
  "url": "^0.11.4",
68
- "webpack": "^5.99.7",
68
+ "webpack": "^5.99.8",
69
69
  "webpack-cli": "^6.0.1",
70
70
  "webpack-dev-server": "^5.2.1",
71
71
  "webpack-hook-plugin": "^1.0.7",
@@ -0,0 +1,64 @@
1
+ ## Introduction
2
+
3
+ Modern JavaScript frameworks have revolutionized front-end development by providing declarative ways to build
4
+ user interfaces, primarily centered around enhancing HTML with custom syntax like JSX or Angular directives.
5
+ However, the complexity of applications extends far beyond the Document Object Model (DOM), encompassing crucial
6
+ non-DOM entities such as data stores, state providers, routers, view controllers, selection models, and layouts.
7
+ While existing frameworks offer solutions for managing these aspects, they often lack a truly consistent, declarative,
8
+ and nested approach to their configuration, a gap that a class config system aims to fill.
9
+
10
+ ## A bad example
11
+ I recently found this Angular code snippet (new public API draft) on LinkedIn:
12
+
13
+ <pre data-javascript>
14
+ // MyComponent with an attribute
15
+ <MyComponent myAttribute="someValue" />
16
+
17
+ // MyComponent with an input binding
18
+ <MyComponent [myInput]="mySignal()" />
19
+
20
+ // MyComponent is the host element
21
+ <MyComponent @MyDirective />
22
+
23
+ // Same as the selector: a[mat-button], anchor element is the host element
24
+ <MatButton:a></MatButton:a>
25
+
26
+ // Scoped inputs for MyDirective
27
+ <MyComponent @MyDirective(input1="someString" [input2]="mySignal()") />
28
+ </pre>
29
+
30
+ Now you might wonder why I think that this is not a good way to create apps.
31
+
32
+ Currently, the configuration and management of these non-DOM entities can feel somewhat disparate across different
33
+ frameworks. State management, for instance, might involve dedicated libraries (like Redux or Vuex), routing is
34
+ handled by router-specific configurations, and layouts might be defined through a mix of component composition and
35
+ potentially separate layout configurations. While these solutions are functional, they don't always present a
36
+ unified configuration tree that mirrors the nested, hierarchical structure often used for describing the UI.
37
+ The syntax and patterns for configuring a data store can be quite different from those used to define a route or
38
+ a view controller.
39
+
40
+ This is where the benefit of a class config system becomes apparent. The vision is a system that allows developers
41
+ to describe the desired state and relationships of all application components, regardless of whether they directly
42
+ interact with the DOM, using a consistent, declarative, and nested configuration structure.
43
+
44
+ Imagine defining your application's data stores, their initial states, and how they relate to each other, alongside
45
+ the routes of your application, the view controllers responsible for handling those routes, and the layouts they will
46
+ use – all within a unified configuration syntax. This nested structure would clearly illustrate the dependencies and
47
+ composition of the application's various parts, offering a holistic view that is often obscured when non-DOM elements
48
+ are configured in isolation using different mechanisms.
49
+
50
+ ## Key advantages
51
+ A class config system, by treating all application entities as configurable classes within a unified hierarchy,
52
+ offers several key advantages:
53
+
54
+ * ***Consistency***: Provides a single, predictable way to configure any part of the application, reducing the cognitive load on developers who would otherwise need to learn and context-switch between different configuration paradigms for DOM and non-DOM elements.
55
+ * ***Declarative Clarity***: Enables developers to declare the desired state and relationships of their application's components in a clear and concise manner, rather than writing imperative code to set up and connect these entities. This improves readability and maintainability.
56
+ * ***Nested Structure***: Allows for the natural expression of hierarchical relationships between components, whether they are parent-child UI elements or a router managing various routes, each with associated view controllers and data requirements. This mirrors the often tree-like structure of applications.
57
+ * ***Improved Maintainability***: Changes to the application's structure or behavior can be made in a centralized and organized configuration, rather than spread across various imperative code snippets and disparate configuration files.
58
+ * ***Enhanced Tooling and Abstraction***: A unified system provides a solid foundation for building powerful development tools, such as visual editors or automatic documentation generators, that can understand and manipulate the entire application's structure. It also allows for higher levels of abstraction, potentially simplifying the definition of complex application patterns.
59
+ * ***Reactive Configuration***: Similar to how UI frameworks react to state changes and update the DOM, a reactive class config system can react to changes in the configuration itself (in a development context, for example) to facilitate hot module replacement or dynamic updates of non-DOM entities.
60
+
61
+ While existing frameworks have made significant strides in declarative UI development, the concept of extending this
62
+ declarative, nested configuration approach consistently to all aspects of an application, particularly the non-DOM realm,
63
+ represents a powerful next step. A class config system holds the promise of a more unified, maintainable, and
64
+ understandable way to build complex modern web applications.
@@ -3,6 +3,7 @@
3
3
  {"name": "Benefits", "parentId": null, "isLeaf": false, "id": "Benefits"},
4
4
  {"name": "Introduction ", "parentId": "Benefits", "id": "benefits.Introduction"},
5
5
  {"name": "Off the Main Thread", "parentId": "Benefits", "id": "benefits.Multi-Threading"},
6
+ {"name": "Unified Config System", "parentId": "Benefits", "id": "benefits.ConfigSystem"},
6
7
  {"name": "Extreme Speed", "parentId": "Benefits", "id": "benefits.Speed"},
7
8
  {"name": "Multi-Window Applications", "parentId": "Benefits", "id": "benefits.Multi-Window"},
8
9
  {"name": "Quick Application Development", "parentId": "Benefits", "id": "benefits.Quick"},
@@ -263,12 +263,12 @@ const DefaultConfig = {
263
263
  useVdomWorker: true,
264
264
  /**
265
265
  * buildScripts/injectPackageVersion.mjs will update this value
266
- * @default '9.0.0'
266
+ * @default '9.0.2'
267
267
  * @memberOf! module:Neo
268
268
  * @name config.version
269
269
  * @type String
270
270
  */
271
- version: '9.0.0'
271
+ version: '9.0.2'
272
272
  };
273
273
 
274
274
  Object.assign(DefaultConfig, {
@@ -331,7 +331,7 @@ class Container extends Component {
331
331
  parent = item.parent;
332
332
 
333
333
  if (parent && parent !== me) {
334
- parent.remove(item, false);
334
+ parent.remove?.(item, false);
335
335
  delete item.vdom.removeDom;
336
336
 
337
337
  // Convenience logic, especially for moving components into different browser windows:
@@ -155,7 +155,7 @@ class RecordFactory extends Base {
155
155
  me[isModifiedSymbol] = false
156
156
  }
157
157
 
158
- me.setSilent(config); // We do not want to fire change events when constructing
158
+ me.setSilent(config) // We do not want to fire change events when constructing
159
159
  }
160
160
 
161
161
  /**
@@ -77,9 +77,10 @@ class Layout extends Base {
77
77
  applyChildAttributes(item, index) {}
78
78
 
79
79
  /**
80
+ * @param {Boolean} silent=false
80
81
  * @protected
81
82
  */
82
- applyRenderAttributes() {
83
+ applyRenderAttributes(silent=false) {
83
84
  let me = this,
84
85
  {container, containerCls} = me,
85
86
  {wrapperCls} = container;
@@ -91,7 +92,7 @@ class Layout extends Base {
91
92
 
92
93
  NeoArray.add(wrapperCls, containerCls);
93
94
 
94
- container.wrapperCls = wrapperCls
95
+ container[silent ? 'setSilent' : 'set']({wrapperCls})
95
96
  }
96
97
  }
97
98
 
@@ -286,44 +286,15 @@ class Cube extends Card {
286
286
  }
287
287
 
288
288
  /**
289
- *
289
+ * @returns {String}
290
290
  */
291
- destroy(...args) {
292
- let me = this,
293
- {container} = me,
294
- {style, vdom} = container;
295
-
296
- Object.assign(style, {
297
- '--perspective': null,
298
- '--rot-x' : null,
299
- '--rot-y' : null,
300
- '--rot-z' : null,
301
- '--side-x' : null,
302
- '--side-y' : null,
303
- '--side-z' : null
304
- });
305
-
306
- container.style = style;
307
-
308
- vdom.cn = container.getVdomItemsRoot().cn;
309
-
310
- if (me.hideInactiveCardsOnDestroy) {
311
- container.items.forEach((item, index) => {
312
- if (index < 6 && index !== me.activeIndex) {
313
- item.vdom.removeDom = true
314
- }
315
- })
316
- }
317
-
318
- // override
319
- container.getVdomItemsRoot = me.#cachedVdomItemsRoot;
320
-
321
- container.updateDepth = -1;
322
- container.update();
323
-
324
- super.destroy(...args)
291
+ getPlaneId() {
292
+ return this.id + '__plane'
325
293
  }
326
294
 
295
+ /**
296
+ *
297
+ */
327
298
  nestVdom() {
328
299
  let me = this,
329
300
  {container} = me,
@@ -331,7 +302,7 @@ class Cube extends Card {
331
302
  {cn} = vdom;
332
303
 
333
304
  vdom.cn = [
334
- {cls: ['neo-plane'], cn: [
305
+ {cls: ['neo-plane'], id: me.getPlaneId(), cn: [
335
306
  {cls: ['neo-box'], cn}
336
307
  ]}
337
308
  ];
@@ -394,7 +365,40 @@ class Cube extends Card {
394
365
  */
395
366
  removeRenderAttributes() {
396
367
  super.removeRenderAttributes();
397
- this.container.removeCls('neo-animate')
368
+
369
+ let me = this,
370
+ {container} = me,
371
+ {cls, style, vdom} = container;
372
+
373
+ NeoArray.remove(cls, 'neo-animate');
374
+
375
+ Object.assign(style, {
376
+ '--perspective': null,
377
+ '--rot-x' : null,
378
+ '--rot-y' : null,
379
+ '--rot-z' : null,
380
+ '--side-x' : null,
381
+ '--side-y' : null,
382
+ '--side-z' : null
383
+ });
384
+
385
+ container.set({cls, style});
386
+
387
+ vdom.cn = container.getVdomItemsRoot().cn;
388
+
389
+ if (me.hideInactiveCardsOnDestroy) {
390
+ container.items.forEach((item, index) => {
391
+ if (index < 6 && index !== me.activeIndex) {
392
+ item.vdom.removeDom = true
393
+ }
394
+ })
395
+ }
396
+
397
+ // override
398
+ container.getVdomItemsRoot = me.#cachedVdomItemsRoot;
399
+
400
+ container.updateDepth = -1;
401
+ container.update();
398
402
  }
399
403
 
400
404
  /**
@@ -58,12 +58,6 @@ class Container extends BaseContainer {
58
58
  * @protected
59
59
  */
60
60
  scrollbarsCssApplied: false,
61
- /**
62
- * Will get removed in neo v9, assign selection models to table.View instead
63
- * @member {Neo.selection.Model} selectionModel_=null
64
- * @deprecated
65
- */
66
- selectionModel_: null,
67
61
  /**
68
62
  * @member {Boolean} showHeaderFilters_=false
69
63
  */
@@ -139,11 +133,10 @@ class Container extends BaseContainer {
139
133
  sortable : me.sortable,
140
134
  ...me.headerToolbarConfig
141
135
  }, {
142
- module : View,
143
- containerId : me.id,
144
- id : me.viewId,
145
- selectionModel: me.selectionModel, // todo: remove this line in neo v9
146
- store : me.store,
136
+ module : View,
137
+ containerId: me.id,
138
+ id : me.viewId,
139
+ store : me.store,
147
140
  ...me.viewConfig
148
141
  }];
149
142
 
@@ -195,19 +188,6 @@ class Container extends BaseContainer {
195
188
  }
196
189
  }
197
190
 
198
- /**
199
- * Triggered after the selectionModel config got changed
200
- * @param {Neo.selection.Model} value
201
- * @param {Neo.selection.Model} oldValue
202
- * @protected
203
- * @deprecated
204
- */
205
- afterSetSelectionModel(value, oldValue) {
206
- if (value && this.view) {
207
- this.view.selectionModel = value
208
- }
209
- }
210
-
211
191
  /**
212
192
  * Triggered after the showHeaderFilters config got changed
213
193
  * @param {Boolean} value