@t007/dialog 0.0.31 → 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.d.ts CHANGED
@@ -1,8 +1,7 @@
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
7
  /** Text for the confirmation button. @default "OK". */
@@ -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 };
@@ -5,7 +5,7 @@
5
5
  return Math.min(Math.max(val, min), max);
6
6
  }
7
7
 
8
- // ../../../sia-reactor/dist/chunk-243U74PP.js
8
+ // ../../../sia-reactor/dist/chunk-ORK3EGB6.js
9
9
  function onAllMethods(owner, callback, skipOwn = true, nested = false) {
10
10
  let proto = owner;
11
11
  while (proto && proto !== Object.prototype) {
@@ -25,16 +25,22 @@
25
25
  function createEl(tag, props, dataset, styles, el = tag ? document?.createElement(tag) : null) {
26
26
  return assignEl(el, props, dataset, styles);
27
27
  }
28
- function assignEl(el, props, dataset, styles) {
28
+ function assignEl(el, props, dataset, styles, nodiff = true) {
29
29
  if (!el) return null;
30
30
  if (props) {
31
- for (const k of Object.keys(props)) if (props[k] !== void 0) el[k] = props[k];
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
+ }
32
34
  }
33
35
  if (dataset) {
34
- for (const k of Object.keys(dataset)) if (dataset[k] !== void 0) el.dataset[k] = String(dataset[k]);
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
+ }
35
39
  }
36
40
  if (styles) {
37
- for (const k of Object.keys(styles)) if (styles[k] !== void 0) el.style[k] = styles[k];
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
+ }
38
44
  }
39
45
  return el;
40
46
  }
@@ -43,35 +49,19 @@
43
49
  return !activeEl ? null : activeEl.shadowRoot ? getActiveEl(activeEl.shadowRoot) : activeEl;
44
50
  }
45
51
 
46
- // ../../../sia-reactor/dist/chunk-2ZYYYSZ4.js
52
+ // ../../../sia-reactor/dist/chunk-SHWIAQD2.js
47
53
  var RTR_BATCH = "undefined" !== typeof window ? ("undefined" !== typeof queueMicrotask ? queueMicrotask : setTimeout).bind(window) : "undefined" !== typeof process && process.nextTick ? process.nextTick : setTimeout;
48
54
  var RTR_LOG = console.log.bind(console, "[S.I.A Reactor]");
49
55
  var NIL = Object.freeze({});
50
56
  var NOOP = () => {
51
57
  };
52
- var CTX = {
53
- /** Flag indicating whether the application is running in development mode. */
54
- isDevEnv: "undefined" !== typeof process ? process.env.NODE_ENV !== "production" : true,
55
- /** Flag indicating whether an operation is bypassing checks so reactors can allow all writes. */
56
- usingForce: false,
57
- /** Active `Autotracker` instance, override for automatic dependency collection on `Reactor` traps. */
58
- autotracker: null,
59
- /** Extensible meta context for payloads and cross-cutting concerns. */
60
- meta: null,
61
- /** Default configuration for new `Reactor` instances and also fallback for utils that need and are called without these options. */
62
- defaults: {
63
- crossRealms: false,
64
- smartCloning: false,
65
- eventBubbling: true,
66
- eventCapturing: "auto",
67
- lineageTracing: false,
68
- preserveContext: false,
69
- equalityFunction: Object.is,
70
- batchingFunction: RTR_BATCH
71
- }
72
- };
58
+ var isDevEnv = false;
59
+ try {
60
+ isDevEnv = process.env.NODE_ENV !== "production";
61
+ } catch (e) {
62
+ }
73
63
 
74
- // ../utils/dist/chunk-HGUYOV3P.js
64
+ // ../utils/dist/chunk-ZALPHCSJ.js
75
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] *)";
76
66
  var isInteractive = (target) => target instanceof HTMLElement && target.matches(INTERACTIVE_SELECTOR);
