@revealui/presentation 0.2.0 → 0.3.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 (130) hide show
  1. package/README.md +146 -42
  2. package/dist/Box-DC3F8eRf.js +430 -0
  3. package/dist/Box-DC3F8eRf.js.map +1 -0
  4. package/dist/Text-jQVi12Hi.js +218 -0
  5. package/dist/Text-jQVi12Hi.js.map +1 -0
  6. package/dist/client.d.ts +3 -1
  7. package/dist/client.d.ts.map +1 -1
  8. package/dist/client.js +134 -2803
  9. package/dist/client.js.map +1 -1
  10. package/dist/components/BuiltWithRevealUI.d.ts +12 -0
  11. package/dist/components/BuiltWithRevealUI.d.ts.map +1 -0
  12. package/dist/components/Button.d.ts +2 -1
  13. package/dist/components/Button.d.ts.map +1 -1
  14. package/dist/components/Card.d.ts +18 -6
  15. package/dist/components/Card.d.ts.map +1 -1
  16. package/dist/components/Checkbox.d.ts +6 -3
  17. package/dist/components/Checkbox.d.ts.map +1 -1
  18. package/dist/components/FormLabel.d.ts +5 -1
  19. package/dist/components/FormLabel.d.ts.map +1 -1
  20. package/dist/components/Input.d.ts +4 -2
  21. package/dist/components/Input.d.ts.map +1 -1
  22. package/dist/components/Label.d.ts +7 -2
  23. package/dist/components/Label.d.ts.map +1 -1
  24. package/dist/components/Pagination.d.ts +12 -23
  25. package/dist/components/Pagination.d.ts.map +1 -1
  26. package/dist/components/Select.d.ts +36 -13
  27. package/dist/components/Select.d.ts.map +1 -1
  28. package/dist/components/Textarea.d.ts +4 -2
  29. package/dist/components/Textarea.d.ts.map +1 -1
  30. package/dist/components/accordion.d.ts.map +1 -1
  31. package/dist/components/alert.d.ts.map +1 -1
  32. package/dist/components/auth-layout.d.ts +7 -2
  33. package/dist/components/auth-layout.d.ts.map +1 -1
  34. package/dist/components/avatar-group.d.ts.map +1 -1
  35. package/dist/components/avatar.d.ts +6 -5
  36. package/dist/components/avatar.d.ts.map +1 -1
  37. package/dist/components/badge.d.ts +5 -5
  38. package/dist/components/badge.d.ts.map +1 -1
  39. package/dist/components/breadcrumb.d.ts.map +1 -1
  40. package/dist/components/button-headless.d.ts +2 -1
  41. package/dist/components/button-headless.d.ts.map +1 -1
  42. package/dist/components/callout.d.ts.map +1 -1
  43. package/dist/components/checkbox-headless.d.ts.map +1 -1
  44. package/dist/components/code-block.d.ts.map +1 -1
  45. package/dist/components/combobox.d.ts.map +1 -1
  46. package/dist/components/dialog.d.ts.map +1 -1
  47. package/dist/components/drawer.d.ts.map +1 -1
  48. package/dist/components/dropdown.d.ts.map +1 -1
  49. package/dist/components/empty-state.d.ts.map +1 -1
  50. package/dist/components/fieldset.d.ts.map +1 -1
  51. package/dist/components/heading.d.ts.map +1 -1
  52. package/dist/components/index.d.ts +19 -1
  53. package/dist/components/index.d.ts.map +1 -1
  54. package/dist/components/input-headless.d.ts +5 -3
  55. package/dist/components/input-headless.d.ts.map +1 -1
  56. package/dist/components/kbd.d.ts.map +1 -1
  57. package/dist/components/link.d.ts +3 -2
  58. package/dist/components/link.d.ts.map +1 -1
  59. package/dist/components/listbox.d.ts.map +1 -1
  60. package/dist/components/navbar.d.ts +5 -5
  61. package/dist/components/navbar.d.ts.map +1 -1
  62. package/dist/components/pricing-table.d.ts +23 -0
  63. package/dist/components/pricing-table.d.ts.map +1 -0
  64. package/dist/components/progress.d.ts.map +1 -1
  65. package/dist/components/radio.d.ts.map +1 -1
  66. package/dist/components/rating.d.ts.map +1 -1
  67. package/dist/components/select-headless.d.ts +5 -2
  68. package/dist/components/select-headless.d.ts.map +1 -1
  69. package/dist/components/sidebar-layout.d.ts.map +1 -1
  70. package/dist/components/sidebar.d.ts +5 -5
  71. package/dist/components/sidebar.d.ts.map +1 -1
  72. package/dist/components/skeleton.d.ts.map +1 -1
  73. package/dist/components/slider.d.ts.map +1 -1
  74. package/dist/components/stacked-layout.d.ts.map +1 -1
  75. package/dist/components/stat.d.ts.map +1 -1
  76. package/dist/components/stepper.d.ts.map +1 -1
  77. package/dist/components/switch.d.ts.map +1 -1
  78. package/dist/components/table.d.ts.map +1 -1
  79. package/dist/components/tabs.d.ts.map +1 -1
  80. package/dist/components/text.d.ts.map +1 -1
  81. package/dist/components/textarea-headless.d.ts +5 -2
  82. package/dist/components/textarea-headless.d.ts.map +1 -1
  83. package/dist/components/timeline.d.ts.map +1 -1
  84. package/dist/components/toast.d.ts.map +1 -1
  85. package/dist/components/tooltip.d.ts +7 -5
  86. package/dist/components/tooltip.d.ts.map +1 -1
  87. package/dist/hooks/index.d.ts.map +1 -1
  88. package/dist/hooks/use-click-outside.d.ts.map +1 -1
  89. package/dist/hooks/use-close-context.d.ts.map +1 -1
  90. package/dist/hooks/use-controllable-state.d.ts.map +1 -1
  91. package/dist/hooks/use-data-interactive.d.ts.map +1 -1
  92. package/dist/hooks/use-field-context.d.ts.map +1 -1
  93. package/dist/hooks/use-focus-trap.d.ts.map +1 -1
  94. package/dist/hooks/use-layout-animation.d.ts.map +1 -1
  95. package/dist/hooks/use-popover.d.ts.map +1 -1
  96. package/dist/hooks/use-roving-tabindex.d.ts.map +1 -1
  97. package/dist/hooks/use-toggle.d.ts.map +1 -1
  98. package/dist/hooks/use-transition.d.ts.map +1 -1
  99. package/dist/hooks/use-type-ahead.d.ts.map +1 -1
  100. package/dist/index.d.ts +1 -0
  101. package/dist/index.d.ts.map +1 -1
  102. package/dist/index.js +206 -65
  103. package/dist/index.js.map +1 -1
  104. package/dist/primitives/Box.d.ts +3 -1
  105. package/dist/primitives/Box.d.ts.map +1 -1
  106. package/dist/primitives/Flex.d.ts +3 -1
  107. package/dist/primitives/Flex.d.ts.map +1 -1
  108. package/dist/primitives/Grid.d.ts +3 -1
  109. package/dist/primitives/Grid.d.ts.map +1 -1
  110. package/dist/primitives/Heading.d.ts +3 -1
  111. package/dist/primitives/Heading.d.ts.map +1 -1
  112. package/dist/primitives/Slot.d.ts +3 -1
  113. package/dist/primitives/Slot.d.ts.map +1 -1
  114. package/dist/primitives/Text.d.ts +3 -1
  115. package/dist/primitives/Text.d.ts.map +1 -1
  116. package/dist/primitives/index.d.ts.map +1 -1
  117. package/dist/server.d.ts +2 -1
  118. package/dist/server.d.ts.map +1 -1
  119. package/dist/server.js +14 -13
  120. package/dist/tooltip-DQYjYWbe.js +5085 -0
  121. package/dist/tooltip-DQYjYWbe.js.map +1 -0
  122. package/dist/utils/cn.d.ts.map +1 -1
  123. package/dist/utils/index.d.ts.map +1 -1
  124. package/package.json +7 -4
  125. package/dist/Box-DDhRNK02.js +0 -45
  126. package/dist/Box-DDhRNK02.js.map +0 -1
  127. package/dist/Text-BIym7IhD.js +0 -425
  128. package/dist/Text-BIym7IhD.js.map +0 -1
  129. package/dist/tooltip-oH4lAnkn.js +0 -2277
  130. package/dist/tooltip-oH4lAnkn.js.map +0 -1
