neo.mjs 6.13.0 → 6.15.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/apps/ServiceWorker.mjs +2 -2
- package/apps/covid/neo-config.json +1 -1
- package/apps/covid/view/HeaderContainer.mjs +2 -2
- package/apps/form/view/pages/Page10.mjs +2 -2
- package/apps/portal/view/ViewportController.mjs +5 -4
- package/apps/portal/view/home/ContentBox.mjs +80 -0
- package/apps/portal/view/home/MainContainer.mjs +51 -15
- package/apps/portal/view/learn/ContentTreeList.mjs +10 -3
- package/apps/portal/view/learn/MainContainerController.mjs +37 -5
- package/apps/portal/view/learn/MainContainerModel.mjs +51 -7
- package/apps/portal/view/learn/PageContainer.mjs +21 -9
- package/apps/sharedcovid/neo-config.json +1 -1
- package/apps/sharedcovid/view/HeaderContainer.mjs +2 -2
- package/examples/ServiceWorker.mjs +2 -2
- package/examples/button/base/MainContainer.mjs +2 -2
- package/examples/button/split/MainContainer.mjs +2 -2
- package/examples/component/process/MainContainer.mjs +3 -3
- package/examples/component/process/realWorldExample/MainContainer.mjs +15 -15
- package/examples/component/toast/MainContainer.mjs +4 -4
- package/examples/dialog/DemoDialog.mjs +4 -4
- package/examples/fieldWithPrefix/MainContainer.mjs +4 -5
- package/examples/form/field/{select → combobox}/MainContainer.mjs +7 -10
- package/examples/form/field/{select → combobox}/MainModel.mjs +4 -4
- package/examples/form/field/{select → combobox}/MainStore.mjs +2 -2
- package/examples/form/field/{select → combobox}/app.mjs +1 -1
- package/examples/form/field/{select → combobox}/index.html +1 -1
- package/examples/form/field/{select → combobox}/neo-config.json +1 -1
- package/examples/tableFiltering/MainContainer.mjs +2 -2
- package/package.json +4 -4
- package/resources/data/deck/learnneo/pages/2023-10-14T19-25-08-153Z.md +16 -1
- package/resources/data/deck/learnneo/pages/ComponentsAndContainers.md +180 -0
- package/resources/data/deck/learnneo/pages/Config.md +11 -4
- package/resources/data/deck/learnneo/pages/DescribingTheUI.md +6 -0
- package/resources/data/deck/learnneo/pages/Earthquakes.md +36 -9
- package/resources/data/deck/learnneo/pages/Events.md +55 -43
- package/resources/data/deck/learnneo/pages/GuideEvents.md +9 -8
- package/resources/data/deck/learnneo/pages/References.md +14 -7
- package/resources/data/deck/learnneo/pages/TodoList.md +241 -0
- package/resources/data/deck/learnneo/pages/WhyNeo-Quick.md +6 -11
- package/resources/data/deck/learnneo/tree.json +2 -0
- package/resources/scss/src/apps/portal/home/ContentBox.scss +26 -0
- package/resources/scss/src/apps/portal/home/MainContainer.scss +4 -12
- package/resources/scss/src/apps/portal/learn/MainContainer.scss +0 -7
- package/resources/scss/src/apps/portal/learn/PageContainer.scss +35 -0
- package/resources/scss/src/apps/portal/learn/PageSectionsPanel.scss +8 -0
- package/resources/scss/src/form/field/{Select.scss → ComboBox.scss} +8 -8
- package/resources/scss/theme-dark/form/field/ComboBox.scss +9 -0
- package/resources/scss/theme-light/form/field/ComboBox.scss +9 -0
- package/resources/scss/theme-neo-light/form/field/ComboBox.scss +9 -0
- package/src/DefaultConfig.mjs +2 -2
- package/src/component/Base.mjs +16 -1
- package/src/container/Viewport.mjs +5 -2
- package/src/controller/Application.mjs +12 -1
- package/src/controller/Base.mjs +15 -4
- package/src/controller/Component.mjs +5 -1
- package/src/core/Observable.mjs +62 -22
- package/src/form/field/Base.mjs +21 -9
- package/src/form/field/Chip.mjs +3 -3
- package/src/form/field/Color.mjs +3 -3
- package/src/form/field/{Select.mjs → ComboBox.mjs} +179 -130
- package/src/form/field/Country.mjs +3 -3
- package/src/form/field/Text.mjs +7 -10
- package/src/form/field/_export.mjs +2 -2
- package/src/main/DomEvents.mjs +2 -1
- package/src/main/addon/MonacoEditor.mjs +2 -2
- package/src/main/addon/Navigator.mjs +27 -24
- package/src/selection/ListModel.mjs +13 -14
- package/src/selection/Model.mjs +10 -10
- package/src/toolbar/Paging.mjs +2 -2
- package/src/util/HashHistory.mjs +1 -0
- package/src/worker/App.mjs +5 -1
- package/src/worker/Manager.mjs +14 -7
- package/test/components/app.mjs +1 -1
- package/test/components/files/form/field/{Select.mjs → ComboBox.mjs} +9 -7
- package/test/components/siesta.js +1 -1
- package/resources/scss/theme-dark/form/field/Select.scss +0 -9
- package/resources/scss/theme-light/form/field/Select.scss +0 -9
- package/resources/scss/theme-neo-light/form/field/Select.scss +0 -9
@@ -295,7 +295,7 @@ class Navigator extends Base {
|
|
295
295
|
if (typeof el.click === 'function') {
|
296
296
|
el.click();
|
297
297
|
}
|
298
|
-
// It operates through a
|
298
|
+
// It operates through a listener, so needs an event firing into it.
|
299
299
|
else {
|
300
300
|
const
|
301
301
|
rect = el.getBoundingClientRect(),
|
@@ -324,7 +324,7 @@ class Navigator extends Base {
|
|
324
324
|
if (!data.subject) {
|
325
325
|
// If subject has been unmounted, we cannot navigate
|
326
326
|
if (!(data = DomAccess.getElement(data.id)?.$navigator)) {
|
327
|
-
return
|
327
|
+
return
|
328
328
|
}
|
329
329
|
}
|
330
330
|
|
@@ -344,8 +344,8 @@ class Navigator extends Base {
|
|
344
344
|
|
345
345
|
// Scroll the target into view smoothly before we focus it without triggering a scroll
|
346
346
|
newActiveElement.scrollIntoView({
|
347
|
-
|
348
|
-
|
347
|
+
behavior : 'smooth',
|
348
|
+
block : 'nearest'
|
349
349
|
});
|
350
350
|
|
351
351
|
// Find a focusable element which may be the item, or inside the item to draw focus to.
|
@@ -356,7 +356,7 @@ class Navigator extends Base {
|
|
356
356
|
if (focusTarget) {
|
357
357
|
focusTarget.focus({ preventScroll : true });
|
358
358
|
}
|
359
|
-
// If not, we
|
359
|
+
// If not, we programmatically navigate there
|
360
360
|
else {
|
361
361
|
this.setActiveItem(newActiveElement, data);
|
362
362
|
}
|
@@ -377,34 +377,37 @@ class Navigator extends Base {
|
|
377
377
|
data.activeIndex = newActiveElement ? allItems.indexOf(newActiveElement) : -1;
|
378
378
|
|
379
379
|
newActiveElement.scrollIntoView({
|
380
|
-
|
381
|
-
|
382
|
-
|
380
|
+
behavior: 'smooth',
|
381
|
+
block : 'nearest',
|
382
|
+
inline : 'nearest'
|
383
383
|
});
|
384
384
|
|
385
385
|
// Link the event source or the encapsulating element to the active item for A11Y
|
386
386
|
(data.eventSource || data.subject).setAttribute('aria-activedescendant', data.activeItem.id);
|
387
387
|
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
388
|
+
// navigating to the same element should get ignored
|
389
|
+
if (data.activeItem !== data.previousActiveItem) {
|
390
|
+
DomEvents.sendMessageToApp({
|
391
|
+
type : 'neonavigate',
|
392
|
+
target : data.id,
|
393
|
+
path : [{
|
394
|
+
id : data.id
|
395
|
+
}],
|
396
|
+
activeItem : data.activeItem.id,
|
397
|
+
previousActiveItem : data.previousActiveItem?.id,
|
398
|
+
activeIndex : data.activeIndex,
|
399
|
+
previousActiveIndex : data.previousActiveIndex,
|
400
|
+
altKey : Neo.altKeyDown,
|
401
|
+
ctrlKey : Neo.controlKeyDown,
|
402
|
+
metaKey : Neo.metaKeyDown,
|
403
|
+
shiftKey : Neo.shiftKeyDown
|
404
|
+
})
|
405
|
+
}
|
403
406
|
|
404
407
|
// Navigation causes click if autoClick set.
|
405
408
|
// TabPanels work like this.
|
406
409
|
if (data.autoClick) {
|
407
|
-
this.clickItem(newActiveElement)
|
410
|
+
this.clickItem(newActiveElement)
|
408
411
|
}
|
409
412
|
}
|
410
413
|
|
@@ -58,13 +58,13 @@ class ListModel extends Model {
|
|
58
58
|
* @param {Object} data
|
59
59
|
*/
|
60
60
|
onListClick({ currentTarget }) {
|
61
|
-
const {
|
61
|
+
const {view} = this;
|
62
62
|
|
63
63
|
if (!view.disableSelection) {
|
64
64
|
const record = view.store.get(view.getItemRecordId(currentTarget));
|
65
65
|
|
66
66
|
if (record) {
|
67
|
-
this.select(record)
|
67
|
+
this.select(record)
|
68
68
|
}
|
69
69
|
}
|
70
70
|
}
|
@@ -74,8 +74,8 @@ class ListModel extends Model {
|
|
74
74
|
*/
|
75
75
|
onListNavigate(data) {
|
76
76
|
const
|
77
|
-
{
|
78
|
-
{
|
77
|
+
{view} = this,
|
78
|
+
{store} = view;
|
79
79
|
|
80
80
|
data.record = store.getAt(Math.min(data.activeIndex, store.getCount()));
|
81
81
|
view._focusIndex = store.indexOf(data.record); // silent update, no need to refocus
|
@@ -89,16 +89,16 @@ class ListModel extends Model {
|
|
89
89
|
register(component) {
|
90
90
|
super.register(component);
|
91
91
|
|
92
|
-
let me
|
93
|
-
id
|
94
|
-
view = me.view;
|
92
|
+
let me = this,
|
93
|
+
{id, view} = me;
|
95
94
|
|
96
95
|
view.addDomListeners([{
|
97
|
-
click
|
96
|
+
click: me.onListClick,
|
97
|
+
scope: me,
|
98
98
|
|
99
99
|
// Should be `.${view.itemCls}:not(.neo-disabled,.neo-list-header)`
|
100
100
|
// TODO parse delegate selectors
|
101
|
-
delegate
|
101
|
+
delegate: path => {
|
102
102
|
for (let i = 0, { length } = path; i < length; i++) {
|
103
103
|
const { cls } = path[i];
|
104
104
|
|
@@ -106,12 +106,11 @@ class ListModel extends Model {
|
|
106
106
|
return i;
|
107
107
|
}
|
108
108
|
}
|
109
|
-
}
|
110
|
-
scope : me
|
109
|
+
}
|
111
110
|
}, {
|
112
111
|
neonavigate : me.onListNavigate,
|
113
|
-
scope
|
114
|
-
}])
|
112
|
+
scope : me
|
113
|
+
}]);
|
115
114
|
|
116
115
|
view.keys?._keys.push(
|
117
116
|
{fn: 'onKeyDownDown' ,key: 'Down' ,scope: id},
|
@@ -132,7 +131,7 @@ class ListModel extends Model {
|
|
132
131
|
itemId = recordKey && view.getItemId(recordKey);
|
133
132
|
|
134
133
|
if (itemId) {
|
135
|
-
this.select(itemId)
|
134
|
+
this.select(itemId)
|
136
135
|
}
|
137
136
|
}
|
138
137
|
|
package/src/selection/Model.mjs
CHANGED
@@ -217,16 +217,16 @@ class Model extends Base {
|
|
217
217
|
* @param {String} [selectedCls]
|
218
218
|
*/
|
219
219
|
select(items, itemCollection=this.items, selectedCls) {
|
220
|
-
let me
|
221
|
-
view = me
|
222
|
-
vdom = view.vdom;
|
220
|
+
let me = this,
|
221
|
+
{view} = me;
|
223
222
|
|
224
223
|
// We hold vdom ids for now, so all incoming selections must be converted.
|
225
|
-
items = (items = Array.isArray(items) ?
|
224
|
+
items = (items = Array.isArray(items) ?
|
225
|
+
items : [items]).map(item => item.isRecord ? view.getItemId(item) : Neo.isObject(item) ? item.id : item);
|
226
226
|
|
227
227
|
if (!Neo.isEqual(itemCollection, items)) {
|
228
228
|
if (me.singleSelect) {
|
229
|
-
me.deselectAll(true)
|
229
|
+
me.deselectAll(true)
|
230
230
|
}
|
231
231
|
|
232
232
|
items.forEach((node, i) => {
|
@@ -234,22 +234,22 @@ class Model extends Base {
|
|
234
234
|
|
235
235
|
if (node) {
|
236
236
|
node.cls = NeoArray.add(node.cls || [], selectedCls || me.selectedCls);
|
237
|
-
node['aria-selected'] = true
|
237
|
+
node['aria-selected'] = true
|
238
238
|
}
|
239
239
|
});
|
240
240
|
|
241
241
|
NeoArray.add(itemCollection, items);
|
242
242
|
|
243
|
-
view
|
243
|
+
!view.silentSelect && view.update();
|
244
244
|
|
245
245
|
view.onSelect?.(items);
|
246
246
|
|
247
247
|
me.fire('selectionChange', {
|
248
|
-
selection
|
249
|
-
})
|
248
|
+
selection: itemCollection
|
249
|
+
})
|
250
250
|
}
|
251
251
|
else {
|
252
|
-
me.fire('noChange')
|
252
|
+
me.fire('noChange')
|
253
253
|
}
|
254
254
|
}
|
255
255
|
|
package/src/toolbar/Paging.mjs
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import ClassSystemUtil from '../util/ClassSystem.mjs';
|
2
|
-
import
|
2
|
+
import ComboBox from '../form/field/ComboBox.mjs';
|
3
3
|
import Toolbar from './Base.mjs';
|
4
4
|
|
5
5
|
/**
|
@@ -75,7 +75,7 @@ class Paging extends Toolbar {
|
|
75
75
|
text : 'Rows per page:'
|
76
76
|
},
|
77
77
|
rowsPerPage: {
|
78
|
-
module :
|
78
|
+
module : ComboBox,
|
79
79
|
clearable : false,
|
80
80
|
hideLabel : true,
|
81
81
|
listConfig : {highlightFilterValue: false},
|
package/src/util/HashHistory.mjs
CHANGED
package/src/worker/App.mjs
CHANGED
@@ -370,7 +370,11 @@ class App extends Base {
|
|
370
370
|
app = module.onStart();
|
371
371
|
|
372
372
|
// short delay to ensure Component Controllers are ready
|
373
|
-
config.hash && setTimeout(() =>
|
373
|
+
config.hash && setTimeout(() => {
|
374
|
+
HashHistory.push(config.hash);
|
375
|
+
// apps which will get created later must not use outdated hash values
|
376
|
+
delete config.hash
|
377
|
+
}, 5)
|
374
378
|
})
|
375
379
|
}
|
376
380
|
|
package/src/worker/Manager.mjs
CHANGED
@@ -6,12 +6,11 @@ import Observable from '../core/Observable.mjs';
|
|
6
6
|
import RemoteMethodAccess from './mixin/RemoteMethodAccess.mjs';
|
7
7
|
|
8
8
|
const NeoConfig = Neo.config,
|
9
|
-
devMode = NeoConfig.environment === 'development'
|
10
|
-
windowId = new Date().getTime();
|
9
|
+
devMode = NeoConfig.environment === 'development';
|
11
10
|
|
12
11
|
/**
|
13
12
|
* The worker manager lives inside the main thread and creates the App, Data & VDom worker.
|
14
|
-
* Also responsible for sending messages from the main thread to the different workers.
|
13
|
+
* Also, responsible for sending messages from the main thread to the different workers.
|
15
14
|
* @class Neo.worker.Manager
|
16
15
|
* @extends Neo.core.Base
|
17
16
|
* @singleton
|
@@ -72,6 +71,12 @@ class Manager extends Base {
|
|
72
71
|
* @protected
|
73
72
|
*/
|
74
73
|
webWorkersEnabled: false,
|
74
|
+
/**
|
75
|
+
* Using the current timestamp as an unique window identifier
|
76
|
+
* @member {Number} windowId=new Date().getTime()
|
77
|
+
* @protected
|
78
|
+
*/
|
79
|
+
windowId: new Date().getTime(),
|
75
80
|
/**
|
76
81
|
* Contains the fileNames for the App, Data & Vdom workers
|
77
82
|
* @member {Object} workers
|
@@ -174,9 +179,10 @@ class Manager extends Base {
|
|
174
179
|
* Calls createWorker for each worker inside the this.workers config.
|
175
180
|
*/
|
176
181
|
createWorkers() {
|
177
|
-
let me
|
178
|
-
config
|
179
|
-
hash
|
182
|
+
let me = this,
|
183
|
+
config = Neo.clone(NeoConfig, true),
|
184
|
+
hash = location.hash,
|
185
|
+
windowId = me.windowId,
|
180
186
|
key, value;
|
181
187
|
|
182
188
|
// remove configs which are not relevant for the workers scope
|
@@ -186,7 +192,8 @@ class Manager extends Base {
|
|
186
192
|
if (hash) {
|
187
193
|
config.hash = {
|
188
194
|
hash : DomEvents.parseHash(hash.substring(1)),
|
189
|
-
hashString: hash.substring(1)
|
195
|
+
hashString: hash.substring(1),
|
196
|
+
windowId : me.windowId
|
190
197
|
}
|
191
198
|
}
|
192
199
|
|
package/test/components/app.mjs
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
import '../../src/button/Base.mjs';
|
5
5
|
import '../../src/component/DateSelector.mjs';
|
6
|
+
import '../../src/form/field/ComboBox.mjs';
|
6
7
|
import '../../src/list/Chip.mjs';
|
7
|
-
import '../../src/form/field/Select.mjs';
|
8
8
|
|
9
9
|
export const onStart = () => Neo.app({name: 'AppEmpty'})
|
@@ -3,7 +3,7 @@ StartTest(t => {
|
|
3
3
|
|
4
4
|
async function setup(config = {}) {
|
5
5
|
testId = await Neo.worker.App.createNeoInstance(Neo.merge({
|
6
|
-
ntype : '
|
6
|
+
ntype : 'combobox',
|
7
7
|
labelPosition: 'inline',
|
8
8
|
labelText : 'US States',
|
9
9
|
labelWidth : 80,
|
@@ -17,10 +17,10 @@ StartTest(t => {
|
|
17
17
|
model: {
|
18
18
|
fields: [{
|
19
19
|
name: 'abbreviation',
|
20
|
-
type: '
|
20
|
+
type: 'String'
|
21
21
|
}, {
|
22
22
|
name: 'name',
|
23
|
-
type: '
|
23
|
+
type: 'String'
|
24
24
|
}]
|
25
25
|
}
|
26
26
|
}
|
@@ -202,17 +202,19 @@ StartTest(t => {
|
|
202
202
|
|
203
203
|
await t.waitFor(100);
|
204
204
|
|
205
|
-
//
|
206
|
-
|
205
|
+
// typeahead input must be cleared, forceSelection must pick the closest value onFocusLeave
|
206
|
+
// todo: add another test without forceSelection => Inputs must have been cleared. Both typeahead and filter.
|
207
|
+
t.isDeeply(t.query(`#${testId} input`).map(i => i.value), ['', 'Marshall Islands']);
|
207
208
|
|
208
209
|
blurEl.remove();
|
209
210
|
});
|
210
211
|
|
211
212
|
t.it('With store as data', async t => {
|
212
213
|
await setup({
|
213
|
-
labelText
|
214
|
-
store
|
214
|
+
labelText: 'Foo',
|
215
|
+
store : ['Foo', 'Bar', 'Bletch']
|
215
216
|
});
|
217
|
+
|
216
218
|
await t.click('.neo-field-trigger.fa-caret-down');
|
217
219
|
|
218
220
|
await t.waitForSelector('.neo-list-item:contains(Foo)');
|
@@ -1,9 +0,0 @@
|
|
1
|
-
:root .neo-theme-dark { // .neo-selectfield
|
2
|
-
--selectfield-input-hint-color : #bbb;
|
3
|
-
--selectfield-input-hint-opacity : 0.6;
|
4
|
-
--selectfield-list-search-background-color : inherit;
|
5
|
-
--selectfield-list-search-color : #fff;
|
6
|
-
--selectfield-list-search-color-selected : #000;
|
7
|
-
--selectfield-picker-container-border : 1px solid #bbb;
|
8
|
-
--selectfield-picker-container-border-radius: 0;
|
9
|
-
}
|
@@ -1,9 +0,0 @@
|
|
1
|
-
:root .neo-theme-light { // .neo-selectfield
|
2
|
-
--selectfield-input-hint-color : #333;
|
3
|
-
--selectfield-input-hint-opacity : 0.6;
|
4
|
-
--selectfield-list-search-background-color : inherit;
|
5
|
-
--selectfield-list-search-color : red;
|
6
|
-
--selectfield-list-search-color-selected : red;
|
7
|
-
--selectfield-picker-container-border : 1px solid #1c60a0;
|
8
|
-
--selectfield-picker-container-border-radius: 3px;
|
9
|
-
}
|
@@ -1,9 +0,0 @@
|
|
1
|
-
:root .neo-theme-neo-light { // .neo-selectfield
|
2
|
-
--selectfield-input-hint-color : #333;
|
3
|
-
--selectfield-input-hint-opacity : 0.6;
|
4
|
-
--selectfield-list-search-background-color : inherit;
|
5
|
-
--selectfield-list-search-color : red;
|
6
|
-
--selectfield-list-search-color-selected : red;
|
7
|
-
--selectfield-picker-container-border : 1px solid #1c60a0;
|
8
|
-
--selectfield-picker-container-border-radius: 3px;
|
9
|
-
}
|