77
67
  var VIRTUAL_RESOURCE = /* @__PURE__ */ Symbol.for("T007_VIRTUAL_RESOURCE");
@@ -143,33 +133,33 @@
143
133
  window.T007_DIALOG_CSS_SRC ??= `https://cdn.jsdelivr.net/npm/@t007/dialog@latest/dist/index.min.css`;
144
134
  }
145
135
 
146
- // ../utils/dist/chunk-ZRCBB5P4.js
136
+ // ../utils/dist/chunk-NX2LWYD6.js
147
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) {
148
- 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);
149
139
  if (!enabled || existing) return existing ? existing : void 0;
150
140
  scoped = scoped && root instanceof HTMLElement, root = scoped ? root : root === document ? document : window;
151
- 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) => {
152
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;
153
143
  return (!scoped ? true : root.contains(t)) && onOutside(e);
154
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);
155
145
  root.addEventListener("mousedown", handleClick, capture), root.addEventListener("touchstart", handleClick, { passive: true, capture });
156
146
  root.addEventListener("keydown", handleEscape, capture);
157
147
  el.addEventListener("focusout", handleFocusOut, capture);
158
- if (!stack.includes(el)) stack.push(el), stacks.set(root, stack);
159
148
  const destroy = () => {
160
149
  root.removeEventListener("mousedown", handleClick, capture), root.removeEventListener("touchstart", handleClick, capture);
161
150
  root.removeEventListener("keydown", handleEscape, capture);
162
151
  el.removeEventListener("focusout", handleFocusOut, capture);
163
152
  t007._outsiders.delete(el), stack.splice(stack.indexOf(el), 1);
164
153
  };
165
- return t007._outsiders.set(el, destroy), destroy;
154
+ return !stack.includes(el) && stack.push(el), t007._outsiders.set(el, destroy), destroy;
166
155
  }
167
156
  var removeOutsideClick = (el) => t007._outsiders?.get(el)?.();
168
157
  function initFocusTrap(el, { enabled = false, initialSelector = "[data-autofocus]", ringClassName = "focus-outline", root = window, scoped = true, capture = true } = NIL) {
169
- 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);
170
159
  if (!enabled || existing) return existing ? existing : void 0;
171
160
  scoped = scoped && root instanceof HTMLElement, root = scoped ? root : root === document ? document : window;
172
- 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) => {
173
163
  if (!scoped) return resetFocus(pre ? -1 : 0);
174
164
  if (rt.hasAttribute("tabindex")) return rt.focus();
175
165
  const items = getFocusable();
@@ -179,24 +169,24 @@
179
169
  while (p !== ceil && (!all.length || (pre ? rt.contains(all[0]) : rt.contains(all.at(-1))))) all = getFocusable(p = p.parentElement || ceil);
180
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();
181
171
  (pre ? first : last).blur();
182
- }, handleFocusIn = () => {
172
+ }, handleFocusIn = (e) => {
183
173
  if (document.querySelector("dialog:modal") && !el.matches("dialog:modal")) return;
184
- 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();
185
175
  }, handleInitialBlur = () => initial.classList.remove(ringClassName);
186
176
  first.addEventListener("focus", (e) => el.contains(e.relatedTarget) ? edgeFocus(true) : resetFocus(), capture), el.prepend(first);
187
177
  last.addEventListener("focus", (e) => el.contains(e.relatedTarget) ? edgeFocus() : resetFocus(-1), capture), el.append(last);
188
178
  root.addEventListener("focusin", handleFocusIn, capture);
189
179
  if (initial || !el.contains(focused)) !initial ? setTimeout(resetFocus) : setTimeout(() => (initial.classList.add(ringClassName), initial.focus(), initial.addEventListener("blur", handleInitialBlur, capture)));
