@oscarpalmer/oui 0.17.0 → 0.18.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 (58) hide show
  1. package/dist/css/badge.css +3 -3
  2. package/dist/css/content.css +9 -11
  3. package/dist/css/form.css +36 -22
  4. package/dist/css/message.css +4 -0
  5. package/dist/css/reset.css +176 -56
  6. package/dist/css/tooltip.css +8 -0
  7. package/dist/js/attributable.full.js +48 -0
  8. package/dist/js/attributable.js +30 -45
  9. package/dist/js/floatable.full.js +413 -0
  10. package/dist/js/floatable.js +254 -169
  11. package/dist/js/focus-trap/embedded.full.js +351 -0
  12. package/dist/js/focus-trap/embedded.js +131 -131
  13. package/dist/js/focus-trap/standalone.full.js +402 -0
  14. package/dist/js/focus-trap/standalone.js +4 -4
  15. package/dist/js/index.js +4 -5
  16. package/dist/js/oui.full.js +1596 -0
  17. package/dist/js/popover.full.js +822 -0
  18. package/dist/js/popover.js +83 -162
  19. package/dist/js/splitter.full.js +605 -0
  20. package/dist/js/splitter.js +263 -245
  21. package/dist/js/tooltip.full.js +679 -0
  22. package/dist/js/tooltip.js +159 -150
  23. package/package.json +31 -59
  24. package/src/css/content.scss +1 -2
  25. package/src/css/form.scss +12 -4
  26. package/src/css/message.scss +3 -0
  27. package/src/css/mixins.scss +7 -0
  28. package/src/css/reset.scss +180 -54
  29. package/src/css/tooltip.scss +8 -0
  30. package/src/js/floatable.ts +380 -133
  31. package/src/js/focus-trap/embedded.ts +149 -64
  32. package/src/js/focus-trap/standalone.ts +4 -4
  33. package/src/js/index.ts +1 -0
  34. package/src/js/popover.ts +50 -120
  35. package/src/js/splitter.ts +250 -103
  36. package/src/js/tooltip.ts +155 -68
  37. package/types/floatable.d.ts +17 -10
  38. package/types/focus-trap/embedded.d.ts +18 -5
  39. package/types/index.d.ts +1 -0
  40. package/types/popover.d.ts +2 -0
  41. package/types/splitter.d.ts +13 -1
  42. package/types/tooltip.d.ts +2 -1
  43. package/dist/js/attributable.cjs +0 -51
  44. package/dist/js/floatable.cjs +0 -176
  45. package/dist/js/focus-trap/embedded.cjs +0 -150
  46. package/dist/js/focus-trap/standalone.cjs +0 -8
  47. package/dist/js/index.cjs +0 -6
  48. package/dist/js/popover.cjs +0 -166
  49. package/dist/js/splitter.cjs +0 -272
  50. package/dist/js/tooltip.cjs +0 -166
  51. package/types/attributable.d.cts +0 -5
  52. package/types/floatable.d.cts +0 -20
  53. package/types/focus-trap/embedded.d.cts +0 -15
  54. package/types/focus-trap/standalone.d.cts +0 -3
  55. package/types/index.d.cts +0 -14
  56. package/types/popover.d.cts +0 -14
  57. package/types/splitter.d.cts +0 -10
  58. package/types/tooltip.d.cts +0 -3
package/src/js/tooltip.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import {isNullableOrWhitespace} from '@oscarpalmer/atoms/is';
2
2
  import {on} from '@oscarpalmer/toretto/event';
3
+ import {findAncestor} from '@oscarpalmer/toretto/find';
3
4
  import {attributable} from './attributable';
4
- import {activate, deactivate, Floatable} from './floatable';
5
+ import {Floatable} from './floatable';
5
6
 
