@vertz/ui-primitives 0.2.14 → 0.2.16

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 (108) hide show
  1. package/dist/shared/chunk-0mcr52hc.js +78 -0
  2. package/dist/shared/chunk-2h5qpc00.js +98 -0
  3. package/dist/shared/chunk-31yptvbf.js +151 -0
  4. package/dist/shared/chunk-34yfm2b0.js +182 -0
  5. package/dist/shared/chunk-3pantb0p.js +108 -0
  6. package/dist/shared/chunk-3s6s6f06.js +61 -0
  7. package/dist/shared/chunk-48v8j0vh.js +267 -0
  8. package/dist/shared/chunk-6dmt4513.js +78 -0
  9. package/dist/shared/chunk-6pnjrst7.js +108 -0
  10. package/dist/shared/chunk-6sqwjfg8.js +169 -0
  11. package/dist/shared/chunk-8qfeqrrz.js +179 -0
  12. package/dist/shared/chunk-8y1jf6xr.js +17 -0
  13. package/dist/shared/chunk-9cqe2q6e.js +56 -0
  14. package/dist/shared/chunk-a6wp8c32.js +32 -0
  15. package/dist/shared/chunk-bcfzteh0.js +148 -0
  16. package/dist/shared/chunk-cr9sbwns.js +235 -0
  17. package/dist/shared/chunk-cvbf1js1.js +52 -0
  18. package/dist/shared/chunk-dkhst4wv.js +97 -0
  19. package/dist/shared/chunk-e2v1c9ex.js +62 -0
  20. package/dist/shared/chunk-e3aj5yw4.js +115 -0
  21. package/dist/shared/chunk-fv1y77tn.js +225 -0
  22. package/dist/shared/chunk-h42bk324.js +58 -0
  23. package/dist/shared/chunk-h9m9x5my.js +119 -0
  24. package/dist/shared/chunk-jctqs9m4.js +60 -0
  25. package/dist/shared/chunk-n92bvn5d.js +149 -0
  26. package/dist/shared/chunk-qpfqyrc5.js +19 -0
  27. package/dist/shared/chunk-qq0e0gym.js +73 -0
  28. package/dist/shared/chunk-t1vkvsz2.js +175 -0
  29. package/dist/shared/chunk-tk1k1bet.js +93 -0
  30. package/dist/shared/chunk-tvpgeswh.js +216 -0
  31. package/dist/shared/chunk-vcp10kne.js +175 -0
  32. package/dist/shared/chunk-ve006hmy.js +51 -0
  33. package/dist/shared/chunk-vq9tfzh8.js +30 -0
  34. package/dist/shared/chunk-vvjyx7fe.js +62 -0
  35. package/dist/shared/chunk-vx1ajy2z.js +115 -0
  36. package/dist/shared/chunk-w06tst6x.js +57 -0
  37. package/dist/shared/chunk-wnttq0gv.js +49 -0
  38. package/dist/shared/chunk-x6qzr3g6.js +100 -0
  39. package/dist/src/accordion/accordion.d.ts +23 -0
  40. package/dist/src/accordion/accordion.js +9 -0
  41. package/dist/src/alert-dialog/alert-dialog.d.ts +26 -0
  42. package/dist/src/alert-dialog/alert-dialog.js +9 -0
  43. package/dist/src/badge/badge.d.ts +10 -0
  44. package/dist/src/badge/badge.js +7 -0
  45. package/dist/src/button/button.d.ts +18 -0
  46. package/dist/src/button/button.js +8 -0
  47. package/dist/src/calendar/calendar.d.ts +40 -0
  48. package/dist/src/calendar/calendar.js +6 -0
  49. package/dist/src/carousel/carousel.d.ts +27 -0
  50. package/dist/src/carousel/carousel.js +8 -0
  51. package/dist/src/checkbox/checkbox.d.ts +20 -0
  52. package/dist/src/checkbox/checkbox.js +9 -0
  53. package/dist/src/collapsible/collapsible.d.ts +21 -0
  54. package/dist/src/collapsible/collapsible.js +8 -0
  55. package/dist/src/combobox/combobox.d.ts +23 -0
  56. package/dist/src/combobox/combobox.js +9 -0
  57. package/dist/src/command/command.d.ts +29 -0
  58. package/dist/src/command/command.js +9 -0
  59. package/dist/src/context-menu/context-menu.d.ts +39 -0
  60. package/dist/src/context-menu/context-menu.js +11 -0
  61. package/dist/src/date-picker/date-picker.d.ts +47 -0
  62. package/dist/src/date-picker/date-picker.js +14 -0
  63. package/dist/src/dialog/dialog.d.ts +24 -0
  64. package/dist/src/dialog/dialog.js +10 -0
  65. package/dist/src/dropdown-menu/dropdown-menu.d.ts +42 -0
  66. package/dist/src/dropdown-menu/dropdown-menu.js +12 -0
  67. package/dist/src/hover-card/hover-card.d.ts +33 -0
  68. package/dist/src/hover-card/hover-card.js +10 -0
  69. package/dist/src/index.js +136 -0
  70. package/dist/src/menu/menu.d.ts +39 -0
  71. package/dist/src/menu/menu.js +11 -0
  72. package/dist/src/menubar/menubar.d.ts +40 -0
  73. package/dist/src/menubar/menubar.js +12 -0
  74. package/dist/src/navigation-menu/navigation-menu.d.ts +25 -0
  75. package/dist/src/navigation-menu/navigation-menu.js +10 -0
  76. package/dist/src/popover/popover.d.ts +32 -0
  77. package/dist/src/popover/popover.js +12 -0
  78. package/dist/src/progress/progress.d.ts +20 -0
  79. package/dist/src/progress/progress.js +8 -0
  80. package/dist/src/radio/radio.d.ts +18 -0
  81. package/dist/src/radio/radio.js +10 -0
  82. package/dist/src/resizable-panel/resizable-panel.d.ts +24 -0
  83. package/dist/src/resizable-panel/resizable-panel.js +8 -0
  84. package/dist/src/scroll-area/scroll-area.d.ts +25 -0
  85. package/dist/src/scroll-area/scroll-area.js +6 -0
  86. package/dist/src/select/select.d.ts +41 -0
  87. package/dist/src/select/select.js +11 -0
  88. package/dist/src/sheet/sheet.d.ts +24 -0
  89. package/dist/src/sheet/sheet.js +10 -0
  90. package/dist/src/slider/slider.d.ts +24 -0
  91. package/dist/src/slider/slider.js +9 -0
  92. package/dist/src/switch/switch.d.ts +9 -0
  93. package/dist/src/switch/switch.js +8 -0
  94. package/dist/src/tabs/tabs.d.ts +23 -0
  95. package/dist/src/tabs/tabs.js +10 -0
  96. package/dist/src/toast/toast.d.ts +24 -0
  97. package/dist/src/toast/toast.js +8 -0
  98. package/dist/src/toggle/toggle.d.ts +9 -0
  99. package/dist/src/toggle/toggle.js +8 -0
  100. package/dist/src/toggle-group/toggle-group.d.ts +22 -0
  101. package/dist/src/toggle-group/toggle-group.js +9 -0
  102. package/dist/src/tooltip/tooltip.d.ts +32 -0
  103. package/dist/src/tooltip/tooltip.js +10 -0
  104. package/dist/src/utils.d.ts +176 -0
  105. package/dist/src/utils.js +72 -0
  106. package/package.json +12 -10
  107. package/dist/index.js +0 -3675
  108. /package/dist/{index.d.ts → src/index.d.ts} +0 -0