190
- if (!stack.includes(el)) stack.push(el), stacks.set(root, stack);
191
180
  const destroy = () => {
192
181
  focused?.isConnected && focused.focus(), first.remove(), last.remove();
193
182
  root.removeEventListener("focusin", handleFocusIn, capture);
194
183
  initial?.removeEventListener("blur", handleInitialBlur, capture);
195
184
  t007._ftrappers.delete(el), stack.splice(stack.indexOf(el), 1);
196
185
  };
197
- 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;
198
188
  }
199
- var removeFocusTrap = (el) => t007._ftrappers?.get(el)?.();
189
+ var removeFocusTrap = (el) => t007._ftrappers?.get(el)?.destroy();
200
190
  var getTargetIndex = ({ key, currIndex, length, gridX, gridY, vGridY, loop, ctrlKey = false, rtl }) => {
201
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;
202
192
  let targetIndex = key === "Home" || key === "End" ? move : currIndex + move;
@@ -269,7 +259,7 @@
269
259
  if (!config.enabled || existing) return existing ? existing : void 0;
270
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 };
271
261
  let gridX = grid.x || 1, gridY = grid.y || 1, vGridY = grid.vY || 1, activeIndex = -1, buffer = "", timeout = null, items = [];
272
- 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));
273
263
  const getAbleIndex = (targetIndex, e = { key: "ArrowRight", ctrlKey: false }) => {
274
264
  if (shouldSnub() || !items.length) return null;
275
265
  let index = targetIndex;
@@ -344,34 +334,41 @@
344
334
  if (idx !== -1) goToIndex(idx);
345
335
  };
346
336
  for (const el of items) el.addEventListener("mouseenter", handleHover);
347
- const mutationObserver = new MutationObserver(() => {
337
+ const sync = () => {
348
338
  const oldEl = items[activeIndex];
339
+ for (const el of items) el.removeEventListener("mouseenter", handleHover);
349
340
  getItems();
341
+ for (const el of items) el.addEventListener("mouseenter", handleHover);
342
+ calcGrid();
350
343
  const newEl = items[activeIndex];
351
344
  updateDOM();
352
345
  if (oldEl && newEl && oldEl === newEl) return;
353
- resetActiveIndex();
354
- updateDOM();
355
- });
346
+ resetActiveIndex(), updateDOM();
347
+ };
348
+ const mutationObserver = new MutationObserver(sync);
356
349
  mutationObserver.observe(container, { childList: true, subtree: true });
357
350
  const setGrid = (g) => {
358
351
  if (g.x !== void 0) gridX = g.x;
359
352
  if (g.y !== void 0) gridY = g.y;
360
353
  if (g.vY !== void 0) vGridY = g.vY;
361
354
  };
362
- 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
+ };
363
362
  setGrid(grid), calcGrid();
364
- const ancestor = items.length > 1 ? getCommonAncestor(items[0], items[1]) : container;
365
- const resizeObserver = new ResizeObserver(calcGrid);
366
- if (ancestor) resizeObserver.observe(ancestor);
367
363
  const destroy = () => {
368
364
  for (const el of interactiveEls) el?.removeEventListener("keydown", simulateKey);
369
365
  container.removeEventListener("focusout", handleFocusOut);
370
366
  for (const el of items) el.removeEventListener("mouseenter", handleHover);
371
367
  mutationObserver.disconnect(), resizeObserver.disconnect();
372
368
  if (timeout) clearTimeout(timeout);
369
+ t007._arrownavs.delete(container);
373
370
  };
374
- 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 };
375
372
  return t007._arrownavs.set(container, handle), handle;
376
373
  }
377
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.31",
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",
@@ -57,7 +57,7 @@
57
57
  "accessible"
58
58
  ],
59
59
  "dependencies": {
60
- "@t007/utils": "^0.0.34"
60
+ "@t007/utils": "^0.0.35"
61
61
  },
62
62
  "devDependencies": {
63
63
  "esbuild-sass-plugin": "^3.7.0"