6
7
  type Attributes = {
7
8
  ariaDescribedby: string | null;
@@ -14,47 +15,80 @@ type Content = {
14
15
  };
15
16
 
16
17
  class Tooltip {
17
- abortController = new AbortController();
18
18
  attributes: Attributes;
19
+
19
20
  floatable: Floatable;
20
21
 
22
+ timer: number | undefined;
23
+
21
24
  constructor(anchor: HTMLElement, content: Content) {
22
25
  this.attributes = content.attributes;
23
26
 
24
- this.floatable = new Floatable(
27
+ this.floatable = new Floatable({
25
28
  anchor,
26
- content.element,
27
- `${selector}-position`,
28
- 'vertical',
29
- true,
30
- );
29
+ content: content.element,
30
+ defaultPosition: 'vertical',
31
+ interactive: false,
32
+ preferAbove: true,
33
+ positionAttribute: ATTRIBUTE_POSITION,
34
+ });
35
+
36
+ anchor.insertAdjacentElement('afterend', content.element);
31
37
 
32
- initialize(this);
38
+ TOOLTIPS_ALL.set(content.element, this);
33
39
  }
34
40
 
35
41
  destroy(): void {
36
- deactivate(this.floatable, active);
37
- reset(this.floatable.anchor, this.attributes);
42
+ const {attributes, floatable} = this;
38
43
 
39
- this.abortController.abort();
40
- this.floatable.content.remove();
41
- this.floatable.destroy();
44
+ TOOLTIPS_ACTIVE.delete(this);
45
+ TOOLTIPS_ALL.delete(floatable.options.anchor);
46
+ TOOLTIPS_ALL.delete(floatable.options.content);
47
+
48
+ reset(floatable.options.anchor, attributes);
49
+
50
+ floatable.options.content.remove();
51
+ floatable.destroy();
42
52
 
43
- this.abortController = undefined as never;
44
53
  this.attributes = undefined as never;
45
54
  this.floatable = undefined as never;
46
55
  }
47
56
  }
48
57
 
49
58
  function addTooltip(anchor: HTMLElement): void {
50
- if (tooltips.has(anchor)) {
59
+ if (TOOLTIPS_ALL.has(anchor)) {
51
60
  return;
52
61
  }
53
62
 
54
63
  const content = getContent(anchor);
55
64
 
56
65
  if (content != null) {
57
- tooltips.set(anchor, new Tooltip(anchor, content));
66
+ TOOLTIPS_ALL.set(anchor, new Tooltip(anchor, content));
67
+ }
68
+ }
69
+
70
+ function closeTooltips(next: Tooltip | undefined): void {
71
+ const tooltips = [...TOOLTIPS_ACTIVE];
72
+
73
+ for (const active of tooltips) {
74
+ if (active === next) {
75
+ continue;
76
+ }
77
+
78
+ if (active.timer != null) {
79
+ clearTimeout(active.timer);
80
+ }
81
+
82
+ active.floatable.options.content.removeAttribute(
83
+ 'oui-tooltip-content-active',
84
+ );
85
+
86
+ requestAnimationFrame(() => {
87
+ active.timer = setTimeout(() => {
88
+ TOOLTIPS_ACTIVE.delete(active);
89
+ active.floatable.toggle(false);
90
+ }, delay) as never;
91
+ });
58
92
  }
59
93
  }
60
94
 
@@ -119,7 +153,7 @@ function getContent(anchor: HTMLElement): Content | undefined {
119
153
  }
120
154
 
121
155
  function getElements(attribute: string | null): HTMLElement[] {
122
- const ids = attribute?.split(/\s+/) ?? [];
156
+ const ids = attribute?.split(EXPRESSION_WHITESPACE) ?? [];
123
157
  const elements: HTMLElement[] = [];
124
158
 
125
159
  for (const id of ids) {
@@ -144,57 +178,92 @@ function getElements(attribute: string | null): HTMLElement[] {
144
178
  function getWrapper(anchor: HTMLElement): HTMLElement {
145
179
  const wrapper = document.createElement('div');
146
180
 
147
- wrapper.setAttribute(`${selector}-content`, '');
181
+ wrapper.setAttribute(ATTRIBUTE_CONTENT, '');
148
182
 
149
- wrapper.className = anchor.getAttribute(`${selector}-class`) ?? '';
183
+ wrapper.className = anchor.getAttribute(ATTRIBUTE_CLASS) ?? '';
150
184
  wrapper.hidden = true;
151
- wrapper.id = `${selector}-${++index}`;
185
+ wrapper.id = `${SELECTOR}-${++index}`;
152
186
  wrapper.role = 'tooltip';
153
187
  wrapper.tabIndex = -1;
154
188
 
155
189
  return wrapper;
156
190
  }
157
191
 
158
- function initialize(tooltip: Tooltip): void {
159
- const {abortController, floatable} = tooltip;
160
- const {anchor, content} = floatable;
161
-
162
- anchor.insertAdjacentElement('afterend', content);
163
-
164
- const elements = [anchor, content];
165
-
166
- for (const element of elements) {
167
- for (const event of activateEvents) {
168
- on(
169
- element,
170
- event,
171
- () => {
172
- activate(floatable, active, undefined, 250);
173
- },
174
- {
175
- signal: abortController.signal,
176
- },
177
- );
192
+ function onActivate(event: Event): void {
193
+ onToggle(event, true);
194
+ }
195
+
196
+ function onClick(event: Event): void {
197
+ if (findAncestor(event.target as HTMLElement, SELECTOR_CONTENT) != null) {
198
+ event.stopPropagation();
199
+ }
200
+ }
201
+
202
+ function onDeactivate(event: Event): void {
203
+ onToggle(event, false);
204
+ }
205
+
206
+ function onToggle(event: Event, activate: boolean): void {
207
+ if (toggle != null) {
208
+ cancelAnimationFrame(toggle);
209
+ }
210
+
211
+ toggle = requestAnimationFrame(() => {
212
+ toggle = undefined;
213
+
214
+ const element = findAncestor(
215
+ event.target as HTMLElement,
216
+ SELECTOR_FULL,
217
+ ) as HTMLElement;
218
+
219
+ const tooltip = TOOLTIPS_ALL.get(element);
220
+
221
+ if (TOOLTIPS_ACTIVE.size > 0) {
222
+ closeTooltips(tooltip);
178
223
  }
179
224
 
180
- for (const event of deactivateEvents) {
181
- on(
182
- element,
183
- event,
184
- () => {
185
- deactivate(floatable, active, undefined, 250);
186
- },
187
- {
188
- signal: abortController.signal,
189
- },
190
- );
225
+ if (
226
+ tooltip == null ||
227
+ tooltip.floatable.options.content.hasAttribute(
228
+ 'oui-tooltip-content-active',
229
+ ) === activate
230
+ ) {
231
+ return;
191
232
  }
192
- }
233
+
234
+ if (activate) {
235
+ if (tooltip.timer != null) {
236
+ clearTimeout(tooltip.timer);
237
+ }
238
+
239
+ TOOLTIPS_ACTIVE.add(tooltip);
240
+ tooltip.floatable.toggle(true);
241
+
242
+ requestAnimationFrame(() => {
243
+ tooltip.floatable.options.content.setAttribute(
244
+ 'oui-tooltip-content-active',
245
+ '',
246
+ );
247
+ });
248
+
249
+ return;
250
+ }
251
+
252
+ tooltip.floatable.options.content.removeAttribute(
253
+ 'oui-tooltip-content-active',
254
+ );
255
+
256
+ tooltip.timer ??= setTimeout(() => {
257
+ TOOLTIPS_ACTIVE.delete(tooltip);
258
+ tooltip.floatable.toggle(false);
259
+ }, delay) as never;
260
+ });
193
261
  }
194
262
 
195
263
  function removeTooltip(element: HTMLElement): void {
196
- tooltips.get(element)?.destroy();
197
- tooltips.delete(element);
264
+ if (!element.hasAttribute(ATTRIBUTE_CONTENT)) {
265
+ TOOLTIPS_ALL.get(element)?.destroy();
266
+ }
198
267
  }
199
268
 
200
269
  function reset(anchor: HTMLElement, attributes: Attributes): void {
@@ -205,28 +274,46 @@ function reset(anchor: HTMLElement, attributes: Attributes): void {
205
274
  }
206
275
  }
207
276
 
277
+ function setDelay(value: number): void {
278
+ delay = typeof value === 'number' && value >= 0 ? value : delay;
279
+ }
280
+
208
281
  //
209
282
 
210
- const active = new Set<Floatable>();
283
+ const SELECTOR = 'oui-tooltip';
284
+
285
+ const ATTRIBUTE_CLASS = `${SELECTOR}-class`;
286
+
287
+ const ATTRIBUTE_CONTENT = `${SELECTOR}-content`;
288
+
289
+ const ATTRIBUTE_POSITION = `${SELECTOR}-position`;
290
+
291
+ const SELECTOR_CONTENT = `[${ATTRIBUTE_CONTENT}]`;
292
+
293
+ const SELECTOR_FULL = `[${SELECTOR}], [${ATTRIBUTE_CONTENT}]`;
211
294
 
212
- const activateEvents = ['focus', 'mouseenter', 'touchstart'];
295
+ const EXPRESSION_WHITESPACE = /\s+/;
213
296
 
214
- const deactivateEvents = ['blur', 'mouseleave'];
297
+ const TOOLTIPS_ACTIVE: Set<Tooltip> = new Set();
215
298
 
216
- const selector = 'oui-tooltip';
299
+ const TOOLTIPS_ALL: WeakMap<HTMLElement, Tooltip> = new WeakMap();
217
300
 
218
- const tooltips = new WeakMap<HTMLElement, Tooltip>();
301
+ let delay = 250;
219
302
 
220
303
  let index = 0;
221
304
 
305
+ let toggle: DOMHighResTimeStamp | undefined;
306
+
222
307
  //
223
308
 
224
- attributable(selector, addTooltip, removeTooltip);
309
+ attributable(SELECTOR, addTooltip, removeTooltip);
225
310
 
226
- on(document, 'keydown', event => {
227
- if (event.key === 'Escape') {
228
- for (const floatable of active) {
229
- deactivate(floatable, active);
230
- }
231
- }
232
- });
311
+ on(document, 'click', onClick, {capture: true});
312
+ on(document, 'focusin', onActivate);
313
+ on(document, 'focusout', onDeactivate);
314
+ on(document, 'mousemove', onActivate);
315
+ on(document, 'touchstart', onActivate);
316
+
317
+ //
318
+
319
+ export {setDelay};
@@ -1,17 +1,24 @@
1
1
  export declare class Floatable {
2
- anchor: HTMLElement;
3
- content: HTMLElement;
4
- readonly attribute: string;
5
- readonly position: Position;
6
- readonly preferAbove: boolean;
7
- activate: number | undefined;
2
+ readonly options: Options;
8
3
  active: boolean;
9
- deactivate: number | undefined;
4
+ disabled: boolean;
10
5
  frame: DOMHighResTimeStamp | undefined;
11
- constructor(anchor: HTMLElement, content: HTMLElement, attribute: string, position: Position, preferAbove: boolean);
6
+ ignoreFocus: boolean;
7
+ constructor(options: Options);
12
8
  destroy(): void;
9
+ disable(): void;
10
+ enable(): void;
11
+ toggle(active: boolean, ignoreFocus?: boolean): void;
13
12
  }
13
+ type Options = {
14
+ anchor: HTMLElement;
15
+ content: HTMLElement;
16
+ defaultPosition: Position;
17
+ interactive: boolean;
18
+ positionAttribute: string;
19
+ preferAbove: boolean;
20
+ onAfter?: (active: boolean) => void;
21
+ };
14
22
  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';
15
- export declare function activate(floatable: Floatable, active: Set<Floatable>, order?: Floatable[], time?: number): void;
16
- export declare function deactivate(floatable: Floatable, active: Set<Floatable>, order?: Floatable[], time?: number): void;
23
+ export declare function deactivate(floatable: Floatable): void;
17
24
  export {};
@@ -1,11 +1,24 @@
1
1
  export declare class FocusTrap {
2
+ disabled: boolean;
3
+ connected: boolean;
2
4
  element: HTMLElement;
3
- active: boolean;
4
- constructor(element: HTMLElement);
5
+ embedded: boolean;
6
+ get contain(): boolean;
7
+ get noescape(): boolean;
8
+ constructor(element: HTMLElement, options?: Options);
9
+ connect(): void;
5
10
  destroy(): void;
6
11
  disable(): void;
12
+ disconnect(): void;
7
13
  enable(): void;
14
+ focus(last: boolean): void;
8
15
  }
9
- export declare function createFocusTrap(element: HTMLElement): FocusTrap;
10
- export declare const focusTraps: WeakMap<HTMLElement, FocusTrap>;
11
- export declare const selector = "oui-focus-trap";
16
+ type Options = {
17
+ noescape: boolean;
18
+ };
19
+ export declare function createFocusTrap(element: HTMLElement, options?: Options): FocusTrap;
20
+ export declare const FOCUS_TRAP_SELECTOR = "oui-focus-trap";
21
+ export declare const FOCUS_TRAP_CONTAIN = "oui-focus-trap-contain";
22
+ export declare const FOCUS_TRAP_NOESCAPE = "oui-focus-trap-noescape";
23
+ export declare const FOCUSTRAPS_ALL: WeakMap<HTMLElement, FocusTrap>;
24
+ export {};
package/types/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './focus-trap/standalone';
2
2
  export * from './popover';
3
+ export * from './splitter';
3
4
  export * from './tooltip';
@@ -7,6 +7,8 @@ export declare class OuiPopoverElement extends HTMLElement {
7
7
  #private;
8
8
  constructor();
9
9
  close(): void;
10
+ connectedCallback(): void;
11
+ disconnectedCallback(): void;
10
12
  hidePopover(): void;
11
13
  open(): void;
12
14
  showPopover(): void;
@@ -1,11 +1,23 @@
1
1
  declare global {
2
2
  interface HTMLElementTagNameMap {
3
- 'oui-splitter': OuiSplitterElement;
3
+ [SELECTOR]: OuiSplitterElement;
4
4
  }
5
5
  }
6
6
  export declare class OuiSplitterElement extends HTMLElement {
7
7
  #private;
8
+ static readonly observedAttributes: string[];
9
+ get max(): number;
10
+ set max(value: number);
11
+ get min(): number;
12
+ set min(value: number);
13
+ get size(): number;
14
+ set size(value: number);
15
+ get type(): string;
16
+ set type(value: string);
8
17
  constructor();
9
18
  connectedCallback(): void;
10
19
  disconnectedCallback(): void;
20
+ attributeChangedCallback(name: string): void;
11
21
  }
22
+ declare const SELECTOR = "oui-splitter";
23
+ export {};
@@ -1 +1,2 @@
1
- export {};
1
+ declare function setDelay(value: number): void;
2
+ export { setDelay };
@@ -1,51 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- function attributable(attribute, add, remove) {
4
- const observer = new MutationObserver((entries) => {
5
- const { length } = entries;
6
- for (let index = 0; index < length; index += 1) {
7
- const entry = entries[index];
8
- if (entry.type === "attributes" && entry.target instanceof HTMLElement) {
9
- if (entry.target.hasAttribute(attribute)) {
10
- handleAdded(attribute, [entry.target], add);
11
- } else {
12
- handleRemoved([entry.target], remove);
13
- }
14
- } else if (entry.type === "childList") {
15
- handleAdded(attribute, entry.addedNodes, add);
16
- handleRemoved(entry.removedNodes, remove);
17
- }
18
- }
19
- });
20
- observer.observe(document, {
21
- attributeFilter: [attribute],
22
- attributes: true,
23
- childList: true,
24
- subtree: true
25
- });
26
- requestAnimationFrame(() => {
27
- handleAdded(attribute, document.querySelectorAll(`[${attribute}]`), add);
28
- });
29
- }
30
- function handleAdded(attribute, nodes, add) {
31
- const elements = [...nodes].filter(
32
- (node) => node instanceof HTMLElement
33
- );
34
- const { length } = elements;
35
- for (let index = 0; index < length; index += 1) {
36
- const element = elements[index];
37
- if (element.hasAttribute(attribute)) {
38
- add(element);
39
- }
40
- }
41
- }
42
- function handleRemoved(nodes, remove) {
43
- const elements = [...nodes].filter(
44
- (node) => node instanceof HTMLElement
45
- );
46
- const { length } = elements;
47
- for (let index = 0; index < length; index += 1) {
48
- remove(elements[index]);
49
- }
50
- }
51
- exports.attributable = attributable;
@@ -1,176 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- class Floatable {
4
- constructor(anchor, content, attribute, position, preferAbove) {
5
- this.anchor = anchor;
6
- this.content = content;
7
- this.attribute = attribute;
8
- this.position = position;
9
- this.preferAbove = preferAbove;
10
- setStyles(content);
11
- }
12
- activate;
13
- active = false;
14
- deactivate;
15
- frame;
16
- destroy() {
17
- this.activate = void 0;
18
- this.deactivate = void 0;
19
- this.frame = void 0;
20
- this.anchor = void 0;
21
- this.content = void 0;
22
- }
23
- }
24
- function activate(floatable, active, order, time) {
25
- stop(floatable);
26
- if (floatable.active) {
27
- return;
28
- }
29
- if (time == null || time === 0) {
30
- onActivate(floatable, active, order);
31
- } else {
32
- floatable.activate = +setTimeout(() => {
33
- onActivate(floatable, active, order);
34
- }, time);
35
- }
36
- }
37
- function deactivate(floatable, active, order, time) {
38
- stop(floatable);
39
- if (!floatable.active) {
40
- return;
41
- }
42
- if (time == null || time === 0) {
43
- onDeactivate(floatable, active, order);
44
- } else {
45
- floatable.deactivate = +setTimeout(() => {
46
- onDeactivate(floatable, active, order);
47
- }, time);
48
- }
49
- }
50
- function getX(anchor, content, position) {
51
- if (position.endsWith("-end")) {
52
- const end = anchor.right - content.width;
53
- return end - margin < 0 ? margin : end;
54
- }
55
- if (position.endsWith("-start")) {
56
- const start = anchor.left;
57
- return start + content.width + margin > window.innerWidth ? window.innerWidth - content.width - margin : start;
58
- }
59
- if (position.startsWith("end")) {
60
- return anchor.right + margin;
61
- }
62
- if (position.startsWith("start")) {
63
- return anchor.left - content.width - margin;
64
- }
65
- if (position.startsWith("horizontal")) {
66
- if (anchor.right + content.width + margin <= window.innerWidth) {
67
- return anchor.right + margin;
68
- }
69
- return anchor.left - content.width - margin;
70
- }
71
- return anchor.left + (anchor.width - content.width) / 2;
72
- }
73
- function getY(anchor, content, position, preferAbove) {
74
- if (position.startsWith("above")) {
75
- return anchor.top - content.height - margin;
76
- }
77
- if (position.startsWith("below")) {
78
- return anchor.bottom + margin;
79
- }
80
- if (position.endsWith("bottom")) {
81
- const bottom = anchor.bottom - content.height;
82
- return bottom + margin < 0 ? margin : bottom;
83
- }
84
- if (position.endsWith("top")) {
85
- const top = anchor.top;
86
- return top + content.height + margin > window.innerHeight ? window.innerHeight - content.height - margin : top;
87
- }
88
- if (position.startsWith("vertical")) {
89
- if (preferAbove && anchor.top - content.height - margin >= 0) {
90
- return anchor.top - content.height - margin;
91
- }
92
- if (anchor.bottom + content.height + margin <= document.body.clientHeight) {
93
- return anchor.bottom + margin;
94
- }
95
- return anchor.top - content.height - margin;
96
- }
97
- return anchor.top + (anchor.height - content.height) / 2;
98
- }
99
- function onActivate(floatable, active, order) {
100
- floatable.active = true;
101
- active.add(floatable);
102
- if (order != null) {
103
- order.push(floatable);
104
- }
105
- document.body.append(floatable.content);
106
- floatable.content.hidden = false;
107
- update(floatable);
108
- }
109
- function onDeactivate(floatable, active, order) {
110
- floatable.active = false;
111
- active.delete(floatable);
112
- const index = order?.indexOf(floatable) ?? -1;
113
- if (index > -1) {
114
- order?.splice(index, 1);
115
- }
116
- floatable.content.hidden = true;
117
- floatable.anchor.insertAdjacentElement("afterend", floatable.content);
118
- }
119
- function update(floatable) {
120
- let position = floatable.anchor.getAttribute(floatable.attribute)?.trim() ?? floatable.position;
121
- if (!positions.has(position)) {
122
- position = floatable.position;
123
- }
124
- function run() {
125
- const anchor = floatable.anchor.getBoundingClientRect();
126
- const content = floatable.content.getBoundingClientRect();
127
- const left = getX(anchor, content, position);
128
- const top = getY(anchor, content, position, floatable.preferAbove);
129
- floatable.content.style.inset = `${top}px auto auto ${left}px`;
130
- floatable.frame = requestAnimationFrame(run);
131
- }
132
- floatable.frame = requestAnimationFrame(run);
133
- }
134
- function setStyles(content) {
135
- content.style.position = "fixed";
136
- content.style.inset = "0 auto auto 0";
137
- content.style.zIndex = "10";
138
- }
139
- function stop(floatable) {
140
- if (floatable.frame != null) {
141
- cancelAnimationFrame(floatable.frame);
142
- }
143
- if (floatable.activate != null) {
144
- clearTimeout(floatable.activate);
145
- }
146
- if (floatable.deactivate != null) {
147
- clearTimeout(floatable.deactivate);
148
- }
149
- floatable.activate = void 0;
150
- floatable.deactivate = void 0;
151
- floatable.frame = void 0;
152
- }
153
- const margin = Number.parseInt(getComputedStyle(document.documentElement).fontSize, 10) / 2;
154
- const positions = /* @__PURE__ */ new Set([
155
- "above",
156
- "above-end",
157
- "above-start",
158
- "below",
159
- "below-end",
160
- "below-start",
161
- "end",
162
- "end-bottom",
163
- "end-top",
164
- "horizontal",
165
- "horizontal-bottom",
166
- "horizontal-top",
167
- "start",
168
- "start-bottom",
169
- "start-top",
170
- "vertical",
171
- "vertical-end",
172
- "vertical-start"
173
- ]);
174
- exports.Floatable = Floatable;
175
- exports.activate = activate;
176
- exports.deactivate = deactivate;