ajo-ui 0.1.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 (103) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +126 -0
  3. package/dist/accordion.js +130 -0
  4. package/dist/avatar.js +54 -0
  5. package/dist/calendar.js +2 -0
  6. package/dist/carousel.js +239 -0
  7. package/dist/chart.js +790 -0
  8. package/dist/checkbox-group.js +70 -0
  9. package/dist/checkbox.js +77 -0
  10. package/dist/chunks/bar-CVafh6C1.js +99 -0
  11. package/dist/chunks/calendar-q8jZ8Cxr.js +1923 -0
  12. package/dist/chunks/collection-DtRB63U4.js +111 -0
  13. package/dist/chunks/data-table-DpkWv4y4.js +1039 -0
  14. package/dist/chunks/menu-B45IyHHC.js +704 -0
  15. package/dist/chunks/native-BJdhd9XJ.js +20 -0
  16. package/dist/chunks/popup-C8Bb3l_g.js +459 -0
  17. package/dist/chunks/popup-surface-BDCgtVU0.js +18 -0
  18. package/dist/chunks/position-D6_i_SRn.js +434 -0
  19. package/dist/chunks/virtual-list-B7hjGkjk.js +413 -0
  20. package/dist/collapsible.js +106 -0
  21. package/dist/command.js +263 -0
  22. package/dist/context-menu.js +112 -0
  23. package/dist/data-table.js +5 -0
  24. package/dist/dialog.js +207 -0
  25. package/dist/direction.js +22 -0
  26. package/dist/drawer.js +139 -0
  27. package/dist/field.js +26 -0
  28. package/dist/index.js +38 -0
  29. package/dist/input-date.js +994 -0
  30. package/dist/input-group.js +52 -0
  31. package/dist/input-otp.js +179 -0
  32. package/dist/menu.js +2 -0
  33. package/dist/menubar.js +236 -0
  34. package/dist/message-scroller.js +446 -0
  35. package/dist/navigation-menu.js +330 -0
  36. package/dist/popover.js +307 -0
  37. package/dist/progress.js +39 -0
  38. package/dist/radio-group.js +107 -0
  39. package/dist/resizable.js +172 -0
  40. package/dist/select.js +961 -0
  41. package/dist/sidebar.js +343 -0
  42. package/dist/slider.js +259 -0
  43. package/dist/switch.js +53 -0
  44. package/dist/tabs.js +182 -0
  45. package/dist/toast.js +492 -0
  46. package/dist/toggle-group.js +111 -0
  47. package/dist/toggle.js +52 -0
  48. package/dist/toolbar.js +127 -0
  49. package/dist/tooltip.js +196 -0
  50. package/dist/utils.js +104 -0
  51. package/dist/virtual-list.js +2 -0
  52. package/package.json +250 -0
  53. package/src/accordion.tsx +261 -0
  54. package/src/availability.ts +261 -0
  55. package/src/avatar.tsx +99 -0
  56. package/src/bar.ts +156 -0
  57. package/src/calendar.tsx +1441 -0
  58. package/src/carousel.tsx +424 -0
  59. package/src/chart.tsx +1194 -0
  60. package/src/checkbox-group.tsx +132 -0
  61. package/src/checkbox.tsx +130 -0
  62. package/src/collapsible.tsx +188 -0
  63. package/src/collection.ts +154 -0
  64. package/src/command.tsx +511 -0
  65. package/src/context-menu.tsx +233 -0
  66. package/src/data-table-contract.ts +143 -0
  67. package/src/data-table-model.ts +760 -0
  68. package/src/data-table.tsx +475 -0
  69. package/src/dialog.tsx +393 -0
  70. package/src/direction.tsx +45 -0
  71. package/src/drawer.tsx +251 -0
  72. package/src/field.tsx +61 -0
  73. package/src/index.ts +37 -0
  74. package/src/input-date.tsx +1539 -0
  75. package/src/input-group.tsx +142 -0
  76. package/src/input-otp.tsx +324 -0
  77. package/src/menu-cluster.ts +124 -0
  78. package/src/menu.tsx +1095 -0
  79. package/src/menubar.tsx +459 -0
  80. package/src/message-scroller.tsx +732 -0
  81. package/src/native.ts +26 -0
  82. package/src/navigation-menu.tsx +578 -0
  83. package/src/popover.tsx +519 -0
  84. package/src/popup-surface.tsx +31 -0
  85. package/src/popup.ts +569 -0
  86. package/src/position.ts +523 -0
  87. package/src/progress.tsx +70 -0
  88. package/src/radio-group.tsx +186 -0
  89. package/src/resizable.tsx +310 -0
  90. package/src/segments.ts +922 -0
  91. package/src/select.tsx +1501 -0
  92. package/src/sidebar.tsx +683 -0
  93. package/src/slider.tsx +424 -0
  94. package/src/switch.tsx +104 -0
  95. package/src/tabs.tsx +314 -0
  96. package/src/toast.tsx +923 -0
  97. package/src/toggle-group.tsx +249 -0
  98. package/src/toggle.tsx +91 -0
  99. package/src/toolbar.tsx +212 -0
  100. package/src/tooltip.tsx +359 -0
  101. package/src/utils.ts +204 -0
  102. package/src/virtual-list.tsx +205 -0
  103. package/src/virtual.ts +385 -0
