neo.mjs 10.0.0-beta.6 → 10.0.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/.github/RELEASE_NOTES/v10.0.0-beta.1.md +20 -0
- package/.github/RELEASE_NOTES/v10.0.0-beta.2.md +73 -0
- package/.github/RELEASE_NOTES/v10.0.0-beta.3.md +39 -0
- package/.github/RELEASE_NOTES/v10.0.0.md +52 -0
- package/ServiceWorker.mjs +2 -2
- package/apps/portal/index.html +1 -1
- package/apps/portal/view/ViewportController.mjs +6 -4
- package/apps/portal/view/examples/List.mjs +28 -19
- package/apps/portal/view/home/FooterContainer.mjs +1 -1
- package/examples/functional/button/base/MainContainer.mjs +207 -0
- package/examples/functional/button/base/app.mjs +6 -0
- package/examples/functional/button/base/index.html +11 -0
- package/examples/functional/button/base/neo-config.json +6 -0
- package/learn/blog/v10-deep-dive-functional-components.md +293 -0
- package/learn/blog/v10-deep-dive-reactivity.md +522 -0
- package/learn/blog/v10-deep-dive-state-provider.md +432 -0
- package/learn/blog/v10-deep-dive-vdom-revolution.md +194 -0
- package/learn/blog/v10-post1-love-story.md +383 -0
- package/learn/guides/uibuildingblocks/WorkingWithVDom.md +26 -2
- package/package.json +3 -3
- package/src/DefaultConfig.mjs +2 -2
- package/src/Neo.mjs +47 -45
- package/src/component/Abstract.mjs +412 -0
- package/src/component/Base.mjs +18 -380
- package/src/core/Base.mjs +34 -33
- package/src/core/Effect.mjs +30 -34
- package/src/core/EffectManager.mjs +101 -14
- package/src/core/Observable.mjs +69 -65
- package/src/form/field/Text.mjs +11 -5
- package/src/functional/button/Base.mjs +384 -0
- package/src/functional/component/Base.mjs +51 -145
- package/src/layout/Cube.mjs +8 -4
- package/src/manager/VDomUpdate.mjs +179 -94
- package/src/mixin/VdomLifecycle.mjs +4 -1
- package/src/state/Provider.mjs +41 -27
- package/src/util/VDom.mjs +11 -4
- package/src/util/vdom/TreeBuilder.mjs +38 -62
- package/src/worker/mixin/RemoteMethodAccess.mjs +1 -6
- package/test/siesta/siesta.js +15 -3
- package/test/siesta/tests/VdomCalendar.mjs +7 -7
- package/test/siesta/tests/VdomHelper.mjs +7 -7
- package/test/siesta/tests/classic/Button.mjs +113 -0
- package/test/siesta/tests/core/EffectBatching.mjs +46 -41
- package/test/siesta/tests/functional/Button.mjs +113 -0
- package/test/siesta/tests/state/ProviderNestedDataConfigs.mjs +59 -0
- package/test/siesta/tests/vdom/Advanced.mjs +14 -8
- package/test/siesta/tests/vdom/VdomAsymmetricUpdates.mjs +9 -9
- package/test/siesta/tests/vdom/VdomRealWorldUpdates.mjs +6 -6
- package/test/siesta/tests/vdom/layout/Cube.mjs +11 -7
- package/test/siesta/tests/vdom/table/Container.mjs +9 -5
- package/src/core/EffectBatchManager.mjs +0 -67
package/src/component/Base.mjs
CHANGED
@@ -1,35 +1,27 @@
|
|
1
|
-
import
|
1
|
+
import Abstract from './Abstract.mjs';
|
2
2
|
import ClassSystemUtil from '../util/ClassSystem.mjs';
|
3
3
|
import ComponentManager from '../manager/Component.mjs';
|
4
|
-
import DomEvents from '../mixin/DomEvents.mjs';
|
5
4
|
import KeyNavigation from '../util/KeyNavigation.mjs';
|
6
5
|
import Logger from '../util/Logger.mjs';
|
7
6
|
import NeoArray from '../util/Array.mjs';
|
8
|
-
import Observable from '../core/Observable.mjs';
|
9
7
|
import Rectangle from '../util/Rectangle.mjs';
|
10
8
|
import Style from '../util/Style.mjs';
|
11
|
-
import VdomLifecycle from '../mixin/VdomLifecycle.mjs';
|
12
9
|
import VDomUtil from '../util/VDom.mjs';
|
13
10
|
import VNodeUtil from '../util/VNode.mjs';
|
14
11
|
import {isDescriptor} from '../core/ConfigSymbols.mjs';
|
15
12
|
|
16
13
|
const
|
17
|
-
addUnits
|
18
|
-
closestController
|
19
|
-
|
20
|
-
|
21
|
-
lengthRE = /^\d+\w+$/,
|
22
|
-
twoWayBindingSymbol = Symbol.for('twoWayBinding');
|
14
|
+
addUnits = value => value == null ? value : isNaN(value) ? value : `${value}px`,
|
15
|
+
closestController = Symbol.for('closestController'),
|
16
|
+
{currentWorker} = Neo,
|
17
|
+
lengthRE = /^\d+\w+$/;
|
23
18
|
|
24
19
|
/**
|
25
20
|
* Base class for all Components which have a DOM representation
|
26
21
|
* @class Neo.component.Base
|
27
|
-
* @extends Neo.
|
28
|
-
* @mixes Neo.component.mixin.DomEvents
|
29
|
-
* @mixes Neo.core.Observable
|
30
|
-
* @mixes Neo.component.mixin.VdomLifecycle
|
22
|
+
* @extends Neo.component.Abstract
|
31
23
|
*/
|
32
|
-
class Component extends
|
24
|
+
class Component extends Abstract {
|
33
25
|
/**
|
34
26
|
* Valid values for hideMode
|
35
27
|
* @member {String[]} hideModes=['removeDom','visibility']
|
@@ -63,36 +55,11 @@ class Component extends Base {
|
|
63
55
|
constrainTo: 'document.body'
|
64
56
|
}
|
65
57
|
},
|
66
|
-
/**
|
67
|
-
* The name of the App this component belongs to
|
68
|
-
* @member {String|null} appName_=null
|
69
|
-
* @reactive
|
70
|
-
*/
|
71
|
-
appName_: null,
|
72
58
|
/**
|
73
59
|
* CSS selectors to apply to the root level node of this component
|
74
60
|
* @member {String[]} baseCls=[]
|
75
61
|
*/
|
76
62
|
baseCls: [],
|
77
|
-
/**
|
78
|
-
* Bind configs to state.Provider data properties.
|
79
|
-
* Example for a button.Base:
|
80
|
-
* @example
|
81
|
-
* bind: {
|
82
|
-
* iconCls: data => `fa fa-{$data.icon}`,
|
83
|
-
* text : data => data.foo.bar
|
84
|
-
* }
|
85
|
-
* @see https://github.com/neomjs/neo/blob/dev/examples/stateProvider
|
86
|
-
* @member {Object|null} bind=null
|
87
|
-
*/
|
88
|
-
bind: null,
|
89
|
-
/**
|
90
|
-
* Custom CSS selectors to apply to the root level node of this component
|
91
|
-
* You can override baseCls to remove default selectors.
|
92
|
-
* @member {String[]} cls_=null
|
93
|
-
* @reactive
|
94
|
-
*/
|
95
|
-
cls_: null,
|
96
63
|
/**
|
97
64
|
* manager.Focus will change this flag on focusin & out dom events
|
98
65
|
* @member {Boolean} containsFocus_=false
|
@@ -106,20 +73,6 @@ class Component extends Base {
|
|
106
73
|
* @reactive
|
107
74
|
*/
|
108
75
|
controller_: null,
|
109
|
-
/**
|
110
|
-
* Convenience shortcut to access the data config of the closest state.Provider.
|
111
|
-
* Read only.
|
112
|
-
* @member {Object} data_=null
|
113
|
-
* @protected
|
114
|
-
* @reactive
|
115
|
-
*/
|
116
|
-
data_: null,
|
117
|
-
/**
|
118
|
-
* Disabled components will get the neo-disabled cls applied and won't receive DOM events
|
119
|
-
* @member {Boolean} disabled_=false
|
120
|
-
* @reactive
|
121
|
-
*/
|
122
|
-
disabled_: false,
|
123
76
|
/**
|
124
77
|
* Set this config to true to dynamically import a DropZone module & create an instance
|
125
78
|
* @member {Boolean} droppable_=false
|
@@ -214,31 +167,6 @@ class Component extends Base {
|
|
214
167
|
* @reactive
|
215
168
|
*/
|
216
169
|
minWidth_: null,
|
217
|
-
/**
|
218
|
-
* @member {Neo.core.Base[]} mixins=[DomEvents, Observable, VdomLifecycle]
|
219
|
-
*/
|
220
|
-
mixins: [DomEvents, Observable, VdomLifecycle],
|
221
|
-
/**
|
222
|
-
* Override specific stateProvider data properties.
|
223
|
-
* This will merge the content.
|
224
|
-
* @member {Object|null} modelData=null
|
225
|
-
*/
|
226
|
-
modelData: null,
|
227
|
-
/**
|
228
|
-
* If the parentId does not match a neo component id, you can manually set this value for finding
|
229
|
-
* view controllers or state providers.
|
230
|
-
* Use case: manually dropping components into a vdom structure
|
231
|
-
* @member {Neo.component.Base|null} parentComponent_=null
|
232
|
-
* @protected
|
233
|
-
* @reactive
|
234
|
-
*/
|
235
|
-
parentComponent_: null,
|
236
|
-
/**
|
237
|
-
* The parent component id or document.body
|
238
|
-
* @member {String} parentId_='document.body'
|
239
|
-
* @reactive
|
240
|
-
*/
|
241
|
-
parentId_: 'document.body',
|
242
170
|
/**
|
243
171
|
* Array of Plugin Modules and / or config objects
|
244
172
|
* @member {Array|null} plugins_=null
|
@@ -276,12 +204,6 @@ class Component extends Base {
|
|
276
204
|
* @reactive
|
277
205
|
*/
|
278
206
|
scrollable_: false,
|
279
|
-
/**
|
280
|
-
* Optionally add a state.Provider to share state data with child components
|
281
|
-
* @member {Object|null} stateProvider_=null
|
282
|
-
* @reactive
|
283
|
-
*/
|
284
|
-
stateProvider_: null,
|
285
207
|
/**
|
286
208
|
* Style attributes added to this vdom root. see: getVdomRoot()
|
287
209
|
* @member {Object} style={[isDescriptor]: true, merge: 'shallow', value: null}
|
@@ -337,12 +259,6 @@ class Component extends Base {
|
|
337
259
|
* @reactive
|
338
260
|
*/
|
339
261
|
width_: null,
|
340
|
-
/**
|
341
|
-
* The custom windowIs (timestamp) this component belongs to
|
342
|
-
* @member {Number|null} windowId_=null
|
343
|
-
* @reactive
|
344
|
-
*/
|
345
|
-
windowId_: null,
|
346
262
|
/**
|
347
263
|
* @member {String[]|null} wrapperCls_=null
|
348
264
|
* @reactive
|
@@ -365,21 +281,6 @@ class Component extends Base {
|
|
365
281
|
_vdom: {}
|
366
282
|
}
|
367
283
|
|
368
|
-
/**
|
369
|
-
* Internal flag which will get set to true while a component is waiting for its mountedPromise
|
370
|
-
* @member {Boolean} isAwaitingMount=false
|
371
|
-
* @protected
|
372
|
-
*/
|
373
|
-
isAwaitingMount = false
|
374
|
-
|
375
|
-
/**
|
376
|
-
* Convenience shortcut to access the App this component belongs to
|
377
|
-
* @returns {Neo.controller.Application|null}
|
378
|
-
*/
|
379
|
-
get app() {
|
380
|
-
return Neo.apps[this.appName] || null
|
381
|
-
}
|
382
|
-
|
383
284
|
/**
|
384
285
|
* Returns true if this Component is fully visible, that is it is not hidden and has no hidden ancestors
|
385
286
|
*/
|
@@ -387,54 +288,6 @@ class Component extends Base {
|
|
387
288
|
return this.mounted && !this.hidden && (!this.parent || this.parent.isVisible);
|
388
289
|
}
|
389
290
|
|
390
|
-
/**
|
391
|
-
* Apply component based listeners
|
392
|
-
* @member {Object} listeners={}
|
393
|
-
*/
|
394
|
-
get listeners() {
|
395
|
-
return this._listeners || {}
|
396
|
-
}
|
397
|
-
set listeners(value) {
|
398
|
-
this._listeners = value
|
399
|
-
}
|
400
|
-
|
401
|
-
/**
|
402
|
-
* A Promise that resolves when the component is mounted to the DOM.
|
403
|
-
* This provides a convenient way to wait for the component to be fully
|
404
|
-
* available and interactive before executing subsequent logic.
|
405
|
-
*
|
406
|
-
* It also handles unmounting by resetting the promise, so it can be safely
|
407
|
-
* awaited again if the component is remounted.
|
408
|
-
* @returns {Promise<Neo.component.Base>}
|
409
|
-
*/
|
410
|
-
get mountedPromise() {
|
411
|
-
let me = this;
|
412
|
-
|
413
|
-
if (!me._mountedPromise) {
|
414
|
-
me._mountedPromise = new Promise(resolve => {
|
415
|
-
if (me.mounted) {
|
416
|
-
// If already mounted, resolve immediately.
|
417
|
-
resolve(me)
|
418
|
-
} else {
|
419
|
-
// Otherwise, store the resolver to be called by afterSetMounted.
|
420
|
-
me.mountedPromiseResolve = resolve
|
421
|
-
}
|
422
|
-
})
|
423
|
-
}
|
424
|
-
|
425
|
-
return this._mountedPromise
|
426
|
-
}
|
427
|
-
|
428
|
-
/**
|
429
|
-
* Convenience method to access the parent component
|
430
|
-
* @returns {Neo.component.Base|null}
|
431
|
-
*/
|
432
|
-
get parent() {
|
433
|
-
let me = this;
|
434
|
-
|
435
|
-
return me.parentComponent || (me.parentId === 'document.body' ? null : Neo.getComponent(me.parentId))
|
436
|
-
}
|
437
|
-
|
438
291
|
/**
|
439
292
|
* True after the component render() method was called. Also fires the rendered event.
|
440
293
|
* @member {Boolean} rendered=false
|
@@ -541,30 +394,6 @@ class Component extends Base {
|
|
541
394
|
me.update()
|
542
395
|
}
|
543
396
|
|
544
|
-
/**
|
545
|
-
* Triggered after any config got changed
|
546
|
-
* @param {String} key
|
547
|
-
* @param {*} value
|
548
|
-
* @param {*} oldValue
|
549
|
-
* @protected
|
550
|
-
*/
|
551
|
-
afterSetConfig(key, value, oldValue) {
|
552
|
-
let me = this;
|
553
|
-
|
554
|
-
if (Neo.isUsingStateProviders && me[twoWayBindingSymbol]) {
|
555
|
-
// When a component config is updated by its state provider, this flag is set to the config's key.
|
556
|
-
// This prevents circular updates in two-way data bindings by skipping the push back to the state provider.
|
557
|
-
if (me._skipTwoWayPush === key) {
|
558
|
-
return;
|
559
|
-
}
|
560
|
-
let binding = me.bind?.[key];
|
561
|
-
|
562
|
-
if (binding?.twoWay) {
|
563
|
-
this.getStateProvider()?.setData(binding.key, value)
|
564
|
-
}
|
565
|
-
}
|
566
|
-
}
|
567
|
-
|
568
397
|
/**
|
569
398
|
* Triggered after the disabled config got changed
|
570
399
|
* @param {Boolean} value
|
@@ -655,10 +484,7 @@ class Component extends Base {
|
|
655
484
|
*/
|
656
485
|
afterSetId(value, oldValue) {
|
657
486
|
super.afterSetId(value, oldValue);
|
658
|
-
this.changeVdomRootKey('id', value)
|
659
|
-
|
660
|
-
oldValue && ComponentManager.unregister(oldValue);
|
661
|
-
value && ComponentManager.register(this)
|
487
|
+
this.changeVdomRootKey('id', value)
|
662
488
|
}
|
663
489
|
|
664
490
|
/**
|
@@ -746,31 +572,24 @@ class Component extends Base {
|
|
746
572
|
* @protected
|
747
573
|
*/
|
748
574
|
afterSetMounted(value, oldValue) {
|
575
|
+
super.afterSetMounted(value, oldValue);
|
576
|
+
|
749
577
|
if (oldValue !== undefined) {
|
750
|
-
let me
|
751
|
-
{id, windowId} = me;
|
578
|
+
let me = this;
|
752
579
|
|
753
580
|
if (value) { // mount
|
754
581
|
me.hasBeenMounted = true;
|
755
582
|
|
756
|
-
me.initDomEvents();
|
757
|
-
|
758
583
|
if (me.floating) {
|
759
584
|
me.alignTo();
|
760
585
|
|
761
586
|
// Focus will be pushed into the first input field or other focusable item
|
762
|
-
me.focus(id, true)
|
587
|
+
me.focus(me.id, true)
|
763
588
|
}
|
764
589
|
|
765
|
-
me.mountedPromiseResolve?.(this);
|
766
|
-
delete me.mountedPromiseResolve;
|
767
|
-
|
768
590
|
me.fire('mounted', me.id);
|
769
591
|
} else { // unmount
|
770
|
-
me.revertFocus()
|
771
|
-
|
772
|
-
// The promise needs to get reset, in case the component gets remounted.
|
773
|
-
delete me._mountedPromise;
|
592
|
+
me.revertFocus()
|
774
593
|
}
|
775
594
|
}
|
776
595
|
}
|
@@ -856,16 +675,6 @@ class Component extends Base {
|
|
856
675
|
}
|
857
676
|
}
|
858
677
|
|
859
|
-
/**
|
860
|
-
* Triggered after the stateProvider config got changed
|
861
|
-
* @param {Neo.state.Provider} value
|
862
|
-
* @param {Object|Neo.state.Provider|null} oldValue
|
863
|
-
* @protected
|
864
|
-
*/
|
865
|
-
afterSetStateProvider(value, oldValue) {
|
866
|
-
value?.createBindings(this)
|
867
|
-
}
|
868
|
-
|
869
678
|
/**
|
870
679
|
* Triggered after the style config got changed
|
871
680
|
* @param {Object} value
|
@@ -987,21 +796,12 @@ class Component extends Base {
|
|
987
796
|
* @protected
|
988
797
|
*/
|
989
798
|
afterSetWindowId(value, oldValue) {
|
990
|
-
|
991
|
-
controller = me.controller;
|
992
|
-
|
993
|
-
if (value) {
|
994
|
-
currentWorker.insertThemeFiles(value, me.__proto__);
|
799
|
+
super.afterSetWindowId(value, oldValue);
|
995
800
|
|
996
|
-
|
997
|
-
controller.windowId = value
|
998
|
-
}
|
999
|
-
}
|
801
|
+
let controller = this.controller;
|
1000
802
|
|
1001
|
-
|
1002
|
-
|
1003
|
-
if (oldValue) {
|
1004
|
-
me.isVdomUpdating = false
|
803
|
+
if (controller) {
|
804
|
+
controller.windowId = value
|
1005
805
|
}
|
1006
806
|
}
|
1007
807
|
|
@@ -1085,16 +885,6 @@ class Component extends Base {
|
|
1085
885
|
return value ? [...value] : []
|
1086
886
|
}
|
1087
887
|
|
1088
|
-
/**
|
1089
|
-
* Triggered when accessing the data config
|
1090
|
-
* Convenience shortcut which is expensive to use, since it will generate a merged parent state providers data map.
|
1091
|
-
* @param {Object} value
|
1092
|
-
* @protected
|
1093
|
-
*/
|
1094
|
-
beforeGetData(value) {
|
1095
|
-
return this.getStateProvider().getHierarchyData()
|
1096
|
-
}
|
1097
|
-
|
1098
888
|
/**
|
1099
889
|
* Triggered when accessing the style config
|
1100
890
|
* @param {Object} value
|
@@ -1255,31 +1045,6 @@ class Component extends Base {
|
|
1255
1045
|
return (Neo.isNumber(oldValue) && oldValue > 0) ? (oldValue - 1) : 0
|
1256
1046
|
}
|
1257
1047
|
|
1258
|
-
/**
|
1259
|
-
* Triggered before the stateProvider config gets changed.
|
1260
|
-
* Creates a state.Provider instance if needed.
|
1261
|
-
* @param {Object} value
|
1262
|
-
* @param {Object} oldValue
|
1263
|
-
* @returns {Neo.state.Provider}
|
1264
|
-
* @protected
|
1265
|
-
*/
|
1266
|
-
beforeSetStateProvider(value, oldValue) {
|
1267
|
-
oldValue?.destroy();
|
1268
|
-
|
1269
|
-
if (value) {
|
1270
|
-
let me = this,
|
1271
|
-
defaultValues = {component: me};
|
1272
|
-
|
1273
|
-
if (me.modelData) {
|
1274
|
-
defaultValues.data = me.modelData
|
1275
|
-
}
|
1276
|
-
|
1277
|
-
return ClassSystemUtil.beforeSetInstance(value, 'Neo.state.Provider', defaultValues)
|
1278
|
-
}
|
1279
|
-
|
1280
|
-
return null
|
1281
|
-
}
|
1282
|
-
|
1283
1048
|
/**
|
1284
1049
|
* Triggered before the updateDepth config gets changed.
|
1285
1050
|
* @param {Number} value
|
@@ -1377,14 +1142,10 @@ class Component extends Base {
|
|
1377
1142
|
|
1378
1143
|
me.revertFocus();
|
1379
1144
|
|
1380
|
-
me.removeDomEvents();
|
1381
|
-
|
1382
1145
|
me.controller = null; // triggers destroy()
|
1383
1146
|
|
1384
1147
|
me.reference && me.getController()?.removeReference(me); // remove own reference from parent controllers
|
1385
1148
|
|
1386
|
-
me.stateProvider = null; // triggers destroy()
|
1387
|
-
|
1388
1149
|
me.plugins?.forEach(plugin => {
|
1389
1150
|
plugin.destroy()
|
1390
1151
|
});
|
@@ -1400,8 +1161,6 @@ class Component extends Base {
|
|
1400
1161
|
}
|
1401
1162
|
}
|
1402
1163
|
|
1403
|
-
ComponentManager.unregister(me);
|
1404
|
-
|
1405
1164
|
super.destroy();
|
1406
1165
|
|
1407
1166
|
// We do want to prevent delayed calls after a component instance got destroyed.
|
@@ -1442,35 +1201,6 @@ class Component extends Base {
|
|
1442
1201
|
return result
|
1443
1202
|
}
|
1444
1203
|
|
1445
|
-
/**
|
1446
|
-
* Find an instance stored inside a config via optionally passing a ntype.
|
1447
|
-
* Returns this[configName] or the closest parent component with a match.
|
1448
|
-
* Used by getController() & getStateProvider()
|
1449
|
-
* @param {String} configName
|
1450
|
-
* @param {String} [ntype]
|
1451
|
-
* @returns {Neo.core.Base|null}
|
1452
|
-
*/
|
1453
|
-
getConfigInstanceByNtype(configName, ntype) {
|
1454
|
-
let me = this,
|
1455
|
-
config = me[configName],
|
1456
|
-
{parentComponent} = me;
|
1457
|
-
|
1458
|
-
if (config && (!ntype || ntype === config.ntype)) {
|
1459
|
-
return config
|
1460
|
-
}
|
1461
|
-
|
1462
|
-
if (!parentComponent && me.parentId) {
|
1463
|
-
parentComponent = me.parent || Neo.get(me.parentId);
|
1464
|
-
}
|
1465
|
-
|
1466
|
-
if (parentComponent) {
|
1467
|
-
// todo: We need ?. until functional.component.Base supports controllers
|
1468
|
-
return parentComponent.getConfigInstanceByNtype?.(configName, ntype)
|
1469
|
-
}
|
1470
|
-
|
1471
|
-
return null
|
1472
|
-
}
|
1473
|
-
|
1474
1204
|
/**
|
1475
1205
|
* Returns this.controller or the closest parent controller
|
1476
1206
|
* @param {String} [ntype]
|
@@ -1564,45 +1294,6 @@ class Component extends Base {
|
|
1564
1294
|
return this.down({reference: value})
|
1565
1295
|
}
|
1566
1296
|
|
1567
|
-
/**
|
1568
|
-
* Convenience shortcut
|
1569
|
-
* @param args
|
1570
|
-
* @returns {*}
|
1571
|
-
*/
|
1572
|
-
getState(...args) {
|
1573
|
-
return this.getStateProvider().getData(...args)
|
1574
|
-
}
|
1575
|
-
|
1576
|
-
/**
|
1577
|
-
* Returns this.stateProvider or the closest parent stateProvider
|
1578
|
-
* @param {String} [ntype]
|
1579
|
-
* @returns {Neo.state.Provider|null}
|
1580
|
-
*/
|
1581
|
-
getStateProvider(ntype) {
|
1582
|
-
if (!Neo.isUsingStateProviders) {
|
1583
|
-
return null
|
1584
|
-
}
|
1585
|
-
|
1586
|
-
let me = this,
|
1587
|
-
provider;
|
1588
|
-
|
1589
|
-
if (!ntype) {
|
1590
|
-
provider = me[closestProvider];
|
1591
|
-
|
1592
|
-
if (provider) {
|
1593
|
-
return provider
|
1594
|
-
}
|
1595
|
-
}
|
1596
|
-
|
1597
|
-
provider = me.getConfigInstanceByNtype('stateProvider', ntype);
|
1598
|
-
|
1599
|
-
if (!ntype) {
|
1600
|
-
me[closestProvider] = provider
|
1601
|
-
}
|
1602
|
-
|
1603
|
-
return provider
|
1604
|
-
}
|
1605
|
-
|
1606
1297
|
/**
|
1607
1298
|
* Walks up the vdom tree and returns the closest theme found
|
1608
1299
|
* @returns {String}
|
@@ -1677,14 +1368,6 @@ class Component extends Base {
|
|
1677
1368
|
this.autoRender && this.render()
|
1678
1369
|
}
|
1679
1370
|
|
1680
|
-
/**
|
1681
|
-
* @param args
|
1682
|
-
*/
|
1683
|
-
initConfig(...args) {
|
1684
|
-
super.initConfig(...args);
|
1685
|
-
this.getStateProvider()?.createBindings(this)
|
1686
|
-
}
|
1687
|
-
|
1688
1371
|
/**
|
1689
1372
|
* Check if this component or any of its parents is floating
|
1690
1373
|
* @returns {Boolean}
|
@@ -1794,12 +1477,11 @@ class Component extends Base {
|
|
1794
1477
|
*
|
1795
1478
|
*/
|
1796
1479
|
onConstructed() {
|
1797
|
-
super.onConstructed()
|
1480
|
+
super.onConstructed();
|
1798
1481
|
|
1799
1482
|
let me = this;
|
1800
1483
|
|
1801
1484
|
me.keys?.register(me);
|
1802
|
-
me.getStateProvider()?.createBindings(me)
|
1803
1485
|
}
|
1804
1486
|
|
1805
1487
|
/**
|
@@ -1892,50 +1574,6 @@ class Component extends Base {
|
|
1892
1574
|
}
|
1893
1575
|
}
|
1894
1576
|
|
1895
|
-
/**
|
1896
|
-
* Change multiple configs at once, ensuring that all afterSet methods get all new assigned values
|
1897
|
-
* @param {Object} values={}
|
1898
|
-
* @param {Boolean} silent=false
|
1899
|
-
* @returns {Promise<*>}
|
1900
|
-
*/
|
1901
|
-
set(values={}, silent=false) {
|
1902
|
-
const
|
1903
|
-
me = this,
|
1904
|
-
wasHidden = me.hidden;
|
1905
|
-
|
1906
|
-
me.setSilent(values);
|
1907
|
-
|
1908
|
-
if (!silent && me.needsVdomUpdate) {
|
1909
|
-
if (wasHidden && !me.hidden) {
|
1910
|
-
me.show();
|
1911
|
-
return Promise.resolve()
|
1912
|
-
}
|
1913
|
-
|
1914
|
-
return me.promiseUpdate()
|
1915
|
-
}
|
1916
|
-
|
1917
|
-
return Promise.resolve()
|
1918
|
-
}
|
1919
|
-
|
1920
|
-
/**
|
1921
|
-
* A silent version of set(), which does not trigger a vdom update at the end.
|
1922
|
-
* Useful for batching multiple config changes.
|
1923
|
-
* @param {Object} values={}
|
1924
|
-
*/
|
1925
|
-
setSilent(values={}) {
|
1926
|
-
this.silentVdomUpdate = true;
|
1927
|
-
super.set(values);
|
1928
|
-
this.silentVdomUpdate = false
|
1929
|
-
}
|
1930
|
-
|
1931
|
-
/**
|
1932
|
-
* Convenience shortcut
|
1933
|
-
* @param args
|
1934
|
-
*/
|
1935
|
-
setState(...args) {
|
1936
|
-
this.getStateProvider().setData(...args)
|
1937
|
-
}
|
1938
|
-
|
1939
1577
|
/**
|
1940
1578
|
* Show the component.
|
1941
1579
|
* hideMode: 'removeDom' uses vdom removeDom.
|
package/src/core/Base.mjs
CHANGED
@@ -4,7 +4,8 @@ import Util from '../core/Ut
|
|
4
4
|
import Config from './Config.mjs';
|
5
5
|
import {isDescriptor} from './ConfigSymbols.mjs';
|
6
6
|
import IdGenerator from './IdGenerator.mjs';
|
7
|
-
import
|
7
|
+
import EffectManager from './EffectManager.mjs';
|
8
|
+
|
8
9
|
|
9
10
|
const configSymbol = Symbol.for('configSymbol'),
|
10
11
|
forceAssignConfigs = Symbol('forceAssignConfigs'),
|
@@ -233,8 +234,6 @@ class Base {
|
|
233
234
|
me.id = config.id || IdGenerator.getId(this.getIdKey());
|
234
235
|
delete config.id;
|
235
236
|
|
236
|
-
me.getStaticConfig('observable') && me.initObservable(config);
|
237
|
-
|
238
237
|
// assign class field values prior to configs
|
239
238
|
config = me.setFields(config);
|
240
239
|
|
@@ -325,9 +324,9 @@ class Base {
|
|
325
324
|
*
|
326
325
|
* @example
|
327
326
|
* // Imagine you have hundreds of buttons in your app, and you want all of them
|
328
|
-
* // to have `labelPosition: 'top'` instead of the default `'left'`.
|
327
|
+
* // to have `labelPosition: 'top'` instead of the default `'left'`.
|
329
328
|
* // Instead of configuring each instance, you can define an overwrite.
|
330
|
-
*
|
329
|
+
*
|
331
330
|
* // inside an Overwrites.mjs file loaded by your app:
|
332
331
|
* Neo.overwrites = {
|
333
332
|
* Neo: {
|
@@ -338,7 +337,7 @@ class Base {
|
|
338
337
|
* }
|
339
338
|
* }
|
340
339
|
* };
|
341
|
-
*
|
340
|
+
*
|
342
341
|
* // Now, every `Neo.button.Base` (and any class that extends it) will have this
|
343
342
|
* // new default value on its prototype.
|
344
343
|
*
|
@@ -826,40 +825,42 @@ class Base {
|
|
826
825
|
let me = this,
|
827
826
|
classFieldsViaSet = {};
|
828
827
|
|
829
|
-
//
|
830
|
-
|
831
|
-
|
832
|
-
values = me.setFields(values);
|
828
|
+
// Prevent Effects from running for bulk changes
|
829
|
+
EffectManager.pause();
|
833
830
|
|
834
|
-
|
835
|
-
|
836
|
-
// See: https://github.com/neomjs/neo/issues/2201
|
837
|
-
if (me[forceAssignConfigs] !== true && Object.keys(me[configSymbol]).length > 0) {
|
838
|
-
me.processConfigs()
|
839
|
-
}
|
831
|
+
try {
|
832
|
+
values = me.setFields(values);
|
840
833
|
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
834
|
+
// If the initial config processing is still running,
|
835
|
+
// finish this one first before dropping new values into the configSymbol.
|
836
|
+
// See: https://github.com/neomjs/neo/issues/2201
|
837
|
+
if (me[forceAssignConfigs] !== true && Object.keys(me[configSymbol]).length > 0) {
|
838
|
+
me.processConfigs()
|
846
839
|
}
|
847
|
-
})
|
848
840
|
|
849
|
-
|
850
|
-
|
841
|
+
// Store class fields which are defined via get() & set() and ensure they won't get added to the config symbol.
|
842
|
+
Object.entries(values).forEach(([key, value]) => {
|
843
|
+
if (!me.isConfig(key)) {
|
844
|
+
classFieldsViaSet[key] = value;
|
845
|
+
delete values[key]
|
846
|
+
}
|
847
|
+
})
|
851
848
|
|
852
|
-
|
853
|
-
|
854
|
-
Object.entries(classFieldsViaSet).forEach(([key, value]) => {
|
855
|
-
me[key] = value
|
856
|
-
})
|
849
|
+
// Add reactive configs to the configSymbol
|
850
|
+
Object.assign(me[configSymbol], values);
|
857
851
|
|
858
|
-
|
859
|
-
|
852
|
+
// Process class fields which are defined via get() & set() => now they can access the latest values
|
853
|
+
// for reactive and non-reactive configs, as well as class fields defined with values.
|
854
|
+
Object.entries(classFieldsViaSet).forEach(([key, value]) => {
|
855
|
+
me[key] = value
|
856
|
+
})
|
860
857
|
|
861
|
-
|
862
|
-
|
858
|
+
// Process reactive configs
|
859
|
+
me.processConfigs(true);
|
860
|
+
} finally {
|
861
|
+
// Trigger the skipped Effect, if needed
|
862
|
+
EffectManager.resume()
|
863
|
+
}
|
863
864
|
}
|
864
865
|
|
865
866
|
/**
|