neo.mjs 5.10.3 → 5.10.5

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 (55) hide show
  1. package/apps/ServiceWorker.mjs +2 -2
  2. package/buildScripts/createClass.mjs +10 -2
  3. package/examples/ConfigurationViewport.mjs +6 -2
  4. package/examples/ServiceWorker.mjs +2 -2
  5. package/examples/component/process/MainContainer.mjs +90 -0
  6. package/examples/component/process/app.mjs +6 -0
  7. package/examples/component/process/index.html +11 -0
  8. package/examples/component/process/neo-config.json +6 -0
  9. package/examples/component/process/realWorldExample/MainContainer.mjs +334 -0
  10. package/examples/component/process/realWorldExample/RangeHeader.jpg +0 -0
  11. package/examples/component/process/realWorldExample/app.mjs +6 -0
  12. package/examples/component/process/realWorldExample/index.html +11 -0
  13. package/examples/component/process/realWorldExample/neo-config.json +6 -0
  14. package/examples/component/progress/MainContainer.mjs +71 -0
  15. package/examples/component/progress/app.mjs +6 -0
  16. package/examples/component/progress/index.html +11 -0
  17. package/examples/component/progress/neo-config.json +6 -0
  18. package/examples/component/toast/MainContainer.mjs +9 -6
  19. package/examples/component/toast/MainContainerController.mjs +5 -5
  20. package/examples/component/toast/neo-config.json +1 -1
  21. package/examples/container/accordion/MainContainer.mjs +123 -0
  22. package/examples/container/accordion/app.mjs +6 -0
  23. package/examples/container/accordion/index.html +11 -0
  24. package/examples/container/accordion/neo-config.json +6 -0
  25. package/package.json +3 -3
  26. package/resources/scss/src/component/Process.scss +2 -4
  27. package/resources/scss/src/component/Progress.scss +3 -0
  28. package/resources/scss/src/container/Accordion.scss +25 -0
  29. package/resources/scss/src/container/AccordionItem.scss +83 -0
  30. package/resources/scss/src/container/Dialog.scss +11 -1
  31. package/resources/scss/src/form/field/CheckBox.scss +1 -0
  32. package/resources/scss/src/form/field/Range.scss +1 -0
  33. package/resources/scss/theme-dark/component/Process.scss +8 -8
  34. package/resources/scss/theme-dark/component/Progress.scss +9 -0
  35. package/resources/scss/theme-dark/container/Accordion.scss +13 -0
  36. package/resources/scss/theme-dark/container/AccordionItem.scss +23 -0
  37. package/resources/scss/theme-light/component/Process.scss +7 -7
  38. package/resources/scss/theme-light/component/Progress.scss +9 -0
  39. package/resources/scss/theme-light/container/Accordion.scss +13 -0
  40. package/resources/scss/theme-light/container/AccordionItem.scss +23 -0
  41. package/src/DefaultConfig.mjs +2 -2
  42. package/src/component/Process.mjs +11 -7
  43. package/src/component/Progress.mjs +113 -0
  44. package/src/component/Splitter.mjs +5 -4
  45. package/src/component/Toast.mjs +2 -1
  46. package/src/container/Accordion.mjs +130 -0
  47. package/src/container/AccordionItem.mjs +178 -0
  48. package/src/container/Dialog.mjs +37 -54
  49. package/src/form/Container.mjs +42 -25
  50. package/src/form/field/Number.mjs +49 -37
  51. package/src/form/field/Range.mjs +31 -4
  52. package/src/form/field/TextArea.mjs +3 -2
  53. package/src/main/DomEvents.mjs +2 -1
  54. package/src/manager/Toast.mjs +5 -1
  55. package/src/util/String.mjs +56 -0
