@oscarpalmer/oui 0.19.0 → 0.21.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 (63) hide show
  1. package/dist/css/a11y.css +0 -1
  2. package/dist/css/form.css +0 -1
  3. package/dist/css/popover.css +22 -0
  4. package/dist/css/reset.css +8 -8
  5. package/dist/css/table.css +1 -1
  6. package/dist/css/tooltip.css +43 -0
  7. package/dist/js/focus-trap/embedded.d.mts +26 -0
  8. package/dist/js/focus-trap/{embedded.js → embedded.mjs} +11 -9
  9. package/dist/js/focus-trap/standalone.d.mts +1 -0
  10. package/dist/js/focus-trap/{standalone.js → standalone.mjs} +5 -2
  11. package/dist/js/index.d.mts +4 -0
  12. package/dist/js/index.mjs +7 -0
  13. package/dist/js/internal/attributable.d.mts +4 -0
  14. package/dist/js/{attributable.full.js → internal/attributable.mjs} +8 -1
  15. package/dist/js/internal/draggable.d.mts +2 -0
  16. package/dist/js/internal/draggable.mjs +212 -0
  17. package/dist/js/internal/floatable.d.mts +26 -0
  18. package/dist/js/{floatable.js → internal/floatable.mjs} +73 -50
  19. package/dist/js/movable-BEo2LbUI.d.mts +101 -0
  20. package/dist/js/movable.d.mts +2 -0
  21. package/dist/js/movable.mjs +152 -0
  22. package/dist/js/popover.d.mts +20 -0
  23. package/dist/js/{popover.js → popover.mjs} +10 -8
  24. package/dist/js/sortable.d.mts +2 -0
  25. package/dist/js/sortable.mjs +243 -0
  26. package/dist/js/splitter.d.mts +25 -0
  27. package/dist/js/{splitter.js → splitter.mjs} +62 -60
  28. package/dist/js/tooltip.d.mts +4 -0
  29. package/dist/js/{tooltip.js → tooltip.mjs} +22 -20
  30. package/package.json +66 -69
  31. package/src/css/mixins.scss +30 -1
  32. package/src/css/popover.scss +6 -1
  33. package/src/css/reset.scss +4 -4
  34. package/src/css/table.scss +1 -1
  35. package/src/css/tooltip.scss +55 -1
  36. package/src/js/focus-trap/embedded.ts +4 -10
  37. package/src/js/focus-trap/standalone.ts +1 -1
  38. package/src/js/index.ts +3 -1
  39. package/src/js/{attributable.ts → internal/attributable.ts} +11 -1
  40. package/src/js/internal/draggable.ts +515 -0
  41. package/src/js/{floatable.ts → internal/floatable.ts} +141 -63
  42. package/src/js/movable.ts +260 -0
  43. package/src/js/popover.ts +1 -1
  44. package/src/js/sortable.ts +467 -0
  45. package/src/js/splitter.ts +3 -9
  46. package/src/js/tooltip.ts +11 -9
  47. package/dist/js/attributable.js +0 -36
  48. package/dist/js/floatable.full.js +0 -398
  49. package/dist/js/focus-trap/embedded.full.js +0 -408
  50. package/dist/js/focus-trap/standalone.full.js +0 -447
  51. package/dist/js/index.js +0 -5
  52. package/dist/js/oui.full.js +0 -1573
  53. package/dist/js/popover.full.js +0 -760
  54. package/dist/js/splitter.full.js +0 -769
  55. package/dist/js/tooltip.full.js +0 -613
  56. package/types/attributable.d.ts +0 -1
  57. package/types/floatable.d.ts +0 -24
  58. package/types/focus-trap/embedded.d.ts +0 -24
  59. package/types/focus-trap/standalone.d.ts +0 -1
  60. package/types/index.d.ts +0 -4
  61. package/types/popover.d.ts +0 -17
  62. package/types/splitter.d.ts +0 -23
  63. package/types/tooltip.d.ts +0 -2
package/dist/css/a11y.css CHANGED
@@ -7,7 +7,6 @@
7
7
  width: 1px !important;
