neo.mjs 4.3.1 → 4.3.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.
@@ -13,7 +13,8 @@ class MainContainer extends ConfigurationViewport {
13
13
  static getConfig() {return {
14
14
  className : 'Neo.examples.tab.container.MainContainer',
15
15
  autoMount : true,
16
- configItemLabelWidth: 130,
16
+ configItemLabelWidth: 160,
17
+ configItemWidth : 280,
17
18
  layout : {ntype: 'hbox', align: 'stretch'}
18
19
  }}
19
20
 
@@ -121,6 +122,45 @@ class MainContainer extends ConfigurationViewport {
121
122
  labelText: 'Tab 1 text',
122
123
  listeners: {change: me.onFirstTabHeaderConfigChange.bind(me, 'text')},
123
124
  value : me.getFirstTabHeader().text
125
+ }, {
126
+ module : Radio,
127
+ checked : me.getBadgeTabHeader().badgePosition === 'bottom-left',
128
+ hideValueLabel: false,
129
+ labelText : 'badgePosition',
130
+ listeners : {change: me.onBadgeRadioChange.bind(me, 'badgePosition', 'bottom-left')},
131
+ name : 'badgePosition',
132
+ style : {marginTop: '50px'},
133
+ valueLabelText: 'bottom-left'
134
+ }, {
135
+ module : Radio,
136
+ checked : me.getBadgeTabHeader().badgePosition === 'bottom-right',
137
+ hideValueLabel: false,
138
+ labelText : '',
139
+ listeners : {change: me.onBadgeRadioChange.bind(me, 'badgePosition', 'bottom-right')},
140
+ name : 'badgePosition',
141
+ valueLabelText: 'bottom-right'
142
+ }, {
143
+ module : Radio,
144
+ checked : me.getBadgeTabHeader().badgePosition === 'top-left',
145
+ hideValueLabel: false,
146
+ labelText : '',
147
+ listeners : {change: me.onBadgeRadioChange.bind(me, 'badgePosition', 'top-left')},
148
+ name : 'badgePosition',
149
+ valueLabelText: 'top-left'
150
+ }, {
151
+ module : Radio,
152
+ checked : me.getBadgeTabHeader().badgePosition === 'top-right',
153
+ hideValueLabel: false,
154
+ labelText : '',
155
+ listeners : {change: me.onBadgeRadioChange.bind(me, 'badgePosition', 'top-right')},
156
+ name : 'badgePosition',
157
+ valueLabelText: 'top-right'
158
+ }, {
159
+ module : TextField,
160
+ labelText: 'badgeText',
161
+ listeners: {change: me.onBadgeConfigChange.bind(me, 'badgeText')},
162
+ style : {marginTop: '10px'},
163
+ value : me.getBadgeTabHeader().badgeText
124
164
  }];
125
165
  }
126
166
 
@@ -158,11 +198,17 @@ class MainContainer extends ConfigurationViewport {
158
198
  }
159
199
 
160
200
  /**
161
- * @param {String} config
162
- * @param {Object} opts
201
+ * @returns {Neo.tab.header.Button}
163
202
  */
