cx 23.5.0 → 23.5.1
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/dist/manifest.js +791 -791
- package/dist/ui.js +7 -2
- package/dist/widgets.js +8 -4
- package/package.json +1 -1
- package/src/data/StringTemplate.spec.js +105 -95
- package/src/ui/FocusManager.js +171 -171
- package/src/widgets/grid/Grid.js +3273 -3266
package/dist/ui.js
CHANGED
|
@@ -1403,14 +1403,19 @@ function unfocusElement(target, unfocusParentOverlay) {
|
|
|
1403
1403
|
if (!target) target = activeElement;
|
|
1404
1404
|
if (unfocusParentOverlay) {
|
|
1405
1405
|
var focusableOverlayContainer = closestParent(target, function (el) {
|
|
1406
|
-
|
|
1406
|
+
var _el$dataset;
|
|
1407
|
+
return (_el$dataset = el.dataset) == null ? void 0 : _el$dataset.focusableOverlayContainer;
|
|
1407
1408
|
});
|
|
1408
1409
|
if (focusableOverlayContainer) target = focusableOverlayContainer;
|
|
1409
1410
|
}
|
|
1410
1411
|
|
|
1411
1412
|
//find the closest focusable parent of the target element and focus it instead
|
|
1412
1413
|
var focusableParent = closestParent(target, function (el) {
|
|
1413
|
-
|
|
1414
|
+
var _el$dataset2;
|
|
1415
|
+
return (
|
|
1416
|
+
isFocusable(el) &&
|
|
1417
|
+
(!unfocusParentOverlay || ((_el$dataset2 = el.dataset) == null ? void 0 : _el$dataset2.focusableOverlayContainer))
|
|
1418
|
+
);
|
|
1414
1419
|
});
|
|
1415
1420
|
if (focusableParent && focusableParent !== document.body) focusableParent.focus();
|
|
1416
1421
|
else activeElement.blur();
|
package/dist/widgets.js
CHANGED
|
@@ -17364,11 +17364,15 @@ var GridComponent = /*#__PURE__*/ (function (_VDOM$Component) {
|
|
|
17364
17364
|
var widget = instance.widget;
|
|
17365
17365
|
if (widget.scrollable)
|
|
17366
17366
|
this.offResize = ResizeManager.trackElement(this.dom.scroller, function () {
|
|
17367
|
+
//ignore changes if the element is not visible on the page
|
|
17368
|
+
if (_this10.dom.scroller.offsetWidth == 0) return;
|
|
17367
17369
|
//update fixed header/footer
|
|
17368
|
-
|
|
17369
|
-
|
|
17370
|
-
|
|
17371
|
-
|
|
17370
|
+
requestAnimationFrame(function () {
|
|
17371
|
+
_this10.componentDidUpdate();
|
|
17372
|
+
instance.setState({
|
|
17373
|
+
dimensionsVersion: instance.state.dimensionsVersion + 1,
|
|
17374
|
+
lockedColWidth: {},
|
|
17375
|
+
});
|
|
17372
17376
|
});
|
|
17373
17377
|
});
|
|
17374
17378
|
if (widget.pipeKeyDown) instance.invoke("pipeKeyDown", this.handleKeyDown.bind(this), instance);
|
package/package.json
CHANGED
|
@@ -1,95 +1,105 @@
|
|
|
1
|
-
import { StringTemplate } from "./StringTemplate";
|
|
2
|
-
import assert from "assert";
|
|
3
|
-
|
|
4
|
-
describe("StringTemplate", function () {
|
|
5
|
-
describe("#compile()", function () {
|
|
6
|
-
it("returns a selector", function () {
|
|
7
|
-
var e = StringTemplate.compile("Hello {person.name}");
|
|
8
|
-
var state = {
|
|
9
|
-
person: {
|
|
10
|
-
name: "Jim",
|
|
11
|
-
},
|
|
12
|
-
};
|
|
13
|
-
assert.equal(e(state), "Hello Jim");
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it("properly encodes ' and \"", function () {
|
|
17
|
-
var e = StringTemplate.compile('It\'s "working"!');
|
|
18
|
-
assert.equal(e({}), 'It\'s "working"!');
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it("supports multi-line strings", function () {
|
|
22
|
-
var e = StringTemplate.compile("a\nb");
|
|
23
|
-
assert.equal(e(), "a\nb");
|
|
24
|
-
|
|
25
|
-
var e = StringTemplate.compile("a\r\nb");
|
|
26
|
-
assert.equal(e(), "a\r\nb");
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
describe("double brackets are used to escape brackets", function () {
|
|
31
|
-
it("double brackets are preserved", function () {
|
|
32
|
-
var e = StringTemplate.compile("Hello {{person.name}}");
|
|
33
|
-
var state = {
|
|
34
|
-
person: {
|
|
35
|
-
name: "Jim",
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
assert.equal(e(state), "Hello {person.name}");
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it("triple brackets are converted to single brackets and a binding", function () {
|
|
42
|
-
var e = StringTemplate.compile("Hello {{{person.name}}}");
|
|
43
|
-
var state = {
|
|
44
|
-
person: {
|
|
45
|
-
name: "Jim",
|
|
46
|
-
},
|
|
47
|
-
};
|
|
48
|
-
assert.equal(e(state), "Hello {Jim}");
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
describe("supports formatting", function () {
|
|
53
|
-
it("with colon", function () {
|
|
54
|
-
var e = StringTemplate.compile("{str:suffix;kg}");
|
|
55
|
-
assert.equal(e({ str: "5" }), "5kg");
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it("with multiple formats", function () {
|
|
59
|
-
var e = StringTemplate.compile("{str:suffix;kg:wrap;(;)}");
|
|
60
|
-
assert.equal(e({ str: "5" }), "(5kg)");
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it("with null values", function () {
|
|
64
|
-
var e = StringTemplate.compile("{str:suffix;kg:|N/A}");
|
|
65
|
-
assert.equal(e({ str: null }), "N/A");
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it("of null values", function () {
|
|
69
|
-
var e = StringTemplate.compile("{str|N/A}");
|
|
70
|
-
assert.equal(e({ str: null }), "N/A");
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
describe("supports expressions", function () {
|
|
75
|
-
it("using []", function () {
|
|
76
|
-
var e = StringTemplate.compile("1 + 2 = {[1+2]}");
|
|
77
|
-
assert.equal(e(), "1 + 2 = 3");
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it("using %", function () {
|
|
81
|
-
var e = StringTemplate.compile("1 + 2 = %{1+2}");
|
|
82
|
-
assert.equal(e(), "1 + 2 = 3");
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it("with subexpressions", function () {
|
|
86
|
-
var e = StringTemplate.compile("1 + 2 = {[%{1+2}]}");
|
|
87
|
-
assert.equal(e(), "1 + 2 = 3");
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it("with a conditional operator", function () {
|
|
91
|
-
var e = StringTemplate.compile("1 + 2 = {[true ? 3 : 2]:s}");
|
|
92
|
-
assert.equal(e(), "1 + 2 = 3");
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
|
|
1
|
+
import { StringTemplate } from "./StringTemplate";
|
|
2
|
+
import assert from "assert";
|
|
3
|
+
|
|
4
|
+
describe("StringTemplate", function () {
|
|
5
|
+
describe("#compile()", function () {
|
|
6
|
+
it("returns a selector", function () {
|
|
7
|
+
var e = StringTemplate.compile("Hello {person.name}");
|
|
8
|
+
var state = {
|
|
9
|
+
person: {
|
|
10
|
+
name: "Jim",
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
assert.equal(e(state), "Hello Jim");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("properly encodes ' and \"", function () {
|
|
17
|
+
var e = StringTemplate.compile('It\'s "working"!');
|
|
18
|
+
assert.equal(e({}), 'It\'s "working"!');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("supports multi-line strings", function () {
|
|
22
|
+
var e = StringTemplate.compile("a\nb");
|
|
23
|
+
assert.equal(e(), "a\nb");
|
|
24
|
+
|
|
25
|
+
var e = StringTemplate.compile("a\r\nb");
|
|
26
|
+
assert.equal(e(), "a\r\nb");
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe("double brackets are used to escape brackets", function () {
|
|
31
|
+
it("double brackets are preserved", function () {
|
|
32
|
+
var e = StringTemplate.compile("Hello {{person.name}}");
|
|
33
|
+
var state = {
|
|
34
|
+
person: {
|
|
35
|
+
name: "Jim",
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
assert.equal(e(state), "Hello {person.name}");
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("triple brackets are converted to single brackets and a binding", function () {
|
|
42
|
+
var e = StringTemplate.compile("Hello {{{person.name}}}");
|
|
43
|
+
var state = {
|
|
44
|
+
person: {
|
|
45
|
+
name: "Jim",
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
assert.equal(e(state), "Hello {Jim}");
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe("supports formatting", function () {
|
|
53
|
+
it("with colon", function () {
|
|
54
|
+
var e = StringTemplate.compile("{str:suffix;kg}");
|
|
55
|
+
assert.equal(e({ str: "5" }), "5kg");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("with multiple formats", function () {
|
|
59
|
+
var e = StringTemplate.compile("{str:suffix;kg:wrap;(;)}");
|
|
60
|
+
assert.equal(e({ str: "5" }), "(5kg)");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("with null values", function () {
|
|
64
|
+
var e = StringTemplate.compile("{str:suffix;kg:|N/A}");
|
|
65
|
+
assert.equal(e({ str: null }), "N/A");
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("of null values", function () {
|
|
69
|
+
var e = StringTemplate.compile("{str|N/A}");
|
|
70
|
+
assert.equal(e({ str: null }), "N/A");
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("supports expressions", function () {
|
|
75
|
+
it("using []", function () {
|
|
76
|
+
var e = StringTemplate.compile("1 + 2 = {[1+2]}");
|
|
77
|
+
assert.equal(e(), "1 + 2 = 3");
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("using %", function () {
|
|
81
|
+
var e = StringTemplate.compile("1 + 2 = %{1+2}");
|
|
82
|
+
assert.equal(e(), "1 + 2 = 3");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("with subexpressions", function () {
|
|
86
|
+
var e = StringTemplate.compile("1 + 2 = {[%{1+2}]}");
|
|
87
|
+
assert.equal(e(), "1 + 2 = 3");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("with a conditional operator", function () {
|
|
91
|
+
var e = StringTemplate.compile("1 + 2 = {[true ? 3 : 2]:s}");
|
|
92
|
+
assert.equal(e(), "1 + 2 = 3");
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("with sub-expression formatting", function () {
|
|
96
|
+
var e = StringTemplate.compile("{[!!{person.age} ? {person.age:suffix; years old} : 'Age unknown']}");
|
|
97
|
+
var state = {
|
|
98
|
+
person: {
|
|
99
|
+
age: 32,
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
assert.equal(e(state), "32 years old");
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
});
|
package/src/ui/FocusManager.js
CHANGED
|
@@ -1,171 +1,171 @@
|
|
|
1
|
-
import { isSelfOrDescendant, findFirst, findFirstChild, isFocusable, closestParent } from "../util/DOM";
|
|
2
|
-
import { batchUpdates } from "./batchUpdates";
|
|
3
|
-
import { SubscriberList } from "../util/SubscriberList";
|
|
4
|
-
import { isTouchEvent } from "../util/isTouchEvent";
|
|
5
|
-
import { getActiveElement } from "../util/getActiveElement";
|
|
6
|
-
|
|
7
|
-
/*
|
|
8
|
-
* Purpose of FocusManager is to provide focusout notifications.
|
|
9
|
-
* IE and Firefox do not provide relatedTarget info in blur events which makes it impossible
|
|
10
|
-
* to determine if focus went outside or stayed inside the component.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
let subscribers = new SubscriberList(),
|
|
14
|
-
timerInterval = 300,
|
|
15
|
-
timerId = null;
|
|
16
|
-
|
|
17
|
-
let lastActiveElement = null;
|
|
18
|
-
let pending = false;
|
|
19
|
-
|
|
20
|
-
export class FocusManager {
|
|
21
|
-
static subscribe(callback) {
|
|
22
|
-
let unsubscribe = subscribers.subscribe(callback);
|
|
23
|
-
checkTimer();
|
|
24
|
-
return unsubscribe;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
static onFocusOut(el, callback) {
|
|
28
|
-
let active = isSelfOrDescendant(el, getActiveElement());
|
|
29
|
-
return this.subscribe((focusedEl) => {
|
|
30
|
-
if (!active) active = isSelfOrDescendant(el, getActiveElement());
|
|
31
|
-
else if (!isSelfOrDescendant(el, focusedEl)) {
|
|
32
|
-
active = false;
|
|
33
|
-
callback(focusedEl);
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
static oneFocusOut(el, callback) {
|
|
39
|
-
this.nudge();
|
|
40
|
-
let off = this.subscribe((focusedEl) => {
|
|
41
|
-
if (!isSelfOrDescendant(el, focusedEl)) {
|
|
42
|
-
callback(focusedEl);
|
|
43
|
-
off();
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
return off;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
static nudge() {
|
|
50
|
-
if (typeof document !== "undefined" && getActiveElement() !== lastActiveElement) {
|
|
51
|
-
if (!pending) {
|
|
52
|
-
pending = true;
|
|
53
|
-
setTimeout(function () {
|
|
54
|
-
pending = false;
|
|
55
|
-
if (getActiveElement() !== lastActiveElement) {
|
|
56
|
-
lastActiveElement = getActiveElement();
|
|
57
|
-
batchUpdates(() => {
|
|
58
|
-
subscribers.notify(lastActiveElement);
|
|
59
|
-
});
|
|
60
|
-
checkTimer();
|
|
61
|
-
}
|
|
62
|
-
}, 0);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
static focus(el) {
|
|
68
|
-
el.focus();
|
|
69
|
-
this.nudge();
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
static focusFirst(el) {
|
|
73
|
-
let focusable = findFirst(el, isFocusable);
|
|
74
|
-
if (focusable) this.focus(focusable);
|
|
75
|
-
return focusable;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
static focusFirstChild(el) {
|
|
79
|
-
let focusable = findFirstChild(el, isFocusable);
|
|
80
|
-
if (focusable) this.focus(focusable);
|
|
81
|
-
return focusable;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
static focusNext(el) {
|
|
85
|
-
let next = el,
|
|
86
|
-
skip = true;
|
|
87
|
-
do {
|
|
88
|
-
if (!skip) {
|
|
89
|
-
let focusable = this.focusFirst(next);
|
|
90
|
-
if (focusable) return focusable;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (next.nextSibling) {
|
|
94
|
-
next = next.nextSibling;
|
|
95
|
-
skip = false;
|
|
96
|
-
} else {
|
|
97
|
-
next = next.parentNode;
|
|
98
|
-
skip = true;
|
|
99
|
-
}
|
|
100
|
-
} while (next);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
static setInterval(interval) {
|
|
104
|
-
timerInterval = interval;
|
|
105
|
-
checkTimer();
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export function oneFocusOut(component, el, callback) {
|
|
110
|
-
if (!component.oneFocusOut)
|
|
111
|
-
component.oneFocusOut = FocusManager.oneFocusOut(el, (focus) => {
|
|
112
|
-
delete component.oneFocusOut;
|
|
113
|
-
callback(focus);
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export function offFocusOut(component) {
|
|
118
|
-
if (component.oneFocusOut) {
|
|
119
|
-
component.oneFocusOut();
|
|
120
|
-
delete component.oneFocusOut;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export function preventFocus(e) {
|
|
125
|
-
//Focus can be prevented only on mousedown event. On touchstart this will not work
|
|
126
|
-
//preventDefault cannot be used as it prevents scrolling
|
|
127
|
-
if (e.type !== "mousedown") return;
|
|
128
|
-
|
|
129
|
-
e.preventDefault();
|
|
130
|
-
|
|
131
|
-
unfocusElement(e.currentTarget, false);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function checkTimer() {
|
|
135
|
-
let shouldRun = !subscribers.isEmpty();
|
|
136
|
-
|
|
137
|
-
if (shouldRun && !timerId)
|
|
138
|
-
timerId = setInterval(() => {
|
|
139
|
-
FocusManager.nudge();
|
|
140
|
-
}, timerInterval);
|
|
141
|
-
|
|
142
|
-
if (!shouldRun && timerId) {
|
|
143
|
-
clearInterval(timerId);
|
|
144
|
-
timerId = null;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
export function preventFocusOnTouch(e, force = false) {
|
|
149
|
-
if (force || isTouchEvent()) preventFocus(e);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
export function unfocusElement(target = null, unfocusParentOverlay = true) {
|
|
153
|
-
const activeElement = getActiveElement();
|
|
154
|
-
if (!target) target = activeElement;
|
|
155
|
-
|
|
156
|
-
if (unfocusParentOverlay) {
|
|
157
|
-
let focusableOverlayContainer = closestParent(target, (el) => el.dataset
|
|
158
|
-
if (focusableOverlayContainer) target = focusableOverlayContainer;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
//find the closest focusable parent of the target element and focus it instead
|
|
162
|
-
let focusableParent = closestParent(
|
|
163
|
-
target,
|
|
164
|
-
(el) => isFocusable(el) && (!unfocusParentOverlay || el.dataset
|
|
165
|
-
);
|
|
166
|
-
|
|
167
|
-
if (focusableParent && focusableParent !== document.body) focusableParent.focus();
|
|
168
|
-
else activeElement.blur();
|
|
169
|
-
|
|
170
|
-
FocusManager.nudge();
|
|
171
|
-
}
|
|
1
|
+
import { isSelfOrDescendant, findFirst, findFirstChild, isFocusable, closestParent } from "../util/DOM";
|
|
2
|
+
import { batchUpdates } from "./batchUpdates";
|
|
3
|
+
import { SubscriberList } from "../util/SubscriberList";
|
|
4
|
+
import { isTouchEvent } from "../util/isTouchEvent";
|
|
5
|
+
import { getActiveElement } from "../util/getActiveElement";
|
|
6
|
+
|
|
7
|
+
/*
|
|
8
|
+
* Purpose of FocusManager is to provide focusout notifications.
|
|
9
|
+
* IE and Firefox do not provide relatedTarget info in blur events which makes it impossible
|
|
10
|
+
* to determine if focus went outside or stayed inside the component.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
let subscribers = new SubscriberList(),
|
|
14
|
+
timerInterval = 300,
|
|
15
|
+
timerId = null;
|
|
16
|
+
|
|
17
|
+
let lastActiveElement = null;
|
|
18
|
+
let pending = false;
|
|
19
|
+
|
|
20
|
+
export class FocusManager {
|
|
21
|
+
static subscribe(callback) {
|
|
22
|
+
let unsubscribe = subscribers.subscribe(callback);
|
|
23
|
+
checkTimer();
|
|
24
|
+
return unsubscribe;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static onFocusOut(el, callback) {
|
|
28
|
+
let active = isSelfOrDescendant(el, getActiveElement());
|
|
29
|
+
return this.subscribe((focusedEl) => {
|
|
30
|
+
if (!active) active = isSelfOrDescendant(el, getActiveElement());
|
|
31
|
+
else if (!isSelfOrDescendant(el, focusedEl)) {
|
|
32
|
+
active = false;
|
|
33
|
+
callback(focusedEl);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static oneFocusOut(el, callback) {
|
|
39
|
+
this.nudge();
|
|
40
|
+
let off = this.subscribe((focusedEl) => {
|
|
41
|
+
if (!isSelfOrDescendant(el, focusedEl)) {
|
|
42
|
+
callback(focusedEl);
|
|
43
|
+
off();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
return off;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static nudge() {
|
|
50
|
+
if (typeof document !== "undefined" && getActiveElement() !== lastActiveElement) {
|
|
51
|
+
if (!pending) {
|
|
52
|
+
pending = true;
|
|
53
|
+
setTimeout(function () {
|
|
54
|
+
pending = false;
|
|
55
|
+
if (getActiveElement() !== lastActiveElement) {
|
|
56
|
+
lastActiveElement = getActiveElement();
|
|
57
|
+
batchUpdates(() => {
|
|
58
|
+
subscribers.notify(lastActiveElement);
|
|
59
|
+
});
|
|
60
|
+
checkTimer();
|
|
61
|
+
}
|
|
62
|
+
}, 0);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static focus(el) {
|
|
68
|
+
el.focus();
|
|
69
|
+
this.nudge();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
static focusFirst(el) {
|
|
73
|
+
let focusable = findFirst(el, isFocusable);
|
|
74
|
+
if (focusable) this.focus(focusable);
|
|
75
|
+
return focusable;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static focusFirstChild(el) {
|
|
79
|
+
let focusable = findFirstChild(el, isFocusable);
|
|
80
|
+
if (focusable) this.focus(focusable);
|
|
81
|
+
return focusable;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
static focusNext(el) {
|
|
85
|
+
let next = el,
|
|
86
|
+
skip = true;
|
|
87
|
+
do {
|
|
88
|
+
if (!skip) {
|
|
89
|
+
let focusable = this.focusFirst(next);
|
|
90
|
+
if (focusable) return focusable;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (next.nextSibling) {
|
|
94
|
+
next = next.nextSibling;
|
|
95
|
+
skip = false;
|
|
96
|
+
} else {
|
|
97
|
+
next = next.parentNode;
|
|
98
|
+
skip = true;
|
|
99
|
+
}
|
|
100
|
+
} while (next);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
static setInterval(interval) {
|
|
104
|
+
timerInterval = interval;
|
|
105
|
+
checkTimer();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function oneFocusOut(component, el, callback) {
|
|
110
|
+
if (!component.oneFocusOut)
|
|
111
|
+
component.oneFocusOut = FocusManager.oneFocusOut(el, (focus) => {
|
|
112
|
+
delete component.oneFocusOut;
|
|
113
|
+
callback(focus);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function offFocusOut(component) {
|
|
118
|
+
if (component.oneFocusOut) {
|
|
119
|
+
component.oneFocusOut();
|
|
120
|
+
delete component.oneFocusOut;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function preventFocus(e) {
|
|
125
|
+
//Focus can be prevented only on mousedown event. On touchstart this will not work
|
|
126
|
+
//preventDefault cannot be used as it prevents scrolling
|
|
127
|
+
if (e.type !== "mousedown") return;
|
|
128
|
+
|
|
129
|
+
e.preventDefault();
|
|
130
|
+
|
|
131
|
+
unfocusElement(e.currentTarget, false);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function checkTimer() {
|
|
135
|
+
let shouldRun = !subscribers.isEmpty();
|
|
136
|
+
|
|
137
|
+
if (shouldRun && !timerId)
|
|
138
|
+
timerId = setInterval(() => {
|
|
139
|
+
FocusManager.nudge();
|
|
140
|
+
}, timerInterval);
|
|
141
|
+
|
|
142
|
+
if (!shouldRun && timerId) {
|
|
143
|
+
clearInterval(timerId);
|
|
144
|
+
timerId = null;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function preventFocusOnTouch(e, force = false) {
|
|
149
|
+
if (force || isTouchEvent()) preventFocus(e);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function unfocusElement(target = null, unfocusParentOverlay = true) {
|
|
153
|
+
const activeElement = getActiveElement();
|
|
154
|
+
if (!target) target = activeElement;
|
|
155
|
+
|
|
156
|
+
if (unfocusParentOverlay) {
|
|
157
|
+
let focusableOverlayContainer = closestParent(target, (el) => el.dataset?.focusableOverlayContainer);
|
|
158
|
+
if (focusableOverlayContainer) target = focusableOverlayContainer;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
//find the closest focusable parent of the target element and focus it instead
|
|
162
|
+
let focusableParent = closestParent(
|
|
163
|
+
target,
|
|
164
|
+
(el) => isFocusable(el) && (!unfocusParentOverlay || el.dataset?.focusableOverlayContainer)
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
if (focusableParent && focusableParent !== document.body) focusableParent.focus();
|
|
168
|
+
else activeElement.blur();
|
|
169
|
+
|
|
170
|
+
FocusManager.nudge();
|
|
171
|
+
}
|