dalila 1.5.13 → 1.7.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 (137) hide show
  1. package/README.md +47 -0
  2. package/dist/componentes/ui/accordion/index.d.ts +2 -0
  3. package/dist/componentes/ui/accordion/index.js +114 -0
  4. package/dist/componentes/ui/calendar/index.d.ts +2 -0
  5. package/dist/componentes/ui/calendar/index.js +132 -0
  6. package/dist/componentes/ui/combobox/index.d.ts +2 -0
  7. package/dist/componentes/ui/combobox/index.js +161 -0
  8. package/dist/componentes/ui/dialog/index.d.ts +10 -0
  9. package/dist/componentes/ui/dialog/index.js +54 -0
  10. package/dist/componentes/ui/drawer/index.d.ts +2 -0
  11. package/dist/componentes/ui/drawer/index.js +41 -0
  12. package/dist/componentes/ui/dropdown/index.d.ts +2 -0
  13. package/dist/componentes/ui/dropdown/index.js +48 -0
  14. package/dist/componentes/ui/dropzone/index.d.ts +2 -0
  15. package/dist/componentes/ui/dropzone/index.js +92 -0
  16. package/dist/componentes/ui/env.d.ts +1 -0
  17. package/dist/componentes/ui/env.js +2 -0
  18. package/dist/componentes/ui/index.d.ts +13 -0
  19. package/dist/componentes/ui/index.js +12 -0
  20. package/dist/componentes/ui/popover/index.d.ts +2 -0
  21. package/dist/componentes/ui/popover/index.js +156 -0
  22. package/dist/componentes/ui/runtime.d.ts +20 -0
  23. package/dist/componentes/ui/runtime.js +421 -0
  24. package/dist/componentes/ui/tabs/index.d.ts +3 -0
  25. package/dist/componentes/ui/tabs/index.js +101 -0
  26. package/dist/componentes/ui/toast/index.d.ts +3 -0
  27. package/dist/componentes/ui/toast/index.js +115 -0
  28. package/dist/componentes/ui/ui-types.d.ts +175 -0
  29. package/dist/componentes/ui/ui-types.js +1 -0
  30. package/dist/componentes/ui/validate.d.ts +7 -0
  31. package/dist/componentes/ui/validate.js +71 -0
  32. package/dist/components/ui/accordion/index.d.ts +2 -0
  33. package/dist/components/ui/accordion/index.js +114 -0
  34. package/dist/components/ui/calendar/index.d.ts +2 -0
  35. package/dist/components/ui/calendar/index.js +132 -0
  36. package/dist/components/ui/combobox/index.d.ts +2 -0
  37. package/dist/components/ui/combobox/index.js +161 -0
  38. package/dist/components/ui/dialog/index.d.ts +10 -0
  39. package/dist/components/ui/dialog/index.js +54 -0
  40. package/dist/components/ui/drawer/index.d.ts +2 -0
  41. package/dist/components/ui/drawer/index.js +41 -0
  42. package/dist/components/ui/dropdown/index.d.ts +2 -0
  43. package/dist/components/ui/dropdown/index.js +48 -0
  44. package/dist/components/ui/dropzone/index.d.ts +2 -0
  45. package/dist/components/ui/dropzone/index.js +92 -0
  46. package/dist/components/ui/env.d.ts +1 -0
  47. package/dist/components/ui/env.js +2 -0
  48. package/dist/components/ui/index.d.ts +13 -0
  49. package/dist/components/ui/index.js +12 -0
  50. package/dist/components/ui/popover/index.d.ts +2 -0
  51. package/dist/components/ui/popover/index.js +156 -0
  52. package/dist/components/ui/runtime.d.ts +20 -0
  53. package/dist/components/ui/runtime.js +421 -0
  54. package/dist/components/ui/tabs/index.d.ts +3 -0
  55. package/dist/components/ui/tabs/index.js +101 -0
  56. package/dist/components/ui/toast/index.d.ts +3 -0
  57. package/dist/components/ui/toast/index.js +115 -0
  58. package/dist/components/ui/ui-types.d.ts +175 -0
  59. package/dist/components/ui/ui-types.js +1 -0
  60. package/dist/components/ui/validate.d.ts +7 -0
  61. package/dist/components/ui/validate.js +71 -0
  62. package/dist/form/form-types.d.ts +181 -0
  63. package/dist/form/form-types.js +4 -0
  64. package/dist/form/form.d.ts +71 -0
  65. package/dist/form/form.js +1073 -0
  66. package/dist/form/index.d.ts +2 -0
  67. package/dist/form/index.js +2 -0
  68. package/dist/index.d.ts +1 -0
  69. package/dist/index.js +1 -0
  70. package/dist/runtime/bind.js +567 -9
  71. package/dist/ui/accordion.d.ts +2 -0
  72. package/dist/ui/accordion.js +114 -0
  73. package/dist/ui/calendar.d.ts +2 -0
  74. package/dist/ui/calendar.js +132 -0
  75. package/dist/ui/combobox.d.ts +2 -0
  76. package/dist/ui/combobox.js +161 -0
  77. package/dist/ui/dialog.d.ts +10 -0
  78. package/dist/ui/dialog.js +54 -0
  79. package/dist/ui/drawer.d.ts +2 -0
  80. package/dist/ui/drawer.js +41 -0
  81. package/dist/ui/dropdown.d.ts +2 -0
  82. package/dist/ui/dropdown.js +48 -0
  83. package/dist/ui/dropzone.d.ts +2 -0
  84. package/dist/ui/dropzone.js +92 -0
  85. package/dist/ui/env.d.ts +1 -0
  86. package/dist/ui/env.js +2 -0
  87. package/dist/ui/index.d.ts +13 -0
  88. package/dist/ui/index.js +12 -0
  89. package/dist/ui/popover.d.ts +2 -0
  90. package/dist/ui/popover.js +156 -0
  91. package/dist/ui/runtime.d.ts +20 -0
  92. package/dist/ui/runtime.js +421 -0
  93. package/dist/ui/tabs.d.ts +3 -0
  94. package/dist/ui/tabs.js +101 -0
  95. package/dist/ui/toast.d.ts +3 -0
  96. package/dist/ui/toast.js +115 -0
  97. package/dist/ui/ui-types.d.ts +175 -0
  98. package/dist/ui/ui-types.js +1 -0
  99. package/dist/ui/validate.d.ts +7 -0
  100. package/dist/ui/validate.js +71 -0
  101. package/package.json +60 -2
  102. package/src/components/ui/accordion/accordion.css +90 -0
  103. package/src/components/ui/alert/alert.css +78 -0
  104. package/src/components/ui/avatar/avatar.css +45 -0
  105. package/src/components/ui/badge/badge.css +71 -0
  106. package/src/components/ui/breadcrumb/breadcrumb.css +41 -0
  107. package/src/components/ui/button/button.css +135 -0
  108. package/src/components/ui/calendar/calendar.css +96 -0
  109. package/src/components/ui/card/card.css +93 -0
  110. package/src/components/ui/checkbox/checkbox.css +57 -0
  111. package/src/components/ui/chip/chip.css +62 -0
  112. package/src/components/ui/collapsible/collapsible.css +61 -0
  113. package/src/components/ui/combobox/combobox.css +85 -0
  114. package/src/components/ui/dalila/dalila.css +42 -0
  115. package/src/components/ui/dalila-core/dalila-core.css +14 -0
  116. package/src/components/ui/dialog/dialog.css +125 -0
  117. package/src/components/ui/drawer/drawer.css +122 -0
  118. package/src/components/ui/dropdown/dropdown.css +87 -0
  119. package/src/components/ui/dropzone/dropzone.css +47 -0
  120. package/src/components/ui/empty-state/empty-state.css +33 -0
  121. package/src/components/ui/form/form.css +44 -0
  122. package/src/components/ui/input/input.css +106 -0
  123. package/src/components/ui/layout/layout.css +62 -0
  124. package/src/components/ui/pagination/pagination.css +55 -0
  125. package/src/components/ui/popover/popover.css +55 -0
  126. package/src/components/ui/radio/radio.css +56 -0
  127. package/src/components/ui/separator/separator.css +38 -0
  128. package/src/components/ui/skeleton/skeleton.css +57 -0
  129. package/src/components/ui/slider/slider.css +60 -0
  130. package/src/components/ui/spinner/spinner.css +38 -0
  131. package/src/components/ui/table/table.css +54 -0
  132. package/src/components/ui/tabs/tabs.css +74 -0
  133. package/src/components/ui/toast/toast.css +100 -0
  134. package/src/components/ui/toggle/toggle.css +90 -0
  135. package/src/components/ui/tokens/tokens.css +161 -0
  136. package/src/components/ui/tooltip/tooltip.css +53 -0
  137. package/src/components/ui/typography/typography.css +81 -0
