@oscarpalmer/oui 0.28.0 → 0.29.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.
Files changed (46) hide show
  1. package/dist/js/dialog.d.mts +1 -1
  2. package/dist/js/dialog.mjs +19 -20
  3. package/dist/js/{draggable-zszaW1qS.d.mts → draggable-fIYXd8eO.d.mts} +3 -3
  4. package/dist/js/floatable/floatable.embedded.d.mts +2 -2
  5. package/dist/js/floatable/floatable.embedded.mjs +17 -16
  6. package/dist/js/floatable/floatable.standalone.d.mts +1 -1
  7. package/dist/js/{floatable.embedded-YxGwzgbE.d.mts → floatable.embedded-DUR8bQBK.d.mts} +1 -2
  8. package/dist/js/focus-trap/focus-trap.embedded.mjs +6 -5
  9. package/dist/js/index.d.mts +2 -2
  10. package/dist/js/index.mjs +1 -0
  11. package/dist/js/internal/attributable.mjs +3 -4
  12. package/dist/js/internal/draggable.d.mts +1 -1
  13. package/dist/js/internal/draggable.mjs +11 -8
  14. package/dist/js/internal/navigable.d.mts +32 -0
  15. package/dist/js/internal/navigable.mjs +107 -0
  16. package/dist/js/menu.d.mts +1 -0
  17. package/dist/js/menu.mjs +168 -0
  18. package/dist/js/movable/movable.embedded.d.mts +1 -1
  19. package/dist/js/movable/movable.embedded.mjs +8 -13
  20. package/dist/js/movable/movable.standalone.d.mts +1 -1
  21. package/dist/js/popover.d.mts +1 -1
  22. package/dist/js/popover.mjs +27 -12
  23. package/dist/js/resizable/resizable.embedded.mjs +16 -11
  24. package/dist/js/sortable/sortable.embedded.d.mts +1 -1
  25. package/dist/js/sortable/sortable.embedded.mjs +15 -13
  26. package/dist/js/sortable/sortable.standalone.d.mts +1 -1
  27. package/dist/js/splitter.mjs +29 -25
  28. package/dist/js/toolbar.mjs +12 -88
  29. package/dist/js/tooltip.d.mts +1 -1
  30. package/dist/js/tooltip.mjs +12 -17
  31. package/package.json +7 -3
  32. package/src/js/dialog.ts +22 -26
  33. package/src/js/floatable/floatable.embedded.ts +19 -18
  34. package/src/js/focus-trap/focus-trap.embedded.ts +6 -5
  35. package/src/js/index.ts +1 -0
  36. package/src/js/internal/attributable.ts +3 -5
  37. package/src/js/internal/draggable.ts +12 -9
  38. package/src/js/internal/navigable.ts +247 -0
  39. package/src/js/menu.ts +345 -0
  40. package/src/js/movable/movable.embedded.ts +10 -13
  41. package/src/js/popover.ts +41 -15
  42. package/src/js/resizable/resizable.embedded.ts +17 -10
  43. package/src/js/sortable/sortable.embedded.ts +17 -22
  44. package/src/js/splitter.ts +40 -35
  45. package/src/js/toolbar.ts +27 -178
  46. package/src/js/tooltip.ts +18 -30
@@ -1,4 +1,4 @@
1
- import { h as OuiMovable } from "./draggable-zszaW1qS.mjs";
1
+ import { h as OuiMovable } from "./draggable-fIYXd8eO.mjs";
2
2
  import { n as OuiResizable } from "./resizable.embedded-CXrUVPzR.mjs";
3
3
  import { RemovableEventListener } from "@oscarpalmer/toretto/models";
4
4
 