8
8
  height: 1px !important;
9
9
  padding: 0 !important;
10
- clip: rect(1px, 1px 1px, 1px) !important;
11
10
  clip-path: inset(50%) !important;
12
11
  overflow: hidden !important;
13
12
  border: 0 !important;
package/dist/css/form.css CHANGED
@@ -711,7 +711,6 @@
711
711
  width: 1px !important;
712
712
  height: 1px !important;
713
713
  padding: 0 !important;
714
- clip: rect(1px, 1px 1px, 1px) !important;
715
714
  clip-path: inset(50%) !important;
716
715
  overflow: hidden !important;
717
716
  border: 0 !important;
@@ -1,12 +1,34 @@
1
1
 
2
2
  :where([oui-popover-content]) {
3
3
  box-shadow: inset 0 1px 0 0 transparent, 0 0 0 1px rgba(0, 0, 0, 0.05), 0 1px 2px -0.5px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.05), 0 4px 8px -2px rgba(0, 0, 0, 0.05), 0 8px 16px -4px rgba(0, 0, 0, 0.05), 0 16px 32px -8px rgba(0, 0, 0, 0.05), 0 32px 64px -16px rgba(0, 0, 0, 0.05), 0 64px 128px -32px rgba(0, 0, 0, 0.05);
4
+ --margin-left: 0;
5
+ --margin-top: 0;
6
+ margin: var(--margin-top, 0) 0 0 var(--margin-left, 0);
7
+ pointer-events: all !important;
8
+ }
9
+ :where([oui-popover-content])[position^=above], :where([oui-popover-content])[position^=top] {
10
+ --margin-top: -0.5rem;
11
+ }
12
+ :where([oui-popover-content])[position^=below], :where([oui-popover-content])[position^=bottom] {
13
+ --margin-top: 0.5rem;
14
+ }
15
+ :where([oui-popover-content])[position^=end], :where([oui-popover-content])[position^=right] {
16
+ --margin-left: 0.5rem;
17
+ }
18
+ :where([oui-popover-content])[position^=left], :where([oui-popover-content])[position^=start] {
19
+ --margin-left: -0.5rem;
20
+ }
21
+ :where([oui-popover-content]) {
4
22
  padding: 1rem;
23
+ overscroll-behavior: contain;
5
24
  background-color: var(--oui-absolute);
6
25
  border-radius: 0.5rem;
7
26
  }
8
27
  :where([oui-popover-content]):focus {
9
28
  outline: none;
10
29
  }
30
+ :where([oui-popover-content]) * {
31
+ overscroll-behavior: contain;
32
+ }
11
33
 
12
34
 
@@ -56,7 +56,7 @@
56
56
  -moz-tab-size: 4;
57
57
  -o-tab-size: 4;
58
58
  tab-size: 4;
59
- word-break: break-word;
59
+ overflow-wrap: break-word;
60
60
  }
61
61
 
62
62
  :where(body) {
@@ -105,9 +105,9 @@ input[type=reset i],
105
105
  input[type=submit i],
106
106
  summary) {
107
107
  /** Correct the inability to style clickable types in iOS [HR][RS][SE] */
108
- -webkit-appearance: button;
109
- -moz-appearance: button;
110
- appearance: button;
108
+ -webkit-appearance: auto;
109
+ -moz-appearance: auto;
110
+ appearance: auto;
111
111
  /** Ditto */
112
112
  cursor: pointer;
113
113
  }
@@ -174,7 +174,7 @@ summary) {
174
174
  }
175
175
 
176
176
  :where(small, sub, sup) {
177
- font-size: 0.875rem;
177
+ font-size: 0.875em;
178
178
  }
179
179
 