@@ -0,0 +1,54 @@
1
+ import { signal } from "../../../core/signal.js";
2
+ import { getCurrentScope } from "../../../core/scope.js";
3
+ import { validateDialogOptions } from "../validate.js";
4
+ /**
5
+ * Shared dialog behavior — used by both createDialog and createDrawer.
6
+ */
7
+ export function _attachDialogBehavior(el, open, closeFn, opts) {
8
+ const scope = getCurrentScope();
9
+ // Sync signal → native dialog
10
+ const unsub = open.on((isOpen) => {
11
+ if (isOpen && !el.open)
12
+ el.showModal();
13
+ else if (!isOpen && el.open)
14
+ el.close();
15
+ });
16
+ // Native close event → sync signal
17
+ const onClose = () => open.set(false);
18
+ el.addEventListener("close", onClose);
19
+ // Backdrop click
20
+ const onBackdropClick = (e) => {
21
+ if (opts.closeOnBackdrop && e.target === el)
22
+ closeFn();
23
+ };
24
+ el.addEventListener("click", onBackdropClick);
25
+ // Escape key
26
+ if (!opts.closeOnEscape) {
27
+ const onCancel = (e) => e.preventDefault();
28
+ el.addEventListener("cancel", onCancel);
29
+ if (scope) {
30
+ scope.onCleanup(() => el.removeEventListener("cancel", onCancel));
31
+ }
32
+ }
33
+ // ARIA
34
+ el.setAttribute("aria-modal", "true");
35
+ if (scope) {
36
+ scope.onCleanup(() => {
37
+ unsub();
38
+ el.removeEventListener("close", onClose);
39
+ el.removeEventListener("click", onBackdropClick);
40
+ });
41
+ }
42
+ }
43
+ export function createDialog(options = {}) {
44
+ validateDialogOptions(options);
45
+ const { closeOnBackdrop = true, closeOnEscape = true } = options;
46
+ const open = signal(false);
47
+ const show = () => open.set(true);
48
+ const close = () => open.set(false);
49
+ const toggle = () => open.update((v) => !v);
50
+ const _attachTo = (el) => {
51
+ _attachDialogBehavior(el, open, close, { closeOnBackdrop, closeOnEscape });
52
+ };
53
+ return { open, show, close, toggle, _attachTo };
54
+ }
@@ -0,0 +1,2 @@
1
+ import type { Drawer, DrawerOptions } from "../ui-types.js";
2
+ export declare function createDrawer(options?: DrawerOptions): Drawer;
@@ -0,0 +1,41 @@
1
+ import { signal } from "../../../core/signal.js";
2
+ import { getCurrentScope } from "../../../core/scope.js";
3
+ import { _attachDialogBehavior } from "../dialog/index.js";
4
+ import { validateDrawerOptions } from "../validate.js";
5
+ const SIDE_CLASSES = {
6
+ right: "",
7
+ left: "d-drawer-left",
8
+ bottom: "d-sheet",
9
+ };
10
+ export function createDrawer(options = {}) {
11
+ validateDrawerOptions(options);
12
+ const { closeOnBackdrop = true, closeOnEscape = true, side: initialSide = "right", } = options;
13
+ const open = signal(false);
14
+ const side = signal(initialSide);
15
+ const show = () => open.set(true);
16
+ const close = () => open.set(false);
17
+ const toggle = () => open.update((v) => !v);
18
+ const _attachTo = (el) => {
19
+ const scope = getCurrentScope();
20
+ // Shared dialog behavior (open sync, backdrop, escape, ARIA)
21
+ _attachDialogBehavior(el, open, close, { closeOnBackdrop, closeOnEscape });
22
+ // Apply initial side class
23
+ const initial = SIDE_CLASSES[side()];
24
+ if (initial)
25
+ el.classList.add(initial);
26
+ // React to side changes
27
+ const unsub = side.on((s) => {
28
+ for (const cls of Object.values(SIDE_CLASSES)) {
29
+ if (cls)
30
+ el.classList.remove(cls);
31
+ }
32
+ const cls = SIDE_CLASSES[s];
33
+ if (cls)
34
+ el.classList.add(cls);
35
+ });
36
+ if (scope) {
37
+ scope.onCleanup(() => unsub());
38
+ }
39
+ };
40
+ return { open, side, show, close, toggle, _attachTo };
41
+ }
@@ -0,0 +1,2 @@
1
+ import type { Dropdown, DropdownOptions } from "../ui-types.js";
2
+ export declare function createDropdown(options?: DropdownOptions): Dropdown;
@@ -0,0 +1,48 @@
1
+ import { signal } from "../../../core/signal.js";
2
+ import { getCurrentScope } from "../../../core/scope.js";
3
+ import { isBrowser } from "../env.js";
4
+ export function createDropdown(options = {}) {
5
+ const { closeOnSelect = true } = options;
6
+ const open = signal(false);
7
+ const toggle = (ev) => {
8
+ if (ev)
9
+ ev.stopPropagation();
10
+ open.update((v) => !v);
11
+ };
12
+ const close = () => open.set(false);
13
+ const select = (ev) => {
14
+ if (ev)
15
+ ev.stopPropagation();
16
+ if (closeOnSelect)
17
+ close();
18
+ };
19
+ const _attachTo = (el) => {
20
+ const scope = getCurrentScope();
21
+ // ARIA
22
+ const trigger = el.querySelector("button, [role='button'], [data-d-tag='d-button']");
23
+ const menu = el.querySelector("[data-d-tag='d-menu'], .d-menu");
24
+ if (menu)
25
+ menu.setAttribute("role", "menu");
26
+ if (trigger) {
27
+ trigger.setAttribute("aria-haspopup", "true");
28
+ trigger.setAttribute("aria-expanded", "false");
29
+ }
30
+ const unsubAria = open.on((isOpen) => {
31
+ trigger?.setAttribute("aria-expanded", String(isOpen));
32
+ });
33
+ const onDocClick = (e) => {
34
+ if (!el.contains(e.target))
35
+ close();
36
+ };
37
+ if (isBrowser)
38
+ document.addEventListener("click", onDocClick);
39
+ if (scope) {
40
+ scope.onCleanup(() => {
41
+ unsubAria();
42
+ if (isBrowser)
43
+ document.removeEventListener("click", onDocClick);
44
+ });
45
+ }
46
+ };
47
+ return { open, toggle, close, select, _attachTo };
48
+ }
@@ -0,0 +1,2 @@
1
+ import type { Dropzone, DropzoneOptions } from "../ui-types.js";
2
+ export declare function createDropzone(options?: DropzoneOptions): Dropzone;
@@ -0,0 +1,92 @@
1
+ import { signal } from "../../../core/signal.js";
2
+ import { getCurrentScope } from "../../../core/scope.js";
3
+ import { validateDropzoneOptions } from "../validate.js";
4
+ export function createDropzone(options = {}) {
5
+ validateDropzoneOptions(options);
6
+ const { accept, multiple = true, maxFiles, maxSize } = options;
7
+ const dragging = signal(false);
8
+ const files = signal([]);
9
+ let inputEl = null;
10
+ const filterFiles = (fileList) => {
11
+ let result = fileList;
12
+ if (accept) {
13
+ const types = accept.split(",").map((t) => t.trim().toLowerCase());
14
+ result = result.filter((f) => {
15
+ const ext = "." + f.name.split(".").pop()?.toLowerCase();
16
+ const mime = f.type.toLowerCase();
17
+ return types.some((t) => t === ext || t === mime || (t.endsWith("/*") && mime.startsWith(t.slice(0, -1))));
18
+ });
19
+ }
20
+ if (maxSize) {
21
+ result = result.filter((f) => f.size <= maxSize);
22
+ }
23
+ if (maxFiles) {
24
+ result = result.slice(0, maxFiles);
25
+ }
26
+ return result;
27
+ };
28
+ const addFiles = (newFiles) => {
29
+ const filtered = filterFiles(newFiles);
30
+ if (multiple) {
31
+ files.update((current) => {
32
+ const combined = [...current, ...filtered];
33
+ return maxFiles ? combined.slice(0, maxFiles) : combined;
34
+ });
35
+ }
36
+ else {
37
+ files.set(filtered.slice(0, 1));
38
+ }
39
+ };
40
+ const browse = () => {
41
+ inputEl?.click();
42
+ };
43
+ const handleClick = () => browse();
44
+ const handleDragover = (ev) => {
45
+ ev.preventDefault();
46
+ dragging.set(true);
47
+ };
48
+ const handleDragleave = () => {
49
+ dragging.set(false);
50
+ };
51
+ const handleDrop = (ev) => {
52
+ ev.preventDefault();
53
+ dragging.set(false);
54
+ if (ev.dataTransfer?.files) {
55
+ addFiles(Array.from(ev.dataTransfer.files));
56
+ }
57
+ };
58
+ const _attachTo = (el) => {
59
+ const scope = getCurrentScope();
60
+ // ARIA
61
+ el.setAttribute("role", "button");
62
+ el.setAttribute("tabindex", "0");
63
+ inputEl = el.querySelector('input[type="file"]');
64
+ if (inputEl) {
65
+ if (accept)
66
+ inputEl.accept = accept;
67
+ inputEl.multiple = multiple;
68
+ const onInputChange = () => {
69
+ if (inputEl?.files) {
70
+ addFiles(Array.from(inputEl.files));
71
+ inputEl.value = "";
72
+ }
73
+ };
74
+ inputEl.addEventListener("change", onInputChange);
75
+ if (scope) {
76
+ scope.onCleanup(() => {
77
+ inputEl?.removeEventListener("change", onInputChange);
78
+ });
79
+ }
80
+ }
81
+ };
82
+ return {
83
+ dragging,
84
+ files,
85
+ browse,
86
+ handleClick,
87
+ handleDragover,
88
+ handleDragleave,
89
+ handleDrop,
90
+ _attachTo,
91
+ };
92
+ }
@@ -0,0 +1 @@
1
+ export declare const isBrowser: boolean;
@@ -0,0 +1,2 @@
1
+ // ── Environment Detection ───────────────────────────────────────────
2
+ export const isBrowser = typeof window !== "undefined" && typeof document !== "undefined";
@@ -0,0 +1,13 @@
1
+ export * from "./ui-types.js";
2
+ export { createDialog, _attachDialogBehavior } from "./dialog/index.js";
3
+ export { createDrawer } from "./drawer/index.js";
4
+ export { createToast, toastIcon } from "./toast/index.js";
5
+ export { createTabs, tabBindings } from "./tabs/index.js";
6
+ export { createDropdown } from "./dropdown/index.js";
7
+ export { createCombobox } from "./combobox/index.js";
8
+ export { createAccordion } from "./accordion/index.js";
9
+ export { createCalendar } from "./calendar/index.js";
10
+ export { createDropzone } from "./dropzone/index.js";
11
+ export { createPopover } from "./popover/index.js";
12
+ export { mountUI } from "./runtime.js";
13
+ export type { MountUIOptions } from "./runtime.js";
@@ -0,0 +1,12 @@
1
+ export * from "./ui-types.js";
2
+ export { createDialog, _attachDialogBehavior } from "./dialog/index.js";
3
+ export { createDrawer } from "./drawer/index.js";
4
+ export { createToast, toastIcon } from "./toast/index.js";
5
+ export { createTabs, tabBindings } from "./tabs/index.js";
6
+ export { createDropdown } from "./dropdown/index.js";
7
+ export { createCombobox } from "./combobox/index.js";
8
+ export { createAccordion } from "./accordion/index.js";
9
+ export { createCalendar } from "./calendar/index.js";
10
+ export { createDropzone } from "./dropzone/index.js";
11
+ export { createPopover } from "./popover/index.js";
12
+ export { mountUI } from "./runtime.js";
@@ -0,0 +1,2 @@
1
+ import type { Popover, PopoverOptions } from "../ui-types.js";
2
+ export declare function createPopover(options?: PopoverOptions): Popover;
@@ -0,0 +1,156 @@
1
+ import { signal } from "../../../core/signal.js";
2
+ import { getCurrentScope } from "../../../core/scope.js";
3
+ import { validatePopoverOptions } from "../validate.js";
4
+ import { isBrowser } from "../env.js";
5
+ let popoverUid = 0;
6
+ function computePosition(trigger, popoverEl, placement, gap, viewportPadding) {
7
+ const triggerRect = trigger.getBoundingClientRect();
8
+ const popRect = popoverEl.getBoundingClientRect();
9
+ const vw = isBrowser ? window.innerWidth : 1024;
10
+ const vh = isBrowser ? window.innerHeight : 768;
11
+ // ── Flip when not enough space ──
12
+ let effective = placement;
13
+ if (effective.startsWith("bottom") && triggerRect.bottom + gap + popRect.height > vh - viewportPadding) {
14
+ if (triggerRect.top - gap - popRect.height >= viewportPadding) {
15
+ effective = effective.replace("bottom", "top");
16
+ }
17
+ }
18
+ else if (effective.startsWith("top") && triggerRect.top - gap - popRect.height < viewportPadding) {
19
+ if (triggerRect.bottom + gap + popRect.height <= vh - viewportPadding) {
20
+ effective = effective.replace("top", "bottom");
21
+ }
22
+ }
23
+ else if (effective === "left" && triggerRect.left - gap - popRect.width < viewportPadding) {
24
+ if (triggerRect.right + gap + popRect.width <= vw - viewportPadding) {
25
+ effective = "right";
26
+ }
27
+ }
28
+ else if (effective === "right" && triggerRect.right + gap + popRect.width > vw - viewportPadding) {
29
+ if (triggerRect.left - gap - popRect.width >= viewportPadding) {
30
+ effective = "left";
31
+ }
32
+ }
33
+ let top = 0;
34
+ let left = 0;
35
+ switch (effective) {
36
+ case "bottom":
37
+ top = triggerRect.bottom + gap;
38
+ left = triggerRect.left + (triggerRect.width - popRect.width) / 2;
39
+ break;
40
+ case "bottom-start":
41
+ top = triggerRect.bottom + gap;
42
+ left = triggerRect.left;
43
+ break;
44
+ case "top":
45
+ top = triggerRect.top - popRect.height - gap;
46
+ left = triggerRect.left + (triggerRect.width - popRect.width) / 2;
47
+ break;
48
+ case "top-start":
49
+ top = triggerRect.top - popRect.height - gap;
50
+ left = triggerRect.left;
51
+ break;
52
+ case "left":
53
+ top = triggerRect.top + (triggerRect.height - popRect.height) / 2;
54
+ left = triggerRect.left - popRect.width - gap;
55
+ break;
56
+ case "right":
57
+ top = triggerRect.top + (triggerRect.height - popRect.height) / 2;
58
+ left = triggerRect.right + gap;
59
+ break;
60
+ }
61
+ // Viewport clamping
62
+ const maxLeft = vw - popRect.width - viewportPadding;
63
+ left = Math.min(Math.max(viewportPadding, left), Math.max(viewportPadding, maxLeft));
64
+ const maxTop = vh - popRect.height - viewportPadding;
65
+ top = Math.min(Math.max(viewportPadding, top), Math.max(viewportPadding, maxTop));
66
+ return { top, left };
67
+ }
68
+ export function createPopover(options = {}) {
69
+ validatePopoverOptions(options);
70
+ const { placement: initialPlacement = "bottom", gap = 8, viewportPadding = 12, } = options;
71
+ const open = signal(false);
72
+ const placement = signal(initialPlacement);
73
+ const show = () => open.set(true);
74
+ const hide = () => open.set(false);
75
+ const toggle = () => open.update((v) => !v);
76
+ const position = (trigger, popoverEl) => {
77
+ const { top, left } = computePosition(trigger, popoverEl, placement(), gap, viewportPadding);
78
+ popoverEl.style.position = "fixed";
79
+ popoverEl.style.top = `${top}px`;
80
+ popoverEl.style.left = `${left}px`;
81
+ };
82
+ const _attachTo = (trigger, popoverEl) => {
83
+ const scope = getCurrentScope();
84
+ // Ensure popover attribute for native API
85
+ if (!popoverEl.hasAttribute("popover")) {
86
+ popoverEl.setAttribute("popover", "manual");
87
+ }
88
+ const reposition = () => {
89
+ try {
90
+ if (!popoverEl.matches(":popover-open"))
91
+ return;
92
+ }
93
+ catch {
94
+ return;
95
+ }
96
+ position(trigger, popoverEl);
97
+ };
98
+ // Sync open signal → native popover
99
+ const unsub = open.on((isOpen) => {
100
+ try {
101
+ const isNativeOpen = popoverEl.matches(":popover-open");
102
+ if (isOpen && !isNativeOpen) {
103
+ popoverEl.showPopover();
104
+ reposition();
105
+ }
106
+ else if (!isOpen && isNativeOpen) {
107
+ popoverEl.hidePopover();
108
+ }
109
+ }
110
+ catch {
111
+ // Popover API not supported or element not connected
112
+ }
113
+ });
114
+ // Sync native toggle → signal
115
+ const onToggle = (ev) => {
116
+ const state = ev.newState;
117
+ if (state === "open") {
118
+ if (!open.peek())
119
+ open.set(true);
120
+ reposition();
121
+ }
122
+ else {
123
+ if (open.peek())
124
+ open.set(false);
125
+ }
126
+ };
127
+ popoverEl.addEventListener("toggle", onToggle);
128
+ // Reposition on scroll/resize
129
+ if (isBrowser) {
130
+ window.addEventListener("resize", reposition);
131
+ window.addEventListener("scroll", reposition, { passive: true });
132
+ }
133
+ // ARIA
134
+ const popoverId = popoverEl.id || `d-popover-${++popoverUid}`;
135
+ if (!popoverEl.id)
136
+ popoverEl.id = popoverId;
137
+ trigger.setAttribute("aria-controls", popoverId);
138
+ trigger.setAttribute("aria-expanded", "false");
139
+ trigger.setAttribute("aria-haspopup", "true");
140
+ const unsubAria = open.on((isOpen) => {
141
+ trigger.setAttribute("aria-expanded", String(isOpen));
142
+ });
143
+ if (scope) {
144
+ scope.onCleanup(() => {
145
+ unsub();
146
+ unsubAria();
147
+ popoverEl.removeEventListener("toggle", onToggle);
148
+ if (isBrowser) {
149
+ window.removeEventListener("resize", reposition);
150
+ window.removeEventListener("scroll", reposition);
151
+ }
152
+ });
153
+ }
154
+ };
155
+ return { open, show, hide, toggle, placement, position, _attachTo };
156
+ }
@@ -0,0 +1,20 @@
1
+ import { type Signal } from "../../core/signal.js";
2
+ import { type BindContext } from "../../runtime/bind.js";
3
+ import type { Calendar, Combobox, Dialog, Drawer, Dropdown, Dropzone, PopoverMount, TabsMount, Toast } from "./ui-types.js";
4
+ export interface MountUIOptions {
5
+ context?: BindContext;
6
+ events?: string[];
7
+ theme?: boolean;
8
+ sliderValue?: Signal<string>;
9
+ dialogs?: Record<string, Dialog>;
10
+ drawers?: Record<string, Drawer>;
11
+ dropdowns?: Record<string, Dropdown>;
12
+ combos?: Record<string, Combobox>;
13
+ tabs?: Record<string, TabsMount>;
14
+ toasts?: Record<string, Toast>;
15
+ popovers?: Record<string, PopoverMount>;
16
+ dropzones?: Record<string, Dropzone>;
17
+ calendars?: Record<string, Calendar>;
18
+ accordions?: Record<string, import("./ui-types.js").Accordion>;
19
+ }
20
+ export declare function mountUI(root: Element, options: MountUIOptions): () => void;