@@ -0,0 +1,330 @@
1
+ import { text, triggerAttrs } from "./utils.js";
2
+ import { n as popup, t as contentAttrs } from "./chunks/popup-C8Bb3l_g.js";
3
+ import { t as bar } from "./chunks/bar-CVafh6C1.js";
4
+ import { callHandler, id, listen, statefulRootAttrs } from "ajo-cloves";
5
+ import { context } from "ajo/context";
6
+ import { Fragment, jsx } from "ajo/jsx-runtime";
7
+ //#region packages/ajo-ui/src/navigation-menu.tsx
8
+ var RootContext = context(null);
9
+ var ItemContext = context(null);
10
+ var triggers = (root) => Array.from(root.querySelectorAll("[data-navigation-menu-trigger=\"true\"]")).filter((trigger) => !trigger.disabled && trigger.offsetParent !== null && trigger.closest("[data-slot=\"navigation-menu\"]") === root);
11
+ var FOCUSABLE = "a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])";
12
+ var NavigationMenuRoot = function* ({ defaultValue, value }) {
13
+ let closeDelay = 300;
14
+ const closeFocus = { current: null };
15
+ let onValueChange;
16
+ let openDelay = 200;
17
+ let pendingFocus = "";
18
+ const state = bar(this, {
19
+ triggers: () => triggers(this),
20
+ initialValue: String(value ?? defaultValue ?? ""),
21
+ onValueChange: (next, event) => onValueChange?.(next, event)
22
+ });
23
+ const openTrigger = () => triggers(this).find((trigger) => trigger.dataset.value === state.value);
24
+ const focusPanel = (trigger) => {
25
+ const contentId = trigger.getAttribute("aria-controls");
26
+ (contentId ? document.getElementById(contentId) : null)?.querySelector(FOCUSABLE)?.focus();
27
+ };
28
+ const close = (event, focus) => {
29
+ pendingFocus = "";
30
+ closeFocus.current = focus ?? null;
31
+ state.close(event);
32
+ };
33
+ listen(this, "keydown", (event) => {
34
+ if (event.defaultPrevented) return;
35
+ const target = event.target;
36
+ if (target?.closest("[data-slot=\"navigation-menu\"]") !== this) return;
37
+ const trigger = target?.closest("[data-navigation-menu-trigger=\"true\"]");
38
+ if (!trigger) {
39
+ if (event.key === "Escape" && state.value) {
40
+ event.preventDefault();
41
+ close(event, openTrigger());
42
+ }
43
+ return;
44
+ }
45
+ if (state.handle(event)) return;
46
+ if (event.key === "ArrowDown" || event.key === "Enter" || event.key === " ") {
47
+ event.preventDefault();
48
+ const next = trigger.dataset.value ?? "";
49
+ if (state.value === next) if (event.key === "ArrowDown") focusPanel(trigger);
50
+ else close(event);
51
+ else {
52
+ pendingFocus = next;
53
+ state.setValue(next, event);
54
+ }
55
+ }
56
+ });
57
+ listen(this, "focusout", (event) => {
58
+ if (!state.value) return;
59
+ const next = event.relatedTarget;
60
+ if (next && this.contains(next)) return;
61
+ if (!next && this.contains(document.activeElement)) return;
62
+ close(event);
63
+ });
64
+ for (const args of this) {
65
+ closeDelay = Math.max(0, Number(args.closeDelay ?? 300));
66
+ onValueChange = args.onValueChange;
67
+ openDelay = Math.max(0, Number(args.openDelay ?? 200));
68
+ state.sync(args.value != null ? String(args.value ?? "") : void 0);
69
+ if (pendingFocus && pendingFocus !== state.value) pendingFocus = "";
70
+ if (closeFocus.current) {
71
+ const target = closeFocus.current;
72
+ closeFocus.current = null;
73
+ if (!state.value) queueMicrotask(() => {
74
+ if (!state.value) target.focus();
75
+ });
76
+ }
77
+ RootContext({
78
+ close,
79
+ closeDelay,
80
+ follow: (next, event) => {
81
+ pendingFocus = "";
82
+ state.follow(next, event);
83
+ },
84
+ gap: args.gap,
85
+ open: (next, event) => {
86
+ if (pendingFocus !== next) pendingFocus = "";
87
+ state.setValue(next, event);
88
+ },
89
+ openDelay,
90
+ placement: args.placement,
91
+ takeFocus: (value) => {
92
+ if (!value || pendingFocus !== value) return false;
93
+ pendingFocus = "";
94
+ return true;
95
+ },
96
+ value: state.value
97
+ });
98
+ yield /* @__PURE__ */ jsx(Fragment, { children: args.children });
99
+ }
100
+ };
101
+ NavigationMenuRoot.is = "nav";
102
+ /** Unstyled root landmark and state provider for a navigation menu. */
103
+ var NavigationMenu = ({ children, class: classes, closeDelay, defaultValue, gap, onValueChange, openDelay, placement, value, ...attrs }) => /* @__PURE__ */ jsx(NavigationMenuRoot, {
104
+ ...statefulRootAttrs(attrs),
105
+ closeDelay,
106
+ defaultValue,
107
+ gap,
108
+ onValueChange,
109
+ openDelay,
110
+ placement,
111
+ value,
112
+ "attr:class": classes,
113
+ "attr:data-slot": "navigation-menu",
114
+ children
115
+ });
116
+ /** Unstyled horizontal list of navigation menu items. */
117
+ var NavigationMenuList = ({ children, class: classes, ...attrs }) => /* @__PURE__ */ jsx("ul", {
118
+ ...attrs,
119
+ class: classes,
120
+ "data-slot": "navigation-menu-list",
121
+ children
122
+ });
123
+ var NavigationMenuItemRoot = function* ({ value }) {
124
+ const fallback = value ?? id("navigation-menu-item");
125
+ let disabled = false;
126
+ let itemValue = String(fallback);
127
+ let root = null;
128
+ let item;
129
+ item = popup(this, {
130
+ prefix: "navigation-menu",
131
+ profile: "navigation",
132
+ initialOpen: false,
133
+ disabled: () => disabled,
134
+ hover: {
135
+ openDelay: () => root?.openDelay ?? 200,
136
+ closeDelay: () => root?.closeDelay ?? 300
137
+ },
138
+ onOpenChange: (next, event) => {
139
+ if (next) root?.open(itemValue, event);
140
+ else if (root?.value === itemValue) root.close(event);
141
+ },
142
+ reference: (view) => view.trigger,
143
+ source: (view) => view.trigger,
144
+ referenceHidden: "close",
145
+ dismiss: {
146
+ escape: false,
147
+ outside: true,
148
+ inside: (view) => [view.trigger, view.content],
149
+ onDismiss: (event) => closeItem(event)
150
+ },
151
+ onPosition: () => {
152
+ if (root?.takeFocus(itemValue)) item.content?.querySelector(FOCUSABLE)?.focus();
153
+ },
154
+ onSync: (opened) => {
155
+ if (!opened) cause = "";
156
+ }
157
+ });
158
+ let cause = "";
159
+ const registerTriggerHover = (hovering, event) => {
160
+ if (hovering) {
161
+ if (!item.open) cause = "hover";
162
+ item.hold("trigger", event);
163
+ if (!disabled) root?.follow(itemValue, event);
164
+ } else {
165
+ if (!item.open && cause === "hover") cause = "";
166
+ item.release("trigger", event);
167
+ }
168
+ };
169
+ const registerContentHover = (hovering, event) => hovering ? item.hold("content", event) : item.release("content", event);
170
+ const registerTriggerFocus = (event) => {
171
+ if (!disabled) root?.follow(itemValue, event);
172
+ };
173
+ const openItem = (event) => {
174
+ if (disabled) return;
175
+ cause = "press";
176
+ item.cancelHover();
177
+ if (root) root.open(itemValue, event);
178
+ else item.setOpen(true, event);
179
+ };
180
+ const closeItem = (event) => root ? root.close(event) : item.close(event);
181
+ const clickTrigger = (event) => {
182
+ if (disabled) return;
183
+ if (!item.open) openItem(event);
184
+ else if (cause === "hover") {
185
+ cause = "press";
186
+ item.cancelHover();
187
+ } else closeItem(event);
188
+ };
189
+ for (const args of this) {
190
+ root = RootContext();
191
+ itemValue = String(args.value ?? fallback);
192
+ disabled = Boolean(args.disabled);
193
+ const opened = item.sync(root ? root.value === itemValue : null, {
194
+ placement: root?.placement,
195
+ gap: root?.gap
196
+ });
197
+ if (!opened) cause = "";
198
+ ItemContext({
199
+ adoptTriggerId: item.adoptTriggerId,
200
+ clickTrigger,
201
+ close: closeItem,
202
+ contentId: item.contentId,
203
+ contentStyle: item.contentStyle,
204
+ disabled,
205
+ open: opened,
206
+ registerContentHover,
207
+ registerTriggerFocus,
208
+ registerTriggerHover,
209
+ setContent: item.setContent,
210
+ setTrigger: item.setTrigger,
211
+ triggerId: item.triggerId,
212
+ value: itemValue
213
+ });
214
+ yield /* @__PURE__ */ jsx(Fragment, { children: args.children });
215
+ }
216
+ };
217
+ NavigationMenuItemRoot.is = "li";
218
+ /** Unstyled top-level item inside a NavigationMenuList. */
219
+ var NavigationMenuItem = ({ children, class: classes, disabled, value, ...attrs }) => /* @__PURE__ */ jsx(NavigationMenuItemRoot, {
220
+ ...statefulRootAttrs(attrs),
221
+ disabled,
222
+ value,
223
+ "attr:class": classes,
224
+ "attr:data-disabled": disabled ? "true" : void 0,
225
+ "attr:data-slot": "navigation-menu-item",
226
+ children
227
+ });
228
+ /** Unstyled button that opens an item content panel. */
229
+ var NavigationMenuTrigger = ({ children, class: classes, disabled, id: idArg, ref, textValue, type = "button", "set:onclick": onClick, "set:onfocus": onFocus, "set:onmouseenter": onMouseEnter, "set:onmouseleave": onMouseLeave, ...attrs }) => {
230
+ const item = ItemContext();
231
+ const disabledFlag = Boolean(disabled ?? item?.disabled);
232
+ const label = textValue ?? text(children);
233
+ const adoptedId = item?.adoptTriggerId(idArg);
234
+ return /* @__PURE__ */ jsx("button", {
235
+ ...attrs,
236
+ ...triggerAttrs({
237
+ controls: item?.contentId,
238
+ expanded: Boolean(item?.open),
239
+ id: adoptedId ?? idArg,
240
+ open: Boolean(item?.open),
241
+ ref,
242
+ setTrigger: item?.setTrigger,
243
+ triggerId: item?.triggerId
244
+ }),
245
+ class: classes,
246
+ "data-label": label,
247
+ "data-navigation-menu-trigger": "true",
248
+ "data-slot": "navigation-menu-trigger",
249
+ "data-value": item?.value,
250
+ disabled: disabledFlag,
251
+ type,
252
+ "set:onclick": (event) => {
253
+ callHandler(onClick, event);
254
+ if (event.defaultPrevented || disabledFlag) return;
255
+ item?.clickTrigger(event);
256
+ },
257
+ "set:onfocus": (event) => {
258
+ callHandler(onFocus, event);
259
+ if (event.defaultPrevented || disabledFlag) return;
260
+ item?.registerTriggerFocus(event);
261
+ },
262
+ "set:onmouseenter": (event) => {
263
+ callHandler(onMouseEnter, event);
264
+ if (event.defaultPrevented || disabledFlag) return;
265
+ item?.registerTriggerHover(true, event);
266
+ },
267
+ "set:onmouseleave": (event) => {
268
+ callHandler(onMouseLeave, event);
269
+ item?.registerTriggerHover(false, event);
270
+ },
271
+ children
272
+ });
273
+ };
274
+ /** Unstyled popover panel for a NavigationMenuItem. */
275
+ var NavigationMenuContent = ({ children, class: classes, ref, style, "set:onmouseenter": onMouseEnter, "set:onmouseleave": onMouseLeave, ...attrs }) => {
276
+ const item = ItemContext();
277
+ return /* @__PURE__ */ jsx("div", {
278
+ ...attrs,
279
+ ...contentAttrs({
280
+ id: item?.contentId,
281
+ open: Boolean(item?.open),
282
+ ref,
283
+ setContent: item?.setContent,
284
+ style: item?.contentStyle(style),
285
+ tabindex: "-1"
286
+ }),
287
+ "aria-labelledby": item?.triggerId,
288
+ class: classes,
289
+ "data-slot": "navigation-menu-content",
290
+ "set:onmouseenter": (event) => {
291
+ callHandler(onMouseEnter, event);
292
+ item?.registerContentHover(true, event);
293
+ },
294
+ "set:onmouseleave": (event) => {
295
+ callHandler(onMouseLeave, event);
296
+ item?.registerContentHover(false, event);
297
+ },
298
+ children
299
+ });
300
+ };
301
+ /** Unstyled link for use inside or directly within a navigation menu item. */
302
+ var NavigationMenuLink = ({ active, as = "a", children, class: classes, type = "button", "set:onclick": onClick, ...attrs }) => {
303
+ const item = ItemContext();
304
+ const state = active ? "true" : void 0;
305
+ const current = active ? "page" : void 0;
306
+ const click = (event) => {
307
+ callHandler(onClick, event);
308
+ if (!event.defaultPrevented) item?.close(event);
309
+ };
310
+ if (as === "button") return /* @__PURE__ */ jsx("button", {
311
+ ...attrs,
312
+ class: classes,
313
+ "data-active": state,
314
+ "data-slot": "navigation-menu-link",
315
+ type,
316
+ "set:onclick": click,
317
+ children
318
+ });
319
+ return /* @__PURE__ */ jsx("a", {
320
+ ...attrs,
321
+ "aria-current": current,
322
+ class: classes,
323
+ "data-active": state,
324
+ "data-slot": "navigation-menu-link",
325
+ "set:onclick": click,
326
+ children
327
+ });
328
+ };
329
+ //#endregion
330
+ export { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger };
@@ -0,0 +1,307 @@
1
+ import { popupStyle, triggerAttrs } from "./utils.js";
2
+ import { n as popup, t as contentAttrs } from "./chunks/popup-C8Bb3l_g.js";
3
+ import { t as PopupSurface } from "./chunks/popup-surface-BDCgtVU0.js";
4
+ import { callHandler, callRef, statefulRootAttrs } from "ajo-cloves";
5
+ import { context } from "ajo/context";
6
+ import { Fragment, jsx, jsxs } from "ajo/jsx-runtime";
7
+ //#region packages/ajo-ui/src/popover.tsx
8
+ var PopoverContext = context(null);
9
+ /** Shared root body for both interaction modes; the mode is fixed per host. */
10
+ function* popoverEngine(initial, mode) {
11
+ let closeDelay = 300;
12
+ let disabled = false;
13
+ let onOpenChange;
14
+ let openDelay = 700;
15
+ let popover;
16
+ popover = popup(this, {
17
+ prefix: "popover",
18
+ profile: "popover",
19
+ initialOpen: Boolean(initial.open ?? initial.defaultOpen),
20
+ disabled: () => disabled,
21
+ hover: mode === "hover" ? {
22
+ openDelay: () => openDelay,
23
+ closeDelay: () => closeDelay
24
+ } : void 0,
25
+ onOpenChange: (next, event) => onOpenChange?.(next, event),
26
+ reference: (view) => view.reference ?? view.trigger,
27
+ referenceHidden: "close",
28
+ dismiss: {
29
+ prevent: mode === "hover",
30
+ outside: true,
31
+ onDismiss: (event, view) => {
32
+ view.cancelHover();
33
+ view.setOpen(false, event);
34
+ if (mode === "click") queueMicrotask(() => view.trigger?.focus());
35
+ }
36
+ }
37
+ });
38
+ const close = (event) => {
39
+ popover.cancelHover();
40
+ popover.close(event);
41
+ };
42
+ const openWithDelay = (event) => popover.hold("trigger", event);
43
+ const registerTriggerHover = (hovering, event) => hovering ? popover.hold("trigger", event) : popover.release("trigger", event);
44
+ const registerContentHover = (hovering, event) => hovering ? popover.hold("content", event) : popover.release("content", event);
45
+ const registerTriggerFocus = (focused, event) => focused ? popover.hold("focus-trigger", event) : popover.release("focus-trigger", event);
46
+ const registerContentFocus = (focused, event) => focused ? popover.hold("focus-content", event) : popover.release("focus-content", event);
47
+ for (const args of this) {
48
+ closeDelay = Math.max(0, Number(args.closeDelay ?? 300));
49
+ disabled = Boolean(args.disabled);
50
+ onOpenChange = args.onOpenChange;
51
+ openDelay = Math.max(0, Number(args.openDelay ?? 700));
52
+ const opened = popover.sync(args.open == null ? null : Boolean(args.open), {
53
+ placement: args.placement,
54
+ gap: args.gap
55
+ });
56
+ PopoverContext({
57
+ ...popover,
58
+ close: mode === "hover" ? close : popover.close,
59
+ description: args.description,
60
+ disabled,
61
+ label: args.label,
62
+ open: opened,
63
+ openOn: mode,
64
+ ...mode === "hover" ? {
65
+ openWithDelay,
66
+ registerContentFocus,
67
+ registerContentHover,
68
+ registerTriggerFocus,
69
+ registerTriggerHover
70
+ } : {}
71
+ });
72
+ yield /* @__PURE__ */ jsx(Fragment, { children: args.children });
73
+ }
74
+ }
75
+ var PopoverClickRoot = function* (args) {
76
+ yield* popoverEngine.call(this, args, "click");
77
+ };
78
+ var PopoverHoverRoot = function* (args) {
79
+ yield* popoverEngine.call(this, args, "hover");
80
+ };
81
+ /** Unstyled root provider for a popover. */
82
+ var Popover = ({ children, class: classes, "data-slot": slot = "popover", closeDelay, defaultOpen, description, disabled, gap, label, onOpenChange, open, openDelay, openOn = "click", placement, ...attrs }) => openOn === "hover" ? /* @__PURE__ */ jsx(PopoverHoverRoot, {
83
+ ...statefulRootAttrs(attrs),
84
+ closeDelay,
85
+ defaultOpen,
86
+ description,
87
+ disabled,
88
+ gap,
89
+ label,
90
+ onOpenChange,
91
+ open,
92
+ openDelay,
93
+ placement,
94
+ "attr:class": classes,
95
+ "attr:data-slot": slot,
96
+ children
97
+ }) : /* @__PURE__ */ jsx(PopoverClickRoot, {
98
+ ...statefulRootAttrs(attrs),
99
+ defaultOpen,
100
+ description,
101
+ disabled,
102
+ gap,
103
+ label,
104
+ onOpenChange,
105
+ open,
106
+ placement,
107
+ "attr:class": classes,
108
+ "attr:data-slot": slot,
109
+ children
110
+ });
111
+ /** Unstyled button that opens a Popover. */
112
+ var PopoverTrigger = (args) => {
113
+ const popover = PopoverContext();
114
+ const all = args;
115
+ if (popover?.openOn === "hover") {
116
+ const { as = "button", children, class: classes, "data-slot": slot = "popover-trigger", disabled, id, ref, type = "button", "set:onblur": onBlur, "set:onfocus": onFocus, "set:onkeydown": onKeydown, "set:onmouseleave": onMouseLeave, "set:onmouseenter": onMouseEnter, ...attrs } = all;
117
+ const disabledFlag = Boolean(disabled ?? popover.disabled);
118
+ const common = {
119
+ ...attrs,
120
+ ...triggerAttrs({
121
+ controls: popover.contentId,
122
+ expanded: popover.open,
123
+ haspopup: "dialog",
124
+ id,
125
+ open: popover.open,
126
+ ref,
127
+ setTrigger: popover.setTrigger,
128
+ triggerId: popover.triggerId
129
+ }),
130
+ class: classes,
131
+ "data-slot": slot,
132
+ "set:onblur": (event) => {
133
+ callHandler(onBlur, event);
134
+ popover.registerTriggerFocus?.(false, event);
135
+ },
136
+ "set:onfocus": (event) => {
137
+ callHandler(onFocus, event);
138
+ if (event.defaultPrevented || disabledFlag) return;
139
+ popover.registerTriggerFocus?.(true, event);
140
+ },
141
+ "set:onkeydown": (event) => {
142
+ callHandler(onKeydown, event);
143
+ },
144
+ "set:onmouseleave": (event) => {
145
+ callHandler(onMouseLeave, event);
146
+ popover.registerTriggerHover?.(false, event);
147
+ },
148
+ "set:onmouseenter": (event) => {
149
+ callHandler(onMouseEnter, event);
150
+ if (event.defaultPrevented || disabledFlag) return;
151
+ popover.registerTriggerHover?.(true, event);
152
+ }
153
+ };
154
+ if (as === "a") {
155
+ const anchor = attrs;
156
+ return /* @__PURE__ */ jsx("a", {
157
+ ...common,
158
+ "aria-disabled": disabledFlag ? "true" : void 0,
159
+ href: disabledFlag ? void 0 : anchor.href,
160
+ tabIndex: disabledFlag ? -1 : anchor.tabIndex,
161
+ children
162
+ });
163
+ }
164
+ if (as === "span") return /* @__PURE__ */ jsx("span", {
165
+ ...common,
166
+ "aria-disabled": disabledFlag ? "true" : void 0,
167
+ children
168
+ });
169
+ return /* @__PURE__ */ jsx("button", {
170
+ ...common,
171
+ disabled: disabledFlag,
172
+ type,
173
+ children
174
+ });
175
+ }
176
+ const { children, "data-slot": slot = "popover-trigger", disabled, id, ref, type = "button", "set:onclick": onClick, ...attrs } = all;
177
+ const disabledFlag = Boolean(disabled ?? popover?.disabled);
178
+ return /* @__PURE__ */ jsx("button", {
179
+ ...attrs,
180
+ ...triggerAttrs({
181
+ controls: popover?.contentId,
182
+ expanded: Boolean(popover?.open),
183
+ haspopup: "dialog",
184
+ id,
185
+ open: Boolean(popover?.open),
186
+ ref,
187
+ setTrigger: popover?.setTrigger,
188
+ triggerId: popover?.triggerId
189
+ }),
190
+ "data-slot": slot,
191
+ disabled: disabledFlag,
192
+ "set:onclick": (event) => {
193
+ callHandler(onClick, event);
194
+ if (event.defaultPrevented) return;
195
+ popover?.setOpen(!popover.open, event);
196
+ },
197
+ type,
198
+ children
199
+ });
200
+ };
201
+ /** Optional explicit anchor used to position PopoverContent independently of the trigger. */
202
+ var PopoverAnchor = ({ children, class: classes, "data-slot": slot = "popover-anchor", ref, ...attrs }) => {
203
+ const popover = PopoverContext();
204
+ const reference = (element) => {
205
+ popover?.setReference(element);
206
+ callRef(ref, element);
207
+ };
208
+ return /* @__PURE__ */ jsx("div", {
209
+ ...attrs,
210
+ class: classes,
211
+ "data-slot": slot,
212
+ ref: reference,
213
+ children
214
+ });
215
+ };
216
+ /** Unstyled floating panel for a Popover. */
217
+ var PopoverContent = (args) => {
218
+ const popover = PopoverContext();
219
+ const titleId = popover ? `${popover.contentId}-title` : void 0;
220
+ const descriptionId = popover?.description ? `${popover.contentId}-description` : void 0;
221
+ const heading = popover ? /* @__PURE__ */ jsxs("div", {
222
+ "data-slot": "popover-header",
223
+ children: [/* @__PURE__ */ jsx("h2", {
224
+ "data-slot": "popover-title",
225
+ id: titleId,
226
+ children: popover.label
227
+ }), popover.description ? /* @__PURE__ */ jsx("p", {
228
+ "data-slot": "popover-description",
229
+ id: descriptionId,
230
+ children: popover.description
231
+ }) : null]
232
+ }) : null;
233
+ if (popover?.openOn === "hover") {
234
+ const { arrow = false, children, class: classes, "data-slot": slot = "popover-content", ref, style, "set:onfocusin": onFocusIn, "set:onfocusout": onFocusOut, "set:onmouseleave": onMouseLeave, "set:onmouseenter": onMouseEnter, ...attrs } = args;
235
+ return /* @__PURE__ */ jsxs("div", {
236
+ ...attrs,
237
+ ...contentAttrs({
238
+ id: popover.contentId,
239
+ open: popover.open,
240
+ ref,
241
+ setContent: popover.setContent,
242
+ style: popover.contentStyle(style),
243
+ tabindex: "-1"
244
+ }),
245
+ "aria-describedby": descriptionId,
246
+ "aria-labelledby": titleId,
247
+ class: classes,
248
+ "data-arrow": arrow ? "true" : void 0,
249
+ "data-slot": slot,
250
+ role: "dialog",
251
+ "set:onfocusout": (event) => {
252
+ callHandler(onFocusOut, event);
253
+ const next = event.relatedTarget;
254
+ if (next && popover.content?.contains(next)) return;
255
+ popover.registerContentFocus?.(false, event);
256
+ },
257
+ "set:onfocusin": (event) => {
258
+ callHandler(onFocusIn, event);
259
+ popover.registerContentFocus?.(true, event);
260
+ },
261
+ "set:onmouseleave": (event) => {
262
+ callHandler(onMouseLeave, event);
263
+ popover.registerContentHover?.(false, event);
264
+ },
265
+ "set:onmouseenter": (event) => {
266
+ callHandler(onMouseEnter, event);
267
+ popover.registerContentHover?.(true, event);
268
+ },
269
+ children: [
270
+ /* @__PURE__ */ jsx(PopupSurface, {
271
+ arrow,
272
+ popup: popover
273
+ }),
274
+ heading,
275
+ children
276
+ ]
277
+ });
278
+ }
279
+ const { arrow = false, children, class: classes, "data-slot": slot = "popover-content", ref, style, ...attrs } = args;
280
+ return /* @__PURE__ */ jsxs("div", {
281
+ ...attrs,
282
+ ...contentAttrs({
283
+ id: popover?.contentId,
284
+ open: Boolean(popover?.open),
285
+ ref,
286
+ setContent: popover?.setContent,
287
+ style: popover?.contentStyle(style) ?? popupStyle(style),
288
+ tabindex: "-1"
289
+ }),
290
+ "aria-describedby": descriptionId,
291
+ "aria-labelledby": titleId,
292
+ class: classes,
293
+ "data-arrow": arrow ? "true" : void 0,
294
+ "data-slot": slot,
295
+ role: "dialog",
296
+ children: [
297
+ /* @__PURE__ */ jsx(PopupSurface, {
298
+ arrow,
299
+ popup: popover
300
+ }),
301
+ heading,
302
+ children
303
+ ]
304
+ });
305
+ };
306
+ //#endregion
307
+ export { Popover, PopoverAnchor, PopoverContent, PopoverTrigger };
@@ -0,0 +1,39 @@
1
+ import { toNumber } from "./utils.js";
2
+ import { clamp } from "ajo-cloves";
3
+ import { jsx } from "ajo/jsx-runtime";
4
+ //#region packages/ajo-ui/src/progress.tsx
5
+ var state = (value, max) => {
6
+ if (value == null) return "indeterminate";
7
+ if (value >= max) return "complete";
8
+ return "loading";
9
+ };
10
+ var percent = (value, max) => value == null || max <= 0 ? 0 : clamp(value / max * 100, 0, 100);
11
+ /** Unstyled progress bar with determinate and indeterminate states. */
12
+ var Progress = ({ "aria-label": ariaLabel, "aria-valuetext": ariaValueText, getValueLabel, indicatorClass, max = 100, role = "progressbar", value = null, ...attrs }) => {
13
+ const maxValue = Math.max(1, toNumber(max, 100));
14
+ const current = value == null ? null : clamp(toNumber(value, 0), 0, maxValue);
15
+ const progress = percent(current, maxValue);
16
+ const progressState = state(current, maxValue);
17
+ const valueText = current == null ? ariaValueText : ariaValueText ?? getValueLabel?.(current, maxValue);
18
+ return /* @__PURE__ */ jsx("div", {
19
+ ...attrs,
20
+ "aria-label": ariaLabel,
21
+ "aria-valuemax": maxValue,
22
+ "aria-valuemin": "0",
23
+ "aria-valuenow": current == null ? void 0 : current,
24
+ "aria-valuetext": valueText,
25
+ "data-max": maxValue,
26
+ "data-slot": "progress",
27
+ "data-state": progressState,
28
+ "data-value": current == null ? void 0 : current,
29
+ role,
30
+ children: /* @__PURE__ */ jsx("div", {
31
+ "aria-hidden": "true",
32
+ class: indicatorClass,
33
+ "data-slot": "progress-indicator",
34
+ style: current == null ? void 0 : `transform:translateX(-${100 - progress}%)`
35
+ })
36
+ });
37
+ };
38
+ //#endregion
39
+ export { Progress };