@justanarthur/modo-ui 0.0.0-stage → 0.2.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 (171) hide show
  1. package/LICENSE +21 -0
  2. package/LICENSE.beui +21 -0
  3. package/LICENSE.fluid-functionalism +21 -0
  4. package/LICENSE.motion-primitives +21 -0
  5. package/LICENSE.sileo +21 -0
  6. package/README.md +608 -2
  7. package/dist/base.css +994 -0
  8. package/dist/blocks/sidebar-app/index.d.ts +34 -0
  9. package/dist/blocks/sidebar-app/index.js +31 -0
  10. package/dist/components/badge/index.d.ts +59 -0
  11. package/dist/components/badge/index.js +16 -0
  12. package/dist/components/button/index.d.ts +59 -0
  13. package/dist/components/button/index.js +14 -0
  14. package/dist/components/card/index.d.ts +141 -0
  15. package/dist/components/card/index.js +42 -0
  16. package/dist/components/inputs/checkbox-group/index.d.ts +50 -0
  17. package/dist/components/inputs/checkbox-group/index.js +21 -0
  18. package/dist/components/inputs/color-picker/index.d.ts +137 -0
  19. package/dist/components/inputs/color-picker/index.js +35 -0
  20. package/dist/components/inputs/combobox/index.d.ts +161 -0
  21. package/dist/components/inputs/combobox/index.js +38 -0
  22. package/dist/components/inputs/date-time/calendar/index.d.ts +45 -0
  23. package/dist/components/inputs/date-time/calendar/index.js +18 -0
  24. package/dist/components/inputs/date-time/date-picker/index.d.ts +82 -0
  25. package/dist/components/inputs/date-time/date-picker/index.js +32 -0
  26. package/dist/components/inputs/date-time/date-range-picker/index.d.ts +64 -0
  27. package/dist/components/inputs/date-time/date-range-picker/index.js +31 -0
  28. package/dist/components/inputs/date-time/duration-picker/index.d.ts +57 -0
  29. package/dist/components/inputs/date-time/duration-picker/index.js +31 -0
  30. package/dist/components/inputs/date-time/month-picker/index.d.ts +57 -0
  31. package/dist/components/inputs/date-time/month-picker/index.js +30 -0
  32. package/dist/components/inputs/date-time/time-picker/index.d.ts +59 -0
  33. package/dist/components/inputs/date-time/time-picker/index.js +31 -0
  34. package/dist/components/inputs/input/index.d.ts +84 -0
  35. package/dist/components/inputs/input/index.js +19 -0
  36. package/dist/components/inputs/input-copy/index.d.ts +44 -0
  37. package/dist/components/inputs/input-copy/index.js +16 -0
  38. package/dist/components/inputs/input-message/index.d.ts +125 -0
  39. package/dist/components/inputs/input-message/index.js +25 -0
  40. package/dist/components/inputs/radio-group/index.d.ts +58 -0
  41. package/dist/components/inputs/radio-group/index.js +20 -0
  42. package/dist/components/inputs/search/index.d.ts +83 -0
  43. package/dist/components/inputs/search/index.js +25 -0
  44. package/dist/components/inputs/select/index.d.ts +105 -0
  45. package/dist/components/inputs/select/index.js +34 -0
  46. package/dist/components/inputs/slider/index.d.ts +108 -0
  47. package/dist/components/inputs/slider/index.js +14 -0
  48. package/dist/components/inputs/switch/index.d.ts +43 -0
  49. package/dist/components/inputs/switch/index.js +14 -0
  50. package/dist/components/navigation/accordion/index.d.ts +117 -0
  51. package/dist/components/navigation/accordion/index.js +28 -0
  52. package/dist/components/navigation/sidebar/index.d.ts +388 -0
  53. package/dist/components/navigation/sidebar/index.js +99 -0
  54. package/dist/components/navigation/tabs/index.d.ts +70 -0
  55. package/dist/components/navigation/tabs/index.js +23 -0
  56. package/dist/components/navigation/tabs-subtle/index.d.ts +73 -0
  57. package/dist/components/navigation/tabs-subtle/index.js +21 -0
  58. package/dist/components/overlays/alert-dialog/index.d.ts +67 -0
  59. package/dist/components/overlays/alert-dialog/index.js +22 -0
  60. package/dist/components/overlays/command/index.d.ts +121 -0
  61. package/dist/components/overlays/command/index.js +36 -0
  62. package/dist/components/overlays/context-menu/index.d.ts +97 -0
  63. package/dist/components/overlays/context-menu/index.js +29 -0
  64. package/dist/components/overlays/dialog/index.d.ts +130 -0
  65. package/dist/components/overlays/dialog/index.js +37 -0
  66. package/dist/components/overlays/dropdown/index.d.ts +222 -0
  67. package/dist/components/overlays/dropdown/index.js +44 -0
  68. package/dist/components/overlays/popover/index.d.ts +87 -0
  69. package/dist/components/overlays/popover/index.js +26 -0
  70. package/dist/components/overlays/preview-card/index.d.ts +75 -0
  71. package/dist/components/overlays/preview-card/index.js +19 -0
  72. package/dist/components/overlays/sheet/index.d.ts +67 -0
  73. package/dist/components/overlays/sheet/index.js +24 -0
  74. package/dist/components/overlays/toast/index.d.ts +107 -0
  75. package/dist/components/overlays/toast/index.js +21 -0
  76. package/dist/components/overlays/tooltip/index.d.ts +75 -0
  77. package/dist/components/overlays/tooltip/index.js +17 -0
  78. package/dist/components/table/index.d.ts +44 -0
  79. package/dist/components/table/index.js +26 -0
  80. package/dist/components/thinking-indicator/index.d.ts +32 -0
  81. package/dist/components/thinking-indicator/index.js +13 -0
  82. package/dist/index.d.ts +3926 -0
  83. package/dist/index.js +511 -0
  84. package/dist/preset.d.ts +104 -0
  85. package/dist/preset.js +124 -0
  86. package/dist/primitives/code/index.d.ts +23 -0
  87. package/dist/primitives/code/index.js +11 -0
  88. package/dist/primitives/craft/index.d.ts +31 -0
  89. package/dist/primitives/craft/index.js +11 -0
  90. package/dist/primitives/fluid-hover/index.d.ts +233 -0
  91. package/dist/primitives/fluid-hover/index.js +25 -0
  92. package/dist/primitives/morph/index.d.ts +127 -0
  93. package/dist/primitives/morph/index.js +19 -0
  94. package/dist/primitives/motion/index.d.ts +115 -0
  95. package/dist/primitives/motion/index.js +19 -0
  96. package/dist/primitives/scroll-area/index.d.ts +41 -0
  97. package/dist/primitives/scroll-area/index.js +12 -0
  98. package/dist/primitives/sizes/index.d.ts +128 -0
  99. package/dist/primitives/sizes/index.js +21 -0
  100. package/dist/primitives/surface/index.d.ts +69 -0
  101. package/dist/primitives/surface/index.js +17 -0
  102. package/dist/shared/components-0ke6xada.js +123 -0
  103. package/dist/shared/components-0q0sqfh4.js +146 -0
  104. package/dist/shared/components-0sn7ypjw.js +61 -0
  105. package/dist/shared/components-1j9791sn.js +345 -0
  106. package/dist/shared/components-1rfwbyyc.js +361 -0
  107. package/dist/shared/components-1v7rxytx.js +30 -0
  108. package/dist/shared/components-1xekx2hx.js +215 -0
  109. package/dist/shared/components-39jq9va1.js +86 -0
  110. package/dist/shared/components-3gae8nta.js +719 -0
  111. package/dist/shared/components-3k8xpnpq.js +1759 -0
  112. package/dist/shared/components-3ky44908.js +9 -0
  113. package/dist/shared/components-3mkepka5.js +111 -0
  114. package/dist/shared/components-3wk0w46f.js +667 -0
  115. package/dist/shared/components-4cnjmgex.js +124 -0
  116. package/dist/shared/components-59efxjd9.js +298 -0
  117. package/dist/shared/components-5xc2j8jz.js +159 -0
  118. package/dist/shared/components-62ybc7t2.js +496 -0
  119. package/dist/shared/components-66mv71kx.js +262 -0
  120. package/dist/shared/components-7ans7ce5.js +120 -0
  121. package/dist/shared/components-7btqt08d.js +270 -0
  122. package/dist/shared/components-7r3etddy.js +171 -0
  123. package/dist/shared/components-7x9kawxv.js +152 -0
  124. package/dist/shared/components-8fpr3s4p.js +292 -0
  125. package/dist/shared/components-9jvzzvt1.js +198 -0
  126. package/dist/shared/components-apdwtweq.js +484 -0
  127. package/dist/shared/components-asr5pg50.js +191 -0
  128. package/dist/shared/components-b2wyq2cq.js +232 -0
  129. package/dist/shared/components-c6s6b43g.js +15 -0
  130. package/dist/shared/components-ca2c898n.js +1828 -0
  131. package/dist/shared/components-cbxjn9p8.js +141 -0
  132. package/dist/shared/components-chacnk61.js +216 -0
  133. package/dist/shared/components-cv16mryv.js +62 -0
  134. package/dist/shared/components-ez65vtbq.js +110 -0
  135. package/dist/shared/components-ezxhrmer.js +17 -0
  136. package/dist/shared/components-gc5vtq2f.js +149 -0
  137. package/dist/shared/components-gf5s6ap9.js +42 -0
  138. package/dist/shared/components-gvr9w41t.js +193 -0
  139. package/dist/shared/components-h2dpcwgc.js +137 -0
  140. package/dist/shared/components-hawvy2qz.js +105 -0
  141. package/dist/shared/components-hqeq3w9q.js +375 -0
  142. package/dist/shared/components-jjw69c4c.js +28 -0
  143. package/dist/shared/components-jwst3vtj.js +346 -0
  144. package/dist/shared/components-kvr7f9hy.js +45 -0
  145. package/dist/shared/components-men63rwj.js +9 -0
  146. package/dist/shared/components-mhd39z7x.js +22 -0
  147. package/dist/shared/components-n7mjr357.js +26 -0
  148. package/dist/shared/components-ng72k97e.js +128 -0
  149. package/dist/shared/components-nh8tma1n.js +986 -0
  150. package/dist/shared/components-njzgqdwy.js +445 -0
  151. package/dist/shared/components-ny774h8p.js +293 -0
  152. package/dist/shared/components-q4daerx0.js +58 -0
  153. package/dist/shared/components-q5xj5c16.js +79 -0
  154. package/dist/shared/components-rr7a6ja9.js +160 -0
  155. package/dist/shared/components-s2bz1xpk.js +63 -0
  156. package/dist/shared/components-tqvarbfv.js +288 -0
  157. package/dist/shared/components-v6xp325t.js +304 -0
  158. package/dist/shared/components-v7wtz8hk.js +144 -0
  159. package/dist/shared/components-vc7vq5nz.js +32 -0
  160. package/dist/shared/components-vfbhxf5r.js +58 -0
  161. package/dist/shared/components-vynjtrk6.js +19 -0
  162. package/dist/shared/components-wvp1m52g.js +1200 -0
  163. package/dist/shared/components-yh3kwdhr.js +981 -0
  164. package/dist/shared/components-ytb2tefr.js +291 -0
  165. package/dist/shared/components-zfnmn5d4.js +220 -0
  166. package/dist/shared/components-zrkzcayz.js +141 -0
  167. package/dist/shared/components-zx6b6yby.js +42 -0
  168. package/dist/styles.css +1949 -0
  169. package/dist/tailwind.css +219 -0
  170. package/dist/tokens.css +345 -0
  171. package/package.json +103 -4
