@oscarpalmer/oui 0.22.1 → 0.23.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/popover.css +15 -19
- package/dist/css/reset.css +16 -4
- package/dist/css/tooltip.css +23 -19
- package/dist/js/focus-trap/embedded.d.mts +2 -2
- package/dist/js/focus-trap/embedded.mjs +5 -1
- package/dist/js/focus-trap/standalone.mjs +2 -6
- package/dist/js/index.d.mts +1 -2
- package/dist/js/index.mjs +2 -2
- package/dist/js/internal/floatable.d.mts +12 -20
- package/dist/js/internal/floatable.mjs +32 -153
- package/dist/js/popover.d.mts +1 -20
- package/dist/js/popover.mjs +53 -82
- package/dist/js/tooltip.d.mts +1 -1
- package/dist/js/tooltip.mjs +101 -126
- package/package.json +6 -6
- package/src/css/mixins.scss +14 -12
- package/src/css/popover.scss +1 -9
- package/src/css/reset.scss +16 -4
- package/src/css/tooltip.scss +9 -7
- package/src/js/focus-trap/embedded.ts +6 -1
- package/src/js/focus-trap/standalone.ts +2 -7
- package/src/js/index.ts +2 -1
- package/src/js/internal/floatable.ts +44 -303
- package/src/js/popover.ts +69 -131
- package/src/js/tooltip.ts +135 -180
package/dist/css/popover.css
CHANGED
|
@@ -1,34 +1,30 @@
|
|
|
1
1
|
|
|
2
2
|
:where([oui-popover-content]) {
|
|
3
3
|
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);
|
|
4
|
-
--margin-
|
|
5
|
-
--margin-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
--margin-bottom: 0.5em;
|
|
5
|
+
--margin-left: 0.5em;
|
|
6
|
+
--margin-right: 0.5em;
|
|
7
|
+
--margin-top: 0.5em;
|
|
8
|
+
inset-block: var(--margin-top) var(--margin-bottom);
|
|
9
|
+
inset-inline: var(--margin-left) var(--margin-right);
|
|
8
10
|
}
|
|
9
|
-
:where([oui-popover-content])[oui-position
|
|
10
|
-
margin: 0
|
|
11
|
+
:where([oui-popover-content])[oui-position$=bottom] {
|
|
12
|
+
--margin-bottom: 0;
|
|
11
13
|
}
|
|
12
|
-
:where([oui-popover-content])[oui-position
|
|
13
|
-
margin: 0
|
|
14
|
+
:where([oui-popover-content])[oui-position$=end] {
|
|
15
|
+
--margin-right: 0;
|
|
14
16
|
}
|
|
15
|
-
:where([oui-popover-content])[oui-position
|
|
16
|
-
margin: 0
|
|
17
|
+
:where([oui-popover-content])[oui-position$=start] {
|
|
18
|
+
--margin-left: 0;
|
|
17
19
|
}
|
|
18
|
-
:where([oui-popover-content])[oui-position
|
|
19
|
-
margin: 0
|
|
20
|
+
:where([oui-popover-content])[oui-position$=top] {
|
|
21
|
+
--margin-top: 0;
|
|
20
22
|
}
|
|
21
23
|
:where([oui-popover-content]) {
|
|
22
24
|
padding: 1rem;
|
|
23
|
-
overscroll-behavior: contain;
|
|
24
25
|
background-color: var(--oui-absolute);
|
|
26
|
+
border: none;
|
|
25
27
|
border-radius: 0.25rem;
|
|
26
28
|
}
|
|
27
|
-
:where([oui-popover-content]):focus {
|
|
28
|
-
outline: none;
|
|
29
|
-
}
|
|
30
|
-
:where([oui-popover-content]) * {
|
|
31
|
-
overscroll-behavior: contain;
|
|
32
|
-
}
|
|
33
29
|
|
|
34
30
|
|
package/dist/css/reset.css
CHANGED
|
@@ -367,6 +367,14 @@ summary) {
|
|
|
367
367
|
/**
|
|
368
368
|
* Attributes
|
|
369
369
|
*/
|
|
370
|
+
:where([aria-busy=true i]) {
|
|
371
|
+
cursor: progress;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
:where([aria-controls]) {
|
|
375
|
+
cursor: pointer;
|
|
376
|
+
}
|
|
377
|
+
|
|
370
378
|
:where([disabled], [aria-disabled=true i]) {
|
|
371
379
|
cursor: default;
|
|
372
380
|
}
|
|
@@ -375,12 +383,16 @@ summary) {
|
|
|
375
383
|
display: none !important;
|
|
376
384
|
}
|
|
377
385
|
|
|
378
|
-
:where([
|
|
379
|
-
|
|
386
|
+
:where([popover]) {
|
|
387
|
+
display: none !important;
|
|
388
|
+
overflow: visible;
|
|
389
|
+
overscroll-behavior: contain;
|
|
390
|
+
border: none;
|
|
391
|
+
color: currentcolor;
|
|
380
392
|
}
|
|
381
393
|
|
|
382
|
-
:where([
|
|
383
|
-
|
|
394
|
+
:where([popover]:popover-open) {
|
|
395
|
+
display: inherit !important;
|
|
384
396
|
}
|
|
385
397
|
|
|
386
398
|
/**
|
package/dist/css/tooltip.css
CHANGED
|
@@ -27,62 +27,66 @@ var)) {
|
|
|
27
27
|
|
|
28
28
|
:where([oui-tooltip-content]) {
|
|
29
29
|
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);
|
|
30
|
-
--margin-
|
|
31
|
-
--margin-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
--margin-bottom: 0.5em;
|
|
31
|
+
--margin-left: 0.5em;
|
|
32
|
+
--margin-right: 0.5em;
|
|
33
|
+
--margin-top: 0.5em;
|
|
34
|
+
inset-block: var(--margin-top) var(--margin-bottom);
|
|
35
|
+
inset-inline: var(--margin-left) var(--margin-right);
|
|
34
36
|
}
|
|
35
|
-
:where([oui-tooltip-content])[oui-position
|
|
36
|
-
margin: 0
|
|
37
|
+
:where([oui-tooltip-content])[oui-position$=bottom] {
|
|
38
|
+
--margin-bottom: 0;
|
|
37
39
|
}
|
|
38
|
-
:where([oui-tooltip-content])[oui-position
|
|
39
|
-
margin: 0
|
|
40
|
+
:where([oui-tooltip-content])[oui-position$=end] {
|
|
41
|
+
--margin-right: 0;
|
|
40
42
|
}
|
|
41
|
-
:where([oui-tooltip-content])[oui-position
|
|
42
|
-
margin: 0
|
|
43
|
+
:where([oui-tooltip-content])[oui-position$=start] {
|
|
44
|
+
--margin-left: 0;
|
|
43
45
|
}
|
|
44
|
-
:where([oui-tooltip-content])[oui-position
|
|
45
|
-
margin: 0
|
|
46
|
+
:where([oui-tooltip-content])[oui-position$=top] {
|
|
47
|
+
--margin-top: 0;
|
|
46
48
|
}
|
|
47
49
|
:where([oui-tooltip-content]) {
|
|
48
50
|
max-width: 48ch;
|
|
49
51
|
padding: 0.75em 1em;
|
|
52
|
+
overflow: visible;
|
|
50
53
|
opacity: 0;
|
|
51
54
|
background-color: var(--oui-absolute);
|
|
52
55
|
border-radius: 0.25rem;
|
|
53
56
|
font-size: 0.875rem;
|
|
54
57
|
pointer-events: none;
|
|
55
|
-
transition: opacity 0.125s ease-in-out;
|
|
58
|
+
transition: opacity 0.125s ease-in-out 0s;
|
|
59
|
+
transition-behavior: allow-discrete;
|
|
56
60
|
}
|
|
57
61
|
:where([oui-tooltip-content])::after {
|
|
58
62
|
content: "";
|
|
59
|
-
|
|
63
|
+
display: block;
|
|
60
64
|
position: absolute;
|
|
61
65
|
}
|
|
62
66
|
:where([oui-tooltip-content])[oui-position^=above]::after, :where([oui-tooltip-content])[oui-position^=below]::after, :where([oui-tooltip-content])[oui-position^=bottom]::after, :where([oui-tooltip-content])[oui-position^=top]::after {
|
|
63
67
|
width: 100%;
|
|
64
|
-
height:
|
|
68
|
+
height: 1em;
|
|
65
69
|
}
|
|
66
70
|
:where([oui-tooltip-content])[oui-position^=above]::after, :where([oui-tooltip-content])[oui-position^=top]::after {
|
|
67
|
-
inset: 100% 0 0;
|
|
71
|
+
inset: calc(100% - 0.5em) 0 0;
|
|
68
72
|
}
|
|
69
73
|
:where([oui-tooltip-content])[oui-position^=below]::after, :where([oui-tooltip-content])[oui-position^=bottom]::after {
|
|
70
74
|
inset: -0.5em 0 0;
|
|
71
75
|
}
|
|
72
76
|
:where([oui-tooltip-content])[oui-position^=end]::after, :where([oui-tooltip-content])[oui-position^=left]::after, :where([oui-tooltip-content])[oui-position^=right]::after, :where([oui-tooltip-content])[oui-position^=start]::after {
|
|
73
|
-
width:
|
|
77
|
+
width: 1em;
|
|
74
78
|
height: 100%;
|
|
75
79
|
}
|
|
76
80
|
:where([oui-tooltip-content])[oui-position^=end]::after, :where([oui-tooltip-content])[oui-position^=right]::after {
|
|
77
81
|
inset: 0 0 0 -0.5em;
|
|
78
82
|
}
|
|
79
83
|
:where([oui-tooltip-content])[oui-position^=left]::after, :where([oui-tooltip-content])[oui-position^=start]::after {
|
|
80
|
-
inset: 0 0 0 100
|
|
84
|
+
inset: 0 0 0 calc(100% - 0.5em);
|
|
81
85
|
}
|
|
82
86
|
|
|
83
87
|
:where([oui-tooltip-content][oui-tooltip-content-active]) {
|
|
84
88
|
opacity: 1;
|
|
85
|
-
pointer-events:
|
|
89
|
+
pointer-events: all;
|
|
86
90
|
}
|
|
87
91
|
|
|
88
92
|
|
|
@@ -18,9 +18,9 @@ type Options = {
|
|
|
18
18
|
noescape: boolean;
|
|
19
19
|
};
|
|
20
20
|
declare function createFocusTrap(element: HTMLElement, options?: Options): FocusTrap;
|
|
21
|
+
declare function removeFocusTrap(element: HTMLElement): void;
|
|
21
22
|
declare const FOCUS_TRAP_SELECTOR = "oui-focus-trap";
|
|
22
23
|
declare const FOCUS_TRAP_CONTAIN = "oui-focus-trap-contain";
|
|
23
24
|
declare const FOCUS_TRAP_NOESCAPE = "oui-focus-trap-noescape";
|
|
24
|
-
declare const FOCUSTRAPS_ALL: WeakMap<HTMLElement, FocusTrap>;
|
|
25
25
|
//#endregion
|
|
26
|
-
export {
|
|
26
|
+
export { FOCUS_TRAP_CONTAIN, FOCUS_TRAP_NOESCAPE, FOCUS_TRAP_SELECTOR, FocusTrap, createFocusTrap, removeFocusTrap };
|
|
@@ -96,6 +96,10 @@ function onTab(event) {
|
|
|
96
96
|
if (index === -1 || elements.length === 0) tabToTrap(focusTrap, elements, element);
|
|
97
97
|
else tabToElement(focusTrap, elements, index, event.shiftKey ? -1 : 1);
|
|
98
98
|
}
|
|
99
|
+
function removeFocusTrap(element) {
|
|
100
|
+
FOCUSTRAPS_ALL.get(element)?.destroy();
|
|
101
|
+
FOCUSTRAPS_ALL.delete(element);
|
|
102
|
+
}
|
|
99
103
|
function setConnected(focusTrap, value) {
|
|
100
104
|
if (!focusTrap.embedded || focusTrap.connected === value) return;
|
|
101
105
|
focusTrap.connected = value;
|
|
@@ -149,4 +153,4 @@ on(document, "keydown", onKeydown, EVENT_OPTIONS);
|
|
|
149
153
|
on(document, "mousedown", onPointerdown, EVENT_OPTIONS);
|
|
150
154
|
on(document, "touchstart", onPointerdown, EVENT_OPTIONS);
|
|
151
155
|
//#endregion
|
|
152
|
-
export {
|
|
156
|
+
export { FOCUS_TRAP_CONTAIN, FOCUS_TRAP_NOESCAPE, FOCUS_TRAP_SELECTOR, FocusTrap, createFocusTrap, removeFocusTrap };
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { attributable } from "../internal/attributable.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { FOCUS_TRAP_SELECTOR, createFocusTrap, removeFocusTrap } from "./embedded.mjs";
|
|
3
3
|
//#region src/js/focus-trap/standalone.ts
|
|
4
|
-
|
|
5
|
-
FOCUSTRAPS_ALL.get(element)?.destroy();
|
|
6
|
-
FOCUSTRAPS_ALL.delete(element);
|
|
7
|
-
}
|
|
8
|
-
attributable(FOCUS_TRAP_SELECTOR, createFocusTrap, removeFocusTraps);
|
|
4
|
+
attributable(FOCUS_TRAP_SELECTOR, createFocusTrap, removeFocusTrap);
|
|
9
5
|
//#endregion
|
|
10
6
|
export {};
|
package/dist/js/index.d.mts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { OuiPopoverElement } from "./popover.mjs";
|
|
2
1
|
import { OuiSplitterElement } from "./splitter.mjs";
|
|
3
2
|
import { setTooltipDelay } from "./tooltip.mjs";
|
|
4
|
-
export {
|
|
3
|
+
export { OuiSplitterElement, setTooltipDelay };
|
package/dist/js/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "./focus-trap/standalone.mjs";
|
|
2
2
|
import "./movable.mjs";
|
|
3
|
-
import
|
|
3
|
+
import "./popover.mjs";
|
|
4
4
|
import "./sortable.mjs";
|
|
5
5
|
import { OuiSplitterElement } from "./splitter.mjs";
|
|
6
6
|
import { setTooltipDelay } from "./tooltip.mjs";
|
|
7
|
-
export {
|
|
7
|
+
export { OuiSplitterElement, setTooltipDelay };
|
|
@@ -1,26 +1,18 @@
|
|
|
1
1
|
//#region src/js/internal/floatable.d.ts
|
|
2
2
|
declare class Floatable {
|
|
3
|
-
readonly options: Options;
|
|
4
|
-
active: boolean;
|
|
5
|
-
disabled: boolean;
|
|
6
|
-
frame: DOMHighResTimeStamp | undefined;
|
|
7
|
-
ignoreFocus: boolean;
|
|
8
|
-
constructor(options: Options);
|
|
9
|
-
destroy(): void;
|
|
10
|
-
disable(): void;
|
|
11
|
-
enable(): void;
|
|
12
|
-
toggle(active: boolean, ignoreFocus?: boolean): void;
|
|
13
|
-
}
|
|
14
|
-
type Options = {
|
|
15
3
|
anchor: HTMLElement;
|
|
16
4
|
content: HTMLElement;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
5
|
+
options: FloatableOptions;
|
|
6
|
+
constructor(anchor: HTMLElement, content: HTMLElement, options: FloatableOptions);
|
|
7
|
+
destroy(): void;
|
|
8
|
+
update(): void;
|
|
9
|
+
}
|
|
10
|
+
type FloatableOptions = {
|
|
11
|
+
attribute: string;
|
|
12
|
+
position: FloatablePosition;
|
|
22
13
|
};
|
|
23
|
-
type
|
|
24
|
-
declare function
|
|
14
|
+
type FloatablePosition = 'above' | 'above-end' | 'above-start' | 'below' | 'below-end' | 'below-start' | 'end' | 'end-bottom' | 'end-top' | 'start' | 'start-bottom' | 'start-top';
|
|
15
|
+
declare function createFloatable(anchor: HTMLElement | null, content: HTMLElement, options: FloatableOptions): Floatable | undefined;
|
|
16
|
+
declare function removeFloatable(content: HTMLElement): void;
|
|
25
17
|
//#endregion
|
|
26
|
-
export { Floatable,
|
|
18
|
+
export { Floatable, FloatableOptions, FloatablePosition, createFloatable, removeFloatable };
|
|
@@ -1,149 +1,49 @@
|
|
|
1
|
-
import { on } from "@oscarpalmer/toretto/event";
|
|
2
|
-
import { findAncestor } from "@oscarpalmer/toretto/find";
|
|
3
1
|
//#region src/js/internal/floatable.ts
|
|
4
2
|
var Floatable = class {
|
|
3
|
+
anchor;
|
|
4
|
+
content;
|
|
5
5
|
options;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
ignoreFocus = false;
|
|
10
|
-
constructor(options) {
|
|
6
|
+
constructor(anchor, content, options) {
|
|
7
|
+
this.anchor = anchor;
|
|
8
|
+
this.content = content;
|
|
11
9
|
this.options = options;
|
|
12
|
-
|
|
10
|
+
const anchorName = getAnchorName(anchor);
|
|
11
|
+
anchor.style.anchorName = anchorName;
|
|
12
|
+
content.style.positionAnchor = anchorName;
|
|
13
13
|
}
|
|
14
14
|
destroy() {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
state?.active.delete(this);
|
|
18
|
-
state?.mapped.delete(this.options.anchor);
|
|
19
|
-
state?.mapped.delete(this.options.content);
|
|
20
|
-
this.options.anchor = void 0;
|
|
21
|
-
this.options.content = void 0;
|
|
15
|
+
this.anchor = null;
|
|
16
|
+
this.content = null;
|
|
22
17
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
this.disabled = true;
|
|
26
|
-
stop(this);
|
|
27
|
-
getState()?.active.delete(this);
|
|
28
|
-
}
|
|
29
|
-
enable() {
|
|
30
|
-
if (!this.disabled) return;
|
|
31
|
-
this.disabled = false;
|
|
32
|
-
initialize(this);
|
|
33
|
-
}
|
|
34
|
-
toggle(active, ignoreFocus) {
|
|
35
|
-
if (this.disabled || this.active === active) return;
|
|
36
|
-
const state = getState();
|
|
37
|
-
if (state == null) return;
|
|
38
|
-
this.ignoreFocus = !active && (ignoreFocus ?? false);
|
|
39
|
-
stop(this);
|
|
40
|
-
if (active) state.active.add(this);
|
|
41
|
-
else state.active.delete(this);
|
|
42
|
-
if (this.options.interactive) if (active) state.order.push(this);
|
|
43
|
-
else {
|
|
44
|
-
const index = state.order.indexOf(this);
|
|
45
|
-
if (index > -1) state.order.splice(index, 1);
|
|
46
|
-
}
|
|
47
|
-
if (active) activate(this);
|
|
48
|
-
else deactivate(this);
|
|
18
|
+
update() {
|
|
19
|
+
setPosition(this);
|
|
49
20
|
}
|
|
50
21
|
};
|
|
51
|
-
function
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
floatable
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
function closeAbove(element) {
|
|
58
|
-
const state = getState();
|
|
59
|
-
if (state == null) return;
|
|
60
|
-
const index = state.order.findIndex((floatable) => floatable.options.anchor === element || floatable.options.content === element);
|
|
61
|
-
if (index === -1 || index === state.order.length - 1) return;
|
|
62
|
-
while (index < state.order.length - 1) state.order.pop()?.toggle(false, true);
|
|
63
|
-
}
|
|
64
|
-
function closeAll() {
|
|
65
|
-
const state = getState();
|
|
66
|
-
const floatables = [...state?.active ?? []];
|
|
67
|
-
state?.active.clear();
|
|
68
|
-
for (const floatable of floatables) floatable.toggle(false, true);
|
|
69
|
-
}
|
|
70
|
-
function closeNonInteractive(state) {
|
|
71
|
-
for (const floatable of state.active) if (!floatable.options.interactive) floatable.toggle(false);
|
|
72
|
-
}
|
|
73
|
-
function deactivate(floatable) {
|
|
74
|
-
floatable.active = false;
|
|
75
|
-
if (!floatable.options.reusable) {
|
|
76
|
-
floatable.options.content.hidden = true;
|
|
77
|
-
floatable.options.anchor.insertAdjacentElement(INSERT_AFTEREND, floatable.options.content);
|
|
22
|
+
function createFloatable(anchor, content, options) {
|
|
23
|
+
if (anchor == null) return;
|
|
24
|
+
let floatable = instances.get(content);
|
|
25
|
+
if (floatable == null) {
|
|
26
|
+
floatable = new Floatable(anchor, content, options);
|
|
27
|
+
instances.set(content, floatable);
|
|
78
28
|
}
|
|
79
|
-
floatable
|
|
29
|
+
return floatable;
|
|
80
30
|
}
|
|
81
|
-
function getAnchorName() {
|
|
31
|
+
function getAnchorName(anchor) {
|
|
32
|
+
let { anchorName } = anchor.style;
|
|
33
|
+
if (anchorName.length > 0) return anchorName;
|
|
82
34
|
index += 1;
|
|
83
35
|
return `--oui-floatable-anchor-${index}`;
|
|
84
36
|
}
|
|
85
|
-
function
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
function initialize(floatable) {
|
|
89
|
-
const { anchor, content, interactive } = floatable.options;
|
|
90
|
-
if (interactive) {
|
|
91
|
-
anchor.setAttribute(ATTRIBUTE_ANCHOR, "");
|
|
92
|
-
content.setAttribute(ATTRIBUTE_CONTENT, "");
|
|
93
|
-
}
|
|
94
|
-
let anchorName = anchor.style.anchorName;
|
|
95
|
-
if (anchorName.length === 0) anchorName = getAnchorName();
|
|
96
|
-
anchor.style.anchorName = anchorName;
|
|
97
|
-
content.style.position = "absolute";
|
|
98
|
-
content.style.positionAnchor = anchorName;
|
|
99
|
-
content.style.positionTry = "normal flip-start";
|
|
100
|
-
const state = getState();
|
|
101
|
-
state?.mapped.set(anchor, floatable);
|
|
102
|
-
state?.mapped.set(content, floatable);
|
|
103
|
-
}
|
|
104
|
-
function isDisabled(element) {
|
|
105
|
-
return element.disabled || element.readOnly || element.getAttribute("aria-disabled") === "true";
|
|
106
|
-
}
|
|
107
|
-
function onClick(event) {
|
|
108
|
-
const related = findAncestor(event, SELECTOR_ALL);
|
|
109
|
-
if (!(related instanceof HTMLElement)) closeAll();
|
|
110
|
-
else if (related.hasAttribute(ATTRIBUTE_CONTENT)) closeAbove(related);
|
|
111
|
-
else if (!isDisabled(related)) toggle(related);
|
|
112
|
-
}
|
|
113
|
-
function onKeyDown(event) {
|
|
114
|
-
if (event.key !== "Escape") return;
|
|
115
|
-
const state = getState();
|
|
116
|
-
if (state == null || state.active.size === 0) return;
|
|
117
|
-
closeNonInteractive(state);
|
|
118
|
-
const related = findAncestor(event, SELECTOR_CONTENT);
|
|
119
|
-
if (!(related instanceof HTMLElement)) return;
|
|
120
|
-
closeAbove(related);
|
|
121
|
-
const floatable = state.mapped.get(related);
|
|
122
|
-
if (floatable != null) floatable.toggle(false);
|
|
37
|
+
function removeFloatable(content) {
|
|
38
|
+
instances.get(content)?.destroy();
|
|
39
|
+
instances.delete(content);
|
|
123
40
|
}
|
|
124
41
|
function setPosition(floatable) {
|
|
125
|
-
let position = floatable.
|
|
126
|
-
if (AREAS[position] == null) position = floatable.options.
|
|
42
|
+
let position = floatable.anchor.getAttribute(floatable.options.attribute) ?? floatable.options.position;
|
|
43
|
+
if (AREAS[position] == null) position = floatable.options.position;
|
|
127
44
|
const area = AREAS[position];
|
|
128
|
-
floatable.
|
|
129
|
-
floatable.
|
|
130
|
-
floatable.options.onAfter?.(true);
|
|
131
|
-
}
|
|
132
|
-
function stop(floatable) {
|
|
133
|
-
if (floatable.frame != null) cancelAnimationFrame(floatable.frame);
|
|
134
|
-
floatable.frame = void 0;
|
|
135
|
-
}
|
|
136
|
-
function toggle(anchor) {
|
|
137
|
-
const floatable = getState()?.mapped.get(anchor);
|
|
138
|
-
if (floatable == null) {
|
|
139
|
-
closeAll();
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
const active = Boolean(floatable.active);
|
|
143
|
-
const content = findAncestor(floatable.options.anchor, SELECTOR_CONTENT);
|
|
144
|
-
if (content == null) closeAll();
|
|
145
|
-
else closeAbove(content);
|
|
146
|
-
floatable.toggle(!active);
|
|
45
|
+
floatable.content.style.positionArea = area;
|
|
46
|
+
floatable.content.setAttribute(ATTRIBUTE, POSITIONS[area]);
|
|
147
47
|
}
|
|
148
48
|
const AREAS = {
|
|
149
49
|
above: "block-start",
|
|
@@ -159,30 +59,9 @@ const AREAS = {
|
|
|
159
59
|
"start-bottom": "span-start start",
|
|
160
60
|
"start-top": "span-end start"
|
|
161
61
|
};
|
|
162
|
-
const
|
|
163
|
-
const ATTRIBUTE_CONTENT = "oui-floatable-content";
|
|
164
|
-
const ATTRIBUTE_POSITION = "oui-position";
|
|
165
|
-
const INSERT_AFTEREND = "afterend";
|
|
62
|
+
const ATTRIBUTE = "oui-position";
|
|
166
63
|
const POSITIONS = Object.fromEntries(Object.entries(AREAS).map(([position, area]) => [area, position]));
|
|
167
|
-
const
|
|
168
|
-
const SELECTOR_CONTENT = `[${ATTRIBUTE_CONTENT}]`;
|
|
64
|
+
const instances = /* @__PURE__ */ new WeakMap();
|
|
169
65
|
let index = 0;
|
|
170
|
-
if (window._oscarpalmer_oui_floatable == null) {
|
|
171
|
-
Object.defineProperty(window, "_oscarpalmer_oui_floatable", {
|
|
172
|
-
enumerable: false,
|
|
173
|
-
value: {
|
|
174
|
-
active: /* @__PURE__ */ new Set(),
|
|
175
|
-
mapped: /* @__PURE__ */ new Map(),
|
|
176
|
-
order: []
|
|
177
|
-
},
|
|
178
|
-
writable: false
|
|
179
|
-
});
|
|
180
|
-
on(document, "keydown", (event) => {
|
|
181
|
-
onKeyDown(event);
|
|
182
|
-
});
|
|
183
|
-
on(document, "click", (event) => {
|
|
184
|
-
onClick(event);
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
66
|
//#endregion
|
|
188
|
-
export { Floatable,
|
|
67
|
+
export { Floatable, createFloatable, removeFloatable };
|
package/dist/js/popover.d.mts
CHANGED
|
@@ -1,20 +1 @@
|
|
|
1
|
-
|
|
2
|
-
declare global {
|
|
3
|
-
interface HTMLElementTagNameMap {
|
|
4
|
-
'oui-popover': OuiPopoverElement;
|
|
5
|
-
}
|
|
6
|
-
}
|
|
7
|
-
declare class OuiPopoverElement extends HTMLElement {
|
|
8
|
-
#private;
|
|
9
|
-
constructor();
|
|
10
|
-
close(): void;
|
|
11
|
-
connectedCallback(): void;
|
|
12
|
-
disconnectedCallback(): void;
|
|
13
|
-
hidePopover(): void;
|
|
14
|
-
open(): void;
|
|
15
|
-
showPopover(): void;
|
|
16
|
-
toggle(): void;
|
|
17
|
-
togglePopover(options?: boolean): boolean;
|
|
18
|
-
}
|
|
19
|
-
//#endregion
|
|
20
|
-
export { OuiPopoverElement };
|
|
1
|
+
export { };
|
package/dist/js/popover.mjs
CHANGED
|
@@ -1,89 +1,60 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { attributable } from "./internal/attributable.mjs";
|
|
2
|
+
import { createFocusTrap, removeFocusTrap } from "./focus-trap/embedded.mjs";
|
|
3
|
+
import { createFloatable, removeFloatable } from "./internal/floatable.mjs";
|
|
4
|
+
import { on } from "@oscarpalmer/toretto/event";
|
|
5
5
|
//#region src/js/popover.ts
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
content,
|
|
24
|
-
anchor: toggle,
|
|
25
|
-
defaultPosition: "below-start",
|
|
26
|
-
interactive: true,
|
|
27
|
-
positionAttribute: "position",
|
|
28
|
-
reusable: false,
|
|
29
|
-
onAfter: (active) => {
|
|
30
|
-
if (active) focus(content);
|
|
31
|
-
else if (!this.#floatable.ignoreFocus) toggle.focus();
|
|
32
|
-
}
|
|
6
|
+
var Popover = class {
|
|
7
|
+
element;
|
|
8
|
+
anchor;
|
|
9
|
+
floatable;
|
|
10
|
+
focusTrap;
|
|
11
|
+
listener;
|
|
12
|
+
constructor(element) {
|
|
13
|
+
this.element = element;
|
|
14
|
+
this.anchor = element.ownerDocument.querySelector(`[popovertarget="${element.id}"]`);
|
|
15
|
+
this.floatable = createFloatable(this.anchor, element, options);
|
|
16
|
+
this.focusTrap = createFocusTrap(element, { noescape: true });
|
|
17
|
+
this.listener = on(element, EVENT_TOGGLE, (event) => {
|
|
18
|
+
if (event.newState === STATE_OPEN) {
|
|
19
|
+
ignoreFocus = false;
|
|
20
|
+
this.floatable?.update();
|
|
21
|
+
element.focus();
|
|
22
|
+
} else if (!ignoreFocus) this.anchor?.focus();
|
|
33
23
|
});
|
|
34
|
-
this
|
|
35
|
-
|
|
36
|
-
POPOVERS.set(content, this.#floatable);
|
|
24
|
+
this.element.setAttribute(ATTRIBUTE_CONTENT, "");
|
|
25
|
+
this.floatable?.update();
|
|
37
26
|
}
|
|
38
|
-
|
|
39
|
-
this.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
this
|
|
43
|
-
this
|
|
44
|
-
|
|
45
|
-
disconnectedCallback() {
|
|
46
|
-
this.#floatable.disable();
|
|
47
|
-
this.#focusTrap.disconnect();
|
|
48
|
-
}
|
|
49
|
-
hidePopover() {
|
|
50
|
-
if (this.#floatable.active && this.isConnected) this.#floatable.toggle(false);
|
|
51
|
-
}
|
|
52
|
-
open() {
|
|
53
|
-
this.showPopover();
|
|
54
|
-
}
|
|
55
|
-
showPopover() {
|
|
56
|
-
if (!this.#floatable.active && this.isConnected) this.#floatable.toggle(true);
|
|
57
|
-
}
|
|
58
|
-
toggle() {
|
|
59
|
-
this.togglePopover();
|
|
60
|
-
}
|
|
61
|
-
togglePopover(options) {
|
|
62
|
-
if (typeof options === "boolean") {
|
|
63
|
-
if (options === true) this.showPopover();
|
|
64
|
-
else this.hidePopover();
|
|
65
|
-
return options;
|
|
66
|
-
}
|
|
67
|
-
if (this.#floatable.active) {
|
|
68
|
-
this.hidePopover();
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
this.showPopover();
|
|
72
|
-
return true;
|
|
27
|
+
destroy() {
|
|
28
|
+
this.focusTrap?.destroy();
|
|
29
|
+
removeFloatable(this.element);
|
|
30
|
+
removeFocusTrap(this.element);
|
|
31
|
+
this.element.removeAttribute(ATTRIBUTE_CONTENT);
|
|
32
|
+
this.anchor = null;
|
|
33
|
+
this.element = null;
|
|
73
34
|
}
|
|
74
35
|
};
|
|
75
|
-
function
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
});
|
|
36
|
+
function onAdd(element) {
|
|
37
|
+
if (!instances.has(element) && element.getAttribute(ATTRIBUTE) !== POPOVER_HINT) instances.set(element, new Popover(element));
|
|
38
|
+
}
|
|
39
|
+
function onPointerdown() {
|
|
40
|
+
ignoreFocus = true;
|
|
81
41
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
|
|
42
|
+
function onRemove(element) {
|
|
43
|
+
instances.get(element)?.destroy();
|
|
44
|
+
instances.delete(element);
|
|
45
|
+
}
|
|
46
|
+
const ATTRIBUTE = "popover";
|
|
47
|
+
const ATTRIBUTE_CONTENT = "oui-popover-content";
|
|
48
|
+
const EVENT_TOGGLE = "toggle";
|
|
49
|
+
const POPOVER_HINT = "hint";
|
|
50
|
+
const STATE_OPEN = "open";
|
|
51
|
+
const instances = /* @__PURE__ */ new WeakMap();
|
|
52
|
+
const options = {
|
|
53
|
+
attribute: "position",
|
|
54
|
+
position: "below-start"
|
|
55
|
+
};
|
|
56
|
+
let ignoreFocus = false;
|
|
57
|
+
on(document, "pointerdown", onPointerdown, { capture: true });
|
|
58
|
+
attributable(ATTRIBUTE, onAdd, onRemove);
|
|
88
59
|
//#endregion
|
|
89
|
-
export {
|
|
60
|
+
export {};
|
package/dist/js/tooltip.d.mts
CHANGED