@@ -1,2277 +0,0 @@
1
- import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
- import { a as clsx, c as cn, B as Box } from "./Box-DDhRNK02.js";
3
- import React__default, { useState, useId, useCallback, forwardRef, createContext, useContext, useMemo, useRef, useEffect, useReducer } from "react";
4
- import { createPortal } from "react-dom";
5
- function Accordion({
6
- className,
7
- children
8
- }) {
9
- return /* @__PURE__ */ jsx("div", { className: clsx("divide-y divide-zinc-200 dark:divide-zinc-700", className), children });
10
- }
11
- function AccordionItem({
12
- title,
13
- defaultOpen = false,
14
- className,
15
- children
16
- }) {
17
- const [open, setOpen] = useState(defaultOpen);
18
- const id = useId();
19
- return /* @__PURE__ */ jsxs("div", { className, children: [
20
- /* @__PURE__ */ jsxs(
21
- "button",
22
- {
23
- type: "button",
24
- id: `${id}-trigger`,
25
- "aria-expanded": open,
26
- "aria-controls": `${id}-content`,
27
- onClick: () => setOpen((prev) => !prev),
28
- className: "flex w-full items-center justify-between gap-4 py-4 text-left text-sm font-medium text-zinc-950 transition-colors hover:text-zinc-700 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500 dark:text-white dark:hover:text-zinc-300",
29
- children: [
30
- /* @__PURE__ */ jsx("span", { children: title }),
31
- /* @__PURE__ */ jsx(
32
- "svg",
33
- {
34
- "aria-hidden": "true",
35
- viewBox: "0 0 16 16",
36
- fill: "none",
37
- className: clsx(
38
- "size-4 shrink-0 text-zinc-400 transition-transform duration-200",
39
- open && "rotate-180"
40
- ),
41
- children: /* @__PURE__ */ jsx(
42
- "path",
43
- {
44
- d: "M4 6l4 4 4-4",
45
- stroke: "currentColor",
46
- strokeWidth: "1.5",
47
- strokeLinecap: "round",
48
- strokeLinejoin: "round"
49
- }
50
- )
51
- }
52
- )
53
- ]
54
- }
55
- ),
56
- open && /* @__PURE__ */ jsx(
57
- "div",
58
- {
59
- id: `${id}-content`,
60
- role: "region",
61
- "aria-labelledby": `${id}-trigger`,
62
- className: "pb-4 text-sm text-zinc-600 dark:text-zinc-400",
63
- children
64
- }
65
- )
66
- ] });
67
- }
68
- function useDataInteractive({
69
- disabled = false
70
- } = {}) {
71
- const [hover, setHover] = useState(false);
72
- const [focus, setFocus] = useState(false);
73
- const [active, setActive] = useState(false);
74
- const onPointerEnter = useCallback(() => {
75
- if (!disabled) setHover(true);
76
- }, [disabled]);
77
- const onPointerLeave = useCallback(() => {
78
- setHover(false);
79
- setActive(false);
80
- }, []);
81
- const onPointerDown = useCallback(() => {
82
- if (!disabled) setActive(true);
83
- }, [disabled]);
84
- const onPointerUp = useCallback(() => {
85
- setActive(false);
86
- }, []);
87
- const onFocus = useCallback(
88
- (e) => {
89
- if (!disabled && e.currentTarget.matches(":focus-visible")) {
90
- setFocus(true);
91
- }
92
- },
93
- [disabled]
94
- );
95
- const onBlur = useCallback(() => {
96
- setFocus(false);
97
- }, []);
98
- return {
99
- "data-hover": hover ? "" : void 0,
100
- "data-focus": focus ? "" : void 0,
101
- "data-active": active ? "" : void 0,
102
- "data-disabled": disabled ? "" : void 0,
103
- onPointerEnter,
104
- onPointerLeave,
105
- onPointerDown,
106
- onPointerUp,
107
- onFocus,
108
- onBlur
109
- };
110
- }
111
- const Link = forwardRef(function Link2(props, ref) {
112
- const interactiveProps = useDataInteractive();
113
- return /* @__PURE__ */ jsx("a", { ...props, ...interactiveProps, ref });
114
- });
115
- const styles = {
116
- base: [
117
- // Base
118
- "relative isolate inline-flex items-baseline justify-center gap-x-2 rounded-lg border text-base/6 font-semibold",
119
- // Sizing
120
- "px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)] sm:text-sm/6",
121
- // Focus
122
- "focus:not-data-focus:outline-hidden data-focus:outline-2 data-focus:outline-offset-2 data-focus:outline-blue-500",
123
- // Disabled
124
- "data-disabled:opacity-50",
125
- // Icon
126
- "*:data-[slot=icon]:-mx-0.5 *:data-[slot=icon]:my-0.5 *:data-[slot=icon]:size-5 *:data-[slot=icon]:shrink-0 *:data-[slot=icon]:self-center *:data-[slot=icon]:text-(--btn-icon) sm:*:data-[slot=icon]:my-1 sm:*:data-[slot=icon]:size-4 forced-colors:[--btn-icon:ButtonText] forced-colors:data-hover:[--btn-icon:ButtonText]"
127
- ],
128
- solid: [
129
- // Optical border, implemented as the button background to avoid corner artifacts
130
- "border-transparent bg-(--btn-border)",
131
- // Dark mode: border is rendered on `after` so background is set to button background
132
- "dark:bg-(--btn-bg)",
133
- // Button background, implemented as foreground layer to stack on top of pseudo-border layer
134
- "before:absolute before:inset-0 before:-z-10 before:rounded-[calc(var(--radius-lg)-1px)] before:bg-(--btn-bg)",
135
- // Drop shadow, applied to the inset `before` layer so it blends with the border
136
- "before:shadow-sm",
137
- // Background color is moved to control and shadow is removed in dark mode so hide `before` pseudo
138
- "dark:before:hidden",
139
- // Dark mode: Subtle white outline is applied using a border
140
- "dark:border-white/5",
141
- // Shim/overlay, inset to match button foreground and used for hover state + highlight shadow
142
- "after:absolute after:inset-0 after:-z-10 after:rounded-[calc(var(--radius-lg)-1px)]",
143
- // Inner highlight shadow
144
- "after:shadow-[inset_0_1px_--theme(--color-white/15%)]",
145
- // White overlay on hover
146
- "data-active:after:bg-(--btn-hover-overlay) data-hover:after:bg-(--btn-hover-overlay)",
147
- // Dark mode: `after` layer expands to cover entire button
148
- "dark:after:-inset-px dark:after:rounded-lg",
149
- // Disabled
150
- "data-disabled:before:shadow-none data-disabled:after:shadow-none"
151
- ],
152
- outline: [
153
- // Base
154
- "border-zinc-950/10 text-zinc-950 data-active:bg-zinc-950/2.5 data-hover:bg-zinc-950/2.5",
155
- // Dark mode
156
- "dark:border-white/15 dark:text-white dark:[--btn-bg:transparent] dark:data-active:bg-white/5 dark:data-hover:bg-white/5",
157
- // Icon
158
- "[--btn-icon:var(--color-zinc-500)] data-active:[--btn-icon:var(--color-zinc-700)] data-hover:[--btn-icon:var(--color-zinc-700)] dark:data-active:[--btn-icon:var(--color-zinc-400)] dark:data-hover:[--btn-icon:var(--color-zinc-400)]"
159
- ],
160
- plain: [
161
- // Base
162
- "border-transparent text-zinc-950 data-active:bg-zinc-950/5 data-hover:bg-zinc-950/5",
163
- // Dark mode
164
- "dark:text-white dark:data-active:bg-white/10 dark:data-hover:bg-white/10",
165
- // Icon
166
- "[--btn-icon:var(--color-zinc-500)] data-active:[--btn-icon:var(--color-zinc-700)] data-hover:[--btn-icon:var(--color-zinc-700)] dark:[--btn-icon:var(--color-zinc-500)] dark:data-active:[--btn-icon:var(--color-zinc-400)] dark:data-hover:[--btn-icon:var(--color-zinc-400)]"
167
- ],
168
- colors: {
169
- "dark/zinc": [
170
- "text-white [--btn-bg:var(--color-zinc-900)] [--btn-border:var(--color-zinc-950)]/90 [--btn-hover-overlay:var(--color-white)]/10",
171
- "dark:text-white dark:[--btn-bg:var(--color-zinc-600)] dark:[--btn-hover-overlay:var(--color-white)]/5",
172
- "[--btn-icon:var(--color-zinc-400)] data-active:[--btn-icon:var(--color-zinc-300)] data-hover:[--btn-icon:var(--color-zinc-300)]"
173
- ],
174
- light: [
175
- "text-zinc-950 [--btn-bg:white] [--btn-border:var(--color-zinc-950)]/10 [--btn-hover-overlay:var(--color-zinc-950)]/2.5 data-active:[--btn-border:var(--color-zinc-950)]/15 data-hover:[--btn-border:var(--color-zinc-950)]/15",
176
- "dark:text-white dark:[--btn-hover-overlay:var(--color-white)]/5 dark:[--btn-bg:var(--color-zinc-800)]",
177
- "[--btn-icon:var(--color-zinc-500)] data-active:[--btn-icon:var(--color-zinc-700)] data-hover:[--btn-icon:var(--color-zinc-700)] dark:[--btn-icon:var(--color-zinc-500)] dark:data-active:[--btn-icon:var(--color-zinc-400)] dark:data-hover:[--btn-icon:var(--color-zinc-400)]"
178
- ],
179
- "dark/white": [
180
- "text-white [--btn-bg:var(--color-zinc-900)] [--btn-border:var(--color-zinc-950)]/90 [--btn-hover-overlay:var(--color-white)]/10",
181
- "dark:text-zinc-950 dark:[--btn-bg:white] dark:[--btn-hover-overlay:var(--color-zinc-950)]/5",
182
- "[--btn-icon:var(--color-zinc-400)] data-active:[--btn-icon:var(--color-zinc-300)] data-hover:[--btn-icon:var(--color-zinc-300)] dark:[--btn-icon:var(--color-zinc-500)] dark:data-active:[--btn-icon:var(--color-zinc-400)] dark:data-hover:[--btn-icon:var(--color-zinc-400)]"
183
- ],
184
- dark: [
185
- "text-white [--btn-bg:var(--color-zinc-900)] [--btn-border:var(--color-zinc-950)]/90 [--btn-hover-overlay:var(--color-white)]/10",
186
- "dark:[--btn-hover-overlay:var(--color-white)]/5 dark:[--btn-bg:var(--color-zinc-800)]",
187
- "[--btn-icon:var(--color-zinc-400)] data-active:[--btn-icon:var(--color-zinc-300)] data-hover:[--btn-icon:var(--color-zinc-300)]"
188
- ],
189
- white: [
190
- "text-zinc-950 [--btn-bg:white] [--btn-border:var(--color-zinc-950)]/10 [--btn-hover-overlay:var(--color-zinc-950)]/2.5 data-active:[--btn-border:var(--color-zinc-950)]/15 data-hover:[--btn-border:var(--color-zinc-950)]/15",
191
- "dark:[--btn-hover-overlay:var(--color-zinc-950)]/5",
192
- "[--btn-icon:var(--color-zinc-400)] data-active:[--btn-icon:var(--color-zinc-500)] data-hover:[--btn-icon:var(--color-zinc-500)]"
193
- ],
194
- zinc: [
195
- "text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-zinc-600)] [--btn-border:var(--color-zinc-700)]/90",
196
- "dark:[--btn-hover-overlay:var(--color-white)]/5",
197
- "[--btn-icon:var(--color-zinc-400)] data-active:[--btn-icon:var(--color-zinc-300)] data-hover:[--btn-icon:var(--color-zinc-300)]"
198
- ],
199
- indigo: [
200
- "text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-indigo-500)] [--btn-border:var(--color-indigo-600)]/90",
201
- "[--btn-icon:var(--color-indigo-300)] data-active:[--btn-icon:var(--color-indigo-200)] data-hover:[--btn-icon:var(--color-indigo-200)]"
202
- ],
203
- cyan: [
204
- "text-cyan-950 [--btn-bg:var(--color-cyan-300)] [--btn-border:var(--color-cyan-400)]/80 [--btn-hover-overlay:var(--color-white)]/25",
205
- "[--btn-icon:var(--color-cyan-500)]"
206
- ],
207
- red: [
208
- "text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-red-600)] [--btn-border:var(--color-red-700)]/90",
209
- "[--btn-icon:var(--color-red-300)] data-active:[--btn-icon:var(--color-red-200)] data-hover:[--btn-icon:var(--color-red-200)]"
210
- ],
211
- orange: [
212
- "text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-orange-500)] [--btn-border:var(--color-orange-600)]/90",
213
- "[--btn-icon:var(--color-orange-300)] data-active:[--btn-icon:var(--color-orange-200)] data-hover:[--btn-icon:var(--color-orange-200)]"
214
- ],
215
- amber: [
216
- "text-amber-950 [--btn-hover-overlay:var(--color-white)]/25 [--btn-bg:var(--color-amber-400)] [--btn-border:var(--color-amber-500)]/80",
217
- "[--btn-icon:var(--color-amber-600)]"
218
- ],
219
- yellow: [
220
- "text-yellow-950 [--btn-hover-overlay:var(--color-white)]/25 [--btn-bg:var(--color-yellow-300)] [--btn-border:var(--color-yellow-400)]/80",
221
- "[--btn-icon:var(--color-yellow-600)] data-active:[--btn-icon:var(--color-yellow-700)] data-hover:[--btn-icon:var(--color-yellow-700)]"
222
- ],
223
- lime: [
224
- "text-lime-950 [--btn-hover-overlay:var(--color-white)]/25 [--btn-bg:var(--color-lime-300)] [--btn-border:var(--color-lime-400)]/80",
225
- "[--btn-icon:var(--color-lime-600)] data-active:[--btn-icon:var(--color-lime-700)] data-hover:[--btn-icon:var(--color-lime-700)]"
226
- ],
227
- green: [
228
- "text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-green-600)] [--btn-border:var(--color-green-700)]/90",
229
- "[--btn-icon:var(--color-white)]/60 data-active:[--btn-icon:var(--color-white)]/80 data-hover:[--btn-icon:var(--color-white)]/80"
230
- ],
231
- emerald: [
232
- "text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-emerald-600)] [--btn-border:var(--color-emerald-700)]/90",
233
- "[--btn-icon:var(--color-white)]/60 data-active:[--btn-icon:var(--color-white)]/80 data-hover:[--btn-icon:var(--color-white)]/80"
234
- ],
235
- teal: [
236
- "text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-teal-600)] [--btn-border:var(--color-teal-700)]/90",
237
- "[--btn-icon:var(--color-white)]/60 data-active:[--btn-icon:var(--color-white)]/80 data-hover:[--btn-icon:var(--color-white)]/80"
238
- ],
239
- sky: [
240
- "text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-sky-500)] [--btn-border:var(--color-sky-600)]/80",
241
- "[--btn-icon:var(--color-white)]/60 data-active:[--btn-icon:var(--color-white)]/80 data-hover:[--btn-icon:var(--color-white)]/80"
242
- ],
243
- blue: [
244
- "text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-blue-600)] [--btn-border:var(--color-blue-700)]/90",
245
- "[--btn-icon:var(--color-blue-400)] data-active:[--btn-icon:var(--color-blue-300)] data-hover:[--btn-icon:var(--color-blue-300)]"
246
- ],
247
- violet: [
248
- "text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-violet-500)] [--btn-border:var(--color-violet-600)]/90",
249
- "[--btn-icon:var(--color-violet-300)] data-active:[--btn-icon:var(--color-violet-200)] data-hover:[--btn-icon:var(--color-violet-200)]"
250
- ],
251
- purple: [
252
- "text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-purple-500)] [--btn-border:var(--color-purple-600)]/90",
253
- "[--btn-icon:var(--color-purple-300)] data-active:[--btn-icon:var(--color-purple-200)] data-hover:[--btn-icon:var(--color-purple-200)]"
254
- ],
255
- fuchsia: [
256
- "text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-fuchsia-500)] [--btn-border:var(--color-fuchsia-600)]/90",
257
- "[--btn-icon:var(--color-fuchsia-300)] data-active:[--btn-icon:var(--color-fuchsia-200)] data-hover:[--btn-icon:var(--color-fuchsia-200)]"
258
- ],
259
- pink: [
260
- "text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-pink-500)] [--btn-border:var(--color-pink-600)]/90",
261
- "[--btn-icon:var(--color-pink-300)] data-active:[--btn-icon:var(--color-pink-200)] data-hover:[--btn-icon:var(--color-pink-200)]"
262
- ],
263
- rose: [
264
- "text-white [--btn-hover-overlay:var(--color-white)]/10 [--btn-bg:var(--color-rose-500)] [--btn-border:var(--color-rose-600)]/90",
265
- "[--btn-icon:var(--color-rose-300)] data-active:[--btn-icon:var(--color-rose-200)] data-hover:[--btn-icon:var(--color-rose-200)]"
266
- ]
267
- }
268
- };
269
- const Button = forwardRef(function Button2({ color, outline, plain, className, children, ...props }, ref) {
270
- const disabled = "disabled" in props ? props.disabled : false;
271
- const interactiveProps = useDataInteractive({ disabled: disabled ?? false });
272
- const classes = clsx(
273
- className,
274
- styles.base,
275
- outline ? styles.outline : plain ? styles.plain : clsx(styles.solid, styles.colors[color ?? "dark/zinc"])
276
- );
277
- return typeof props.href === "string" ? /* @__PURE__ */ jsx(Link, { ...props, className: classes, ref, children: /* @__PURE__ */ jsx(TouchTarget, { children }) }) : /* @__PURE__ */ jsx(
278
- "button",
279
- {
280
- type: "button",
281
- ...props,
282
- ...interactiveProps,
283
- className: clsx(classes, "cursor-default"),
284
- ref,
285
- children: /* @__PURE__ */ jsx(TouchTarget, { children })
286
- }
287
- );
288
- });
289
- function TouchTarget({ children }) {
290
- return /* @__PURE__ */ jsxs(Fragment, { children: [
291
- /* @__PURE__ */ jsx(
292
- "span",
293
- {
294
- className: "absolute top-1/2 left-1/2 size-[max(100%,2.75rem)] -translate-x-1/2 -translate-y-1/2 pointer-fine:hidden",
295
- "aria-hidden": "true"
296
- }
297
- ),
298
- children
299
- ] });
300
- }
301
- function Avatar({
302
- src = null,
303
- square = false,
304
- initials,
305
- alt = "",
306
- className,
307
- ...props
308
- }) {
309
- const title = alt && alt.trim().length > 0 ? alt.trim() : "Avatar";
310
- return /* @__PURE__ */ jsxs(
311
- "span",
312
- {
313
- "data-slot": "avatar",
314
- ...props,
315
- className: clsx(
316
- className,
317
- // Basic layout
318
- "inline-grid shrink-0 align-middle [--avatar-radius:20%] *:col-start-1 *:row-start-1",
319
- "outline -outline-offset-1 outline-black/10 dark:outline-white/10",
320
- // Border radius
321
- square ? "rounded-(--avatar-radius) *:rounded-(--avatar-radius)" : "rounded-full *:rounded-full"
322
- ),
323
- children: [
324
- initials && /* @__PURE__ */ jsxs(
325
- "svg",
326
- {
327
- className: "size-full fill-current p-[5%] text-[48px] font-medium uppercase select-none",
328
- viewBox: "0 0 100 100",
329
- "aria-hidden": alt && alt.trim().length > 0 ? void 0 : "true",
330
- children: [
331
- /* @__PURE__ */ jsx("title", { children: title }),
332
- /* @__PURE__ */ jsx(
333
- "text",
334
- {
335
- x: "50%",
336
- y: "50%",
337
- alignmentBaseline: "middle",
338
- dominantBaseline: "middle",
339
- textAnchor: "middle",
340
- dy: ".125em",
341
- children: initials
342
- }
343
- )
344
- ]
345
- }
346
- ),
347
- src && /* @__PURE__ */ jsx("img", { className: "size-full", src, alt })
348
- ]
349
- }
350
- );
351
- }
352
- forwardRef(function AvatarButton2({
353
- src,
354
- square = false,
355
- initials,
356
- alt,
357
- className,
358
- ...props
359
- }, ref) {
360
- const disabled = "disabled" in props ? props.disabled : false;
361
- const interactiveProps = useDataInteractive({ disabled: disabled ?? false });
362
- const classes = clsx(
363
- className,
364
- square ? "rounded-[20%]" : "rounded-full",
365
- "relative inline-grid focus:not-data-focus:outline-hidden data-focus:outline-2 data-focus:outline-offset-2 data-focus:outline-blue-500"
366
- );
367
- return typeof props.href === "string" ? /* @__PURE__ */ jsx(Link, { ...props, className: classes, ref, children: /* @__PURE__ */ jsx(TouchTarget, { children: /* @__PURE__ */ jsx(Avatar, { src, square, initials, alt }) }) }) : /* @__PURE__ */ jsx("button", { type: "button", ...props, ...interactiveProps, className: classes, ref, children: /* @__PURE__ */ jsx(TouchTarget, { children: /* @__PURE__ */ jsx(Avatar, { src, square, initials, alt }) }) });
368
- });
369
- function AvatarGroup({
370
- items,
371
- max = 5,
372
- size = "md",
373
- className
374
- }) {
375
- const sizeClasses = { xs: "size-6", sm: "size-8", md: "size-10", lg: "size-12" };
376
- const overlapClass = { xs: "-ml-1.5", sm: "-ml-2", md: "-ml-3", lg: "-ml-4" };
377
- const visible = items.slice(0, max);
378
- const overflow = items.length - max;
379
- return /* @__PURE__ */ jsxs("div", { className: clsx("flex items-center", className), children: [
380
- visible.map((item, i) => {
381
- return /* @__PURE__ */ jsx(
382
- "div",
383
- {
384
- className: clsx(
385
- "ring-2 ring-white dark:ring-zinc-900",
386
- sizeClasses[size],
387
- i > 0 && overlapClass[size],
388
- "rounded-full"
389
- ),
390
- children: /* @__PURE__ */ jsx(
391
- Avatar,
392
- {
393
- src: item.src,
394
- initials: item.initials,
395
- alt: item.alt ?? "",
396
- className: "size-full"
397
- }
398
- )
399
- },
400
- i
401
- );
402
- }),
403
- overflow > 0 && /* @__PURE__ */ jsxs(
404
- "div",
405
- {
406
- className: clsx(
407
- overlapClass[size],
408
- sizeClasses[size],
409
- "flex items-center justify-center rounded-full bg-zinc-200 text-xs font-medium text-zinc-600 ring-2 ring-white dark:bg-zinc-700 dark:text-zinc-300 dark:ring-zinc-900"
410
- ),
411
- role: "img",
412
- "aria-label": `${overflow} more`,
413
- children: [
414
- "+",
415
- overflow
416
- ]
417
- }
418
- )
419
- ] });
420
- }
421
- function Breadcrumb({
422
- items,
423
- separator,
424
- className
425
- }) {
426
- const sep = separator ?? /* @__PURE__ */ jsx("svg", { "aria-hidden": "true", viewBox: "0 0 16 16", fill: "none", className: "size-3.5 text-zinc-400", children: /* @__PURE__ */ jsx(
427
- "path",
428
- {
429
- d: "M6 4l4 4-4 4",
430
- stroke: "currentColor",
431
- strokeWidth: "1.5",
432
- strokeLinecap: "round",
433
- strokeLinejoin: "round"
434
- }
435
- ) });
436
- return /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", children: /* @__PURE__ */ jsx("ol", { className: clsx("flex flex-wrap items-center gap-1.5 text-sm", className), children: items.map((item, index) => {
437
- const isLast = index === items.length - 1;
438
- return (
439
- // biome-ignore lint/suspicious/noArrayIndexKey: breadcrumb items are positionally ordered with no stable ID
440
- /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-1.5", children: [
441
- isLast || !item.href ? /* @__PURE__ */ jsx(
442
- "span",
443
- {
444
- "aria-current": isLast ? "page" : void 0,
445
- className: clsx(
446
- isLast ? "font-medium text-zinc-950 dark:text-white" : "text-zinc-500 dark:text-zinc-400"
447
- ),
448
- children: item.label
449
- }
450
- ) : /* @__PURE__ */ jsx(
451
- "a",
452
- {
453
- href: item.href,
454
- className: "text-zinc-500 transition-colors hover:text-zinc-950 dark:text-zinc-400 dark:hover:text-white",
455
- children: item.label
456
- }
457
- ),
458
- !isLast && sep
459
- ] }, index)
460
- );
461
- }) }) });
462
- }
463
- const CheckboxContext = React__default.createContext(null);
464
- const Checkbox$1 = React__default.forwardRef(
465
- ({ checked, defaultChecked, disabled, onCheckedChange, className, ...props }, ref) => {
466
- const [internalChecked, setInternalChecked] = React__default.useState(
467
- defaultChecked ?? false
468
- );
469
- const handleChange = (e) => {
470
- if (disabled) return;
471
- const newChecked = e.target.checked;
472
- setInternalChecked(newChecked);
473
- onCheckedChange?.(newChecked);
474
- };
475
- React__default.useEffect(() => {
476
- if (checked !== void 0) {
477
- setInternalChecked(checked);
478
- }
479
- }, [checked]);
480
- return /* @__PURE__ */ jsx(CheckboxContext.Provider, { value: { state: internalChecked, disabled, onCheckedChange }, children: /* @__PURE__ */ jsx(
481
- "input",
482
- {
483
- type: "checkbox",
484
- disabled,
485
- checked: checked !== void 0 ? checked : internalChecked === "indeterminate" ? false : internalChecked,
486
- ref: (el) => {
487
- if (el) {
488
- el.indeterminate = internalChecked === "indeterminate";
489
- }
490
- if (ref) {
491
- if (typeof ref === "function") {
492
- ref(el);
493
- } else {
494
- ref.current = el;
495
- }
496
- }
497
- },
498
- onChange: handleChange,
499
- className: cn(
500
- "peer h-4 w-4 shrink-0 rounded border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
501
- className
502
- ),
503
- "data-state": internalChecked === "indeterminate" ? "indeterminate" : internalChecked ? "checked" : "unchecked",
504
- ...props
505
- }
506
- ) });
507
- }
508
- );
509
- Checkbox$1.displayName = "Checkbox";
510
- const CheckboxIndicator = React__default.forwardRef(
511
- ({ className, ...props }, ref) => {
512
- const context = React__default.useContext(CheckboxContext);
513
- if (!context) {
514
- throw new Error("CheckboxIndicator must be used within a Checkbox");
515
- }
516
- return /* @__PURE__ */ jsxs(
517
- "span",
518
- {
519
- "data-state": context.state === "indeterminate" ? "indeterminate" : context.state ? "checked" : "unchecked",
520
- ref,
521
- className: cn("flex items-center justify-center text-current", className),
522
- ...props,
523
- children: [
524
- context.state === true && "✔",
525
- context.state === "indeterminate" && "−"
526
- ]
527
- }
528
- );
529
- }
530
- );
531
- CheckboxIndicator.displayName = "CheckboxIndicator";
532
- const variantStyles = {
533
- info: {
534
- wrapper: "bg-blue-50 ring-blue-200 dark:bg-blue-950/30 dark:ring-blue-800",
535
- icon: "text-blue-600 dark:text-blue-400",
536
- iconChar: "i"
537
- },
538
- warning: {
539
- wrapper: "bg-amber-50 ring-amber-200 dark:bg-amber-950/30 dark:ring-amber-800",
540
- icon: "text-amber-600 dark:text-amber-400",
541
- iconChar: "!"
542
- },
543
- error: {
544
- wrapper: "bg-red-50 ring-red-200 dark:bg-red-950/30 dark:ring-red-800",
545
- icon: "text-red-600 dark:text-red-400",
546
- iconChar: "✕"
547
- },
548
- success: {
549
- wrapper: "bg-green-50 ring-green-200 dark:bg-green-950/30 dark:ring-green-800",
550
- icon: "text-green-600 dark:text-green-400",
551
- iconChar: "✓"
552
- },
553
- tip: {
554
- wrapper: "bg-violet-50 ring-violet-200 dark:bg-violet-950/30 dark:ring-violet-800",
555
- icon: "text-violet-600 dark:text-violet-400",
556
- iconChar: "★"
557
- }
558
- };
559
- function Callout({
560
- variant = "info",
561
- title,
562
- icon,
563
- className,
564
- children
565
- }) {
566
- const styles2 = variantStyles[variant];
567
- return /* @__PURE__ */ jsx("div", { role: "note", className: clsx("rounded-xl p-4 ring-1", styles2.wrapper, className), children: /* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
568
- /* @__PURE__ */ jsx("span", { className: clsx("mt-0.5 shrink-0 text-sm font-bold", styles2.icon), "aria-hidden": "true", children: icon ?? styles2.iconChar }),
569
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
570
- title && /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-zinc-950 dark:text-white", children: title }),
571
- /* @__PURE__ */ jsx("div", { className: clsx("text-sm text-zinc-700 dark:text-zinc-300", title && "mt-1"), children })
572
- ] })
573
- ] }) });
574
- }
575
- const FieldContext = createContext(null);
576
- function useFieldContext() {
577
- return useContext(FieldContext);
578
- }
579
- function FieldProvider({ children, disabled = false }) {
580
- const id = useId();
581
- const value = useMemo(
582
- () => ({
583
- controlId: `${id}-control`,
584
- labelId: `${id}-label`,
585
- descriptionId: `${id}-description`,
586
- errorId: `${id}-error`,
587
- disabled
588
- }),
589
- [id, disabled]
590
- );
591
- return /* @__PURE__ */ jsx(FieldContext, { value, children });
592
- }
593
- function useFieldControlProps() {
594
- const ctx = useFieldContext();
595
- if (!ctx) return {};
596
- return {
597
- id: ctx.controlId,
598
- "aria-labelledby": ctx.labelId,
599
- "aria-describedby": ctx.descriptionId,
600
- "data-disabled": ctx.disabled ? "" : void 0
601
- };
602
- }
603
- function useFieldLabelProps() {
604
- const ctx = useFieldContext();
605
- if (!ctx) return {};
606
- return {
607
- id: ctx.labelId,
608
- htmlFor: ctx.controlId,
609
- "data-disabled": ctx.disabled ? "" : void 0
610
- };
611
- }
612
- function useFieldDescriptionProps() {
613
- const ctx = useFieldContext();
614
- if (!ctx) return {};
615
- return {
616
- id: ctx.descriptionId,
617
- "data-disabled": ctx.disabled ? "" : void 0
618
- };
619
- }
620
- function useFieldErrorProps() {
621
- const ctx = useFieldContext();
622
- if (!ctx) return {};
623
- return {
624
- id: ctx.errorId,
625
- "data-disabled": ctx.disabled ? "" : void 0
626
- };
627
- }
628
- function useControllableState({
629
- value: controlledValue,
630
- defaultValue,
631
- onChange
632
- }) {
633
- const isControlled = controlledValue !== void 0;
634
- const [internalValue, setInternalValue] = useState(defaultValue);
635
- const value = isControlled ? controlledValue : internalValue;
636
- const onChangeRef = useRef(onChange);
637
- onChangeRef.current = onChange;
638
- const setValue = useCallback(
639
- (next) => {
640
- const resolvedValue = typeof next === "function" ? next(value) : next;
641
- if (!isControlled) {
642
- setInternalValue(resolvedValue);
643
- }
644
- onChangeRef.current?.(resolvedValue);
645
- },
646
- [isControlled, value]
647
- );
648
- return [value, setValue];
649
- }
650
- function useToggle({
651
- checked: controlledChecked,
652
- defaultChecked = false,
653
- onChange,
654
- disabled = false
655
- } = {}) {
656
- const [checked, setChecked] = useControllableState({
657
- value: controlledChecked,
658
- defaultValue: defaultChecked,
659
- onChange
660
- });
661
- const toggle = useCallback(() => {
662
- if (!disabled) {
663
- setChecked((prev) => !prev);
664
- }
665
- }, [disabled, setChecked]);
666
- const onClick = useCallback(() => {
667
- toggle();
668
- }, [toggle]);
669
- const onKeyDown = useCallback(
670
- (e) => {
671
- if (e.key === " ") {
672
- e.preventDefault();
673
- toggle();
674
- }
675
- },
676
- [toggle]
677
- );
678
- return {
679
- checked,
680
- toggle,
681
- toggleProps: {
682
- "aria-checked": checked,
683
- "data-checked": checked ? "" : void 0,
684
- tabIndex: 0,
685
- onClick,
686
- onKeyDown
687
- }
688
- };
689
- }
690
- function CheckboxGroup({ className, ...props }) {
691
- return /* @__PURE__ */ jsx(
692
- "div",
693
- {
694
- "data-slot": "control",
695
- ...props,
696
- className: clsx(
697
- className,
698
- // Basic groups
699
- "space-y-3",
700
- // With descriptions
701
- "has-data-[slot=description]:space-y-6 has-data-[slot=description]:**:data-[slot=label]:font-medium"
702
- )
703
- }
704
- );
705
- }
706
- function CheckboxField({
707
- className,
708
- disabled,
709
- ...props
710
- }) {
711
- return /* @__PURE__ */ jsx(FieldProvider, { disabled, children: /* @__PURE__ */ jsx(
712
- "div",
713
- {
714
- "data-slot": "field",
715
- "data-disabled": disabled ? "" : void 0,
716
- ...props,
717
- className: clsx(
718
- className,
719
- // Base layout
720
- "grid grid-cols-[1.125rem_1fr] gap-x-4 gap-y-1 sm:grid-cols-[1rem_1fr]",
721
- // Control layout
722
- "*:data-[slot=control]:col-start-1 *:data-[slot=control]:row-start-1 *:data-[slot=control]:mt-0.75 sm:*:data-[slot=control]:mt-1",
723
- // Label layout
724
- "*:data-[slot=label]:col-start-2 *:data-[slot=label]:row-start-1",
725
- // Description layout
726
- "*:data-[slot=description]:col-start-2 *:data-[slot=description]:row-start-2",
727
- // With description
728
- "has-data-[slot=description]:**:data-[slot=label]:font-medium"
729
- )
730
- }
731
- ) });
732
- }
733
- const base = [
734
- // Basic layout
735
- "relative isolate flex size-4.5 items-center justify-center rounded-[0.3125rem] sm:size-4",
736
- // Background color + shadow applied to inset pseudo element, so shadow blends with border in light mode
737
- "before:absolute before:inset-0 before:-z-10 before:rounded-[calc(0.3125rem-1px)] before:bg-white before:shadow-sm",
738
- // Background color when checked
739
- "group-data-checked:before:bg-(--checkbox-checked-bg)",
740
- // Background color is moved to control and shadow is removed in dark mode so hide `before` pseudo
741
- "dark:before:hidden",
742
- // Background color applied to control in dark mode
743
- "dark:bg-white/5 dark:group-data-checked:bg-(--checkbox-checked-bg)",
744
- // Border
745
- "border border-zinc-950/15 group-data-checked:border-transparent group-data-hover:group-data-checked:border-transparent group-data-hover:border-zinc-950/30 group-data-checked:bg-(--checkbox-checked-border)",
746
- "dark:border-white/15 dark:group-data-checked:border-white/5 dark:group-data-hover:group-data-checked:border-white/5 dark:group-data-hover:border-white/30",
747
- // Inner highlight shadow
748
- "after:absolute after:inset-0 after:rounded-[calc(0.3125rem-1px)] after:shadow-[inset_0_1px_--theme(--color-white/15%)]",
749
- "dark:after:-inset-px dark:after:hidden dark:after:rounded-[0.3125rem] dark:group-data-checked:after:block",
750
- // Focus ring
751
- "group-data-focus:outline-2 group-data-focus:outline-offset-2 group-data-focus:outline-blue-500",
752
- // Disabled state
753
- "group-data-disabled:opacity-50",
754
- "group-data-disabled:border-zinc-950/25 group-data-disabled:bg-zinc-950/5 group-data-disabled:[--checkbox-check:var(--color-zinc-950)]/50 group-data-disabled:before:bg-transparent",
755
- "dark:group-data-disabled:border-white/20 dark:group-data-disabled:bg-white/2.5 dark:group-data-disabled:[--checkbox-check:var(--color-white)]/50 dark:group-data-checked:group-data-disabled:after:hidden",
756
- // Forced colors mode
757
- "forced-colors:[--checkbox-check:HighlightText] forced-colors:[--checkbox-checked-bg:Highlight] forced-colors:group-data-disabled:[--checkbox-check:Highlight]",
758
- "dark:forced-colors:[--checkbox-check:HighlightText] dark:forced-colors:[--checkbox-checked-bg:Highlight] dark:forced-colors:group-data-disabled:[--checkbox-check:Highlight]"
759
- ];
760
- const colors = {
761
- "dark/zinc": [
762
- "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-zinc-900)] [--checkbox-checked-border:var(--color-zinc-950)]/90",
763
- "dark:[--checkbox-checked-bg:var(--color-zinc-600)]"
764
- ],
765
- "dark/white": [
766
- "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-zinc-900)] [--checkbox-checked-border:var(--color-zinc-950)]/90",
767
- "dark:[--checkbox-check:var(--color-zinc-900)] dark:[--checkbox-checked-bg:var(--color-white)] dark:[--checkbox-checked-border:var(--color-zinc-950)]/15"
768
- ],
769
- white: "[--checkbox-check:var(--color-zinc-900)] [--checkbox-checked-bg:var(--color-white)] [--checkbox-checked-border:var(--color-zinc-950)]/15",
770
- dark: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-zinc-900)] [--checkbox-checked-border:var(--color-zinc-950)]/90",
771
- zinc: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-zinc-600)] [--checkbox-checked-border:var(--color-zinc-700)]/90",
772
- red: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-red-600)] [--checkbox-checked-border:var(--color-red-700)]/90",
773
- orange: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-orange-500)] [--checkbox-checked-border:var(--color-orange-600)]/90",
774
- amber: "[--checkbox-check:var(--color-amber-950)] [--checkbox-checked-bg:var(--color-amber-400)] [--checkbox-checked-border:var(--color-amber-500)]/80",
775
- yellow: "[--checkbox-check:var(--color-yellow-950)] [--checkbox-checked-bg:var(--color-yellow-300)] [--checkbox-checked-border:var(--color-yellow-400)]/80",
776
- lime: "[--checkbox-check:var(--color-lime-950)] [--checkbox-checked-bg:var(--color-lime-300)] [--checkbox-checked-border:var(--color-lime-400)]/80",
777
- green: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-green-600)] [--checkbox-checked-border:var(--color-green-700)]/90",
778
- emerald: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-emerald-600)] [--checkbox-checked-border:var(--color-emerald-700)]/90",
779
- teal: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-teal-600)] [--checkbox-checked-border:var(--color-teal-700)]/90",
780
- cyan: "[--checkbox-check:var(--color-cyan-950)] [--checkbox-checked-bg:var(--color-cyan-300)] [--checkbox-checked-border:var(--color-cyan-400)]/80",
781
- sky: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-sky-500)] [--checkbox-checked-border:var(--color-sky-600)]/80",
782
- blue: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-blue-600)] [--checkbox-checked-border:var(--color-blue-700)]/90",
783
- indigo: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-indigo-500)] [--checkbox-checked-border:var(--color-indigo-600)]/90",
784
- violet: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-violet-500)] [--checkbox-checked-border:var(--color-violet-600)]/90",
785
- purple: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-purple-500)] [--checkbox-checked-border:var(--color-purple-600)]/90",
786
- fuchsia: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-fuchsia-500)] [--checkbox-checked-border:var(--color-fuchsia-600)]/90",
787
- pink: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-pink-500)] [--checkbox-checked-border:var(--color-pink-600)]/90",
788
- rose: "[--checkbox-check:var(--color-white)] [--checkbox-checked-bg:var(--color-rose-500)] [--checkbox-checked-border:var(--color-rose-600)]/90"
789
- };
790
- function Checkbox({
791
- color = "dark/zinc",
792
- className,
793
- checked: controlledChecked,
794
- defaultChecked,
795
- onChange,
796
- disabled,
797
- indeterminate,
798
- name,
799
- value,
800
- ...props
801
- }) {
802
- const { checked, toggleProps } = useToggle({
803
- checked: controlledChecked,
804
- defaultChecked,
805
- onChange,
806
- disabled
807
- });
808
- const interactiveProps = useDataInteractive({ disabled });
809
- const handleKeyDown = useCallback(
810
- (e) => {
811
- if (e.key === " ") {
812
- e.preventDefault();
813
- toggleProps.onKeyDown(e);
814
- }
815
- },
816
- [toggleProps]
817
- );
818
- return /* @__PURE__ */ jsxs(
819
- "span",
820
- {
821
- "data-slot": "control",
822
- role: "checkbox",
823
- "aria-checked": indeterminate ? "mixed" : checked,
824
- "data-checked": checked ? "" : void 0,
825
- "data-indeterminate": indeterminate ? "" : void 0,
826
- "data-disabled": disabled ? "" : void 0,
827
- tabIndex: disabled ? void 0 : 0,
828
- onClick: disabled ? void 0 : toggleProps.onClick,
829
- onKeyDown: disabled ? void 0 : handleKeyDown,
830
- ...interactiveProps,
831
- ...props,
832
- className: clsx(className, "group inline-flex focus:outline-hidden"),
833
- children: [
834
- name && /* @__PURE__ */ jsx("input", { type: "hidden", name, value: checked ? value ?? "on" : "" }),
835
- /* @__PURE__ */ jsx("span", { className: clsx([base, colors[color]]), children: /* @__PURE__ */ jsxs(
836
- "svg",
837
- {
838
- className: "size-4 stroke-(--checkbox-check) opacity-0 group-data-checked:opacity-100 sm:h-3.5 sm:w-3.5",
839
- viewBox: "0 0 14 14",
840
- fill: "none",
841
- children: [
842
- /* @__PURE__ */ jsx("title", { children: "Checkmark" }),
843
- /* @__PURE__ */ jsx(
844
- "path",
845
- {
846
- className: "opacity-100 group-data-indeterminate:opacity-0",
847
- d: "M3 8L6 11L11 3.5",
848
- strokeWidth: 2,
849
- strokeLinecap: "round",
850
- strokeLinejoin: "round"
851
- }
852
- ),
853
- /* @__PURE__ */ jsx(
854
- "path",
855
- {
856
- className: "opacity-0 group-data-indeterminate:opacity-100",
857
- d: "M3 7H11",
858
- strokeWidth: 2,
859
- strokeLinecap: "round",
860
- strokeLinejoin: "round"
861
- }
862
- )
863
- ]
864
- }
865
- ) })
866
- ]
867
- }
868
- );
869
- }
870
- function CodeBlock({
871
- code,
872
- language,
873
- filename,
874
- showCopy = true,
875
- className
876
- }) {
877
- const [copied, setCopied] = useState(false);
878
- const handleCopy = useCallback(async () => {
879
- await navigator.clipboard.writeText(code);
880
- setCopied(true);
881
- setTimeout(() => setCopied(false), 2e3);
882
- }, [code]);
883
- return /* @__PURE__ */ jsxs("div", { className: clsx("overflow-hidden rounded-xl bg-zinc-950 ring-1 ring-zinc-800", className), children: [
884
- (filename || language || showCopy) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b border-zinc-800 px-4 py-2.5", children: [
885
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
886
- filename && /* @__PURE__ */ jsx("span", { className: "text-xs text-zinc-400", children: filename }),
887
- language && !filename && /* @__PURE__ */ jsx("span", { className: "rounded bg-zinc-800 px-1.5 py-0.5 text-xs text-zinc-400", children: language })
888
- ] }),
889
- showCopy && /* @__PURE__ */ jsx(
890
- "button",
891
- {
892
- type: "button",
893
- onClick: handleCopy,
894
- "aria-label": copied ? "Copied" : "Copy code",
895
- className: "rounded px-2 py-1 text-xs text-zinc-400 transition-colors hover:bg-zinc-800 hover:text-zinc-200 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500",
896
- children: copied ? "Copied!" : "Copy"
897
- }
898
- )
899
- ] }),
900
- /* @__PURE__ */ jsx("pre", { className: "overflow-x-auto p-4 text-sm leading-relaxed text-zinc-300", children: /* @__PURE__ */ jsx("code", { children: code }) })
901
- ] });
902
- }
903
- function useEscapeKey(onEscape, enabled = true) {
904
- const callbackRef = useRef(onEscape);
905
- callbackRef.current = onEscape;
906
- useEffect(() => {
907
- if (!enabled) return;
908
- function handleKeyDown(e) {
909
- if (e.key === "Escape") {
910
- e.stopPropagation();
911
- callbackRef.current();
912
- }
913
- }
914
- document.addEventListener("keydown", handleKeyDown);
915
- return () => document.removeEventListener("keydown", handleKeyDown);
916
- }, [enabled]);
917
- }
918
- const FOCUSABLE_SELECTOR = [
919
- "a[href]",
920
- "button:not([disabled])",
921
- 'input:not([disabled]):not([type="hidden"])',
922
- "textarea:not([disabled])",
923
- "select:not([disabled])",
924
- '[tabindex]:not([tabindex="-1"])'
925
- ].join(", ");
926
- function getFocusableElements(container) {
927
- return Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR));
928
- }
929
- function useFocusTrap(containerRef, enabled = true) {
930
- useEffect(() => {
931
- if (!enabled) return;
932
- const container = containerRef.current;
933
- if (!container) return;
934
- const previouslyFocused = document.activeElement;
935
- const focusableElements = getFocusableElements(container);
936
- if (focusableElements.length > 0) {
937
- focusableElements[0]?.focus();
938
- } else {
939
- container.setAttribute("tabindex", "-1");
940
- container.focus();
941
- }
942
- function handleKeyDown(e) {
943
- if (e.key !== "Tab" || !container) return;
944
- const focusable = getFocusableElements(container);
945
- if (focusable.length === 0) {
946
- e.preventDefault();
947
- return;
948
- }
949
- const first = focusable[0];
950
- const last = focusable[focusable.length - 1];
951
- if (e.shiftKey && document.activeElement === first) {
952
- e.preventDefault();
953
- last?.focus();
954
- } else if (!e.shiftKey && document.activeElement === last) {
955
- e.preventDefault();
956
- first?.focus();
957
- }
958
- }
959
- document.addEventListener("keydown", handleKeyDown, true);
960
- return () => {
961
- document.removeEventListener("keydown", handleKeyDown, true);
962
- previouslyFocused?.focus();
963
- };
964
- }, [containerRef, enabled]);
965
- }
966
- function useScrollLock(enabled = true) {
967
- useEffect(() => {
968
- if (!enabled) return;
969
- const originalOverflow = document.body.style.overflow;
970
- const originalPaddingRight = document.body.style.paddingRight;
971
- const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
972
- document.body.style.overflow = "hidden";
973
- if (scrollbarWidth > 0) {
974
- document.body.style.paddingRight = `${scrollbarWidth}px`;
975
- }
976
- return () => {
977
- document.body.style.overflow = originalOverflow;
978
- document.body.style.paddingRight = originalPaddingRight;
979
- };
980
- }, [enabled]);
981
- }
982
- function useTransition(show) {
983
- const nodeRef = useRef(null);
984
- const [, setTick] = useState(0);
985
- const rerender = useCallback(() => setTick((t) => t + 1), []);
986
- const phase = useRef(
987
- show ? "visible" : "hidden"
988
- );
989
- const prevShow = useRef(show);
990
- const cleanupRef = useRef(null);
991
- useEffect(() => {
992
- cleanupRef.current?.();
993
- cleanupRef.current = null;
994
- if (show && !prevShow.current) {
995
- phase.current = "enter-from";
996
- rerender();
997
- const frame1 = requestAnimationFrame(() => {
998
- const frame2 = requestAnimationFrame(() => {
999
- if (phase.current !== "enter-from") return;
1000
- phase.current = "enter-to";
1001
- rerender();
1002
- const node = nodeRef.current;
1003
- if (!node) {
1004
- phase.current = "visible";
1005
- rerender();
1006
- return;
1007
- }
1008
- let cleaned = false;
1009
- const done = () => {
1010
- if (cleaned) return;
1011
- cleaned = true;
1012
- phase.current = "visible";
1013
- rerender();
1014
- };
1015
- node.addEventListener("transitionend", done, { once: true });
1016
- const fallback = setTimeout(done, 500);
1017
- cleanupRef.current = () => {
1018
- cleaned = true;
1019
- node.removeEventListener("transitionend", done);
1020
- clearTimeout(fallback);
1021
- };
1022
- });
1023
- cleanupRef.current = () => cancelAnimationFrame(frame2);
1024
- });
1025
- cleanupRef.current = () => cancelAnimationFrame(frame1);
1026
- } else if (!show && prevShow.current) {
1027
- phase.current = "leave";
1028
- rerender();
1029
- const node = nodeRef.current;
1030
- if (!node) {
1031
- phase.current = "hidden";
1032
- rerender();
1033
- prevShow.current = show;
1034
- return;
1035
- }
1036
- let cleaned = false;
1037
- const done = () => {
1038
- if (cleaned) return;
1039
- cleaned = true;
1040
- phase.current = "hidden";
1041
- rerender();
1042
- };
1043
- node.addEventListener("transitionend", done, { once: true });
1044
- const fallback = setTimeout(done, 500);
1045
- cleanupRef.current = () => {
1046
- cleaned = true;
1047
- node.removeEventListener("transitionend", done);
1048
- clearTimeout(fallback);
1049
- };
1050
- }
1051
- prevShow.current = show;
1052
- }, [show, rerender]);
1053
- useEffect(() => {
1054
- return () => {
1055
- cleanupRef.current?.();
1056
- };
1057
- }, []);
1058
- const p = phase.current;
1059
- return {
1060
- mounted: p !== "hidden",
1061
- nodeRef,
1062
- transitionProps: {
1063
- "data-closed": p === "enter-from" || p === "leave" || p === "hidden" ? "" : void 0,
1064
- "data-enter": p === "enter-from" || p === "enter-to" ? "" : void 0,
1065
- "data-leave": p === "leave" ? "" : void 0,
1066
- "data-transition": p === "enter-from" || p === "enter-to" || p === "leave" ? "" : void 0
1067
- }
1068
- };
1069
- }
1070
- const sideClasses$1 = {
1071
- left: "inset-y-0 left-0 h-full w-full max-w-sm data-closed:-translate-x-full",
1072
- right: "inset-y-0 right-0 h-full w-full max-w-sm data-closed:translate-x-full",
1073
- top: "inset-x-0 top-0 w-full max-h-[50vh] data-closed:-translate-y-full",
1074
- bottom: "inset-x-0 bottom-0 w-full max-h-[50vh] data-closed:translate-y-full"
1075
- };
1076
- function Drawer({
1077
- open,
1078
- onClose,
1079
- side = "right",
1080
- className,
1081
- children
1082
- }) {
1083
- const panelRef = useRef(null);
1084
- const titleId = useId();
1085
- const backdrop = useTransition(open);
1086
- const panel = useTransition(open);
1087
- useScrollLock(open);
1088
- useFocusTrap(panelRef, open);
1089
- useEscapeKey(onClose, open);
1090
- const handleBackdropClick = useCallback(
1091
- (e) => {
1092
- if (e.target === e.currentTarget) onClose();
1093
- },
1094
- [onClose]
1095
- );
1096
- if (!(backdrop.mounted || panel.mounted)) return null;
1097
- return createPortal(
1098
- /* @__PURE__ */ jsxs("div", { role: "dialog", "aria-modal": "true", "aria-labelledby": titleId, children: [
1099
- backdrop.mounted && /* @__PURE__ */ jsx(
1100
- "div",
1101
- {
1102
- ref: backdrop.nodeRef,
1103
- ...backdrop.transitionProps,
1104
- onClick: handleBackdropClick,
1105
- className: "fixed inset-0 z-40 bg-zinc-950/25 transition duration-200 data-closed:opacity-0 data-enter:ease-out data-leave:ease-in dark:bg-zinc-950/50"
1106
- }
1107
- ),
1108
- panel.mounted && /* @__PURE__ */ jsx(
1109
- "div",
1110
- {
1111
- ref: (node) => {
1112
- panelRef.current = node;
1113
- panel.nodeRef.current = node;
1114
- },
1115
- ...panel.transitionProps,
1116
- className: clsx(
1117
- "fixed z-50 overflow-y-auto bg-white shadow-xl ring-1 ring-zinc-950/10 transition duration-300 ease-in-out dark:bg-zinc-900 dark:ring-white/10",
1118
- sideClasses$1[side],
1119
- className
1120
- ),
1121
- children
1122
- }
1123
- )
1124
- ] }),
1125
- document.body
1126
- );
1127
- }
1128
- function DrawerHeader({
1129
- onClose,
1130
- className,
1131
- children
1132
- }) {
1133
- return /* @__PURE__ */ jsxs(
1134
- "div",
1135
- {
1136
- className: clsx(
1137
- "flex items-center justify-between border-b border-zinc-200 px-6 py-4 dark:border-zinc-700",
1138
- className
1139
- ),
1140
- children: [
1141
- /* @__PURE__ */ jsx("div", { className: "text-base font-semibold text-zinc-950 dark:text-white", children }),
1142
- onClose && /* @__PURE__ */ jsx(
1143
- "button",
1144
- {
1145
- type: "button",
1146
- "aria-label": "Close drawer",
1147
- onClick: onClose,
1148
- className: "rounded-md p-1 text-zinc-400 hover:text-zinc-600 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500 dark:hover:text-zinc-200",
1149
- children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 16 16", fill: "none", className: "size-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx(
1150
- "path",
1151
- {
1152
- d: "M4 4l8 8M12 4l-8 8",
1153
- stroke: "currentColor",
1154
- strokeWidth: "1.5",
1155
- strokeLinecap: "round"
1156
- }
1157
- ) })
1158
- }
1159
- )
1160
- ]
1161
- }
1162
- );
1163
- }
1164
- function DrawerBody({ className, ...props }) {
1165
- return /* @__PURE__ */ jsx("div", { ...props, className: clsx("px-6 py-4", className) });
1166
- }
1167
- function DrawerFooter({ className, ...props }) {
1168
- return /* @__PURE__ */ jsx(
1169
- "div",
1170
- {
1171
- ...props,
1172
- className: clsx(
1173
- "flex items-center justify-end gap-3 border-t border-zinc-200 px-6 py-4 dark:border-zinc-700",
1174
- className
1175
- )
1176
- }
1177
- );
1178
- }
1179
- function EmptyState({
1180
- icon,
1181
- title,
1182
- description,
1183
- action,
1184
- className
1185
- }) {
1186
- return /* @__PURE__ */ jsxs(
1187
- "div",
1188
- {
1189
- className: clsx(
1190
- "flex flex-col items-center justify-center rounded-xl border border-dashed border-zinc-300 px-6 py-16 text-center dark:border-zinc-700",
1191
- className
1192
- ),
1193
- children: [
1194
- icon && /* @__PURE__ */ jsx("div", { className: "mb-4 flex size-12 items-center justify-center rounded-full bg-zinc-100 text-zinc-500 dark:bg-zinc-800 dark:text-zinc-400", children: icon }),
1195
- /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-zinc-950 dark:text-white", children: title }),
1196
- description && /* @__PURE__ */ jsx("p", { className: "mt-1 max-w-sm text-sm text-zinc-500 dark:text-zinc-400", children: description }),
1197
- action && /* @__PURE__ */ jsx("div", { className: "mt-6", children: action })
1198
- ]
1199
- }
1200
- );
1201
- }
1202
- function InputGroup({ children }) {
1203
- return /* @__PURE__ */ jsx(
1204
- "span",
1205
- {
1206
- "data-slot": "control",
1207
- className: clsx(
1208
- "relative isolate block",
1209
- "has-[[data-slot=icon]:first-child]:[&_input]:pl-10 has-[[data-slot=icon]:last-child]:[&_input]:pr-10 sm:has-[[data-slot=icon]:first-child]:[&_input]:pl-8 sm:has-[[data-slot=icon]:last-child]:[&_input]:pr-8",
1210
- "*:data-[slot=icon]:pointer-events-none *:data-[slot=icon]:absolute *:data-[slot=icon]:top-3 *:data-[slot=icon]:z-10 *:data-[slot=icon]:size-5 sm:*:data-[slot=icon]:top-2.5 sm:*:data-[slot=icon]:size-4",
1211
- "[&>[data-slot=icon]:first-child]:left-3 sm:[&>[data-slot=icon]:first-child]:left-2.5 [&>[data-slot=icon]:last-child]:right-3 sm:[&>[data-slot=icon]:last-child]:right-2.5",
1212
- "*:data-[slot=icon]:text-zinc-500 dark:*:data-[slot=icon]:text-zinc-400"
1213
- ),
1214
- children
1215
- }
1216
- );
1217
- }
1218
- const dateTypes = ["date", "datetime-local", "month", "time", "week"];
1219
- const Input = forwardRef(function Input2({ className, disabled, invalid, ...props }, ref) {
1220
- const interactiveProps = useDataInteractive({ disabled });
1221
- const fieldProps = useFieldControlProps();
1222
- return /* @__PURE__ */ jsx(
1223
- "span",
1224
- {
1225
- "data-slot": "control",
1226
- className: clsx([
1227
- className,
1228
- // Basic layout
1229
- "relative block w-full",
1230
- // Background color + shadow applied to inset pseudo element, so shadow blends with border in light mode
1231
- "before:absolute before:inset-px before:rounded-[calc(var(--radius-lg)-1px)] before:bg-white before:shadow-sm",
1232
- // Background color is moved to control and shadow is removed in dark mode so hide `before` pseudo
1233
- "dark:before:hidden",
1234
- // Focus ring
1235
- "after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:ring-transparent after:ring-inset sm:focus-within:after:ring-2 sm:focus-within:after:ring-blue-500",
1236
- // Disabled state
1237
- "has-data-disabled:opacity-50 has-data-disabled:before:bg-zinc-950/5 has-data-disabled:before:shadow-none"
1238
- ]),
1239
- children: /* @__PURE__ */ jsx(
1240
- "input",
1241
- {
1242
- ref,
1243
- disabled,
1244
- ...props,
1245
- ...interactiveProps,
1246
- ...fieldProps,
1247
- "data-invalid": invalid ? "" : void 0,
1248
- "data-disabled": disabled ? "" : void 0,
1249
- className: clsx([
1250
- // Date classes
1251
- props.type && dateTypes.includes(props.type) && [
1252
- "[&::-webkit-datetime-edit-fields-wrapper]:p-0",
1253
- "[&::-webkit-date-and-time-value]:min-h-[1.5em]",
1254
- "[&::-webkit-datetime-edit]:inline-flex",
1255
- "[&::-webkit-datetime-edit]:p-0",
1256
- "[&::-webkit-datetime-edit-year-field]:p-0",
1257
- "[&::-webkit-datetime-edit-month-field]:p-0",
1258
- "[&::-webkit-datetime-edit-day-field]:p-0",
1259
- "[&::-webkit-datetime-edit-hour-field]:p-0",
1260
- "[&::-webkit-datetime-edit-minute-field]:p-0",
1261
- "[&::-webkit-datetime-edit-second-field]:p-0",
1262
- "[&::-webkit-datetime-edit-millisecond-field]:p-0",
1263
- "[&::-webkit-datetime-edit-meridiem-field]:p-0"
1264
- ],
1265
- // Basic layout
1266
- "relative block w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)]",
1267
- // Typography
1268
- "text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 dark:text-white",
1269
- // Border
1270
- "border border-zinc-950/10 data-hover:border-zinc-950/20 dark:border-white/10 dark:data-hover:border-white/20",
1271
- // Background color
1272
- "bg-transparent dark:bg-white/5",
1273
- // Hide default focus styles
1274
- "focus:outline-hidden",
1275
- // Invalid state
1276
- "data-invalid:border-red-500 data-invalid:data-hover:border-red-500 dark:data-invalid:border-red-600 dark:data-invalid:data-hover:border-red-600",
1277
- // Disabled state
1278
- "data-disabled:border-zinc-950/20 dark:data-disabled:border-white/15 dark:data-disabled:bg-white/2.5 dark:data-hover:data-disabled:border-white/15",
1279
- // System icons
1280
- "dark:scheme-dark"
1281
- ])
1282
- }
1283
- )
1284
- }
1285
- );
1286
- });
1287
- function Kbd({ className, children, ...props }) {
1288
- return /* @__PURE__ */ jsx(
1289
- "kbd",
1290
- {
1291
- ...props,
1292
- className: clsx(
1293
- "inline-flex items-center rounded border border-zinc-300 bg-zinc-100 px-1.5 py-0.5 font-mono text-xs font-medium text-zinc-700 dark:border-zinc-600 dark:bg-zinc-800 dark:text-zinc-300",
1294
- className
1295
- ),
1296
- children
1297
- }
1298
- );
1299
- }
1300
- function KbdShortcut({
1301
- keys,
1302
- separator = "+",
1303
- className
1304
- }) {
1305
- return /* @__PURE__ */ jsx("span", { className: clsx("inline-flex items-center gap-1", className), children: keys.map((key, i) => (
1306
- // biome-ignore lint/suspicious/noArrayIndexKey: keyboard shortcut keys are positionally ordered with no stable ID
1307
- /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
1308
- /* @__PURE__ */ jsx(Kbd, { children: key }),
1309
- i < keys.length - 1 && /* @__PURE__ */ jsx("span", { className: "text-xs text-zinc-400", children: separator })
1310
- ] }, i)
1311
- )) });
1312
- }
1313
- const trackClasses = {
1314
- blue: "bg-blue-600 dark:bg-blue-500",
1315
- green: "bg-green-600 dark:bg-green-500",
1316
- red: "bg-red-600 dark:bg-red-500",
1317
- amber: "bg-amber-500 dark:bg-amber-400",
1318
- violet: "bg-violet-600 dark:bg-violet-500",
1319
- zinc: "bg-zinc-600 dark:bg-zinc-400"
1320
- };
1321
- function Progress({
1322
- value,
1323
- max = 100,
1324
- color = "blue",
1325
- size = "md",
1326
- label,
1327
- showValue = false,
1328
- className
1329
- }) {
1330
- const percentage = Math.min(100, Math.max(0, value / max * 100));
1331
- const heightClass = { xs: "h-1", sm: "h-1.5", md: "h-2.5", lg: "h-4" }[size];
1332
- return /* @__PURE__ */ jsxs("div", { className: clsx("w-full", className), children: [
1333
- (label || showValue) && /* @__PURE__ */ jsxs("div", { className: "mb-1.5 flex items-center justify-between", children: [
1334
- label && /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: label }),
1335
- showValue && /* @__PURE__ */ jsxs("span", { className: "text-sm text-zinc-500 dark:text-zinc-400", children: [
1336
- Math.round(percentage),
1337
- "%"
1338
- ] })
1339
- ] }),
1340
- /* @__PURE__ */ jsx(
1341
- "div",
1342
- {
1343
- role: "progressbar",
1344
- "aria-valuenow": value,
1345
- "aria-valuemin": 0,
1346
- "aria-valuemax": max,
1347
- "aria-label": label,
1348
- className: clsx(
1349
- "w-full overflow-hidden rounded-full bg-zinc-200 dark:bg-zinc-700",
1350
- heightClass
1351
- ),
1352
- children: /* @__PURE__ */ jsx(
1353
- "div",
1354
- {
1355
- className: clsx(
1356
- "h-full rounded-full transition-all duration-300 ease-in-out",
1357
- trackClasses[color]
1358
- ),
1359
- style: { width: `${percentage}%` }
1360
- }
1361
- )
1362
- }
1363
- )
1364
- ] });
1365
- }
1366
- function Rating({
1367
- value: controlledValue,
1368
- defaultValue = 0,
1369
- max = 5,
1370
- onChange,
1371
- readOnly = false,
1372
- size = "md",
1373
- label,
1374
- className
1375
- }) {
1376
- const [internalValue, setInternalValue] = useState(defaultValue);
1377
- const [hovered, setHovered] = useState(0);
1378
- const id = useId();
1379
- const value = controlledValue ?? internalValue;
1380
- const sizeClass = { sm: "size-4", md: "size-6", lg: "size-8" }[size];
1381
- const handleClick = useCallback(
1382
- (star) => {
1383
- if (readOnly) return;
1384
- setInternalValue(star);
1385
- onChange?.(star);
1386
- },
1387
- [readOnly, onChange]
1388
- );
1389
- const display = hovered > 0 ? hovered : value;
1390
- return /* @__PURE__ */ jsxs("div", { className, children: [
1391
- label && /* @__PURE__ */ jsx("span", { id, className: "sr-only", children: label }),
1392
- /* @__PURE__ */ jsx(
1393
- "div",
1394
- {
1395
- role: readOnly ? "img" : "radiogroup",
1396
- "aria-label": label ?? `Rating: ${value} out of ${max}`,
1397
- "aria-labelledby": label ? id : void 0,
1398
- className: "flex items-center gap-0.5",
1399
- children: Array.from({ length: max }).map((_, i) => {
1400
- const star = i + 1;
1401
- const filled = star <= display;
1402
- return (
1403
- // biome-ignore lint/a11y/useAriaPropsSupportedByRole: aria-checked and aria-label are valid on role="radio" per WAI-ARIA spec
1404
- /* @__PURE__ */ jsx(
1405
- "button",
1406
- {
1407
- type: "button",
1408
- role: readOnly ? void 0 : "radio",
1409
- "aria-checked": readOnly ? void 0 : value === star,
1410
- "aria-label": readOnly ? void 0 : `${star} star${star !== 1 ? "s" : ""}`,
1411
- disabled: readOnly,
1412
- onClick: () => handleClick(star),
1413
- onMouseEnter: () => !readOnly && setHovered(star),
1414
- onMouseLeave: () => !readOnly && setHovered(0),
1415
- className: clsx(
1416
- sizeClass,
1417
- "transition-colors",
1418
- readOnly ? "cursor-default" : "cursor-pointer focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500"
1419
- ),
1420
- children: /* @__PURE__ */ jsx(
1421
- "svg",
1422
- {
1423
- viewBox: "0 0 20 20",
1424
- "aria-hidden": "true",
1425
- className: clsx(
1426
- "size-full",
1427
- filled ? "fill-amber-400 text-amber-400" : "fill-zinc-200 text-zinc-200 dark:fill-zinc-700 dark:text-zinc-700"
1428
- ),
1429
- children: /* @__PURE__ */ jsx("path", { d: "M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z" })
1430
- }
1431
- )
1432
- },
1433
- star
1434
- )
1435
- );
1436
- })
1437
- }
1438
- )
1439
- ] });
1440
- }
1441
- const Check = ({ className }) => {
1442
- return /* @__PURE__ */ jsxs(
1443
- "svg",
1444
- {
1445
- xmlns: "http://www.w3.org/2000/svg",
1446
- fill: "none",
1447
- viewBox: "0 0 24 24",
1448
- strokeWidth: 1.5,
1449
- stroke: "currentColor",
1450
- className: cn("size-6", className),
1451
- children: [
1452
- /* @__PURE__ */ jsx("title", { children: "Selected" }),
1453
- /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M6 12l4 4L18 8" })
1454
- ]
1455
- }
1456
- );
1457
- };
1458
- const ChevronUp = ({ className }) => {
1459
- return /* @__PURE__ */ jsxs(
1460
- "svg",
1461
- {
1462
- xmlns: "http://www.w3.org/2000/svg",
1463
- fill: "none",
1464
- viewBox: "0 0 24 24",
1465
- strokeWidth: 1.5,
1466
- stroke: "currentColor",
1467
- className: cn("size-6", className),
1468
- children: [
1469
- /* @__PURE__ */ jsx("title", { children: "Scroll up" }),
1470
- /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19.5 15.75l-7.5-7.5-7.5 7.5" })
1471
- ]
1472
- }
1473
- );
1474
- };
1475
- const ChevronDown = ({ className }) => {
1476
- return /* @__PURE__ */ jsxs(
1477
- "svg",
1478
- {
1479
- xmlns: "http://www.w3.org/2000/svg",
1480
- fill: "none",
1481
- viewBox: "0 0 24 24",
1482
- strokeWidth: 1.5,
1483
- stroke: "currentColor",
1484
- className: cn("size-6", className),
1485
- children: [
1486
- /* @__PURE__ */ jsx("title", { children: "Scroll down" }),
1487
- /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4.5 8.25l7.5 7.5 7.5-7.5" })
1488
- ]
1489
- }
1490
- );
1491
- };
1492
- const Select$1 = React__default.forwardRef(
1493
- ({ children, className, ...props }, ref) => /* @__PURE__ */ jsx(Box, { ref, className: cn(className), ...props, children })
1494
- );
1495
- Select$1.displayName = "Select";
1496
- const SelectGroup = React__default.forwardRef(
1497
- ({ children, className, ...props }, ref) => /* @__PURE__ */ jsx(Box, { ref, className: cn(className), ...props, children })
1498
- );
1499
- SelectGroup.displayName = "SelectGroup";
1500
- const SelectValue = React__default.forwardRef(
1501
- ({ placeholder, children, value, ...props }, ref) => /* @__PURE__ */ jsx("span", { ref, ...props, children: children || placeholder || value })
1502
- );
1503
- SelectValue.displayName = "SelectValue";
1504
- const SelectTrigger = React__default.forwardRef(
1505
- ({ children, className, ...props }, ref) => /* @__PURE__ */ jsxs(
1506
- Box,
1507
- {
1508
- className: cn(
1509
- "flex h-10 w-full items-center justify-between rounded border border-input bg-background px-3 py-2 text-inherit ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
1510
- className
1511
- ),
1512
- ref,
1513
- ...props,
1514
- children: [
1515
- children,
1516
- /* @__PURE__ */ jsx(ChevronDown, { className: "size-4 opacity-50" })
1517
- ]
1518
- }
1519
- )
1520
- );
1521
- SelectTrigger.displayName = "SelectTrigger";
1522
- const SelectScrollUpButton = React__default.forwardRef(
1523
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1524
- "button",
1525
- {
1526
- className: cn("flex cursor-default items-center justify-center py-1", className),
1527
- ref,
1528
- ...props,
1529
- children: /* @__PURE__ */ jsx(ChevronUp, { className: "size-4" })
1530
- }
1531
- )
1532
- );
1533
- SelectScrollUpButton.displayName = "SelectScrollUpButton";
1534
- const SelectScrollDownButton = React__default.forwardRef(
1535
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
1536
- "button",
1537
- {
1538
- className: cn("flex cursor-default items-center justify-center py-1", className),
1539
- ref,
1540
- ...props,
1541
- children: /* @__PURE__ */ jsx(ChevronDown, { className: "size-4" })
1542
- }
1543
- )
1544
- );
1545
- SelectScrollDownButton.displayName = "SelectScrollDownButton";
1546
- const SelectContent = React__default.forwardRef(
1547
- ({ children, className, ...props }, ref) => /* @__PURE__ */ jsxs(
1548
- Box,
1549
- {
1550
- className: cn(
1551
- "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded border bg-card text-popover-foreground shadow-md",
1552
- className
1553
- ),
1554
- ref,
1555
- ...props,
1556
- children: [
1557
- /* @__PURE__ */ jsx(SelectScrollUpButton, {}),
1558
- /* @__PURE__ */ jsx("div", { className: "p-1", children }),
1559
- /* @__PURE__ */ jsx(SelectScrollDownButton, {})
1560
- ]
1561
- }
1562
- )
1563
- );
1564
- SelectContent.displayName = "SelectContent";
1565
- const SelectLabel = React__default.forwardRef(
1566
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { className: cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className), ref, ...props })
1567
- );
1568
- SelectLabel.displayName = "SelectLabel";
1569
- const SelectItem = React__default.forwardRef(
1570
- ({ children, className, value, ...props }, ref) => /* @__PURE__ */ jsxs(
1571
- Box,
1572
- {
1573
- className: cn(
1574
- "relative flex w-full cursor-default select-none items-center rounded py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
1575
- className
1576
- ),
1577
- "data-value": value,
1578
- ref,
1579
- ...props,
1580
- children: [
1581
- /* @__PURE__ */ jsx("span", { className: "absolute left-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ jsx(Check, { className: "size-4" }) }),
1582
- /* @__PURE__ */ jsx("span", { children })
1583
- ]
1584
- }
1585
- )
1586
- );
1587
- SelectItem.displayName = "SelectItem";
1588
- const SelectSeparator = React__default.forwardRef(
1589
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(Box, { className: cn("-mx-1 my-1 h-px bg-muted", className), ref, ...props })
1590
- );
1591
- SelectSeparator.displayName = "SelectSeparator";
1592
- const Select = forwardRef(function Select2({ className, multiple, disabled, invalid, ...props }, ref) {
1593
- const interactiveProps = useDataInteractive({ disabled });
1594
- const fieldProps = useFieldControlProps();
1595
- return /* @__PURE__ */ jsxs(
1596
- "span",
1597
- {
1598
- "data-slot": "control",
1599
- className: clsx([
1600
- className,
1601
- // Basic layout
1602
- "group relative block w-full",
1603
- // Background color + shadow applied to inset pseudo element, so shadow blends with border in light mode
1604
- "before:absolute before:inset-px before:rounded-[calc(var(--radius-lg)-1px)] before:bg-white before:shadow-sm",
1605
- // Background color is moved to control and shadow is removed in dark mode so hide `before` pseudo
1606
- "dark:before:hidden",
1607
- // Focus ring
1608
- "after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:ring-transparent after:ring-inset has-data-focus:after:ring-2 has-data-focus:after:ring-blue-500",
1609
- // Disabled state
1610
- "has-data-disabled:opacity-50 has-data-disabled:before:bg-zinc-950/5 has-data-disabled:before:shadow-none"
1611
- ]),
1612
- children: [
1613
- /* @__PURE__ */ jsx(
1614
- "select",
1615
- {
1616
- ref,
1617
- multiple,
1618
- disabled,
1619
- ...props,
1620
- ...interactiveProps,
1621
- ...fieldProps,
1622
- "data-invalid": invalid ? "" : void 0,
1623
- "data-disabled": disabled ? "" : void 0,
1624
- className: clsx([
1625
- // Basic layout
1626
- "relative block w-full appearance-none rounded-lg py-[calc(--spacing(2.5)-1px)] sm:py-[calc(--spacing(1.5)-1px)]",
1627
- // Horizontal padding
1628
- multiple ? "px-[calc(--spacing(3.5)-1px)] sm:px-[calc(--spacing(3)-1px)]" : "pr-[calc(--spacing(10)-1px)] pl-[calc(--spacing(3.5)-1px)] sm:pr-[calc(--spacing(9)-1px)] sm:pl-[calc(--spacing(3)-1px)]",
1629
- // Options (multi-select)
1630
- "[&_optgroup]:font-semibold",
1631
- // Typography
1632
- "text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 dark:text-white dark:*:text-white",
1633
- // Border
1634
- "border border-zinc-950/10 data-hover:border-zinc-950/20 dark:border-white/10 dark:data-hover:border-white/20",
1635
- // Background color
1636
- "bg-transparent dark:bg-white/5 dark:*:bg-zinc-800",
1637
- // Hide default focus styles
1638
- "focus:outline-hidden",
1639
- // Invalid state
1640
- "data-invalid:border-red-500 data-invalid:data-hover:border-red-500 dark:data-invalid:border-red-600 dark:data-invalid:data-hover:border-red-600",
1641
- // Disabled state
1642
- "data-disabled:border-zinc-950/20 data-disabled:opacity-100 dark:data-disabled:border-white/15 dark:data-disabled:bg-white/2.5 dark:data-hover:data-disabled:border-white/15"
1643
- ])
1644
- }
1645
- ),
1646
- !multiple && /* @__PURE__ */ jsx("span", { className: "pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2", children: /* @__PURE__ */ jsxs(
1647
- "svg",
1648
- {
1649
- className: "size-5 stroke-zinc-500 group-has-data-disabled:stroke-zinc-600 sm:size-4 dark:stroke-zinc-400 forced-colors:stroke-[CanvasText]",
1650
- viewBox: "0 0 16 16",
1651
- "aria-hidden": "true",
1652
- fill: "none",
1653
- children: [
1654
- /* @__PURE__ */ jsx(
1655
- "path",
1656
- {
1657
- d: "M5.75 10.75L8 13L10.25 10.75",
1658
- strokeWidth: 1.5,
1659
- strokeLinecap: "round",
1660
- strokeLinejoin: "round"
1661
- }
1662
- ),
1663
- /* @__PURE__ */ jsx(
1664
- "path",
1665
- {
1666
- d: "M10.25 5.25L8 3L5.75 5.25",
1667
- strokeWidth: 1.5,
1668
- strokeLinecap: "round",
1669
- strokeLinejoin: "round"
1670
- }
1671
- )
1672
- ]
1673
- }
1674
- ) })
1675
- ]
1676
- }
1677
- );
1678
- });
1679
- function Skeleton({ className, ...props }) {
1680
- return /* @__PURE__ */ jsx(
1681
- "div",
1682
- {
1683
- "aria-hidden": "true",
1684
- ...props,
1685
- className: clsx("animate-pulse rounded-md bg-zinc-200 dark:bg-zinc-700", className)
1686
- }
1687
- );
1688
- }
1689
- function SkeletonText({ lines = 3, className }) {
1690
- return /* @__PURE__ */ jsx("div", { className: clsx("space-y-2", className), children: Array.from({ length: lines }).map((_, i) => {
1691
- return /* @__PURE__ */ jsx(
1692
- Skeleton,
1693
- {
1694
- className: clsx("h-4", i === lines - 1 && lines > 1 ? "w-4/5" : "w-full")
1695
- },
1696
- i
1697
- );
1698
- }) });
1699
- }
1700
- function SkeletonCard({ className }) {
1701
- return /* @__PURE__ */ jsxs("div", { className: clsx("rounded-xl border border-zinc-200 p-4 dark:border-zinc-700", className), children: [
1702
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
1703
- /* @__PURE__ */ jsx(Skeleton, { className: "size-10 rounded-full" }),
1704
- /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-2", children: [
1705
- /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-1/3" }),
1706
- /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-1/2" })
1707
- ] })
1708
- ] }),
1709
- /* @__PURE__ */ jsx(SkeletonText, { lines: 3, className: "mt-4" })
1710
- ] });
1711
- }
1712
- function Slider({
1713
- value: controlledValue,
1714
- defaultValue = 0,
1715
- min = 0,
1716
- max = 100,
1717
- step = 1,
1718
- onChange,
1719
- disabled = false,
1720
- label,
1721
- showValue = false,
1722
- className
1723
- }) {
1724
- const [internalValue, setInternalValue] = useState(defaultValue);
1725
- const value = controlledValue ?? internalValue;
1726
- const id = useId();
1727
- const handleChange = useCallback(
1728
- (e) => {
1729
- const next = Number(e.target.value);
1730
- setInternalValue(next);
1731
- onChange?.(next);
1732
- },
1733
- [onChange]
1734
- );
1735
- const percentage = (value - min) / (max - min) * 100;
1736
- return /* @__PURE__ */ jsxs("div", { className: clsx("w-full", className), children: [
1737
- (label || showValue) && /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between", children: [
1738
- label && /* @__PURE__ */ jsx("label", { htmlFor: id, className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: label }),
1739
- showValue && /* @__PURE__ */ jsx("span", { className: "text-sm text-zinc-500 dark:text-zinc-400", children: value })
1740
- ] }),
1741
- /* @__PURE__ */ jsx(
1742
- "input",
1743
- {
1744
- id,
1745
- type: "range",
1746
- min,
1747
- max,
1748
- step,
1749
- value,
1750
- disabled,
1751
- onChange: handleChange,
1752
- style: { "--slider-pct": `${percentage}%` },
1753
- className: clsx(
1754
- "h-2 w-full cursor-pointer appearance-none rounded-full outline-none",
1755
- "bg-zinc-200 dark:bg-zinc-700",
1756
- "[&::-webkit-slider-thumb]:size-4 [&::-webkit-slider-thumb]:cursor-pointer [&::-webkit-slider-thumb]:appearance-none",
1757
- "[&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-blue-600 [&::-webkit-slider-thumb]:shadow-sm",
1758
- "[&::-webkit-slider-thumb]:ring-2 [&::-webkit-slider-thumb]:ring-white [&::-webkit-slider-thumb]:dark:ring-zinc-900",
1759
- "[&::-moz-range-thumb]:size-4 [&::-moz-range-thumb]:cursor-pointer [&::-moz-range-thumb]:appearance-none",
1760
- "[&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-none [&::-moz-range-thumb]:bg-blue-600",
1761
- "focus-visible:[&::-webkit-slider-thumb]:outline-2 focus-visible:[&::-webkit-slider-thumb]:outline-offset-2 focus-visible:[&::-webkit-slider-thumb]:outline-blue-500",
1762
- disabled && "cursor-not-allowed opacity-50"
1763
- )
1764
- }
1765
- )
1766
- ] });
1767
- }
1768
- function Stat({
1769
- label,
1770
- value,
1771
- change,
1772
- trend,
1773
- description,
1774
- icon,
1775
- className
1776
- }) {
1777
- const trendColor = {
1778
- up: "text-green-600 dark:text-green-400",
1779
- down: "text-red-600 dark:text-red-400",
1780
- neutral: "text-zinc-500 dark:text-zinc-400"
1781
- };
1782
- const trendArrow = { up: "↑", down: "↓", neutral: "→" };
1783
- return /* @__PURE__ */ jsxs(
1784
- "div",
1785
- {
1786
- className: clsx(
1787
- "rounded-xl bg-white p-6 ring-1 ring-zinc-950/5 dark:bg-zinc-900 dark:ring-white/10",
1788
- className
1789
- ),
1790
- children: [
1791
- /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between", children: [
1792
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-zinc-500 dark:text-zinc-400", children: label }),
1793
- icon && /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-zinc-100 p-2 dark:bg-zinc-800", children: icon })
1794
- ] }),
1795
- /* @__PURE__ */ jsx("p", { className: "mt-2 text-3xl font-semibold tracking-tight text-zinc-950 dark:text-white", children: value }),
1796
- (change || description) && /* @__PURE__ */ jsxs("div", { className: "mt-2 flex items-center gap-2", children: [
1797
- change && trend && /* @__PURE__ */ jsxs("span", { className: clsx("text-sm font-medium", trendColor[trend]), children: [
1798
- trendArrow[trend],
1799
- " ",
1800
- change
1801
- ] }),
1802
- description && /* @__PURE__ */ jsx("span", { className: "text-sm text-zinc-500 dark:text-zinc-400", children: description })
1803
- ] })
1804
- ]
1805
- }
1806
- );
1807
- }
1808
- function StatGroup({
1809
- className,
1810
- children
1811
- }) {
1812
- return /* @__PURE__ */ jsx("div", { className: clsx("grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4", className), children });
1813
- }
1814
- function Stepper({
1815
- steps,
1816
- orientation = "horizontal",
1817
- className
1818
- }) {
1819
- return orientation === "vertical" ? /* @__PURE__ */ jsx(StepperVertical, { steps, className }) : /* @__PURE__ */ jsx(StepperHorizontal, { steps, className });
1820
- }
1821
- function StepIcon({ status }) {
1822
- if (status === "complete") {
1823
- return /* @__PURE__ */ jsx("span", { className: "flex size-8 items-center justify-center rounded-full bg-blue-600", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 16 16", fill: "none", className: "size-4 text-white", "aria-hidden": "true", children: /* @__PURE__ */ jsx(
1824
- "path",
1825
- {
1826
- d: "M3 8l3.5 3.5L13 4",
1827
- stroke: "currentColor",
1828
- strokeWidth: "2",
1829
- strokeLinecap: "round",
1830
- strokeLinejoin: "round"
1831
- }
1832
- ) }) });
1833
- }
1834
- if (status === "current") {
1835
- return /* @__PURE__ */ jsx("span", { className: "flex size-8 items-center justify-center rounded-full border-2 border-blue-600 bg-white dark:bg-zinc-900", children: /* @__PURE__ */ jsx("span", { className: "size-2.5 rounded-full bg-blue-600" }) });
1836
- }
1837
- return /* @__PURE__ */ jsx("span", { className: "flex size-8 items-center justify-center rounded-full border-2 border-zinc-300 bg-white dark:border-zinc-600 dark:bg-zinc-900", children: /* @__PURE__ */ jsx("span", { className: "size-2.5 rounded-full bg-transparent" }) });
1838
- }
1839
- function StepperHorizontal({ steps, className }) {
1840
- return /* @__PURE__ */ jsx("nav", { "aria-label": "Progress", children: /* @__PURE__ */ jsx("ol", { className: clsx("flex items-center", className), children: steps.map((step, index) => {
1841
- const isLast = index === steps.length - 1;
1842
- return (
1843
- // biome-ignore lint/suspicious/noArrayIndexKey: stepper steps are positionally ordered with no stable ID
1844
- /* @__PURE__ */ jsxs("li", { className: clsx("flex items-center", !isLast && "flex-1"), children: [
1845
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1.5", children: [
1846
- /* @__PURE__ */ jsx(StepIcon, { status: step.status }),
1847
- /* @__PURE__ */ jsx(
1848
- "span",
1849
- {
1850
- className: clsx(
1851
- "text-xs font-medium",
1852
- step.status === "current" ? "text-blue-600" : step.status === "complete" ? "text-zinc-950 dark:text-white" : "text-zinc-400 dark:text-zinc-500"
1853
- ),
1854
- children: step.label
1855
- }
1856
- )
1857
- ] }),
1858
- !isLast && /* @__PURE__ */ jsx(
1859
- "div",
1860
- {
1861
- "aria-hidden": "true",
1862
- className: clsx(
1863
- "mx-3 h-px flex-1",
1864
- step.status === "complete" ? "bg-blue-600" : "bg-zinc-200 dark:bg-zinc-700"
1865
- )
1866
- }
1867
- )
1868
- ] }, index)
1869
- );
1870
- }) }) });
1871
- }
1872
- function StepperVertical({ steps, className }) {
1873
- return /* @__PURE__ */ jsx("nav", { "aria-label": "Progress", children: /* @__PURE__ */ jsx("ol", { className: clsx("space-y-0", className), children: steps.map((step, index) => {
1874
- const isLast = index === steps.length - 1;
1875
- return (
1876
- // biome-ignore lint/suspicious/noArrayIndexKey: stepper steps are positionally ordered with no stable ID
1877
- /* @__PURE__ */ jsxs("li", { className: "relative flex gap-4", children: [
1878
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
1879
- /* @__PURE__ */ jsx(StepIcon, { status: step.status }),
1880
- !isLast && /* @__PURE__ */ jsx(
1881
- "div",
1882
- {
1883
- "aria-hidden": "true",
1884
- className: clsx(
1885
- "w-px flex-1",
1886
- step.status === "complete" ? "bg-blue-600" : "bg-zinc-200 dark:bg-zinc-700"
1887
- )
1888
- }
1889
- )
1890
- ] }),
1891
- /* @__PURE__ */ jsxs("div", { className: clsx("pb-6 pt-1", isLast && "pb-0"), children: [
1892
- /* @__PURE__ */ jsx(
1893
- "p",
1894
- {
1895
- className: clsx(
1896
- "text-sm font-medium",
1897
- step.status === "current" ? "text-blue-600" : step.status === "complete" ? "text-zinc-950 dark:text-white" : "text-zinc-400 dark:text-zinc-500"
1898
- ),
1899
- children: step.label
1900
- }
1901
- ),
1902
- step.description && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-sm text-zinc-500 dark:text-zinc-400", children: step.description })
1903
- ] })
1904
- ] }, index)
1905
- );
1906
- }) }) });
1907
- }
1908
- const TabsContext = createContext(null);
1909
- function useTabsContext() {
1910
- const ctx = useContext(TabsContext);
1911
- if (!ctx) throw new Error("Tabs subcomponents must be used inside <Tabs>");
1912
- return ctx;
1913
- }
1914
- function Tabs({
1915
- defaultTab,
1916
- value,
1917
- onChange,
1918
- className,
1919
- children
1920
- }) {
1921
- const baseId = useId();
1922
- const [internalTab, setInternalTab] = useState(defaultTab ?? "");
1923
- const activeTab = value ?? internalTab;
1924
- const setActiveTab = useCallback(
1925
- (id) => {
1926
- setInternalTab(id);
1927
- onChange?.(id);
1928
- },
1929
- [onChange]
1930
- );
1931
- return /* @__PURE__ */ jsx(TabsContext, { value: { activeTab, setActiveTab, baseId }, children: /* @__PURE__ */ jsx("div", { className, children }) });
1932
- }
1933
- function TabList({
1934
- className,
1935
- children
1936
- }) {
1937
- return /* @__PURE__ */ jsx(
1938
- "div",
1939
- {
1940
- role: "tablist",
1941
- className: clsx("flex border-b border-zinc-200 dark:border-zinc-700", className),
1942
- children
1943
- }
1944
- );
1945
- }
1946
- function Tab({
1947
- id,
1948
- className,
1949
- children
1950
- }) {
1951
- const { activeTab, setActiveTab, baseId } = useTabsContext();
1952
- const isActive = activeTab === id;
1953
- return /* @__PURE__ */ jsx(
1954
- "button",
1955
- {
1956
- type: "button",
1957
- role: "tab",
1958
- id: `${baseId}-tab-${id}`,
1959
- "aria-controls": `${baseId}-panel-${id}`,
1960
- "aria-selected": isActive,
1961
- tabIndex: isActive ? 0 : -1,
1962
- onClick: () => setActiveTab(id),
1963
- className: clsx(
1964
- className,
1965
- "relative -mb-px border-b-2 px-4 py-2.5 text-sm font-medium transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500",
1966
- isActive ? "border-blue-600 text-blue-600 dark:border-blue-400 dark:text-blue-400" : "border-transparent text-zinc-500 hover:text-zinc-700 dark:text-zinc-400 dark:hover:text-zinc-200"
1967
- ),
1968
- children
1969
- }
1970
- );
1971
- }
1972
- function TabPanel({
1973
- id,
1974
- className,
1975
- children
1976
- }) {
1977
- const { activeTab, baseId } = useTabsContext();
1978
- if (activeTab !== id) return null;
1979
- return /* @__PURE__ */ jsx(
1980
- "div",
1981
- {
1982
- role: "tabpanel",
1983
- id: `${baseId}-panel-${id}`,
1984
- "aria-labelledby": `${baseId}-tab-${id}`,
1985
- tabIndex: 0,
1986
- className: clsx("focus-visible:outline-none", className),
1987
- children
1988
- }
1989
- );
1990
- }
1991
- const Textarea = forwardRef(function Textarea2({ className, resizable = true, disabled, invalid, ...props }, ref) {
1992
- const interactiveProps = useDataInteractive({ disabled });
1993
- const fieldProps = useFieldControlProps();
1994
- return /* @__PURE__ */ jsx(
1995
- "span",
1996
- {
1997
- "data-slot": "control",
1998
- className: clsx([
1999
- className,
2000
- // Basic layout
2001
- "relative block w-full",
2002
- // Background color + shadow applied to inset pseudo element, so shadow blends with border in light mode
2003
- "before:absolute before:inset-px before:rounded-[calc(var(--radius-lg)-1px)] before:bg-white before:shadow-sm",
2004
- // Background color is moved to control and shadow is removed in dark mode so hide `before` pseudo
2005
- "dark:before:hidden",
2006
- // Focus ring
2007
- "after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:ring-transparent after:ring-inset sm:focus-within:after:ring-2 sm:focus-within:after:ring-blue-500",
2008
- // Disabled state
2009
- "has-data-disabled:opacity-50 has-data-disabled:before:bg-zinc-950/5 has-data-disabled:before:shadow-none"
2010
- ]),
2011
- children: /* @__PURE__ */ jsx(
2012
- "textarea",
2013
- {
2014
- ref,
2015
- disabled,
2016
- ...props,
2017
- ...interactiveProps,
2018
- ...fieldProps,
2019
- "data-invalid": invalid ? "" : void 0,
2020
- "data-disabled": disabled ? "" : void 0,
2021
- className: clsx([
2022
- // Basic layout
2023
- "relative block h-full w-full appearance-none rounded-lg px-[calc(--spacing(3.5)-1px)] py-[calc(--spacing(2.5)-1px)] sm:px-[calc(--spacing(3)-1px)] sm:py-[calc(--spacing(1.5)-1px)]",
2024
- // Typography
2025
- "text-base/6 text-zinc-950 placeholder:text-zinc-500 sm:text-sm/6 dark:text-white",
2026
- // Border
2027
- "border border-zinc-950/10 data-hover:border-zinc-950/20 dark:border-white/10 dark:data-hover:border-white/20",
2028
- // Background color
2029
- "bg-transparent dark:bg-white/5",
2030
- // Hide default focus styles
2031
- "focus:outline-hidden",
2032
- // Invalid state
2033
- "data-invalid:border-red-500 data-invalid:data-hover:border-red-500 dark:data-invalid:border-red-600 dark:data-invalid:data-hover:border-red-600",
2034
- // Disabled state
2035
- "disabled:border-zinc-950/20 dark:disabled:border-white/15 dark:disabled:bg-white/2.5 dark:data-hover:disabled:border-white/15",
2036
- // Resizable
2037
- resizable ? "resize-y" : "resize-none"
2038
- ])
2039
- }
2040
- )
2041
- }
2042
- );
2043
- });
2044
- function Timeline({
2045
- className,
2046
- children
2047
- }) {
2048
- return /* @__PURE__ */ jsx("ol", { className: clsx("relative", className), children });
2049
- }
2050
- function TimelineItem({
2051
- icon,
2052
- date,
2053
- title,
2054
- description,
2055
- isLast = false,
2056
- className
2057
- }) {
2058
- return /* @__PURE__ */ jsxs("li", { className: clsx("relative flex gap-4", !isLast && "pb-8", className), children: [
2059
- !isLast && /* @__PURE__ */ jsx(
2060
- "div",
2061
- {
2062
- "aria-hidden": "true",
2063
- className: "absolute left-4 top-8 -bottom-0 w-px bg-zinc-200 dark:bg-zinc-700"
2064
- }
2065
- ),
2066
- /* @__PURE__ */ jsx("div", { className: "relative z-10 flex size-8 shrink-0 items-center justify-center rounded-full bg-white ring-1 ring-zinc-200 dark:bg-zinc-900 dark:ring-zinc-700", children: icon ?? /* @__PURE__ */ jsx("div", { className: "size-2 rounded-full bg-zinc-400 dark:bg-zinc-500" }) }),
2067
- /* @__PURE__ */ jsxs("div", { className: "flex-1 pt-0.5", children: [
2068
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-baseline justify-between gap-x-4", children: [
2069
- /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-zinc-950 dark:text-white", children: title }),
2070
- date && /* @__PURE__ */ jsx("time", { className: "shrink-0 text-xs text-zinc-400 dark:text-zinc-500", children: date })
2071
- ] }),
2072
- description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-zinc-600 dark:text-zinc-400", children: description })
2073
- ] })
2074
- ] });
2075
- }
2076
- function toastReducer(state, action) {
2077
- switch (action.type) {
2078
- case "ADD":
2079
- return [...state, action.toast];
2080
- case "REMOVE":
2081
- return state.filter((t) => t.id !== action.id);
2082
- }
2083
- }
2084
- const ToastContext = createContext(null);
2085
- function ToastProvider({ children }) {
2086
- const [toasts, dispatch] = useReducer(toastReducer, []);
2087
- const addToast = useCallback((toast) => {
2088
- const id = Math.random().toString(36).slice(2);
2089
- const duration = toast.duration ?? 5e3;
2090
- dispatch({ type: "ADD", toast: { ...toast, id } });
2091
- if (duration > 0) {
2092
- setTimeout(() => dispatch({ type: "REMOVE", id }), duration);
2093
- }
2094
- return id;
2095
- }, []);
2096
- const removeToast = useCallback((id) => {
2097
- dispatch({ type: "REMOVE", id });
2098
- }, []);
2099
- return /* @__PURE__ */ jsxs(ToastContext, { value: { toasts, addToast, removeToast }, children: [
2100
- children,
2101
- typeof document !== "undefined" && createPortal(/* @__PURE__ */ jsx(ToastList, { toasts, onRemove: removeToast }), document.body)
2102
- ] });
2103
- }
2104
- function useToast() {
2105
- const ctx = useContext(ToastContext);
2106
- if (!ctx) throw new Error("useToast must be used within a ToastProvider");
2107
- return ctx;
2108
- }
2109
- const variantClasses = {
2110
- default: "bg-white dark:bg-zinc-800 ring-zinc-950/10 dark:ring-white/10",
2111
- success: "bg-white dark:bg-zinc-800 ring-green-500/30",
2112
- error: "bg-white dark:bg-zinc-800 ring-red-500/30",
2113
- warning: "bg-white dark:bg-zinc-800 ring-amber-500/30",
2114
- info: "bg-white dark:bg-zinc-800 ring-blue-500/30"
2115
- };
2116
- const variantIconClasses = {
2117
- default: "hidden",
2118
- success: "text-green-500",
2119
- error: "text-red-500",
2120
- warning: "text-amber-500",
2121
- info: "text-blue-500"
2122
- };
2123
- const variantIcons = {
2124
- default: "",
2125
- success: "✓",
2126
- error: "✕",
2127
- warning: "!",
2128
- info: "i"
2129
- };
2130
- function ToastList({ toasts, onRemove }) {
2131
- if (toasts.length === 0) return null;
2132
- return /* @__PURE__ */ jsx(
2133
- "div",
2134
- {
2135
- "aria-live": "assertive",
2136
- className: "pointer-events-none fixed inset-0 z-50 flex flex-col items-end justify-end gap-2 p-4 sm:p-6",
2137
- children: toasts.map((toast) => /* @__PURE__ */ jsx(ToastItem, { toast, onRemove }, toast.id))
2138
- }
2139
- );
2140
- }
2141
- function ToastItem({ toast, onRemove }) {
2142
- const variant = toast.variant ?? "default";
2143
- return /* @__PURE__ */ jsxs(
2144
- "div",
2145
- {
2146
- role: "alert",
2147
- className: clsx(
2148
- "pointer-events-auto flex w-full max-w-sm items-start gap-3 rounded-xl p-4 shadow-lg ring-1",
2149
- variantClasses[variant]
2150
- ),
2151
- children: [
2152
- variant !== "default" && /* @__PURE__ */ jsx("span", { className: clsx("mt-0.5 text-sm font-bold", variantIconClasses[variant]), children: variantIcons[variant] }),
2153
- /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
2154
- /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-zinc-950 dark:text-white", children: toast.title }),
2155
- toast.description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-zinc-500 dark:text-zinc-400", children: toast.description })
2156
- ] }),
2157
- /* @__PURE__ */ jsx(
2158
- "button",
2159
- {
2160
- type: "button",
2161
- "aria-label": "Dismiss",
2162
- onClick: () => onRemove(toast.id),
2163
- className: "shrink-0 rounded-md text-zinc-400 hover:text-zinc-600 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500 dark:text-zinc-500 dark:hover:text-zinc-300",
2164
- children: /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "✕" })
2165
- }
2166
- )
2167
- ]
2168
- }
2169
- );
2170
- }
2171
- const sideClasses = {
2172
- top: "bottom-full left-1/2 -translate-x-1/2 mb-2",
2173
- bottom: "top-full left-1/2 -translate-x-1/2 mt-2",
2174
- left: "right-full top-1/2 -translate-y-1/2 mr-2",
2175
- right: "left-full top-1/2 -translate-y-1/2 ml-2"
2176
- };
2177
- function Tooltip({
2178
- content,
2179
- side = "top",
2180
- className,
2181
- children
2182
- }) {
2183
- const [visible, setVisible] = useState(false);
2184
- const id = useId();
2185
- const timeoutRef = useRef(null);
2186
- const show = useCallback(() => {
2187
- timeoutRef.current = setTimeout(() => setVisible(true), 200);
2188
- }, []);
2189
- const hide = useCallback(() => {
2190
- if (timeoutRef.current) clearTimeout(timeoutRef.current);
2191
- setVisible(false);
2192
- }, []);
2193
- return /* @__PURE__ */ jsxs("span", { className: "relative inline-flex", onMouseEnter: show, onMouseLeave: hide, children: [
2194
- children,
2195
- visible && /* @__PURE__ */ jsx(
2196
- "span",
2197
- {
2198
- role: "tooltip",
2199
- id,
2200
- className: clsx(
2201
- className,
2202
- sideClasses[side],
2203
- "pointer-events-none absolute z-50 w-max max-w-xs rounded-lg bg-zinc-950 px-2.5 py-1.5 text-xs text-white shadow-lg dark:bg-zinc-700"
2204
- ),
2205
- children: content
2206
- }
2207
- )
2208
- ] });
2209
- }
2210
- export {
2211
- useScrollLock as $,
2212
- Accordion as A,
2213
- Breadcrumb as B,
2214
- Callout as C,
2215
- Drawer as D,
2216
- EmptyState as E,
2217
- SkeletonText as F,
2218
- Slider as G,
2219
- Stat as H,
2220
- Input as I,
2221
- StatGroup as J,
2222
- Kbd as K,
2223
- Stepper as L,
2224
- TabList as M,
2225
- TabPanel as N,
2226
- Tabs as O,
2227
- Progress as P,
2228
- Textarea as Q,
2229
- Rating as R,
2230
- Select as S,
2231
- Tab as T,
2232
- Timeline as U,
2233
- TimelineItem as V,
2234
- ToastProvider as W,
2235
- Tooltip as X,
2236
- TouchTarget as Y,
2237
- useToast as Z,
2238
- useTransition as _,
2239
- AccordionItem as a,
2240
- useFocusTrap as a0,
2241
- useEscapeKey as a1,
2242
- useDataInteractive as a2,
2243
- Link as a3,
2244
- useControllableState as a4,
2245
- useFieldDescriptionProps as a5,
2246
- useFieldErrorProps as a6,
2247
- FieldProvider as a7,
2248
- useFieldLabelProps as a8,
2249
- useToggle as a9,
2250
- Avatar as aa,
2251
- AvatarGroup as b,
2252
- Button as c,
2253
- Checkbox as d,
2254
- Checkbox$1 as e,
2255
- CheckboxField as f,
2256
- CheckboxGroup as g,
2257
- CheckboxIndicator as h,
2258
- CodeBlock as i,
2259
- DrawerBody as j,
2260
- DrawerFooter as k,
2261
- DrawerHeader as l,
2262
- InputGroup as m,
2263
- KbdShortcut as n,
2264
- Select$1 as o,
2265
- SelectContent as p,
2266
- SelectGroup as q,
2267
- SelectItem as r,
2268
- SelectLabel as s,
2269
- SelectScrollDownButton as t,
2270
- SelectScrollUpButton as u,
2271
- SelectSeparator as v,
2272
- SelectTrigger as w,
2273
- SelectValue as x,
2274
- Skeleton as y,
2275
- SkeletonCard as z
2276
- };
2277
- //# sourceMappingURL=tooltip-oH4lAnkn.js.map