@t007/dialog 0.0.30 → 0.0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.css CHANGED
@@ -37,12 +37,12 @@
37
37
  --t007-dialog-button-padding-block: calc(var(--t007-dialog-unit) * 0.5);
38
38
  --t007-dialog-button-border-radius: calc(var(--t007-dialog-unit) * 1.25);
39
39
  --t007-dialog-button-gap: calc(var(--t007-dialog-unit) * 0.65);
40
- --t007-confirm-button-color: grey;
41
- --t007-confirm-button-background: var(--t007-cancel-button-color);
42
- --t007-cancel-button-color: greenyellow;
43
- --t007-cancel-button-background: var(--t007-confirm-button-color);
44
- --t007-confirm-button-outline-color: var(--t007-cancel-button-color);
45
- --t007-cancel-button-outline-color: var(--t007-cancel-button-color);
40
+ --t007-dialog-confirm-button-color: grey;
41
+ --t007-dialog-confirm-button-background: var(--t007-dialog-cancel-button-color);
42
+ --t007-dialog-cancel-button-color: greenyellow;
43
+ --t007-dialog-cancel-button-background: var(--t007-dialog-confirm-button-color);
44
+ --t007-dialog-confirm-button-outline-color: var(--t007-dialog-cancel-button-color);
45
+ --t007-dialog-cancel-button-outline-color: var(--t007-dialog-cancel-button-color);
46
46
  }