@@ -0,0 +1,262 @@
1
+ import {
2
+ useIcon
3
+ } from "./components-zrkzcayz.js";
4
+ import {
5
+ useReduceMotion
6
+ } from "./components-men63rwj.js";
7
+ import {
8
+ MorphSurface
9
+ } from "./components-0q0sqfh4.js";
10
+ import {
11
+ useMorph
12
+ } from "./components-hqeq3w9q.js";
13
+ import {
14
+ cn2
15
+ } from "./components-ezxhrmer.js";
16
+ import {
17
+ shapeMap,
18
+ useShape
19
+ } from "./components-cv16mryv.js";
20
+ import {
21
+ useSize2
22
+ } from "./components-0sn7ypjw.js";
23
+ import {
24
+ SURFACE_BG,
25
+ SURFACE_SHADOW,
26
+ useSurface2,
27
+ SurfaceProvider2
28
+ } from "./components-zx6b6yby.js";
29
+ import {
30
+ useControllableState
31
+ } from "./components-n7mjr357.js";
32
+ import {
33
+ CommandListRoot2,
34
+ CommandShortcut2,
35
+ CommandList2
36
+ } from "./components-8fpr3s4p.js";
37
+ import {
38
+ spring2
39
+ } from "./components-1v7rxytx.js";
40
+
41
+ // components/inputs/search/index.tsx
42
+ import { Autocomplete } from "@base-ui/react/autocomplete";
43
+ import { motion } from "motion/react";
44
+ import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
45
+ import { flushSync } from "react-dom";
46
+ import { jsx, jsxs } from "react/jsx-runtime";
47
+ var INSET = { default: "pl-2.5", compact: "pl-[7px]" };
48
+ var SQUARE = { default: "w-9", compact: "w-7" };
49
+ var PILL = { default: "min-w-[160px]", compact: "min-w-[128px]" };
50
+ var isEditable = (target) => target instanceof HTMLElement && (target.isContentEditable || target.closest("input, textarea, select") !== null);
51
+ function Search2({
52
+ variant = "pill",
53
+ placeholder = "Search",
54
+ items,
55
+ value,
56
+ defaultValue = "",
57
+ onValueChange,
58
+ onSubmit,
59
+ expanded,
60
+ defaultExpanded = false,
61
+ onExpandedChange,
62
+ width = 288,
63
+ align = "start",
64
+ shortcut,
65
+ emptyMessage = "No results found.",
66
+ effect,
67
+ tier = "moderate",
68
+ className
69
+ }) {
70
+ const [query, setQuery] = useControllableState(value, defaultValue, onValueChange);
71
+ const [isExpanded, setExpanded] = useControllableState(expanded, defaultExpanded, onExpandedChange);
72
+ const [suggesting, setSuggesting] = useState(false);
73
+ const [settled, setSettled] = useState(isExpanded);
74
+ const [rest, setRest] = useState(0);
75
+ const reduced = useReduceMotion();
76
+ const shape = useShape();
77
+ const size = useSize2();
78
+ const level = Math.min(useSurface2() + 2, 8);
79
+ const SearchIcon = useIcon("search");
80
+ const XIcon = useIcon("x");
81
+ const button = useRef(null);
82
+ const field = useRef(null);
83
+ const input = useRef(null);
84
+ const origin = useRef({});
85
+ const suggestions = useMemo(() => items?.map((item) => typeof item === "string" ? { label: item } : item), [items]);
86
+ const open = suggesting && isExpanded && settled;
87
+ const lifted = isExpanded || settled;
88
+ const morph = useMorph(open, origin, { from: field, effect, tier });
89
+ useLayoutEffect(() => {
90
+ const el = button.current;
91
+ if (!el)
92
+ return;
93
+ const observer = new ResizeObserver(() => setRest(el.offsetWidth));
94
+ observer.observe(el);
95
+ return () => observer.disconnect();
96
+ }, []);
97
+ const expand = () => {
98
+ flushSync(() => setExpanded(true));
99
+ input.current?.focus({ preventScroll: true });
100
+ };
101
+ const collapse = (refocus) => {
102
+ flushSync(() => {
103
+ setQuery("");
104
+ setSuggesting(false);
105
+ setExpanded(false);
106
+ });
107
+ if (refocus)
108
+ button.current?.focus();
109
+ };
110
+ useEffect(() => {
111
+ if (!shortcut || isExpanded)
112
+ return;
113
+ const onKey = (event) => {
114
+ if (event.defaultPrevented || event.key !== shortcut || event.metaKey || event.ctrlKey || event.altKey)
115
+ return;
116
+ if (isEditable(event.target))
117
+ return;
118
+ event.preventDefault();
119
+ expand();
120
+ };
121
+ window.addEventListener("keydown", onKey);
122
+ return () => window.removeEventListener("keydown", onKey);
123
+ }, [shortcut, isExpanded]);
124
+ const onKeyDown = (event) => {
125
+ if (event.key !== "Escape" || open)
126
+ return;
127
+ event.stopPropagation();
128
+ if (query)
129
+ setQuery("");
130
+ else
131
+ collapse(true);
132
+ };
133
+ const inputProps = {
134
+ ref: input,
135
+ placeholder,
136
+ "aria-label": placeholder,
137
+ onKeyDown,
138
+ className: cn2("h-full min-w-0 flex-1 bg-transparent text-foreground outline-none placeholder:text-muted-foreground [&::-webkit-search-cancel-button]:hidden", size.text)
139
+ };
140
+ const root = /* @__PURE__ */ jsx("search", {
141
+ onBlur: (event) => {
142
+ if (!isExpanded || query || event.currentTarget.contains(event.relatedTarget))
143
+ return;
144
+ collapse(false);
145
+ },
146
+ className: cn2("group/search relative inline-flex shrink-0 align-middle", className),
147
+ children: /* @__PURE__ */ jsxs("form", {
148
+ className: "contents",
149
+ onSubmit: (event) => {
150
+ event.preventDefault();
151
+ onSubmit?.(query);
152
+ },
153
+ children: [
154
+ /* @__PURE__ */ jsxs("button", {
155
+ ref: button,
156
+ type: "button",
157
+ "aria-label": placeholder,
158
+ onClick: expand,
159
+ className: cn2("relative z-[1] flex items-center outline-none focus-visible:ring-1 focus-visible:ring-focus-ring", size.control, size.gap, size.text, shape.input, variant === "icon" ? cn2("cursor-pointer justify-center", SQUARE[size.variant]) : cn2("cursor-text pr-2.5", INSET[size.variant], PILL[size.variant]), isExpanded && "invisible"),
160
+ children: [
161
+ /* @__PURE__ */ jsx(SearchIcon, {
162
+ size: size.icon,
163
+ strokeWidth: 1.5,
164
+ className: "shrink-0 text-muted-foreground transition-colors duration-fast group-hover/search:text-foreground"
165
+ }),
166
+ variant === "pill" && /* @__PURE__ */ jsx("span", {
167
+ className: "text-muted-foreground",
168
+ children: placeholder
169
+ }),
170
+ variant === "pill" && shortcut && /* @__PURE__ */ jsx(CommandShortcut2, {
171
+ className: "pl-4",
172
+ children: shortcut
173
+ })
174
+ ]
175
+ }),
176
+ rest > 0 && /* @__PURE__ */ jsx(motion.div, {
177
+ ref: field,
178
+ className: cn2("absolute top-0 h-full overflow-hidden ring-1 transition-[box-shadow] duration-moderate", align === "end" ? "right-0" : "left-0", shape.input, lifted ? cn2("z-10 ring-transparent", SURFACE_BG[level], SURFACE_SHADOW[3]) : "ring-border group-hover/search:bg-muted/50"),
179
+ initial: false,
180
+ animate: { width: isExpanded ? width : rest },
181
+ transition: reduced ? { duration: 0 } : isExpanded ? spring2.slow : spring2.slow.exit,
182
+ onAnimationComplete: () => setSettled(isExpanded),
183
+ children: lifted && /* @__PURE__ */ jsxs("div", {
184
+ className: cn2("flex h-full items-center pr-1.5", size.gap, INSET[size.variant]),
185
+ style: { width },
186
+ children: [
187
+ /* @__PURE__ */ jsx(SearchIcon, {
188
+ size: size.icon,
189
+ strokeWidth: 1.5,
190
+ className: "shrink-0 text-muted-foreground"
191
+ }),
192
+ suggestions ? /* @__PURE__ */ jsx(Autocomplete.Input, {
193
+ ...inputProps
194
+ }) : /* @__PURE__ */ jsx("input", {
195
+ ...inputProps,
196
+ type: "search",
197
+ value: query,
198
+ onChange: (event) => setQuery(event.target.value)
199
+ }),
200
+ query && /* @__PURE__ */ jsx("button", {
201
+ type: "button",
202
+ "aria-label": "Clear",
203
+ onMouseDown: (event) => event.preventDefault(),
204
+ onClick: () => {
205
+ setQuery("");
206
+ input.current?.focus();
207
+ },
208
+ className: "flex size-6 shrink-0 items-center justify-center rounded-md text-muted-foreground outline-none transition-[color,background-color] duration-fast hover:bg-hover hover:text-foreground active:bg-active focus-visible:ring-1 focus-visible:ring-focus-ring",
209
+ children: /* @__PURE__ */ jsx(XIcon, {
210
+ size: size.icon - 2,
211
+ strokeWidth: 1.5
212
+ })
213
+ })
214
+ ]
215
+ })
216
+ })
217
+ ]
218
+ })
219
+ });
220
+ if (!suggestions)
221
+ return root;
222
+ return /* @__PURE__ */ jsxs(CommandListRoot2, {
223
+ items: suggestions,
224
+ value: query,
225
+ onValueChange: setQuery,
226
+ open,
227
+ onOpenChange: setSuggesting,
228
+ children: [
229
+ root,
230
+ /* @__PURE__ */ jsx(Autocomplete.Portal, {
231
+ children: /* @__PURE__ */ jsx(Autocomplete.Positioner, {
232
+ anchor: field,
233
+ side: "bottom",
234
+ align,
235
+ sideOffset: 8,
236
+ className: "z-50 outline-none",
237
+ children: /* @__PURE__ */ jsx(Autocomplete.Popup, {
238
+ ref: morph.popupRef,
239
+ className: "relative outline-none",
240
+ children: /* @__PURE__ */ jsx(SurfaceProvider2, {
241
+ value: level,
242
+ children: /* @__PURE__ */ jsx(MorphSurface, {
243
+ morph,
244
+ bg: SURFACE_BG[level],
245
+ shadow: SURFACE_SHADOW[3],
246
+ radius: shapeMap.rounded.container,
247
+ className: "flex max-h-[min(300px,var(--available-height))] w-[var(--anchor-width)] flex-col overflow-hidden",
248
+ children: /* @__PURE__ */ jsx(CommandList2, {
249
+ emptyMessage,
250
+ onPick: (item) => onSubmit?.(item.label)
251
+ })
252
+ })
253
+ })
254
+ })
255
+ })
256
+ })
257
+ ]
258
+ });
259
+ }
260
+ var search_default = Search2;
261
+
262
+ export { Search2, search_default };
@@ -0,0 +1,120 @@
1
+ import {
2
+ defaultLocale,
3
+ fieldLabel,
4
+ dividedColumns,
5
+ ScrollColumn
6
+ } from "./components-9jvzzvt1.js";
7
+ import {
8
+ cn2
9
+ } from "./components-ezxhrmer.js";
10
+ import {
11
+ useControllableState
12
+ } from "./components-n7mjr357.js";
13
+ import {
14
+ PickerShell,
15
+ PickerInput
16
+ } from "./components-7btqt08d.js";
17
+ import {
18
+ pad
19
+ } from "./components-q4daerx0.js";
20
+
21
+ // components/inputs/date-time/duration-picker/index.tsx
22
+ import { formatDuration } from "date-fns";
23
+ import { useMemo, useRef } from "react";
24
+ import { jsx, jsxs } from "react/jsx-runtime";
25
+ var TYPED = /^\s*(\d{1,3})(?::(\d{1,2}))?\s*$/;
26
+ function DurationPicker2({
27
+ value: valueProp,
28
+ defaultValue = null,
29
+ onValueChange,
30
+ maxHours = 99,
31
+ minuteStep = 1,
32
+ locale = defaultLocale,
33
+ placeholder,
34
+ disabled,
35
+ invalid,
36
+ size,
37
+ open: openProp,
38
+ defaultOpen = false,
39
+ onOpenChange,
40
+ id,
41
+ from,
42
+ effect,
43
+ hideSource,
44
+ tier,
45
+ className
46
+ }) {
47
+ const [value, setValue] = useControllableState(valueProp, defaultValue, onValueChange);
48
+ const [open, setOpen] = useControllableState(openProp, defaultOpen, onOpenChange);
49
+ const input = useRef(null);
50
+ const hours = value?.hours ?? 0;
51
+ const minutes = value?.minutes ?? 0;
52
+ const display = value ? hours || minutes ? formatDuration({ hours, minutes }, { locale, format: ["hours", "minutes"] }) : formatDuration({ minutes: 0 }, { locale, format: ["minutes"], zero: true }) : "";
53
+ const readDuration = (text) => {
54
+ if (!text.trim()) {
55
+ setValue(null);
56
+ return true;
57
+ }
58
+ const match = TYPED.exec(text);
59
+ const h = Number(match?.[1]);
60
+ const m = Number(match?.[2] ?? 0);
61
+ if (!match || h > maxHours || m > 59)
62
+ return false;
63
+ setValue({ hours: h, minutes: m });
64
+ return true;
65
+ };
66
+ const hourOptions = useMemo(() => Array.from({ length: maxHours + 1 }, (_, h) => ({ value: h, label: String(h) })), [maxHours]);
67
+ const minuteOptions = useMemo(() => Array.from({ length: Math.ceil(60 / minuteStep) }, (_, i) => ({
68
+ value: i * minuteStep,
69
+ label: pad(i * minuteStep)
70
+ })), [minuteStep]);
71
+ return /* @__PURE__ */ jsx(PickerShell, {
72
+ open,
73
+ onOpenChange: setOpen,
74
+ size,
75
+ invalid,
76
+ disabled,
77
+ icon: "clock",
78
+ display,
79
+ placeholder,
80
+ header: /* @__PURE__ */ jsx(PickerInput, {
81
+ ref: input,
82
+ "aria-label": placeholder ?? "Duration",
83
+ placeholder: "0:00",
84
+ formatted: value ? `${hours}:${pad(minutes)}` : "",
85
+ onText: readDuration,
86
+ onEnter: () => setOpen(false),
87
+ className: "flex-1"
88
+ }),
89
+ initialFocus: input,
90
+ popupClassName: "w-[max(var(--anchor-width,0px),14rem)]",
91
+ id,
92
+ from,
93
+ effect,
94
+ hideSource,
95
+ tier,
96
+ className,
97
+ children: /* @__PURE__ */ jsxs("div", {
98
+ className: cn2(dividedColumns, "h-56"),
99
+ children: [
100
+ /* @__PURE__ */ jsx(ScrollColumn, {
101
+ label: fieldLabel(locale, "hour"),
102
+ options: hourOptions,
103
+ value: value ? hours : null,
104
+ onValueChange: (h) => setValue({ hours: h, minutes }),
105
+ className: "min-w-0 flex-1"
106
+ }),
107
+ /* @__PURE__ */ jsx(ScrollColumn, {
108
+ label: fieldLabel(locale, "minute"),
109
+ options: minuteOptions,
110
+ value: value ? minutes : null,
111
+ onValueChange: (m) => setValue({ hours, minutes: m }),
112
+ className: "min-w-0 flex-1"
113
+ })
114
+ ]
115
+ })
116
+ });
117
+ }
118
+ var duration_picker_default = DurationPicker2;
119
+
120
+ export { DurationPicker2, duration_picker_default };
@@ -0,0 +1,270 @@
1
+ import {
2
+ fieldVariants,
3
+ fieldIconClasses
4
+ } from "./components-mhd39z7x.js";
5
+ import {
6
+ useIcon
7
+ } from "./components-zrkzcayz.js";
8
+ import {
9
+ MorphSurface
10
+ } from "./components-0q0sqfh4.js";
11
+ import {
12
+ opensInPlace,
13
+ inPlaceOffset,
14
+ useMorphOrigin,
15
+ useMorph
16
+ } from "./components-hqeq3w9q.js";
17
+ import {
18
+ cn2
19
+ } from "./components-ezxhrmer.js";
20
+ import {
21
+ useShape
22
+ } from "./components-cv16mryv.js";
23
+ import {
24
+ useSize2
25
+ } from "./components-0sn7ypjw.js";
26
+ import {
27
+ SURFACE_BG,
28
+ SURFACE_SHADOW,
29
+ useSurface2,
30
+ SurfaceProvider2
31
+ } from "./components-zx6b6yby.js";
32
+ import {
33
+ useControllableState
34
+ } from "./components-n7mjr357.js";
35
+ import {
36
+ useIsMobile
37
+ } from "./components-c6s6b43g.js";
38
+ import {
39
+ SizeProvider2
40
+ } from "./components-jjw69c4c.js";
41
+ import {
42
+ button_default
43
+ } from "./components-b2wyq2cq.js";
44
+ import {
45
+ sheet_default
46
+ } from "./components-rr7a6ja9.js";
47
+ import {
48
+ input_default
49
+ } from "./components-gvr9w41t.js";
50
+
51
+ // components/inputs/date-time/picker-shell.tsx
52
+ import { Popover } from "@base-ui/react/popover";
53
+ import { forwardRef, useCallback, useState } from "react";
54
+ import { jsx, jsxs } from "react/jsx-runtime";
55
+ function PickerShell({ open: openProp, defaultOpen = false, onOpenChange, size, ...props }) {
56
+ const [open, setOpen] = useControllableState(openProp, defaultOpen, onOpenChange);
57
+ const mobile = useIsMobile(640);
58
+ const shell = mobile ? /* @__PURE__ */ jsx(PickerSheet, {
59
+ open,
60
+ setOpen,
61
+ ...props
62
+ }) : /* @__PURE__ */ jsx(PickerPopover, {
63
+ open,
64
+ setOpen,
65
+ ...props
66
+ });
67
+ return size ? /* @__PURE__ */ jsx(SizeProvider2, {
68
+ size,
69
+ children: shell
70
+ }) : shell;
71
+ }
72
+ var PickerField = forwardRef(({ icon, display, placeholder, invalid, disabled, id, className, ...props }, ref) => {
73
+ const Icon = useIcon(icon);
74
+ const shape = useShape();
75
+ const sizeClasses = useSize2();
76
+ const compact = sizeClasses.variant === "compact";
77
+ return /* @__PURE__ */ jsxs("button", {
78
+ ref,
79
+ type: "button",
80
+ id,
81
+ disabled,
82
+ "aria-invalid": invalid || undefined,
83
+ "data-invalid": invalid || undefined,
84
+ "data-disabled": disabled || undefined,
85
+ ...props,
86
+ className: cn2(fieldVariants({ variant: "bordered" }), "flex w-full min-w-0 items-center text-left cursor-pointer outline-none focus-visible:ring-focus-ring", sizeClasses.gap, sizeClasses.control, compact ? "px-2" : "px-2.5", shape.input, className),
87
+ children: [
88
+ /* @__PURE__ */ jsx(Icon, {
89
+ size: sizeClasses.icon,
90
+ strokeWidth: 1.5,
91
+ className: fieldIconClasses
92
+ }),
93
+ /* @__PURE__ */ jsx("span", {
94
+ className: cn2("flex-1 truncate", sizeClasses.text, display ? "text-foreground" : "text-muted-foreground"),
95
+ children: display || placeholder
96
+ })
97
+ ]
98
+ });
99
+ });
100
+ PickerField.displayName = "PickerField";
101
+ function PanelHeader({
102
+ header,
103
+ closeLabel = "Close",
104
+ close
105
+ }) {
106
+ const X = useIcon("x");
107
+ const sizeClasses = useSize2();
108
+ return /* @__PURE__ */ jsxs("div", {
109
+ className: "flex items-center gap-1 border-b border-border pb-1",
110
+ children: [
111
+ /* @__PURE__ */ jsx("div", {
112
+ className: "flex min-w-0 flex-1 items-center",
113
+ children: header
114
+ }),
115
+ /* @__PURE__ */ jsx(button_default, {
116
+ variant: "ghost",
117
+ size: "icon-sm",
118
+ "aria-label": closeLabel,
119
+ onClick: close,
120
+ children: /* @__PURE__ */ jsx(X, {
121
+ size: sizeClasses.icon,
122
+ strokeWidth: 1.5
123
+ })
124
+ })
125
+ ]
126
+ });
127
+ }
128
+ function PickerPopover({
129
+ open,
130
+ setOpen,
131
+ header,
132
+ initialFocus,
133
+ closeLabel,
134
+ dir,
135
+ popupClassName,
136
+ from,
137
+ effect,
138
+ hideSource,
139
+ tier = "moderate",
140
+ children,
141
+ ...field
142
+ }) {
143
+ const { origin, capture } = useMorphOrigin();
144
+ const morph = useMorph(open, origin, { from, effect, hideSource, tier });
145
+ const shape = useShape();
146
+ const level = Math.min(useSurface2() + 2, 8);
147
+ const handleOpenChange = useCallback((next, details) => {
148
+ if (next)
149
+ capture(details);
150
+ setOpen(next);
151
+ }, [capture, setOpen]);
152
+ return /* @__PURE__ */ jsxs(Popover.Root, {
153
+ open,
154
+ onOpenChange: handleOpenChange,
155
+ modal: false,
156
+ children: [
157
+ /* @__PURE__ */ jsx(Popover.Trigger, {
158
+ disabled: field.disabled,
159
+ render: /* @__PURE__ */ jsx(PickerField, {
160
+ ...field
161
+ })
162
+ }),
163
+ /* @__PURE__ */ jsx(Popover.Portal, {
164
+ children: /* @__PURE__ */ jsx(Popover.Positioner, {
165
+ side: "bottom",
166
+ align: "start",
167
+ sideOffset: opensInPlace({ effect, hideSource }) ? inPlaceOffset : 6,
168
+ className: "z-50 outline-none",
169
+ children: /* @__PURE__ */ jsx(Popover.Popup, {
170
+ ref: morph.popupRef,
171
+ initialFocus,
172
+ className: "relative outline-none",
173
+ children: /* @__PURE__ */ jsx(SurfaceProvider2, {
174
+ value: level,
175
+ children: /* @__PURE__ */ jsx(MorphSurface, {
176
+ morph,
177
+ bg: SURFACE_BG[level],
178
+ shadow: SURFACE_SHADOW[3],
179
+ radius: shape.container,
180
+ className: cn2("flex max-w-[calc(100vw-1rem)] flex-col gap-1 p-1", popupClassName),
181
+ children: /* @__PURE__ */ jsxs("div", {
182
+ dir,
183
+ className: "flex min-h-0 flex-col gap-1",
184
+ children: [
185
+ /* @__PURE__ */ jsx(PanelHeader, {
186
+ header,
187
+ closeLabel,
188
+ close: () => setOpen(false)
189
+ }),
190
+ children
191
+ ]
192
+ })
193
+ })
194
+ })
195
+ })
196
+ })
197
+ })
198
+ ]
199
+ });
200
+ }
201
+ function PickerSheet({ open, setOpen, header, closeLabel, dir, children, ...field }) {
202
+ const {
203
+ initialFocus: _focus,
204
+ popupClassName: _width,
205
+ from: _from,
206
+ effect: _effect,
207
+ hideSource: _hide,
208
+ tier: _tier,
209
+ ...fieldProps
210
+ } = field;
211
+ return /* @__PURE__ */ jsxs(sheet_default, {
212
+ open,
213
+ onOpenChange: setOpen,
214
+ children: [
215
+ /* @__PURE__ */ jsx(sheet_default.Trigger, {
216
+ disabled: field.disabled,
217
+ render: /* @__PURE__ */ jsx(PickerField, {
218
+ ...fieldProps
219
+ })
220
+ }),
221
+ /* @__PURE__ */ jsx(sheet_default.Content, {
222
+ className: "gap-2 p-3 pt-3",
223
+ children: /* @__PURE__ */ jsxs("div", {
224
+ dir,
225
+ className: "flex min-h-0 flex-col gap-2",
226
+ children: [
227
+ /* @__PURE__ */ jsx(PanelHeader, {
228
+ header,
229
+ closeLabel,
230
+ close: () => setOpen(false)
231
+ }),
232
+ children
233
+ ]
234
+ })
235
+ })
236
+ ]
237
+ });
238
+ }
239
+ var PickerInput = forwardRef(({ formatted, onText, onEnter, onFocus, onBlur, onKeyDown, className, ...props }, ref) => {
240
+ const [draft, setDraft] = useState(null);
241
+ const [invalid, setInvalid] = useState(false);
242
+ return /* @__PURE__ */ jsx(input_default, {
243
+ ref,
244
+ ...props,
245
+ className: cn2("hover:ring-transparent focus-within:ring-transparent data-[active]:ring-transparent", className),
246
+ value: draft ?? formatted,
247
+ invalid,
248
+ onChange: (text) => {
249
+ setDraft(text);
250
+ setInvalid(!onText(text));
251
+ },
252
+ onFocus: (e) => {
253
+ e.currentTarget.select();
254
+ onFocus?.(e);
255
+ },
256
+ onBlur: (e) => {
257
+ setDraft(null);
258
+ setInvalid(false);
259
+ onBlur?.(e);
260
+ },
261
+ onKeyDown: (e) => {
262
+ if (e.key === "Enter" && !invalid)
263
+ onEnter?.();
264
+ onKeyDown?.(e);
265
+ }
266
+ });
267
+ });
268
+ PickerInput.displayName = "PickerInput";
269
+
270
+ export { PickerShell, PickerInput };