@oscarpalmer/oui 0.26.1 → 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.
Files changed (64) hide show
  1. package/dist/css/floatable.css +0 -2
  2. package/dist/css/message.css +1 -0
  3. package/dist/css/reset.css +1 -0
  4. package/dist/js/dialog.d.mts +2 -0
  5. package/dist/js/dialog.mjs +16 -1
  6. package/dist/js/draggable-zszaW1qS.d.mts +155 -0
  7. package/dist/js/floatable/floatable.embedded.d.mts +2 -0
  8. package/dist/js/floatable/{embedded.mjs → floatable.embedded.mjs} +16 -11
  9. package/dist/js/floatable/floatable.standalone.d.mts +2 -0
  10. package/dist/js/floatable/floatable.standalone.mjs +2 -0
  11. package/dist/js/{embedded-CSOh5njI.d.mts → floatable.embedded-YxGwzgbE.d.mts} +5 -2
  12. package/dist/js/focus-trap/focus-trap.embedded.d.mts +2 -0
  13. package/dist/js/focus-trap/{embedded.mjs → focus-trap.embedded.mjs} +17 -15
  14. package/dist/js/focus-trap/focus-trap.standalone.d.mts +2 -0
  15. package/dist/js/focus-trap/focus-trap.standalone.mjs +2 -0
  16. package/dist/js/{embedded-CHK82Uh5.d.mts → focus-trap.embedded-DR8NpZfr.d.mts} +18 -18
  17. package/dist/js/index.d.mts +4 -3
  18. package/dist/js/index.mjs +8 -7
  19. package/dist/js/internal/draggable.d.mts +2 -2
  20. package/dist/js/internal/draggable.mjs +146 -94
  21. package/dist/js/movable/movable.embedded.d.mts +2 -0
  22. package/dist/js/movable/movable.embedded.mjs +184 -0
  23. package/dist/js/movable/movable.standalone.d.mts +2 -0
  24. package/dist/js/movable/movable.standalone.mjs +2 -0
  25. package/dist/js/popover.d.mts +2 -2
  26. package/dist/js/popover.mjs +4 -3
  27. package/dist/js/sortable/sortable.embedded.d.mts +2 -0
  28. package/dist/js/{sortable.mjs → sortable/sortable.embedded.mjs} +88 -63
  29. package/dist/js/sortable/sortable.standalone.d.mts +2 -0
  30. package/dist/js/sortable/sortable.standalone.mjs +2 -0
  31. package/dist/js/splitter.mjs +5 -5
  32. package/dist/js/toolbar.mjs +6 -6
  33. package/dist/js/tooltip.d.mts +2 -2
  34. package/dist/js/tooltip.mjs +36 -33
  35. package/package.json +11 -11
  36. package/src/css/floatable.scss +0 -2
  37. package/src/css/message.scss +1 -0
  38. package/src/css/reset.scss +1 -0
  39. package/src/js/dialog.ts +31 -1
  40. package/src/js/floatable/{embedded.ts → floatable.embedded.ts} +18 -10
  41. package/src/js/floatable/floatable.standalone.ts +6 -0
  42. package/src/js/focus-trap/{embedded.ts → focus-trap.embedded.ts} +20 -17
  43. package/src/js/focus-trap/focus-trap.standalone.ts +1 -0
  44. package/src/js/index.ts +4 -4
  45. package/src/js/internal/draggable.ts +309 -168
  46. package/src/js/movable/movable.embedded.ts +328 -0
  47. package/src/js/movable/movable.standalone.ts +2 -0
  48. package/src/js/popover.ts +3 -2
  49. package/src/js/{sortable.ts → sortable/sortable.embedded.ts} +170 -103
  50. package/src/js/sortable/sortable.standalone.ts +2 -0
  51. package/src/js/tooltip.ts +49 -43
  52. package/dist/js/floatable/embedded.d.mts +0 -2
  53. package/dist/js/floatable/standalone.d.mts +0 -2
  54. package/dist/js/floatable/standalone.mjs +0 -2
  55. package/dist/js/focus-trap/embedded.d.mts +0 -2
  56. package/dist/js/focus-trap/standalone.d.mts +0 -2
  57. package/dist/js/focus-trap/standalone.mjs +0 -6
  58. package/dist/js/movable-dNqBctx3.d.mts +0 -101
  59. package/dist/js/movable.d.mts +0 -2
  60. package/dist/js/movable.mjs +0 -152
  61. package/dist/js/sortable.d.mts +0 -2
  62. package/src/js/floatable/standalone.ts +0 -1
  63. package/src/js/focus-trap/standalone.ts +0 -6
  64. package/src/js/movable.ts +0 -260