47
47
  :where(.t007-dialog) .t007-input-field {
48
48
  --t007-input-color: var(--t007-dialog-message-color);
@@ -213,13 +213,13 @@ body:has(> .t007-dialog) {
213
213
  transition: 100ms ease;
214
214
  }
215
215
  .t007-dialog-confirm-button {
216
- color: var(--t007-confirm-button-color);
217
- background: var(--t007-confirm-button-background);
216
+ color: var(--t007-dialog-confirm-button-color);
217
+ background: var(--t007-dialog-confirm-button-background);
218
218
  opacity: 1;
219
219
  }
220
220
  .t007-dialog-cancel-button {
221
- color: var(--t007-cancel-button-color);
222
- background: var(--t007-cancel-button-background);
221
+ color: var(--t007-dialog-cancel-button-color);
222
+ background: var(--t007-dialog-cancel-button-background);
223
223
  opacity: 0.9;
224
224
  }
225
225
  .t007-dialog button:hover {
@@ -236,8 +236,8 @@ body:has(> .t007-dialog) {
236
236
  outline-width: var(--t007-button-outline-width);
237
237
  }
238
238
  .t007-dialog-confirm-button:focus {
239
- outline-color: var(--t007-confirm-button-outline-color);
239
+ outline-color: var(--t007-dialog-confirm-button-outline-color);
240
240
  }
241
241
  .t007-dialog-cancel-button:focus {
242
- outline-color: var(--t007-cancel-button-outline-color);
242
+ outline-color: var(--t007-dialog-cancel-button-outline-color);
243
243
  }
package/dist/index.d.ts CHANGED
@@ -1,19 +1,18 @@
1
- import "@t007/utils";
2
- import type { FieldOptions } from "@t007/input";
1
+ import { FieldOptions } from '@t007/input';
3
2
 
4
3
  /** Shared options for alert, confirm, and prompt dialogs. */
5
- export interface DialogOptions {
4
+ interface DialogOptions {
6
5
  /** Unique identifier for the dialog for programmatic dismissal. Auto-generated by default. */
7
6
  id?: string;
8
- /** Text for the confirmation button. Defaults to "OK". */
7
+ /** Text for the confirmation button. @default "OK". */
9
8
  confirmText?: string;
10
- /** Text for the cancel button where applicable. Defaults to "Cancel". */
9
+ /** Text for the cancel button where applicable. @default "Cancel". */
11
10
  cancelText?: string;
12
- /** Browser behavior for handling dialog closure. Defaults to "any". */
11
+ /** Browser behavior for handling dialog closure. @default "any". */
13
12
  closedBy?: HTMLDialogElement["closedBy"];
14
13
  /** Render dialog inside a specific root element instead of document body. */
15
14
  rootElement?: HTMLElement;
16
- /** Whether to restrict interactions to `rootElement` if provided. Defaults to `true`. */
15
+ /** Whether to restrict interactions to `rootElement` if provided. @default `true`. */
17
16
  scoped?: boolean;
18
17
  }
19
18
 
@@ -23,31 +22,31 @@ export interface DialogOptions {
23
22
  * @param id Optional unique identifier of the dialog to check.
24
23
  * @return `true` if the specified dialog (or any dialog when no id is provided) is active, otherwise `false`.
25
24
  */
26
- export function isActive(id?: string): boolean;
25
+ declare function isActive(id?: string): boolean;
27
26
  /** Show an alert dialog and resolve when the user confirms.
28
27
  * @param message Message shown in the dialog body.
29
28
  * @param options Optional dialog configuration.
30
29
  * @returns Promise that resolves to the user choice.
31
30
  */
32
- export function alert(message: string, options?: DialogOptions): Promise<boolean>;
31
+ declare function alert(message: string, options?: DialogOptions): Promise<boolean>;
33
32
  /** Show a confirm dialog and resolve with the user choice.
34
33
  * @param question Question shown in the dialog body.
35
34
  * @param options Optional dialog configuration.
36
35
  * @returns Promise that resolves to true when confirmed.
37
36
  */
38
- export function confirm(question: string, options?: DialogOptions): Promise<boolean>;
37
+ declare function confirm(question: string, options?: DialogOptions): Promise<boolean>;
39
38
  /** Show a prompt dialog and resolve with the entered value.
40
39
  * @param question Question shown in the dialog body.
41
40
  * @param defaultValue Initial value for the prompt input.
42
41
  * @param options Optional dialog configuration.
43
42
  * @returns Promise that resolves to the entered string or null.
44
43
  */
45
- export function prompt(question: string, defaultValue?: string, options?: DialogOptions & FieldOptions): Promise<string | null>;
44
+ declare function prompt(question: string, defaultValue?: string, options?: DialogOptions & FieldOptions): Promise<string | null>;
46
45
  /** Dismiss a dialog by id or all dialogs when no id is provided.
47
46
  * @param id Optional unique identifier of the dialog to dismiss. If not provided, all dialogs will be dismissed.
48
47
  * @param response Optional value to resolve the dialog's promise with. If not provided, defaults to `true` for confirm and alert dialogs, and `null` for prompt dialogs.
49
48
  */
50
- export function dismiss(id?: string, response?: any): void;
49
+ declare function dismiss(id?: string, response?: any): void;
51
50
 
52
51
  interface Dialog {
53
52
  isActive(id?: string): boolean;
@@ -74,3 +73,5 @@ declare global {
74
73
  Prompt?: T007Namespace["prompt"];
75
74
  }
76
75
  }
76
+
77
+ export { type DialogOptions, alert, confirm, dismiss, isActive, prompt };
@@ -1,32 +1,11 @@
1
1
  "use strict";
2
2
  (() => {
3
- // ../../../sia-reactor/dist/chunk-IBAPWB27.js
3
+ // ../../../sia-reactor/dist/chunk-JGEI2Q4M.js
4
4
  function clamp(min = 0, val, max = Infinity) {
5
5
  return Math.min(Math.max(val, min), max);
6
6
  }
7
7
 
8
- // ../../../sia-reactor/dist/chunk-RI45W4O6.js
9
- function createEl(tag, props, dataset, styles, el = tag ? document?.createElement(tag) : null) {
10
- return assignEl(el, props, dataset, styles), el;
11
- }
12
- function assignEl(el, props, dataset, styles) {
13
- if (!el) return;
14
- if (props) {
15
- for (const k of Object.keys(props)) if (props[k] !== void 0) el[k] = props[k];
16
- }
17
- if (dataset) {
18
- for (const k of Object.keys(dataset)) if (dataset[k] !== void 0) el.dataset[k] = String(dataset[k]);
19
- }
20
- if (styles) {
21
- for (const k of Object.keys(styles)) if (styles[k] !== void 0) el.style[k] = styles[k];
22
- }
23
- }
24
- function getActiveEl(root) {
25
- const activeEl = (root ?? document).activeElement;
26
- return !activeEl ? null : activeEl.shadowRoot ? getActiveEl(activeEl.shadowRoot) : activeEl;
27
- }
28
-
29
- // ../../../sia-reactor/dist/chunk-3OT72G7R.js
8
+ // ../../../sia-reactor/dist/chunk-ORK3EGB6.js
30
9
  function onAllMethods(owner, callback, skipOwn = true, nested = false) {
31
10
  let proto = owner;
32
11
  while (proto && proto !== Object.prototype) {
@@ -43,52 +22,75 @@
43
22
  owner2[method] = owner2[method].bind(owner2);
44
23
  });
45
24
  }
25
+ function createEl(tag, props, dataset, styles, el = tag ? document?.createElement(tag) : null) {
26
+ return assignEl(el, props, dataset, styles);
27
+ }
28
+ function assignEl(el, props, dataset, styles, nodiff = true) {
29
+ if (!el) return null;
30
+ if (props) {
31
+ for (const k of Object.keys(props)) if (props[k] !== void 0) {
32
+ if (nodiff || el[k] !== props[k]) el[k] = props[k];
33
+ }
34
+ }
35
+ if (dataset) {
36
+ for (const k of Object.keys(dataset)) if (dataset[k] !== void 0) {
37
+ if (nodiff || el.dataset[k] !== dataset[k]) el.dataset[k] = String(dataset[k]);
38
+ }
39
+ }
40
+ if (styles) {
41
+ for (const k of Object.keys(styles)) if (styles[k] !== void 0) {
42
+ if (nodiff || el.style[k] !== styles[k]) el.style[k] = styles[k];
43
+ }
44
+ }
45
+ return el;
46
+ }
47
+ function getActiveEl(root) {
48
+ const activeEl = (root ?? document).activeElement;
49
+ return !activeEl ? null : activeEl.shadowRoot ? getActiveEl(activeEl.shadowRoot) : activeEl;
50
+ }
46
51
 
47
- // ../../../sia-reactor/dist/chunk-4PLMBUCP.js
48
- var CTX = {
49
- /** Flag indicating whether the application is running in development mode. */
50
- isDevEnv: "undefined" !== typeof process ? process.env.NODE_ENV !== "production" : true,
51
- /** Flag indicating whether a cascade is currently ongoing so reactors can allow all writes. */
52
- isCascading: false,
53
- /** Active `Autotracker` instance, override for automatic dependency collection on `Reactor` traps. */
54
- autotracker: null
55
- };
52
+ // ../../../sia-reactor/dist/chunk-SHWIAQD2.js
56
53
  var RTR_BATCH = "undefined" !== typeof window ? ("undefined" !== typeof queueMicrotask ? queueMicrotask : setTimeout).bind(window) : "undefined" !== typeof process && process.nextTick ? process.nextTick : setTimeout;
57
54
  var RTR_LOG = console.log.bind(console, "[S.I.A Reactor]");
58
55
  var NIL = Object.freeze({});
59
56
  var NOOP = () => {
60
57
  };
58
+ var isDevEnv = false;
59
+ try {
60
+ isDevEnv = process.env.NODE_ENV !== "production";
61
+ } catch (e) {
62
+ }
61
63
 
62
- // ../utils/dist/chunk-4O76EZJ4.js
63
- var INTERACTIVE_SELECTOR = ":is(button,[href],input:not([type='hidden']),select,textarea,details>summary,[contenteditable='true'],iframe,audio[controls],video[controls],[tabindex]):not([disabled],[tabindex='-1'],[data-focus-guard],[inert],[inert] *)";
64
+ // ../utils/dist/chunk-ZALPHCSJ.js
65
+ var INTERACTIVE_SELECTOR = ":is(button,[href],input:not([type='hidden']),select,textarea,details>summary,[contenteditable],iframe,audio[controls],video[controls],[tabindex]):not([disabled],[tabindex='-1'],[data-focus-guard],[inert],[inert] *)";
64
66
  var isInteractive = (target) => target instanceof HTMLElement && target.matches(INTERACTIVE_SELECTOR);
65
67
  var VIRTUAL_RESOURCE = /* @__PURE__ */ Symbol.for("T007_VIRTUAL_RESOURCE");
66
- function loadResource(req, type = "style", { module, media, crossOrigin, integrity, referrerPolicy, nonce, fetchPriority, attempts = 3, retryKey = false } = {}, w = window) {
67
- w.t007 ??= {}, w.t007._resourceCache ??= {};
68
+ function loadResource(req, type = "style", { module, media, crossOrigin, integrity, referrerPolicy, nonce, fetchPriority, attempts = 3, retryKey = false } = {}, win = window) {
69
+ win.t007 ??= {}, win.t007._resourceCache ??= {};
68
70
  if (req === VIRTUAL_RESOURCE || isSym(req)) return Promise.resolve();
69
71
  const src = req;
70
- if (w.t007._resourceCache[src]) return w.t007._resourceCache[src];
71
- const existing = type === "script" ? Array.prototype.find.call(w.document.scripts, (s) => isSameURL(s.src, src)) : type === "style" ? Array.prototype.find.call(w.document.styleSheets, (s) => isSameURL(s.href, src)) : null;
72
- if (existing) return w.t007._resourceCache[src] = Promise.resolve(existing);
73
- w.t007._resourceCache[src] = new Promise((resolve, reject) => {
72
+ if (win.t007._resourceCache[src]) return win.t007._resourceCache[src];
73
+ const existing = type === "script" ? Array.prototype.find.call(win.document.scripts, (s) => isSameURL(s.src, src)) : type === "style" ? Array.prototype.find.call(win.document.styleSheets, (s) => isSameURL(s.href, src)) : null;
74
+ if (existing) return win.t007._resourceCache[src] = Promise.resolve(existing);
75
+ win.t007._resourceCache[src] = new Promise((resolve, reject) => {
74
76
  (function tryLoad(remaining, el) {
75
77
  const onerror = () => {
76
78
  el?.remove?.();
77
79
  if (remaining > 1) {
78
80
  setTimeout(tryLoad, 1e3, remaining - 1);
79
- console.warn(`Retrying ${type} load (${attempts - remaining + 1}): ${src}...`);
81
+ console.warn(`Retrying ${type} load for "${src}" (${attempts - remaining + 1})...`);
80
82
  } else {
81
- delete w.t007._resourceCache[src];
82
- reject(new Error(`${type} load failed after ${attempts} attempts: ${src}`));
83
+ delete win.t007._resourceCache[src];
84
+ reject(new Error(`${capitalize(type)} load failed for "${src}" after ${attempts - 1} attempts`));
83
85
  }
84
86
  };
85
87
  const url = retryKey && remaining < attempts ? `${src}${src.includes("?") ? "&" : "?"}_${retryKey}=${Date.now()}` : src;
86
- if (type === "script") w.document.body.append(el = createEl("script", { src: url, type: module ? "module" : "text/javascript", crossOrigin, integrity, referrerPolicy, nonce, fetchPriority, onload: () => resolve(el), onerror }) || "");
87
- else if (type === "style") w.document.head.append(el = createEl("link", { rel: "stylesheet", href: url, media, crossOrigin, integrity, referrerPolicy, nonce, fetchPriority, onload: () => resolve(el), onerror }) || "");
88
+ if (type === "script") win.document.body.append(el = createEl("script", { src: url, type: module ? "module" : "text/javascript", crossOrigin, integrity, referrerPolicy, nonce, fetchPriority, onload: () => resolve(el), onerror }) || "");
89
+ else if (type === "style") win.document.head.append(el = createEl("link", { rel: "stylesheet", href: url, media, crossOrigin, integrity, referrerPolicy, nonce, fetchPriority, onload: () => resolve(el), onerror }) || "");
88
90
  else reject(new Error(`Unsupported resource type: ${type}`));
89
91
  })(attempts);
90
92
  });
91
- return w.t007._resourceCache[src];
93
+ return win.t007._resourceCache[src];
92
94
  }
93
95
  function isDef(val) {
94
96
  return "undefined" !== typeof val;
@@ -102,6 +104,9 @@
102
104
  function uid(prefix = "") {
103
105
  return prefix + Date.now().toString(36) + "_" + performance.now().toString(36).replace(".", "") + "_" + Math.random().toString(36).slice(2);
104
106
  }
107
+ function capitalize(word = "") {
108
+ return word.replace(/^(\s*)([a-z])/i, (_, s, l) => s + l.toUpperCase());
109
+ }
105
110
  function parseCSSTime(time) {
106
111
  return time?.endsWith?.("ms") ? parseFloat(time) : parseFloat(time) * 1e3;
107
112
  }
@@ -114,6 +119,7 @@
114
119
  }
115
120
  }
116
121
  function isSameURL(url1, url2) {
122
+ if (url1 === url2) return true;
117
123
  if (!isStr(url1) || !isStr(url2) || !url1 || !url2) return false;
118
124
  return cleanURL(url1) === cleanURL(url2);
119
125
  }
@@ -127,33 +133,33 @@
127
133
  window.T007_DIALOG_CSS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/dialog@latest/dist/index.min.css`;
128
134
  }
129
135
 
130
- // ../utils/dist/chunk-QJ72EQCJ.js
136
+ // ../utils/dist/chunk-NX2LWYD6.js
131
137
  function initOutsideClick(el, { enabled = false, onOutside = NOOP, outOnClick = true, outOnEscape = true, outOnFocusOut = false, allowBounds = false, allowInputs = false, root = window, scoped = true, capture = true } = NIL) {
132
- const stacks = t007._outsiders_stacks ??= /* @__PURE__ */ new WeakMap(), existing = (t007._outsiders ??= /* @__PURE__ */ new WeakMap()).get(el);
138
+ const stack = t007._outsiders_stack ??= [], existing = (t007._outsiders ??= /* @__PURE__ */ new WeakMap()).get(el);
133
139
  if (!enabled || existing) return existing ? existing : void 0;
134
140
  scoped = scoped && root instanceof HTMLElement, root = scoped ? root : root === document ? document : window;
135
- const stack = stacks.get(root) ?? [], onScopedOut = (e, t, p = e.touches?.[0] || e, rect = allowBounds ? el.getBoundingClientRect() : null) => {
141
+ const onScopedOut = (e, t, p = e.touches?.[0] || e, rect = allowBounds ? el.getBoundingClientRect() : null) => {
136
142
  if (stack.at(-1) !== el || (allowBounds ? p.clientX >= rect.left && p.clientX <= rect.right && p.clientY >= rect.top && p.clientY <= rect.bottom : el.contains(t))) return false;
137
143
  return (!scoped ? true : root.contains(t)) && onOutside(e);
138
144
  }, handleClick = ((e) => outOnClick && !(allowInputs && isInteractive(e.target)) && onScopedOut(e, e.target)), handleEscape = ((e) => outOnEscape && e.key === "Escape" && !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey && stack.at(-1) === el && onOutside(e)), handleFocusOut = (e) => outOnFocusOut && !el.contains(e.relatedTarget) && onScopedOut(e, e.relatedTarget);
139
145
  root.addEventListener("mousedown", handleClick, capture), root.addEventListener("touchstart", handleClick, { passive: true, capture });
140
146
  root.addEventListener("keydown", handleEscape, capture);
141
147
  el.addEventListener("focusout", handleFocusOut, capture);
142
- if (!stack.includes(el)) stack.push(el), stacks.set(root, stack);
143
148
  const destroy = () => {
144
149
  root.removeEventListener("mousedown", handleClick, capture), root.removeEventListener("touchstart", handleClick, capture);
145
150
  root.removeEventListener("keydown", handleEscape, capture);
146
151
  el.removeEventListener("focusout", handleFocusOut, capture);
147
152
  t007._outsiders.delete(el), stack.splice(stack.indexOf(el), 1);
148
153
  };
149
- return t007._outsiders.set(el, destroy), destroy;
154
+ return !stack.includes(el) && stack.push(el), t007._outsiders.set(el, destroy), destroy;
150
155
  }
151
156
  var removeOutsideClick = (el) => t007._outsiders?.get(el)?.();
152
157
  function initFocusTrap(el, { enabled = false, initialSelector = "[data-autofocus]", ringClassName = "focus-outline", root = window, scoped = true, capture = true } = NIL) {
153
- const stacks = t007._ftrappers_stacks ??= /* @__PURE__ */ new WeakMap(), existing = (t007._ftrappers ??= /* @__PURE__ */ new WeakMap()).get(el);
158
+ const stack = t007._ftrappers_stack ??= [], existing = (t007._ftrappers ??= /* @__PURE__ */ new WeakMap()).get(el);
154
159
  if (!enabled || existing) return existing ? existing : void 0;
155
160
  scoped = scoped && root instanceof HTMLElement, root = scoped ? root : root === document ? document : window;
156
- const stack = stacks.get(root) ?? [], focused = document.querySelector(":focus"), initial = el.querySelector(initialSelector), first = createEl("span", { tabIndex: 0 }, { focusGuard: "start" }, { position: "absolute", width: "0", height: "0", pointerEvents: "none" }), last = createEl("span", { tabIndex: 0 }, { focusGuard: "end" }, { position: "absolute", width: "0", height: "0", pointerEvents: "none" }), getFocusable = (c = el) => [...c.querySelectorAll(INTERACTIVE_SELECTOR)], resetFocus = (i = 0, els = getFocusable()) => els?.length ? els.at(i).focus() : (!el.hasAttribute("tabindex") && (el.tabIndex = -1), el.focus()), edgeFocus = (pre = false, rt = root) => {
161
+ let recovering = false;
162
+ const focused = document.querySelector(":focus"), initial = el.querySelector(initialSelector), first = createEl("span", { tabIndex: 0 }, { focusGuard: "start" }, { position: "absolute", width: "0", height: "0", pointerEvents: "none" }), last = createEl("span", { tabIndex: 0 }, { focusGuard: "end" }, { position: "absolute", width: "0", height: "0", pointerEvents: "none" }), getFocusable = (c = el) => [...c.querySelectorAll(INTERACTIVE_SELECTOR)], resetFocus = (i = 0, els = getFocusable()) => !recovering && (recovering = true, els?.length ? els.at(i).focus() : (!el.hasAttribute("tabindex") && (el.tabIndex = -1), el.focus()), recovering = false), edgeFocus = (pre = false, rt = root) => {
157
163
  if (!scoped) return resetFocus(pre ? -1 : 0);
158
164
  if (rt.hasAttribute("tabindex")) return rt.focus();
159
165
  const items = getFocusable();
@@ -163,24 +169,24 @@
163
169
  while (p !== ceil && (!all.length || (pre ? rt.contains(all[0]) : rt.contains(all.at(-1))))) all = getFocusable(p = p.parentElement || ceil);
164
170
  for (let target, len = all.length, i = all.indexOf(items[pre ? 0 : items.length - 1]) + (pre ? -1 : 1); pre ? i >= 0 : i < len; pre ? i-- : i++) if (!rt.contains(target = all[i])) return target.focus();
165
171
  (pre ? first : last).blur();
166
- }, handleFocusIn = () => {
172
+ }, handleFocusIn = (e) => {
167
173
  if (document.querySelector("dialog:modal") && !el.matches("dialog:modal")) return;
168
- stack.at(-1) === el && getActiveEl(el.ownerDocument) !== root && !el.contains(getActiveEl(el.ownerDocument)) && resetFocus();
174
+ stack.at(-1) === el && getActiveEl(el.ownerDocument) !== root && !el.contains(getActiveEl(el.ownerDocument)) && !e.composedPath().includes(el) && resetFocus();
169
175
  }, handleInitialBlur = () => initial.classList.remove(ringClassName);
170
176
  first.addEventListener("focus", (e) => el.contains(e.relatedTarget) ? edgeFocus(true) : resetFocus(), capture), el.prepend(first);
171
177
  last.addEventListener("focus", (e) => el.contains(e.relatedTarget) ? edgeFocus() : resetFocus(-1), capture), el.append(last);
172
178
  root.addEventListener("focusin", handleFocusIn, capture);
173
179
  if (initial || !el.contains(focused)) !initial ? setTimeout(resetFocus) : setTimeout(() => (initial.classList.add(ringClassName), initial.focus(), initial.addEventListener("blur", handleInitialBlur, capture)));
174
- if (!stack.includes(el)) stack.push(el), stacks.set(root, stack);
175
180
  const destroy = () => {
176
181
  focused?.isConnected && focused.focus(), first.remove(), last.remove();
177
182
  root.removeEventListener("focusin", handleFocusIn, capture);
178
183
  initial?.removeEventListener("blur", handleInitialBlur, capture);
179
184
  t007._ftrappers.delete(el), stack.splice(stack.indexOf(el), 1);
180
185
  };
181
- return t007._ftrappers.set(el, destroy), destroy;
186
+ const handle = { destroy, sync: () => (el.prepend(first), el.append(last)) };
187
+ return !stack.includes(el) && stack.push(el), t007._ftrappers.set(el, handle), handle;
182
188
  }
183
- var removeFocusTrap = (el) => t007._ftrappers?.get(el)?.();
189
+ var removeFocusTrap = (el) => t007._ftrappers?.get(el)?.destroy();
184
190
  var getTargetIndex = ({ key, currIndex, length, gridX, gridY, vGridY, loop, ctrlKey = false, rtl }) => {
185
191
  const rowStart = currIndex - currIndex % gridX, rowEnd = Math.min(rowStart + gridX - 1, length - 1), colStart = currIndex % gridX, colEnd = Math.min(colStart + gridX * (gridY - 1), length - 1), canX = gridX > 1, canY = gridY > 1, horizontalMove = rtl ? { ArrowRight: canX ? -1 : 0, ArrowLeft: canX ? 1 : 0 } : { ArrowRight: canX ? 1 : 0, ArrowLeft: canX ? -1 : 0 }, move = { ...horizontalMove, ArrowDown: canY ? gridX : 0, ArrowUp: canY ? -gridX : 0, Home: ctrlKey ? 0 : rowStart, End: ctrlKey ? length - 1 : rowEnd, PageDown: (vGridY - 1) * gridX, PageUp: -(vGridY - 1) * gridX }[key] ?? 0;
186
192
  let targetIndex = key === "Home" || key === "End" ? move : currIndex + move;
@@ -240,7 +246,7 @@
240
246
  rtl: null,
241
247
  grid: {},
242
248
  activeClass: "focus-outlined",
243
- inputSelector: "input,textarea,[contenteditable='true']",
249
+ inputSelector: "input,textarea,[contenteditable]",
244
250
  focusOptions: { preventScroll: false },
245
251
  scrollIntoView: { block: "nearest", inline: "nearest" },
246
252
  onSelect: NOOP,
@@ -253,7 +259,7 @@
253
259
  if (!config.enabled || existing) return existing ? existing : void 0;
254
260
  const { enabled: isEnabled, selector, focusOnHover, loop, virtual, typeahead, resetMs, activeClass, inputSelector, defaultTabbableIndex, baseTabIndex, grid, rtl: isRtl, focusOptions, scrollIntoView, onSelect, onFocusOut, rovingTab } = { ...DEFAULT_CONFIG, ...config };
255
261
  let gridX = grid.x || 1, gridY = grid.y || 1, vGridY = grid.vY || 1, activeIndex = -1, buffer = "", timeout = null, items = [];
256
- const enabled = isEnabled ?? virtual, roving = rovingTab ?? !virtual, rtl = isRtl ?? ("undefined" === typeof document ? false : getComputedStyle(container).direction === "rtl"), shouldSnub = () => !enabled || !container, isItemDisabled = (el) => !el || el.hasAttribute("disabled") || el.hasAttribute("aria-disabled"), getItems = () => items = Array.from(container.querySelectorAll(selector));
262
+ const enabled = isEnabled ?? virtual, roving = rovingTab ?? !virtual, rtl = isRtl ?? ("undefined" === typeof document ? false : getComputedStyle(container).direction === "rtl"), shouldSnub = () => !enabled || !container, isItemDisabled = (el) => !el || el.matches('[disabled],[aria-disabled="true"],[inert],:disabled'), getItems = () => items = Array.from(container.querySelectorAll(selector));
257
263
  const getAbleIndex = (targetIndex, e = { key: "ArrowRight", ctrlKey: false }) => {
258
264
  if (shouldSnub() || !items.length) return null;
259
265
  let index = targetIndex;
@@ -328,34 +334,41 @@
328
334
  if (idx !== -1) goToIndex(idx);
329
335
  };
330
336
  for (const el of items) el.addEventListener("mouseenter", handleHover);
331
- const mutationObserver = new MutationObserver(() => {
337
+ const sync = () => {
332
338
  const oldEl = items[activeIndex];
339
+ for (const el of items) el.removeEventListener("mouseenter", handleHover);
333
340
  getItems();
341
+ for (const el of items) el.addEventListener("mouseenter", handleHover);
342
+ calcGrid();
334
343
  const newEl = items[activeIndex];
335
344
  updateDOM();
336
345
  if (oldEl && newEl && oldEl === newEl) return;
337
- resetActiveIndex();
338
- updateDOM();
339
- });
346
+ resetActiveIndex(), updateDOM();
347
+ };
348
+ const mutationObserver = new MutationObserver(sync);
340
349
  mutationObserver.observe(container, { childList: true, subtree: true });
341
350
  const setGrid = (g) => {
342
351
  if (g.x !== void 0) gridX = g.x;
343
352
  if (g.y !== void 0) gridY = g.y;
344
353
  if (g.vY !== void 0) vGridY = g.vY;
345
354
  };
346
- const calcGrid = () => setGrid(getGrid(items, !grid.x, !grid.y, !grid.vY));
355
+ let ancestor = null;
356
+ const resizeObserver = new ResizeObserver(() => calcGrid());
357
+ const calcGrid = () => {
358
+ setGrid(getGrid(items, !grid.x, !grid.y, !grid.vY));
359
+ const next = items.length > 1 ? getCommonAncestor(items[0], items[1]) : container;
360
+ if (next && next !== ancestor) ancestor && resizeObserver.unobserve(ancestor), ancestor = next, resizeObserver.observe(ancestor);
361
+ };
347
362
  setGrid(grid), calcGrid();
348
- const ancestor = items.length > 1 ? getCommonAncestor(items[0], items[1]) : container;
349
- const resizeObserver = new ResizeObserver(calcGrid);
350
- if (ancestor) resizeObserver.observe(ancestor);
351
363
  const destroy = () => {
352
364
  for (const el of interactiveEls) el?.removeEventListener("keydown", simulateKey);
353
365
  container.removeEventListener("focusout", handleFocusOut);
354
366
  for (const el of items) el.removeEventListener("mouseenter", handleHover);
355
367
  mutationObserver.disconnect(), resizeObserver.disconnect();
356
368
  if (timeout) clearTimeout(timeout);
369
+ t007._arrownavs.delete(container);
357
370
  };
358
- const handle = { gridX: () => gridX, gridY: () => gridY, vGridY: () => vGridY, items: () => items, activeIndex: () => activeIndex, activeItem: () => items[activeIndex] ?? null, getAbleIndex, typeAhead, goToIndex, simulateKey, destroy };
371
+ const handle = { gridX: () => gridX, gridY: () => gridY, vGridY: () => vGridY, items: () => items, activeIndex: () => activeIndex, activeItem: () => items[activeIndex] ?? null, getAbleIndex, typeAhead, goToIndex, simulateKey, sync, destroy };
359
372
  return t007._arrownavs.set(container, handle), handle;
360
373
  }
361
374
  var removeArrowNavigation = (container) => t007._arrownavs?.get(container)?.destroy();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@t007/dialog",
3
- "version": "0.0.30",
3
+ "version": "0.0.32",
4
4
  "description": "A lightweight, pure JS dialog system.",
5
5
  "author": "Oketade Oluwatobiloba <tobioketade007@gmail.com>",
6
6
  "license": "MIT",
@@ -21,7 +21,8 @@
21
21
  "types": "./dist/index.d.ts",
22
22
  "style": "./dist/index.css",
23
23
  "sideEffects": [
24
- "*.css"
24
+ "**/*.css",
25
+ "**/*.scss"
25
26
  ],
26
27
  "exports": {
27
28
  ".": {
@@ -56,7 +57,7 @@
56
57
  "accessible"
57
58
  ],
58
59
  "dependencies": {
59
- "@t007/utils": "^0.0.33"
60
+ "@t007/utils": "^0.0.35"
60
61
  },
61
62
  "devDependencies": {
62
63
  "esbuild-sass-plugin": "^3.7.0"