@@ -0,0 +1,179 @@
1
+ import {
2
+ createDismiss
3
+ } from "./chunk-a6wp8c32.js";
4
+ import {
5
+ createFloatingPosition,
6
+ virtualElement
7
+ } from "./chunk-0mcr52hc.js";
8
+ import {
9
+ Keys,
10
+ handleListNavigation,
11
+ isKey
12
+ } from "./chunk-jctqs9m4.js";
13
+ import {
14
+ setDataState,
15
+ setHidden,
16
+ setHiddenAnimated
17
+ } from "./chunk-vvjyx7fe.js";
18
+ import {
19
+ uniqueId
20
+ } from "./chunk-8y1jf6xr.js";
21
+
22
+ // src/context-menu/context-menu.ts
23
+ import { signal } from "@vertz/ui";
24
+ var ContextMenu = {
25
+ Root(options = {}) {
26
+ const { onSelect, positioning } = options;
27
+ const state = {
28
+ open: signal(false),
29
+ activeIndex: signal(-1)
30
+ };
31
+ const items = [];
32
+ let floatingCleanup = null;
33
+ let dismissCleanup = null;
34
+ const trigger = document.createElement("div");
35
+ const contentId = uniqueId("ctx-menu");
36
+ const content = document.createElement("div");
37
+ content.setAttribute("role", "menu");
38
+ content.id = contentId;
39
+ content.style.position = "fixed";
40
+ setHidden(content, true);
41
+ setDataState(content, "closed");
42
+ function handleClickOutside(event) {
43
+ const target = event.target;
44
+ if (!trigger.contains(target) && !content.contains(target)) {
45
+ close();
46
+ }
47
+ }
48
+ function open(x, y) {
49
+ state.open.value = true;
50
+ setHidden(content, false);
51
+ setDataState(content, "open");
52
+ if (positioning) {
53
+ const result = createFloatingPosition(virtualElement(x, y), content, {
54
+ strategy: "fixed",
55
+ ...positioning
56
+ });
57
+ floatingCleanup = result.cleanup;
58
+ dismissCleanup = createDismiss({
59
+ onDismiss: close,
60
+ insideElements: [trigger, content],
61
+ escapeKey: false
62
+ });
63
+ } else {
64
+ content.style.left = `${x}px`;
65
+ content.style.top = `${y}px`;
66
+ document.addEventListener("mousedown", handleClickOutside);
67
+ }
68
+ state.activeIndex.value = 0;
69
+ updateActiveItem(0);
70
+ items[0]?.focus();
71
+ }
72
+ function close() {
73
+ state.open.value = false;
74
+ setDataState(content, "closed");
75
+ setHiddenAnimated(content, true);
76
+ if (positioning) {
77
+ floatingCleanup?.();
78
+ floatingCleanup = null;
79
+ dismissCleanup?.();
80
+ dismissCleanup = null;
81
+ } else {
82
+ document.removeEventListener("mousedown", handleClickOutside);
83
+ }
84
+ }
85
+ function updateActiveItem(index) {
86
+ for (let i = 0;i < items.length; i++) {
87
+ items[i]?.setAttribute("tabindex", i === index ? "0" : "-1");
88
+ }
89
+ }
90
+ trigger.addEventListener("contextmenu", (event) => {
91
+ event.preventDefault();
92
+ if (state.open.peek()) {
93
+ close();
94
+ }
95
+ open(event.clientX, event.clientY);
96
+ });
97
+ content.addEventListener("keydown", (event) => {
98
+ if (isKey(event, Keys.Escape)) {
99
+ event.preventDefault();
100
+ close();
101
+ return;
102
+ }
103
+ if (isKey(event, Keys.Enter, Keys.Space)) {
104
+ event.preventDefault();
105
+ const active = items[state.activeIndex.peek()];
106
+ if (active) {
107
+ const val = active.getAttribute("data-value");
108
+ if (val !== null) {
109
+ onSelect?.(val);
110
+ close();
111
+ }
112
+ }
113
+ return;
114
+ }
115
+ const result = handleListNavigation(event, items, { orientation: "vertical" });
116
+ if (result) {
117
+ const idx = items.indexOf(result);
118
+ if (idx >= 0) {
119
+ state.activeIndex.value = idx;
120
+ updateActiveItem(idx);
121
+ }
122
+ return;
123
+ }
124
+ if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
125
+ const char = event.key.toLowerCase();
126
+ const match = items.find((item) => item.textContent?.toLowerCase().startsWith(char));
127
+ if (match) {
128
+ const idx = items.indexOf(match);
129
+ state.activeIndex.value = idx;
130
+ updateActiveItem(idx);
131
+ match.focus();
132
+ }
133
+ }
134
+ });
135
+ function createItem(value, label, parent) {
136
+ const item = document.createElement("div");
137
+ item.setAttribute("role", "menuitem");
138
+ item.setAttribute("data-value", value);
139
+ item.setAttribute("tabindex", "-1");
140
+ item.textContent = label ?? value;
141
+ item.addEventListener("click", () => {
142
+ onSelect?.(value);
143
+ close();
144
+ });
145
+ items.push(item);
146
+ (parent ?? content).appendChild(item);
147
+ return item;
148
+ }
149
+ function Item(value, label) {
150
+ return createItem(value, label);
151
+ }
152
+ function Group(label) {
153
+ const el = document.createElement("div");
154
+ el.setAttribute("role", "group");
155
+ el.setAttribute("aria-label", label);
156
+ content.appendChild(el);
157
+ return {
158
+ el,
159
+ Item: (value, itemLabel) => createItem(value, itemLabel, el)
160
+ };
161
+ }
162
+ function Separator() {
163
+ const hr = document.createElement("hr");
164
+ hr.setAttribute("role", "separator");
165
+ content.appendChild(hr);
166
+ return hr;
167
+ }
168
+ function Label(text) {
169
+ const el = document.createElement("div");
170
+ el.setAttribute("role", "none");
171
+ el.textContent = text;
172
+ content.appendChild(el);
173
+ return el;
174
+ }
175
+ return { trigger, content, state, Item, Group, Separator, Label };
176
+ }
177
+ };
178
+
179
+ export { ContextMenu };
@@ -0,0 +1,17 @@
1
+ // src/utils/id.ts
2
+ var counter = 0;
3
+ function uniqueId(prefix = "vz") {
4
+ return `${prefix}-${++counter}`;
5
+ }
6
+ function linkedIds(prefix = "vz") {
7
+ const base = uniqueId(prefix);
8
+ return {
9
+ triggerId: `${base}-trigger`,
10
+ contentId: `${base}-content`
11
+ };
12
+ }
13
+ function resetIdCounter() {
14
+ counter = 0;
15
+ }
16
+
17
+ export { uniqueId, linkedIds, resetIdCounter };
@@ -0,0 +1,56 @@
1
+ import {
2
+ Keys,
3
+ isKey
4
+ } from "./chunk-jctqs9m4.js";
5
+ import {
6
+ uniqueId
7
+ } from "./chunk-8y1jf6xr.js";
8
+
9
+ // src/toggle/toggle.tsx
10
+ import { signal } from "@vertz/ui";
11
+ import { __attr, __element, __on } from "@vertz/ui/internals";
12
+ function ToggleRoot(options = {}) {
13
+ const { defaultPressed = false, disabled = false, onPressedChange } = options;
14
+ const pressed = signal(defaultPressed, "pressed");
15
+ function toggle() {
16
+ if (disabled)
17
+ return;
18
+ pressed.value = !pressed.value;
19
+ onPressedChange?.(pressed.value);
20
+ }
21
+ return (() => {
22
+ const __el0 = __element("button");
23
+ __el0.setAttribute("data-v-id", "ToggleRoot");
24
+ __el0.setAttribute("type", "button");
25
+ {
26
+ const __v = uniqueId("toggle");
27
+ if (__v != null && __v !== false)
28
+ __el0.setAttribute("id", __v === true ? "" : __v);
29
+ }
30
+ __attr(__el0, "aria-pressed", () => pressed.value ? "true" : "false");
31
+ __attr(__el0, "data-state", () => pressed.value ? "on" : "off");
32
+ {
33
+ const __v = disabled;
34
+ if (__v != null && __v !== false)
35
+ __el0.setAttribute("disabled", __v === true ? "" : __v);
36
+ }
37
+ {
38
+ const __v = disabled ? "true" : undefined;
39
+ if (__v != null && __v !== false)
40
+ __el0.setAttribute("aria-disabled", __v === true ? "" : __v);
41
+ }
42
+ __on(__el0, "click", toggle);
43
+ __on(__el0, "keydown", (e) => {
44
+ if (isKey(e, Keys.Space)) {
45
+ e.preventDefault();
46
+ toggle();
47
+ }
48
+ });
49
+ return __el0;
50
+ })();
51
+ }
52
+ var Toggle = {
53
+ Root: ToggleRoot
54
+ };
55
+
56
+ export { Toggle };
@@ -0,0 +1,32 @@
1
+ // src/utils/dismiss.ts
2
+ function createDismiss(options) {
3
+ const { onDismiss, insideElements, escapeKey = true, clickOutside = true } = options;
4
+ function handlePointerDown(event) {
5
+ const target = event.target;
6
+ const isInside = insideElements.some((el) => el.contains(target));
7
+ if (!isInside) {
8
+ onDismiss();
9
+ }
10
+ }
11
+ function handleKeyDown(event) {
12
+ if (event.key === "Escape") {
13
+ onDismiss();
14
+ }
15
+ }
16
+ if (clickOutside) {
17
+ document.addEventListener("pointerdown", handlePointerDown, true);
18
+ }
19
+ if (escapeKey) {
20
+ document.addEventListener("keydown", handleKeyDown);
21
+ }
22
+ return function cleanup() {
23
+ if (clickOutside) {
24
+ document.removeEventListener("pointerdown", handlePointerDown, true);
25
+ }
26
+ if (escapeKey) {
27
+ document.removeEventListener("keydown", handleKeyDown);
28
+ }
29
+ };
30
+ }
31
+
32
+ export { createDismiss };
@@ -0,0 +1,148 @@
1
+ import {
2
+ Keys,
3
+ isKey
4
+ } from "./chunk-jctqs9m4.js";
5
+ import {
6
+ setDataState,
7
+ setExpanded,
8
+ setHidden,
9
+ setHiddenAnimated,
10
+ setSelected
11
+ } from "./chunk-vvjyx7fe.js";
12
+ import {
13
+ linkedIds
14
+ } from "./chunk-8y1jf6xr.js";
15
+
16
+ // src/combobox/combobox.ts
17
+ import { signal } from "@vertz/ui";
18
+ var Combobox = {
19
+ Root(options = {}) {
20
+ const { defaultValue = "", onValueChange, onInputChange } = options;
21
+ const ids = linkedIds("combobox");
22
+ const state = {
23
+ open: signal(false),
24
+ value: signal(defaultValue),
25
+ inputValue: signal(defaultValue),
26
+ activeIndex: signal(-1)
27
+ };
28
+ const optionElements = [];
29
+ const input = document.createElement("input");
30
+ input.setAttribute("type", "text");
31
+ input.setAttribute("role", "combobox");
32
+ input.setAttribute("aria-autocomplete", "list");
33
+ input.setAttribute("aria-controls", ids.contentId);
34
+ input.setAttribute("aria-haspopup", "listbox");
35
+ input.id = ids.triggerId;
36
+ input.value = defaultValue;
37
+ setExpanded(input, false);
38
+ const listbox = document.createElement("div");
39
+ listbox.setAttribute("role", "listbox");
40
+ listbox.id = ids.contentId;
41
+ setHidden(listbox, true);
42
+ setDataState(listbox, "closed");
43
+ function open() {
44
+ state.open.value = true;
45
+ setExpanded(input, true);
46
+ setHidden(listbox, false);
47
+ setDataState(listbox, "open");
48
+ }
49
+ function close() {
50
+ state.open.value = false;
51
+ state.activeIndex.value = -1;
52
+ setExpanded(input, false);
53
+ setDataState(listbox, "closed");
54
+ setHiddenAnimated(listbox, true);
55
+ updateActiveDescendant(-1);
56
+ }
57
+ function selectOption(value) {
58
+ state.value.value = value;
59
+ state.inputValue.value = value;
60
+ input.value = value;
61
+ for (const opt of optionElements) {
62
+ const isActive = opt.getAttribute("data-value") === value;
63
+ setSelected(opt, isActive);
64
+ setDataState(opt, isActive ? "active" : "inactive");
65
+ }
66
+ onValueChange?.(value);
67
+ close();
68
+ input.focus();
69
+ }
70
+ function updateActiveDescendant(index) {
71
+ const opt = optionElements[index];
72
+ if (index >= 0 && opt) {
73
+ input.setAttribute("aria-activedescendant", opt.id);
74
+ for (let i = 0;i < optionElements.length; i++) {
75
+ const el = optionElements[i];
76
+ if (el)
77
+ setDataState(el, i === index ? "active" : "inactive");
78
+ }
79
+ } else {
80
+ input.removeAttribute("aria-activedescendant");
81
+ }
82
+ }
83
+ input.addEventListener("input", () => {
84
+ state.inputValue.value = input.value;
85
+ onInputChange?.(input.value);
86
+ if (!state.open.peek())
87
+ open();
88
+ });
89
+ input.addEventListener("focus", () => {
90
+ if (!state.open.peek() && input.value.length > 0)
91
+ open();
92
+ });
93
+ input.addEventListener("keydown", (event) => {
94
+ if (isKey(event, Keys.Escape)) {
95
+ event.preventDefault();
96
+ close();
97
+ return;
98
+ }
99
+ if (isKey(event, Keys.ArrowDown)) {
100
+ event.preventDefault();
101
+ if (!state.open.peek()) {
102
+ open();
103
+ }
104
+ const next = Math.min(state.activeIndex.peek() + 1, optionElements.length - 1);
105
+ state.activeIndex.value = next;
106
+ updateActiveDescendant(next);
107
+ return;
108
+ }
109
+ if (isKey(event, Keys.ArrowUp)) {
110
+ event.preventDefault();
111
+ const prev = Math.max(state.activeIndex.peek() - 1, 0);
112
+ state.activeIndex.value = prev;
113
+ updateActiveDescendant(prev);
114
+ return;
115
+ }
116
+ if (isKey(event, Keys.Enter)) {
117
+ event.preventDefault();
118
+ const idx = state.activeIndex.peek();
119
+ if (idx >= 0 && idx < optionElements.length) {
120
+ const val = optionElements[idx]?.getAttribute("data-value");
121
+ if (val != null)
122
+ selectOption(val);
123
+ }
124
+ return;
125
+ }
126
+ });
127
+ function Option(value, label) {
128
+ const opt = document.createElement("div");
129
+ const optId = `${ids.contentId}-opt-${optionElements.length}`;
130
+ opt.setAttribute("role", "option");
131
+ opt.id = optId;
132
+ opt.setAttribute("data-value", value);
133
+ opt.textContent = label ?? value;
134
+ const isSelected = value === defaultValue;
135
+ setSelected(opt, isSelected);
136
+ setDataState(opt, isSelected ? "active" : "inactive");
137
+ opt.addEventListener("click", () => {
138
+ selectOption(value);
139
+ });
140
+ optionElements.push(opt);
141
+ listbox.appendChild(opt);
142
+ return opt;
143
+ }
144
+ return { input, listbox, state, Option };
145
+ }
146
+ };
147
+
148
+ export { Combobox };
@@ -0,0 +1,235 @@
1
+ import {
2
+ createDismiss
3
+ } from "./chunk-a6wp8c32.js";
4
+ import {
5
+ setRovingTabindex
6
+ } from "./chunk-e2v1c9ex.js";
7
+ import {
8
+ createFloatingPosition
9
+ } from "./chunk-0mcr52hc.js";
10
+ import {
11
+ Keys,
12
+ handleListNavigation,
13
+ isKey
14
+ } from "./chunk-jctqs9m4.js";
15
+ import {
16
+ setDataState,
17
+ setExpanded,
18
+ setHidden,
19
+ setHiddenAnimated
20
+ } from "./chunk-vvjyx7fe.js";
21
+ import {
22
+ linkedIds
23
+ } from "./chunk-8y1jf6xr.js";
24
+
25
+ // src/menubar/menubar.ts
26
+ import { signal } from "@vertz/ui";
27
+ var Menubar = {
28
+ Root(options = {}) {
29
+ const { onSelect, positioning } = options;
30
+ const state = { activeMenu: signal(null) };
31
+ const triggers = [];
32
+ const menus = new Map;
33
+ let floatingCleanup = null;
34
+ let dismissCleanup = null;
35
+ const root = document.createElement("div");
36
+ root.setAttribute("role", "menubar");
37
+ function closeAll() {
38
+ for (const [, menu] of menus) {
39
+ setExpanded(menu.trigger, false);
40
+ setDataState(menu.trigger, "closed");
41
+ setDataState(menu.content, "closed");
42
+ setHiddenAnimated(menu.content, true);
43
+ }
44
+ state.activeMenu.value = null;
45
+ if (positioning) {
46
+ floatingCleanup?.();
47
+ floatingCleanup = null;
48
+ dismissCleanup?.();
49
+ dismissCleanup = null;
50
+ } else {
51
+ document.removeEventListener("mousedown", handleClickOutside);
52
+ }
53
+ }
54
+ function openMenu(value) {
55
+ const current = state.activeMenu.peek();
56
+ if (current && current !== value) {
57
+ const prev = menus.get(current);
58
+ if (prev) {
59
+ setExpanded(prev.trigger, false);
60
+ setDataState(prev.trigger, "closed");
61
+ setDataState(prev.content, "closed");
62
+ setHiddenAnimated(prev.content, true);
63
+ }
64
+ if (positioning) {
65
+ floatingCleanup?.();
66
+ floatingCleanup = null;
67
+ }
68
+ }
69
+ const menu = menus.get(value);
70
+ if (!menu)
71
+ return;
72
+ state.activeMenu.value = value;
73
+ setExpanded(menu.trigger, true);
74
+ setHidden(menu.content, false);
75
+ setDataState(menu.trigger, "open");
76
+ setDataState(menu.content, "open");
77
+ if (positioning) {
78
+ const result = createFloatingPosition(menu.trigger, menu.content, positioning);
79
+ floatingCleanup = result.cleanup;
80
+ if (!dismissCleanup) {
81
+ dismissCleanup = createDismiss({
82
+ onDismiss: closeAll,
83
+ insideElements: [root],
84
+ escapeKey: false
85
+ });
86
+ }
87
+ } else {
88
+ document.addEventListener("mousedown", handleClickOutside);
89
+ }
90
+ const firstItem = menu.items[0];
91
+ if (firstItem) {
92
+ firstItem.setAttribute("tabindex", "0");
93
+ firstItem.focus();
94
+ }
95
+ }
96
+ function handleClickOutside(event) {
97
+ const target = event.target;
98
+ if (!root.contains(target)) {
99
+ closeAll();
100
+ }
101
+ }
102
+ root.addEventListener("keydown", (event) => {
103
+ if (isKey(event, Keys.ArrowLeft, Keys.ArrowRight, Keys.Home, Keys.End)) {
104
+ const focused = document.activeElement;
105
+ const triggerIndex = triggers.indexOf(focused);
106
+ if (triggerIndex >= 0) {
107
+ const result = handleListNavigation(event, triggers, { orientation: "horizontal" });
108
+ if (result && state.activeMenu.peek()) {
109
+ const newTrigger = result;
110
+ const menuValue = newTrigger.getAttribute("data-value");
111
+ if (menuValue)
112
+ openMenu(menuValue);
113
+ }
114
+ }
115
+ }
116
+ });
117
+ function Menu(value, label) {
118
+ const ids = linkedIds("menubar-menu");
119
+ const items = [];
120
+ const trigger = document.createElement("button");
121
+ trigger.setAttribute("type", "button");
122
+ trigger.setAttribute("role", "menuitem");
123
+ trigger.id = ids.triggerId;
124
+ trigger.setAttribute("aria-controls", ids.contentId);
125
+ trigger.setAttribute("aria-haspopup", "menu");
126
+ trigger.setAttribute("data-value", value);
127
+ trigger.textContent = label ?? value;
128
+ setExpanded(trigger, false);
129
+ setDataState(trigger, "closed");
130
+ setRovingTabindex(triggers.concat(trigger), triggers.length);
131
+ const content = document.createElement("div");
132
+ content.setAttribute("role", "menu");
133
+ content.id = ids.contentId;
134
+ setHidden(content, true);
135
+ setDataState(content, "closed");
136
+ trigger.addEventListener("click", () => {
137
+ if (state.activeMenu.peek() === value) {
138
+ closeAll();
139
+ } else {
140
+ openMenu(value);
141
+ }
142
+ });
143
+ trigger.addEventListener("keydown", (event) => {
144
+ if (isKey(event, Keys.ArrowDown, Keys.Enter, Keys.Space)) {
145
+ event.preventDefault();
146
+ openMenu(value);
147
+ }
148
+ });
149
+ content.addEventListener("keydown", (event) => {
150
+ if (isKey(event, Keys.Escape)) {
151
+ event.preventDefault();
152
+ event.stopPropagation();
153
+ closeAll();
154
+ trigger.focus();
155
+ return;
156
+ }
157
+ if (isKey(event, Keys.Enter, Keys.Space)) {
158
+ event.preventDefault();
159
+ const active = document.activeElement;
160
+ const activeItem = items.find((item) => item === active);
161
+ if (activeItem) {
162
+ const val = activeItem.getAttribute("data-value");
163
+ if (val !== null) {
164
+ onSelect?.(val);
165
+ closeAll();
166
+ trigger.focus();
167
+ }
168
+ }
169
+ return;
170
+ }
171
+ if (isKey(event, Keys.ArrowLeft, Keys.ArrowRight)) {
172
+ event.preventDefault();
173
+ const triggerIdx = triggers.indexOf(trigger);
174
+ let nextIdx;
175
+ if (isKey(event, Keys.ArrowRight)) {
176
+ nextIdx = (triggerIdx + 1) % triggers.length;
177
+ } else {
178
+ nextIdx = (triggerIdx - 1 + triggers.length) % triggers.length;
179
+ }
180
+ const nextTrigger = triggers[nextIdx];
181
+ if (nextTrigger) {
182
+ nextTrigger.focus();
183
+ const nextValue = nextTrigger.getAttribute("data-value");
184
+ if (nextValue)
185
+ openMenu(nextValue);
186
+ }
187
+ return;
188
+ }
189
+ handleListNavigation(event, items, { orientation: "vertical" });
190
+ });
191
+ function createItem(val, itemLabel, parent) {
192
+ const item = document.createElement("div");
193
+ item.setAttribute("role", "menuitem");
194
+ item.setAttribute("data-value", val);
195
+ item.setAttribute("tabindex", "-1");
196
+ item.textContent = itemLabel ?? val;
197
+ item.addEventListener("click", () => {
198
+ onSelect?.(val);
199
+ closeAll();
200
+ trigger.focus();
201
+ });
202
+ items.push(item);
203
+ (parent ?? content).appendChild(item);
204
+ return item;
205
+ }
206
+ function Item(val, itemLabel) {
207
+ return createItem(val, itemLabel);
208
+ }
209
+ function Group(groupLabel) {
210
+ const el = document.createElement("div");
211
+ el.setAttribute("role", "group");
212
+ el.setAttribute("aria-label", groupLabel);
213
+ content.appendChild(el);
214
+ return {
215
+ el,
216
+ Item: (val, l) => createItem(val, l, el)
217
+ };
218
+ }
219
+ function Separator() {
220
+ const hr = document.createElement("hr");
221
+ hr.setAttribute("role", "separator");
222
+ content.appendChild(hr);
223
+ return hr;
224
+ }
225
+ triggers.push(trigger);
226
+ setRovingTabindex(triggers, 0);
227
+ menus.set(value, { trigger, content, items });
228
+ root.appendChild(trigger);
229
+ return { trigger, content, Item, Group, Separator };
230
+ }
231
+ return { root, state, Menu };
232
+ }
233
+ };
234
+
235
+ export { Menubar };