@@ -0,0 +1,113 @@
1
+ import Base from '../component/Base.mjs';
2
+
3
+ /**
4
+ * @class Neo.component.Progress
5
+ * @extends Neo.component.Base
6
+ */
7
+ class Progress extends Base {
8
+ static config = {
9
+ /**
10
+ * @member {String} className='Neo.component.Progress'
11
+ * @protected
12
+ */
13
+ className: 'Neo.component.Progress',
14
+ /**
15
+ * @member {String} ntype='progress'
16
+ * @protected
17
+ */
18
+ ntype: 'progress',
19
+ /**
20
+ * @member {String[]} baseCls=['neo-progress-label']
21
+ * @protected
22
+ */
23
+ baseCls: ['neo-progress'],
24
+ /**
25
+ * @member {String|null} labelText_=null
26
+ */
27
+ labelText_: null,
28
+ /**
29
+ * @member {Number} max_=100
30
+ */
31
+ max_: 100,
32
+ /**
33
+ * @member {Number|null} value_=null
34
+ */
35
+ value_: null,
36
+ /**
37
+ * @member {Object} _vdom
38
+ */
39
+ _vdom:
40
+ {tag: 'div', cls: ['neo-progress'], cn: [
41
+ {tag: 'label'},
42
+ {tag: 'progress'}
43
+ ]}
44
+ }
45
+
46
+ /**
47
+ * Triggered after the id config got changed
48
+ * @param {String} value
49
+ * @param {String} oldValue
50
+ * @protected
51
+ */
52
+ afterSetId(value, oldValue) {
53
+ super.afterSetId(value, oldValue);
54
+
55
+ this.vdom.cn[0].for = value;
56
+ this.update()
57
+ }
58
+
59
+ /**
60
+ * Triggered after the labelText config got changed
61
+ * @param {String|null} value
62
+ * @param {String|null} oldValue
63
+ * @protected
64
+ */
65
+ afterSetLabelText(value, oldValue) {
66
+ this.vdom.cn[0].html = value;
67
+ this.update()
68
+ }
69
+
70
+ /**
71
+ * Triggered after the max config got changed
72
+ * @param {Number} value
73
+ * @param {Number} oldValue
74
+ * @protected
75
+ */
76
+ afterSetMax(value, oldValue) {
77
+ this.vdom.cn[1].max = value;
78
+ this.update()
79
+ }
80
+
81
+ /**
82
+ * Triggered after the value config got changed
83
+ * @param {Number|null} value
84
+ * @param {Number|null} oldValue
85
+ * @protected
86
+ */
87
+ afterSetValue(value, oldValue) {
88
+ this.vdom.cn[1].value = value;
89
+ this.update()
90
+ }
91
+
92
+ /**
93
+ * Specify a different vdom root if needed to apply the top level style attributes on a different level.
94
+ * Make sure to use getVnodeRoot() as well, to keep the vdom & vnode trees in sync.
95
+ * @returns {Object} The new vdom root
96
+ */
97
+ getVdomRoot() {
98
+ return this.vdom.cn[1]
99
+ }
100
+
101
+ /**
102
+ * Specify a different vnode root if needed to apply the top level style attributes on a different level.
103
+ * Make sure to use getVdomRoot() as well, to keep the vdom & vnode trees in sync.
104
+ * @returns {Object} The new vnode root
105
+ */
106
+ getVnodeRoot() {
107
+ return this.vnode.childNodes[1]
108
+ }
109
+ }
110
+
111
+ Neo.applyClassConfig(Progress);
112
+
113
+ export default Progress;
@@ -136,16 +136,17 @@ class Splitter extends Component {
136
136
  }
137
137
 
138
138
  /**
139
- * @param data
139
+ * @param {Object} data
140
140
  */