@@ -1,18 +1,13 @@
1
- import { attributable } from "./internal/attributable.mjs";
2
- import { OuiDraggable, addDraggable, removeDraggable } from "./internal/draggable.mjs";
1
+ import { attributable } from "../internal/attributable.mjs";
2
+ import { OuiDraggable, addDraggable, getDraggableStates, removeDraggable } from "../internal/draggable.mjs";
3
3
  import { getPosition } from "@oscarpalmer/toretto/event";
4
4
  import { isHTMLOrSVGElement } from "@oscarpalmer/toretto/is";
5
5
  import { findAncestor, getElementFromPosition } from "@oscarpalmer/toretto/find";
6
6
  import { createElement } from "@oscarpalmer/toretto/create";
7
- //#region src/js/sortable.ts
7
+ //#region src/js/sortable/sortable.embedded.ts
8
8
  var OuiSortable = class extends OuiDraggable {
9
- connections;
10
- origin;
11
- get dragged() {
12
- return getDragPlaceholder();
13
- }
14
- constructor(element) {
15
- super("sort", element, {
9
+ constructor(element, options) {
10
+ super("sortable", "sort", ATTRIBUTE, element, {
16
11
  container: {
17
12
  attribute: ATTRIBUTE_CONTAINER,
18
13
  map: CONTAINERS
@@ -24,17 +19,19 @@ var OuiSortable = class extends OuiDraggable {
24
19
  onEnd,
25
20
  onMove
26
21
  },
22
+ input: options,
27
23
  position: {
28
24
  getOffset: getOffsetPosition,
29
25
  getOriginal: getOriginalPosition
30
- }
31
- });
32
- this.connections = this.element.getAttribute(ATTRIBUTE_CONNECTIONS);
26
+ },
27
+ getDragged: getDragPlaceholder,
28
+ getOrigin: () => (getDraggableStates(element)?.sortable)?.origin
29
+ }, { connections: element.getAttribute(ATTRIBUTE_CONNECTIONS) });
33
30
  }
34
31
  };
35
32
  function afterEnd(insert, from, events, elements, position, valid) {
36
33
  elements.origin?.removeAttribute(ATTRIBUTE_ORIGIN);
37
- from.origin = void 0;
34
+ from.state.origin = void 0;
38
35
  resetPlaceholders();
39
36
  if (!valid || events.some((event) => event.defaultPrevented)) return;
40
37
  if (insert !== "insert") {
@@ -49,44 +46,50 @@ function afterEnd(insert, from, events, elements, position, valid) {
49
46
  elements.target?.insertAdjacentElement(insertion, elements.origin);
50
47
  document.body.removeAttribute(ATTRIBUTE_ACTIVE);
51
48
  }
49
+ /**
50
+ * Creates _(or retrieves)_ a _OuiSortable_ instance for an element
51
+ *
52
+ * @param element Element to make sortable
53
+ * @returns _OuiSortable_ instance
54
+ */
55
+ function createSortable(element, options) {
56
+ if (!isHTMLOrSVGElement(element)) throw new TypeError(MESSAGE);
57
+ return addSortable(element, options);
58
+ }
52
59
  function getDragPlaceholder() {
53
60
  placeholder.drag.default ??= createElement("div");
54
61
  return placeholder.drag.custom ?? placeholder.drag.default;
55
62
  }
56
- function getOffsetPosition(_, draggable, element, position) {
63
+ function getOffsetPosition(_, item, element, position) {
57
64
  const rectangle = element.getBoundingClientRect();
58
65
  return {
59
- x: draggable.horizontal ? 0 : position.x - rectangle.left,
60
- y: draggable.vertical ? 0 : position.y - rectangle.top
66
+ x: item.state.horizontal ? 0 : position.x - rectangle.left,
67
+ y: item.state.vertical ? 0 : position.y - rectangle.top
61
68
  };
62
69
  }
63
70
  function getOriginalPosition(_, __, position) {
64
71
  return position;
65
72
  }
66
- function getPositionPlaceholder(sortable) {
73
+ function getPositionPlaceholder(item) {
67
74
  placeholder.position ??= createElement("div");
68
75
  placeholder.position.setAttribute(ATTRIBUTE_PLACEHOLDER_POSITION, "");
69
- if (sortable.origin != null) placeholder.position.style.setProperty("--placeholder-height", `${sortable.origin.getBoundingClientRect().height}px`);
76
+ if (item.state.origin != null) placeholder.position.style.setProperty("--placeholder-height", `${item.state.origin.getBoundingClientRect().height}px`);
70
77
  return placeholder.position;
71
78
  }
72
- function onBegin(_, state, draggable, element) {
73
- const sortable = draggable;
74
- sortable.origin = element;
75
- setPlaceholder(state, sortable, element);
79
+ function onBegin(_, globals, item, element) {
80
+ item.state.origin = element;
81
+ setPlaceholder(globals, item, element);
76
82
  element.setAttribute(ATTRIBUTE_ORIGIN, "");
77
83
  document.body.setAttribute(ATTRIBUTE_ACTIVE, "");
78
84
  }
79
- function onCancel(_, draggable) {
80
- const sortable = draggable;
81
- const { origin } = sortable;
82
- origin?.removeAttribute(ATTRIBUTE_ORIGIN);
85
+ function onCancel(_, item) {
86
+ item.state.origin?.removeAttribute(ATTRIBUTE_ORIGIN);
83
87
  document.body.removeAttribute(ATTRIBUTE_ACTIVE);
84
88
  resetPlaceholders();
85
- sortable.origin = void 0;
89
+ item.state.origin = void 0;
86
90
  }
87
- function onEnd(event, state, draggable, reset) {
88
- const from = draggable;
89
- const { origin } = from;
91
+ function onEnd(event, globals, item, reset) {
92
+ const { origin } = item.state;
90
93
  const position = getPosition(event) ?? {
91
94
  x: 0,
92
95
  y: 0
@@ -96,18 +99,26 @@ function onEnd(event, state, draggable, reset) {
96
99
  if (element?.hasAttribute(ATTRIBUTE_PLACEHOLDER_POSITION)) if (element.getAttribute(ATTRIBUTE_PLACEHOLDER_POSITION) === "after") element = element.previousElementSibling;
97
100
  else element = element.nextElementSibling;
98
101
  let insert = "insert";
99
- let to;
102
+ let toInstance;
103
+ let toState;
100
104
  if (element == null) {
101
105
  element = findAncestor(target, SELECTOR);
102
- to = state.instances.get(element)?.sortable;
106
+ toInstance = globals.instances.get(element)?.sortable;
107
+ toState = globals.states.get(element)?.sortable;
103
108
  insert = element == null ? void 0 : element.children.length === 0 ? "append" : "prepend";
104
- } else to = state.instances.get(element.parentElement)?.sortable;
105
- const valid = insert != null && validatePosition(state, from, to, position);
109
+ } else {
110
+ toInstance = globals.instances.get(element.parentElement)?.sortable;
111
+ toState = globals.states.get(element.parentElement)?.sortable;
112
+ }
113
+ const valid = insert != null && validatePosition(globals, item, {
114
+ instance: toInstance,
115
+ state: toState
116
+ }, position);
106
117
  const options = {
107
118
  detail: valid ? {
108
119
  from: {
109
120
  element: origin,
110
- position: { ...state.original }
121
+ position: { ...globals.original }
111
122
  },
112
123
  to: {
113
124
  element,
@@ -119,25 +130,34 @@ function onEnd(event, state, draggable, reset) {
119
130
  };
120
131
  const fromEvent = new CustomEvent(EVENT_END, options);
121
132
  const toEvent = new CustomEvent(EVENT_END, options);
122
- from.element.dispatchEvent(fromEvent);
123
- if (from !== to) to?.element.dispatchEvent(toEvent);
133
+ item.instance.element.dispatchEvent(fromEvent);
134
+ if (item.instance !== toInstance) toInstance?.element.dispatchEvent(toEvent);
124
135
  setTimeout(() => {
125
- afterEnd(insert, from, [fromEvent, toEvent], {
136
+ afterEnd(insert, item, [fromEvent, toEvent], {
126
137
  origin,
127
138
  target: element
128
139
  }, position, valid);
129
140
  reset();
130
141
  });
131
142
  }
132
- function onMove(event, state, draggable, position) {
133
- const from = draggable;
134
- const fromElement = from.origin;
143
+ function onMove(event, globals, item, position) {
144
+ const fromElement = item.state.origin;
135
145
  const toElement = findAncestor(event, SELECTOR_ITEM);
136
- let to;
137
- if (toElement == null) to = state.instances.get(findAncestor(event, SELECTOR))?.sortable;
138
- else to = state.instances.get(toElement.parentElement)?.sortable;
139
- if (!validatePosition(state, from, to, position.original)) return;
140
- const placeholder = getPositionPlaceholder(from);
146
+ let toInstance;
147
+ let toState;
148
+ if (toElement == null) {
149
+ const element = findAncestor(event, SELECTOR);
150
+ toInstance = globals.instances.get(element)?.sortable;
151
+ toState = globals.states.get(element)?.sortable;
152
+ } else {
153
+ toInstance = globals.instances.get(toElement.parentElement)?.sortable;
154
+ toState = globals.states.get(toElement.parentElement)?.sortable;
155
+ }
156
+ if (toInstance == null || !validatePosition(globals, item, {
157
+ instance: toInstance,
158
+ state: toState
159
+ }, position.original)) return;
160
+ const placeholder = getPositionPlaceholder(item);
141
161
  if (toElement != null && toElement !== fromElement) {
142
162
  const { height, top } = toElement.getBoundingClientRect();
143
163
  let place;
@@ -153,7 +173,7 @@ function onMove(event, state, draggable, position) {
153
173
  return {
154
174
  from: {
155
175
  element: fromElement,
156
- position: { ...state.original }
176
+ position: { ...globals.original }
157
177
  },
158
178
  to: {
159
179
  element: toElement,
@@ -167,21 +187,21 @@ function resetPlaceholders() {
167
187
  placeholder.position?.remove();
168
188
  placeholder.drag.custom = void 0;
169
189
  }
170
- function setPlaceholder(state, sortable, origin) {
190
+ function setPlaceholder(state, item, origin) {
171
191
  const element = getDragPlaceholder();
172
192
  placeholder.drag.default.innerHTML = "";
173
- updatePlaceholder(sortable, element);
193
+ updatePlaceholder(item, element);
174
194
  const event = new CustomEvent(EVENT_PLACEHOLDER, {
175
195
  cancelable: true,
176
196
  detail: {
177
197
  origin,
178
- parent: sortable.element,
198
+ parent: item.state.element,
179
199
  placeholder: element,
180
200
  create: (value) => {
181
201
  if (!isHTMLOrSVGElement(value)) return;
182
202
  const element = value;
183
203
  placeholder.drag.custom = element;
184
- updatePlaceholder(sortable, element);
204
+ updatePlaceholder(item, element);
185
205
  state.element = {
186
206
  rectangle: element.getBoundingClientRect(),
187
207
  node: element
@@ -189,27 +209,30 @@ function setPlaceholder(state, sortable, origin) {
189
209
  }
190
210
  }
191
211
  });
192
- sortable.element.dispatchEvent(event);
212
+ item.instance.element.dispatchEvent(event);
193
213
  setTimeout(() => {
194
214
  if (!event.defaultPrevented && placeholder.drag.custom == null) placeholder.drag.default?.append(element.cloneNode(true));
195
215
  document.body.append(placeholder.drag.custom ?? placeholder.drag.default ?? "");
196
216
  });
197
217
  }
198
- function updatePlaceholder(sortable, element) {
218
+ function updatePlaceholder(item, element) {
199
219
  element.style.position = "fixed";
200
220
  element.setAttribute(ATTRIBUTE_PLACEHOLDER_DRAG, "");
201
- if (sortable.horizontal) element.setAttribute(ATTRIBUTE_HORIZONTAL, "");
221
+ const state = getDraggableStates(item.state.element)?.sortable;
222
+ if (state == null) return;
223
+ if (state.horizontal) element.setAttribute(ATTRIBUTE_HORIZONTAL, "");
202
224
  else element.removeAttribute(ATTRIBUTE_HORIZONTAL);
203
- if (sortable.vertical) element.setAttribute(ATTRIBUTE_VERTICAL, "");
225
+ if (state.vertical) element.setAttribute(ATTRIBUTE_VERTICAL, "");
204
226
  else element.removeAttribute(ATTRIBUTE_VERTICAL);
205
227
  }
206
228
  function validatePosition(_, from, to, position) {
207
229
  let valid = true;
208
- const rectangle = from.origin?.getBoundingClientRect();
209
- if (rectangle != null && !from.horizontal) valid = position.x >= rectangle.left && position.x <= rectangle.right;
210
- if (valid && rectangle != null && !from.vertical) valid = position.y >= rectangle.top && position.y <= rectangle.bottom;
211
- if (valid && from.connections != null) valid = to?.element.matches(from.connections) ?? true;
212
- if (valid && to?.connections != null) valid = from.element.matches(to.connections);
230
+ const rectangle = from.state.origin?.getBoundingClientRect();
231
+ const fromState = getDraggableStates(from.state.element)?.sortable;
232
+ if (rectangle != null && !(fromState?.horizontal ?? true)) valid = position.x >= rectangle.left && position.x <= rectangle.right;
233
+ if (valid && rectangle != null && !(fromState?.vertical ?? true)) valid = position.y >= rectangle.top && position.y <= rectangle.bottom;
234
+ if (valid && from.state.connections != null) valid = to?.state.element.matches(from.state.connections) ?? true;
235
+ if (valid && to?.state.connections != null) valid = from.state.element.matches(to.state.connections);
213
236
  return valid;
214
237
  }
215
238
  const ATTRIBUTE = "oui-sortable";
@@ -227,6 +250,7 @@ const EVENT_END = "sort:end";
227
250
  const EVENT_PLACEHOLDER = "sort:placeholder";
228
251
  const INSERT_AFTER = "afterend";
229
252
  const INSERT_BEFORE = "beforebegin";
253
+ const MESSAGE = "The element must be an instance of HTMLElement or SVGElement";
230
254
  const SELECTOR = `[${ATTRIBUTE}]`;
231
255
  const SELECTOR_ITEM = `[${ATTRIBUTE}] > *`;
232
256
  const bound = {
@@ -240,6 +264,7 @@ const placeholder = {
240
264
  },
241
265
  position: void 0
242
266
  };
243
- attributable(ATTRIBUTE, addDraggable.bind(bound), removeDraggable.bind(bound));
267
+ const addSortable = addDraggable.bind(bound);
268
+ attributable(ATTRIBUTE, addSortable, removeDraggable.bind(bound));
244
269
  //#endregion
245
- export { OuiSortable };
270
+ export { OuiSortable, createSortable };
@@ -0,0 +1,2 @@
1
+ import { d as OuiSortable, f as createSortable, t as CreateOuiDraggableOptions } from "../draggable-zszaW1qS.mjs";
2
+ export { type CreateOuiDraggableOptions as CreateOuiSortableOptions, type OuiSortable, createSortable };
@@ -0,0 +1,2 @@
1
+ import { createSortable } from "./sortable.embedded.mjs";
2
+ export { createSortable };
@@ -282,11 +282,11 @@ const ATTRIBUTE_ACTIVE = `${SELECTOR}-active`;
282
282
  const ATTRIBUTE_HANDLE = `${SELECTOR}-handle`;
283
283
  const ATTRIBUTE_HORIZONTAL = `${SELECTOR}-horizontal`;
284
284
  const ATTRIBUTE_SEPARATOR = `${SELECTOR}-separator`;
285
- const KEYS_ABSOLUTE = new Set(["End", "Home"]);
286
- const KEYS_HORIZONTAL = new Set(["ArrowDown", "ArrowUp"]);
287
- const KEYS_NEGATIVE = new Set(["ArrowLeft", "ArrowUp"]);
288
- const KEYS_VERTICAL = new Set(["ArrowLeft", "ArrowRight"]);
289
- const KEYS_ALL = new Set([
285
+ const KEYS_ABSOLUTE = /* @__PURE__ */ new Set(["End", "Home"]);
286
+ const KEYS_HORIZONTAL = /* @__PURE__ */ new Set(["ArrowDown", "ArrowUp"]);
287
+ const KEYS_NEGATIVE = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowUp"]);
288
+ const KEYS_VERTICAL = /* @__PURE__ */ new Set(["ArrowLeft", "ArrowRight"]);
289
+ const KEYS_ALL = /* @__PURE__ */ new Set([
290
290
  ...KEYS_ABSOLUTE,
291
291
  ...KEYS_HORIZONTAL,
292
292
  ...KEYS_VERTICAL
@@ -88,17 +88,17 @@ const KEY_ARROW_DOWN = "ArrowDown";
88
88
  const KEY_ARROW_RIGHT = "ArrowRight";
89
89
  const KEY_END = "End";
90
90
  const KEY_HOME = "Home";
91
- const KEYS_ABSOLUTE = new Set([KEY_END, KEY_HOME]);
92
- const KEYS_HORIZONTAL = new Set([KEY_ARROW_RIGHT, "ArrowLeft"]);
93
- const KEYS_VERTICAL = new Set([KEY_ARROW_DOWN, "ArrowUp"]);
94
- const KEYS_ALL = new Set([
91
+ const KEYS_ABSOLUTE = /* @__PURE__ */ new Set([KEY_END, KEY_HOME]);
92
+ const KEYS_HORIZONTAL = /* @__PURE__ */ new Set([KEY_ARROW_RIGHT, "ArrowLeft"]);
93
+ const KEYS_VERTICAL = /* @__PURE__ */ new Set([KEY_ARROW_DOWN, "ArrowUp"]);
94
+ const KEYS_ALL = /* @__PURE__ */ new Set([
95
95
  ...KEYS_ABSOLUTE,
96
96
  ...KEYS_HORIZONTAL,
97
97
  ...KEYS_VERTICAL
98
98
  ]);
99
- const KEYS_NEXT = new Set([KEY_ARROW_DOWN, KEY_ARROW_RIGHT]);
99
+ const KEYS_NEXT = /* @__PURE__ */ new Set([KEY_ARROW_DOWN, KEY_ARROW_RIGHT]);
100
100
  const ORIENTATION_HORIZONTAL = "horizontal";
101
- const ORIENTATIONS = new Set([ORIENTATION_HORIZONTAL, "vertical"]);
101
+ const ORIENTATIONS = /* @__PURE__ */ new Set([ORIENTATION_HORIZONTAL, "vertical"]);
102
102
  const PROPERTY_DISABLED = "disabled";
103
103
  const SELECTOR = `[${ATTRIBUTE}-item]`;
104
104
  const instances = /* @__PURE__ */ new WeakMap();
@@ -1,4 +1,4 @@
1
- import { n as OuiFloatable } from "./embedded-CSOh5njI.mjs";
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 {
@@ -23,7 +23,7 @@ declare class OuiTooltip {
23
23
  }
24
24
  type OuiTooltipState = {
25
25
  anchor: HTMLElement;
26
- content: HTMLElement;
26
+ elements: HTMLElement[];
27
27
  floatable: OuiFloatable;
28
28
  timer?: number;
29
29
  tooltip: OuiTooltip;
@@ -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,7 @@ var OuiTooltip = class {
12
12
  * Is the tooltip open?
13
13
  */
14
14
  get open() {
15
- return this.#state.content.checkVisibility();
15
+ return this === activeTooltip && content.checkVisibility();
16
16
  }
17
17
  /**
18
18
  * Open or close the tooltip
@@ -39,52 +39,50 @@ var OuiTooltip = class {
39
39
  }
40
40
  };
41
41
  function activate(event, focus) {
42
- const anchor = findAncestor(event, SELECTOR);
43
- const content = findAncestor(event, SELECTOR_CONTENT);
44
- if (anchor == null && content == null) {
42
+ const targetAnchor = findAncestor(event, SELECTOR);
43
+ const targetContent = findAncestor(event, SELECTOR_CONTENT);
44
+ if (targetAnchor == null && targetContent == null) {
45
45
  if (!focused) {
46
- closeTooltip(activeState);
46
+ closeTooltip(true, activeState);
47
47
  activeState = void 0;
48
48
  activeTooltip = void 0;
49
49
  }
50
50
  return;
51
51
  }
52
- const state = states.get(anchor ?? content);
52
+ const state = states.get(targetAnchor ?? targetContent);
53
53
  if (state == null || state.tooltip === activeTooltip) return;
54
54
  const shouldDelay = activeTooltip == null;
55
- closeTooltip(activeState);
55
+ closeTooltip(false, activeState);
56
56
  activeState = state;
57
57
  activeTooltip = state.tooltip;
58
58
  focused = focus;
59
59
  state.timer = setTimeout(() => {
60
- state.content.showPopover({ source: state.anchor });
60
+ content.innerHTML = "";
61
+ content.append(...state.elements);
62
+ state.floatable.show();
61
63
  setTimeout(() => {
62
64
  state.floatable.update();
63
- state.content.setAttribute(ATTRIBUTE_CONTENT_OPEN, "");
64
65
  });
65
66
  }, shouldDelay ? delay : 0);
66
67
  }
67
68
  function addTooltip(element) {
68
69
  if (!states.has(element)) createTooltip(element);
69
70
  }
70
- function closeTooltip(state) {
71
+ function closeTooltip(clear, state) {
71
72
  if (state == null) return;
72
73
  if (state.timer != null) clearTimeout(state.timer);
73
- state.content?.hidePopover();
74
- state.content?.removeAttribute(ATTRIBUTE_CONTENT_OPEN);
74
+ if (clear) content?.hidePopover();
75
75
  }
76
76
  function createTooltip(anchor) {
77
- const content = getContent(anchor);
78
- if (content == null) return;
79
- anchor.insertAdjacentElement("afterend", content);
80
- states.set(anchor, getState(anchor, content));
77
+ const elements = getElements(anchor);
78
+ if (elements == null) return;
79
+ states.set(anchor, getState(anchor, elements));
81
80
  }
82
81
  function destroyTooltip(state) {
83
82
  clearTimeout(state.timer);
84
- state.content.remove();
85
83
  state.floatable.destroy();
86
84
  state.anchor = void 0;
87
- state.content = void 0;
85
+ state.elements = void 0;
88
86
  state.floatable = void 0;
89
87
  state.tooltip = void 0;
90
88
  }
@@ -102,34 +100,31 @@ function findElements(attribute) {
102
100
  }
103
101
  return elements;
104
102
  }
105
- function getContent(anchor) {
106
- const elements = getElements(anchor);
107
- if (elements == null) return;
103
+ function getContent() {
108
104
  const content = createElement(CONTENT_TAGNAME, {
109
105
  popover: "hint",
110
106
  role: "tooltip",
111
107
  tabIndex: -1
112
108
  });
113
109
  content.setAttribute(ATTRIBUTE_CONTENT, "");
114
- content.append(...elements);
115
110
  return content;
116
111
  }
117
112
  function getElements(anchor) {
118
113
  let elements = findElements(anchor.getAttribute(ARIA_LABELLEDBY));
119
- if (elements.length > 0) return elements.map((element) => element.cloneNode(true));
114
+ if (elements.length > 0) return elements;
120
115
  elements = findElements(anchor.getAttribute(ARIA_DESCRIBEDBY));
121
- if (elements.length > 0) return elements.map((element) => element.cloneNode(true));
122
- let content = anchor.getAttribute(ARIA_LABEL);
123
- if (isNullableOrWhitespace(content)) content = anchor.getAttribute(ARIA_DESCRIPTION);
124
- if (isNullableOrWhitespace(content)) return;
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;
125
120
  const paragraph = document.createElement("p");
126
- paragraph.textContent = content;
121
+ paragraph.textContent = text;
127
122
  return [paragraph];
128
123
  }
129
- function getState(anchor, content) {
124
+ function getState(anchor, elements) {
130
125
  const state = {
131
126
  anchor,
132
- content,
127
+ elements,
133
128
  floatable: createEmbeddedFloatable(anchor, content, options),
134
129
  tooltip: null
135
130
  };
@@ -153,7 +148,7 @@ function onFocusout() {
153
148
  if (focusTimer != null) clearTimeout(focusTimer);
154
149
  focusTimer = setTimeout(() => {
155
150
  if (activeTooltip == null || document.activeElement == null || findAncestor(document.activeElement, SELECTOR) != null) return;
156
- closeTooltip(activeState);
151
+ closeTooltip(true, activeState);
157
152
  activeState = void 0;
158
153
  activeTooltip = void 0;
159
154
  });
@@ -161,6 +156,10 @@ function onFocusout() {
161
156
  function onPointermove(event) {
162
157
  activate(event, false);
163
158
  }
159
+ function onToggle(event) {
160
+ if (event.newState === "open") content.setAttribute(ATTRIBUTE_CONTENT_OPEN, "");
161
+ else content.removeAttribute(ATTRIBUTE_CONTENT_OPEN);
162
+ }
164
163
  function removeTooltip(element) {
165
164
  const state = states.get(element);
166
165
  if (state == null) return;
@@ -187,16 +186,20 @@ const ATTRIBUTE_CONTENT = `${ATTRIBUTE}-content`;
187
186
  const ATTRIBUTE_CONTENT_OPEN = `${ATTRIBUTE_CONTENT}-open`;
188
187
  const SELECTOR = `[${ATTRIBUTE}]`;
189
188
  const SELECTOR_CONTENT = `[${ATTRIBUTE_CONTENT}]`;
189
+ const content = getContent();
190
190
  const states = /* @__PURE__ */ new WeakMap();
191
191
  const options = {
192
192
  attribute: `${ATTRIBUTE}-position`,
193
- position: "above"
193
+ position: "above",
194
+ reusable: true
194
195
  };
195
196
  let delay = 500;
196
197
  let focused = false;
197
198
  let activeState;
198
199
  let activeTooltip;
199
200
  let focusTimer;
201
+ document.body.append(content);
202
+ on(content, "toggle", onToggle);
200
203
  on(document, "focusin", onFocusin);
201
204
  on(document, "focusout", onFocusout);
202
205
  on(document, "pointermove", onPointermove);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oscarpalmer/oui",
3
- "version": "0.26.1",
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.70",
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.13",
98
+ "stylelint": "^17.14",
99
99
  "stylelint-config-standard-scss": "^17",
100
100
  "tsdown": "^0.22",
101
101
  "typescript": "^6",
@@ -77,8 +77,6 @@
77
77
  :where([oui-tooltip-content]) {
78
78
  max-width: 48ch;
79
79
  padding: 0.75em 1em;
80
- overflow: visible;
81
- opacity: 0;
82
80
  background-color: var(--oui-absolute);
83
81
  border-radius: 0.25rem;
84
82
  font-size: 0.875rem;
@@ -24,6 +24,7 @@
24
24
  }
25
25
 
26
26
  :where(& h2, & h3, & h4, & h5, & h6) {
27
+ color: var(--oui-foreground, var(--oui-gray-10));
27
28
  font-size: 1em;
28
29
  font-weight: bold;
29
30
  }
@@ -123,6 +123,7 @@
123
123
 
124
124
  :where(dialog) {
125
125
  display: none !important;
126
+ overflow: visible;
126
127
  overscroll-behavior: contain;
127
128
  border: none;
128
129
  color: currentcolor;