@@ -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.setAttribute(ARIA_MODAL, String(isModal));
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.setAttribute(ARIA_MODAL, String(state.modal));
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) handle.setAttribute(ATTRIBUTE_MOVABLE_HANDLE, "");
73
- return createMovable(element, { container: element.getAttribute(ATTRIBUTE_CONTAINER) ?? void 0 });
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
- handle.setAttribute(RESIZABLE_ATTRIBUTE_HANDLE, "");
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, EVENT_TOGGLE, (event) => {
88
+ listeners: [getOnBeforeToggleListener(element), on(element, "toggle", (event) => {
86
89
  const { source } = event;
87
90
  if (element.open) {
88
- const modal = source instanceof HTMLButtonElement && source.command === COMMAND_SHOW_MODAL || element.matches(SELECTOR_MODAL);
89
- element.setAttribute(ARIA_MODAL, String(modal));
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.removeAttribute(ATTRIBUTE_OPEN);
97
- element.setAttribute(ARIA_MODAL, String(state.modal));
98
- element.style.inset = "";
99
- element.style.position = "";
100
- element.style.transform = "";
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.getAttribute(ARIA_MODAL) === TRUE
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 OuiFloatableOptions, c as createFloatable, i as OuiFloatable, l as getOnBeforeToggleListener, n as CreateOuiFloatableOptions, o as OuiFloatablePosition, r as FLOATABLE_STATE_OPEN, s as createEmbeddedFloatable, t as ATTRIBUTE_FLOATABLE, u as removeFloatable } from "../floatable.embedded-YxGwzgbE.mjs";
2
- export { ATTRIBUTE_FLOATABLE, CreateOuiFloatableOptions, FLOATABLE_STATE_OPEN, OuiFloatable, OuiFloatableOptions, OuiFloatablePosition, createEmbeddedFloatable, createFloatable, getOnBeforeToggleListener, removeFloatable };
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
- content.setAttribute(ATTRIBUTE_FLOATABLE, "");
28
+ setAttribute(content, ATTRIBUTE_FLOATABLE, "");
26
29
  content.popover = "manual";
27
- }
28
- anchor.style.anchorName = state.name;
29
- content.style.positionAnchor = state.name;
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, EVENT_BEFORE, (event) => {
102
+ return on(element, "beforetoggle", (event) => {
100
103
  const { newState, source } = event;
101
- if (newState === "open" && source?.getAttribute(ARIA_DISABLED) === TRUE) event.preventDefault();
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 = anchor.getAttribute(options.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.style.positionAnchor = state.name;
134
- state.content.style.positionArea = area;
135
- state.content.setAttribute(ATTRIBUTE_POSITION, POSITIONS[area]);
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, FLOATABLE_STATE_OPEN, OuiFloatable, createEmbeddedFloatable, createFloatable, getOnBeforeToggleListener, removeFloatable };
163
+ export { ATTRIBUTE_FLOATABLE, OuiFloatable, createEmbeddedFloatable, createFloatable, getOnBeforeToggleListener, removeFloatable };
@@ -1,2 +1,2 @@
1
- import { c as createFloatable, i as OuiFloatable, n as CreateOuiFloatableOptions, o as OuiFloatablePosition } from "../floatable.embedded-YxGwzgbE.mjs";
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 { OuiFloatableOptions as a, createFloatable as c, OuiFloatable as i, getOnBeforeToggleListener as l, CreateOuiFloatableOptions as n, OuiFloatablePosition as o, FLOATABLE_STATE_OPEN as r, createEmbeddedFloatable as s, ATTRIBUTE_FLOATABLE as t, removeFloatable as u };
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.setAttribute(ATTRIBUTE_FOCUSTRAP_CONTAIN, "");
24
- else if (value === false) this.#state.element.removeAttribute(ATTRIBUTE_FOCUSTRAP_CONTAIN);
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.setAttribute(ATTRIBUTE_FOCUSTRAP_NOESCAPE, "");
50
- else if (value === false) this.#state.element.removeAttribute(ATTRIBUTE_FOCUSTRAP_NOESCAPE);
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.setAttribute(ATTRIBUTE_FOCUSTRAP, "");
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);
@@ -1,7 +1,7 @@
1
- import { d as OuiSortable, f as createSortable, g as createMovable, h as OuiMovable, t as CreateOuiDraggableOptions } from "./draggable-zszaW1qS.mjs";
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 { c as createFloatable, i as OuiFloatable, n as CreateOuiFloatableOptions, o as OuiFloatablePosition } from "./floatable.embedded-YxGwzgbE.mjs";
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" && isHTMLOrSVGElement(entry.target)) if (entry.target.hasAttribute(attribute)) handleAdded(attribute, [entry.target], add);
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(isHTMLOrSVGElement);
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(isHTMLOrSVGElement);
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-zszaW1qS.mjs";
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
- element.setAttribute(attribute, "");
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.style.position = "fixed";
146
- dragged.style.inset = `${next.y}px auto auto ${next.x}px`;
147
- dragged.style.transform = "translate3d(0, 0, 0)";
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.style.inset = `${next.y}px auto auto ${next.x}px`;
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.getAttribute(item.state.options.container.attribute);
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.getAttribute(item.state.options.direction.attribute);
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 { };