180
180
  :where(sub, sup) {
@@ -277,9 +277,9 @@ summary) {
277
277
 
278
278
  ::file-selector-button {
279
279
  /** Correct the inability to style upload buttons in iOS and Safari [RS][SE] */
280
- -webkit-appearance: button;
281
- -moz-appearance: button;
282
- appearance: button;
280
+ -webkit-appearance: auto;
281
+ -moz-appearance: auto;
282
+ appearance: auto;
283
283
  color: inherit;
284
284
  font: inherit;
285
285
  line-height: 1.25;
@@ -6,10 +6,10 @@
6
6
  :where(.oui-table_wrapper) {
7
7
  max-height: 32em;
8
8
  overflow: auto;
9
+ overscroll-behavior: contain;
9
10
  border: 1px solid var(--oui-gray-3);
10
11
  border-radius: 0.25em;
11
12
  position: relative;
12
- overscroll-behavior-y: none;
13
13
  }
14
14
  :where(.oui-table caption) {
15
15
  height: 2rem;
@@ -27,6 +27,24 @@ var)) {
27
27
 
28
28
  :where([oui-tooltip-content]) {
29
29
  box-shadow: inset 0 1px 0 0 transparent, 0 0 0 1px rgba(0, 0, 0, 0.05), 0 1px 2px -0.5px rgba(0, 0, 0, 0.05), 0 2px 4px -1px rgba(0, 0, 0, 0.05), 0 4px 8px -2px rgba(0, 0, 0, 0.05), 0 8px 16px -4px rgba(0, 0, 0, 0.05), 0 16px 32px -8px rgba(0, 0, 0, 0.05), 0 32px 64px -16px rgba(0, 0, 0, 0.05), 0 64px 128px -32px rgba(0, 0, 0, 0.05);
30
+ --margin-left: 0;
31
+ --margin-top: 0;
32
+ margin: var(--margin-top, 0) 0 0 var(--margin-left, 0);
33
+ pointer-events: all !important;
34
+ }
35
+ :where([oui-tooltip-content])[position^=above], :where([oui-tooltip-content])[position^=top] {
36
+ --margin-top: -0.5rem;
37
+ }
38
+ :where([oui-tooltip-content])[position^=below], :where([oui-tooltip-content])[position^=bottom] {
39
+ --margin-top: 0.5rem;
40
+ }
41
+ :where([oui-tooltip-content])[position^=end], :where([oui-tooltip-content])[position^=right] {
42
+ --margin-left: 0.5rem;
43
+ }
44
+ :where([oui-tooltip-content])[position^=left], :where([oui-tooltip-content])[position^=start] {
45
+ --margin-left: -0.5rem;
46
+ }
47
+ :where([oui-tooltip-content]) {
30
48
  max-width: 48ch;
31
49
  padding: 0.75em 1em;
32
50
  opacity: 0;
@@ -36,6 +54,31 @@ var)) {
36
54
  transition: opacity 0.125s ease-in-out;
37
55
  transition-delay: 0s;
38
56
  }
57
+ :where([oui-tooltip-content])::after {
58
+ content: "";
59
+ opacity: 0;
60
+ position: absolute;
61
+ }
62
+ :where([oui-tooltip-content])[position^=above]::after, :where([oui-tooltip-content])[position^=below]::after, :where([oui-tooltip-content])[position^=bottom]::after, :where([oui-tooltip-content])[position^=top]::after {
63
+ width: 100%;
64
+ height: 0.5rem;
65
+ }
66
+ :where([oui-tooltip-content])[position^=above]::after, :where([oui-tooltip-content])[position^=top]::after {
67
+ inset: 100% 0 0;
68
+ }
69
+ :where([oui-tooltip-content])[position^=below]::after, :where([oui-tooltip-content])[position^=bottom]::after {
70
+ inset: -5rem 0 0;
71
+ }
72
+ :where([oui-tooltip-content])[position^=end]::after, :where([oui-tooltip-content])[position^=left]::after, :where([oui-tooltip-content])[position^=right]::after, :where([oui-tooltip-content])[position^=start]::after {
73
+ width: 0.5rem;
74
+ height: 100%;
75
+ }
76
+ :where([oui-tooltip-content])[position^=end]::after, :where([oui-tooltip-content])[position^=right]::after {
77
+ inset: 0 0 0 -0.5rem;
78
+ }
79
+ :where([oui-tooltip-content])[position^=left]::after, :where([oui-tooltip-content])[position^=start]::after {
80
+ inset: 0 0 0 100%;
81
+ }
39
82
 
40
83
  :where([oui-tooltip-content][oui-tooltip-content-active]) {
41
84
  opacity: 1;
@@ -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 const FOCUS_TRAP_SELECTOR = "oui-focus-trap";
22
+ declare const FOCUS_TRAP_CONTAIN = "oui-focus-trap-contain";
23
+ declare const FOCUS_TRAP_NOESCAPE = "oui-focus-trap-noescape";
24
+ declare const FOCUSTRAPS_ALL: WeakMap<HTMLElement, FocusTrap>;
25
+ //#endregion
26
+ export { FOCUSTRAPS_ALL, FOCUS_TRAP_CONTAIN, FOCUS_TRAP_NOESCAPE, FOCUS_TRAP_SELECTOR, FocusTrap, createFocusTrap };
@@ -1,7 +1,8 @@
1
+ import { clamp } from "@oscarpalmer/atoms/number";
1
2
  import { on } from "@oscarpalmer/toretto/event";
2
3
  import { findAncestor } from "@oscarpalmer/toretto/find";
3
- import { clamp } from "@oscarpalmer/atoms/number";
4
4
  import { getFocusable } from "@oscarpalmer/toretto/focusable";
5
+ //#region src/js/focus-trap/embedded.ts
5
6
  var FocusTrap = class {
6
7
  disabled = false;
7
8
  connected = true;
@@ -48,7 +49,7 @@ function createFocusTrap(element, options) {
48
49
  return focusTrap;
49
50
  }
50
51
  function onEscape(event) {
51
- let element = findAncestor(event.target, ATTRIBUTE_SELECTOR);
52
+ let element = findAncestor(event, ATTRIBUTE_SELECTOR);
52
53
  let focusTrap = FOCUSTRAPS_ALL.get(element);
53
54
  if (element == null || focusTrap == null) return;
54
55
  while (focusTrap.disabled) {
@@ -60,7 +61,7 @@ function onEscape(event) {
60
61
  focusTrap?.disable();
61
62
  }
62
63
  function onFocusIn(event) {
63
- lastTarget = FOCUSTRAPS_ALL.get(findAncestor(event.target, ATTRIBUTE_SELECTOR)) == null ? void 0 : event.target;
64
+ lastTarget = FOCUSTRAPS_ALL.get(findAncestor(event, ATTRIBUTE_SELECTOR)) == null ? void 0 : event.target;
64
65
  }
65
66
  function onKeydown(event) {
66
67
  switch (event.key) {
@@ -75,7 +76,7 @@ function onKeydown(event) {
75
76
  }
76
77
  function onPointerdown(event) {
77
78
  const lastFocusTrap = findAncestor(lastTarget, ATTRIBUTE_SELECTOR);
78
- const nextFocusTrap = findAncestor(event.target, ATTRIBUTE_SELECTOR);
79
+ const nextFocusTrap = findAncestor(event, ATTRIBUTE_SELECTOR);
79
80
  if (lastFocusTrap != null && nextFocusTrap !== lastFocusTrap) {
80
81
  if (FOCUSTRAPS_ALL.get(lastFocusTrap)?.contain ?? false) {
81
82
  event.preventDefault();
@@ -86,7 +87,7 @@ function onPointerdown(event) {
86
87
  for (const focusTrap of FOCUSTRAPS_DISABLED) if (focusTrap.element !== nextFocusTrap) focusTrap.enable();
87
88
  }
88
89
  function onTab(event) {
89
- const element = findAncestor(event.target, ATTRIBUTE_SELECTOR);
90
+ const element = findAncestor(event, ATTRIBUTE_SELECTOR);
90
91
  const focusTrap = FOCUSTRAPS_ALL.get(element);
91
92
  if (focusTrap == null) return;
92
93
  if (!focusTrap.disabled) event.preventDefault();
@@ -133,18 +134,19 @@ function tabToTrap(focusTrap, elements, element, index) {
133
134
  }
134
135
  }
135
136
  const FOCUS_TRAP_SELECTOR = "oui-focus-trap";
136
- var ATTRIBUTE_SELECTOR = `[${FOCUS_TRAP_SELECTOR}]`;
137
- var EVENT_OPTIONS = {
137
+ const ATTRIBUTE_SELECTOR = `[${FOCUS_TRAP_SELECTOR}]`;
138
+ const EVENT_OPTIONS = {
138
139
  capture: true,
139
140
  passive: false
140
141
  };
141
142
  const FOCUS_TRAP_CONTAIN = `${FOCUS_TRAP_SELECTOR}-contain`;
142
143
  const FOCUS_TRAP_NOESCAPE = `${FOCUS_TRAP_SELECTOR}-noescape`;
143
144
  const FOCUSTRAPS_ALL = /* @__PURE__ */ new WeakMap();
144
- var FOCUSTRAPS_DISABLED = /* @__PURE__ */ new Set();
145
- var lastTarget;
145
+ const FOCUSTRAPS_DISABLED = /* @__PURE__ */ new Set();
146
+ let lastTarget;
146
147
  on(document, "focusin", onFocusIn, EVENT_OPTIONS);
147
148
  on(document, "keydown", onKeydown, EVENT_OPTIONS);
148
149
  on(document, "mousedown", onPointerdown, EVENT_OPTIONS);
149
150
  on(document, "touchstart", onPointerdown, EVENT_OPTIONS);
151
+ //#endregion
150
152
  export { FOCUSTRAPS_ALL, FOCUS_TRAP_CONTAIN, FOCUS_TRAP_NOESCAPE, FOCUS_TRAP_SELECTOR, FocusTrap, createFocusTrap };
@@ -0,0 +1 @@
1
+ export { };
@@ -1,7 +1,10 @@
1
- import { attributable } from "../attributable.js";
2
- import { FOCUSTRAPS_ALL, FOCUS_TRAP_SELECTOR, createFocusTrap } from "./embedded.js";
1
+ import { attributable } from "../internal/attributable.mjs";
2
+ import { FOCUSTRAPS_ALL, FOCUS_TRAP_SELECTOR, createFocusTrap } from "./embedded.mjs";
3
+ //#region src/js/focus-trap/standalone.ts
3
4
  function removeFocusTraps(element) {
4
5
  FOCUSTRAPS_ALL.get(element)?.destroy();
5
6
  FOCUSTRAPS_ALL.delete(element);
6
7
  }
7
8
  attributable(FOCUS_TRAP_SELECTOR, createFocusTrap, removeFocusTraps);
9
+ //#endregion
10
+ export {};
@@ -0,0 +1,4 @@
1
+ import { OuiPopoverElement } from "./popover.mjs";
2
+ import { OuiSplitterElement } from "./splitter.mjs";
3
+ import { setTooltipDelay } from "./tooltip.mjs";
4
+ export { OuiPopoverElement, OuiSplitterElement, setTooltipDelay };
@@ -0,0 +1,7 @@
1
+ import "./focus-trap/standalone.mjs";
2
+ import "./movable.mjs";
3
+ import { OuiPopoverElement } from "./popover.mjs";
4
+ import "./sortable.mjs";
5
+ import { OuiSplitterElement } from "./splitter.mjs";
6
+ import { setTooltipDelay } from "./tooltip.mjs";
7
+ export { OuiPopoverElement, OuiSplitterElement, setTooltipDelay };
@@ -0,0 +1,4 @@
1
+ //#region src/js/internal/attributable.d.ts
2
+ declare function attributable(attribute: string, add: (element: HTMLElement) => void, remove: (element: HTMLElement) => void): void;
3
+ //#endregion
4
+ export { attributable };
@@ -1,3 +1,4 @@
1
+ //#region src/js/internal/attributable.ts
1
2
  function attributable(attribute, add, remove) {
2
3
  new MutationObserver((entries) => {
3
4
  const { length } = entries;
@@ -26,11 +27,17 @@ function handleAdded(attribute, nodes, add) {
26
27
  for (let index = 0; index < length; index += 1) {
27
28
  const element = elements[index];
28
29
  if (element.hasAttribute(attribute)) add(element);
30
+ if (element.hasChildNodes()) handleAdded(attribute, element.childNodes, add);
29
31
  }
30
32
  }
31
33
  function handleRemoved(nodes, remove) {
32
34
  const elements = [...nodes].filter((node) => node instanceof HTMLElement);
33
35
  const { length } = elements;
34
- for (let index = 0; index < length; index += 1) remove(elements[index]);
36
+ for (let index = 0; index < length; index += 1) {
37
+ const element = elements[index];
38
+ remove(element);
39
+ if (element.hasChildNodes()) handleRemoved(element.childNodes, remove);
40
+ }
35
41
  }
42
+ //#endregion
36
43
  export { attributable };
@@ -0,0 +1,2 @@
1
+ import { a as DraggableState, i as DraggableBound, n as DragMovePosition, o as addDraggable, r as Draggable, s as removeDraggable } from "../movable-BEo2LbUI.mjs";
2
+ export { DragMovePosition, Draggable, DraggableBound, DraggableState, addDraggable, removeDraggable };
@@ -0,0 +1,212 @@
1
+ import { clamp } from "@oscarpalmer/atoms/number";
2
+ import { getPosition, on } from "@oscarpalmer/toretto/event";
3
+ import { findAncestor } from "@oscarpalmer/toretto/find";
4
+ import { toggleStyles } from "@oscarpalmer/toretto/style";
5
+ import supportsTouch from "@oscarpalmer/toretto/touch";
6
+ //#region src/js/internal/draggable.ts
7
+ var Draggable = class {
8
+ container;
9
+ hasHandles;
10
+ horizontal = true;
11
+ vertical = true;
12
+ constructor(prefix, element, options) {
13
+ this.prefix = prefix;
14
+ this.element = element;
15
+ this.options = options;
16
+ setContainer(this, options);
17
+ setDirection(this, options);
18
+ }
19
+ destroy() {
20
+ unsetContainer(this, this.options);
21
+ this.container = void 0;
22
+ this.element = void 0;
23
+ this.options = void 0;
24
+ }
25
+ };
26
+ function addDraggable(element) {
27
+ let instances = state.instances.get(element);
28
+ if (instances == null) {
29
+ instances = {};
30
+ state.instances.set(element, instances);
31
+ }
32
+ instances[this.property] ??= new this.constructor(element);
33
+ }
34
+ function getHandle(event, isMovable) {
35
+ return findAncestor(event, isMovable ? SELECTOR_MOVABLE_HANDLE : SELECTOR_SORTABLE_HANDLE);
36
+ }
37
+ function getNextPosition(draggable, position) {
38
+ let x = state.original?.x ?? 0;
39
+ let y = state.original?.y ?? 0;
40
+ if (draggable.horizontal) {
41
+ x = position.x - (state.offset?.x ?? 0);
42
+ if (state.container != null && state.element != null) x = clamp(x, state.container.left, state.container.right - state.element.rectangle.width);
43
+ }
44
+ if (draggable.vertical) {
45
+ y = position.y - (state.offset?.y ?? 0);
46
+ if (state.container != null && state.element != null) y = clamp(y, state.container.top, state.container.bottom - state.element.rectangle.height);
47
+ }
48
+ return {
49
+ x,
50
+ y
51
+ };
52
+ }
53
+ function onKeydown(event) {
54
+ if (current == null || event.key !== KEY_ESCAPE) return;
55
+ const { origin } = current;
56
+ current.options.drag.onCancel?.(state, current);
57
+ current.element.dispatchEvent(new CustomEvent(`${current.prefix}:cancel`, { detail: { element: origin } }));
58
+ reset();
59
+ }
60
+ function onPointerdown(event) {
61
+ if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey || (supportsTouch.value ? event.type === "mousedown" : event.type === "touchstart" || event.button !== 0)) return;
62
+ const container = findAncestor(event, SELECTOR);
63
+ const instances = state.instances.get(container);
64
+ if (instances == null) return;
65
+ const isMovable = container.hasAttribute(ATTRIBUTE_MOVABLE);
66
+ const instance = isMovable ? instances.movable : instances.sortable;
67
+ if (instance == null) return;
68
+ if (supportsTouch.value) event.preventDefault();
69
+ let element = container;
70
+ if (!isMovable) {
71
+ element = findAncestor(event, SELECTOR_SORTABLE_ITEM);
72
+ if (element == null || element.parentElement !== container) return;
73
+ }
74
+ let handle = element;
75
+ instance.hasHandles ??= element.querySelector(SELECTOR_SORTABLE_HANDLE) != null;
76
+ if (instance.hasHandles) handle = getHandle(event, isMovable);
77
+ if (handle == null) return;
78
+ const { dragged } = instance;
79
+ const rectangle = dragged.getBoundingClientRect();
80
+ const position = getPosition(event) ?? {
81
+ x: 0,
82
+ y: 0
83
+ };
84
+ current = instance;
85
+ state.container = instance.container?.getBoundingClientRect();
86
+ state.element = {
87
+ rectangle,
88
+ node: dragged
89
+ };
90
+ state.offset = instance.options.position.getOffset(state, instance, element, position);
91
+ state.original = instance.options.position.getOriginal(state, instance, position);
92
+ const begin = new CustomEvent(`${instance.prefix}:begin`, {
93
+ detail: {
94
+ element,
95
+ position: { ...state.original }
96
+ },
97
+ cancelable: true
98
+ });
99
+ instance.element.dispatchEvent(begin);
100
+ setTimeout(() => {
101
+ if (begin.defaultPrevented) {
102
+ current?.options.drag.onCancel(state, instance);
103
+ reset();
104
+ return;
105
+ }
106
+ const next = getNextPosition(instance, position);
107
+ dragged.style.position = "fixed";
108
+ dragged.style.inset = `${next.y}px auto auto ${next.x}px`;
109
+ instance.options.drag.onBegin(event, state, instance, element, handle, next);
110
+ styleToggler.set();
111
+ });
112
+ }
113
+ function onPointermove(event) {
114
+ if (current == null) return;
115
+ const position = getPosition(event);
116
+ if (position == null) return;
117
+ const next = getNextPosition(current, position);
118
+ if (state.element != null) state.element.node.style.inset = `${next.y}px auto auto ${next.x}px`;
119
+ const detail = current.options.drag.onMove(event, state, current, {
120
+ calculated: next,
121
+ original: position
122
+ });
123
+ current.element.dispatchEvent(new CustomEvent(`${current.prefix}:move`, { detail }));
124
+ }
125
+ function onPointerup(event) {
126
+ current?.options.drag.onEnd?.(event, state, current, reset);
127
+ }
128
+ function removeDraggable(element) {
129
+ const { property } = this;
130
+ const instances = state.instances.get(element);
131
+ if (instances == null || instances[property] == null) return;
132
+ instances[property]?.destroy();
133
+ instances[property] = void 0;
134
+ if (instances[properties[property]] == null) state.instances.delete(element);
135
+ }
136
+ function reset() {
137
+ current = void 0;
138
+ state.container = void 0;
139
+ state.element = void 0;
140
+ state.offset = void 0;
141
+ state.original = void 0;
142
+ styleToggler.remove();
143
+ }
144
+ function setContainer(draggable, options) {
145
+ const selector = draggable.element.getAttribute(options.container.attribute);
146
+ if (typeof selector !== "string") return;
147
+ draggable.container = globals.has(selector) ? draggable.element.ownerDocument.body : document.querySelector(selector) ?? void 0;
148
+ if (draggable.container == null) return;
149
+ const set = options.container.map.get(draggable.container);
150
+ if (set == null) options.container.map.set(draggable.container, new Set([draggable]));
151
+ else set.add(draggable);
152
+ options.container.onInitialize?.(draggable);
153
+ }
154
+ function setDirection(draggable, options) {
155
+ const direction = draggable.element.getAttribute(options.direction.attribute);
156
+ if (horizontals.has(direction)) draggable.vertical = false;
157
+ else if (verticals.has(direction)) draggable.horizontal = false;
158
+ options.direction.onAfter?.(draggable);
159
+ }
160
+ function unsetContainer(draggable, options) {
161
+ const { container } = draggable;
162
+ if (container == null) return;
163
+ const set = options.container.map.get(container);
164
+ let empty = false;
165
+ if (set != null) {
166
+ set.delete(draggable);
167
+ if (set.size === 0) {
168
+ empty = true;
169
+ options.container.map.delete(container);
170
+ }
171
+ }
172
+ options.container.onDestroy?.(draggable, container, empty);
173
+ }
174
+ const ATTRIBUTE_MOVABLE = "oui-movable";
175
+ const ATTRIBUTE_SORTABLE = "oui-sortable";
176
+ const KEY_ESCAPE = "Escape";
177
+ const SELECTOR = `[${ATTRIBUTE_MOVABLE}], [${ATTRIBUTE_SORTABLE}]`;
178
+ const SELECTOR_MOVABLE_HANDLE = `[${ATTRIBUTE_MOVABLE}-handle]`;
179
+ const SELECTOR_SORTABLE_HANDLE = `[${ATTRIBUTE_SORTABLE}-handle]`;
180
+ const SELECTOR_SORTABLE_ITEM = `[${ATTRIBUTE_SORTABLE}] > *`;
181
+ const globals = new Set([
182
+ "body",
183
+ "document",
184
+ "window"
185
+ ]);
186
+ const horizontals = new Set(["horizontal", "x"]);
187
+ const properties = {
188
+ movable: "sortable",
189
+ sortable: "movable"
190
+ };
191
+ const state = {
192
+ container: void 0,
193
+ element: void 0,
194
+ instances: /* @__PURE__ */ new WeakMap(),
195
+ offset: void 0,
196
+ original: void 0
197
+ };
198
+ const styleToggler = toggleStyles(document.body, {
199
+ touchAction: "none",
200
+ userSelect: "none",
201
+ webkitUserSelect: "none"
202
+ });
203
+ const verticals = new Set(["vertical", "y"]);
204
+ let current;
205
+ on(document, "keydown", onKeydown);
206
+ on(document, "mousedown", onPointerdown);
207
+ on(document, "pointermove", onPointermove);
208
+ on(document, "pointerup", onPointerup);
209
+ on(document, "touchcancel", onPointerup, { passive: false });
210
+ on(document, "touchstart", onPointerdown, { passive: false });
211
+ //#endregion
212
+ export { Draggable, addDraggable, removeDraggable };
@@ -0,0 +1,26 @@
1
+ //#region src/js/internal/floatable.d.ts
2
+ declare class Floatable {
3
+ readonly options: Options;
4
+ active: boolean;
5
+ disabled: boolean;
6
+ frame: DOMHighResTimeStamp | undefined;
7
+ ignoreFocus: boolean;
8
+ constructor(options: Options);
9
+ destroy(): void;
10
+ disable(): void;
11
+ enable(): void;
12
+ toggle(active: boolean, ignoreFocus?: boolean): void;
13
+ }
14
+ type Options = {
15
+ anchor: HTMLElement;
16
+ content: HTMLElement;
17
+ defaultPosition: Position;
18
+ interactive: boolean;
19
+ positionAttribute: string;
20
+ preferAbove: boolean;
21
+ onAfter?: (active: boolean) => void;
22
+ };
23
+ type Position = 'above' | 'above-end' | 'above-start' | 'below' | 'below-end' | 'below-start' | 'end' | 'end-bottom' | 'end-top' | 'horizontal' | 'horizontal-bottom' | 'horizontal-top' | 'start' | 'start-bottom' | 'start-top' | 'vertical' | 'vertical-end' | 'vertical-start';
24
+ declare function deactivate(floatable: Floatable): void;
25
+ //#endregion
26
+ export { Floatable, deactivate };