164
- onFirstTabHeaderConfigChange(config, opts) {
165
- this.exampleComponent.getTabBar().items[0][config] = opts.value;
203
+ getBadgeTabHeader() {
204
+ let tabHeaders = this.exampleComponent.getTabBar().items,
205
+ item
206
+
207
+ for (item of tabHeaders) {
208
+ if (item.text === 'Tab 3') {
209
+ return item;
210
+ }
211
+ }
166
212
  }
167
213
 
168
214
  /**
@@ -172,6 +218,33 @@ class MainContainer extends ConfigurationViewport {
172
218
  return this.exampleComponent.getTabBar().items[0];
173
219
  }
174
220
 
221
+ /**
222
+ * @param {String} config
223
+ * @param {Object} opts
224
+ */
225
+ onBadgeConfigChange(config, opts) {
226
+ this.getBadgeTabHeader()[config] = opts.value;
227
+ }
228
+
229
+ /**
230
+ * @param {String} config
231
+ * @param {String} value
232
+ * @param {Object} opts
233
+ */
234
+ onBadgeRadioChange(config, value, opts) {
235
+ if (opts.value === true) { // we only want to listen to check events, not uncheck
236
+ this.getBadgeTabHeader()[config] = value;
237
+ }
238
+ }
239
+
240
+ /**
241
+ * @param {String} config
242
+ * @param {Object} opts
243
+ */
244
+ onFirstTabHeaderConfigChange(config, opts) {
245
+ this.exampleComponent.getTabBar().items[0][config] = opts.value;
246
+ }
247
+
175
248
  /**
176
249
  * @param {Object} data
177
250
  * @param {Neo.component.Base} data.component
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "4.3.1",
3
+ "version": "4.3.2",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -8,8 +8,13 @@
8
8
  flex : auto !important;
9
9
  font-weight: 400;
10
10
  overflow-y : auto;
11
+ position : relative;
11
12
  word-break : break-word;
12
13
 
14
+ .neo-absolute {
15
+ position: absolute;
16
+ }
17
+
13
18
  a {
14
19
  color: #1c60a0;
15
20
  }
@@ -109,4 +114,4 @@
109
114
  }
110
115
  }
111
116
  }
112
- }
117
+ }
@@ -64,27 +64,29 @@
64
64
  color : v(button-badge-color);
65
65
  margin-left : auto;
66
66
  padding : 3px;
67
+ pointer-events : none;
67
68
  position : absolute;
69
+ user-select : none;
68
70
  z-index : 2;
69
71
 
70
72
  &.neo-bottom-left {
71
- bottom: -10px;
72
- left : -10px;
73
+ bottom: v(button-badge-margin-top);
74
+ left : v(button-badge-margin-left);
73
75
  }
74
76
 
75
77
  &.neo-bottom-right {
76
- bottom: -10px;
77
- right : -10px;
78
+ bottom: v(button-badge-margin-top);
79
+ right : v(button-badge-margin-left);
78
80
  }
79
81
 
80
82
  &.neo-top-left {
81
- left: -10px;
82
- top : -10px;
83
+ left: v(button-badge-margin-left);
84
+ top : v(button-badge-margin-top);
83
85
  }
84
86
 
85
87
  &.neo-top-right {
86
- right: -10px;
87
- top : -10px;
88
+ right: v(button-badge-margin-left);
89
+ top : v(button-badge-margin-top);
88
90
  }
89
91
  }
90
92
 
@@ -1,3 +1,4 @@
1
1
  .neo-label {
2
+ user-select: none;
2
3
  white-space: nowrap;
3
- }
4
+ }
@@ -26,11 +26,13 @@
26
26
  }
27
27
 
28
28
  .neo-radio-label {
29
- color : v(textfield-label-color);
30
- display: inline-block;
29
+ color : v(textfield-label-color);
30
+ display : inline-block;
31
+ user-select: none;
31
32
  }
32
33
 
33
34
  .neo-radio-value-label {
34
- color: v(textfield-label-color);
35
+ color : v(textfield-label-color);
36
+ user-select: none;
35
37
  }
36
- }
38
+ }
@@ -232,8 +232,9 @@
232
232
  }
233
233
 
234
234
  .neo-textfield-label {
235
- color : v(textfield-label-color);
236
- display: inline-block;
237
- flex : 0 0 auto;
235
+ color : v(textfield-label-color);
236
+ display : inline-block;
237
+ flex : 0 0 auto;
238
+ user-select: none;
238
239
  }
239
240
  }
@@ -62,4 +62,4 @@
62
62
  animation-duration: 0ms !important;
63
63
  }
64
64
  }
65
- }
65
+ }
@@ -24,12 +24,45 @@
24
24
  }
25
25
  }
26
26
 
27
+ .neo-button-badge {
28
+ transform : rotate(180deg);
29
+ writing-mode: vertical-rl;
30
+
31
+ &.neo-bottom-left {
32
+ bottom: v(button-badge-margin-top);
33
+ left : unset;
34
+ right : v(button-badge-margin-left);
35
+ top : unset;
36
+ }
37
+
38
+ &.neo-bottom-right {
39
+ bottom: unset;
40
+ left : unset;
41
+ right : v(button-badge-margin-left);
42
+ top : v(button-badge-margin-top);
43
+ }
44
+
45
+ &.neo-top-left {
46
+ bottom: v(button-badge-margin-top);
47
+ left : v(button-badge-margin-left);
48
+ right : unset;
49
+ top : unset;
50
+ }
51
+
52
+ &.neo-top-right {
53
+ bottom: unset;
54
+ left : v(button-badge-margin-left);
55
+ right : unset;
56
+ top : v(button-badge-margin-top);
57
+ }
58
+ }
59
+
27
60
  .neo-button-glyph {
28
61
  transform: rotate(-90deg);
29
62
  }
30
63
 
31
64
  .neo-button-text {
32
- transform: rotate(180deg);
65
+ transform : rotate(180deg);
33
66
  writing-mode: vertical-rl;
34
67
  }
35
68
 
@@ -58,6 +91,38 @@
58
91
  }
59
92
  }
60
93
 
94
+ .neo-button-badge {
95
+ writing-mode: vertical-lr;
96
+
97
+ &.neo-bottom-left {
98
+ bottom: unset;
99
+ left : v(button-badge-margin-left);
100
+ right : unset;
101
+ top : v(button-badge-margin-top);
102
+ }
103
+
104
+ &.neo-bottom-right {
105
+ bottom: v(button-badge-margin-top);
106
+ left : v(button-badge-margin-left);
107
+ right : unset;
108
+ top : unset;
109
+ }
110
+
111
+ &.neo-top-left {
112
+ bottom: unset;
113
+ left : unset;
114
+ right : v(button-badge-margin-left);
115
+ top : v(button-badge-margin-top);
116
+ }
117
+
118
+ &.neo-top-right {
119
+ bottom: v(button-badge-margin-top);
120
+ left : unset;
121
+ right : v(button-badge-margin-left);
122
+ top : unset;
123
+ }
124
+ }
125
+
61
126
  .neo-button-glyph {
62
127
  transform: rotate(90deg);
63
128
  }
@@ -73,7 +138,8 @@
73
138
  }
74
139
  }
75
140
 
76
- &.neo-dock-bottom, &.neo-dock-top {
141
+ &.neo-dock-bottom,
142
+ &.neo-dock-top {
77
143
  .neo-button {
78
144
  &.icon-left {
79
145
  .neo-button-glyph {
@@ -85,4 +151,4 @@
85
151
  margin: 0 10px 0 5px;
86
152
  }
87
153
  }
88
- }
154
+ }
@@ -8,6 +8,8 @@ $neoMap: map-merge($neoMap, (
8
8
  'button-background-gradient-start': #434749,
9
9
  'button-badge-background-color' : #64b5f6,
10
10
  'button-badge-color' : #282828,
11
+ 'button-badge-margin-left' : -10px,
12
+ 'button-badge-margin-top' : -10px,
11
13
  'button-border' : 1px solid #2b2b2b,
12
14
  'button-border-radius' : 0,
13
15
  'button-glyph-color' : #bbb,
@@ -38,6 +40,8 @@ $neoMap: map-merge($neoMap, (
38
40
  --button-background-gradient-start: #{neo(button-background-gradient-start)};
39
41
  --button-badge-background-color : #{neo(button-badge-background-color)};
40
42
  --button-badge-color : #{neo(button-badge-color)};
43
+ --button-badge-margin-left : #{neo(button-badge-margin-left)};
44
+ --button-badge-margin-top : #{neo(button-badge-margin-top)};
41
45
  --button-border : #{neo(button-border)};
42
46
  --button-border-radius : #{neo(button-border-radius)};
43
47
  --button-glyph-color : #{neo(button-glyph-color)};
@@ -8,6 +8,8 @@ $neoMap: map-merge($neoMap, (
8
8
  'button-background-gradient-start': #434749,
9
9
  'button-badge-background-color' : #1c60a0,
10
10
  'button-badge-color' : #fff,
11
+ 'button-badge-margin-left' : -10px,
12
+ 'button-badge-margin-top' : -10px,
11
13
  'button-border' : 1px solid #ddd,
12
14
  'button-border-radius' : 3px,
13
15
  'button-glyph-color' : #1c60a0,
@@ -38,6 +40,8 @@ $neoMap: map-merge($neoMap, (
38
40
  --button-background-gradient-start: #{neo(button-background-gradient-start)};
39
41
  --button-badge-background-color : #{neo(button-badge-background-color)};
40
42
  --button-badge-color : #{neo(button-badge-color)};
43
+ --button-badge-margin-left : #{neo(button-badge-margin-left)};
44
+ --button-badge-margin-top : #{neo(button-badge-margin-top)};
41
45
  --button-border : #{neo(button-border)};
42
46
  --button-border-radius : #{neo(button-border-radius)};
43
47
  --button-glyph-color : #{neo(button-glyph-color)};
@@ -255,10 +255,10 @@ class Base extends CoreBase {
255
255
  */
256
256
  silentVdomUpdate: false,
257
257
  /**
258
- * Top level style attributes
259
- * @member {Object} style={}
258
+ * Style attributes added to this vdom root. see: getVdomRoot()
259
+ * @member {Object} style_=null
260
260
  */
261
- style: {},
261
+ style_: null,
262
262
  /**
263
263
  * Add tooltip config objects
264
264
  * See tooltip/Base.mjs
@@ -321,23 +321,6 @@ class Base extends CoreBase {
321
321
  }
322
322
  }
323
323
 
324
- /**
325
- * Top level style attributes
326
- * @member {Object} style={}
327
- */
328
- get style() {
329
- // we need to "clone" the object, otherwise changes will get applied directly and there are no deltas
330
- // this only affects non vdom related style to DOM deltas
331
- return Neo.clone(this._style || {});
332
- }
333
- set style(value) {
334
- let me = this,
335
- oldStyle = me.style; // cloned => getter
336
-
337
- me._style = value;
338
- me.updateStyle(value, oldStyle);
339
- }
340
-
341
324
  /**
342
325
  * The setter will handle vdom updates automatically
343
326
  * @member {Object} vdom=this._vdom
@@ -346,45 +329,7 @@ class Base extends CoreBase {
346
329
  return this._vdom;
347
330
  }
348
331
  set vdom(value) {
349
- let me = this,
350
- app = Neo.apps[me.appName],
351
- vdom = value,
352
- listenerId;
353
-
354
- // It is important to keep the vdom tree stable to ensure that containers do not lose the references to their
355
- // child vdom trees. The if case should not happen, but in case it does, keeping the reference and merging
356
- // the content over seems to be the best strategy
357
- if (me._vdom !== vdom) {
358
- Logger.warn('vdom got replaced for: ' + me.id + '. Copying the content into the reference holder object');
359
-
360
- Object.keys(me._vdom).forEach(key => {
361
- delete me._vdom[key];
362
- });
363
-
364
- Object.assign(me._vdom, vdom);
365
- } else {
366
- me._vdom = vdom;
367
- }
368
-
369
- if (me.silentVdomUpdate) {
370
- me.needsVdomUpdate = true;
371
- } else {
372
- if (!me.mounted && me.isConstructed && !me.hasRenderingListener && app?.rendering === true) {
373
- me.hasRenderingListener = true;
374
-
375
- listenerId = app.on('mounted', () => {
376
- app.un('mounted', listenerId);
377
-
378
- setTimeout(() => {
379
- me.vnode && me.updateVdom(me.vdom, me.vnode);
380
- }, 50);
381
- });
382
- } else if (me.mounted) {
383
- me.vnode && me.updateVdom(vdom, me.vnode);
384
- }
385
-
386
- me.hasUnmountedVdomChanges = !me.mounted && me.hasBeenMounted;
387
- }
332
+ this.afterSetVdom(value, value);
388
333
  }
389
334
 
390
335
  /**
@@ -665,6 +610,18 @@ class Base extends CoreBase {
665
610
  }
666
611
  }
667
612
 
613
+ /**
614
+ * Triggered after the style config got changed
615
+ * @param {Object} value
616
+ * @param {Object} oldValue
617
+ * @protected
618
+ */
619
+ afterSetStyle(value, oldValue) {
620
+ if (!(!value && oldValue === undefined)) {
621
+ this.updateStyle(value, oldValue);
622
+ }
623
+ }
624
+
668
625
  /**
669
626
  * Triggered after the tooltips config got changed
670
627
  * @param {Boolean} value
@@ -685,6 +642,54 @@ class Base extends CoreBase {
685
642
  }
686
643
  }
687
644
 
645
+ /**
646
+ * Triggered after the vdom config got changed
647
+ * @param {Object} value
648
+ * @param {Object|null} oldValue
649
+ * @protected
650
+ */
651
+ afterSetVdom(value, oldValue) {
652
+ let me = this,
653
+ app = Neo.apps[me.appName],
654
+ vdom = value,
655
+ listenerId;
656
+
657
+ // It is important to keep the vdom tree stable to ensure that containers do not lose the references to their
658
+ // child vdom trees. The if case should not happen, but in case it does, keeping the reference and merging
659
+ // the content over seems to be the best strategy
660
+ if (me._vdom !== vdom) {
661
+ Logger.warn('vdom got replaced for: ' + me.id + '. Copying the content into the reference holder object');
662
+
663
+ Object.keys(me._vdom).forEach(key => {
664
+ delete me._vdom[key];
665
+ });
666
+
667
+ Object.assign(me._vdom, vdom);
668
+ } else {
669
+ me._vdom = vdom;
670
+ }
671
+
672
+ if (me.silentVdomUpdate) {
673
+ me.needsVdomUpdate = true;
674
+ } else {
675
+ if (!me.mounted && me.isConstructed && !me.hasRenderingListener && app?.rendering === true) {
676
+ me.hasRenderingListener = true;
677
+
678
+ listenerId = app.on('mounted', () => {
679
+ app.un('mounted', listenerId);
680
+
681
+ setTimeout(() => {
682
+ me.vnode && me.updateVdom(me.vdom, me.vnode);
683
+ }, 50);
684
+ });
685
+ } else if (me.mounted) {
686
+ me.vnode && me.updateVdom(vdom, me.vnode);
687
+ }
688
+
689
+ me.hasUnmountedVdomChanges = !me.mounted && me.hasBeenMounted;
690
+ }
691
+ }
692
+
688
693
  /**
689
694
  * Triggered after the vnode config got changed
690
695
  * @param {Object} value
@@ -714,15 +719,22 @@ class Base extends CoreBase {
714
719
  * @protected
715
720
  */
716
721
  afterSetWrapperCls(value, oldValue) {
722
+ oldValue = oldValue ? oldValue : [];
723
+ value = value ? value : [];
724
+
717
725
  let me = this,
718
726
  vdom = me.vdom,
719
727
  vdomRoot = me.getVdomRoot(),
720
728
  cls = me.vdom?.cls || [];
721
729
 
722
730
  if (vdom === vdomRoot) {
723
- // we are not using a wrapper => cls & wrapperCls share the same node
724
- me.afterSetCls(me._cls, me._cls);
731
+ // we need to merge changes
732
+ cls = [...cls, ...value];
733
+ NeoArray.remove(cls, NeoArray.difference(oldValue, value));
734
+ vdom.cls = cls;
735
+
725
736
  } else {
737
+ // we are not using a wrapper => cls & wrapperCls share the same node
726
738
  value = value ? value : [];
727
739
 
728
740
  oldValue && NeoArray.remove(cls, oldValue);
@@ -731,12 +743,12 @@ class Base extends CoreBase {
731
743
  if (vdom) {
732
744
  vdom.cls = cls;
733
745
  }
746
+ }
734
747
 
735
- if (me.isVdomUpdating || me.silentVdomUpdate) {
736
- me.needsVdomUpdate = true;
737
- } else if (me.mounted) {
738
- me.updateCls(value, oldValue);
739
- }
748
+ if (me.isVdomUpdating || me.silentVdomUpdate) {
749
+ me.needsVdomUpdate = true;
750
+ } else if (me.mounted) {
751
+ me.updateCls(value, oldValue);
740
752
  }
741
753
  }
742
754
 
@@ -780,6 +792,15 @@ class Base extends CoreBase {
780
792
  return this.getModel().getHierarchyData();
781
793
  }
782
794
 
795
+ /**
796
+ * Triggered when accessing the style config
797
+ * @param {Object} value
798
+ * @protected
799
+ */
800
+ beforeGetStyle(value) {
801
+ return {...value};
802
+ }
803
+
783
804
  /**
784
805
  * Triggered when accessing the wrapperCls config
785
806
  * @param {String[]|null} value
@@ -171,10 +171,11 @@ class Base extends Component {
171
171
 
172
172
  /**
173
173
  * @param {Object|String} value
174
+ * @param {Object|String|Neo.layout.Base} oldValue
174
175
  * @returns {Neo.layout.Base}
175
176
  * @protected
176
177
  */
177
- beforeSetLayout(value) {
178
+ beforeSetLayout(value, oldValue) {
178
179
  return this.createLayout(value);
179
180
  }
180
181
 
@@ -458,8 +459,7 @@ class Base extends Component {
458
459
  if (config.ntype.indexOf('layout-') < 0) {
459
460
  config.ntype = 'layout-' + config.ntype;
460
461
  }
461
- }
462
- else if (config.indexOf('layout-') < 0) {
462
+ } else if (config.indexOf('layout-') < 0) {
463
463
  config = {
464
464
  ntype: 'layout-' + config
465
465
  };
@@ -47,15 +47,14 @@ class DragZone extends BaseDragZone {
47
47
  adjustToolbarItemCls(draggable) {
48
48
  let me = this,
49
49
  owner = me.owner,
50
- vdom = owner.vdom;
50
+ wrapperCls;
51
51
 
52
- vdom.cn.forEach(item => {
53
- item.cls = item.cls || [];
52
+ owner.items.forEach(item => {
53
+ wrapperCls = item.wrapperCls || [];
54
54
 
55
- NeoArray[draggable ? 'add' : 'remove'](item.cls, 'neo-draggable');
55
+ NeoArray[draggable ? 'add' : 'remove'](wrapperCls, 'neo-draggable');
56
+ item.wrapperCls = wrapperCls;
56
57
  });
57
-
58
- owner.vdom = vdom;
59
58
  }
60
59
 
61
60
  /**
@@ -893,11 +893,13 @@ class Text extends Base {
893
893
  onFocusLeave(data) {
894
894
  let me = this,
895
895
  centerBorderEl = me.getCenterBorderEl(), // labelPosition: 'inline'
896
+ cls = me.cls,
896
897
  vdom = me.vdom;
897
898
 
898
899
  me.validate(); // silent
899
900
 
900
- NeoArray.remove(me._cls, 'neo-focus');
901
+ NeoArray.remove(cls, 'neo-focus');
902
+ me.cls = cls;
901
903
 
902
904
  if (centerBorderEl && me.isEmpty()) {
903
905
  delete centerBorderEl.width;
@@ -82,7 +82,7 @@ class Flexbox extends Base {
82
82
  * @protected
83
83
  */
84
84
  afterSetAlign(value, oldValue) {
85
- this.updateInputValue(value, oldValue, 'align');
85
+ oldValue && this.updateInputValue(value, oldValue, 'align');
86
86
  }
87
87
 
88
88
  /**
@@ -92,7 +92,7 @@ class Flexbox extends Base {
92
92
  * @protected
93
93
  */
94
94
  afterSetDirection(value, oldValue) {
95
- this.updateInputValue(value, oldValue, 'direction');
95
+ oldValue && this.updateInputValue(value, oldValue, 'direction');
96
96
  }
97
97
 
98
98
  /**
@@ -102,7 +102,7 @@ class Flexbox extends Base {
102
102
  * @protected
103
103
  */
104
104
  afterSetPack(value, oldValue) {
105
- this.updateInputValue(value, oldValue, 'pack');
105
+ oldValue && this.updateInputValue(value, oldValue, 'pack');
106
106
  }
107
107
 
108
108
  /**
@@ -112,7 +112,7 @@ class Flexbox extends Base {
112
112
  * @protected
113
113
  */
114
114
  afterSetWrap(value, oldValue) {
115
- this.updateInputValue(value, oldValue, 'wrap');
115
+ oldValue && this.updateInputValue(value, oldValue, 'wrap');
116
116
  }
117
117
 
118
118
  /**