@oscarpalmer/oui 0.28.0 → 0.29.1
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/js/dialog.d.mts +1 -1
- package/dist/js/dialog.mjs +19 -20
- package/dist/js/{draggable-zszaW1qS.d.mts → draggable-fIYXd8eO.d.mts} +3 -3
- package/dist/js/floatable/floatable.embedded.d.mts +2 -2
- package/dist/js/floatable/floatable.embedded.mjs +17 -16
- package/dist/js/floatable/floatable.standalone.d.mts +1 -1
- package/dist/js/{floatable.embedded-YxGwzgbE.d.mts → floatable.embedded-DUR8bQBK.d.mts} +1 -2
- package/dist/js/focus-trap/focus-trap.embedded.mjs +6 -5
- package/dist/js/index.d.mts +2 -2
- package/dist/js/index.mjs +1 -0
- package/dist/js/internal/attributable.mjs +3 -4
- package/dist/js/internal/draggable.d.mts +1 -1
- package/dist/js/internal/draggable.mjs +11 -8
- package/dist/js/internal/navigable.d.mts +32 -0
- package/dist/js/internal/navigable.mjs +107 -0
- package/dist/js/menu.d.mts +1 -0
- package/dist/js/menu.mjs +168 -0
- package/dist/js/movable/movable.embedded.d.mts +1 -1
- package/dist/js/movable/movable.embedded.mjs +8 -13
- package/dist/js/movable/movable.standalone.d.mts +1 -1
- package/dist/js/popover.d.mts +1 -1
- package/dist/js/popover.mjs +28 -13
- package/dist/js/resizable/resizable.embedded.mjs +16 -11
- package/dist/js/sortable/sortable.embedded.d.mts +1 -1
- package/dist/js/sortable/sortable.embedded.mjs +15 -13
- package/dist/js/sortable/sortable.standalone.d.mts +1 -1
- package/dist/js/splitter.mjs +29 -25
- package/dist/js/toolbar.mjs +12 -88
- package/dist/js/tooltip.d.mts +1 -1
- package/dist/js/tooltip.mjs +12 -17
- package/package.json +7 -3
- package/src/js/dialog.ts +22 -26
- package/src/js/floatable/floatable.embedded.ts +19 -18
- package/src/js/focus-trap/focus-trap.embedded.ts +6 -5
- package/src/js/index.ts +1 -0
- package/src/js/internal/attributable.ts +3 -5
- package/src/js/internal/draggable.ts +12 -9
- package/src/js/internal/navigable.ts +247 -0
- package/src/js/menu.ts +345 -0
- package/src/js/movable/movable.embedded.ts +10 -13
- package/src/js/popover.ts +42 -16
- package/src/js/resizable/resizable.embedded.ts +17 -10
- package/src/js/sortable/sortable.embedded.ts +17 -22
- package/src/js/splitter.ts +40 -35
- package/src/js/toolbar.ts +27 -178
- package/src/js/tooltip.ts +18 -30
package/dist/js/dialog.d.mts
CHANGED
package/dist/js/dialog.mjs
CHANGED
|
@@ -3,7 +3,10 @@ import { attributable } from "./internal/attributable.mjs";
|
|
|
3
3
|
import { ATTRIBUTE_MOVABLE_HANDLE, createMovable } from "./movable/movable.embedded.mjs";
|
|
4
4
|
import "./movable/movable.standalone.mjs";
|
|
5
5
|
import { RESIZABLE_ATTRIBUTE_HANDLE, createResizable } from "./resizable/resizable.embedded.mjs";
|
|
6
|
+
import { getAria, setAria } from "@oscarpalmer/toretto/aria";
|
|
6
7
|
import { on } from "@oscarpalmer/toretto/event";
|
|
8
|
+
import { getAttribute, setAttribute } from "@oscarpalmer/toretto/attribute";
|
|
9
|
+
import { setStyles } from "@oscarpalmer/toretto/style";
|
|
7
10
|
//#region src/js/dialog.ts
|
|
8
11
|
var OuiDialog = class {
|
|
9
12
|
#state;
|
|
@@ -35,7 +38,7 @@ var OuiDialog = class {
|
|
|
35
38
|
const { element } = this.#state;
|
|
36
39
|
if (element == null || element.open) return;
|
|
37
40
|
const isModal = modal !== false;
|
|
38
|
-
element
|
|
41
|
+
setAria(element, "modal", isModal);
|
|
39
42
|
if (isModal) element.showModal();
|
|
40
43
|
else element.show();
|
|
41
44
|
}
|
|
@@ -46,7 +49,7 @@ function addDialog(element) {
|
|
|
46
49
|
}
|
|
47
50
|
function destroyDialog(state) {
|
|
48
51
|
state.element.close();
|
|
49
|
-
state.element
|
|
52
|
+
setAria(state.element, "modal", state.modal);
|
|
50
53
|
state.element.removeAttribute(ATTRIBUTE_OPEN);
|
|
51
54
|
for (const listener of state.listeners) listener();
|
|
52
55
|
state.movable?.destroy();
|
|
@@ -69,39 +72,40 @@ function getDialog(element) {
|
|
|
69
72
|
function getMovable(element) {
|
|
70
73
|
const handles = element.querySelectorAll(SELECTOR_MOVER);
|
|
71
74
|
if (handles.length === 0) return;
|
|
72
|
-
for (const handle of handles)
|
|
73
|
-
return createMovable(element, { container:
|
|
75
|
+
for (const handle of handles) setAttribute(handle, ATTRIBUTE_MOVABLE_HANDLE, "");
|
|
76
|
+
return createMovable(element, { container: getAttribute(element, ATTRIBUTE_CONTAINER) });
|
|
74
77
|
}
|
|
75
78
|
function getResizable(element) {
|
|
76
79
|
const handle = element.querySelector(SELECTOR_RESIZER);
|
|
77
80
|
if (handle == null) return;
|
|
78
|
-
|
|
81
|
+
setAttribute(handle, RESIZABLE_ATTRIBUTE_HANDLE, "");
|
|
79
82
|
return createResizable(element);
|
|
80
83
|
}
|
|
81
84
|
function getState(element) {
|
|
82
85
|
const state = {
|
|
83
86
|
element,
|
|
84
87
|
dialog: void 0,
|
|
85
|
-
listeners: [getOnBeforeToggleListener(element), on(element,
|
|
88
|
+
listeners: [getOnBeforeToggleListener(element), on(element, "toggle", (event) => {
|
|
86
89
|
const { source } = event;
|
|
87
90
|
if (element.open) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
element.setAttribute(ATTRIBUTE_OPEN, "");
|
|
91
|
+
setAria(element, "modal", source instanceof HTMLButtonElement && source.command === "show-modal" || element.matches(":modal"));
|
|
92
|
+
setAttribute(element, ATTRIBUTE_OPEN, "");
|
|
91
93
|
element.focus();
|
|
92
94
|
setTimeout(() => {
|
|
93
95
|
state.resizable?.set();
|
|
94
96
|
}, 500);
|
|
95
97
|
} else {
|
|
96
|
-
element
|
|
97
|
-
element
|
|
98
|
-
element
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
setAttribute(element, ATTRIBUTE_OPEN);
|
|
99
|
+
setAria(element, "modal", state.modal);
|
|
100
|
+
setStyles(element, {
|
|
101
|
+
inset: "",
|
|
102
|
+
position: "",
|
|
103
|
+
transform: ""
|
|
104
|
+
});
|
|
101
105
|
state.resizable?.reset();
|
|
102
106
|
}
|
|
103
107
|
})],
|
|
104
|
-
modal: element
|
|
108
|
+
modal: getAria(element, "modal") === "true" || element.matches(":modal")
|
|
105
109
|
};
|
|
106
110
|
state.dialog = new OuiDialog(state);
|
|
107
111
|
state.movable = getMovable(element);
|
|
@@ -114,17 +118,12 @@ function removeDialog(element) {
|
|
|
114
118
|
destroyDialog(state);
|
|
115
119
|
states.delete(element);
|
|
116
120
|
}
|
|
117
|
-
const ARIA_MODAL = "aria-modal";
|
|
118
121
|
const ATTRIBUTE = "oui-dialog";
|
|
119
122
|
const ATTRIBUTE_CONTAINER = `${ATTRIBUTE}-container`;
|
|
120
123
|
const ATTRIBUTE_OPEN = `${ATTRIBUTE}-open`;
|
|
121
|
-
const COMMAND_SHOW_MODAL = "show-modal";
|
|
122
|
-
const EVENT_TOGGLE = "toggle";
|
|
123
124
|
const MESSAGE = "The element must be an instance of HTMLDialogElement";
|
|
124
125
|
const SELECTOR_MOVER = `[${ATTRIBUTE}-mover]`;
|
|
125
|
-
const SELECTOR_MODAL = ":modal";
|
|
126
126
|
const SELECTOR_RESIZER = `[${ATTRIBUTE}-resizer]`;
|
|
127
|
-
const TRUE = "true";
|
|
128
127
|
const states = /* @__PURE__ */ new WeakMap();
|
|
129
128
|
attributable(ATTRIBUTE, addDialog, removeDialog);
|
|
130
129
|
//#endregion
|
|
@@ -17,8 +17,8 @@ type OuiMovableState = {
|
|
|
17
17
|
style: OuiMovableStyle;
|
|
18
18
|
};
|
|
19
19
|
type OuiMovableStyle = {
|
|
20
|
-
inset: string;
|
|
21
|
-
position: string;
|
|
20
|
+
inset: string | undefined;
|
|
21
|
+
position: string | undefined;
|
|
22
22
|
};
|
|
23
23
|
/**
|
|
24
24
|
* Creates _(or retrieves)_ a _OuiMovable_ instance for an element
|
|
@@ -35,7 +35,7 @@ declare class OuiSortable extends OuiDraggable<OuiSortableState> {
|
|
|
35
35
|
constructor(element: HTMLElement, options?: CreateOuiDraggableOptions);
|
|
36
36
|
}
|
|
37
37
|
type OuiSortableState = {
|
|
38
|
-
connections: string | null;
|
|
38
|
+
connections: string | null | undefined;
|
|
39
39
|
origin?: HTMLElement;
|
|
40
40
|
};
|
|
41
41
|
/**
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { ATTRIBUTE_FLOATABLE, CreateOuiFloatableOptions,
|
|
1
|
+
import { a as OuiFloatablePosition, c as getOnBeforeToggleListener, i as OuiFloatableOptions, l as removeFloatable, n as CreateOuiFloatableOptions, o as createEmbeddedFloatable, r as OuiFloatable, s as createFloatable, t as ATTRIBUTE_FLOATABLE } from "../floatable.embedded-DUR8bQBK.mjs";
|
|
2
|
+
export { ATTRIBUTE_FLOATABLE, CreateOuiFloatableOptions, OuiFloatable, OuiFloatableOptions, OuiFloatablePosition, createEmbeddedFloatable, createFloatable, getOnBeforeToggleListener, removeFloatable };
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { getAria } from "@oscarpalmer/toretto/aria";
|
|
1
2
|
import { on } from "@oscarpalmer/toretto/event";
|
|
2
3
|
import { isPlainObject } from "@oscarpalmer/atoms/is";
|
|
4
|
+
import { getAttribute, setAttribute } from "@oscarpalmer/toretto/attribute";
|
|
3
5
|
import { isHTMLOrSVGElement } from "@oscarpalmer/toretto/is";
|
|
6
|
+
import { setStyle, setStyles } from "@oscarpalmer/toretto/style";
|
|
4
7
|
//#region src/js/floatable/floatable.embedded.ts
|
|
5
8
|
var OuiFloatable = class {
|
|
6
9
|
#destroyed = false;
|
|
@@ -22,11 +25,11 @@ var OuiFloatable = class {
|
|
|
22
25
|
this.#state = state;
|
|
23
26
|
const { anchor, content } = state;
|
|
24
27
|
if (standalone) {
|
|
25
|
-
|
|
28
|
+
setAttribute(content, ATTRIBUTE_FLOATABLE, "");
|
|
26
29
|
content.popover = "manual";
|
|
27
|
-
}
|
|
28
|
-
anchor
|
|
29
|
-
content
|
|
30
|
+
} else content.popover ??= "auto";
|
|
31
|
+
setStyle(anchor, "anchorName", state.name);
|
|
32
|
+
setStyle(content, "positionAnchor", state.name);
|
|
30
33
|
}
|
|
31
34
|
/**
|
|
32
35
|
* Destroy the floatable, removing it from the DOM and cleaning up references
|
|
@@ -96,9 +99,9 @@ function createInstance(anchor, content, options, standalone) {
|
|
|
96
99
|
return floatable;
|
|
97
100
|
}
|
|
98
101
|
function getOnBeforeToggleListener(element) {
|
|
99
|
-
return on(element,
|
|
102
|
+
return on(element, "beforetoggle", (event) => {
|
|
100
103
|
const { newState, source } = event;
|
|
101
|
-
if (newState === "open" && source
|
|
104
|
+
if (newState === "open" && source != null && getAria(source, "disabled") === "true") event.preventDefault();
|
|
102
105
|
}, { passive: false });
|
|
103
106
|
}
|
|
104
107
|
function getOptions(input) {
|
|
@@ -112,8 +115,8 @@ function getPosition$1(state, override) {
|
|
|
112
115
|
if (override != null && override in AREAS) return override;
|
|
113
116
|
const { anchor, options } = state;
|
|
114
117
|
if (options.attribute == null) return options.position;
|
|
115
|
-
const attribute =
|
|
116
|
-
return attribute in AREAS ? attribute : options.position;
|
|
118
|
+
const attribute = getAttribute(anchor, options.attribute);
|
|
119
|
+
return attribute != null && attribute in AREAS ? attribute : options.position;
|
|
117
120
|
}
|
|
118
121
|
function getState(anchor, content, options) {
|
|
119
122
|
return {
|
|
@@ -130,9 +133,11 @@ function removeFloatable(content) {
|
|
|
130
133
|
function setPosition(state, override) {
|
|
131
134
|
const position = getPosition$1(state, override);
|
|
132
135
|
const area = AREAS[position];
|
|
133
|
-
state.content
|
|
134
|
-
state.content
|
|
135
|
-
|
|
136
|
+
setAttribute(state.content, ATTRIBUTE_POSITION, POSITIONS[area]);
|
|
137
|
+
setStyles(state.content, {
|
|
138
|
+
positionAnchor: state.name,
|
|
139
|
+
positionArea: area
|
|
140
|
+
});
|
|
136
141
|
}
|
|
137
142
|
const AREAS = {
|
|
138
143
|
above: "block-start",
|
|
@@ -148,15 +153,11 @@ const AREAS = {
|
|
|
148
153
|
"start-bottom": "span-start start",
|
|
149
154
|
"start-top": "span-end start"
|
|
150
155
|
};
|
|
151
|
-
const ARIA_DISABLED = "aria-disabled";
|
|
152
156
|
const ATTRIBUTE_FLOATABLE = "oui-floatable";
|
|
153
157
|
const ATTRIBUTE_POSITION = "oui-position";
|
|
154
|
-
const EVENT_BEFORE = "beforetoggle";
|
|
155
|
-
const FLOATABLE_STATE_OPEN = "open";
|
|
156
158
|
const MESSAGE = "Anchor and content must be an HTMLElement or SVGElement";
|
|
157
159
|
const POSITIONS = Object.fromEntries(Object.entries(AREAS).map(([position, area]) => [area, position]));
|
|
158
|
-
const TRUE = "true";
|
|
159
160
|
const instances = /* @__PURE__ */ new WeakMap();
|
|
160
161
|
let index = 0;
|
|
161
162
|
//#endregion
|
|
162
|
-
export { ATTRIBUTE_FLOATABLE,
|
|
163
|
+
export { ATTRIBUTE_FLOATABLE, OuiFloatable, createEmbeddedFloatable, createFloatable, getOnBeforeToggleListener, removeFloatable };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as OuiFloatablePosition, n as CreateOuiFloatableOptions, r as OuiFloatable, s as createFloatable } from "../floatable.embedded-DUR8bQBK.mjs";
|
|
2
2
|
export { type CreateOuiFloatableOptions, type OuiFloatable, type OuiFloatablePosition, createFloatable };
|
|
@@ -66,6 +66,5 @@ declare function createFloatable(anchor: HTMLElement, content: HTMLElement, opti
|
|
|
66
66
|
declare function getOnBeforeToggleListener(element: HTMLElement): RemovableEventListener;
|
|
67
67
|
declare function removeFloatable(content: HTMLElement): void;
|
|
68
68
|
declare const ATTRIBUTE_FLOATABLE = "oui-floatable";
|
|
69
|
-
declare const FLOATABLE_STATE_OPEN = "open";
|
|
70
69
|
//#endregion
|
|
71
|
-
export {
|
|
70
|
+
export { OuiFloatablePosition as a, getOnBeforeToggleListener as c, OuiFloatableOptions as i, removeFloatable as l, CreateOuiFloatableOptions as n, createEmbeddedFloatable as o, OuiFloatable as r, createFloatable as s, ATTRIBUTE_FLOATABLE as t };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { attributable } from "../internal/attributable.mjs";
|
|
2
2
|
import { on } from "@oscarpalmer/toretto/event";
|
|
3
3
|
import { isPlainObject } from "@oscarpalmer/atoms/is";
|
|
4
|
+
import { setAttribute } from "@oscarpalmer/toretto/attribute";
|
|
4
5
|
import { isHTMLOrSVGElement } from "@oscarpalmer/toretto/is";
|
|
5
6
|
import { clamp } from "@oscarpalmer/atoms/number";
|
|
6
7
|
import { findAncestor } from "@oscarpalmer/toretto/find";
|
|
@@ -20,8 +21,8 @@ var OuiFocusTrap = class {
|
|
|
20
21
|
* Should focus be maintained within the _focus trap_ when clicking outside of it?
|
|
21
22
|
*/
|
|
22
23
|
set contain(value) {
|
|
23
|
-
if (value === true) this.#state.element
|
|
24
|
-
else if (value === false) this.#state.element
|
|
24
|
+
if (value === true) setAttribute(this.#state.element, ATTRIBUTE_FOCUSTRAP_CONTAIN, "");
|
|
25
|
+
else if (value === false) setAttribute(this.#state.element, ATTRIBUTE_FOCUSTRAP_CONTAIN, void 0);
|
|
25
26
|
}
|
|
26
27
|
/**
|
|
27
28
|
* Is the _focus trap_ disabled?
|
|
@@ -46,14 +47,14 @@ var OuiFocusTrap = class {
|
|
|
46
47
|
* Should the _focus trap_ allow focus to escape when pressing _Escape_?
|
|
47
48
|
*/
|
|
48
49
|
set noescape(value) {
|
|
49
|
-
if (value === true) this.#state.element
|
|
50
|
-
else if (value === false) this.#state.element
|
|
50
|
+
if (value === true) setAttribute(this.#state.element, ATTRIBUTE_FOCUSTRAP_NOESCAPE, "");
|
|
51
|
+
else if (value === false) setAttribute(this.#state.element, ATTRIBUTE_FOCUSTRAP_NOESCAPE, void 0);
|
|
51
52
|
}
|
|
52
53
|
constructor(state) {
|
|
53
54
|
this.#state = state;
|
|
54
55
|
this.#tabIndex = state.element.tabIndex;
|
|
55
56
|
state.element.tabIndex = -1;
|
|
56
|
-
state.element
|
|
57
|
+
setAttribute(state.element, ATTRIBUTE_FOCUSTRAP, "");
|
|
57
58
|
this.contain = state.options.contain;
|
|
58
59
|
this.noescape = state.options.noescape;
|
|
59
60
|
states.set(this, state);
|
package/dist/js/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { d as OuiSortable, f as createSortable, g as createMovable, h as OuiMovable, t as CreateOuiDraggableOptions } from "./draggable-
|
|
1
|
+
import { d as OuiSortable, f as createSortable, g as createMovable, h as OuiMovable, t as CreateOuiDraggableOptions } from "./draggable-fIYXd8eO.mjs";
|
|
2
2
|
import { a as createResizable, n as OuiResizable, t as CreateOuiResizableOptions } from "./resizable.embedded-CXrUVPzR.mjs";
|
|
3
3
|
import { OuiDialog, getDialog } from "./dialog.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { a as OuiFloatablePosition, n as CreateOuiFloatableOptions, r as OuiFloatable, s as createFloatable } from "./floatable.embedded-DUR8bQBK.mjs";
|
|
5
5
|
import { a as OuiFocusTrapOptions, i as OuiFocusTrap, o as createFocusTrap } from "./focus-trap.embedded-DR8NpZfr.mjs";
|
|
6
6
|
import { OuiPopover, getPopover } from "./popover.mjs";
|
|
7
7
|
import { OuiSplitterElement } from "./splitter.mjs";
|
package/dist/js/index.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { createMovable } from "./movable/movable.embedded.mjs";
|
|
|
3
3
|
import "./movable/movable.standalone.mjs";
|
|
4
4
|
import { createResizable } from "./resizable/resizable.embedded.mjs";
|
|
5
5
|
import { getDialog } from "./dialog.mjs";
|
|
6
|
+
import "./menu.mjs";
|
|
6
7
|
import "./toolbar.mjs";
|
|
7
8
|
import "./floatable/floatable.standalone.mjs";
|
|
8
9
|
import { createFocusTrap } from "./focus-trap/focus-trap.embedded.mjs";
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { isHTMLOrSVGElement } from "@oscarpalmer/toretto/is";
|
|
2
1
|
//#region src/js/internal/attributable.ts
|
|
3
2
|
function attributable(attribute, add, remove) {
|
|
4
3
|
new MutationObserver((entries) => {
|
|
5
4
|
const { length } = entries;
|
|
6
5
|
for (let index = 0; index < length; index += 1) {
|
|
7
6
|
const entry = entries[index];
|
|
8
|
-
if (entry.type === "attributes" &&
|
|
7
|
+
if (entry.type === "attributes" && entry.target instanceof Element) if (entry.target.hasAttribute(attribute)) handleAdded(attribute, [entry.target], add);
|
|
9
8
|
else handleRemoved([entry.target], remove);
|
|
10
9
|
else if (entry.type === "childList") {
|
|
11
10
|
handleAdded(attribute, entry.addedNodes, add);
|
|
@@ -23,7 +22,7 @@ function attributable(attribute, add, remove) {
|
|
|
23
22
|
});
|
|
24
23
|
}
|
|
25
24
|
function handleAdded(attribute, nodes, add) {
|
|
26
|
-
const elements = [...nodes].filter(
|
|
25
|
+
const elements = [...nodes].filter((node) => node instanceof Element);
|
|
27
26
|
const { length } = elements;
|
|
28
27
|
for (let index = 0; index < length; index += 1) {
|
|
29
28
|
const element = elements[index];
|
|
@@ -32,7 +31,7 @@ function handleAdded(attribute, nodes, add) {
|
|
|
32
31
|
}
|
|
33
32
|
}
|
|
34
33
|
function handleRemoved(nodes, remove) {
|
|
35
|
-
const elements = [...nodes].filter(
|
|
34
|
+
const elements = [...nodes].filter((node) => node instanceof Element);
|
|
36
35
|
const { length } = elements;
|
|
37
36
|
for (let index = 0; index < length; index += 1) {
|
|
38
37
|
const element = elements[index];
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as OuiDraggableGlobals, c as addDraggable, i as OuiDraggableBound, l as getDraggableStates, n as OuiDragMovePosition, o as OuiDraggableItem, r as OuiDraggable, s as OuiDraggableState, t as CreateOuiDraggableOptions, u as removeDraggable } from "../draggable-
|
|
1
|
+
import { a as OuiDraggableGlobals, c as addDraggable, i as OuiDraggableBound, l as getDraggableStates, n as OuiDragMovePosition, o as OuiDraggableItem, r as OuiDraggable, s as OuiDraggableState, t as CreateOuiDraggableOptions, u as removeDraggable } from "../draggable-fIYXd8eO.mjs";
|
|
2
2
|
export { CreateOuiDraggableOptions, OuiDragMovePosition, OuiDraggable, OuiDraggableBound, OuiDraggableGlobals, OuiDraggableItem, OuiDraggableState, addDraggable, getDraggableStates, removeDraggable };
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { getPosition, on } from "@oscarpalmer/toretto/event";
|
|
2
|
+
import { getAttribute, setAttribute } from "@oscarpalmer/toretto/attribute";
|
|
2
3
|
import { isHTMLOrSVGElement } from "@oscarpalmer/toretto/is";
|
|
4
|
+
import { setStyle, setStyles, toggleStyles } from "@oscarpalmer/toretto/style";
|
|
3
5
|
import { clamp } from "@oscarpalmer/atoms/number";
|
|
4
6
|
import { findAncestor } from "@oscarpalmer/toretto/find";
|
|
5
|
-
import { toggleStyles } from "@oscarpalmer/toretto/style";
|
|
6
7
|
import supportsTouch from "@oscarpalmer/toretto/touch";
|
|
7
8
|
//#region src/js/internal/draggable.ts
|
|
8
9
|
var OuiDraggable = class {
|
|
@@ -30,7 +31,7 @@ var OuiDraggable = class {
|
|
|
30
31
|
};
|
|
31
32
|
setContainer(item);
|
|
32
33
|
setDirection(item);
|
|
33
|
-
|
|
34
|
+
setAttribute(element, attribute, "");
|
|
34
35
|
let states = globals.states.get(element);
|
|
35
36
|
states ??= {};
|
|
36
37
|
states[this.#name] = this.#state;
|
|
@@ -142,9 +143,11 @@ function onPointerdown(event) {
|
|
|
142
143
|
return;
|
|
143
144
|
}
|
|
144
145
|
const next = getNextPosition(item, position);
|
|
145
|
-
dragged
|
|
146
|
-
|
|
147
|
-
|
|
146
|
+
setStyles(dragged, {
|
|
147
|
+
position: "fixed",
|
|
148
|
+
inset: `${next.y}px auto auto ${next.x}px`,
|
|
149
|
+
transform: "translate3d(0, 0, 0)"
|
|
150
|
+
});
|
|
148
151
|
item.state.options.drag.onBegin?.(event, globals, item, element, handle, next);
|
|
149
152
|
item.state.styling.set();
|
|
150
153
|
styleToggler.set();
|
|
@@ -155,7 +158,7 @@ function onPointermove(event) {
|
|
|
155
158
|
const position = getPosition(event);
|
|
156
159
|
if (position == null) return;
|
|
157
160
|
const next = getNextPosition(current, position);
|
|
158
|
-
if (globals.element != null) globals.element.node
|
|
161
|
+
if (globals.element != null) setStyle(globals.element.node, "inset", `${next.y}px auto auto ${next.x}px`);
|
|
159
162
|
const detail = current.state.options.drag.onMove(event, globals, current, {
|
|
160
163
|
calculated: next,
|
|
161
164
|
original: position
|
|
@@ -192,7 +195,7 @@ function setContainer(item) {
|
|
|
192
195
|
setContainerElement(item, container);
|
|
193
196
|
return;
|
|
194
197
|
}
|
|
195
|
-
const selector = container ?? item.instance.element
|
|
198
|
+
const selector = container ?? getAttribute(item.instance.element, item.state.options.container.attribute);
|
|
196
199
|
if (typeof selector !== "string") return;
|
|
197
200
|
const element = containers.has(selector) ? item.state.element.ownerDocument.body : document.querySelector(selector) ?? void 0;
|
|
198
201
|
if (isHTMLOrSVGElement(element)) setContainerElement(item, element);
|
|
@@ -205,7 +208,7 @@ function setContainerElement(item, element) {
|
|
|
205
208
|
item.state.options.container.onInitialize?.(item);
|
|
206
209
|
}
|
|
207
210
|
function setDirection(item) {
|
|
208
|
-
const direction = item.state.element
|
|
211
|
+
const direction = getAttribute(item.state.element, item.state.options.direction.attribute);
|
|
209
212
|
if (horizontals.has(direction)) item.state.vertical = false;
|
|
210
213
|
else if (verticals.has(direction)) item.state.horizontal = false;
|
|
211
214
|
item.state.options.direction.onAfter?.(item);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { AriaRole, RemovableEventListener } from "@oscarpalmer/toretto/models";
|
|
2
|
+
|
|
3
|
+
//#region src/js/internal/navigable.d.ts
|
|
4
|
+
declare class OuiNavigable {
|
|
5
|
+
active: OuiNavigableActive;
|
|
6
|
+
element: HTMLElement;
|
|
7
|
+
listeners: RemovableEventListener[];
|
|
8
|
+
options: OuiNavigableOptions;
|
|
9
|
+
orientation: OuiNavigableOrientation;
|
|
10
|
+
constructor(element: HTMLElement, options: OuiNavigableOptions);
|
|
11
|
+
destroy(): void;
|
|
12
|
+
}
|
|
13
|
+
type OuiNavigableActive = {
|
|
14
|
+
element?: HTMLElement;
|
|
15
|
+
index: number;
|
|
16
|
+
};
|
|
17
|
+
type OuiNavigableOptions = {
|
|
18
|
+
role?: AriaRole;
|
|
19
|
+
selector: string;
|
|
20
|
+
vertical: boolean;
|
|
21
|
+
onDeactivate?: (event: KeyboardEvent, navigable: OuiNavigable) => void;
|
|
22
|
+
onPreventNavigation?: (event: KeyboardEvent, navigable: OuiNavigable) => boolean;
|
|
23
|
+
onShouldActivate?: (event: KeyboardEvent, navigable: OuiNavigable) => boolean;
|
|
24
|
+
onShouldDeactivate?: (event: KeyboardEvent, navigable: OuiNavigable) => boolean | undefined;
|
|
25
|
+
};
|
|
26
|
+
type OuiNavigableOrientation = 'horizontal' | 'vertical';
|
|
27
|
+
declare function getNavigable(element: HTMLElement, options: OuiNavigableOptions): OuiNavigable;
|
|
28
|
+
declare function updateNavigableFocus(navigable: OuiNavigable, focus: boolean, items?: HTMLElement[]): void;
|
|
29
|
+
declare const NAVIGABLE_KEYS_HORIZONTAL: Set<string>;
|
|
30
|
+
declare const NAVIGABLE_KEYS_VERTICAL: Set<string>;
|
|
31
|
+
//#endregion
|
|
32
|
+
export { NAVIGABLE_KEYS_HORIZONTAL, NAVIGABLE_KEYS_VERTICAL, OuiNavigable, OuiNavigableOptions, getNavigable, updateNavigableFocus };
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { getAria, setRole } from "@oscarpalmer/toretto/aria";
|
|
2
|
+
import { on } from "@oscarpalmer/toretto/event";
|
|
3
|
+
import { isHTMLOrSVGElement } from "@oscarpalmer/toretto/is";
|
|
4
|
+
import { clamp } from "@oscarpalmer/atoms/number";
|
|
5
|
+
import { findAncestor } from "@oscarpalmer/toretto/find";
|
|
6
|
+
//#region src/js/internal/navigable.ts
|
|
7
|
+
var OuiNavigable = class {
|
|
8
|
+
active = { index: 0 };
|
|
9
|
+
element;
|
|
10
|
+
listeners;
|
|
11
|
+
options;
|
|
12
|
+
orientation;
|
|
13
|
+
constructor(element, options) {
|
|
14
|
+
this.element = element;
|
|
15
|
+
this.options = options;
|
|
16
|
+
this.listeners = [on(element, "focusin", (event) => {
|
|
17
|
+
onFocusin(this, event);
|
|
18
|
+
}), on(element, "keydown", (event) => {
|
|
19
|
+
onKeydown(this, event);
|
|
20
|
+
})];
|
|
21
|
+
this.orientation = getOrientation(element, options);
|
|
22
|
+
if (options.role != null) setRole(element, options.role);
|
|
23
|
+
}
|
|
24
|
+
destroy() {
|
|
25
|
+
const listeners = this.listeners.splice(0);
|
|
26
|
+
for (const listener of listeners) listener();
|
|
27
|
+
this.active.element = void 0;
|
|
28
|
+
this.element = void 0;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
function getItems(container, selector) {
|
|
32
|
+
return [...container.querySelectorAll(selector)].filter(isValidItem);
|
|
33
|
+
}
|
|
34
|
+
function getNavigable(element, options) {
|
|
35
|
+
return new OuiNavigable(element, options);
|
|
36
|
+
}
|
|
37
|
+
function getOrientation(element, options) {
|
|
38
|
+
const attribute = getAria(element, "orientation");
|
|
39
|
+
return ORIENTATIONS.has(attribute) ? attribute : options.vertical ? ORIENTATION_VERTICAL : ORIENTATION_HORIZONTAL;
|
|
40
|
+
}
|
|
41
|
+
function isValidItem(element) {
|
|
42
|
+
return "disabled" in element ? element.disabled !== true : true;
|
|
43
|
+
}
|
|
44
|
+
function onFocusin(navigable, event) {
|
|
45
|
+
const item = findAncestor(event, navigable.options.selector);
|
|
46
|
+
if (!isHTMLOrSVGElement(item) || !isValidItem(item)) return;
|
|
47
|
+
const items = getItems(navigable.element, navigable.options.selector);
|
|
48
|
+
const index = items.indexOf(item);
|
|
49
|
+
if (index === -1) return;
|
|
50
|
+
navigable.active.element = item;
|
|
51
|
+
navigable.active.index = index;
|
|
52
|
+
updateNavigableFocus(navigable, false, items);
|
|
53
|
+
}
|
|
54
|
+
function onKeydown(navigable, event) {
|
|
55
|
+
const escaped = event.key === "Escape";
|
|
56
|
+
const stopPropagation = navigable.options.onShouldDeactivate?.(event, navigable);
|
|
57
|
+
if (escaped || stopPropagation != null) {
|
|
58
|
+
if (escaped || stopPropagation) event.stopPropagation();
|
|
59
|
+
navigable.options.onDeactivate?.(event, navigable);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (!KEYS_ALL.has(event.key)) return;
|
|
63
|
+
const mustActivate = KEYS_ACTIVATE.has(event.key);
|
|
64
|
+
const shouldActivate = navigable.options.onShouldActivate?.(event, navigable) === true;
|
|
65
|
+
if (mustActivate || shouldActivate || navigable.options.onPreventNavigation?.(event, navigable) === true) event.stopPropagation();
|
|
66
|
+
if (mustActivate || shouldActivate) return;
|
|
67
|
+
const items = getItems(navigable.element, navigable.options.selector);
|
|
68
|
+
const { length } = items;
|
|
69
|
+
if (length === 0) return;
|
|
70
|
+
let index;
|
|
71
|
+
if (KEYS_ABSOLUTE.has(event.key)) index = event.key === "Home" ? 0 : items.length - 1;
|
|
72
|
+
else {
|
|
73
|
+
const direction = NAVIGABLE_KEYS_HORIZONTAL.has(event.key) ? ORIENTATION_HORIZONTAL : ORIENTATION_VERTICAL;
|
|
74
|
+
if (navigable.orientation === direction) {
|
|
75
|
+
if (navigable.active.element instanceof HTMLSelectElement) event.preventDefault();
|
|
76
|
+
index = clamp(navigable.active.index + (KEYS_NEXT.has(event.key) ? 1 : -1), 0, length - 1, true);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (index == null || index === navigable.active.index) return;
|
|
80
|
+
navigable.active.element = items[index];
|
|
81
|
+
navigable.active.index = index;
|
|
82
|
+
updateNavigableFocus(navigable, true, items);
|
|
83
|
+
}
|
|
84
|
+
function updateNavigableFocus(navigable, focus, items) {
|
|
85
|
+
const updated = items ?? getItems(navigable.element, navigable.options.selector);
|
|
86
|
+
const { length } = updated;
|
|
87
|
+
if (length === 0) return;
|
|
88
|
+
for (let index = 0; index < length; index += 1) updated[index].tabIndex = index === navigable.active.index ? 0 : -1;
|
|
89
|
+
navigable.active.element ??= updated[navigable.active.index];
|
|
90
|
+
if (focus) navigable.active.element?.focus();
|
|
91
|
+
}
|
|
92
|
+
const KEYS_ABSOLUTE = /* @__PURE__ */ new Set(["End", "Home"]);
|
|
93
|
+
const KEYS_ACTIVATE = /* @__PURE__ */ new Set(["Enter", " "]);
|
|
94
|
+
const NAVIGABLE_KEYS_HORIZONTAL = /* @__PURE__ */ new Set(["ArrowRight", "ArrowLeft"]);
|
|
95
|
+
const NAVIGABLE_KEYS_VERTICAL = /* @__PURE__ */ new Set(["ArrowDown", "ArrowUp"]);
|
|
96
|
+
const KEYS_ALL = /* @__PURE__ */ new Set([
|
|
97
|
+
...KEYS_ABSOLUTE,
|
|
98
|
+
...KEYS_ACTIVATE,
|
|
99
|
+
...NAVIGABLE_KEYS_HORIZONTAL,
|
|
100
|
+
...NAVIGABLE_KEYS_VERTICAL
|
|
101
|
+
]);
|
|
102
|
+
const KEYS_NEXT = /* @__PURE__ */ new Set(["ArrowDown", "ArrowRight"]);
|
|
103
|
+
const ORIENTATION_HORIZONTAL = "horizontal";
|
|
104
|
+
const ORIENTATION_VERTICAL = "vertical";
|
|
105
|
+
const ORIENTATIONS = /* @__PURE__ */ new Set([ORIENTATION_HORIZONTAL, ORIENTATION_VERTICAL]);
|
|
106
|
+
//#endregion
|
|
107
|
+
export { NAVIGABLE_KEYS_HORIZONTAL, NAVIGABLE_KEYS_VERTICAL, OuiNavigable, getNavigable, updateNavigableFocus };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|