@oscarpalmer/oui 0.12.0 → 0.14.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/dist/css/badge.css +9 -3
- package/dist/css/tooltip.css +23 -0
- package/dist/css/value.css +1 -0
- package/dist/js/attributable.cjs +51 -0
- package/dist/js/attributable.js +51 -0
- package/dist/js/floatable.cjs +121 -0
- package/dist/js/floatable.js +121 -0
- package/dist/js/focus-trap.cjs +19 -62
- package/dist/js/focus-trap.js +19 -62
- package/dist/js/tooltip.cjs +161 -0
- package/dist/js/tooltip.js +160 -0
- package/package.json +15 -5
- package/src/css/badge.scss +10 -3
- package/src/css/mixins.scss +13 -0
- package/src/css/tooltip.scss +21 -0
- package/src/js/attributable.ts +70 -0
- package/src/js/floatable.ts +168 -0
- package/src/js/focus-trap.ts +16 -64
- package/src/js/tooltip.ts +227 -0
- package/types/attributable.d.cts +5 -0
- package/types/attributable.d.ts +1 -0
- package/types/floatable.d.cts +16 -0
- package/types/floatable.d.ts +12 -0
- package/types/tooltip.d.cts +3 -0
- package/types/tooltip.d.ts +1 -0
package/dist/css/badge.css
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
/*! https://github.com/oscarpalmer/oui */
|
|
2
2
|
|
|
3
|
+
.oui {
|
|
4
|
+
/* Colors*/
|
|
5
|
+
}
|
|
3
6
|
:where(.oui-pill, .oui-tag) {
|
|
4
7
|
--oui-shadow-mixed: color-mix(
|
|
5
8
|
in oklab,
|
|
@@ -28,9 +31,12 @@
|
|
|
28
31
|
:where(.oui-pill-tiny, .oui-tag-tiny) {
|
|
29
32
|
color: color-mix(in oklab, var(--oui-foreground, var(--oui-gray-8)), transparent 12.5%);
|
|
30
33
|
font-size: 0.75em;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
}
|
|
35
|
+
:where(.oui-pill-tiny) {
|
|
36
|
+
padding: 0.25em 0.75em;
|
|
37
|
+
}
|
|
38
|
+
:where(.oui-tag-tiny) {
|
|
39
|
+
padding: 0.25em 0.5em;
|
|
34
40
|
}
|
|
35
41
|
:where(.oui-pill-blue, .oui-tag-blue) {
|
|
36
42
|
--oui-background: var(--oui-blue-0);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
|
|
2
|
+
:where([oui-tooltip]:is(abbr, b, cite, dfn, code, em, i, kbd, mark, q, samp, small, span, strong, sub, sup, time, var)) {
|
|
3
|
+
-webkit-text-decoration: underline dotted;
|
|
4
|
+
text-decoration: underline dotted;
|
|
5
|
+
-webkit-text-decoration-skip: ink;
|
|
6
|
+
text-decoration-skip-ink: auto;
|
|
7
|
+
text-underline-offset: 0.25em;
|
|
8
|
+
cursor: help;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
:where([oui-tooltip-content]) {
|
|
12
|
+
box-shadow: inset 0 1px 0 0 transparent, 0 0 0 1px rgba(0, 0, 0, 0.05), 0 1px 2px -0.5px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.05), 0 4px 8px -2px rgba(0, 0, 0, 0.05), 0 8px 16px -4px rgba(0, 0, 0, 0.05), 0 16px 32px -8px rgba(0, 0, 0, 0.05), 0 32px 64px -16px rgba(0, 0, 0, 0.05), 0 64px 128px -32px rgba(0, 0, 0, 0.05);
|
|
13
|
+
max-width: 48ch;
|
|
14
|
+
padding: 0.75em 1em;
|
|
15
|
+
background-color: var(--oui-absolute);
|
|
16
|
+
border-radius: 0.25rem;
|
|
17
|
+
font-size: 0.875rem;
|
|
18
|
+
position: fixed;
|
|
19
|
+
inset: 0 auto auto 0;
|
|
20
|
+
z-index: 10;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
function attributable(attribute, add, remove) {
|
|
4
|
+
const observer = new MutationObserver((entries) => {
|
|
5
|
+
const { length } = entries;
|
|
6
|
+
for (let index = 0; index < length; index += 1) {
|
|
7
|
+
const entry = entries[index];
|
|
8
|
+
if (entry.type === "attributes" && entry.target instanceof HTMLElement) {
|
|
9
|
+
if (entry.target.hasAttribute(attribute)) {
|
|
10
|
+
handleAdded(attribute, [entry.target], add);
|
|
11
|
+
} else {
|
|
12
|
+
handleRemoved([entry.target], remove);
|
|
13
|
+
}
|
|
14
|
+
} else if (entry.type === "childList") {
|
|
15
|
+
handleAdded(attribute, entry.addedNodes, add);
|
|
16
|
+
handleRemoved(entry.removedNodes, remove);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
observer.observe(document, {
|
|
21
|
+
attributeFilter: [attribute],
|
|
22
|
+
attributes: true,
|
|
23
|
+
childList: true,
|
|
24
|
+
subtree: true
|
|
25
|
+
});
|
|
26
|
+
requestAnimationFrame(() => {
|
|
27
|
+
handleAdded(attribute, document.querySelectorAll(`[${attribute}]`), add);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function handleAdded(attribute, nodes, add) {
|
|
31
|
+
const elements = [...nodes].filter(
|
|
32
|
+
(node) => node instanceof HTMLElement
|
|
33
|
+
);
|
|
34
|
+
const { length } = elements;
|
|
35
|
+
for (let index = 0; index < length; index += 1) {
|
|
36
|
+
const element = elements[index];
|
|
37
|
+
if (element.hasAttribute(attribute)) {
|
|
38
|
+
add(element);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function handleRemoved(nodes, remove) {
|
|
43
|
+
const elements = [...nodes].filter(
|
|
44
|
+
(node) => node instanceof HTMLElement
|
|
45
|
+
);
|
|
46
|
+
const { length } = elements;
|
|
47
|
+
for (let index = 0; index < length; index += 1) {
|
|
48
|
+
remove(elements[index]);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.attributable = attributable;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
function attributable(attribute, add, remove) {
|
|
2
|
+
const observer = new MutationObserver((entries) => {
|
|
3
|
+
const { length } = entries;
|
|
4
|
+
for (let index = 0; index < length; index += 1) {
|
|
5
|
+
const entry = entries[index];
|
|
6
|
+
if (entry.type === "attributes" && entry.target instanceof HTMLElement) {
|
|
7
|
+
if (entry.target.hasAttribute(attribute)) {
|
|
8
|
+
handleAdded(attribute, [entry.target], add);
|
|
9
|
+
} else {
|
|
10
|
+
handleRemoved([entry.target], remove);
|
|
11
|
+
}
|
|
12
|
+
} else if (entry.type === "childList") {
|
|
13
|
+
handleAdded(attribute, entry.addedNodes, add);
|
|
14
|
+
handleRemoved(entry.removedNodes, remove);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
observer.observe(document, {
|
|
19
|
+
attributeFilter: [attribute],
|
|
20
|
+
attributes: true,
|
|
21
|
+
childList: true,
|
|
22
|
+
subtree: true
|
|
23
|
+
});
|
|
24
|
+
requestAnimationFrame(() => {
|
|
25
|
+
handleAdded(attribute, document.querySelectorAll(`[${attribute}]`), add);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function handleAdded(attribute, nodes, add) {
|
|
29
|
+
const elements = [...nodes].filter(
|
|
30
|
+
(node) => node instanceof HTMLElement
|
|
31
|
+
);
|
|
32
|
+
const { length } = elements;
|
|
33
|
+
for (let index = 0; index < length; index += 1) {
|
|
34
|
+
const element = elements[index];
|
|
35
|
+
if (element.hasAttribute(attribute)) {
|
|
36
|
+
add(element);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function handleRemoved(nodes, remove) {
|
|
41
|
+
const elements = [...nodes].filter(
|
|
42
|
+
(node) => node instanceof HTMLElement
|
|
43
|
+
);
|
|
44
|
+
const { length } = elements;
|
|
45
|
+
for (let index = 0; index < length; index += 1) {
|
|
46
|
+
remove(elements[index]);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export {
|
|
50
|
+
attributable
|
|
51
|
+
};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
class Floatable {
|
|
4
|
+
constructor(anchor, content) {
|
|
5
|
+
this.anchor = anchor;
|
|
6
|
+
this.content = content;
|
|
7
|
+
}
|
|
8
|
+
activate;
|
|
9
|
+
active = false;
|
|
10
|
+
deactivate;
|
|
11
|
+
frame;
|
|
12
|
+
destroy() {
|
|
13
|
+
this.activate = void 0;
|
|
14
|
+
this.deactivate = void 0;
|
|
15
|
+
this.frame = void 0;
|
|
16
|
+
this.anchor = void 0;
|
|
17
|
+
this.content = void 0;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function activate(floatable, active, time) {
|
|
21
|
+
stop(floatable);
|
|
22
|
+
if (floatable.active) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (time == null || time === 0) {
|
|
26
|
+
onActivate(floatable, active);
|
|
27
|
+
} else {
|
|
28
|
+
floatable.activate = +setTimeout(() => {
|
|
29
|
+
onActivate(floatable, active);
|
|
30
|
+
}, time);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function deactivate(floatable, active, time) {
|
|
34
|
+
stop(floatable);
|
|
35
|
+
if (!floatable.active) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (time == null || time === 0) {
|
|
39
|
+
onDeactivate(floatable, active);
|
|
40
|
+
} else {
|
|
41
|
+
floatable.deactivate = +setTimeout(() => {
|
|
42
|
+
onDeactivate(floatable, active);
|
|
43
|
+
}, time);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function getX(anchor, content) {
|
|
47
|
+
if (content.width + 2 * margin >= window.innerWidth) {
|
|
48
|
+
return {
|
|
49
|
+
left: margin,
|
|
50
|
+
right: margin
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const left = anchor.left + (anchor.width - content.width) / 2;
|
|
54
|
+
const right = window.innerWidth - margin;
|
|
55
|
+
if (left < margin) {
|
|
56
|
+
return {
|
|
57
|
+
left: margin
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (left + content.width > right) {
|
|
61
|
+
return {
|
|
62
|
+
right: margin
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
left
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function getY(anchor, content) {
|
|
70
|
+
let top = anchor.top - content.height - margin;
|
|
71
|
+
if (top - margin >= 0) {
|
|
72
|
+
return top;
|
|
73
|
+
}
|
|
74
|
+
top = anchor.bottom + margin;
|
|
75
|
+
if (top + content.height + margin <= window.innerHeight) {
|
|
76
|
+
return top;
|
|
77
|
+
}
|
|
78
|
+
return anchor.top + (anchor.height - content.height) / 2;
|
|
79
|
+
}
|
|
80
|
+
function onActivate(floatable, active) {
|
|
81
|
+
floatable.active = true;
|
|
82
|
+
active.add(floatable);
|
|
83
|
+
document.body.append(floatable.content);
|
|
84
|
+
floatable.content.hidden = false;
|
|
85
|
+
update(floatable);
|
|
86
|
+
}
|
|
87
|
+
function onDeactivate(floatable, active) {
|
|
88
|
+
floatable.active = false;
|
|
89
|
+
active.delete(floatable);
|
|
90
|
+
floatable.content.hidden = true;
|
|
91
|
+
floatable.anchor.insertAdjacentElement("afterend", floatable.content);
|
|
92
|
+
}
|
|
93
|
+
function update(floatable) {
|
|
94
|
+
function run() {
|
|
95
|
+
const anchor = floatable.anchor.getBoundingClientRect();
|
|
96
|
+
const content = floatable.content.getBoundingClientRect();
|
|
97
|
+
const { left, right } = getX(anchor, content);
|
|
98
|
+
const top = getY(anchor, content);
|
|
99
|
+
floatable.content.style.inset = `${top}px ${right == null ? "auto" : `${right}px`} auto ${left == null ? "auto" : `${left}px`}`;
|
|
100
|
+
floatable.frame = requestAnimationFrame(run);
|
|
101
|
+
}
|
|
102
|
+
floatable.frame = requestAnimationFrame(run);
|
|
103
|
+
}
|
|
104
|
+
function stop(floatable) {
|
|
105
|
+
if (floatable.frame != null) {
|
|
106
|
+
cancelAnimationFrame(floatable.frame);
|
|
107
|
+
}
|
|
108
|
+
if (floatable.activate != null) {
|
|
109
|
+
clearTimeout(floatable.activate);
|
|
110
|
+
}
|
|
111
|
+
if (floatable.deactivate != null) {
|
|
112
|
+
clearTimeout(floatable.deactivate);
|
|
113
|
+
}
|
|
114
|
+
floatable.activate = void 0;
|
|
115
|
+
floatable.deactivate = void 0;
|
|
116
|
+
floatable.frame = void 0;
|
|
117
|
+
}
|
|
118
|
+
const margin = Number.parseInt(getComputedStyle(document.documentElement).fontSize, 10) / 4;
|
|
119
|
+
exports.Floatable = Floatable;
|
|
120
|
+
exports.activate = activate;
|
|
121
|
+
exports.deactivate = deactivate;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
class Floatable {
|
|
2
|
+
constructor(anchor, content) {
|
|
3
|
+
this.anchor = anchor;
|
|
4
|
+
this.content = content;
|
|
5
|
+
}
|
|
6
|
+
activate;
|
|
7
|
+
active = false;
|
|
8
|
+
deactivate;
|
|
9
|
+
frame;
|
|
10
|
+
destroy() {
|
|
11
|
+
this.activate = void 0;
|
|
12
|
+
this.deactivate = void 0;
|
|
13
|
+
this.frame = void 0;
|
|
14
|
+
this.anchor = void 0;
|
|
15
|
+
this.content = void 0;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function activate(floatable, active, time) {
|
|
19
|
+
stop(floatable);
|
|
20
|
+
if (floatable.active) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (time == null || time === 0) {
|
|
24
|
+
onActivate(floatable, active);
|
|
25
|
+
} else {
|
|
26
|
+
floatable.activate = +setTimeout(() => {
|
|
27
|
+
onActivate(floatable, active);
|
|
28
|
+
}, time);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function deactivate(floatable, active, time) {
|
|
32
|
+
stop(floatable);
|
|
33
|
+
if (!floatable.active) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (time == null || time === 0) {
|
|
37
|
+
onDeactivate(floatable, active);
|
|
38
|
+
} else {
|
|
39
|
+
floatable.deactivate = +setTimeout(() => {
|
|
40
|
+
onDeactivate(floatable, active);
|
|
41
|
+
}, time);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function getX(anchor, content) {
|
|
45
|
+
if (content.width + 2 * margin >= window.innerWidth) {
|
|
46
|
+
return {
|
|
47
|
+
left: margin,
|
|
48
|
+
right: margin
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const left = anchor.left + (anchor.width - content.width) / 2;
|
|
52
|
+
const right = window.innerWidth - margin;
|
|
53
|
+
if (left < margin) {
|
|
54
|
+
return {
|
|
55
|
+
left: margin
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (left + content.width > right) {
|
|
59
|
+
return {
|
|
60
|
+
right: margin
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
left
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function getY(anchor, content) {
|
|
68
|
+
let top = anchor.top - content.height - margin;
|
|
69
|
+
if (top - margin >= 0) {
|
|
70
|
+
return top;
|
|
71
|
+
}
|
|
72
|
+
top = anchor.bottom + margin;
|
|
73
|
+
if (top + content.height + margin <= window.innerHeight) {
|
|
74
|
+
return top;
|
|
75
|
+
}
|
|
76
|
+
return anchor.top + (anchor.height - content.height) / 2;
|
|
77
|
+
}
|
|
78
|
+
function onActivate(floatable, active) {
|
|
79
|
+
floatable.active = true;
|
|
80
|
+
active.add(floatable);
|
|
81
|
+
document.body.append(floatable.content);
|
|
82
|
+
floatable.content.hidden = false;
|
|
83
|
+
update(floatable);
|
|
84
|
+
}
|
|
85
|
+
function onDeactivate(floatable, active) {
|
|
86
|
+
floatable.active = false;
|
|
87
|
+
active.delete(floatable);
|
|
88
|
+
floatable.content.hidden = true;
|
|
89
|
+
floatable.anchor.insertAdjacentElement("afterend", floatable.content);
|
|
90
|
+
}
|
|
91
|
+
function update(floatable) {
|
|
92
|
+
function run() {
|
|
93
|
+
const anchor = floatable.anchor.getBoundingClientRect();
|
|
94
|
+
const content = floatable.content.getBoundingClientRect();
|
|
95
|
+
const { left, right } = getX(anchor, content);
|
|
96
|
+
const top = getY(anchor, content);
|
|
97
|
+
floatable.content.style.inset = `${top}px ${right == null ? "auto" : `${right}px`} auto ${left == null ? "auto" : `${left}px`}`;
|
|
98
|
+
floatable.frame = requestAnimationFrame(run);
|
|
99
|
+
}
|
|
100
|
+
floatable.frame = requestAnimationFrame(run);
|
|
101
|
+
}
|
|
102
|
+
function stop(floatable) {
|
|
103
|
+
if (floatable.frame != null) {
|
|
104
|
+
cancelAnimationFrame(floatable.frame);
|
|
105
|
+
}
|
|
106
|
+
if (floatable.activate != null) {
|
|
107
|
+
clearTimeout(floatable.activate);
|
|
108
|
+
}
|
|
109
|
+
if (floatable.deactivate != null) {
|
|
110
|
+
clearTimeout(floatable.deactivate);
|
|
111
|
+
}
|
|
112
|
+
floatable.activate = void 0;
|
|
113
|
+
floatable.deactivate = void 0;
|
|
114
|
+
floatable.frame = void 0;
|
|
115
|
+
}
|
|
116
|
+
const margin = Number.parseInt(getComputedStyle(document.documentElement).fontSize, 10) / 4;
|
|
117
|
+
export {
|
|
118
|
+
Floatable,
|
|
119
|
+
activate,
|
|
120
|
+
deactivate
|
|
121
|
+
};
|
package/dist/js/focus-trap.cjs
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
2
|
const number = require("@oscarpalmer/atoms/number");
|
|
6
3
|
const event = require("@oscarpalmer/toretto/event");
|
|
7
4
|
const find = require("@oscarpalmer/toretto/find");
|
|
8
5
|
const focusable = require("@oscarpalmer/toretto/focusable");
|
|
6
|
+
const attributable = require("./attributable.cjs");
|
|
9
7
|
class FocusTrap {
|
|
10
8
|
constructor(element) {
|
|
11
|
-
__publicField(this, "active", true);
|
|
12
9
|
this.element = element;
|
|
13
10
|
element.setAttribute("aria-modal", "true");
|
|
14
11
|
element.setAttribute("tabindex", "-1");
|
|
15
12
|
}
|
|
13
|
+
active = true;
|
|
16
14
|
activate() {
|
|
17
15
|
this.element.setAttribute("aria-modal", "true");
|
|
18
16
|
this.active = true;
|
|
@@ -27,20 +25,12 @@ class FocusTrap {
|
|
|
27
25
|
inactive.add(this);
|
|
28
26
|
}
|
|
29
27
|
}
|
|
30
|
-
function
|
|
31
|
-
|
|
32
|
-
(
|
|
33
|
-
);
|
|
34
|
-
const { length } = elements;
|
|
35
|
-
for (let index = 0; index < length; index += 1) {
|
|
36
|
-
const element = elements[index];
|
|
37
|
-
if (element.hasAttribute(selector)) {
|
|
38
|
-
focusTraps.set(element, new FocusTrap(element));
|
|
39
|
-
}
|
|
28
|
+
function addFocusTrap(element) {
|
|
29
|
+
if (!focusTraps.has(element)) {
|
|
30
|
+
focusTraps.set(element, new FocusTrap(element));
|
|
40
31
|
}
|
|
41
32
|
}
|
|
42
33
|
function onEscape(event2) {
|
|
43
|
-
var _a;
|
|
44
34
|
if (event2.key !== "Escape") {
|
|
45
35
|
return;
|
|
46
36
|
}
|
|
@@ -48,7 +38,7 @@ function onEscape(event2) {
|
|
|
48
38
|
document.activeElement,
|
|
49
39
|
`[${selector}]`
|
|
50
40
|
);
|
|
51
|
-
|
|
41
|
+
focusTraps.get(element)?.inactivate();
|
|
52
42
|
}
|
|
53
43
|
function onFocusOut() {
|
|
54
44
|
if (inactive.size === 0) {
|
|
@@ -67,7 +57,6 @@ function onFocusOut() {
|
|
|
67
57
|
});
|
|
68
58
|
}
|
|
69
59
|
function onTab(event2) {
|
|
70
|
-
var _a;
|
|
71
60
|
if (event2.key !== "Tab") {
|
|
72
61
|
return;
|
|
73
62
|
}
|
|
@@ -75,7 +64,7 @@ function onTab(event2) {
|
|
|
75
64
|
event2.target,
|
|
76
65
|
`[${selector}]`
|
|
77
66
|
);
|
|
78
|
-
if (!(
|
|
67
|
+
if (!(focusTraps.get(element)?.active ?? false)) {
|
|
79
68
|
return;
|
|
80
69
|
}
|
|
81
70
|
event2.preventDefault();
|
|
@@ -95,53 +84,21 @@ function onTab(event2) {
|
|
|
95
84
|
elements[next].focus();
|
|
96
85
|
}
|
|
97
86
|
}
|
|
98
|
-
function removeFocusTraps(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
(node) => node instanceof HTMLElement
|
|
102
|
-
);
|
|
103
|
-
const { length } = elements;
|
|
104
|
-
for (let index = 0; index < length; index += 1) {
|
|
105
|
-
const element = elements[index];
|
|
106
|
-
(_a = focusTraps.get(element)) == null ? void 0 : _a.destroy();
|
|
107
|
-
focusTraps.delete(element);
|
|
108
|
-
}
|
|
87
|
+
function removeFocusTraps(element) {
|
|
88
|
+
focusTraps.get(element)?.destroy();
|
|
89
|
+
focusTraps.delete(element);
|
|
109
90
|
}
|
|
110
91
|
const focusTraps = /* @__PURE__ */ new WeakMap();
|
|
111
92
|
const inactive = /* @__PURE__ */ new Set();
|
|
112
|
-
const observer = new MutationObserver((entries) => {
|
|
113
|
-
const { length } = entries;
|
|
114
|
-
for (let index = 0; index < length; index += 1) {
|
|
115
|
-
const entry = entries[index];
|
|
116
|
-
if (entry.type === "attributes" && entry.target instanceof HTMLElement) {
|
|
117
|
-
if (entry.target.hasAttribute(selector)) {
|
|
118
|
-
addFocusTraps([entry.target]);
|
|
119
|
-
} else {
|
|
120
|
-
removeFocusTraps([entry.target]);
|
|
121
|
-
}
|
|
122
|
-
} else if (entry.type === "childList") {
|
|
123
|
-
addFocusTraps(entry.addedNodes);
|
|
124
|
-
removeFocusTraps(entry.removedNodes);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
93
|
const selector = "oui-focus-trap";
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
childList: true,
|
|
133
|
-
subtree: true
|
|
94
|
+
attributable.attributable(selector, addFocusTrap, removeFocusTraps);
|
|
95
|
+
event.on(document, "focusout", onFocusOut, {
|
|
96
|
+
capture: true
|
|
134
97
|
});
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
capture: true,
|
|
142
|
-
passive: false
|
|
143
|
-
});
|
|
144
|
-
event.on(document, "keydown", onEscape, {
|
|
145
|
-
passive: false
|
|
146
|
-
});
|
|
98
|
+
event.on(document, "keydown", onTab, {
|
|
99
|
+
capture: true,
|
|
100
|
+
passive: false
|
|
101
|
+
});
|
|
102
|
+
event.on(document, "keydown", onEscape, {
|
|
103
|
+
passive: false
|
|
147
104
|
});
|
package/dist/js/focus-trap.js
CHANGED
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
var __defProp = Object.defineProperty;
|
|
2
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
1
|
import { clamp } from "@oscarpalmer/atoms/number";
|
|
5
2
|
import { on } from "@oscarpalmer/toretto/event";
|
|
6
3
|
import { findAncestor } from "@oscarpalmer/toretto/find";
|
|
7
4
|
import { getFocusable } from "@oscarpalmer/toretto/focusable";
|
|
5
|
+
import { attributable } from "./attributable.js";
|
|
8
6
|
class FocusTrap {
|
|
9
7
|
constructor(element) {
|
|
10
|
-
__publicField(this, "active", true);
|
|
11
8
|
this.element = element;
|
|
12
9
|
element.setAttribute("aria-modal", "true");
|
|
13
10
|
element.setAttribute("tabindex", "-1");
|
|
14
11
|
}
|
|
12
|
+
active = true;
|
|
15
13
|
activate() {
|
|
16
14
|
this.element.setAttribute("aria-modal", "true");
|
|
17
15
|
this.active = true;
|
|
@@ -26,20 +24,12 @@ class FocusTrap {
|
|
|
26
24
|
inactive.add(this);
|
|
27
25
|
}
|
|
28
26
|
}
|
|
29
|
-
function
|
|
30
|
-
|
|
31
|
-
(
|
|
32
|
-
);
|
|
33
|
-
const { length } = elements;
|
|
34
|
-
for (let index = 0; index < length; index += 1) {
|
|
35
|
-
const element = elements[index];
|
|
36
|
-
if (element.hasAttribute(selector)) {
|
|
37
|
-
focusTraps.set(element, new FocusTrap(element));
|
|
38
|
-
}
|
|
27
|
+
function addFocusTrap(element) {
|
|
28
|
+
if (!focusTraps.has(element)) {
|
|
29
|
+
focusTraps.set(element, new FocusTrap(element));
|
|
39
30
|
}
|
|
40
31
|
}
|
|
41
32
|
function onEscape(event) {
|
|
42
|
-
var _a;
|
|
43
33
|
if (event.key !== "Escape") {
|
|
44
34
|
return;
|
|
45
35
|
}
|
|
@@ -47,7 +37,7 @@ function onEscape(event) {
|
|
|
47
37
|
document.activeElement,
|
|
48
38
|
`[${selector}]`
|
|
49
39
|
);
|
|
50
|
-
|
|
40
|
+
focusTraps.get(element)?.inactivate();
|
|
51
41
|
}
|
|
52
42
|
function onFocusOut() {
|
|
53
43
|
if (inactive.size === 0) {
|
|
@@ -66,7 +56,6 @@ function onFocusOut() {
|
|
|
66
56
|
});
|
|
67
57
|
}
|
|
68
58
|
function onTab(event) {
|
|
69
|
-
var _a;
|
|
70
59
|
if (event.key !== "Tab") {
|
|
71
60
|
return;
|
|
72
61
|
}
|
|
@@ -74,7 +63,7 @@ function onTab(event) {
|
|
|
74
63
|
event.target,
|
|
75
64
|
`[${selector}]`
|
|
76
65
|
);
|
|
77
|
-
if (!(
|
|
66
|
+
if (!(focusTraps.get(element)?.active ?? false)) {
|
|
78
67
|
return;
|
|
79
68
|
}
|
|
80
69
|
event.preventDefault();
|
|
@@ -94,53 +83,21 @@ function onTab(event) {
|
|
|
94
83
|
elements[next].focus();
|
|
95
84
|
}
|
|
96
85
|
}
|
|
97
|
-
function removeFocusTraps(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
(node) => node instanceof HTMLElement
|
|
101
|
-
);
|
|
102
|
-
const { length } = elements;
|
|
103
|
-
for (let index = 0; index < length; index += 1) {
|
|
104
|
-
const element = elements[index];
|
|
105
|
-
(_a = focusTraps.get(element)) == null ? void 0 : _a.destroy();
|
|
106
|
-
focusTraps.delete(element);
|
|
107
|
-
}
|
|
86
|
+
function removeFocusTraps(element) {
|
|
87
|
+
focusTraps.get(element)?.destroy();
|
|
88
|
+
focusTraps.delete(element);
|
|
108
89
|
}
|
|
109
90
|
const focusTraps = /* @__PURE__ */ new WeakMap();
|
|
110
91
|
const inactive = /* @__PURE__ */ new Set();
|
|
111
|
-
const observer = new MutationObserver((entries) => {
|
|
112
|
-
const { length } = entries;
|
|
113
|
-
for (let index = 0; index < length; index += 1) {
|
|
114
|
-
const entry = entries[index];
|
|
115
|
-
if (entry.type === "attributes" && entry.target instanceof HTMLElement) {
|
|
116
|
-
if (entry.target.hasAttribute(selector)) {
|
|
117
|
-
addFocusTraps([entry.target]);
|
|
118
|
-
} else {
|
|
119
|
-
removeFocusTraps([entry.target]);
|
|
120
|
-
}
|
|
121
|
-
} else if (entry.type === "childList") {
|
|
122
|
-
addFocusTraps(entry.addedNodes);
|
|
123
|
-
removeFocusTraps(entry.removedNodes);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
92
|
const selector = "oui-focus-trap";
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
childList: true,
|
|
132
|
-
subtree: true
|
|
93
|
+
attributable(selector, addFocusTrap, removeFocusTraps);
|
|
94
|
+
on(document, "focusout", onFocusOut, {
|
|
95
|
+
capture: true
|
|
133
96
|
});
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
capture: true,
|
|
141
|
-
passive: false
|
|
142
|
-
});
|
|
143
|
-
on(document, "keydown", onEscape, {
|
|
144
|
-
passive: false
|
|
145
|
-
});
|
|
97
|
+
on(document, "keydown", onTab, {
|
|
98
|
+
capture: true,
|
|
99
|
+
passive: false
|
|
100
|
+
});
|
|
101
|
+
on(document, "keydown", onEscape, {
|
|
102
|
+
passive: false
|
|
146
103
|
});
|