@oscarpalmer/oui 0.26.0 → 0.27.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/floatable.css +0 -2
- package/dist/css/message.css +1 -0
- package/dist/css/reset.css +1 -0
- package/dist/js/dialog.d.mts +6 -0
- package/dist/js/dialog.mjs +23 -1
- package/dist/js/draggable-zszaW1qS.d.mts +155 -0
- package/dist/js/floatable/floatable.embedded.d.mts +2 -0
- package/dist/js/floatable/{embedded.mjs → floatable.embedded.mjs} +22 -17
- package/dist/js/floatable/floatable.standalone.d.mts +2 -0
- package/dist/js/floatable/floatable.standalone.mjs +2 -0
- package/dist/js/{embedded-ai6cqURc.d.mts → floatable.embedded-YxGwzgbE.d.mts} +13 -10
- package/dist/js/focus-trap/focus-trap.embedded.d.mts +2 -0
- package/dist/js/focus-trap/{embedded.mjs → focus-trap.embedded.mjs} +17 -15
- package/dist/js/focus-trap/focus-trap.standalone.d.mts +2 -0
- package/dist/js/focus-trap/focus-trap.standalone.mjs +2 -0
- package/dist/js/{embedded-CHK82Uh5.d.mts → focus-trap.embedded-DR8NpZfr.d.mts} +18 -18
- package/dist/js/index.d.mts +4 -3
- package/dist/js/index.mjs +8 -7
- package/dist/js/internal/draggable.d.mts +2 -2
- package/dist/js/internal/draggable.mjs +146 -94
- package/dist/js/movable/movable.embedded.d.mts +2 -0
- package/dist/js/movable/movable.embedded.mjs +184 -0
- package/dist/js/movable/movable.standalone.d.mts +2 -0
- package/dist/js/movable/movable.standalone.mjs +2 -0
- package/dist/js/popover.d.mts +3 -2
- package/dist/js/popover.mjs +8 -3
- package/dist/js/sortable/sortable.embedded.d.mts +2 -0
- package/dist/js/{sortable.mjs → sortable/sortable.embedded.mjs} +88 -63
- package/dist/js/sortable/sortable.standalone.d.mts +2 -0
- package/dist/js/sortable/sortable.standalone.mjs +2 -0
- package/dist/js/splitter.d.mts +24 -0
- package/dist/js/splitter.mjs +33 -9
- package/dist/js/toolbar.mjs +6 -6
- package/dist/js/tooltip.d.mts +12 -2
- package/dist/js/tooltip.mjs +49 -33
- package/package.json +11 -11
- package/src/css/floatable.scss +0 -2
- package/src/css/message.scss +1 -0
- package/src/css/reset.scss +1 -0
- package/src/js/dialog.ts +42 -1
- package/src/js/floatable/{embedded.ts → floatable.embedded.ts} +26 -18
- package/src/js/floatable/floatable.standalone.ts +6 -0
- package/src/js/focus-trap/{embedded.ts → focus-trap.embedded.ts} +20 -17
- package/src/js/focus-trap/focus-trap.standalone.ts +1 -0
- package/src/js/index.ts +4 -4
- package/src/js/internal/draggable.ts +309 -168
- package/src/js/movable/movable.embedded.ts +328 -0
- package/src/js/movable/movable.standalone.ts +2 -0
- package/src/js/popover.ts +11 -2
- package/src/js/{sortable.ts → sortable/sortable.embedded.ts} +170 -103
- package/src/js/sortable/sortable.standalone.ts +2 -0
- package/src/js/splitter.ts +28 -4
- package/src/js/tooltip.ts +66 -43
- package/dist/js/floatable/embedded.d.mts +0 -2
- package/dist/js/floatable/standalone.d.mts +0 -2
- package/dist/js/floatable/standalone.mjs +0 -2
- package/dist/js/focus-trap/embedded.d.mts +0 -2
- package/dist/js/focus-trap/standalone.d.mts +0 -2
- package/dist/js/focus-trap/standalone.mjs +0 -6
- package/dist/js/movable-dNqBctx3.d.mts +0 -101
- package/dist/js/movable.d.mts +0 -2
- package/dist/js/movable.mjs +0 -152
- package/dist/js/sortable.d.mts +0 -2
- package/src/js/floatable/standalone.ts +0 -1
- package/src/js/focus-trap/standalone.ts +0 -6
- package/src/js/movable.ts +0 -260
package/dist/js/tooltip.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as OuiFloatable } from "./floatable.embedded-YxGwzgbE.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/js/tooltip.d.ts
|
|
4
4
|
declare class OuiTooltip {
|
|
@@ -7,6 +7,10 @@ declare class OuiTooltip {
|
|
|
7
7
|
* Is the tooltip open?
|
|
8
8
|
*/
|
|
9
9
|
get open(): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Open or close the tooltip
|
|
12
|
+
*/
|
|
13
|
+
set open(value: boolean);
|
|
10
14
|
constructor(state: OuiTooltipState);
|
|
11
15
|
/**
|
|
12
16
|
* Closes the tooltip
|
|
@@ -19,11 +23,17 @@ declare class OuiTooltip {
|
|
|
19
23
|
}
|
|
20
24
|
type OuiTooltipState = {
|
|
21
25
|
anchor: HTMLElement;
|
|
22
|
-
|
|
26
|
+
elements: HTMLElement[];
|
|
23
27
|
floatable: OuiFloatable;
|
|
24
28
|
timer?: number;
|
|
25
29
|
tooltip: OuiTooltip;
|
|
26
30
|
};
|
|
31
|
+
/**
|
|
32
|
+
* Get the _OuiTooltip_ for an element
|
|
33
|
+
*
|
|
34
|
+
* @param element Element to get _OuiTooltip_ for
|
|
35
|
+
* @returns _OuiTooltip_ instance
|
|
36
|
+
*/
|
|
27
37
|
declare function getTooltip(element: HTMLElement): OuiTooltip | undefined;
|
|
28
38
|
/**
|
|
29
39
|
* Set the delay before showing the tooltip, in milliseconds
|
package/dist/js/tooltip.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createEmbeddedFloatable } from "./floatable/embedded.mjs";
|
|
1
|
+
import { createEmbeddedFloatable } from "./floatable/floatable.embedded.mjs";
|
|
2
2
|
import { attributable } from "./internal/attributable.mjs";
|
|
3
3
|
import { on } from "@oscarpalmer/toretto/event";
|
|
4
4
|
import { isNullableOrWhitespace } from "@oscarpalmer/atoms/is";
|
|
@@ -12,7 +12,14 @@ var OuiTooltip = class {
|
|
|
12
12
|
* Is the tooltip open?
|
|
13
13
|
*/
|
|
14
14
|
get open() {
|
|
15
|
-
return this
|
|
15
|
+
return this === activeTooltip && content.checkVisibility();
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Open or close the tooltip
|
|
19
|
+
*/
|
|
20
|
+
set open(value) {
|
|
21
|
+
if (value === true) this.show();
|
|
22
|
+
else if (value === false) this.hide();
|
|
16
23
|
}
|
|
17
24
|
constructor(state) {
|
|
18
25
|
this.#state = state;
|
|
@@ -32,52 +39,50 @@ var OuiTooltip = class {
|
|
|
32
39
|
}
|
|
33
40
|
};
|
|
34
41
|
function activate(event, focus) {
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
if (
|
|
42
|
+
const targetAnchor = findAncestor(event, SELECTOR);
|
|
43
|
+
const targetContent = findAncestor(event, SELECTOR_CONTENT);
|
|
44
|
+
if (targetAnchor == null && targetContent == null) {
|
|
38
45
|
if (!focused) {
|
|
39
|
-
closeTooltip(activeState);
|
|
46
|
+
closeTooltip(true, activeState);
|
|
40
47
|
activeState = void 0;
|
|
41
48
|
activeTooltip = void 0;
|
|
42
49
|
}
|
|
43
50
|
return;
|
|
44
51
|
}
|
|
45
|
-
const state = states.get(
|
|
52
|
+
const state = states.get(targetAnchor ?? targetContent);
|
|
46
53
|
if (state == null || state.tooltip === activeTooltip) return;
|
|
47
54
|
const shouldDelay = activeTooltip == null;
|
|
48
|
-
closeTooltip(activeState);
|
|
55
|
+
closeTooltip(false, activeState);
|
|
49
56
|
activeState = state;
|
|
50
57
|
activeTooltip = state.tooltip;
|
|
51
58
|
focused = focus;
|
|
52
59
|
state.timer = setTimeout(() => {
|
|
53
|
-
|
|
60
|
+
content.innerHTML = "";
|
|
61
|
+
content.append(...state.elements);
|
|
62
|
+
state.floatable.show();
|
|
54
63
|
setTimeout(() => {
|
|
55
64
|
state.floatable.update();
|
|
56
|
-
state.content.setAttribute(ATTRIBUTE_CONTENT_OPEN, "");
|
|
57
65
|
});
|
|
58
66
|
}, shouldDelay ? delay : 0);
|
|
59
67
|
}
|
|
60
68
|
function addTooltip(element) {
|
|
61
69
|
if (!states.has(element)) createTooltip(element);
|
|
62
70
|
}
|
|
63
|
-
function closeTooltip(state) {
|
|
71
|
+
function closeTooltip(clear, state) {
|
|
64
72
|
if (state == null) return;
|
|
65
73
|
if (state.timer != null) clearTimeout(state.timer);
|
|
66
|
-
|
|
67
|
-
state.content?.removeAttribute(ATTRIBUTE_CONTENT_OPEN);
|
|
74
|
+
if (clear) content?.hidePopover();
|
|
68
75
|
}
|
|
69
76
|
function createTooltip(anchor) {
|
|
70
|
-
const
|
|
71
|
-
if (
|
|
72
|
-
|
|
73
|
-
states.set(anchor, getState(anchor, content));
|
|
77
|
+
const elements = getElements(anchor);
|
|
78
|
+
if (elements == null) return;
|
|
79
|
+
states.set(anchor, getState(anchor, elements));
|
|
74
80
|
}
|
|
75
81
|
function destroyTooltip(state) {
|
|
76
82
|
clearTimeout(state.timer);
|
|
77
|
-
state.content.remove();
|
|
78
83
|
state.floatable.destroy();
|
|
79
84
|
state.anchor = void 0;
|
|
80
|
-
state.
|
|
85
|
+
state.elements = void 0;
|
|
81
86
|
state.floatable = void 0;
|
|
82
87
|
state.tooltip = void 0;
|
|
83
88
|
}
|
|
@@ -95,40 +100,43 @@ function findElements(attribute) {
|
|
|
95
100
|
}
|
|
96
101
|
return elements;
|
|
97
102
|
}
|
|
98
|
-
function getContent(
|
|
99
|
-
const elements = getElements(anchor);
|
|
100
|
-
if (elements == null) return;
|
|
103
|
+
function getContent() {
|
|
101
104
|
const content = createElement(CONTENT_TAGNAME, {
|
|
102
105
|
popover: "hint",
|
|
103
106
|
role: "tooltip",
|
|
104
107
|
tabIndex: -1
|
|
105
108
|
});
|
|
106
109
|
content.setAttribute(ATTRIBUTE_CONTENT, "");
|
|
107
|
-
content.append(...elements);
|
|
108
110
|
return content;
|
|
109
111
|
}
|
|
110
112
|
function getElements(anchor) {
|
|
111
113
|
let elements = findElements(anchor.getAttribute(ARIA_LABELLEDBY));
|
|
112
|
-
if (elements.length > 0) return elements
|
|
114
|
+
if (elements.length > 0) return elements;
|
|
113
115
|
elements = findElements(anchor.getAttribute(ARIA_DESCRIBEDBY));
|
|
114
|
-
if (elements.length > 0) return elements
|
|
115
|
-
let
|
|
116
|
-
if (isNullableOrWhitespace(
|
|
117
|
-
if (isNullableOrWhitespace(
|
|
116
|
+
if (elements.length > 0) return elements;
|
|
117
|
+
let text = anchor.getAttribute(ARIA_LABEL);
|
|
118
|
+
if (isNullableOrWhitespace(text)) text = anchor.getAttribute(ARIA_DESCRIPTION);
|
|
119
|
+
if (isNullableOrWhitespace(text)) return;
|
|
118
120
|
const paragraph = document.createElement("p");
|
|
119
|
-
paragraph.textContent =
|
|
121
|
+
paragraph.textContent = text;
|
|
120
122
|
return [paragraph];
|
|
121
123
|
}
|
|
122
|
-
function getState(anchor,
|
|
124
|
+
function getState(anchor, elements) {
|
|
123
125
|
const state = {
|
|
124
126
|
anchor,
|
|
125
|
-
|
|
127
|
+
elements,
|
|
126
128
|
floatable: createEmbeddedFloatable(anchor, content, options),
|
|
127
129
|
tooltip: null
|
|
128
130
|
};
|
|
129
131
|
state.tooltip = new OuiTooltip(state);
|
|
130
132
|
return state;
|
|
131
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Get the _OuiTooltip_ for an element
|
|
136
|
+
*
|
|
137
|
+
* @param element Element to get _OuiTooltip_ for
|
|
138
|
+
* @returns _OuiTooltip_ instance
|
|
139
|
+
*/
|
|
132
140
|
function getTooltip(element) {
|
|
133
141
|
return states.get(element)?.tooltip;
|
|
134
142
|
}
|
|
@@ -140,7 +148,7 @@ function onFocusout() {
|
|
|
140
148
|
if (focusTimer != null) clearTimeout(focusTimer);
|
|
141
149
|
focusTimer = setTimeout(() => {
|
|
142
150
|
if (activeTooltip == null || document.activeElement == null || findAncestor(document.activeElement, SELECTOR) != null) return;
|
|
143
|
-
closeTooltip(activeState);
|
|
151
|
+
closeTooltip(true, activeState);
|
|
144
152
|
activeState = void 0;
|
|
145
153
|
activeTooltip = void 0;
|
|
146
154
|
});
|
|
@@ -148,6 +156,10 @@ function onFocusout() {
|
|
|
148
156
|
function onPointermove(event) {
|
|
149
157
|
activate(event, false);
|
|
150
158
|
}
|
|
159
|
+
function onToggle(event) {
|
|
160
|
+
if (event.newState === "open") content.setAttribute(ATTRIBUTE_CONTENT_OPEN, "");
|
|
161
|
+
else content.removeAttribute(ATTRIBUTE_CONTENT_OPEN);
|
|
162
|
+
}
|
|
151
163
|
function removeTooltip(element) {
|
|
152
164
|
const state = states.get(element);
|
|
153
165
|
if (state == null) return;
|
|
@@ -174,16 +186,20 @@ const ATTRIBUTE_CONTENT = `${ATTRIBUTE}-content`;
|
|
|
174
186
|
const ATTRIBUTE_CONTENT_OPEN = `${ATTRIBUTE_CONTENT}-open`;
|
|
175
187
|
const SELECTOR = `[${ATTRIBUTE}]`;
|
|
176
188
|
const SELECTOR_CONTENT = `[${ATTRIBUTE_CONTENT}]`;
|
|
189
|
+
const content = getContent();
|
|
177
190
|
const states = /* @__PURE__ */ new WeakMap();
|
|
178
191
|
const options = {
|
|
179
192
|
attribute: `${ATTRIBUTE}-position`,
|
|
180
|
-
position: "above"
|
|
193
|
+
position: "above",
|
|
194
|
+
reusable: true
|
|
181
195
|
};
|
|
182
196
|
let delay = 500;
|
|
183
197
|
let focused = false;
|
|
184
198
|
let activeState;
|
|
185
199
|
let activeTooltip;
|
|
186
200
|
let focusTimer;
|
|
201
|
+
document.body.append(content);
|
|
202
|
+
on(content, "toggle", onToggle);
|
|
187
203
|
on(document, "focusin", onFocusin);
|
|
188
204
|
on(document, "focusout", onFocusout);
|
|
189
205
|
on(document, "pointermove", onPointermove);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oscarpalmer/oui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "Styles, components, and utilities for building websites and applications.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"css",
|
|
@@ -38,24 +38,24 @@
|
|
|
38
38
|
"default": "./dist/js/dialog.mjs"
|
|
39
39
|
},
|
|
40
40
|
"./floatable": {
|
|
41
|
-
"types": "./dist/js/floatable/standalone.d.mts",
|
|
42
|
-
"default": "./dist/js/floatable/standalone.mjs"
|
|
41
|
+
"types": "./dist/js/floatable/floatable.standalone.d.mts",
|
|
42
|
+
"default": "./dist/js/floatable/floatable.standalone.mjs"
|
|
43
43
|
},
|
|
44
44
|
"./focus-trap": {
|
|
45
|
-
"types": "./dist/js/focus-trap/standalone.d.mts",
|
|
46
|
-
"default": "./dist/js/focus-trap/standalone.mjs"
|
|
45
|
+
"types": "./dist/js/focus-trap/focus-trap.standalone.d.mts",
|
|
46
|
+
"default": "./dist/js/focus-trap/focus-trap.standalone.mjs"
|
|
47
47
|
},
|
|
48
48
|
"./movable": {
|
|
49
|
-
"types": "./dist/js/movable.d.mts",
|
|
50
|
-
"default": "./dist/js/movable.mjs"
|
|
49
|
+
"types": "./dist/js/movable/movable.standalone.d.mts",
|
|
50
|
+
"default": "./dist/js/movable/movable.standalone.mjs"
|
|
51
51
|
},
|
|
52
52
|
"./popover": {
|
|
53
53
|
"types": "./dist/js/popover.d.mts",
|
|
54
54
|
"default": "./dist/js/popover.mjs"
|
|
55
55
|
},
|
|
56
56
|
"./sortable": {
|
|
57
|
-
"types": "./dist/js/sortable.d.mts",
|
|
58
|
-
"default": "./dist/js/sortable.mjs"
|
|
57
|
+
"types": "./dist/js/sortable/sortable.standalone.d.mts",
|
|
58
|
+
"default": "./dist/js/sortable/sortable.standalone.mjs"
|
|
59
59
|
},
|
|
60
60
|
"./splitter": {
|
|
61
61
|
"types": "./dist/js/splitter.d.mts",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"@oscarpalmer/toretto": "^0.46"
|
|
87
87
|
},
|
|
88
88
|
"devDependencies": {
|
|
89
|
-
"@oxlint/plugins": "^1.
|
|
89
|
+
"@oxlint/plugins": "^1.72",
|
|
90
90
|
"@vitest/coverage-istanbul": "^4.1",
|
|
91
91
|
"autoprefixer": "^10.5",
|
|
92
92
|
"concurrently": "^10",
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
"postcss-input-range": "^6",
|
|
96
96
|
"postcss-scss": "^4",
|
|
97
97
|
"sass": "^1.101",
|
|
98
|
-
"stylelint": "^17.
|
|
98
|
+
"stylelint": "^17.14",
|
|
99
99
|
"stylelint-config-standard-scss": "^17",
|
|
100
100
|
"tsdown": "^0.22",
|
|
101
101
|
"typescript": "^6",
|
package/src/css/floatable.scss
CHANGED
package/src/css/message.scss
CHANGED
package/src/css/reset.scss
CHANGED
package/src/js/dialog.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {on} from '@oscarpalmer/toretto/event';
|
|
2
2
|
import type {RemovableEventListener} from '@oscarpalmer/toretto/models';
|
|
3
|
-
import {getOnBeforeToggleListener} from './floatable/embedded';
|
|
3
|
+
import {getOnBeforeToggleListener} from './floatable/floatable.embedded';
|
|
4
4
|
import {attributable} from './internal/attributable';
|
|
5
|
+
import {ATTRIBUTE_MOVABLE_HANDLE} from './movable/movable.embedded';
|
|
6
|
+
import {createMovable, type OuiMovable} from './movable/movable.standalone';
|
|
5
7
|
|
|
6
8
|
// #region Types
|
|
7
9
|
|
|
@@ -15,6 +17,17 @@ class OuiDialog {
|
|
|
15
17
|
return this.#state.element.open;
|
|
16
18
|
}
|
|
17
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Open or close the dialog
|
|
22
|
+
*/
|
|
23
|
+
set open(value: boolean) {
|
|
24
|
+
if (value === true) {
|
|
25
|
+
this.show();
|
|
26
|
+
} else if (value === false) {
|
|
27
|
+
this.hide();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
18
31
|
constructor(state: OuiDialogState) {
|
|
19
32
|
this.#state = state;
|
|
20
33
|
}
|
|
@@ -68,6 +81,7 @@ type OuiDialogState = {
|
|
|
68
81
|
element: HTMLDialogElement;
|
|
69
82
|
listeners: RemovableEventListener[];
|
|
70
83
|
modal: boolean;
|
|
84
|
+
movable?: OuiMovable;
|
|
71
85
|
};
|
|
72
86
|
|
|
73
87
|
// #endregion
|
|
@@ -109,6 +123,22 @@ function getDialog(element: HTMLDialogElement): OuiDialog | undefined {
|
|
|
109
123
|
return states.get(element)?.dialog;
|
|
110
124
|
}
|
|
111
125
|
|
|
126
|
+
function getMovable(element: HTMLDialogElement): OuiMovable | undefined {
|
|
127
|
+
const handles = element.querySelectorAll(SELECTOR_MOVER);
|
|
128
|
+
|
|
129
|
+
if (handles.length === 0) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
for (const handle of handles) {
|
|
134
|
+
handle.setAttribute(ATTRIBUTE_MOVABLE_HANDLE, '');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return createMovable(element, {
|
|
138
|
+
container: element.getAttribute(ATTRIBUTE_CONTAINER) ?? undefined,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
112
142
|
function getState(element: HTMLDialogElement): OuiDialogState {
|
|
113
143
|
const state: OuiDialogState = {
|
|
114
144
|
element,
|
|
@@ -125,9 +155,15 @@ function getState(element: HTMLDialogElement): OuiDialogState {
|
|
|
125
155
|
|
|
126
156
|
element.setAttribute(ARIA_MODAL, String(modal));
|
|
127
157
|
element.setAttribute(ATTRIBUTE_OPEN, '');
|
|
158
|
+
|
|
159
|
+
element.focus();
|
|
128
160
|
} else {
|
|
129
161
|
element.removeAttribute(ATTRIBUTE_OPEN);
|
|
130
162
|
element.setAttribute(ARIA_MODAL, String(state.modal));
|
|
163
|
+
|
|
164
|
+
element.style.inset = '';
|
|
165
|
+
element.style.position = '';
|
|
166
|
+
element.style.transform = '';
|
|
131
167
|
}
|
|
132
168
|
}),
|
|
133
169
|
],
|
|
@@ -135,6 +171,7 @@ function getState(element: HTMLDialogElement): OuiDialogState {
|
|
|
135
171
|
};
|
|
136
172
|
|
|
137
173
|
state.dialog = new OuiDialog(state);
|
|
174
|
+
state.movable = getMovable(element);
|
|
138
175
|
|
|
139
176
|
return state;
|
|
140
177
|
}
|
|
@@ -159,6 +196,8 @@ const ARIA_MODAL = 'aria-modal';
|
|
|
159
196
|
|
|
160
197
|
const ATTRIBUTE = 'oui-dialog';
|
|
161
198
|
|
|
199
|
+
const ATTRIBUTE_CONTAINER = `${ATTRIBUTE}-container`;
|
|
200
|
+
|
|
162
201
|
const ATTRIBUTE_OPEN = `${ATTRIBUTE}-open`;
|
|
163
202
|
|
|
164
203
|
const COMMAND_SHOW_MODAL = 'show-modal';
|
|
@@ -167,6 +206,8 @@ const EVENT_TOGGLE = 'toggle';
|
|
|
167
206
|
|
|
168
207
|
const MESSAGE = 'The element must be an instance of HTMLDialogElement';
|
|
169
208
|
|
|
209
|
+
const SELECTOR_MOVER = `[${ATTRIBUTE}-mover]`;
|
|
210
|
+
|
|
170
211
|
const SELECTOR_MODAL = ':modal';
|
|
171
212
|
|
|
172
213
|
const TRUE = 'true';
|
|
@@ -5,13 +5,13 @@ import type {RemovableEventListener} from '@oscarpalmer/toretto/models';
|
|
|
5
5
|
|
|
6
6
|
// #region Types
|
|
7
7
|
|
|
8
|
-
type CreateOuiFloatableOptions = {
|
|
8
|
+
export type CreateOuiFloatableOptions = {
|
|
9
9
|
/**
|
|
10
|
-
* Open the
|
|
10
|
+
* Open the floatable when created? _(defaults to `true`)_
|
|
11
11
|
*/
|
|
12
12
|
open?: boolean;
|
|
13
13
|
/**
|
|
14
|
-
* Position of the
|
|
14
|
+
* Position of the floatable _(defaults to `below`)_
|
|
15
15
|
*/
|
|
16
16
|
position?: OuiFloatablePosition;
|
|
17
17
|
};
|
|
@@ -22,14 +22,14 @@ export class OuiFloatable {
|
|
|
22
22
|
readonly #state: OuiFloatableState;
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
* Is the
|
|
25
|
+
* Is the floatable open?
|
|
26
26
|
*/
|
|
27
27
|
get open(): boolean {
|
|
28
28
|
return this.#state.content.checkVisibility();
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
|
-
* Open or close the
|
|
32
|
+
* Open or close the floatable
|
|
33
33
|
*/
|
|
34
34
|
set open(value: boolean) {
|
|
35
35
|
if (value === true) {
|
|
@@ -50,14 +50,12 @@ export class OuiFloatable {
|
|
|
50
50
|
content.popover = 'manual';
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
anchor.style.anchorName = anchorName;
|
|
56
|
-
content.style.positionAnchor = anchorName;
|
|
53
|
+
anchor.style.anchorName = state.name;
|
|
54
|
+
content.style.positionAnchor = state.name;
|
|
57
55
|
}
|
|
58
56
|
|
|
59
57
|
/**
|
|
60
|
-
* Destroy the
|
|
58
|
+
* Destroy the floatable, removing it from the DOM and cleaning up references
|
|
61
59
|
*/
|
|
62
60
|
destroy(): void {
|
|
63
61
|
if (this.#destroyed) {
|
|
@@ -73,7 +71,7 @@ export class OuiFloatable {
|
|
|
73
71
|
}
|
|
74
72
|
|
|
75
73
|
/**
|
|
76
|
-
* Closes the
|
|
74
|
+
* Closes the floatable
|
|
77
75
|
*/
|
|
78
76
|
hide(): void {
|
|
79
77
|
if (!this.#destroyed && this.open) {
|
|
@@ -82,7 +80,7 @@ export class OuiFloatable {
|
|
|
82
80
|
}
|
|
83
81
|
|
|
84
82
|
/**
|
|
85
|
-
* Opens the
|
|
83
|
+
* Opens the floatable
|
|
86
84
|
*/
|
|
87
85
|
show(): void {
|
|
88
86
|
if (!this.#destroyed && !this.open) {
|
|
@@ -91,7 +89,7 @@ export class OuiFloatable {
|
|
|
91
89
|
}
|
|
92
90
|
|
|
93
91
|
/**
|
|
94
|
-
* Update the position of the
|
|
92
|
+
* Update the position of the floatable, with an optional new position
|
|
95
93
|
*
|
|
96
94
|
* @param position Optional new position
|
|
97
95
|
*/
|
|
@@ -105,6 +103,7 @@ export class OuiFloatable {
|
|
|
105
103
|
export type OuiFloatableOptions = {
|
|
106
104
|
attribute?: string;
|
|
107
105
|
position: OuiFloatablePosition;
|
|
106
|
+
reusable: boolean;
|
|
108
107
|
};
|
|
109
108
|
|
|
110
109
|
export type OuiFloatablePosition =
|
|
@@ -124,6 +123,7 @@ export type OuiFloatablePosition =
|
|
|
124
123
|
type OuiFloatableState = {
|
|
125
124
|
anchor: HTMLElement;
|
|
126
125
|
content: HTMLElement;
|
|
126
|
+
name: string;
|
|
127
127
|
options: OuiFloatableOptions;
|
|
128
128
|
};
|
|
129
129
|
|
|
@@ -171,6 +171,7 @@ export function createFloatable(
|
|
|
171
171
|
content,
|
|
172
172
|
{
|
|
173
173
|
position,
|
|
174
|
+
reusable: false,
|
|
174
175
|
},
|
|
175
176
|
true,
|
|
176
177
|
);
|
|
@@ -194,12 +195,14 @@ function createInstance(
|
|
|
194
195
|
throw new TypeError(MESSAGE);
|
|
195
196
|
}
|
|
196
197
|
|
|
197
|
-
let floatable = instances.get(content);
|
|
198
|
+
let floatable = options.reusable ? undefined : instances.get(content);
|
|
198
199
|
|
|
199
200
|
if (floatable == null) {
|
|
200
201
|
floatable = new OuiFloatable(getState(anchor, content, options), standalone);
|
|
201
202
|
|
|
202
|
-
|
|
203
|
+
if (!options.reusable) {
|
|
204
|
+
instances.set(content, floatable);
|
|
205
|
+
}
|
|
203
206
|
}
|
|
204
207
|
|
|
205
208
|
return floatable;
|
|
@@ -212,7 +215,7 @@ export function getOnBeforeToggleListener(element: HTMLElement): RemovableEventL
|
|
|
212
215
|
event => {
|
|
213
216
|
const {newState, source} = event;
|
|
214
217
|
|
|
215
|
-
if (newState ===
|
|
218
|
+
if (newState === FLOATABLE_STATE_OPEN && source?.getAttribute(ARIA_DISABLED) === TRUE) {
|
|
216
219
|
event.preventDefault();
|
|
217
220
|
}
|
|
218
221
|
},
|
|
@@ -255,9 +258,12 @@ function getState(
|
|
|
255
258
|
content: HTMLElement,
|
|
256
259
|
options: OuiFloatableOptions,
|
|
257
260
|
): OuiFloatableState {
|
|
261
|
+
const name = getAnchorName(anchor);
|
|
262
|
+
|
|
258
263
|
const state: OuiFloatableState = {
|
|
259
264
|
anchor,
|
|
260
265
|
content,
|
|
266
|
+
name,
|
|
261
267
|
options,
|
|
262
268
|
};
|
|
263
269
|
|
|
@@ -266,6 +272,7 @@ function getState(
|
|
|
266
272
|
|
|
267
273
|
export function removeFloatable(content: HTMLElement): void {
|
|
268
274
|
instances.get(content)?.destroy();
|
|
275
|
+
|
|
269
276
|
instances.delete(content);
|
|
270
277
|
}
|
|
271
278
|
|
|
@@ -274,6 +281,7 @@ function setPosition(state: OuiFloatableState, override?: OuiFloatablePosition):
|
|
|
274
281
|
|
|
275
282
|
const area = AREAS[position];
|
|
276
283
|
|
|
284
|
+
state.content.style.positionAnchor = state.name;
|
|
277
285
|
state.content.style.positionArea = area;
|
|
278
286
|
|
|
279
287
|
state.content.setAttribute(ATTRIBUTE_POSITION, POSITIONS[area]);
|
|
@@ -306,14 +314,14 @@ const ATTRIBUTE_POSITION = 'oui-position';
|
|
|
306
314
|
|
|
307
315
|
const EVENT_BEFORE = 'beforetoggle';
|
|
308
316
|
|
|
317
|
+
export const FLOATABLE_STATE_OPEN = 'open';
|
|
318
|
+
|
|
309
319
|
const MESSAGE = 'Anchor and content must be an HTMLElement or SVGElement';
|
|
310
320
|
|
|
311
321
|
const POSITIONS = Object.fromEntries(
|
|
312
322
|
Object.entries(AREAS).map(([position, area]) => [area, position]),
|
|
313
323
|
) as Record<string, OuiFloatablePosition>;
|
|
314
324
|
|
|
315
|
-
const STATE_OPEN = 'open';
|
|
316
|
-
|
|
317
325
|
const TRUE = 'true';
|
|
318
326
|
|
|
319
327
|
const instances = new WeakMap<HTMLElement, OuiFloatable>();
|