neo.mjs 6.10.10 → 6.10.11
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/view/learn/ContentTreeList.mjs +24 -12
- package/apps/portal/view/learn/LivePreview.mjs +28 -11
- package/buildScripts/createAppMinimal.mjs +391 -0
- package/examples/ServiceWorker.mjs +2 -2
- package/examples/button/base/neo-config.json +2 -1
- package/examples/list/chip/neo-config.json +1 -2
- package/package.json +72 -70
- package/resources/data/deck/learnneo/data/theBeatles.json +22 -0
- package/resources/data/deck/learnneo/p/2023-10-14T19-25-08-153Z.md +29 -20
- package/resources/data/deck/learnneo/p/ComponentModels.md +116 -1
- package/resources/data/deck/learnneo/p/Config.md +157 -0
- package/resources/data/deck/learnneo/p/DescribingTheUI.md +67 -1
- package/resources/data/deck/learnneo/p/Earthquakes.md +214 -0
- package/resources/data/deck/learnneo/p/Events.md +142 -1
- package/resources/data/deck/learnneo/p/Extending.md +116 -1
- package/resources/data/deck/learnneo/p/References.md +126 -0
- package/resources/data/deck/learnneo/p/TestLivePreview.md +28 -6
- package/resources/data/deck/learnneo/t.json +5 -6
- package/resources/data/deck/training/p/2022-12-27T21-55-30-948Z.md +1 -1
- package/resources/data/deck/training/p/2022-12-27T22-23-55-083Z.md +1 -1
- package/resources/data/deck/training/p/2022-12-29T16-00-13-223Z.md +1 -1
- package/resources/data/deck/training/p/2022-12-29T18-34-25-826Z.md +1 -1
- package/resources/data/deck/training/p/2022-12-29T18-36-56-893Z.md +1 -1
- package/resources/data/deck/training/p/2022-12-31T18-43-56-338Z.md +1 -1
- package/resources/data/deck/training/p/2022-12-31T18-51-50-682Z.md +1 -1
- package/resources/data/deck/training/p/2022-12-31T18-54-04-176Z.md +1 -1
- package/resources/data/deck/training/p/2023-01-01T17-49-18-429Z.md +1 -1
- package/resources/data/deck/training/p/2023-01-01T21-23-17-716Z.md +1 -1
- package/resources/data/deck/training/p/2023-01-06T23-21-31-685Z.md +1 -1
- package/resources/data/deck/training/p/2023-01-06T23-34-13-897Z.md +2 -2
- package/resources/data/deck/training/p/2023-01-06T23-46-36-687Z.md +1 -1
- package/resources/data/deck/training/p/2023-01-08T01-24-21-088Z.md +1 -1
- package/resources/data/deck/training/p/2023-01-08T02-11-26-333Z.md +2 -2
- package/resources/data/deck/training/p/2023-01-14T00-40-27-784Z.md +2 -2
- package/resources/data/deck/training/p/2023-07-31T00-37-21-927Z.md +2 -2
- package/resources/data/deck/training/p/2023-10-14T19-25-08-153Z.md +3 -3
- package/resources/scss/src/apps/newwebsite/Viewport.scss +32 -0
- package/resources/scss/src/apps/portal/learn/ContentView.scss +20 -4
- package/resources/scss/src/apps/portal/learn/LivePreview.scss +8 -0
- package/resources/scss/src/component/Base.scss +13 -4
- package/resources/scss/src/form/field/Select.scss +2 -5
- package/resources/scss/src/form/field/Text.scss +0 -1
- package/resources/scss/src/list/Base.scss +47 -2
- package/resources/scss/src/list/Chip.scss +10 -4
- package/resources/scss/theme-dark/list/Base.scss +11 -10
- package/resources/scss/theme-light/list/Base.scss +11 -10
- package/resources/scss/theme-neo-light/design-tokens/Components.scss +3 -0
- package/resources/scss/theme-neo-light/list/Base.scss +1 -0
- package/src/DefaultConfig.mjs +3 -3
- package/src/component/Base.mjs +7 -0
- package/src/container/Base.mjs +6 -12
- package/src/core/Base.mjs +5 -2
- package/src/data/Model.mjs +7 -0
- package/src/data/RecordFactory.mjs +5 -4
- package/src/form/field/Base.mjs +11 -0
- package/src/form/field/Picker.mjs +0 -1
- package/src/form/field/Select.mjs +208 -257
- package/src/form/field/Text.mjs +3 -3
- package/src/form/field/trigger/Base.mjs +5 -6
- package/src/layout/Flexbox.mjs +23 -31
- package/src/layout/HBox.mjs +1 -1
- package/src/layout/VBox.mjs +1 -1
- package/src/list/Base.mjs +64 -31
- package/src/main/DomAccess.mjs +55 -28
- package/src/main/DomEvents.mjs +2 -1
- package/src/main/DomUtils.mjs +66 -0
- package/src/main/addon/Navigator.mjs +332 -0
- package/src/manager/DomEvent.mjs +2 -1
- package/src/selection/ListModel.mjs +46 -82
- package/src/selection/Model.mjs +56 -33
- package/src/util/Array.mjs +5 -2
- package/src/util/Function.mjs +31 -0
- package/src/util/String.mjs +9 -0
- package/src/vdom/Helper.mjs +1 -2
- package/test/components/app.mjs +4 -3
- package/test/components/files/component/ChipList.mjs +125 -0
- package/test/components/files/form/field/Select.mjs +177 -2
- package/test/components/siesta.js +34 -1
@@ -37,7 +37,7 @@ class Base extends Component {
|
|
37
37
|
/**
|
38
38
|
* @member {Neo.form.field.Base|null} field=null
|
39
39
|
*/
|
40
|
-
|
40
|
+
field_: null,
|
41
41
|
/**
|
42
42
|
* @member {String|null} iconCls_=null
|
43
43
|
*/
|
@@ -62,11 +62,6 @@ class Base extends Component {
|
|
62
62
|
* @protected
|
63
63
|
*/
|
64
64
|
type: 'base',
|
65
|
-
/**
|
66
|
-
* @member {Object} _vdom={tabIndex: -1}
|
67
|
-
*/
|
68
|
-
_vdom:
|
69
|
-
{tabIndex: -1},
|
70
65
|
/**
|
71
66
|
* @member {Number} weight_=10
|
72
67
|
*/
|
@@ -110,6 +105,10 @@ class Base extends Component {
|
|
110
105
|
this.cls = cls;
|
111
106
|
}
|
112
107
|
|
108
|
+
afterSetField(field) {
|
109
|
+
(this.vdom.data || (this.vdom.data = {})).focus = field && field.getInputElId();
|
110
|
+
}
|
111
|
+
|
113
112
|
/**
|
114
113
|
* Triggered after the hidden config got changed
|
115
114
|
* @param {Boolean} value
|
package/src/layout/Flexbox.mjs
CHANGED
@@ -85,7 +85,7 @@ class Flexbox extends Base {
|
|
85
85
|
* @protected
|
86
86
|
*/
|
87
87
|
afterSetAlign(value, oldValue) {
|
88
|
-
oldValue && this.updateInputValue(value, oldValue, 'align')
|
88
|
+
oldValue && this.updateInputValue(value, oldValue, 'align')
|
89
89
|
}
|
90
90
|
|
91
91
|
/**
|
@@ -95,7 +95,7 @@ class Flexbox extends Base {
|
|
95
95
|
* @protected
|
96
96
|
*/
|
97
97
|
afterSetDirection(value, oldValue) {
|
98
|
-
oldValue && this.updateInputValue(value, oldValue, 'direction')
|
98
|
+
oldValue && this.updateInputValue(value, oldValue, 'direction')
|
99
99
|
}
|
100
100
|
|
101
101
|
/**
|
@@ -111,7 +111,7 @@ class Flexbox extends Base {
|
|
111
111
|
style = item.wrapperStyle;
|
112
112
|
|
113
113
|
style.gap = value;
|
114
|
-
item.wrapperStyle = style
|
114
|
+
item.wrapperStyle = style
|
115
115
|
}
|
116
116
|
|
117
117
|
/**
|
@@ -121,7 +121,7 @@ class Flexbox extends Base {
|
|
121
121
|
* @protected
|
122
122
|
*/
|
123
123
|
afterSetPack(value, oldValue) {
|
124
|
-
oldValue && this.updateInputValue(value, oldValue, 'pack')
|
124
|
+
oldValue && this.updateInputValue(value, oldValue, 'pack')
|
125
125
|
}
|
126
126
|
|
127
127
|
/**
|
@@ -131,7 +131,7 @@ class Flexbox extends Base {
|
|
131
131
|
* @protected
|
132
132
|
*/
|
133
133
|
afterSetWrap(value, oldValue) {
|
134
|
-
oldValue && this.updateInputValue(value, oldValue, 'wrap')
|
134
|
+
oldValue && this.updateInputValue(value, oldValue, 'wrap')
|
135
135
|
}
|
136
136
|
|
137
137
|
/**
|
@@ -143,11 +143,11 @@ class Flexbox extends Base {
|
|
143
143
|
flex = style.flex || item.flex || (this.align === 'stretch' ? 1 : '0 1 auto');
|
144
144
|
|
145
145
|
if (flex === 1) {
|
146
|
-
flex = '1 1 auto'
|
146
|
+
flex = '1 1 auto'
|
147
147
|
}
|
148
148
|
|
149
149
|
style.flex = flex;
|
150
|
-
item.wrapperStyle = style
|
150
|
+
item.wrapperStyle = style
|
151
151
|
}
|
152
152
|
|
153
153
|
/**
|
@@ -160,7 +160,7 @@ class Flexbox extends Base {
|
|
160
160
|
wrapperCls = container?.wrapperCls || [];
|
161
161
|
|
162
162
|
if (!container) {
|
163
|
-
Neo.logError('layout.Flexbox: applyRenderAttributes -> container not yet created', me.containerId)
|
163
|
+
Neo.logError('layout.Flexbox: applyRenderAttributes -> container not yet created', me.containerId)
|
164
164
|
}
|
165
165
|
|
166
166
|
NeoArray.add(wrapperCls, prefix + 'container');
|
@@ -170,7 +170,7 @@ class Flexbox extends Base {
|
|
170
170
|
me.pack && NeoArray.add(wrapperCls, prefix + 'pack-' + me.pack);
|
171
171
|
me.wrap && NeoArray.add(wrapperCls, prefix + 'wrap-' + me.wrap);
|
172
172
|
|
173
|
-
container.wrapperCls = wrapperCls
|
173
|
+
container.wrapperCls = wrapperCls
|
174
174
|
}
|
175
175
|
|
176
176
|
/**
|
@@ -181,7 +181,7 @@ class Flexbox extends Base {
|
|
181
181
|
* @returns {String|null} value
|
182
182
|
*/
|
183
183
|
beforeSetAlign(value, oldValue) {
|
184
|
-
return this.testInputValue(value, oldValue, 'alignValues', 'align')
|
184
|
+
return this.testInputValue(value, oldValue, 'alignValues', 'align')
|
185
185
|
}
|
186
186
|
|
187
187
|
/**
|
@@ -203,7 +203,7 @@ class Flexbox extends Base {
|
|
203
203
|
* @returns {String|null} value
|
204
204
|
*/
|
205
205
|
beforeSetPack(value, oldValue) {
|
206
|
-
return this.testInputValue(value, oldValue, 'packValues', 'pack')
|
206
|
+
return this.testInputValue(value, oldValue, 'packValues', 'pack')
|
207
207
|
}
|
208
208
|
|
209
209
|
/**
|
@@ -214,7 +214,7 @@ class Flexbox extends Base {
|
|
214
214
|
* @returns {String} value
|
215
215
|
*/
|
216
216
|
beforeSetWrap(value, oldValue) {
|
217
|
-
return this.testInputValue(value, oldValue, 'wrapValues', 'wrap')
|
217
|
+
return this.testInputValue(value, oldValue, 'wrapValues', 'wrap')
|
218
218
|
}
|
219
219
|
|
220
220
|
/**
|
@@ -227,7 +227,7 @@ class Flexbox extends Base {
|
|
227
227
|
let style = item.wrapperStyle || {};
|
228
228
|
|
229
229
|
style.flex = item.flex || null;
|
230
|
-
item.wrapperStyle = style
|
230
|
+
item.wrapperStyle = style
|
231
231
|
}
|
232
232
|
|
233
233
|
/**
|
@@ -242,25 +242,17 @@ class Flexbox extends Base {
|
|
242
242
|
wrapperCls = container?.wrapperCls || [];
|
243
243
|
|
244
244
|
if (!container) {
|
245
|
-
Neo.logError('layout.Flexbox: removeRenderAttributes -> container not yet created', me.containerId)
|
245
|
+
Neo.logError('layout.Flexbox: removeRenderAttributes -> container not yet created', me.containerId)
|
246
246
|
}
|
247
247
|
|
248
248
|
NeoArray.remove(wrapperCls, prefix + 'container');
|
249
249
|
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
NeoArray.remove(wrapperCls, prefix + 'direction-' + me.direction);
|
255
|
-
}
|
256
|
-
if (me.pack) {
|
257
|
-
NeoArray.remove(wrapperCls, prefix + 'pack-' + me.pack);
|
258
|
-
}
|
259
|
-
if (me.wrap) {
|
260
|
-
NeoArray.remove(wrapperCls, prefix + 'wrap-' + me.wrap);
|
261
|
-
}
|
250
|
+
me.align && NeoArray.remove(wrapperCls, prefix + 'align-' + me.align);
|
251
|
+
me.direction && NeoArray.remove(wrapperCls, prefix + 'direction-' + me.direction);
|
252
|
+
me.pack && NeoArray.remove(wrapperCls, prefix + 'pack-' + me.pack);
|
253
|
+
me.wrap && NeoArray.remove(wrapperCls, prefix + 'wrap-' + me.wrap);
|
262
254
|
|
263
|
-
container.wrapperCls = wrapperCls
|
255
|
+
container.wrapperCls = wrapperCls
|
264
256
|
}
|
265
257
|
|
266
258
|
/**
|
@@ -277,10 +269,10 @@ class Flexbox extends Base {
|
|
277
269
|
|
278
270
|
if (!NeoArray.hasItem(validValues, value)) {
|
279
271
|
Neo.logError(this.containerId, '-> layout: supported values for "' + propertyName + '" are' , validValues);
|
280
|
-
return oldValue
|
272
|
+
return oldValue
|
281
273
|
}
|
282
274
|
|
283
|
-
return value
|
275
|
+
return value
|
284
276
|
}
|
285
277
|
|
286
278
|
/**
|
@@ -300,10 +292,10 @@ class Flexbox extends Base {
|
|
300
292
|
NeoArray.remove(wrapperCls, prefix + propertyName + '-' + oldValue);
|
301
293
|
|
302
294
|
if (value !== null) {
|
303
|
-
NeoArray.add(wrapperCls, prefix + propertyName + '-' + value)
|
295
|
+
NeoArray.add(wrapperCls, prefix + propertyName + '-' + value)
|
304
296
|
}
|
305
297
|
|
306
|
-
container.wrapperCls = wrapperCls
|
298
|
+
container.wrapperCls = wrapperCls
|
307
299
|
}
|
308
300
|
}
|
309
301
|
}
|
package/src/layout/HBox.mjs
CHANGED
package/src/layout/VBox.mjs
CHANGED
package/src/list/Base.mjs
CHANGED
@@ -135,7 +135,13 @@ class Base extends Component {
|
|
135
135
|
* @member {Object} _vdom
|
136
136
|
*/
|
137
137
|
_vdom:
|
138
|
-
{tag: 'ul', cn: []}
|
138
|
+
{tag: 'ul', cn: []},
|
139
|
+
|
140
|
+
/**
|
141
|
+
* An object to help configure the navigation. Used to pass to {@link Neo.main.addon.Navigator#subscribe}.
|
142
|
+
* @member {Object} navigator={}
|
143
|
+
*/
|
144
|
+
navigator : {}
|
139
145
|
}
|
140
146
|
|
141
147
|
/**
|
@@ -172,16 +178,15 @@ class Base extends Component {
|
|
172
178
|
* @param {Number|null} oldValue
|
173
179
|
* @protected
|
174
180
|
*/
|
175
|
-
afterSetActiveIndex(value
|
176
|
-
let me
|
177
|
-
selectionModel = me.selectionModel;
|
181
|
+
afterSetActiveIndex(value) {
|
182
|
+
let me = this;
|
178
183
|
|
179
184
|
if (Neo.isNumber(value)) {
|
180
|
-
selectionModel?.selectAt(value);
|
181
185
|
me.headerlessActiveIndex = me.getHeaderlessIndex(value)
|
182
|
-
|
183
|
-
|
184
|
-
|
186
|
+
Neo.main.addon.Navigator.navigateTo([value, this.navigator])
|
187
|
+
}
|
188
|
+
else if (value) {
|
189
|
+
Neo.main.addon.Navigator.navigateTo([me.getItemId(value[me.getKeyProperty()]), this.navigator])
|
185
190
|
}
|
186
191
|
}
|
187
192
|
|
@@ -257,6 +262,33 @@ class Base extends Component {
|
|
257
262
|
}
|
258
263
|
}
|
259
264
|
|
265
|
+
afterSetMounted(value) {
|
266
|
+
const me = this;
|
267
|
+
|
268
|
+
// Tear down navigation before we lose the element
|
269
|
+
if (!value && me.hasNavigator) {
|
270
|
+
Neo.main.addon.Navigator.unsubscribe(me.navigator);
|
271
|
+
me.hasNavigator = false;
|
272
|
+
me.activeIndex = null
|
273
|
+
}
|
274
|
+
|
275
|
+
super.afterSetMounted(...arguments);
|
276
|
+
|
277
|
+
if (value) {
|
278
|
+
// Set up item navigation in the list
|
279
|
+
if (!me.hasNavigator) {
|
280
|
+
me.navigator = {
|
281
|
+
appName : me.appName,
|
282
|
+
id : me.id,
|
283
|
+
selector : `.${me.itemCls}:not(.neo-disabled,.neo-list-header)`,
|
284
|
+
...me.navigator
|
285
|
+
}
|
286
|
+
me.hasNavigator = true;
|
287
|
+
}
|
288
|
+
Neo.main.addon.Navigator.subscribe(me.navigator)
|
289
|
+
}
|
290
|
+
}
|
291
|
+
|
260
292
|
/**
|
261
293
|
* Triggered after the selectionModel config got changed
|
262
294
|
* @param {Neo.selection.Model} value
|
@@ -392,12 +424,16 @@ class Base extends Component {
|
|
392
424
|
}
|
393
425
|
|
394
426
|
item = {
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
427
|
+
id : itemId,
|
428
|
+
tag : isHeader ? 'dt' : me.itemTagName,
|
429
|
+
'aria-selected' : false,
|
430
|
+
cls
|
399
431
|
};
|
400
432
|
|
433
|
+
if (me.itemsFocusable) {
|
434
|
+
item.tabIndex = -1;
|
435
|
+
}
|
436
|
+
|
401
437
|
if (record.hidden) {
|
402
438
|
item.removeDom = true
|
403
439
|
}
|
@@ -513,15 +549,7 @@ class Base extends Component {
|
|
513
549
|
* @param {String} [id]
|
514
550
|
*/
|
515
551
|
focus(id) {
|
516
|
-
|
517
|
-
|
518
|
-
let me = this;
|
519
|
-
|
520
|
-
id && me.scrollIntoViewOnFocus && Neo.main.DomAccess.scrollIntoView({
|
521
|
-
appName : me.appName,
|
522
|
-
behavior: 'auto',
|
523
|
-
id : id || me.id
|
524
|
-
})
|
552
|
+
Neo.main.addon.Navigator.navigateTo(id, this.navigator)
|
525
553
|
}
|
526
554
|
|
527
555
|
/**
|
@@ -569,11 +597,11 @@ class Base extends Component {
|
|
569
597
|
}
|
570
598
|
|
571
599
|
/**
|
572
|
-
* @param {Number|String}
|
600
|
+
* @param {Number|String|object} recordOrId
|
573
601
|
* @returns {String}
|
574
602
|
*/
|
575
|
-
getItemId(
|
576
|
-
return `${this.id}__${
|
603
|
+
getItemId(recordOrId) {
|
604
|
+
return `${this.id}__${recordOrId.isRecord ? recordOrId[this.getKeyProperty()] : recordOrId}`
|
577
605
|
}
|
578
606
|
|
579
607
|
/**
|
@@ -655,10 +683,6 @@ class Base extends Component {
|
|
655
683
|
// pass the record to class extensions
|
656
684
|
data.record = record;
|
657
685
|
|
658
|
-
if (!me.disableSelection && (!me.useHeaders || !record.isHeader)) {
|
659
|
-
me.selectionModel?.select(node.id)
|
660
|
-
}
|
661
|
-
|
662
686
|
/**
|
663
687
|
* The itemClick event fires when a click occurs on a list item
|
664
688
|
* @event itemClick
|
@@ -723,10 +747,19 @@ class Base extends Component {
|
|
723
747
|
|
724
748
|
/**
|
725
749
|
* Convenience shortcut
|
726
|
-
* @param {Number}
|
750
|
+
* @param {Number|String} item
|
727
751
|
*/
|
728
|
-
selectItem(
|
729
|
-
!this.disableSelection
|
752
|
+
selectItem(item) {
|
753
|
+
if (!this.disableSelection) {
|
754
|
+
// Selecting index
|
755
|
+
if (Neo.isNumber(item)) {
|
756
|
+
this.selectionModel?.selectAt(item)
|
757
|
+
}
|
758
|
+
// Selecting record
|
759
|
+
else if (item) {
|
760
|
+
this.selectionModel?.selectAt(this.store.indexOf(item));
|
761
|
+
}
|
762
|
+
}
|
730
763
|
}
|
731
764
|
}
|
732
765
|
|
package/src/main/DomAccess.mjs
CHANGED
@@ -2,23 +2,14 @@ import Base from '../core/Base.mjs';
|
|
2
2
|
import DeltaUpdates from './mixin/DeltaUpdates.mjs';
|
3
3
|
import Observable from '../core/Observable.mjs';
|
4
4
|
import Rectangle from '../util/Rectangle.mjs';
|
5
|
+
import String from '../util/String.mjs';
|
6
|
+
import DomUtils from './DomUtils.mjs';
|
5
7
|
|
6
8
|
const
|
7
9
|
doPreventDefault = e => e.preventDefault(),
|
8
|
-
filterTabbable = e => !e.classList.contains('neo-focus-trap') && isTabbable(e) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP,
|
10
|
+
filterTabbable = e => !e.classList.contains('neo-focus-trap') && DomUtils.isTabbable(e) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP,
|
9
11
|
lengthRE = /^\d+\w+$/,
|
10
12
|
|
11
|
-
focusableTags = {
|
12
|
-
BODY : 1,
|
13
|
-
BUTTON : 1,
|
14
|
-
EMBED : 1,
|
15
|
-
IFRAME : 1,
|
16
|
-
INPUT : 1,
|
17
|
-
OBJECT : 1,
|
18
|
-
SELECT : 1,
|
19
|
-
TEXTAREA : 1
|
20
|
-
},
|
21
|
-
|
22
13
|
fontSizeProps = [
|
23
14
|
'font-family',
|
24
15
|
'font-kerning',
|
@@ -34,21 +25,15 @@ const
|
|
34
25
|
'word-break'
|
35
26
|
],
|
36
27
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
}
|
47
|
-
|
48
|
-
return focusableTags[nodeName] ||
|
49
|
-
((nodeName === 'A' || nodeName === 'LINK') && !!e.href) ||
|
50
|
-
(tabIndex != null && Number(tabIndex) >= 0) ||
|
51
|
-
e.contentEditable === 'true'
|
28
|
+
capturePassive = {
|
29
|
+
capture : true,
|
30
|
+
passive : true
|
31
|
+
},
|
32
|
+
modifierKeys = {
|
33
|
+
Shift : 1,
|
34
|
+
Alt : 1,
|
35
|
+
Meta : 1,
|
36
|
+
Control : 1
|
52
37
|
};
|
53
38
|
|
54
39
|
/**
|
@@ -103,6 +88,8 @@ class DomAccess extends Base {
|
|
103
88
|
'getScrollingDimensions',
|
104
89
|
'measure',
|
105
90
|
'monitorAutoGrow',
|
91
|
+
'navigate',
|
92
|
+
'navigateTo',
|
106
93
|
'scrollBy',
|
107
94
|
'scrollIntoView',
|
108
95
|
'scrollTo',
|
@@ -168,11 +155,51 @@ class DomAccess extends Base {
|
|
168
155
|
}, 250)
|
169
156
|
}
|
170
157
|
|
158
|
+
me.initGlobalListeners();
|
159
|
+
|
171
160
|
// Set up our aligning callback which is called when things change which may
|
172
161
|
// mean that alignments need to be updated.
|
173
162
|
me.syncAligns = me.syncAligns.bind(me)
|
174
163
|
}
|
175
164
|
|
165
|
+
initGlobalListeners() {
|
166
|
+
const me = this;
|
167
|
+
|
168
|
+
document.addEventListener('mousedown', me.onDocumentMouseDown.bind(me), { capture : true });
|
169
|
+
document.addEventListener('keydown', me.onDocumentKeyDown.bind(me), capturePassive);
|
170
|
+
document.addEventListener('keyup', me.onDocumentKeyUp.bind(me), capturePassive);
|
171
|
+
document.addEventListener('blur', me.onDocumentBlur.bind(me), capturePassive);
|
172
|
+
}
|
173
|
+
|
174
|
+
onDocumentMouseDown(e) {
|
175
|
+
const focusController = e.target?.closest('[data-focus]');
|
176
|
+
|
177
|
+
// data-focus on an element means reject mousedown gestures, and move focus
|
178
|
+
// to the referenced element.
|
179
|
+
if (focusController) {
|
180
|
+
e.preventDefault();
|
181
|
+
document.getElementById(focusController.dataset.focus)?.focus();
|
182
|
+
}
|
183
|
+
}
|
184
|
+
|
185
|
+
onDocumentKeyDown(keyEvent) {
|
186
|
+
if (modifierKeys[keyEvent.key]) {
|
187
|
+
// eg Neo.isShiftKeyDown = true or Neo.isControlKeyDown = true.
|
188
|
+
// Selection can consult this value
|
189
|
+
Neo[`${String.uncapitalize(keyEvent.key)}KeyDown`] = true;
|
190
|
+
}
|
191
|
+
}
|
192
|
+
|
193
|
+
onDocumentKeyUp(keyEvent) {
|
194
|
+
if (modifierKeys[keyEvent.key]) {
|
195
|
+
Neo[`${String.uncapitalize(keyEvent.key)}KeyDown`] = false;
|
196
|
+
}
|
197
|
+
}
|
198
|
+
|
199
|
+
onDocumentBlur() {
|
200
|
+
Neo.altKeyDown = Neo.controlKeyDown = Neo.metaKeyDown = Neo.shiftKeyDown = false;
|
201
|
+
}
|
202
|
+
|
176
203
|
/**
|
177
204
|
* @param {Object} alignSpec
|
178
205
|
*/
|
@@ -433,7 +460,7 @@ class DomAccess extends Base {
|
|
433
460
|
{ defaultView } = node.ownerDocument,
|
434
461
|
rect = this.getBoundingClientRect(node);
|
435
462
|
|
436
|
-
for (let parentElement = node.offsetParent; rect && parentElement !== document.documentElement; parentElement = parentElement.parentElement) {
|
463
|
+
for (let parentElement = node.offsetParent; parentElement && rect && parentElement !== document.documentElement; parentElement = parentElement.parentElement) {
|
437
464
|
if (defaultView.getComputedStyle(parentElement).getPropertyValue('overflow') !== 'visible') {
|
438
465
|
rect = rect.intersects(this.getBoundingClientRect(parentElement))
|
439
466
|
}
|
package/src/main/DomEvents.mjs
CHANGED
@@ -267,7 +267,8 @@ class DomEvents extends Base {
|
|
267
267
|
path : path.map(e => this.getTargetData(e)),
|
268
268
|
target : this.getTargetData(event.target),
|
269
269
|
timeStamp: event.timeStamp,
|
270
|
-
type : event.type
|
270
|
+
type : event.type,
|
271
|
+
data : {...event.target.dataset}
|
271
272
|
};
|
272
273
|
|
273
274
|
if (event.relatedTarget) {
|
@@ -0,0 +1,66 @@
|
|
1
|
+
import Base from '../core/Base.mjs';
|
2
|
+
|
3
|
+
const focusableTags = {
|
4
|
+
BODY : 1,
|
5
|
+
BUTTON : 1,
|
6
|
+
EMBED : 1,
|
7
|
+
IFRAME : 1,
|
8
|
+
INPUT : 1,
|
9
|
+
OBJECT : 1,
|
10
|
+
SELECT : 1,
|
11
|
+
TEXTAREA : 1
|
12
|
+
};
|
13
|
+
|
14
|
+
/**
|
15
|
+
* @class Neo.main.DomUtils
|
16
|
+
* @extends Neo.core.Base
|
17
|
+
* @singleton
|
18
|
+
*/
|
19
|
+
export default class DomUtils extends Base {
|
20
|
+
static config = {
|
21
|
+
/**
|
22
|
+
* @member {String} className='Neo.main.DomUtils'
|
23
|
+
* @protected
|
24
|
+
*/
|
25
|
+
className: 'Neo.main.DomUtils'
|
26
|
+
}
|
27
|
+
|
28
|
+
/**
|
29
|
+
* Analogous to the `HTMLElement` `closest` method. Searches starting at the passed element for
|
30
|
+
* an element for which the passed `filterFn` returns `true`
|
31
|
+
* @param {HTMLElement} el The element to start from.
|
32
|
+
* @param {Function} filterFn A function which returns `true` when the desired element is reached.
|
33
|
+
* @param {HTMLElement} [limit] The element to stop at. This is *not* considered for matching.
|
34
|
+
* @returns
|
35
|
+
*/
|
36
|
+
static closest(el, filterFn, limit = document.body) {
|
37
|
+
while (el?.nodeType === Node.ELEMENT_NODE && el !== limit) {
|
38
|
+
if (filterFn(el)) {
|
39
|
+
return el;
|
40
|
+
}
|
41
|
+
el = el.parentNode;
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
static isFocusable(e) {
|
46
|
+
// May be used as a scopeless callback, so use "DomUtils", not "this"
|
47
|
+
return DomUtils.isTabbable(e) || e.getAttribute('tabIndex') == -1;
|
48
|
+
}
|
49
|
+
|
50
|
+
static isTabbable(e) {
|
51
|
+
const
|
52
|
+
{ nodeName } = e,
|
53
|
+
style = getComputedStyle(e),
|
54
|
+
tabIndex = e.getAttribute('tabIndex');
|
55
|
+
|
56
|
+
// Hidden elements not tabbable
|
57
|
+
if (!e.offsetParent || style.getPropertyValue('visibility') === 'hidden') {
|
58
|
+
return false
|
59
|
+
}
|
60
|
+
|
61
|
+
return focusableTags[nodeName] ||
|
62
|
+
((nodeName === 'A' || nodeName === 'LINK') && !!e.href) ||
|
63
|
+
(tabIndex != null && Number(tabIndex) >= 0) ||
|
64
|
+
e.contentEditable === 'true'
|
65
|
+
}
|
66
|
+
}
|