@oscarpalmer/oui 0.18.0 → 0.19.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 +10 -10
- package/dist/css/button.css +9 -9
- package/dist/css/color.css +99 -99
- package/dist/css/content.css +1 -1
- package/dist/css/flex.css +39 -39
- package/dist/css/form.css +29 -56
- package/dist/css/message.css +6 -6
- package/dist/css/reset.css +3 -2
- package/dist/css/table.css +4 -4
- package/dist/css/tooltip.css +18 -1
- package/dist/js/attributable.full.js +29 -41
- package/dist/js/floatable.full.js +322 -337
- package/dist/js/focus-trap/embedded.full.js +252 -195
- package/dist/js/focus-trap/standalone.full.js +283 -238
- package/dist/js/index.js +3 -3
- package/dist/js/oui.full.js +1170 -1193
- package/dist/js/popover.full.js +568 -630
- package/dist/js/popover.js +1 -1
- package/dist/js/splitter.full.js +533 -369
- package/dist/js/splitter.js +2 -2
- package/dist/js/tooltip.full.js +488 -554
- package/dist/js/tooltip.js +1 -1
- package/package.json +19 -19
- package/src/css/a11y.scss +1 -1
- package/src/css/badge.scss +23 -19
- package/src/css/button.scss +9 -9
- package/src/css/color.scss +99 -99
- package/src/css/content.scss +6 -8
- package/src/css/flex.scss +21 -20
- package/src/css/form.scss +37 -60
- package/src/css/message.scss +8 -12
- package/src/css/mixins.scss +11 -12
- package/src/css/popover.scss +2 -2
- package/src/css/reset.scss +14 -14
- package/src/css/splitter.scss +15 -13
- package/src/css/table.scss +11 -11
- package/src/css/tooltip.scss +25 -4
- package/src/js/attributable.ts +3 -10
- package/src/js/floatable.ts +7 -25
- package/src/js/focus-trap/embedded.ts +6 -24
- package/src/js/popover.ts +3 -3
- package/src/js/splitter.ts +9 -39
- package/src/js/tooltip.ts +5 -17
- package/dist/css/value.css +0 -1
package/dist/js/popover.full.js
CHANGED
|
@@ -1,39 +1,54 @@
|
|
|
1
1
|
function isNumber(value) {
|
|
2
2
|
return typeof value === "number" && !Number.isNaN(value);
|
|
3
3
|
}
|
|
4
|
-
|
|
5
4
|
function getString(value) {
|
|
6
5
|
if (typeof value === "string") return value;
|
|
7
6
|
if (value == null) return "";
|
|
7
|
+
if (typeof value === "function") return getString(value());
|
|
8
8
|
if (typeof value !== "object") return String(value);
|
|
9
9
|
const asString = String(value.valueOf?.() ?? value);
|
|
10
10
|
return asString.startsWith("[object ") ? JSON.stringify(value) : asString;
|
|
11
11
|
}
|
|
12
|
-
|
|
13
12
|
function isNullableOrWhitespace(value) {
|
|
14
13
|
return value == null || EXPRESSION_WHITESPACE.test(getString(value));
|
|
15
14
|
}
|
|
16
15
|
var EXPRESSION_WHITESPACE = /^\s*$/;
|
|
17
|
-
|
|
18
16
|
function getFocusable(parent) {
|
|
19
|
-
return getValidElements(parent, FILTERS_FOCUSABLE);
|
|
17
|
+
return getValidElements(parent, FILTERS_FOCUSABLE, false);
|
|
20
18
|
}
|
|
21
19
|
function getItem(element, tabbable) {
|
|
22
20
|
return {
|
|
23
21
|
element,
|
|
24
|
-
tabIndex: TABINDEX_DEFAULT
|
|
22
|
+
tabIndex: tabbable ? getTabIndex(element) : TABINDEX_DEFAULT
|
|
25
23
|
};
|
|
26
24
|
}
|
|
25
|
+
function getTabIndex(element) {
|
|
26
|
+
const tabIndex = element?.tabIndex ?? TABINDEX_DEFAULT;
|
|
27
|
+
if (tabIndex < TABINDEX_BASE && (EXPRESSION_SPECIAL_TABINDEX.test(element.tagName) || isEditable(element)) && !hasTabIndex(element)) return TABINDEX_BASE;
|
|
28
|
+
return tabIndex;
|
|
29
|
+
}
|
|
27
30
|
function getValidElements(parent, filters, tabbable) {
|
|
28
31
|
if (!(parent instanceof Element)) return [];
|
|
29
32
|
const elements = [...parent.querySelectorAll(SELECTOR_FULL)];
|
|
30
33
|
const items = [];
|
|
31
34
|
let { length } = elements;
|
|
32
|
-
for (let index = 0; index < length; index += 1) {
|
|
33
|
-
const item = getItem(elements[index]);
|
|
35
|
+
for (let index$1 = 0; index$1 < length; index$1 += 1) {
|
|
36
|
+
const item = getItem(elements[index$1], tabbable);
|
|
34
37
|
if (!filters.some((filter) => filter(item))) items.push(item);
|
|
35
38
|
}
|
|
36
|
-
return items.map((item) => item.element);
|
|
39
|
+
if (!tabbable) return items.map((item) => item.element);
|
|
40
|
+
const indiced = [];
|
|
41
|
+
const zeroed = [];
|
|
42
|
+
length = items.length;
|
|
43
|
+
for (let index$1 = 0; index$1 < length; index$1 += 1) {
|
|
44
|
+
const item = items[index$1];
|
|
45
|
+
if (item.tabIndex === TABINDEX_BASE) zeroed.push(item.element);
|
|
46
|
+
else indiced[item.tabIndex] = [...indiced[item.tabIndex] ?? [], item.element];
|
|
47
|
+
}
|
|
48
|
+
return [...indiced.flat(), ...zeroed];
|
|
49
|
+
}
|
|
50
|
+
function hasTabIndex(element) {
|
|
51
|
+
return !Number.isNaN(Number.parseInt(element.getAttribute(ATTRIBUTE_TABINDEX), 10));
|
|
37
52
|
}
|
|
38
53
|
function isDisabled$1(item) {
|
|
39
54
|
if (EXPRESSION_DISABLEABLE.test(item.element.tagName) && isDisabledFromFieldset(item.element)) return true;
|
|
@@ -45,8 +60,8 @@ function isDisabledFromFieldset(element) {
|
|
|
45
60
|
if (parent instanceof HTMLFieldSetElement && parent.disabled) {
|
|
46
61
|
const children = Array.from(parent.children);
|
|
47
62
|
const { length } = children;
|
|
48
|
-
for (let index = 0; index < length; index += 1) {
|
|
49
|
-
const child = children[index];
|
|
63
|
+
for (let index$1 = 0; index$1 < length; index$1 += 1) {
|
|
64
|
+
const child = children[index$1];
|
|
50
65
|
if (child instanceof HTMLLegendElement) return parent.matches(SELECTOR_FIELDSET_DISABLED) || !child.contains(element);
|
|
51
66
|
}
|
|
52
67
|
return true;
|
|
@@ -55,6 +70,9 @@ function isDisabledFromFieldset(element) {
|
|
|
55
70
|
}
|
|
56
71
|
return false;
|
|
57
72
|
}
|
|
73
|
+
function isEditable(element) {
|
|
74
|
+
return EXPRESSION_TRUEISH.test(element.getAttribute(ATTRIBUTE_CONTENTEDITABLE));
|
|
75
|
+
}
|
|
58
76
|
function isHidden(item) {
|
|
59
77
|
if ((item.element.hidden ?? false) || item.element instanceof HTMLInputElement && item.element.type === STYLE_HIDDEN) return true;
|
|
60
78
|
if ((item.element.matches(SELECTOR_SUMMARY_FIRST) ? item.element.parentElement : item.element)?.matches(SELECTOR_DETAILS_CLOSED_CHILDREN) ?? false) return true;
|
|
@@ -65,13 +83,18 @@ function isHidden(item) {
|
|
|
65
83
|
}
|
|
66
84
|
function isInert(item) {
|
|
67
85
|
return (item.element.inert ?? false) || EXPRESSION_TRUEISH.test(item.element.getAttribute(ATTRIBUTE_INERT)) || item.element.parentElement != null && isInert({
|
|
68
|
-
element: item.element.parentElement
|
|
86
|
+
element: item.element.parentElement,
|
|
87
|
+
tabIndex: TABINDEX_DEFAULT
|
|
88
|
+
});
|
|
69
89
|
}
|
|
70
90
|
function isSummarised(item) {
|
|
71
91
|
return item.element instanceof HTMLDetailsElement && [...item.element.children].some((child) => EXPRESSION_SUMMARY.test(child.tagName));
|
|
72
92
|
}
|
|
93
|
+
var ATTRIBUTE_CONTENTEDITABLE = "contenteditable";
|
|
73
94
|
var ATTRIBUTE_INERT = "inert";
|
|
95
|
+
var ATTRIBUTE_TABINDEX = "tabindex";
|
|
74
96
|
var EXPRESSION_DISABLEABLE = /^(button|input|select|textarea)$/i;
|
|
97
|
+
var EXPRESSION_SPECIAL_TABINDEX = /^(audio|details|video)$/i;
|
|
75
98
|
var EXPRESSION_SUMMARY = /^summary$/i;
|
|
76
99
|
var EXPRESSION_TRUEISH = /^(|true)$/i;
|
|
77
100
|
var FILTERS_FOCUSABLE = [
|
|
@@ -80,6 +103,7 @@ var FILTERS_FOCUSABLE = [
|
|
|
80
103
|
isHidden,
|
|
81
104
|
isSummarised
|
|
82
105
|
];
|
|
106
|
+
[...FILTERS_FOCUSABLE];
|
|
83
107
|
var SELECTOR_DETAILS_CLOSED_CHILDREN = "details:not([open]) *";
|
|
84
108
|
var SELECTOR_FIELDSET_DISABLED = "fieldset[disabled] *";
|
|
85
109
|
var SELECTOR_SUMMARY_FIRST = "details > summary:first-of-type";
|
|
@@ -98,26 +122,9 @@ var SELECTOR_FULL = [
|
|
|
98
122
|
].map((selector) => `${selector}:not([inert])`).join(",");
|
|
99
123
|
var STYLE_HIDDEN = "hidden";
|
|
100
124
|
var STYLE_NONE = "none";
|
|
125
|
+
var TABINDEX_BASE = 0;
|
|
101
126
|
var TABINDEX_DEFAULT = -1;
|
|
102
|
-
|
|
103
|
-
function isEventTarget(value) {
|
|
104
|
-
return typeof value === "object" && value != null && typeof value.addEventListener === "function" && typeof value.removeEventListener === "function" && typeof value.dispatchEvent === "function";
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function getBoolean(value, defaultValue) {
|
|
108
|
-
return typeof value === "boolean" ? value : defaultValue ?? false;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function clamp(value, minimum, maximum, loop) {
|
|
112
|
-
if (![
|
|
113
|
-
value,
|
|
114
|
-
minimum,
|
|
115
|
-
maximum
|
|
116
|
-
].every(isNumber)) return NaN;
|
|
117
|
-
if (value < minimum) return maximum ;
|
|
118
|
-
return value > maximum ? minimum : value;
|
|
119
|
-
}
|
|
120
|
-
|
|
127
|
+
function noop() {}
|
|
121
128
|
function calculate() {
|
|
122
129
|
return new Promise((resolve) => {
|
|
123
130
|
const values = [];
|
|
@@ -125,37 +132,131 @@ function calculate() {
|
|
|
125
132
|
function step(now) {
|
|
126
133
|
if (last != null) values.push(now - last);
|
|
127
134
|
last = now;
|
|
128
|
-
if (values.length >=
|
|
129
|
-
|
|
130
|
-
resolve(median);
|
|
131
|
-
} else requestAnimationFrame(step);
|
|
135
|
+
if (values.length >= TOTAL) resolve(values.sort().slice(TRIM_PART, -TRIM_PART).reduce((first, second) => first + second, 0) / (values.length - TRIM_TOTAL));
|
|
136
|
+
else requestAnimationFrame(step);
|
|
132
137
|
}
|
|
133
138
|
requestAnimationFrame(step);
|
|
134
139
|
});
|
|
135
140
|
}
|
|
136
|
-
|
|
137
|
-
var
|
|
138
|
-
var
|
|
139
|
-
calculate()
|
|
140
|
-
|
|
141
|
-
|
|
141
|
+
var TOTAL = 10;
|
|
142
|
+
var TRIM_PART = 2;
|
|
143
|
+
var TRIM_TOTAL = 4;
|
|
144
|
+
await calculate();
|
|
145
|
+
function clamp(value, minimum, maximum, loop) {
|
|
146
|
+
if (![
|
|
147
|
+
value,
|
|
148
|
+
minimum,
|
|
149
|
+
maximum
|
|
150
|
+
].every(isNumber)) return NaN;
|
|
151
|
+
if (value < minimum) return loop === true ? maximum : minimum;
|
|
152
|
+
return value > maximum ? loop === true ? minimum : maximum : value;
|
|
153
|
+
}
|
|
154
|
+
function getBoolean(value, defaultValue) {
|
|
155
|
+
return typeof value === "boolean" ? value : defaultValue ?? false;
|
|
156
|
+
}
|
|
157
|
+
function isEventTarget(value) {
|
|
158
|
+
return typeof value === "object" && value != null && typeof value.addEventListener === "function" && typeof value.removeEventListener === "function" && typeof value.dispatchEvent === "function";
|
|
159
|
+
}
|
|
160
|
+
function addDelegatedHandler(doc, type, name, passive) {
|
|
161
|
+
if (DELEGATED.has(name)) return;
|
|
162
|
+
DELEGATED.add(name);
|
|
163
|
+
doc.addEventListener(type, passive ? HANDLER_PASSIVE : HANDLER_ACTIVE, { passive });
|
|
164
|
+
}
|
|
165
|
+
function addDelegatedListener(target, type, name, listener, passive) {
|
|
166
|
+
target[name] ??= /* @__PURE__ */ new Set();
|
|
167
|
+
target[name].add(listener);
|
|
168
|
+
addDelegatedHandler(document, type, name, passive);
|
|
169
|
+
return () => {
|
|
170
|
+
removeDelegatedListener(target, name, listener);
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
function delegatedEventHandler(event) {
|
|
174
|
+
const key = `${EVENT_PREFIX}${event.type}${this ? EVENT_SUFFIX_PASSIVE : EVENT_SUFFIX_ACTIVE}`;
|
|
175
|
+
const items = event.composedPath();
|
|
176
|
+
const { length } = items;
|
|
177
|
+
let target = items[0];
|
|
178
|
+
Object.defineProperties(event, {
|
|
179
|
+
currentTarget: {
|
|
180
|
+
configurable: true,
|
|
181
|
+
get() {
|
|
182
|
+
return target;
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
target: {
|
|
186
|
+
configurable: true,
|
|
187
|
+
value: target
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
for (let index$1 = 0; index$1 < length; index$1 += 1) {
|
|
191
|
+
const item = items[index$1];
|
|
192
|
+
const listeners = item[key];
|
|
193
|
+
if (item.disabled || listeners == null) continue;
|
|
194
|
+
target = item;
|
|
195
|
+
for (const listener of listeners) {
|
|
196
|
+
listener.call(item, event);
|
|
197
|
+
if (event.cancelBubble) return;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function getDelegatedName(target, type, options) {
|
|
202
|
+
if (isEventTarget(target) && EVENT_TYPES.has(type) && !options.capture && !options.once && options.signal == null) return `${EVENT_PREFIX}${type}${options.passive ? EVENT_SUFFIX_PASSIVE : EVENT_SUFFIX_ACTIVE}`;
|
|
203
|
+
}
|
|
204
|
+
function removeDelegatedListener(target, name, listener) {
|
|
205
|
+
const handlers = target[name];
|
|
206
|
+
if (handlers == null || !handlers.has(listener)) return false;
|
|
207
|
+
handlers.delete(listener);
|
|
208
|
+
if (handlers.size === 0) target[name] = void 0;
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
var DELEGATED = /* @__PURE__ */ new Set();
|
|
212
|
+
var EVENT_PREFIX = "@";
|
|
213
|
+
var EVENT_SUFFIX_ACTIVE = ":active";
|
|
214
|
+
var EVENT_SUFFIX_PASSIVE = ":passive";
|
|
215
|
+
var EVENT_TYPES = new Set([
|
|
216
|
+
"beforeinput",
|
|
217
|
+
"click",
|
|
218
|
+
"dblclick",
|
|
219
|
+
"contextmenu",
|
|
220
|
+
"focusin",
|
|
221
|
+
"focusout",
|
|
222
|
+
"input",
|
|
223
|
+
"keydown",
|
|
224
|
+
"keyup",
|
|
225
|
+
"mousedown",
|
|
226
|
+
"mousemove",
|
|
227
|
+
"mouseout",
|
|
228
|
+
"mouseover",
|
|
229
|
+
"mouseup",
|
|
230
|
+
"pointerdown",
|
|
231
|
+
"pointermove",
|
|
232
|
+
"pointerout",
|
|
233
|
+
"pointerover",
|
|
234
|
+
"pointerup",
|
|
235
|
+
"touchend",
|
|
236
|
+
"touchmove",
|
|
237
|
+
"touchstart"
|
|
238
|
+
]);
|
|
239
|
+
var HANDLER_ACTIVE = delegatedEventHandler.bind(false);
|
|
240
|
+
var HANDLER_PASSIVE = delegatedEventHandler.bind(true);
|
|
142
241
|
function createEventOptions(options) {
|
|
143
242
|
return {
|
|
144
243
|
capture: getBoolean(options?.capture),
|
|
145
244
|
once: getBoolean(options?.once),
|
|
146
245
|
passive: getBoolean(options?.passive, true),
|
|
147
|
-
signal: options?.signal
|
|
246
|
+
signal: options?.signal instanceof AbortSignal ? options.signal : void 0
|
|
148
247
|
};
|
|
149
248
|
}
|
|
150
249
|
function on(target, type, listener, options) {
|
|
151
250
|
if (!isEventTarget(target) || typeof type !== "string" || typeof listener !== "function") return noop;
|
|
152
251
|
const extended = createEventOptions(options);
|
|
252
|
+
const delegated = getDelegatedName(target, type, extended);
|
|
253
|
+
if (delegated != null) return addDelegatedListener(target, type, delegated, listener, extended.passive);
|
|
153
254
|
target.addEventListener(type, listener, extended);
|
|
255
|
+
if (extended.once) return noop;
|
|
154
256
|
return () => {
|
|
155
257
|
target.removeEventListener(type, listener, extended);
|
|
156
258
|
};
|
|
157
259
|
}
|
|
158
|
-
|
|
159
260
|
function findAncestor(origin, selector) {
|
|
160
261
|
if (!(origin instanceof Element) || selector == null) return null;
|
|
161
262
|
if (typeof selector === "string") {
|
|
@@ -171,652 +272,489 @@ function findAncestor(origin, selector) {
|
|
|
171
272
|
}
|
|
172
273
|
return parent;
|
|
173
274
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
state.active.add(this);
|
|
221
|
-
}
|
|
222
|
-
else {
|
|
223
|
-
state.active.delete(this);
|
|
224
|
-
}
|
|
225
|
-
if (this.options.interactive) {
|
|
226
|
-
if (active) {
|
|
227
|
-
state.order.push(this);
|
|
228
|
-
}
|
|
229
|
-
else {
|
|
230
|
-
const index = state.order.indexOf(this);
|
|
231
|
-
if (index > -1) {
|
|
232
|
-
state.order.splice(index, 1);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
if (active) {
|
|
237
|
-
activate(this);
|
|
238
|
-
}
|
|
239
|
-
else {
|
|
240
|
-
deactivate(this);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
//
|
|
275
|
+
var Floatable = class {
|
|
276
|
+
active = false;
|
|
277
|
+
disabled = false;
|
|
278
|
+
frame;
|
|
279
|
+
ignoreFocus = false;
|
|
280
|
+
constructor(options) {
|
|
281
|
+
this.options = options;
|
|
282
|
+
initialize(this);
|
|
283
|
+
}
|
|
284
|
+
destroy() {
|
|
285
|
+
stop(this);
|
|
286
|
+
const state = getState();
|
|
287
|
+
state?.active.delete(this);
|
|
288
|
+
state?.mapped.delete(this.options.anchor);
|
|
289
|
+
state?.mapped.delete(this.options.content);
|
|
290
|
+
this.options.anchor = void 0;
|
|
291
|
+
this.options.content = void 0;
|
|
292
|
+
}
|
|
293
|
+
disable() {
|
|
294
|
+
if (this.disabled) return;
|
|
295
|
+
this.disabled = true;
|
|
296
|
+
stop(this);
|
|
297
|
+
getState()?.active.delete(this);
|
|
298
|
+
}
|
|
299
|
+
enable() {
|
|
300
|
+
if (!this.disabled) return;
|
|
301
|
+
this.disabled = false;
|
|
302
|
+
initialize(this);
|
|
303
|
+
}
|
|
304
|
+
toggle(active, ignoreFocus) {
|
|
305
|
+
if (this.disabled || this.active === active) return;
|
|
306
|
+
const state = getState();
|
|
307
|
+
if (state == null) return;
|
|
308
|
+
this.ignoreFocus = !active && (ignoreFocus ?? false);
|
|
309
|
+
stop(this);
|
|
310
|
+
if (active) state.active.add(this);
|
|
311
|
+
else state.active.delete(this);
|
|
312
|
+
if (this.options.interactive) if (active) state.order.push(this);
|
|
313
|
+
else {
|
|
314
|
+
const index$1 = state.order.indexOf(this);
|
|
315
|
+
if (index$1 > -1) state.order.splice(index$1, 1);
|
|
316
|
+
}
|
|
317
|
+
if (active) activate(this);
|
|
318
|
+
else deactivate(this);
|
|
319
|
+
}
|
|
320
|
+
};
|
|
245
321
|
function activate(floatable) {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
322
|
+
floatable.active = true;
|
|
323
|
+
document.body.append(floatable.options.content);
|
|
324
|
+
floatable.options.content.hidden = false;
|
|
325
|
+
updatePosition(floatable);
|
|
250
326
|
}
|
|
251
327
|
function closeAbove(element) {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
floatable.options.content === element);
|
|
258
|
-
if (index === -1 || index === state.order.length - 1) {
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
while (index < state.order.length - 1) {
|
|
262
|
-
void state.order.pop()?.toggle(false, true);
|
|
263
|
-
}
|
|
328
|
+
const state = getState();
|
|
329
|
+
if (state == null) return;
|
|
330
|
+
const index$1 = state.order.findIndex((floatable) => floatable.options.anchor === element || floatable.options.content === element);
|
|
331
|
+
if (index$1 === -1 || index$1 === state.order.length - 1) return;
|
|
332
|
+
while (index$1 < state.order.length - 1) state.order.pop()?.toggle(false, true);
|
|
264
333
|
}
|
|
265
334
|
function closeAll() {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
void floatable.toggle(false, true);
|
|
271
|
-
}
|
|
335
|
+
const state = getState();
|
|
336
|
+
const floatables = [...state?.active ?? []];
|
|
337
|
+
state?.active.clear();
|
|
338
|
+
for (const floatable of floatables) floatable.toggle(false, true);
|
|
272
339
|
}
|
|
273
340
|
function closeNonInteractive(state) {
|
|
274
|
-
|
|
275
|
-
if (!floatable.options.interactive) {
|
|
276
|
-
void floatable.toggle(false);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
341
|
+
for (const floatable of state.active) if (!floatable.options.interactive) floatable.toggle(false);
|
|
279
342
|
}
|
|
280
343
|
function deactivate(floatable) {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
344
|
+
floatable.active = false;
|
|
345
|
+
floatable.options.content.hidden = true;
|
|
346
|
+
floatable.options.anchor.insertAdjacentElement(INSERT_AFTEREND, floatable.options.content);
|
|
347
|
+
floatable.options.onAfter?.(false);
|
|
285
348
|
}
|
|
286
349
|
function getState() {
|
|
287
|
-
|
|
350
|
+
return window._oscarpalmer_oui_floatable;
|
|
288
351
|
}
|
|
289
352
|
function getX(anchor, content, position) {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
if (position.startsWith(POSITION_HORIZONTAL)) {
|
|
307
|
-
if (anchor.right + content.width <= window.innerWidth) {
|
|
308
|
-
return anchor.right;
|
|
309
|
-
}
|
|
310
|
-
return anchor.left - content.width;
|
|
311
|
-
}
|
|
312
|
-
const left = anchor.left + (anchor.width - content.width) / 2;
|
|
313
|
-
return left < 0 ? 0 : left;
|
|
353
|
+
if (position.endsWith(POSITION_SUFFIX_END)) {
|
|
354
|
+
const end = anchor.right - content.width;
|
|
355
|
+
return end < 0 ? 0 : end;
|
|
356
|
+
}
|
|
357
|
+
if (position.endsWith(POSITION_SUFFIX_START)) {
|
|
358
|
+
const start = anchor.left;
|
|
359
|
+
return start + content.width > window.innerWidth ? window.innerWidth - content.width : start;
|
|
360
|
+
}
|
|
361
|
+
if (position.startsWith(POSITION_END)) return anchor.right;
|
|
362
|
+
if (position.startsWith(POSITION_START)) return anchor.left - content.width;
|
|
363
|
+
if (position.startsWith(POSITION_HORIZONTAL)) {
|
|
364
|
+
if (anchor.right + content.width <= window.innerWidth) return anchor.right;
|
|
365
|
+
return anchor.left - content.width;
|
|
366
|
+
}
|
|
367
|
+
const left = anchor.left + (anchor.width - content.width) / 2;
|
|
368
|
+
return left < 0 ? 0 : left;
|
|
314
369
|
}
|
|
315
370
|
function getY(anchor, content, position, preferAbove) {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
if (position.startsWith(POSITION_VERTICAL)) {
|
|
333
|
-
if (preferAbove && anchor.top - content.height >= 0) {
|
|
334
|
-
return anchor.top - content.height;
|
|
335
|
-
}
|
|
336
|
-
if (anchor.bottom + content.height <= document.body.clientHeight) {
|
|
337
|
-
return anchor.bottom;
|
|
338
|
-
}
|
|
339
|
-
return anchor.top - content.height;
|
|
340
|
-
}
|
|
341
|
-
return anchor.top + (anchor.height - content.height) / 2;
|
|
371
|
+
if (position.startsWith(POSITION_ABOVE)) return anchor.top - content.height;
|
|
372
|
+
if (position.startsWith(POSITION_BELOW)) return anchor.bottom;
|
|
373
|
+
if (position.endsWith(POSITION_BOTTOM)) {
|
|
374
|
+
const bottom = anchor.bottom - content.height;
|
|
375
|
+
return bottom < 0 ? 0 : bottom;
|
|
376
|
+
}
|
|
377
|
+
if (position.endsWith(POSITION_TOP)) {
|
|
378
|
+
const top = anchor.top;
|
|
379
|
+
return top + content.height > window.innerHeight ? window.innerHeight - content.height : top;
|
|
380
|
+
}
|
|
381
|
+
if (position.startsWith(POSITION_VERTICAL)) {
|
|
382
|
+
if (preferAbove && anchor.top - content.height >= 0) return anchor.top - content.height;
|
|
383
|
+
if (anchor.bottom + content.height <= document.body.clientHeight) return anchor.bottom;
|
|
384
|
+
return anchor.top - content.height;
|
|
385
|
+
}
|
|
386
|
+
return anchor.top + (anchor.height - content.height) / 2;
|
|
342
387
|
}
|
|
343
388
|
function initialize(floatable) {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
389
|
+
const { anchor, content, interactive } = floatable.options;
|
|
390
|
+
if (interactive) {
|
|
391
|
+
anchor.setAttribute(ATTRIBUTE_ANCHOR, "");
|
|
392
|
+
content.setAttribute(ATTRIBUTE_CONTENT, "");
|
|
393
|
+
}
|
|
394
|
+
content.style.position = "fixed";
|
|
395
|
+
content.style.inset = "0 auto auto 0";
|
|
396
|
+
content.style.zIndex = "10";
|
|
397
|
+
const state = getState();
|
|
398
|
+
state?.mapped.set(anchor, floatable);
|
|
399
|
+
state?.mapped.set(content, floatable);
|
|
355
400
|
}
|
|
356
401
|
function isDisabled(element) {
|
|
357
|
-
|
|
358
|
-
element.readOnly ||
|
|
359
|
-
element.getAttribute('aria-disabled') === 'true');
|
|
402
|
+
return element.disabled || element.readOnly || element.getAttribute("aria-disabled") === "true";
|
|
360
403
|
}
|
|
361
404
|
function onClick(event) {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
else if (related.hasAttribute(ATTRIBUTE_CONTENT)) {
|
|
367
|
-
closeAbove(related);
|
|
368
|
-
}
|
|
369
|
-
else if (!isDisabled(related)) {
|
|
370
|
-
toggle(related);
|
|
371
|
-
}
|
|
405
|
+
const related = findAncestor(event.target, SELECTOR_ALL);
|
|
406
|
+
if (!(related instanceof HTMLElement)) closeAll();
|
|
407
|
+
else if (related.hasAttribute(ATTRIBUTE_CONTENT)) closeAbove(related);
|
|
408
|
+
else if (!isDisabled(related)) toggle(related);
|
|
372
409
|
}
|
|
373
410
|
function onKeyDown(event) {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
if (!(related instanceof HTMLElement)) {
|
|
384
|
-
return;
|
|
385
|
-
}
|
|
386
|
-
closeAbove(related);
|
|
387
|
-
const floatable = state.mapped.get(related);
|
|
388
|
-
if (floatable != null) {
|
|
389
|
-
void floatable.toggle(false);
|
|
390
|
-
}
|
|
411
|
+
if (event.key !== "Escape") return;
|
|
412
|
+
const state = getState();
|
|
413
|
+
if (state == null || state.active.size === 0) return;
|
|
414
|
+
closeNonInteractive(state);
|
|
415
|
+
const related = findAncestor(event.target, SELECTOR_CONTENT$1);
|
|
416
|
+
if (!(related instanceof HTMLElement)) return;
|
|
417
|
+
closeAbove(related);
|
|
418
|
+
const floatable = state.mapped.get(related);
|
|
419
|
+
if (floatable != null) floatable.toggle(false);
|
|
391
420
|
}
|
|
392
421
|
function stop(floatable) {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
}
|
|
396
|
-
floatable.frame = undefined;
|
|
422
|
+
if (floatable.frame != null) cancelAnimationFrame(floatable.frame);
|
|
423
|
+
floatable.frame = void 0;
|
|
397
424
|
}
|
|
398
425
|
function toggle(anchor) {
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
else {
|
|
410
|
-
closeAbove(content);
|
|
411
|
-
}
|
|
412
|
-
void floatable.toggle(!active);
|
|
426
|
+
const floatable = getState()?.mapped.get(anchor);
|
|
427
|
+
if (floatable == null) {
|
|
428
|
+
closeAll();
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
const active = Boolean(floatable.active);
|
|
432
|
+
const content = findAncestor(floatable.options.anchor, SELECTOR_CONTENT$1);
|
|
433
|
+
if (content == null) closeAll();
|
|
434
|
+
else closeAbove(content);
|
|
435
|
+
floatable.toggle(!active);
|
|
413
436
|
}
|
|
414
437
|
function updatePosition(floatable) {
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
floatable.frame = requestAnimationFrame(run);
|
|
468
|
-
}
|
|
469
|
-
//
|
|
470
|
-
const ATTRIBUTE_ANCHOR = 'oui-floatable-anchor';
|
|
471
|
-
const ATTRIBUTE_CONTENT = 'oui-floatable-content';
|
|
472
|
-
const INSERT_AFTEREND = 'afterend';
|
|
473
|
-
const POSITION_ABOVE = 'above';
|
|
474
|
-
const POSITION_BELOW = 'below';
|
|
475
|
-
const POSITION_BOTTOM = 'bottom';
|
|
476
|
-
const POSITION_END = 'end';
|
|
477
|
-
const POSITION_HORIZONTAL = 'horizontal';
|
|
478
|
-
const POSITION_START = 'start';
|
|
479
|
-
const POSITION_SUFFIX_END = '-end';
|
|
480
|
-
const POSITION_SUFFIX_START = '-start';
|
|
481
|
-
const POSITION_TOP = 'top';
|
|
482
|
-
const POSITION_VERTICAL = 'vertical';
|
|
438
|
+
let position = floatable.options.anchor.getAttribute(floatable.options.positionAttribute)?.trim() ?? floatable.options.defaultPosition;
|
|
439
|
+
if (!POSITIONS.has(position)) position = floatable.options.defaultPosition;
|
|
440
|
+
let previousAnchor;
|
|
441
|
+
let previousContent;
|
|
442
|
+
let calculated = false;
|
|
443
|
+
let runOnAfter = false;
|
|
444
|
+
function run() {
|
|
445
|
+
const anchor = floatable.options.anchor.getBoundingClientRect();
|
|
446
|
+
const content = floatable.options.content.getBoundingClientRect();
|
|
447
|
+
if (calculated) {
|
|
448
|
+
if (previousAnchor != null && previousContent != null) {
|
|
449
|
+
if (PROPERTIES.every((property) => anchor[property] === previousAnchor[property]) && PROPERTIES.every((property) => content[property] === previousContent[property])) {
|
|
450
|
+
floatable.frame = requestAnimationFrame(run);
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
} else calculated = true;
|
|
455
|
+
update(anchor, content);
|
|
456
|
+
}
|
|
457
|
+
function update(anchor, content) {
|
|
458
|
+
previousAnchor = anchor;
|
|
459
|
+
previousContent = content;
|
|
460
|
+
const left = getX(anchor, content, position);
|
|
461
|
+
const top = getY(anchor, content, position, floatable.options.preferAbove);
|
|
462
|
+
if (top + content.height > window.innerHeight) floatable.options.content.style.height = `${window.innerHeight - top}px`;
|
|
463
|
+
else floatable.options.content.style.height = "";
|
|
464
|
+
if (left + content.width > window.innerWidth) floatable.options.content.style.width = `${window.innerWidth - left}px`;
|
|
465
|
+
else floatable.options.content.style.width = "";
|
|
466
|
+
floatable.options.content.style.transform = `translate3d(${left}px, ${top}px, 0)`;
|
|
467
|
+
floatable.frame = requestAnimationFrame(run);
|
|
468
|
+
if (!runOnAfter) {
|
|
469
|
+
runOnAfter = true;
|
|
470
|
+
floatable.options.onAfter?.(true);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
floatable.frame = requestAnimationFrame(run);
|
|
474
|
+
}
|
|
475
|
+
const ATTRIBUTE_ANCHOR = "oui-floatable-anchor";
|
|
476
|
+
const ATTRIBUTE_CONTENT = "oui-floatable-content";
|
|
477
|
+
const INSERT_AFTEREND = "afterend";
|
|
478
|
+
const POSITION_ABOVE = "above";
|
|
479
|
+
const POSITION_BELOW = "below";
|
|
480
|
+
const POSITION_BOTTOM = "bottom";
|
|
481
|
+
const POSITION_END = "end";
|
|
482
|
+
const POSITION_HORIZONTAL = "horizontal";
|
|
483
|
+
const POSITION_START = "start";
|
|
484
|
+
const POSITION_SUFFIX_END = "-end";
|
|
485
|
+
const POSITION_SUFFIX_START = "-start";
|
|
486
|
+
const POSITION_TOP = "top";
|
|
487
|
+
const POSITION_VERTICAL = "vertical";
|
|
483
488
|
const POSITIONS = new Set([
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
489
|
+
"above",
|
|
490
|
+
"above-end",
|
|
491
|
+
"above-start",
|
|
492
|
+
"below",
|
|
493
|
+
"below-end",
|
|
494
|
+
"below-start",
|
|
495
|
+
"end",
|
|
496
|
+
"end-bottom",
|
|
497
|
+
"end-top",
|
|
498
|
+
"horizontal",
|
|
499
|
+
"horizontal-bottom",
|
|
500
|
+
"horizontal-top",
|
|
501
|
+
"start",
|
|
502
|
+
"start-bottom",
|
|
503
|
+
"start-top",
|
|
504
|
+
"vertical",
|
|
505
|
+
"vertical-end",
|
|
506
|
+
"vertical-start"
|
|
502
507
|
]);
|
|
503
|
-
const PROPERTIES = [
|
|
508
|
+
const PROPERTIES = [
|
|
509
|
+
"bottom",
|
|
510
|
+
"left",
|
|
511
|
+
"right",
|
|
512
|
+
"top"
|
|
513
|
+
];
|
|
504
514
|
const SELECTOR_ALL = `[${ATTRIBUTE_ANCHOR}], [${ATTRIBUTE_CONTENT}]`;
|
|
505
515
|
const SELECTOR_CONTENT$1 = `[${ATTRIBUTE_CONTENT}]`;
|
|
506
|
-
//
|
|
507
516
|
if (window._oscarpalmer_oui_floatable == null) {
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
enable() {
|
|
562
|
-
if (this.disabled) {
|
|
563
|
-
setDisabled(this, false);
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
focus(last) {
|
|
567
|
-
tabToTrap(this, getFocusable(this.element), this.element, last ? -1 : 0);
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
//
|
|
517
|
+
Object.defineProperty(window, "_oscarpalmer_oui_floatable", {
|
|
518
|
+
enumerable: false,
|
|
519
|
+
value: {
|
|
520
|
+
active: /* @__PURE__ */ new Set(),
|
|
521
|
+
mapped: /* @__PURE__ */ new Map(),
|
|
522
|
+
order: []
|
|
523
|
+
},
|
|
524
|
+
writable: false
|
|
525
|
+
});
|
|
526
|
+
on(document, "keydown", (event) => {
|
|
527
|
+
onKeyDown(event);
|
|
528
|
+
});
|
|
529
|
+
on(document, "click", (event) => {
|
|
530
|
+
onClick(event);
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
var FocusTrap = class {
|
|
534
|
+
disabled = false;
|
|
535
|
+
connected = true;
|
|
536
|
+
element;
|
|
537
|
+
embedded;
|
|
538
|
+
get contain() {
|
|
539
|
+
return this.element.hasAttribute(FOCUS_TRAP_CONTAIN);
|
|
540
|
+
}
|
|
541
|
+
get noescape() {
|
|
542
|
+
return this.element.hasAttribute(FOCUS_TRAP_NOESCAPE);
|
|
543
|
+
}
|
|
544
|
+
constructor(element, options) {
|
|
545
|
+
this.element = element;
|
|
546
|
+
this.embedded = options != null;
|
|
547
|
+
element.setAttribute("tabindex", "-1");
|
|
548
|
+
if (options != null) element.setAttribute(FOCUS_TRAP_SELECTOR, "");
|
|
549
|
+
if (options?.noescape) element.setAttribute(FOCUS_TRAP_NOESCAPE, "");
|
|
550
|
+
}
|
|
551
|
+
connect() {
|
|
552
|
+
setConnected(this, true);
|
|
553
|
+
}
|
|
554
|
+
destroy() {
|
|
555
|
+
this.element = void 0;
|
|
556
|
+
}
|
|
557
|
+
disable() {
|
|
558
|
+
if (!(this.disabled || this.noescape)) setDisabled(this, true);
|
|
559
|
+
}
|
|
560
|
+
disconnect() {
|
|
561
|
+
setConnected(this, false);
|
|
562
|
+
}
|
|
563
|
+
enable() {
|
|
564
|
+
if (this.disabled) setDisabled(this, false);
|
|
565
|
+
}
|
|
566
|
+
focus(last) {
|
|
567
|
+
tabToTrap(this, getFocusable(this.element), this.element, last ? -1 : 0);
|
|
568
|
+
}
|
|
569
|
+
};
|
|
571
570
|
function createFocusTrap(element, options) {
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
571
|
+
let focusTrap = FOCUSTRAPS_ALL.get(element);
|
|
572
|
+
if (focusTrap == null) {
|
|
573
|
+
focusTrap = new FocusTrap(element, options);
|
|
574
|
+
FOCUSTRAPS_ALL.set(element, focusTrap);
|
|
575
|
+
}
|
|
576
|
+
return focusTrap;
|
|
578
577
|
}
|
|
579
578
|
function onEscape(event) {
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
}
|
|
591
|
-
if (!focusTrap.disabled) {
|
|
592
|
-
break;
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
focusTrap?.disable();
|
|
579
|
+
let element = findAncestor(event.target, ATTRIBUTE_SELECTOR);
|
|
580
|
+
let focusTrap = FOCUSTRAPS_ALL.get(element);
|
|
581
|
+
if (element == null || focusTrap == null) return;
|
|
582
|
+
while (focusTrap.disabled) {
|
|
583
|
+
element = findAncestor(focusTrap.element.parentElement, ATTRIBUTE_SELECTOR);
|
|
584
|
+
focusTrap = FOCUSTRAPS_ALL.get(element);
|
|
585
|
+
if (element == null || focusTrap == null) return;
|
|
586
|
+
if (!focusTrap.disabled) break;
|
|
587
|
+
}
|
|
588
|
+
focusTrap?.disable();
|
|
596
589
|
}
|
|
597
590
|
function onFocusIn(event) {
|
|
598
|
-
|
|
599
|
-
lastTarget = focusTrap == null ? undefined : event.target;
|
|
591
|
+
lastTarget = FOCUSTRAPS_ALL.get(findAncestor(event.target, ATTRIBUTE_SELECTOR)) == null ? void 0 : event.target;
|
|
600
592
|
}
|
|
601
593
|
function onKeydown(event) {
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
}
|
|
594
|
+
switch (event.key) {
|
|
595
|
+
case "Escape":
|
|
596
|
+
onEscape(event);
|
|
597
|
+
break;
|
|
598
|
+
case "Tab":
|
|
599
|
+
onTab(event);
|
|
600
|
+
break;
|
|
601
|
+
default: return;
|
|
602
|
+
}
|
|
612
603
|
}
|
|
613
604
|
function onPointerdown(event) {
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
}
|
|
625
|
-
for (const focusTrap of FOCUSTRAPS_DISABLED) {
|
|
626
|
-
if (focusTrap.element !== nextFocusTrap) {
|
|
627
|
-
focusTrap.enable();
|
|
628
|
-
}
|
|
629
|
-
}
|
|
605
|
+
const lastFocusTrap = findAncestor(lastTarget, ATTRIBUTE_SELECTOR);
|
|
606
|
+
const nextFocusTrap = findAncestor(event.target, ATTRIBUTE_SELECTOR);
|
|
607
|
+
if (lastFocusTrap != null && nextFocusTrap !== lastFocusTrap) {
|
|
608
|
+
if (FOCUSTRAPS_ALL.get(lastFocusTrap)?.contain ?? false) {
|
|
609
|
+
event.preventDefault();
|
|
610
|
+
lastTarget?.focus();
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
if (FOCUSTRAPS_DISABLED.size === 0) return;
|
|
614
|
+
for (const focusTrap of FOCUSTRAPS_DISABLED) if (focusTrap.element !== nextFocusTrap) focusTrap.enable();
|
|
630
615
|
}
|
|
631
616
|
function onTab(event) {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
const elements = getFocusable(element);
|
|
641
|
-
const index = elements.indexOf(event.target);
|
|
642
|
-
if (index === -1 || elements.length === 0) {
|
|
643
|
-
tabToTrap(focusTrap, elements, element);
|
|
644
|
-
}
|
|
645
|
-
else {
|
|
646
|
-
tabToElement(focusTrap, elements, index, event.shiftKey ? -1 : 1);
|
|
647
|
-
}
|
|
617
|
+
const element = findAncestor(event.target, ATTRIBUTE_SELECTOR);
|
|
618
|
+
const focusTrap = FOCUSTRAPS_ALL.get(element);
|
|
619
|
+
if (focusTrap == null) return;
|
|
620
|
+
if (!focusTrap.disabled) event.preventDefault();
|
|
621
|
+
const elements = getFocusable(element);
|
|
622
|
+
const index$1 = elements.indexOf(event.target);
|
|
623
|
+
if (index$1 === -1 || elements.length === 0) tabToTrap(focusTrap, elements, element);
|
|
624
|
+
else tabToElement(focusTrap, elements, index$1, event.shiftKey ? -1 : 1);
|
|
648
625
|
}
|
|
649
626
|
function setConnected(focusTrap, value) {
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
}
|
|
653
|
-
focusTrap.connected = value;
|
|
627
|
+
if (!focusTrap.embedded || focusTrap.connected === value) return;
|
|
628
|
+
focusTrap.connected = value;
|
|
654
629
|
}
|
|
655
630
|
function setDisabled(focusTrap, value) {
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
}
|
|
690
|
-
else {
|
|
691
|
-
const next = elements.length === 0 ? element : elements.at(index ?? 0);
|
|
692
|
-
next.focus();
|
|
693
|
-
lastTarget = next;
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
//
|
|
697
|
-
const FOCUS_TRAP_SELECTOR = 'oui-focus-trap';
|
|
631
|
+
focusTrap.disabled = value;
|
|
632
|
+
if (value) FOCUSTRAPS_DISABLED.add(focusTrap);
|
|
633
|
+
else FOCUSTRAPS_DISABLED.delete(focusTrap);
|
|
634
|
+
}
|
|
635
|
+
function tabToElement(focusTrap, elements, index$1, modifier) {
|
|
636
|
+
const { length } = elements;
|
|
637
|
+
const next = clamp(index$1 + modifier, 0, length - 1, true);
|
|
638
|
+
if (focusTrap.disabled) {
|
|
639
|
+
if (index$1 === length - 1 && next === 0 || index$1 === 0 && next === length - 1) {
|
|
640
|
+
lastTarget = void 0;
|
|
641
|
+
focusTrap.enable();
|
|
642
|
+
}
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
const element = elements[next];
|
|
646
|
+
const elementFocusTrap = FOCUSTRAPS_ALL.get(element);
|
|
647
|
+
if (elementFocusTrap != null) elementFocusTrap.focus(modifier === -1);
|
|
648
|
+
else {
|
|
649
|
+
elements[next].focus();
|
|
650
|
+
lastTarget = elements[next];
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
function tabToTrap(focusTrap, elements, element, index$1) {
|
|
654
|
+
if (focusTrap.disabled) {
|
|
655
|
+
lastTarget = void 0;
|
|
656
|
+
focusTrap.enable();
|
|
657
|
+
} else {
|
|
658
|
+
const next = elements.length === 0 ? element : elements.at(index$1 ?? 0);
|
|
659
|
+
next.focus();
|
|
660
|
+
lastTarget = next;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
const FOCUS_TRAP_SELECTOR = "oui-focus-trap";
|
|
698
664
|
const ATTRIBUTE_SELECTOR = `[${FOCUS_TRAP_SELECTOR}]`;
|
|
699
665
|
const EVENT_OPTIONS = {
|
|
700
|
-
|
|
701
|
-
|
|
666
|
+
capture: true,
|
|
667
|
+
passive: false
|
|
702
668
|
};
|
|
703
669
|
const FOCUS_TRAP_CONTAIN = `${FOCUS_TRAP_SELECTOR}-contain`;
|
|
704
670
|
const FOCUS_TRAP_NOESCAPE = `${FOCUS_TRAP_SELECTOR}-noescape`;
|
|
705
|
-
const FOCUSTRAPS_ALL = new WeakMap();
|
|
706
|
-
const FOCUSTRAPS_DISABLED = new Set();
|
|
671
|
+
const FOCUSTRAPS_ALL = /* @__PURE__ */ new WeakMap();
|
|
672
|
+
const FOCUSTRAPS_DISABLED = /* @__PURE__ */ new Set();
|
|
707
673
|
let lastTarget;
|
|
708
|
-
|
|
709
|
-
on(document,
|
|
710
|
-
on(document,
|
|
711
|
-
on(document,
|
|
712
|
-
on(document, 'touchstart', onPointerdown, EVENT_OPTIONS);
|
|
713
|
-
|
|
674
|
+
on(document, "focusin", onFocusIn, EVENT_OPTIONS);
|
|
675
|
+
on(document, "keydown", onKeydown, EVENT_OPTIONS);
|
|
676
|
+
on(document, "mousedown", onPointerdown, EVENT_OPTIONS);
|
|
677
|
+
on(document, "touchstart", onPointerdown, EVENT_OPTIONS);
|
|
714
678
|
let index = 0;
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
this.togglePopover();
|
|
784
|
-
}
|
|
785
|
-
togglePopover(options) {
|
|
786
|
-
if (typeof options === 'boolean') {
|
|
787
|
-
if (options === true) {
|
|
788
|
-
this.showPopover();
|
|
789
|
-
}
|
|
790
|
-
else {
|
|
791
|
-
this.hidePopover();
|
|
792
|
-
}
|
|
793
|
-
return options;
|
|
794
|
-
}
|
|
795
|
-
if (this.#floatable.active) {
|
|
796
|
-
this.hidePopover();
|
|
797
|
-
return false;
|
|
798
|
-
}
|
|
799
|
-
this.showPopover();
|
|
800
|
-
return true;
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
//
|
|
679
|
+
var OuiPopoverElement = class extends HTMLElement {
|
|
680
|
+
#floatable;
|
|
681
|
+
#focusTrap;
|
|
682
|
+
constructor() {
|
|
683
|
+
super();
|
|
684
|
+
const content = this.querySelector(SELECTOR_CONTENT);
|
|
685
|
+
const toggle$1 = this.querySelector(SELECTOR_TOGGLE);
|
|
686
|
+
if (!(content instanceof HTMLElement)) throw new Error("A oui-popover must have a direct child element with the [oui-popover-content]-attribute");
|
|
687
|
+
if (!(toggle$1 instanceof HTMLButtonElement)) throw new Error("A oui-popover must have a direct child element with the [oui-popover-toggle]-attribute and be a button");
|
|
688
|
+
content.hidden = true;
|
|
689
|
+
content.setAttribute("role", "dialog");
|
|
690
|
+
content.setAttribute("aria-modal", "true");
|
|
691
|
+
if (isNullableOrWhitespace(content.id)) content.setAttribute("id", `${ATTRIBUTE_ID_PREFIX}_${++index}`);
|
|
692
|
+
toggle$1.setAttribute("aria-controls", content.id);
|
|
693
|
+
toggle$1.setAttribute("aria-haspopup", "dialog");
|
|
694
|
+
this.#floatable = new Floatable({
|
|
695
|
+
content,
|
|
696
|
+
anchor: toggle$1,
|
|
697
|
+
defaultPosition: "below-start",
|
|
698
|
+
interactive: true,
|
|
699
|
+
positionAttribute: "position",
|
|
700
|
+
preferAbove: false,
|
|
701
|
+
onAfter: (active) => {
|
|
702
|
+
if (active) focus(content);
|
|
703
|
+
else if (!this.#floatable.ignoreFocus) toggle$1.focus();
|
|
704
|
+
}
|
|
705
|
+
});
|
|
706
|
+
this.#focusTrap = createFocusTrap(content, { noescape: true });
|
|
707
|
+
POPOVERS.set(toggle$1, this.#floatable);
|
|
708
|
+
POPOVERS.set(content, this.#floatable);
|
|
709
|
+
}
|
|
710
|
+
close() {
|
|
711
|
+
this.hidePopover();
|
|
712
|
+
}
|
|
713
|
+
connectedCallback() {
|
|
714
|
+
this.#floatable.enable();
|
|
715
|
+
this.#focusTrap.connect();
|
|
716
|
+
}
|
|
717
|
+
disconnectedCallback() {
|
|
718
|
+
this.#floatable.disable();
|
|
719
|
+
this.#focusTrap.disconnect();
|
|
720
|
+
}
|
|
721
|
+
hidePopover() {
|
|
722
|
+
if (this.#floatable.active && this.isConnected) this.#floatable.toggle(false);
|
|
723
|
+
}
|
|
724
|
+
open() {
|
|
725
|
+
this.showPopover();
|
|
726
|
+
}
|
|
727
|
+
showPopover() {
|
|
728
|
+
if (!this.#floatable.active && this.isConnected) this.#floatable.toggle(true);
|
|
729
|
+
}
|
|
730
|
+
toggle() {
|
|
731
|
+
this.togglePopover();
|
|
732
|
+
}
|
|
733
|
+
togglePopover(options) {
|
|
734
|
+
if (typeof options === "boolean") {
|
|
735
|
+
if (options === true) this.showPopover();
|
|
736
|
+
else this.hidePopover();
|
|
737
|
+
return options;
|
|
738
|
+
}
|
|
739
|
+
if (this.#floatable.active) {
|
|
740
|
+
this.hidePopover();
|
|
741
|
+
return false;
|
|
742
|
+
}
|
|
743
|
+
this.showPopover();
|
|
744
|
+
return true;
|
|
745
|
+
}
|
|
746
|
+
};
|
|
804
747
|
function focus(content) {
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
const ATTRIBUTE_ID_PREFIX = 'oui_popover_content_';
|
|
815
|
-
const POPOVERS = new Map();
|
|
816
|
-
const SELECTOR = 'oui-popover';
|
|
748
|
+
let target = getFocusable(content)[0];
|
|
749
|
+
if (!(target instanceof HTMLElement)) target = content;
|
|
750
|
+
requestAnimationFrame(() => {
|
|
751
|
+
target.focus();
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
const ATTRIBUTE_ID_PREFIX = "oui_popover_content_";
|
|
755
|
+
const POPOVERS = /* @__PURE__ */ new Map();
|
|
756
|
+
const SELECTOR = "oui-popover";
|
|
817
757
|
const SELECTOR_CONTENT = `:scope > [${SELECTOR}-content]`;
|
|
818
758
|
const SELECTOR_TOGGLE = `:scope > [${SELECTOR}-toggle]`;
|
|
819
|
-
//
|
|
820
759
|
customElements.define(SELECTOR, OuiPopoverElement);
|
|
821
|
-
|
|
822
760
|
export { OuiPopoverElement };
|