@oscarpalmer/oui 0.23.1 → 0.25.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/{tooltip.css → floatable.css} +59 -24
- package/dist/css/reset.css +17 -0
- package/dist/js/dialog.d.mts +38 -0
- package/dist/js/dialog.mjs +92 -0
- package/dist/js/embedded-84gxpReS.d.mts +64 -0
- package/dist/js/embedded-BpwzMSEF.d.mts +26 -0
- package/dist/js/floatable/embedded.d.mts +2 -0
- package/dist/js/floatable/embedded.mjs +146 -0
- package/dist/js/floatable/standalone.d.mts +2 -0
- package/dist/js/floatable/standalone.mjs +2 -0
- package/dist/js/focus-trap/embedded.d.mts +1 -25
- package/dist/js/focus-trap/embedded.mjs +1 -1
- package/dist/js/index.d.mts +5 -2
- package/dist/js/index.mjs +7 -4
- package/dist/js/internal/attributable.mjs +4 -3
- package/dist/js/internal/draggable.mjs +1 -1
- package/dist/js/popover.d.mts +38 -1
- package/dist/js/popover.mjs +81 -38
- package/dist/js/sortable.mjs +7 -5
- package/dist/js/splitter.mjs +18 -14
- package/dist/js/tooltip.d.mts +33 -1
- package/dist/js/tooltip.mjs +91 -48
- package/package.json +2 -2
- package/src/css/{tooltip.scss → floatable.scss} +47 -5
- package/src/css/mixins.scss +0 -2
- package/src/css/reset.scss +17 -0
- package/src/js/dialog.ts +188 -0
- package/src/js/floatable/embedded.ts +302 -0
- package/src/js/floatable/standalone.ts +1 -0
- package/src/js/index.ts +4 -2
- package/src/js/internal/attributable.ts +5 -3
- package/src/js/popover.ts +146 -48
- package/src/js/sortable.ts +8 -5
- package/src/js/splitter.ts +26 -9
- package/src/js/tooltip.ts +138 -51
- package/dist/css/popover.css +0 -30
- package/dist/js/internal/floatable.d.mts +0 -18
- package/dist/js/internal/floatable.mjs +0 -67
- package/src/css/popover.scss +0 -10
- package/src/js/internal/floatable.ts +0 -118
|
@@ -1,4 +1,62 @@
|
|
|
1
1
|
|
|
2
|
+
:where([oui-dialog], [oui-popover], [oui-tooltip-content]),
|
|
3
|
+
:where([oui-dialog])::backdrop {
|
|
4
|
+
opacity: 0;
|
|
5
|
+
transition: 0.125s ease-in-out;
|
|
6
|
+
transition-property: opacity, scale;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
:where([oui-dialog], [oui-popover], [oui-tooltip-content]) {
|
|
10
|
+
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);
|
|
11
|
+
background-color: var(--oui-absolute);
|
|
12
|
+
scale: 0.9;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
:where([oui-dialog]:focus, [oui-popover]:focus, [oui-tooltip-content]:focus) {
|
|
16
|
+
outline: none;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
:where([oui-dialog][oui-dialog-open],
|
|
20
|
+
[oui-popover][oui-popover-open],
|
|
21
|
+
[oui-tooltip-content][oui-tooltip-content-open]),
|
|
22
|
+
:where([oui-dialog][oui-dialog-open])::backdrop {
|
|
23
|
+
opacity: 1;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
:where([oui-dialog][oui-dialog-open],
|
|
27
|
+
[oui-popover][oui-popover-open],
|
|
28
|
+
[oui-tooltip-content][oui-tooltip-content-open]) {
|
|
29
|
+
scale: 1;
|
|
30
|
+
transition-delay: 0.125s;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
:where([oui-popover], [oui-tooltip-content]) {
|
|
34
|
+
--margin-bottom: 0.5em;
|
|
35
|
+
--margin-left: 0.5em;
|
|
36
|
+
--margin-right: 0.5em;
|
|
37
|
+
--margin-top: 0.5em;
|
|
38
|
+
inset-block: var(--margin-top) var(--margin-bottom);
|
|
39
|
+
inset-inline: var(--margin-left) var(--margin-right);
|
|
40
|
+
}
|
|
41
|
+
:where([oui-popover], [oui-tooltip-content])[oui-position$=bottom] {
|
|
42
|
+
--margin-bottom: 0;
|
|
43
|
+
}
|
|
44
|
+
:where([oui-popover], [oui-tooltip-content])[oui-position$=end] {
|
|
45
|
+
--margin-right: 0;
|
|
46
|
+
}
|
|
47
|
+
:where([oui-popover], [oui-tooltip-content])[oui-position$=start] {
|
|
48
|
+
--margin-left: 0;
|
|
49
|
+
}
|
|
50
|
+
:where([oui-popover], [oui-tooltip-content])[oui-position$=top] {
|
|
51
|
+
--margin-top: 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
:where([oui-popover]) {
|
|
55
|
+
padding: 1rem;
|
|
56
|
+
background-color: var(--oui-absolute);
|
|
57
|
+
border-radius: 0.25rem;
|
|
58
|
+
}
|
|
59
|
+
|
|
2
60
|
:where([oui-tooltip]:is(abbr,
|
|
3
61
|
b,
|
|
4
62
|
cite,
|
|
@@ -25,27 +83,6 @@ var)) {
|
|
|
25
83
|
cursor: help;
|
|
26
84
|
}
|
|
27
85
|
|
|
28
|
-
:where([oui-tooltip-content]) {
|
|
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-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);
|
|
36
|
-
}
|
|
37
|
-
:where([oui-tooltip-content])[oui-position$=bottom] {
|
|
38
|
-
--margin-bottom: 0;
|
|
39
|
-
}
|
|
40
|
-
:where([oui-tooltip-content])[oui-position$=end] {
|
|
41
|
-
--margin-right: 0;
|
|
42
|
-
}
|
|
43
|
-
:where([oui-tooltip-content])[oui-position$=start] {
|
|
44
|
-
--margin-left: 0;
|
|
45
|
-
}
|
|
46
|
-
:where([oui-tooltip-content])[oui-position$=top] {
|
|
47
|
-
--margin-top: 0;
|
|
48
|
-
}
|
|
49
86
|
:where([oui-tooltip-content]) {
|
|
50
87
|
max-width: 48ch;
|
|
51
88
|
padding: 0.75em 1em;
|
|
@@ -55,8 +92,6 @@ var)) {
|
|
|
55
92
|
border-radius: 0.25rem;
|
|
56
93
|
font-size: 0.875rem;
|
|
57
94
|
pointer-events: none;
|
|
58
|
-
transition: opacity 0.125s ease-in-out 0s;
|
|
59
|
-
transition-behavior: allow-discrete;
|
|
60
95
|
}
|
|
61
96
|
:where([oui-tooltip-content])::after {
|
|
62
97
|
content: "";
|
|
@@ -84,7 +119,7 @@ var)) {
|
|
|
84
119
|
inset: 0 0 0 calc(100% - 0.5em);
|
|
85
120
|
}
|
|
86
121
|
|
|
87
|
-
:where([oui-tooltip-content][oui-tooltip-content-
|
|
122
|
+
:where([oui-tooltip-content][oui-tooltip-content-open]) {
|
|
88
123
|
opacity: 1;
|
|
89
124
|
pointer-events: all;
|
|
90
125
|
}
|
package/dist/css/reset.css
CHANGED
|
@@ -124,6 +124,23 @@ summary) {
|
|
|
124
124
|
display: list-item;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
:where(dialog) {
|
|
128
|
+
display: none !important;
|
|
129
|
+
overscroll-behavior: contain;
|
|
130
|
+
border: none;
|
|
131
|
+
color: currentcolor;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
:where([oui-dialog][aria-modal=true i]) {
|
|
135
|
+
position: fixed;
|
|
136
|
+
inset: 50% auto auto 50%;
|
|
137
|
+
transform: translate3d(-50%, -50%, 0);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
:where(dialog[open]) {
|
|
141
|
+
display: inherit !important;
|
|
142
|
+
}
|
|
143
|
+
|
|
127
144
|
:where(dl, ol, ul) :where(dl, ol, ul) {
|
|
128
145
|
/** Remove the margin on nested lists in Chrome, Edge, and Safari [SE] */
|
|
129
146
|
margin: 0;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { RemovableEventListener } from "@oscarpalmer/toretto/models";
|
|
2
|
+
|
|
3
|
+
//#region src/js/dialog.d.ts
|
|
4
|
+
declare class OuiDialog {
|
|
5
|
+
#private;
|
|
6
|
+
/**
|
|
7
|
+
* Is the dialog open?
|
|
8
|
+
*/
|
|
9
|
+
get open(): boolean;
|
|
10
|
+
constructor(state: OuiDialogState);
|
|
11
|
+
/**
|
|
12
|
+
* Closes the dialog by request
|
|
13
|
+
*/
|
|
14
|
+
hide(request: true, value?: string): void;
|
|
15
|
+
/**
|
|
16
|
+
* Closes the dialog
|
|
17
|
+
*/
|
|
18
|
+
hide(value?: string): void;
|
|
19
|
+
/**
|
|
20
|
+
* Opens the dialog
|
|
21
|
+
*/
|
|
22
|
+
show(modal?: boolean): void;
|
|
23
|
+
}
|
|
24
|
+
type OuiDialogState = {
|
|
25
|
+
dialog: OuiDialog;
|
|
26
|
+
element: HTMLDialogElement;
|
|
27
|
+
listeners: RemovableEventListener[];
|
|
28
|
+
modal: boolean;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Get the _OuiDialog_ for an element
|
|
32
|
+
*
|
|
33
|
+
* @param element Element to get _OuiDialog_ for
|
|
34
|
+
* @returns _OuiDialog_ instance
|
|
35
|
+
*/
|
|
36
|
+
declare function getDialog(element: HTMLDialogElement): OuiDialog | undefined;
|
|
37
|
+
//#endregion
|
|
38
|
+
export { type OuiDialog, getDialog };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { getOnBeforeToggleListener } from "./floatable/embedded.mjs";
|
|
2
|
+
import { attributable } from "./internal/attributable.mjs";
|
|
3
|
+
import { on } from "@oscarpalmer/toretto/event";
|
|
4
|
+
//#region src/js/dialog.ts
|
|
5
|
+
var OuiDialog = class {
|
|
6
|
+
#state;
|
|
7
|
+
/**
|
|
8
|
+
* Is the dialog open?
|
|
9
|
+
*/
|
|
10
|
+
get open() {
|
|
11
|
+
return this.#state.element.open;
|
|
12
|
+
}
|
|
13
|
+
constructor(state) {
|
|
14
|
+
this.#state = state;
|
|
15
|
+
}
|
|
16
|
+
hide(first, second) {
|
|
17
|
+
if (!this.#state.element.open) return;
|
|
18
|
+
if (first === true) this.#state.element.requestClose(typeof second === "string" ? second : void 0);
|
|
19
|
+
else this.#state.element.close(typeof first === "string" ? first : void 0);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Opens the dialog
|
|
23
|
+
*/
|
|
24
|
+
show(modal) {
|
|
25
|
+
const { element } = this.#state;
|
|
26
|
+
if (element == null || element.open) return;
|
|
27
|
+
const isModal = modal !== false;
|
|
28
|
+
element.setAttribute(ARIA_MODAL, String(isModal));
|
|
29
|
+
if (isModal) element.showModal();
|
|
30
|
+
else element.show();
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
function addDialog(element) {
|
|
34
|
+
if (!(element instanceof HTMLDialogElement)) throw new TypeError(MESSAGE);
|
|
35
|
+
if (!states.has(element)) states.set(element, getState(element));
|
|
36
|
+
}
|
|
37
|
+
function destroyDialog(state) {
|
|
38
|
+
state.element.close();
|
|
39
|
+
state.element.setAttribute(ARIA_MODAL, String(state.modal));
|
|
40
|
+
state.element.removeAttribute(ATTRIBUTE_OPEN);
|
|
41
|
+
for (const listener of state.listeners) listener();
|
|
42
|
+
state.dialog = void 0;
|
|
43
|
+
state.element = void 0;
|
|
44
|
+
state.listeners = void 0;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get the _OuiDialog_ for an element
|
|
48
|
+
*
|
|
49
|
+
* @param element Element to get _OuiDialog_ for
|
|
50
|
+
* @returns _OuiDialog_ instance
|
|
51
|
+
*/
|
|
52
|
+
function getDialog(element) {
|
|
53
|
+
return states.get(element)?.dialog;
|
|
54
|
+
}
|
|
55
|
+
function getState(element) {
|
|
56
|
+
const state = {
|
|
57
|
+
element,
|
|
58
|
+
dialog: void 0,
|
|
59
|
+
listeners: [getOnBeforeToggleListener(element), on(element, EVENT_TOGGLE, (event) => {
|
|
60
|
+
const { source } = event;
|
|
61
|
+
if (element.open) {
|
|
62
|
+
const modal = source instanceof HTMLButtonElement && source.command === COMMAND_SHOW_MODAL || element.matches(SELECTOR_MODAL);
|
|
63
|
+
element.setAttribute(ARIA_MODAL, String(modal));
|
|
64
|
+
element.setAttribute(ATTRIBUTE_OPEN, "");
|
|
65
|
+
} else {
|
|
66
|
+
element.removeAttribute(ATTRIBUTE_OPEN);
|
|
67
|
+
element.setAttribute(ARIA_MODAL, String(state.modal));
|
|
68
|
+
}
|
|
69
|
+
})],
|
|
70
|
+
modal: element.getAttribute(ARIA_MODAL) === TRUE
|
|
71
|
+
};
|
|
72
|
+
state.dialog = new OuiDialog(state);
|
|
73
|
+
return state;
|
|
74
|
+
}
|
|
75
|
+
function removeDialog(element) {
|
|
76
|
+
const state = states.get(element);
|
|
77
|
+
if (state == null) return;
|
|
78
|
+
destroyDialog(state);
|
|
79
|
+
states.delete(element);
|
|
80
|
+
}
|
|
81
|
+
const ARIA_MODAL = "aria-modal";
|
|
82
|
+
const ATTRIBUTE = "oui-dialog";
|
|
83
|
+
const ATTRIBUTE_OPEN = `${ATTRIBUTE}-open`;
|
|
84
|
+
const COMMAND_SHOW_MODAL = "show-modal";
|
|
85
|
+
const EVENT_TOGGLE = "toggle";
|
|
86
|
+
const MESSAGE = "The element must be an instance of HTMLDialogElement";
|
|
87
|
+
const SELECTOR_MODAL = ":modal";
|
|
88
|
+
const TRUE = "true";
|
|
89
|
+
const states = /* @__PURE__ */ new WeakMap();
|
|
90
|
+
attributable(ATTRIBUTE, addDialog, removeDialog);
|
|
91
|
+
//#endregion
|
|
92
|
+
export { getDialog };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { RemovableEventListener } from "@oscarpalmer/toretto/models";
|
|
2
|
+
|
|
3
|
+
//#region src/js/floatable/embedded.d.ts
|
|
4
|
+
declare class OuiFloatable {
|
|
5
|
+
#private;
|
|
6
|
+
/**
|
|
7
|
+
* Is the _Floatable_ open?
|
|
8
|
+
*/
|
|
9
|
+
get open(): boolean;
|
|
10
|
+
constructor(state: OuiFloatableState, standalone: boolean);
|
|
11
|
+
/**
|
|
12
|
+
* Destroy the _OuiFloatable_, removing it from the DOM and cleaning up references
|
|
13
|
+
*/
|
|
14
|
+
destroy(): void;
|
|
15
|
+
/**
|
|
16
|
+
* Closes the _OuiFloatable_
|
|
17
|
+
*/
|
|
18
|
+
hide(): void;
|
|
19
|
+
/**
|
|
20
|
+
* Opens the _OuiFloatable_
|
|
21
|
+
*/
|
|
22
|
+
show(): void;
|
|
23
|
+
/**
|
|
24
|
+
* Update the position of the _OuiFloatable_, with an optional new position
|
|
25
|
+
*
|
|
26
|
+
* @param position Optional new position
|
|
27
|
+
*/
|
|
28
|
+
update(position?: OuiFloatablePosition): void;
|
|
29
|
+
}
|
|
30
|
+
type OuiFloatableOptions = {
|
|
31
|
+
attribute?: string;
|
|
32
|
+
position: OuiFloatablePosition;
|
|
33
|
+
};
|
|
34
|
+
type OuiFloatablePosition = 'above' | 'above-end' | 'above-start' | 'below' | 'below-end' | 'below-start' | 'end' | 'end-bottom' | 'end-top' | 'start' | 'start-bottom' | 'start-top';
|
|
35
|
+
type OuiFloatableState = {
|
|
36
|
+
anchor: HTMLElement;
|
|
37
|
+
content: HTMLElement;
|
|
38
|
+
options: OuiFloatableOptions;
|
|
39
|
+
};
|
|
40
|
+
type GetOuiFloatableOptions = {
|
|
41
|
+
/**
|
|
42
|
+
* Open the _OuiFloatable_ when created? _(defaults to `true`)_
|
|
43
|
+
*/
|
|
44
|
+
open?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Position of the _OuiFloatable_ _(defaults to `below`)_
|
|
47
|
+
*/
|
|
48
|
+
position?: OuiFloatablePosition;
|
|
49
|
+
};
|
|
50
|
+
declare function createFloatable(anchor: HTMLElement, content: HTMLElement, options: OuiFloatableOptions, standalone: boolean): OuiFloatable;
|
|
51
|
+
/**
|
|
52
|
+
* Create a _Floatable_ for an anchor and content element
|
|
53
|
+
*
|
|
54
|
+
* @param anchor Anchor element
|
|
55
|
+
* @param content Content element
|
|
56
|
+
* @param options _Floatable_ options
|
|
57
|
+
* @returns _Floatable_ instance
|
|
58
|
+
*/
|
|
59
|
+
declare function getFloatable(anchor: HTMLElement | SVGElement, content: HTMLElement | SVGElement, options?: GetOuiFloatableOptions): OuiFloatable;
|
|
60
|
+
declare function getOnBeforeToggleListener(element: HTMLElement): RemovableEventListener;
|
|
61
|
+
declare function removeFloatable(content: HTMLElement): void;
|
|
62
|
+
declare const ATTRIBUTE_FLOATABLE = "oui-floatable";
|
|
63
|
+
//#endregion
|
|
64
|
+
export { createFloatable as a, removeFloatable as c, OuiFloatablePosition as i, OuiFloatable as n, getFloatable as o, OuiFloatableOptions as r, getOnBeforeToggleListener as s, ATTRIBUTE_FLOATABLE as t };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/js/focus-trap/embedded.d.ts
|
|
2
|
+
declare class FocusTrap {
|
|
3
|
+
disabled: boolean;
|
|
4
|
+
connected: boolean;
|
|
5
|
+
element: HTMLElement;
|
|
6
|
+
embedded: boolean;
|
|
7
|
+
get contain(): boolean;
|
|
8
|
+
get noescape(): boolean;
|
|
9
|
+
constructor(element: HTMLElement, options?: Options);
|
|
10
|
+
connect(): void;
|
|
11
|
+
destroy(): void;
|
|
12
|
+
disable(): void;
|
|
13
|
+
disconnect(): void;
|
|
14
|
+
enable(): void;
|
|
15
|
+
focus(last: boolean): void;
|
|
16
|
+
}
|
|
17
|
+
type Options = {
|
|
18
|
+
noescape: boolean;
|
|
19
|
+
};
|
|
20
|
+
declare function createFocusTrap(element: HTMLElement, options?: Options): FocusTrap;
|
|
21
|
+
declare function removeFocusTrap(element: HTMLElement): void;
|
|
22
|
+
declare const FOCUS_TRAP_SELECTOR = "oui-focus-trap";
|
|
23
|
+
declare const FOCUS_TRAP_CONTAIN = "oui-focus-trap-contain";
|
|
24
|
+
declare const FOCUS_TRAP_NOESCAPE = "oui-focus-trap-noescape";
|
|
25
|
+
//#endregion
|
|
26
|
+
export { createFocusTrap as a, FocusTrap as i, FOCUS_TRAP_NOESCAPE as n, removeFocusTrap as o, FOCUS_TRAP_SELECTOR as r, FOCUS_TRAP_CONTAIN as t };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as createFloatable, c as removeFloatable, i as OuiFloatablePosition, n as OuiFloatable, o as getFloatable, r as OuiFloatableOptions, s as getOnBeforeToggleListener, t as ATTRIBUTE_FLOATABLE } from "../embedded-84gxpReS.mjs";
|
|
2
|
+
export { ATTRIBUTE_FLOATABLE, OuiFloatable, OuiFloatableOptions, OuiFloatablePosition, createFloatable, getFloatable, getOnBeforeToggleListener, removeFloatable };
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { on } from "@oscarpalmer/toretto/event";
|
|
2
|
+
import { isPlainObject } from "@oscarpalmer/atoms/is";
|
|
3
|
+
import { isHTMLOrSVGElement } from "@oscarpalmer/toretto/is";
|
|
4
|
+
//#region src/js/floatable/embedded.ts
|
|
5
|
+
var OuiFloatable = class {
|
|
6
|
+
#destroyed = false;
|
|
7
|
+
#state;
|
|
8
|
+
/**
|
|
9
|
+
* Is the _Floatable_ open?
|
|
10
|
+
*/
|
|
11
|
+
get open() {
|
|
12
|
+
return this.#state.content.checkVisibility();
|
|
13
|
+
}
|
|
14
|
+
constructor(state, standalone) {
|
|
15
|
+
this.#state = state;
|
|
16
|
+
const { anchor, content } = state;
|
|
17
|
+
if (standalone) {
|
|
18
|
+
content.setAttribute(ATTRIBUTE_FLOATABLE, "");
|
|
19
|
+
content.popover = "manual";
|
|
20
|
+
}
|
|
21
|
+
const anchorName = getAnchorName(anchor);
|
|
22
|
+
anchor.style.anchorName = anchorName;
|
|
23
|
+
content.style.positionAnchor = anchorName;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Destroy the _OuiFloatable_, removing it from the DOM and cleaning up references
|
|
27
|
+
*/
|
|
28
|
+
destroy() {
|
|
29
|
+
if (this.#destroyed) return;
|
|
30
|
+
this.#destroyed = true;
|
|
31
|
+
removeFloatable(this.#state.content);
|
|
32
|
+
this.#state.anchor = null;
|
|
33
|
+
this.#state.content = null;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Closes the _OuiFloatable_
|
|
37
|
+
*/
|
|
38
|
+
hide() {
|
|
39
|
+
if (!this.#destroyed && this.open) this.#state.content.hidePopover();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Opens the _OuiFloatable_
|
|
43
|
+
*/
|
|
44
|
+
show() {
|
|
45
|
+
if (!this.#destroyed && !this.open) this.#state.content.showPopover();
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Update the position of the _OuiFloatable_, with an optional new position
|
|
49
|
+
*
|
|
50
|
+
* @param position Optional new position
|
|
51
|
+
*/
|
|
52
|
+
update(position) {
|
|
53
|
+
if (!this.#destroyed) setPosition(this.#state, position);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
function createFloatable(anchor, content, options, standalone) {
|
|
57
|
+
if (!isHTMLOrSVGElement(anchor) || !isHTMLOrSVGElement(content)) throw new TypeError("Anchor and content must be an HTMLElement or SVGElement.");
|
|
58
|
+
let floatable = instances.get(content);
|
|
59
|
+
if (floatable == null) {
|
|
60
|
+
floatable = new OuiFloatable(getState(anchor, content, options), standalone);
|
|
61
|
+
instances.set(content, floatable);
|
|
62
|
+
}
|
|
63
|
+
return floatable;
|
|
64
|
+
}
|
|
65
|
+
function getAnchorName(anchor) {
|
|
66
|
+
let { anchorName } = anchor.style;
|
|
67
|
+
if (anchorName.length > 0) return anchorName;
|
|
68
|
+
index += 1;
|
|
69
|
+
return `--oui-floatable-anchor-${index}`;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Create a _Floatable_ for an anchor and content element
|
|
73
|
+
*
|
|
74
|
+
* @param anchor Anchor element
|
|
75
|
+
* @param content Content element
|
|
76
|
+
* @param options _Floatable_ options
|
|
77
|
+
* @returns _Floatable_ instance
|
|
78
|
+
*/
|
|
79
|
+
function getFloatable(anchor, content, options) {
|
|
80
|
+
const { open, position } = getOptions(options);
|
|
81
|
+
const floatable = createFloatable(anchor, content, { position }, true);
|
|
82
|
+
floatable?.update(position);
|
|
83
|
+
if (open) floatable?.show();
|
|
84
|
+
return floatable;
|
|
85
|
+
}
|
|
86
|
+
function getOnBeforeToggleListener(element) {
|
|
87
|
+
return on(element, EVENT_BEFORE, (event) => {
|
|
88
|
+
const { newState, source } = event;
|
|
89
|
+
if (newState === STATE_OPEN && source?.getAttribute(ARIA_DISABLED) === TRUE) event.preventDefault();
|
|
90
|
+
}, { passive: false });
|
|
91
|
+
}
|
|
92
|
+
function getOptions(input) {
|
|
93
|
+
const object = isPlainObject(input) ? input : {};
|
|
94
|
+
return {
|
|
95
|
+
open: typeof object.open === "boolean" ? object.open : true,
|
|
96
|
+
position: object.position != null && object.position in AREAS ? object.position : "below"
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function getPosition$1(state, override) {
|
|
100
|
+
if (override != null && override in AREAS) return override;
|
|
101
|
+
const { anchor, options } = state;
|
|
102
|
+
if (options.attribute == null) return options.position;
|
|
103
|
+
const attribute = anchor.getAttribute(options.attribute) ?? "";
|
|
104
|
+
return attribute in AREAS ? attribute : options.position;
|
|
105
|
+
}
|
|
106
|
+
function getState(anchor, content, options) {
|
|
107
|
+
return {
|
|
108
|
+
anchor,
|
|
109
|
+
content,
|
|
110
|
+
options
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function removeFloatable(content) {
|
|
114
|
+
instances.get(content)?.destroy();
|
|
115
|
+
instances.delete(content);
|
|
116
|
+
}
|
|
117
|
+
function setPosition(state, override) {
|
|
118
|
+
const area = AREAS[getPosition$1(state, override)];
|
|
119
|
+
state.content.style.positionArea = area;
|
|
120
|
+
state.content.setAttribute(ATTRIBUTE_POSITION, POSITIONS[area]);
|
|
121
|
+
}
|
|
122
|
+
const AREAS = {
|
|
123
|
+
above: "block-start",
|
|
124
|
+
"above-end": "start span-start",
|
|
125
|
+
"above-start": "start span-end",
|
|
126
|
+
below: "block-end",
|
|
127
|
+
"below-end": "end span-start",
|
|
128
|
+
"below-start": "end span-end",
|
|
129
|
+
end: "center end",
|
|
130
|
+
"end-bottom": "span-start end",
|
|
131
|
+
"end-top": "span-end end",
|
|
132
|
+
start: "center start",
|
|
133
|
+
"start-bottom": "span-start start",
|
|
134
|
+
"start-top": "span-end start"
|
|
135
|
+
};
|
|
136
|
+
const ARIA_DISABLED = "aria-disabled";
|
|
137
|
+
const ATTRIBUTE_FLOATABLE = "oui-floatable";
|
|
138
|
+
const ATTRIBUTE_POSITION = "oui-position";
|
|
139
|
+
const EVENT_BEFORE = "beforetoggle";
|
|
140
|
+
const POSITIONS = Object.fromEntries(Object.entries(AREAS).map(([position, area]) => [area, position]));
|
|
141
|
+
const STATE_OPEN = "open";
|
|
142
|
+
const TRUE = "true";
|
|
143
|
+
const instances = /* @__PURE__ */ new WeakMap();
|
|
144
|
+
let index = 0;
|
|
145
|
+
//#endregion
|
|
146
|
+
export { ATTRIBUTE_FLOATABLE, OuiFloatable, createFloatable, getFloatable, getOnBeforeToggleListener, removeFloatable };
|
|
@@ -1,26 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
declare class FocusTrap {
|
|
3
|
-
disabled: boolean;
|
|
4
|
-
connected: boolean;
|
|
5
|
-
element: HTMLElement;
|
|
6
|
-
embedded: boolean;
|
|
7
|
-
get contain(): boolean;
|
|
8
|
-
get noescape(): boolean;
|
|
9
|
-
constructor(element: HTMLElement, options?: Options);
|
|
10
|
-
connect(): void;
|
|
11
|
-
destroy(): void;
|
|
12
|
-
disable(): void;
|
|
13
|
-
disconnect(): void;
|
|
14
|
-
enable(): void;
|
|
15
|
-
focus(last: boolean): void;
|
|
16
|
-
}
|
|
17
|
-
type Options = {
|
|
18
|
-
noescape: boolean;
|
|
19
|
-
};
|
|
20
|
-
declare function createFocusTrap(element: HTMLElement, options?: Options): FocusTrap;
|
|
21
|
-
declare function removeFocusTrap(element: HTMLElement): void;
|
|
22
|
-
declare const FOCUS_TRAP_SELECTOR = "oui-focus-trap";
|
|
23
|
-
declare const FOCUS_TRAP_CONTAIN = "oui-focus-trap-contain";
|
|
24
|
-
declare const FOCUS_TRAP_NOESCAPE = "oui-focus-trap-noescape";
|
|
25
|
-
//#endregion
|
|
1
|
+
import { a as createFocusTrap, i as FocusTrap, n as FOCUS_TRAP_NOESCAPE, o as removeFocusTrap, r as FOCUS_TRAP_SELECTOR, t as FOCUS_TRAP_CONTAIN } from "../embedded-BpwzMSEF.mjs";
|
|
26
2
|
export { FOCUS_TRAP_CONTAIN, FOCUS_TRAP_NOESCAPE, FOCUS_TRAP_SELECTOR, FocusTrap, createFocusTrap, removeFocusTrap };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { clamp } from "@oscarpalmer/atoms/number";
|
|
2
1
|
import { on } from "@oscarpalmer/toretto/event";
|
|
2
|
+
import { clamp } from "@oscarpalmer/atoms/number";
|
|
3
3
|
import { findAncestor } from "@oscarpalmer/toretto/find";
|
|
4
4
|
import { getFocusable } from "@oscarpalmer/toretto/focusable";
|
|
5
5
|
//#region src/js/focus-trap/embedded.ts
|
package/dist/js/index.d.mts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { OuiDialog, getDialog } from "./dialog.mjs";
|
|
2
|
+
import { i as OuiFloatablePosition, n as OuiFloatable, o as getFloatable } from "./embedded-84gxpReS.mjs";
|
|
3
|
+
import { OuiPopover, getPopover } from "./popover.mjs";
|
|
1
4
|
import { OuiSplitterElement } from "./splitter.mjs";
|
|
2
|
-
import { setTooltipDelay } from "./tooltip.mjs";
|
|
3
|
-
export { OuiSplitterElement, setTooltipDelay };
|
|
5
|
+
import { OuiTooltip, getTooltip, setTooltipDelay } from "./tooltip.mjs";
|
|
6
|
+
export { type OuiDialog, type OuiFloatable, type OuiFloatablePosition, type OuiPopover, OuiSplitterElement, type OuiTooltip, getDialog, getFloatable, getPopover, getTooltip, setTooltipDelay };
|
package/dist/js/index.mjs
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import "./
|
|
1
|
+
import { getFloatable } from "./floatable/embedded.mjs";
|
|
2
|
+
import { getDialog } from "./dialog.mjs";
|
|
2
3
|
import "./movable.mjs";
|
|
3
|
-
import "./popover.mjs";
|
|
4
4
|
import "./sortable.mjs";
|
|
5
|
+
import "./floatable/standalone.mjs";
|
|
6
|
+
import "./focus-trap/standalone.mjs";
|
|
7
|
+
import { getPopover } from "./popover.mjs";
|
|
5
8
|
import { OuiSplitterElement } from "./splitter.mjs";
|
|
6
|
-
import { setTooltipDelay } from "./tooltip.mjs";
|
|
7
|
-
export { OuiSplitterElement, setTooltipDelay };
|
|
9
|
+
import { getTooltip, setTooltipDelay } from "./tooltip.mjs";
|
|
10
|
+
export { OuiSplitterElement, getDialog, getFloatable, getPopover, getTooltip, setTooltipDelay };
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { isHTMLOrSVGElement } from "@oscarpalmer/toretto/is";
|
|
1
2
|
//#region src/js/internal/attributable.ts
|
|
2
3
|
function attributable(attribute, add, remove) {
|
|
3
4
|
new MutationObserver((entries) => {
|
|
4
5
|
const { length } = entries;
|
|
5
6
|
for (let index = 0; index < length; index += 1) {
|
|
6
7
|
const entry = entries[index];
|
|
7
|
-
if (entry.type === "attributes" && entry.target
|
|
8
|
+
if (entry.type === "attributes" && isHTMLOrSVGElement(entry.target)) if (entry.target.hasAttribute(attribute)) handleAdded(attribute, [entry.target], add);
|
|
8
9
|
else handleRemoved([entry.target], remove);
|
|
9
10
|
else if (entry.type === "childList") {
|
|
10
11
|
handleAdded(attribute, entry.addedNodes, add);
|
|
@@ -22,7 +23,7 @@ function attributable(attribute, add, remove) {
|
|
|
22
23
|
});
|
|
23
24
|
}
|
|
24
25
|
function handleAdded(attribute, nodes, add) {
|
|
25
|
-
const elements = [...nodes].filter(
|
|
26
|
+
const elements = [...nodes].filter(isHTMLOrSVGElement);
|
|
26
27
|
const { length } = elements;
|
|
27
28
|
for (let index = 0; index < length; index += 1) {
|
|
28
29
|
const element = elements[index];
|
|
@@ -31,7 +32,7 @@ function handleAdded(attribute, nodes, add) {
|
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
function handleRemoved(nodes, remove) {
|
|
34
|
-
const elements = [...nodes].filter(
|
|
35
|
+
const elements = [...nodes].filter(isHTMLOrSVGElement);
|
|
35
36
|
const { length } = elements;
|
|
36
37
|
for (let index = 0; index < length; index += 1) {
|
|
37
38
|
const element = elements[index];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { clamp } from "@oscarpalmer/atoms/number";
|
|
2
1
|
import { getPosition, on } from "@oscarpalmer/toretto/event";
|
|
2
|
+
import { clamp } from "@oscarpalmer/atoms/number";
|
|
3
3
|
import { findAncestor } from "@oscarpalmer/toretto/find";
|
|
4
4
|
import { toggleStyles } from "@oscarpalmer/toretto/style";
|
|
5
5
|
import supportsTouch from "@oscarpalmer/toretto/touch";
|
package/dist/js/popover.d.mts
CHANGED
|
@@ -1 +1,38 @@
|
|
|
1
|
-
|
|
1
|
+
import { n as OuiFloatable } from "./embedded-84gxpReS.mjs";
|
|
2
|
+
import { i as FocusTrap } from "./embedded-BpwzMSEF.mjs";
|
|
3
|
+
import { RemovableEventListener } from "@oscarpalmer/toretto/models";
|
|
4
|
+
|
|
5
|
+
//#region src/js/popover.d.ts
|
|
6
|
+
declare class OuiPopover {
|
|
7
|
+
#private;
|
|
8
|
+
/**
|
|
9
|
+
* Is the popover open?
|
|
10
|
+
*/
|
|
11
|
+
get open(): boolean;
|
|
12
|
+
constructor(state: OuiPopoverState);
|
|
13
|
+
/**
|
|
14
|
+
* Closes the popover
|
|
15
|
+
*/
|
|
16
|
+
hide(): void;
|
|
17
|
+
/**
|
|
18
|
+
* Opens the popover
|
|
19
|
+
*/
|
|
20
|
+
show(): void;
|
|
21
|
+
}
|
|
22
|
+
type OuiPopoverState = {
|
|
23
|
+
anchor: HTMLElement;
|
|
24
|
+
content: HTMLElement;
|
|
25
|
+
floatable: OuiFloatable;
|
|
26
|
+
focusTrap?: FocusTrap;
|
|
27
|
+
listeners: RemovableEventListener[];
|
|
28
|
+
popover: OuiPopover;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Get the _OuiPopover_ for an element
|
|
32
|
+
*
|
|
33
|
+
* @param element Element to get _OuiPopover_ for
|
|
34
|
+
* @returns _OuiPopover_ instance
|
|
35
|
+
*/
|
|
36
|
+
declare function getPopover(element: HTMLElement): OuiPopover | undefined;
|
|
37
|
+
//#endregion
|
|
38
|
+
export { type OuiPopover, getPopover };
|