neo.mjs 6.10.14 → 6.10.16
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/apps/ServiceWorker.mjs +2 -2
- package/apps/portal/neo-config.json +1 -1
- package/examples/ServiceWorker.mjs +2 -2
- package/package.json +71 -71
- package/src/DefaultConfig.mjs +2 -2
- package/src/button/Base.mjs +4 -6
- package/src/data/RecordFactory.mjs +8 -8
- package/src/list/Base.mjs +19 -13
- package/src/main/DomAccess.mjs +2 -3
- package/src/main/addon/Navigator.mjs +18 -11
- package/src/menu/List.mjs +5 -1
- package/src/model/Component.mjs +1 -1
- package/src/vdom/Helper.mjs +8 -3
package/apps/ServiceWorker.mjs
CHANGED
@@ -3,6 +3,6 @@
|
|
3
3
|
"basePath" : "../../",
|
4
4
|
"environment" : "development",
|
5
5
|
"mainPath" : "./Main.mjs",
|
6
|
-
"mainThreadAddons": ["DragDrop", "HighlightJS", "Stylesheet", "Markdown"],
|
6
|
+
"mainThreadAddons": ["DragDrop", "HighlightJS", "Navigator", "Stylesheet", "Markdown"],
|
7
7
|
"themes" : ["neo-theme-neo-light"]
|
8
8
|
}
|
package/package.json
CHANGED
@@ -1,73 +1,73 @@
|
|
1
1
|
{
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
2
|
+
"name": "neo.mjs",
|
3
|
+
"version": "6.10.16",
|
4
|
+
"description": "The webworkers driven UI framework",
|
5
|
+
"type": "module",
|
6
|
+
"repository": {
|
7
|
+
"type": "git",
|
8
|
+
"url": "https://github.com/neomjs/neo.git"
|
9
|
+
},
|
10
|
+
"bin": {
|
11
|
+
"neo-cc": "./buildScripts/createClass.mjs"
|
12
|
+
},
|
13
|
+
"scripts": {
|
14
|
+
"add-config": "node ./buildScripts/addConfig.mjs",
|
15
|
+
"build-all": "node ./buildScripts/buildAll.mjs -f -n",
|
16
|
+
"build-all-questions": "node ./buildScripts/buildAll.mjs -f",
|
17
|
+
"build-themes": "node ./buildScripts/buildThemes.mjs -f",
|
18
|
+
"build-threads": "node ./buildScripts/webpack/buildThreads.mjs -f",
|
19
|
+
"convert-design-tokens": "node ./buildScripts/convertDesignTokens.mjs",
|
20
|
+
"create-app": "node ./buildScripts/createApp.mjs",
|
21
|
+
"create-app-minimal": "node ./buildScripts/createAppMinimal.mjs",
|
22
|
+
"create-class": "node ./buildScripts/createClass.mjs",
|
23
|
+
"create-component": "node ./buildScripts/createComponent.mjs",
|
24
|
+
"generate-docs-json": "node ./buildScripts/docs/jsdocx.mjs",
|
25
|
+
"inject-package-version": "node ./buildScripts/injectPackageVersion.mjs",
|
26
|
+
"server-start": "webpack serve -c ./buildScripts/webpack/webpack.server.config.mjs --open",
|
27
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
28
|
+
"watch-themes": "node ./buildScripts/watchThemes.mjs"
|
29
|
+
},
|
30
|
+
"keywords": [
|
31
|
+
"javascript",
|
32
|
+
"frontend",
|
33
|
+
"framework",
|
34
|
+
"webworker",
|
35
|
+
"ecmascript",
|
36
|
+
"css",
|
37
|
+
"json"
|
38
|
+
],
|
39
|
+
"author": "Tobias Uhlig, Rich Waters",
|
40
|
+
"license": "MIT",
|
41
|
+
"bugs": {
|
42
|
+
"url": "https://github.com/neomjs/neo/issues"
|
43
|
+
},
|
44
|
+
"homepage": "https://neomjs.github.io/pages/",
|
45
|
+
"devDependencies": {
|
46
|
+
"@fortawesome/fontawesome-free": "^6.5.1",
|
47
|
+
"autoprefixer": "^10.4.17",
|
48
|
+
"chalk": "^5.3.0",
|
49
|
+
"clean-webpack-plugin": "^4.0.0",
|
50
|
+
"commander": "^12.0.0",
|
51
|
+
"cssnano": "^6.0.3",
|
52
|
+
"envinfo": "^7.11.1",
|
53
|
+
"fs-extra": "^11.2.0",
|
54
|
+
"highlightjs-line-numbers.js": "^2.8.0",
|
55
|
+
"inquirer": "^9.2.14",
|
56
|
+
"neo-jsdoc": "1.0.1",
|
57
|
+
"neo-jsdoc-x": "1.0.5",
|
58
|
+
"postcss": "^8.4.33",
|
59
|
+
"sass": "^1.70.0",
|
60
|
+
"siesta-lite": "5.5.2",
|
61
|
+
"showdown": "^2.1.0",
|
62
|
+
"url": "^0.11.3",
|
63
|
+
"webpack": "^5.90.1",
|
64
|
+
"webpack-cli": "^5.1.4",
|
65
|
+
"webpack-dev-server": "4.15.1",
|
66
|
+
"webpack-hook-plugin": "^1.0.7",
|
67
|
+
"webpack-node-externals": "^3.0.0"
|
68
|
+
},
|
69
|
+
"funding": {
|
70
|
+
"type": "GitHub Sponsors",
|
71
|
+
"url": "https://github.com/sponsors/tobiu"
|
72
|
+
}
|
73
73
|
}
|
package/src/DefaultConfig.mjs
CHANGED
@@ -236,12 +236,12 @@ const DefaultConfig = {
|
|
236
236
|
useVdomWorker: true,
|
237
237
|
/**
|
238
238
|
* buildScripts/injectPackageVersion.mjs will update this value
|
239
|
-
* @default '6.10.
|
239
|
+
* @default '6.10.16'
|
240
240
|
* @memberOf! module:Neo
|
241
241
|
* @name config.version
|
242
242
|
* @type String
|
243
243
|
*/
|
244
|
-
version: '6.10.
|
244
|
+
version: '6.10.16'
|
245
245
|
};
|
246
246
|
|
247
247
|
Object.assign(DefaultConfig, {
|
package/src/button/Base.mjs
CHANGED
@@ -258,7 +258,7 @@ class Base extends Component {
|
|
258
258
|
menuConfig = isArray ? {} : value,
|
259
259
|
model = me.getModel(),
|
260
260
|
|
261
|
-
config = {
|
261
|
+
config = Neo.merge({
|
262
262
|
module : module.default,
|
263
263
|
align : {edgeAlign : 't0-b0', target: me.id},
|
264
264
|
appName : me.appName,
|
@@ -266,9 +266,8 @@ class Base extends Component {
|
|
266
266
|
floating : true,
|
267
267
|
hidden : true,
|
268
268
|
parentComponent: me,
|
269
|
-
theme : me.theme
|
270
|
-
|
271
|
-
};
|
269
|
+
theme : me.theme
|
270
|
+
}, menuConfig);
|
272
271
|
|
273
272
|
if (items) {
|
274
273
|
config.items = items
|
@@ -544,8 +543,7 @@ class Base extends Component {
|
|
544
543
|
menuList.hidden = hidden;
|
545
544
|
|
546
545
|
if (!hidden) {
|
547
|
-
await this.timeout(50)
|
548
|
-
menuList.focus()
|
546
|
+
await this.timeout(50)
|
549
547
|
}
|
550
548
|
}
|
551
549
|
}
|
@@ -76,7 +76,7 @@ class RecordFactory extends Base {
|
|
76
76
|
|
77
77
|
if (Array.isArray(model.fields)) {
|
78
78
|
model.fields.forEach(field => {
|
79
|
-
let value = config[field.name],
|
79
|
+
let value = config[field.mapping || field.name],
|
80
80
|
symbol = Symbol.for(field.name),
|
81
81
|
parsedValue;
|
82
82
|
|
@@ -126,8 +126,8 @@ class RecordFactory extends Base {
|
|
126
126
|
}
|
127
127
|
}
|
128
128
|
|
129
|
-
Object.defineProperties(me, properties)
|
130
|
-
})
|
129
|
+
Object.defineProperties(me, properties)
|
130
|
+
})
|
131
131
|
}
|
132
132
|
}
|
133
133
|
|
@@ -136,7 +136,7 @@ class RecordFactory extends Base {
|
|
136
136
|
* @param {Object} fields
|
137
137
|
*/
|
138
138
|
set(fields) {
|
139
|
-
instance.setRecordFields(model, this, fields)
|
139
|
+
instance.setRecordFields(model, this, fields)
|
140
140
|
}
|
141
141
|
|
142
142
|
/**
|
@@ -144,17 +144,17 @@ class RecordFactory extends Base {
|
|
144
144
|
* @param {Object} fields
|
145
145
|
*/
|
146
146
|
setSilent(fields) {
|
147
|
-
instance.setRecordFields(model, this, fields, true)
|
147
|
+
instance.setRecordFields(model, this, fields, true)
|
148
148
|
}
|
149
149
|
};
|
150
150
|
|
151
151
|
Object.defineProperty(cls.prototype, 'isRecord', { value : true });
|
152
152
|
Object.defineProperty(cls, 'isClass', { vale : true });
|
153
153
|
|
154
|
-
return ns[key]
|
154
|
+
return ns[key]
|
155
155
|
}
|
156
156
|
|
157
|
-
return ns
|
157
|
+
return ns
|
158
158
|
}
|
159
159
|
}
|
160
160
|
|
@@ -209,7 +209,7 @@ class RecordFactory extends Base {
|
|
209
209
|
* @returns {Boolean}
|
210
210
|
*/
|
211
211
|
isRecord(record) {
|
212
|
-
return record?.
|
212
|
+
return record?.isRecord;
|
213
213
|
}
|
214
214
|
|
215
215
|
/**
|
package/src/list/Base.mjs
CHANGED
@@ -250,30 +250,32 @@ class Base extends Component {
|
|
250
250
|
* @protected
|
251
251
|
*/
|
252
252
|
afterSetHeaderlessActiveIndex(value, oldValue) {
|
253
|
-
let me = this
|
254
|
-
activeIndex;
|
253
|
+
let me = this;
|
255
254
|
|
256
255
|
if (Neo.isNumber(value)) {
|
257
|
-
activeIndex = me.
|
258
|
-
|
259
|
-
me.activeIndex = activeIndex
|
256
|
+
me.activeIndex = me.store.getCount() ? value: null
|
260
257
|
} else if (Neo.isNumber(oldValue)) {
|
261
258
|
me.activeIndex = null
|
262
259
|
}
|
263
260
|
}
|
264
261
|
|
265
|
-
|
262
|
+
/**
|
263
|
+
* Triggered after the mounted config got changed
|
264
|
+
* @param {Boolean} value
|
265
|
+
* @param {Boolean} oldValue
|
266
|
+
* @protected
|
267
|
+
*/
|
268
|
+
afterSetMounted(value, oldValue) {
|
266
269
|
const me = this;
|
267
270
|
|
268
271
|
// Tear down navigation before we lose the element
|
269
272
|
if (!value && me.hasNavigator) {
|
270
273
|
Neo.main.addon.Navigator.unsubscribe(me.navigator);
|
274
|
+
|
271
275
|
me.hasNavigator = false;
|
272
|
-
me.activeIndex
|
276
|
+
me.activeIndex = null
|
273
277
|
}
|
274
278
|
|
275
|
-
super.afterSetMounted(...arguments);
|
276
|
-
|
277
279
|
if (value) {
|
278
280
|
// Set up item navigation in the list
|
279
281
|
if (!me.hasNavigator) {
|
@@ -282,11 +284,15 @@ class Base extends Component {
|
|
282
284
|
id : me.id,
|
283
285
|
selector : `.${me.itemCls}:not(.neo-disabled,.neo-list-header)`,
|
284
286
|
...me.navigator
|
285
|
-
}
|
286
|
-
|
287
|
+
};
|
288
|
+
|
289
|
+
me.hasNavigator = true
|
287
290
|
}
|
291
|
+
|
288
292
|
Neo.main.addon.Navigator.subscribe(me.navigator)
|
289
293
|
}
|
294
|
+
|
295
|
+
super.afterSetMounted(value, oldValue)
|
290
296
|
}
|
291
297
|
|
292
298
|
/**
|
@@ -546,10 +552,10 @@ class Base extends Component {
|
|
546
552
|
|
547
553
|
/**
|
548
554
|
* Calls focus() on the top level DOM node of this component or on a given node via id
|
549
|
-
* @param {String}
|
555
|
+
* @param {String} id
|
550
556
|
*/
|
551
557
|
focus(id) {
|
552
|
-
Neo.main.addon.Navigator.navigateTo(id, this.navigator)
|
558
|
+
Neo.main.addon.Navigator.navigateTo([id, this.navigator])
|
553
559
|
}
|
554
560
|
|
555
561
|
/**
|
package/src/main/DomAccess.mjs
CHANGED
@@ -362,9 +362,8 @@ class DomAccess extends Base {
|
|
362
362
|
if (node) {
|
363
363
|
// The children property means focus inner elements if possible.
|
364
364
|
if (!DomUtils.isFocusable(node) && data.children) {
|
365
|
-
//
|
366
|
-
|
367
|
-
node = node.querySelector('input:not(:disabled)') || node.querySelector('textarea:not(:disabled)') || node.querySelector('button:not(:disabled)') || [...node.querySelectorAll('*')].find(DomUtils.isFocusable);
|
365
|
+
// query for the first focusable decendent
|
366
|
+
node = DomUtils.query(node, DomUtils.isFocusable);
|
368
367
|
}
|
369
368
|
if (node) {
|
370
369
|
node.focus();
|
@@ -30,9 +30,9 @@ class Navigator extends Base {
|
|
30
30
|
*/
|
31
31
|
remote: {
|
32
32
|
app: [
|
33
|
+
'navigateTo',
|
33
34
|
'subscribe',
|
34
|
-
'unsubscribe'
|
35
|
-
'navigateTo'
|
35
|
+
'unsubscribe'
|
36
36
|
]
|
37
37
|
},
|
38
38
|
/**
|
@@ -114,7 +114,7 @@ class Navigator extends Base {
|
|
114
114
|
// The navigables we are dealing with, if they are focusable must *not* be tabbable.
|
115
115
|
// Only *one* must be tabbable, so that tabbing into the subject element goes to the
|
116
116
|
// one active element.
|
117
|
-
//
|
117
|
+
//
|
118
118
|
// Tabbing *from* that must exit the subject element.
|
119
119
|
//
|
120
120
|
// So we must ensure that all the focusable elements except the first are not tabbable.
|
@@ -127,7 +127,14 @@ class Navigator extends Base {
|
|
127
127
|
}
|
128
128
|
|
129
129
|
const
|
130
|
-
|
130
|
+
// Extract all our navigable items, and find the focusable within
|
131
|
+
focusables = Array.from(data.subject.querySelectorAll(data.selector)).reduce((value,item ) => {
|
132
|
+
const f = DomUtils.query(item, DomUtils.isFocusable);
|
133
|
+
if (f){
|
134
|
+
value.push(f);
|
135
|
+
}
|
136
|
+
return value;
|
137
|
+
}, []),
|
131
138
|
defaultActiveItem = focusables[0] || data.subject.querySelector(data.selector);
|
132
139
|
|
133
140
|
// Ensure the items are not tabbable.
|
@@ -192,7 +199,7 @@ class Navigator extends Base {
|
|
192
199
|
const { target } = e;
|
193
200
|
|
194
201
|
// Clear active class from the item we are leaving from.
|
195
|
-
target.closest(data.selector)
|
202
|
+
target.closest(data.selector)?.classList.remove(data.activeCls);
|
196
203
|
|
197
204
|
// On focusout, leave the last active item as tabbable so user can TAB back in here
|
198
205
|
if (!DomUtils.isTabbable(target)) {
|
@@ -205,7 +212,7 @@ class Navigator extends Base {
|
|
205
212
|
|
206
213
|
// If there was a focusable under the mouse, mousedown will have focused it and and we
|
207
214
|
// will have respond to that in navigateFocusInHandler.
|
208
|
-
// If not, we navigate
|
215
|
+
// If not, we navigate programmatically.
|
209
216
|
if (target && !data.findFocusable(target)) {
|
210
217
|
this.navigateTo(target, data);
|
211
218
|
}
|
@@ -214,8 +221,8 @@ class Navigator extends Base {
|
|
214
221
|
navigateMouseDownHandler(e, data) {
|
215
222
|
const target = e.target.closest(data.selector);
|
216
223
|
|
217
|
-
// If there is a focusable
|
218
|
-
// If not, we have to
|
224
|
+
// If there is a focusable under the mouse, it will take focus, and we respond to that in navigateFocusInHandler.
|
225
|
+
// If not, we have to programmatically activate on click, but we must not draw focus away from
|
219
226
|
// where it is, so preventDefault
|
220
227
|
if (target && !data.findFocusable(target)) {
|
221
228
|
e.preventDefault();
|
@@ -241,12 +248,12 @@ class Navigator extends Base {
|
|
241
248
|
if (containerStyle.display === 'flex' && containerStyle.flexDirection === 'row'
|
242
249
|
|| itemStyle.display === 'inline' || itemStyle.display === 'inline-block') {
|
243
250
|
data.previousKey = 'ArrowLeft';
|
244
|
-
data.nextKey
|
251
|
+
data.nextKey = 'ArrowRight';
|
245
252
|
}
|
246
253
|
// Child elements layed out vertically.
|
247
254
|
else {
|
248
255
|
data.previousKey = 'ArrowUp';
|
249
|
-
data.nextKey
|
256
|
+
data.nextKey = 'ArrowDown';
|
250
257
|
}
|
251
258
|
}
|
252
259
|
|
@@ -314,7 +321,7 @@ class Navigator extends Base {
|
|
314
321
|
}
|
315
322
|
|
316
323
|
/**
|
317
|
-
* Navigates to the passed
|
324
|
+
* Navigates to the passed
|
318
325
|
* @param {String|Number} newActiveElement The id of the new active element in the subject
|
319
326
|
* element, or the index of the item.
|
320
327
|
* @param {Object} data The data block as passed to {@link #subscribe}
|
package/src/menu/List.mjs
CHANGED
@@ -38,6 +38,10 @@ class List extends BaseList {
|
|
38
38
|
* @member {Boolean} hideOnLeafItemClick=true
|
39
39
|
*/
|
40
40
|
hideOnLeafItemClick: true,
|
41
|
+
/**
|
42
|
+
* @member {Boolean} itemsFocusable=true
|
43
|
+
*/
|
44
|
+
itemsFocusable: true,
|
41
45
|
/**
|
42
46
|
* Optionally pass menu.Store data directly
|
43
47
|
* @member {Object[]|null} items_=null
|
@@ -100,7 +104,7 @@ class List extends BaseList {
|
|
100
104
|
* @member {Object} _vdom
|
101
105
|
*/
|
102
106
|
_vdom:
|
103
|
-
{tag: 'ul',
|
107
|
+
{tag: 'ul', cn: []}
|
104
108
|
}
|
105
109
|
|
106
110
|
/**
|
package/src/model/Component.mjs
CHANGED
@@ -494,7 +494,7 @@ class Component extends Base {
|
|
494
494
|
let me = this,
|
495
495
|
data, keyLeaf, parentModel, scope;
|
496
496
|
|
497
|
-
if (Neo.isObject(value) && !value
|
497
|
+
if (Neo.isObject(value) && !value.isRecord) {
|
498
498
|
Object.entries(value).forEach(([dataKey, dataValue]) => {
|
499
499
|
me.internalSetData(`${key}.${dataKey}`, dataValue, originModel)
|
500
500
|
})
|
package/src/vdom/Helper.mjs
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import Base from '../core/Base.mjs';
|
2
2
|
import NeoArray from '../util/Array.mjs';
|
3
|
+
import NeoString from '../util/String.mjs';
|
3
4
|
import Style from '../util/Style.mjs';
|
4
5
|
import VNode from './VNode.mjs';
|
5
6
|
import VNodeUtil from '../util/VNode.mjs';
|
@@ -577,14 +578,18 @@ class Helper extends Base {
|
|
577
578
|
Object.entries(attributes).forEach(([key, value]) => {
|
578
579
|
if (this.voidAttributes.includes(key)) {
|
579
580
|
if (value === 'true') { // vnode attribute values get converted into strings
|
580
|
-
string += ` ${key}
|
581
|
+
string += ` ${key}`
|
581
582
|
}
|
582
583
|
} else if (key !== 'removeDom') {
|
583
|
-
|
584
|
+
if (key === 'value') {
|
585
|
+
value = NeoString.escapeHtml(value)
|
586
|
+
}
|
587
|
+
|
588
|
+
string += ` ${key}="${value?.replaceAll?.('"', '"') ?? value}"`
|
584
589
|
}
|
585
590
|
});
|
586
591
|
|
587
|
-
return string + '>'
|
592
|
+
return string + '>'
|
588
593
|
}
|
589
594
|
|
590
595
|
/**
|