141
141
  onDragEnd(data) {
142
142
  let me = this,
143
143
  style = me.style || {},
144
+ parentId = me.parentId,
144
145
  resizeNext = me.resizeTarget === 'next',
145
146
  size = me.size,
146
147
  index, newSize, sibling, parent;
147
148
 
148
- Neo.getComponent(me.parentId).disabled = false;
149
+ Neo.getComponent(parentId).disabled = false;
149
150
 
150
151
  me.dragZone.dragEnd(data);
151
152
 
@@ -153,8 +154,8 @@ class Splitter extends Component {
153
154
 
154
155
  me.style = style;
155
156
 
156
- me.getDomRect(me.parentId).then(parentRect => {
157
- parent = Neo.getComponent(me.parentId);
157
+ me.getDomRect(parentId).then(parentRect => {
158
+ parent = Neo.getComponent(parentId);
158
159
  index = parent.indexOf(me);
159
160
  sibling = parent.items[resizeNext ? index + 1 :index - 1];
160
161
  style = sibling.style || {};
@@ -245,12 +245,13 @@ class Toast extends Base {
245
245
  */
246
246
  async destroy(...args) {
247
247
  let me = this;
248
+ const superDestroy = super.destroy.bind(me);
248
249
 
249
250
  me.addDomListeners({
250
251
  animationend: function () {
251
252
  ToastManager.removeToast(me.id);
252
253
  ToastManager.unregister(me);
253
- me.destroy(true);
254
+ superDestroy(...args);
254
255
  }
255
256
  });
256
257
 
@@ -0,0 +1,130 @@
1
+ import AccordionItem from './AccordionItem.mjs';
2
+ import NeoArray from '../util/Array.mjs';
3
+ import Panel from './Panel.mjs';
4
+
5
+ /**
6
+ * @class Neo.container.Accordion
7
+ * @extends Neo.container.Panel
8
+ */
9
+ class Accordion extends Panel {
10
+ static config = {
11
+ /**
12
+ * @member {String} className='Neo.container.Accordion'
13
+ * @protected
14
+ */
15
+ className: 'Neo.container.Accordion',
16
+ /**
17
+ * @member {String} ntype='accordion'
18
+ * @protected
19
+ */
20
+ ntype: 'accordion',
21
+ /**
22
+ * @member {String[]} baseCls=['neo-accordion']
23
+ */
24
+ baseCls: ['neo-accordion'],
25
+ /**
26
+ * Add zero based numbers, which accordion items you want initially expanded
27
+ * @member {Number[]} initialOpen=[]
28
+ */
29
+ initialOpen_: [],
30
+ /**
31
+ * @member {Object} itemDefaults={ntype:'accordionitem'}
32
+ */
33
+ itemDefaults: {ntype: 'accordionitem'},
34
+ /**
35
+ * @member {Object[]} items=[]
36
+ */
37
+ items: [],
38
+ /**
39
+ * Max number of accordion items, which can be expanded at the same time
40
+ * @member {Number} maxExpandedItems=1
41
+ */
42
+ maxExpandedItems: 1,
43
+ /**
44
+ * Keep track of currently open items
45
+ * @member {String[]} expandedItems=[]
46
+ * @private
47
+ */
48
+ expandedItems_: [],
49
+ /**
50
+ * Creates a top header
51
+ * @memeber {String|null} title=null
52
+ */
53
+ title_: null
54
+ }
55
+
56
+ /**
57
+ * @param {Number[]} value
58
+ * @param {Number[]} oldValue
59
+ */
60
+ afterSetInitialOpen(value, oldValue) {
61
+ const me = this,
62
+ items = me.items,
63
+ expandedItems = me.expandedItems;
64
+
65
+ value.forEach((itemNo) => {
66
+ const id = Neo.getId(me.itemDefaults.ntype),
67
+ item = items[itemNo];
68
+
69
+ item.expanded = true;
70
+ item.id = id;
71
+ NeoArray.add(expandedItems, id);
72
+ });
73
+
74
+ me.expandedItems = expandedItems;
75
+ }
76
+
77
+ /**
78
+ * After changes to title config, we add a header
79
+ * @param {String|null} value
80
+ * @param {String|null} oldValue
81
+ */
82
+ afterSetTitle(value, oldValue) {
83
+ const me = this,
84
+ titleEl = me.down({flag: 'titleEl'});
85
+
86
+ if (value && !titleEl) {
87
+ me.headers = [{
88
+ baseCls: 'neo-accordion-title',
89
+ cls : ['neo-accordion-title'],
90
+ dock : 'top',
91
+ text : value
92
+ }];
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Called by accordion items.
98
+ * Checks for maxExpandedItems
99
+ * @param {Object} data
100
+ * @param {Boolean} data.expanded newState
101
+ * @param {Neo.container.AccordionItem} data.target accordion item
102
+ * @protected
103
+ */
104
+ childExpandChange(data) {
105
+ const me = this,
106
+ maxExpandedItems = me.maxExpandedItems,
107
+ expandedItems = me.expandedItems,
108
+ curNoOpenItems = expandedItems.length,
109
+ target = data.target,
110
+ targetId = target.id,
111
+ expanded = data.expanded;
112
+
113
+ if (expanded
114
+ && maxExpandedItems !== 0
115
+ && curNoOpenItems === maxExpandedItems
116
+ ) {
117
+ Neo.get(expandedItems[0]).expanded = false;
118
+ NeoArray.remove(expandedItems, expandedItems[0]);
119
+ }
120
+
121
+ target.expanded = expanded;
122
+ NeoArray.toggle(expandedItems, targetId);
123
+
124
+ me.expandedItems = expandedItems;
125
+ }
126
+ }
127
+
128
+ Neo.applyClassConfig(Accordion);
129
+
130
+ export default Accordion;
@@ -0,0 +1,178 @@
1
+ import Base from './Base.mjs';
2
+ import Toolbar from '../toolbar/Base.mjs';
3
+ import NeoArray from '../util/Array.mjs';
4
+
5
+ /**
6
+ * @class Neo.container.AccordionItem
7
+ * @extends Neo.container.Base
8
+ */
9
+ class AccordionContainer extends Base {
10
+ static config = {
11
+ /**
12
+ * @member {String} className='Neo.container.AccordionItem'
13
+ * @protected
14
+ */
15
+ className: 'Neo.container.AccordionItem',
16
+ /**
17
+ * @member {String} ntype='accordionitem'
18
+ * @protected
19
+ */
20
+ ntype: 'accordionitem',
21
+ /**
22
+ * @member {String[]} baseCls=['neo-accordion-component']
23
+ */
24
+ baseCls: ['neo-accordion-item'],
25
+
26
+ /**
27
+ * Additional cls for the arrow, in case you need to customize it
28
+ * @member {String[]|String|null} arrowCls=null
29
+ */
30
+ arrowCls: null,
31
+ /**
32
+ * Expand or collapse (true/false) this value
33
+ * @member {Boolean} expanded=false
34
+ */
35
+ expanded_: false,
36
+ /**
37
+ * cls for the icon in front of the title
38
+ * May be empty. 'fa' is preset,
39
+ * so if you use fontawesome you do not have to add it.
40
+ *
41
+ * @member {String[]|String|null} iconCls=null
42
+ */
43
+ iconCls_: null,
44
+ /**
45
+ * Title for Headerbar
46
+ * @member {String|null} title=null
47
+ */
48
+ title_: null
49
+ }
50
+
51
+ /**
52
+ * Runs after afterSetTitle, so that the title component does not exist prior.
53
+ * @protected
54
+ */
55
+ createItems() {
56
+ const me = this,
57
+ items = me.items,
58
+ title = me.title;
59
+ let iconCls = me.iconCls || ['no-icon'],
60
+ arrowCls = me.arrowCls || 'fa-caret-down',
61
+ header, content;
62
+
63
+ if (!Neo.isArray(iconCls)) {
64
+ iconCls = iconCls.split(' ');
65
+ }
66
+ if (!Neo.isArray(arrowCls)) {
67
+ arrowCls = arrowCls.split(' ');
68
+ }
69
+
70
+ header = Neo.create({
71
+ module: Toolbar,
72
+ items : [{
73
+ flag : 'iconEl',
74
+ ntype : 'component',
75
+ baseCls: ['neo-accordion-header-icon'],
76
+ cls : ['fa', ...iconCls],
77
+ }, {
78
+ flag : 'titleEl',
79
+ ntype : 'component',
80
+ baseCls: ['neo-accordion-header-title'],
81
+ html : title
82
+ }, {
83
+ ntype : 'component',
84
+ baseCls: ['neo-accordion-header-arrow'],
85
+ cls : ['fa', ...arrowCls]
86
+ }]
87
+ });
88
+ content = {
89
+ ntype : 'container',
90
+ flag : 'content',
91
+ baseCls: ['neo-accordion-content', 'neo-container'],
92
+ items : items
93
+ };
94
+
95
+ me.items = [header, content];
96
+
97
+ super.createItems();
98
+
99
+ me.addDomListeners([
100
+ {click: me.onExpandClick, delegate: 'neo-accordion-header-arrow'}
101
+ ]);
102
+ }
103
+
104
+ /**
105
+ * After changing expanded, we expand/collapse via CSS
106
+ * @param {Boolean} isExpanded
107
+ */
108
+ afterSetExpanded(isExpanded) {
109
+ const me = this,
110
+ cls = me.cls,
111
+ fn = isExpanded ? 'add' : 'remove';
112
+
113
+ NeoArray[fn](cls, 'neo-expanded');
114
+ me.cls = cls;
115
+
116
+ // Ensure scrollbars are not flipping in and out
117
+ Neo.timeout(450).then(() => {
118
+ NeoArray[fn](cls, 'neo-scrollable');
119
+ me.cls = cls;
120
+ })
121
+ }
122
+
123
+ /**
124
+ * The initial title is set before the component is created,
125
+ * so we have to check if it exists.
126
+ *
127
+ * @param {String[]|String} newValue
128
+ * @param {String[]} oldValue
129
+ */
130
+ afterSetIconCls(newValue, oldValue) {
131
+ let iconEl = this.down({flag: 'iconEl'});
132
+
133
+ if (iconEl) {
134
+ let cls = iconEl.cls;
135
+
136
+ if (!Neo.isArray(newValue)) newValue = newValue.split(' ');
137
+
138
+ NeoArray.remove(cls, oldValue);
139
+ NeoArray.add(cls, newValue);
140
+ iconEl.cls = cls;
141
+ }
142
+ }
143
+
144
+ /**
145
+ * The initial title is set before the component is created,
146
+ * so we have to check if it exists.
147
+ *
148
+ * @param {String} newValue
149
+ */
150
+ afterSetTitle(newValue) {
151
+ let titleEl = this.down({flag: 'titleEl'});
152
+
153
+ if (titleEl) titleEl.html = newValue;
154
+ }
155
+
156
+ /**
157
+ * If the parent is an AccordionContainer, we run the parent function.
158
+ * Otherwise we set this.expanded to the new value.
159
+ */
160
+ onExpandClick() {
161
+ const me = this,
162
+ currentState = me.expanded;
163
+ let parent = me.up('accordion');
164
+
165
+ if (parent.ntype === 'accordion') {
166
+ parent.childExpandChange({
167
+ expanded: !currentState,
168
+ target : me
169
+ });
170
+ } else {
171
+ me.expanded = !currentState;
172
+ }
173
+ }
174
+ }
175
+
176
+ Neo.applyClassConfig(AccordionContainer);
177
+
178
+ export default AccordionContainer;
@@ -21,9 +21,17 @@ class Dialog extends Base {
21
21
  */
22
22
  ntype: 'container-dialog',
23
23
  /**
24
- * @member {String[]} baseCls=['container-dialog']
25
- * @protected
26
- */
24
+ * @member {Boolean} autoMount=true
25
+ */
26
+ autoMount: true,
27
+ /**
28
+ * @member {Boolean} autoRender=true
29
+ */
30
+ autoRender: true,
31
+ /**
32
+ * @member {String[]} baseCls=['neo-container-dialog', 'neo-panel', 'neo-container']
33
+ * @protected
34
+ */
27
35
  baseCls: ['neo-container-dialog', 'neo-panel', 'neo-container'],
28
36
  /**
29
37
  * @member {Object} headerConfig=null
@@ -34,10 +42,16 @@ class Dialog extends Base {
34
42
  */
35
43
  headerToolbar: null,
36
44
  /**
37
- * The CSS class to use for an icon, e.g. 'fa fa-home'
38
- * @member {String|null} [iconCls_=null]
45
+ * The CSS class to use for an icon, e.g. ['fa', 'fa-home']
46
+ * @member {String[]} [iconCls_=null]
39
47
  */
40
48
  iconCls_: null,
49
+ /**
50
+ * @member {Object} itemDefaults
51
+ */
52
+ itemDefaults: {
53
+ baseCls: ['neo-dialog-content']
54
+ },
41
55
  /**
42
56
  * @member {Object[]} items
43
57
  */
@@ -68,11 +82,9 @@ class Dialog extends Base {
68
82
  * @protected
69
83
  */
70
84
  afterSetIconCls(value, oldValue) {
71
- console.log(value, oldValue)
72
-
73
85
  if (!this.headers) { return }
74
- let iconNode = this.headers.down({flag: 'dialog-header-icon'});
75
- let iconNodeCls = [...iconNode.cls];
86
+ let iconNode = this.headers.down({flag: 'dialog-header-icon'}),
87
+ iconNodeCls = [...iconNode.cls];
76
88
 
77
89
  NeoArray.remove(iconNodeCls, oldValue);
78
90
  NeoArray.add( iconNodeCls, value);
@@ -90,41 +102,11 @@ class Dialog extends Base {
90
102
  * @protected
91
103
  */
92
104
  afterSetTitle(value, oldValue) {
93
- this.headerToolbar?.set({
94
- title: value
105
+ this.headerToolbar?.down({flag: 'panel-header-title'}).set({
106
+ text: value
95
107
  });
96
108
  }
97
109
 
98
- /**
99
- * Converts the iconCls array into a string on beforeGet
100
- * @returns {String}
101
- * @protected
102
- */
103
- beforeGetIconCls() {
104
- let iconCls = this._iconCls;
105
-
106
- if (Array.isArray(iconCls)) {
107
- return iconCls.join(' ');
108
- }
109
-
110
- return iconCls;
111
- }
112
-
113
- /**
114
- * Triggered before the iconCls config gets changed. Converts the string into an array if needed.
115
- * @param {Array|String|null} value
116
- * @param {Array|String|null} oldValue
117
- * @returns {Array}
118
- * @protected
119
- */
120
- beforeSetIconCls(value, oldValue) {
121
- if (value && !Array.isArray(value)) {
122
- value = value.split(' ').filter(Boolean);
123
- }
124
-
125
- return value;
126
- }
127
-
128
110
  /**
129
111
  * close the dialog in main thread
130
112
  */
@@ -141,15 +123,15 @@ class Dialog extends Base {
141
123
  * @protected
142
124
  */
143
125
  createHeader() {
144
- let me = this,
145
- cls = ['neo-header-toolbar', 'neo-toolbar'],
146
- headers = me.headers || [],
126
+ let me = this,
127
+ cls = ['neo-header-toolbar', 'neo-toolbar'],
128
+ headers = me.headers || [],
147
129
  headerConfigCopy = {...me.headerConfig};
148
130
  delete headerConfigCopy.items;
149
131
 
150
132
  me.headerToolbar = Neo.create({
151
133
  module : HeaderToolbar,
152
- actions: [{action: 'close', iconCls: 'fa-solid fa-xmark'}],
134
+ actions : [{action: 'close', iconCls: 'fa-solid fa-xmark'}],
153
135
  appName : me.appName,
154
136
  cls,
155
137
  dock : 'top',
@@ -157,15 +139,16 @@ class Dialog extends Base {
157
139
  id : me.getHeaderToolbarId(),
158
140
  listeners: {headerAction: me.executeHeaderAction, scope: me},
159
141
  items : [{
160
- cls: me.iconCls,
161
- flag : 'dialog-header-icon',
142
+ ntype: '',
143
+ cls : ['neo-dialog-header-icon', ...me.iconCls],
144
+ flag : 'dialog-header-icon',
162
145
  }, {
163
- ntype : 'label',
164
- cls : ['neo-panel-header-text', 'neo-label'],
165
- flag : 'title-label',
166
- removeDom: !me.title,
167
- text : me.title
168
- }, ...me.headerConfig.items],
146
+ ntype : 'label',
147
+ cls : ['neo-panel-header-text', 'neo-label'],
148
+ flag : 'panel-header-title',
149
+ hidden: !me.title,
150
+ text : me.title
151
+ }, ...me.headerConfig.items || []],
169
152
 
170
153
  ...headerConfigCopy
171
154
  });
@@ -182,7 +165,7 @@ class Dialog extends Base {
182
165
  let me = this,
183
166
 
184
167
  map = {
185
- close : me.close
168
+ close: me.close
186
169
  };
187
170
 
188
171
  map[data.action]?.call(me, data);