@ansh-ui/react 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 (111) hide show
  1. package/LICENSE +21 -0
  2. package/dist/chunk-5CFQFMP5.js +178 -0
  3. package/dist/chunk-5CFQFMP5.js.map +1 -0
  4. package/dist/chunk-6VRF7X5C.cjs +164 -0
  5. package/dist/chunk-6VRF7X5C.cjs.map +1 -0
  6. package/dist/chunk-AVPEA5PB.cjs +718 -0
  7. package/dist/chunk-AVPEA5PB.cjs.map +1 -0
  8. package/dist/chunk-C32LKF23.cjs +198 -0
  9. package/dist/chunk-C32LKF23.cjs.map +1 -0
  10. package/dist/chunk-C5JG6TMM.cjs +1200 -0
  11. package/dist/chunk-C5JG6TMM.cjs.map +1 -0
  12. package/dist/chunk-DATBU46V.cjs +614 -0
  13. package/dist/chunk-DATBU46V.cjs.map +1 -0
  14. package/dist/chunk-EGG4CP7C.js +320 -0
  15. package/dist/chunk-EGG4CP7C.js.map +1 -0
  16. package/dist/chunk-H34OXXJU.js +55 -0
  17. package/dist/chunk-H34OXXJU.js.map +1 -0
  18. package/dist/chunk-HO2YSF5O.js +187 -0
  19. package/dist/chunk-HO2YSF5O.js.map +1 -0
  20. package/dist/chunk-HPGCILO4.js +760 -0
  21. package/dist/chunk-HPGCILO4.js.map +1 -0
  22. package/dist/chunk-IBXLC5IE.js +154 -0
  23. package/dist/chunk-IBXLC5IE.js.map +1 -0
  24. package/dist/chunk-LDCZQP3R.js +1185 -0
  25. package/dist/chunk-LDCZQP3R.js.map +1 -0
  26. package/dist/chunk-LXCIXR5T.js +27 -0
  27. package/dist/chunk-LXCIXR5T.js.map +1 -0
  28. package/dist/chunk-O2PX54KX.js +94 -0
  29. package/dist/chunk-O2PX54KX.js.map +1 -0
  30. package/dist/chunk-OHBWBXLO.cjs +101 -0
  31. package/dist/chunk-OHBWBXLO.cjs.map +1 -0
  32. package/dist/chunk-OJN5JBNP.cjs +776 -0
  33. package/dist/chunk-OJN5JBNP.cjs.map +1 -0
  34. package/dist/chunk-OLTS6G5M.js +606 -0
  35. package/dist/chunk-OLTS6G5M.js.map +1 -0
  36. package/dist/chunk-PO5DU3FU.cjs +29 -0
  37. package/dist/chunk-PO5DU3FU.cjs.map +1 -0
  38. package/dist/chunk-QO3E7TJS.js +2940 -0
  39. package/dist/chunk-QO3E7TJS.js.map +1 -0
  40. package/dist/chunk-RHTLNSVW.cjs +2976 -0
  41. package/dist/chunk-RHTLNSVW.cjs.map +1 -0
  42. package/dist/chunk-SFU5EPSN.cjs +61 -0
  43. package/dist/chunk-SFU5EPSN.cjs.map +1 -0
  44. package/dist/chunk-T4AK2KLM.js +699 -0
  45. package/dist/chunk-T4AK2KLM.js.map +1 -0
  46. package/dist/chunk-WGYNCSTP.cjs +333 -0
  47. package/dist/chunk-WGYNCSTP.cjs.map +1 -0
  48. package/dist/chunk-XEP6P7E6.js +279 -0
  49. package/dist/chunk-XEP6P7E6.js.map +1 -0
  50. package/dist/chunk-XMXECSQO.cjs +286 -0
  51. package/dist/chunk-XMXECSQO.cjs.map +1 -0
  52. package/dist/chunk-ZWAFLHC2.cjs +181 -0
  53. package/dist/chunk-ZWAFLHC2.cjs.map +1 -0
  54. package/dist/data.cjs +71 -0
  55. package/dist/data.cjs.map +1 -0
  56. package/dist/data.d.cts +316 -0
  57. package/dist/data.d.ts +316 -0
  58. package/dist/data.js +6 -0
  59. package/dist/data.js.map +1 -0
  60. package/dist/form.cjs +153 -0
  61. package/dist/form.cjs.map +1 -0
  62. package/dist/form.d.cts +660 -0
  63. package/dist/form.d.ts +660 -0
  64. package/dist/form.js +8 -0
  65. package/dist/form.js.map +1 -0
  66. package/dist/index.cjs +1641 -0
  67. package/dist/index.cjs.map +1 -0
  68. package/dist/index.d.cts +552 -0
  69. package/dist/index.d.ts +552 -0
  70. package/dist/index.js +956 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/layout.cjs +68 -0
  73. package/dist/layout.cjs.map +1 -0
  74. package/dist/layout.d.cts +169 -0
  75. package/dist/layout.d.ts +169 -0
  76. package/dist/layout.js +7 -0
  77. package/dist/layout.js.map +1 -0
  78. package/dist/motion-CQmCq6_k.d.ts +395 -0
  79. package/dist/motion-CSX4g2N8.d.cts +395 -0
  80. package/dist/motion.cjs +79 -0
  81. package/dist/motion.cjs.map +1 -0
  82. package/dist/motion.d.cts +4 -0
  83. package/dist/motion.d.ts +4 -0
  84. package/dist/motion.js +6 -0
  85. package/dist/motion.js.map +1 -0
  86. package/dist/navigation.cjs +48 -0
  87. package/dist/navigation.cjs.map +1 -0
  88. package/dist/navigation.d.cts +210 -0
  89. package/dist/navigation.d.ts +210 -0
  90. package/dist/navigation.js +7 -0
  91. package/dist/navigation.js.map +1 -0
  92. package/dist/overlay.cjs +69 -0
  93. package/dist/overlay.cjs.map +1 -0
  94. package/dist/overlay.d.cts +330 -0
  95. package/dist/overlay.d.ts +330 -0
  96. package/dist/overlay.js +8 -0
  97. package/dist/overlay.js.map +1 -0
  98. package/dist/position-DVScKcaa.d.cts +66 -0
  99. package/dist/position-DVScKcaa.d.ts +66 -0
  100. package/dist/primitives.cjs +162 -0
  101. package/dist/primitives.cjs.map +1 -0
  102. package/dist/primitives.d.cts +294 -0
  103. package/dist/primitives.d.ts +294 -0
  104. package/dist/primitives.js +9 -0
  105. package/dist/primitives.js.map +1 -0
  106. package/dist/sidebar-D-PafAXw.d.cts +71 -0
  107. package/dist/sidebar-D-PafAXw.d.ts +71 -0
  108. package/dist/styles.css +5575 -0
  109. package/dist/use-observers-B9qtimrk.d.cts +99 -0
  110. package/dist/use-observers-B9qtimrk.d.ts +99 -0
  111. package/package.json +92 -0
@@ -0,0 +1,2976 @@
1
+ 'use strict';
2
+
3
+ var chunkXMXECSQO_cjs = require('./chunk-XMXECSQO.cjs');
4
+ var chunkPO5DU3FU_cjs = require('./chunk-PO5DU3FU.cjs');
5
+ var chunk6VRF7X5C_cjs = require('./chunk-6VRF7X5C.cjs');
6
+ var chunkSFU5EPSN_cjs = require('./chunk-SFU5EPSN.cjs');
7
+ var react = require('react');
8
+ var jsxRuntime = require('react/jsx-runtime');
9
+ var core = require('@ansh-ui/core');
10
+
11
+ var FieldContext = react.createContext(null);
12
+ function useFieldControl() {
13
+ const field = react.useContext(FieldContext);
14
+ if (!field) return {};
15
+ return {
16
+ id: field.id,
17
+ ...field.describedBy ? { "aria-describedby": field.describedBy } : null,
18
+ ...field.invalid ? { "aria-invalid": true } : null,
19
+ ...field.required ? { "aria-required": true } : null,
20
+ ...field.disabled ? { disabled: true } : null
21
+ };
22
+ }
23
+ function useFieldContext() {
24
+ return react.useContext(FieldContext);
25
+ }
26
+ function Field({
27
+ label,
28
+ description,
29
+ error,
30
+ required = false,
31
+ disabled = false,
32
+ orientation = "vertical",
33
+ className,
34
+ children
35
+ }) {
36
+ const id = react.useId();
37
+ const descriptionId = `${id}-description`;
38
+ const errorId = `${id}-error`;
39
+ const describedBy = [error ? errorId : null, description ? descriptionId : null].filter(Boolean).join(" ") || void 0;
40
+ return /* @__PURE__ */ jsxRuntime.jsx(FieldContext.Provider, { value: { id, describedBy, invalid: Boolean(error), required, disabled }, children: /* @__PURE__ */ jsxRuntime.jsxs(
41
+ "div",
42
+ {
43
+ className: chunkSFU5EPSN_cjs.cx(
44
+ "ansh-field",
45
+ `ansh-field--${orientation}`,
46
+ disabled && "ansh-field--disabled",
47
+ className
48
+ ),
49
+ children: [
50
+ label ? /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "ansh-field__label", htmlFor: id, children: [
51
+ label,
52
+ required ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
53
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "ansh-field__required", children: "*" }),
54
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-visually-hidden", children: " (required)" })
55
+ ] }) : null
56
+ ] }) : null,
57
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ansh-field__control", children }),
58
+ description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "ansh-field__description", id: descriptionId, children: description }) : null,
59
+ error ? (
60
+ // `role="alert"` announces the message when it appears after a failed submit, which is
61
+ // the moment it matters. `aria-describedby` alone would only be read on re-focus.
62
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "ansh-field__error", id: errorId, role: "alert", children: error })
63
+ ) : null
64
+ ]
65
+ }
66
+ ) });
67
+ }
68
+ function Fieldset({ legend, description, className, children }) {
69
+ const id = react.useId();
70
+ return /* @__PURE__ */ jsxRuntime.jsxs(
71
+ "fieldset",
72
+ {
73
+ className: chunkSFU5EPSN_cjs.cx("ansh-fieldset", className),
74
+ ...description ? { "aria-describedby": id } : null,
75
+ children: [
76
+ /* @__PURE__ */ jsxRuntime.jsx("legend", { className: "ansh-fieldset__legend", children: legend }),
77
+ description ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "ansh-fieldset__description", id, children: description }) : null,
78
+ children
79
+ ]
80
+ }
81
+ );
82
+ }
83
+ function VisuallyHidden({
84
+ children,
85
+ ...rest
86
+ }) {
87
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-visually-hidden", ...rest, children });
88
+ }
89
+ var Input = react.forwardRef(function Input2({
90
+ size = "md",
91
+ prefix,
92
+ suffix,
93
+ clearable = false,
94
+ onClear,
95
+ invalid,
96
+ className,
97
+ wrapperClassName,
98
+ disabled,
99
+ ...rest
100
+ }, forwardedRef) {
101
+ const fieldProps = useFieldControl();
102
+ const localRef = react.useRef(null);
103
+ const ref = chunk6VRF7X5C_cjs.useMergedRef(localRef, forwardedRef);
104
+ const [hasValue, setHasValue] = react.useState(
105
+ () => String(rest.value ?? rest.defaultValue ?? "").length > 0
106
+ );
107
+ react.useEffect(() => {
108
+ if (rest.value !== void 0) setHasValue(String(rest.value).length > 0);
109
+ }, [rest.value]);
110
+ const showClear = clearable && hasValue && !disabled && !rest.readOnly;
111
+ const grouped = Boolean(prefix || suffix || clearable);
112
+ const control = /* @__PURE__ */ jsxRuntime.jsx(
113
+ "input",
114
+ {
115
+ ref,
116
+ className: chunkSFU5EPSN_cjs.cx("ansh-input", `ansh-input--${size}`, !grouped && className),
117
+ disabled,
118
+ ...fieldProps,
119
+ ...rest,
120
+ ...invalid ? { "aria-invalid": true } : null,
121
+ onChange: (event) => {
122
+ setHasValue(event.target.value.length > 0);
123
+ rest.onChange?.(event);
124
+ }
125
+ }
126
+ );
127
+ if (!grouped) return control;
128
+ return /* @__PURE__ */ jsxRuntime.jsxs(
129
+ "div",
130
+ {
131
+ className: chunkSFU5EPSN_cjs.cx(
132
+ "ansh-input-group",
133
+ `ansh-input-group--${size}`,
134
+ disabled && "ansh-input-group--disabled",
135
+ (invalid || fieldProps["aria-invalid"]) && "ansh-input-group--invalid",
136
+ wrapperClassName,
137
+ className
138
+ ),
139
+ onMouseDown: (event) => {
140
+ if (event.target === event.currentTarget) {
141
+ event.preventDefault();
142
+ localRef.current?.focus();
143
+ }
144
+ },
145
+ children: [
146
+ prefix ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-input-group__affix", "aria-hidden": "true", children: prefix }) : null,
147
+ control,
148
+ showClear ? /* @__PURE__ */ jsxRuntime.jsx(
149
+ "button",
150
+ {
151
+ type: "button",
152
+ className: "ansh-input-group__clear ansh-focusable",
153
+ "aria-label": "Clear",
154
+ onClick: () => {
155
+ const node = localRef.current;
156
+ if (node) {
157
+ const setter = Object.getOwnPropertyDescriptor(
158
+ window.HTMLInputElement.prototype,
159
+ "value"
160
+ )?.set;
161
+ setter?.call(node, "");
162
+ node.dispatchEvent(new Event("input", { bubbles: true }));
163
+ node.focus();
164
+ }
165
+ setHasValue(false);
166
+ onClear?.();
167
+ },
168
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 16 16", width: "12", height: "12", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(
169
+ "path",
170
+ {
171
+ d: "M4 4l8 8M12 4l-8 8",
172
+ stroke: "currentColor",
173
+ strokeWidth: "1.75",
174
+ strokeLinecap: "round",
175
+ fill: "none"
176
+ }
177
+ ) })
178
+ }
179
+ ) : null,
180
+ suffix ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-input-group__affix", children: suffix }) : null
181
+ ]
182
+ }
183
+ );
184
+ });
185
+ var Textarea = react.forwardRef(function Textarea2({
186
+ autoResize = false,
187
+ maxRows = 12,
188
+ showCount = false,
189
+ invalid,
190
+ className,
191
+ ...rest
192
+ }, forwardedRef) {
193
+ const fieldProps = useFieldControl();
194
+ const localRef = react.useRef(null);
195
+ const ref = chunk6VRF7X5C_cjs.useMergedRef(localRef, forwardedRef);
196
+ const [count, setCount] = react.useState(() => String(rest.value ?? rest.defaultValue ?? "").length);
197
+ const resize = react.useCallback(() => {
198
+ const node = localRef.current;
199
+ if (!node || !autoResize) return;
200
+ node.style.height = "auto";
201
+ const lineHeight = Number.parseFloat(getComputedStyle(node).lineHeight) || 20;
202
+ const max = lineHeight * maxRows;
203
+ node.style.height = `${Math.min(node.scrollHeight, max)}px`;
204
+ node.style.overflowY = node.scrollHeight > max ? "auto" : "hidden";
205
+ }, [autoResize, maxRows]);
206
+ react.useEffect(resize, [resize, rest.value]);
207
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkSFU5EPSN_cjs.cx("ansh-textarea-wrap", className), children: [
208
+ /* @__PURE__ */ jsxRuntime.jsx(
209
+ "textarea",
210
+ {
211
+ ref,
212
+ className: chunkSFU5EPSN_cjs.cx("ansh-input", "ansh-textarea", autoResize && "ansh-textarea--auto"),
213
+ ...fieldProps,
214
+ ...rest,
215
+ ...invalid ? { "aria-invalid": true } : null,
216
+ onChange: (event) => {
217
+ setCount(event.target.value.length);
218
+ resize();
219
+ rest.onChange?.(event);
220
+ }
221
+ }
222
+ ),
223
+ showCount ? /* @__PURE__ */ jsxRuntime.jsx(
224
+ "span",
225
+ {
226
+ className: chunkSFU5EPSN_cjs.cx(
227
+ "ansh-textarea__count",
228
+ rest.maxLength !== void 0 && count > rest.maxLength * 0.9 && "ansh-textarea__count--near"
229
+ ),
230
+ "aria-live": "polite",
231
+ children: rest.maxLength !== void 0 ? `${count} / ${rest.maxLength}` : count
232
+ }
233
+ ) : null
234
+ ] });
235
+ });
236
+ var NumberInput = react.forwardRef(function NumberInput2({
237
+ value,
238
+ defaultValue = 0,
239
+ onChange,
240
+ min = Number.NEGATIVE_INFINITY,
241
+ max = Number.POSITIVE_INFINITY,
242
+ step = 1,
243
+ precision,
244
+ size = "md",
245
+ unit,
246
+ steppers = true,
247
+ className,
248
+ disabled,
249
+ ...rest
250
+ }, forwardedRef) {
251
+ const fieldProps = useFieldControl();
252
+ const [current, setCurrent] = chunkPO5DU3FU_cjs.useControllableState({
253
+ value,
254
+ defaultValue,
255
+ onChange
256
+ });
257
+ const decimals = precision ?? (String(step).includes(".") ? String(step).split(".")[1].length : 0);
258
+ const [text, setText] = react.useState(() => current.toFixed(decimals));
259
+ const [editing, setEditing] = react.useState(false);
260
+ react.useEffect(() => {
261
+ if (!editing) setText(current.toFixed(decimals));
262
+ }, [current, decimals, editing]);
263
+ const clamp = (n) => Math.min(Math.max(n, min), max);
264
+ const nudge = (direction, multiplier = 1) => {
265
+ const next = clamp(current + step * direction * multiplier);
266
+ setCurrent(Number(next.toFixed(decimals)));
267
+ };
268
+ const commit = (raw) => {
269
+ const parsed = Number.parseFloat(raw);
270
+ const next = Number.isFinite(parsed) ? clamp(parsed) : current;
271
+ setCurrent(Number(next.toFixed(decimals)));
272
+ setText(next.toFixed(decimals));
273
+ };
274
+ return /* @__PURE__ */ jsxRuntime.jsxs(
275
+ "div",
276
+ {
277
+ className: chunkSFU5EPSN_cjs.cx(
278
+ "ansh-number",
279
+ `ansh-number--${size}`,
280
+ disabled && "ansh-number--disabled",
281
+ className
282
+ ),
283
+ children: [
284
+ /* @__PURE__ */ jsxRuntime.jsx(
285
+ "input",
286
+ {
287
+ ref: forwardedRef,
288
+ type: "text",
289
+ inputMode: "decimal",
290
+ className: "ansh-input ansh-number__input",
291
+ value: text,
292
+ disabled,
293
+ role: "spinbutton",
294
+ "aria-valuenow": current,
295
+ ...Number.isFinite(min) ? { "aria-valuemin": min } : null,
296
+ ...Number.isFinite(max) ? { "aria-valuemax": max } : null,
297
+ ...fieldProps,
298
+ ...rest,
299
+ onFocus: (event) => {
300
+ setEditing(true);
301
+ rest.onFocus?.(event);
302
+ },
303
+ onChange: (event) => setText(event.target.value),
304
+ onBlur: (event) => {
305
+ setEditing(false);
306
+ commit(event.target.value);
307
+ rest.onBlur?.(event);
308
+ },
309
+ onKeyDown: (event) => {
310
+ if (event.key === "ArrowUp") {
311
+ event.preventDefault();
312
+ nudge(1, event.shiftKey ? 10 : 1);
313
+ } else if (event.key === "ArrowDown") {
314
+ event.preventDefault();
315
+ nudge(-1, event.shiftKey ? 10 : 1);
316
+ } else if (event.key === "PageUp") {
317
+ event.preventDefault();
318
+ nudge(1, 10);
319
+ } else if (event.key === "PageDown") {
320
+ event.preventDefault();
321
+ nudge(-1, 10);
322
+ } else if (event.key === "Home" && Number.isFinite(min)) {
323
+ event.preventDefault();
324
+ setCurrent(min);
325
+ } else if (event.key === "End" && Number.isFinite(max)) {
326
+ event.preventDefault();
327
+ setCurrent(max);
328
+ } else if (event.key === "Enter") {
329
+ commit(event.target.value);
330
+ }
331
+ rest.onKeyDown?.(event);
332
+ }
333
+ }
334
+ ),
335
+ unit ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-number__unit", children: unit }) : null,
336
+ steppers ? (
337
+ // `tabIndex={-1}` and `aria-hidden`: the input is already a spinbutton with arrow-key
338
+ // support, so these buttons would be redundant tab stops announcing nothing new.
339
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ansh-number__steppers", "aria-hidden": "true", children: [
340
+ /* @__PURE__ */ jsxRuntime.jsx(
341
+ "button",
342
+ {
343
+ type: "button",
344
+ tabIndex: -1,
345
+ className: "ansh-number__step",
346
+ disabled: disabled || current >= max,
347
+ onClick: () => nudge(1),
348
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 10 6", width: "10", height: "6", children: /* @__PURE__ */ jsxRuntime.jsx(
349
+ "path",
350
+ {
351
+ d: "M1 5l4-4 4 4",
352
+ stroke: "currentColor",
353
+ strokeWidth: "1.5",
354
+ fill: "none",
355
+ strokeLinecap: "round"
356
+ }
357
+ ) })
358
+ }
359
+ ),
360
+ /* @__PURE__ */ jsxRuntime.jsx(
361
+ "button",
362
+ {
363
+ type: "button",
364
+ tabIndex: -1,
365
+ className: "ansh-number__step",
366
+ disabled: disabled || current <= min,
367
+ onClick: () => nudge(-1),
368
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 10 6", width: "10", height: "6", children: /* @__PURE__ */ jsxRuntime.jsx(
369
+ "path",
370
+ {
371
+ d: "M1 1l4 4 4-4",
372
+ stroke: "currentColor",
373
+ strokeWidth: "1.5",
374
+ fill: "none",
375
+ strokeLinecap: "round"
376
+ }
377
+ ) })
378
+ }
379
+ )
380
+ ] })
381
+ ) : null
382
+ ]
383
+ }
384
+ );
385
+ });
386
+ var Checkbox = react.forwardRef(function Checkbox2({
387
+ checked,
388
+ defaultChecked = false,
389
+ onChange,
390
+ indeterminate = false,
391
+ label,
392
+ description,
393
+ size = "md",
394
+ invalid,
395
+ className,
396
+ disabled,
397
+ ...rest
398
+ }, forwardedRef) {
399
+ const fieldProps = useFieldControl();
400
+ const localRef = react.useRef(null);
401
+ const ref = chunk6VRF7X5C_cjs.useMergedRef(localRef, forwardedRef);
402
+ const generatedId = react.useId();
403
+ const id = rest.id ?? fieldProps.id ?? generatedId;
404
+ const descriptionId = `${id}-hint`;
405
+ const [isChecked, setChecked] = chunkPO5DU3FU_cjs.useControllableState({
406
+ value: checked,
407
+ defaultValue: defaultChecked,
408
+ onChange
409
+ });
410
+ react.useEffect(() => {
411
+ if (localRef.current) localRef.current.indeterminate = indeterminate;
412
+ }, [indeterminate]);
413
+ return /* @__PURE__ */ jsxRuntime.jsxs(
414
+ "div",
415
+ {
416
+ className: chunkSFU5EPSN_cjs.cx(
417
+ "ansh-choice",
418
+ `ansh-choice--${size}`,
419
+ disabled && "ansh-choice--disabled",
420
+ className
421
+ ),
422
+ children: [
423
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ansh-choice__box", children: [
424
+ /* @__PURE__ */ jsxRuntime.jsx(
425
+ "input",
426
+ {
427
+ ref,
428
+ type: "checkbox",
429
+ className: "ansh-choice__input",
430
+ checked: isChecked,
431
+ disabled: disabled ?? fieldProps.disabled,
432
+ onChange: (event) => setChecked(event.target.checked),
433
+ ...indeterminate ? { "aria-checked": "mixed" } : null,
434
+ ...invalid ? { "aria-invalid": true } : null,
435
+ ...description ? { "aria-describedby": descriptionId } : null,
436
+ ...rest,
437
+ id
438
+ }
439
+ ),
440
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-choice__indicator ansh-choice__indicator--check", "aria-hidden": "true", children: indeterminate ? /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 14 14", width: "10", height: "10", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 7h8", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) : /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 14 14", width: "10", height: "10", children: /* @__PURE__ */ jsxRuntime.jsx(
441
+ "path",
442
+ {
443
+ d: "M2.5 7.5l3 3 6-6.5",
444
+ stroke: "currentColor",
445
+ strokeWidth: "2",
446
+ strokeLinecap: "round",
447
+ strokeLinejoin: "round",
448
+ fill: "none"
449
+ }
450
+ ) }) })
451
+ ] }),
452
+ label || description ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ansh-choice__text", children: [
453
+ label ? /* @__PURE__ */ jsxRuntime.jsx("label", { className: "ansh-choice__label", htmlFor: id, children: label }) : null,
454
+ description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-choice__description", id: descriptionId, children: description }) : null
455
+ ] }) : null
456
+ ]
457
+ }
458
+ );
459
+ });
460
+ var Switch = react.forwardRef(function Switch2({
461
+ checked,
462
+ defaultChecked = false,
463
+ onChange,
464
+ label,
465
+ description,
466
+ labelPosition = "end",
467
+ size = "md",
468
+ className,
469
+ disabled,
470
+ ...rest
471
+ }, forwardedRef) {
472
+ const fieldProps = useFieldControl();
473
+ const generatedId = react.useId();
474
+ const id = rest.id ?? fieldProps.id ?? generatedId;
475
+ const descriptionId = `${id}-hint`;
476
+ const [isChecked, setChecked] = chunkPO5DU3FU_cjs.useControllableState({
477
+ value: checked,
478
+ defaultValue: defaultChecked,
479
+ onChange
480
+ });
481
+ return /* @__PURE__ */ jsxRuntime.jsxs(
482
+ "div",
483
+ {
484
+ className: chunkSFU5EPSN_cjs.cx(
485
+ "ansh-switch-row",
486
+ `ansh-switch-row--${labelPosition}`,
487
+ disabled && "ansh-choice--disabled",
488
+ className
489
+ ),
490
+ children: [
491
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ansh-switch", "data-size": size, children: [
492
+ /* @__PURE__ */ jsxRuntime.jsx(
493
+ "input",
494
+ {
495
+ ref: forwardedRef,
496
+ type: "checkbox",
497
+ role: "switch",
498
+ className: "ansh-choice__input",
499
+ checked: isChecked,
500
+ disabled: disabled ?? fieldProps.disabled,
501
+ onChange: (event) => setChecked(event.target.checked),
502
+ ...description ? { "aria-describedby": descriptionId } : null,
503
+ ...rest,
504
+ id
505
+ }
506
+ ),
507
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-switch__track", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-switch__thumb" }) })
508
+ ] }),
509
+ label || description ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ansh-choice__text", children: [
510
+ label ? /* @__PURE__ */ jsxRuntime.jsx("label", { className: "ansh-choice__label", htmlFor: id, children: label }) : null,
511
+ description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-choice__description", id: descriptionId, children: description }) : null
512
+ ] }) : null
513
+ ]
514
+ }
515
+ );
516
+ });
517
+ var RadioGroupContext = react.createContext(null);
518
+ function RadioGroup({
519
+ value,
520
+ defaultValue,
521
+ onChange,
522
+ name,
523
+ label,
524
+ orientation = "vertical",
525
+ disabled = false,
526
+ className,
527
+ children
528
+ }) {
529
+ const generatedName = react.useId();
530
+ const [current, setCurrent] = chunkPO5DU3FU_cjs.useControllableState({
531
+ value,
532
+ defaultValue,
533
+ onChange
534
+ });
535
+ return /* @__PURE__ */ jsxRuntime.jsx(
536
+ RadioGroupContext.Provider,
537
+ {
538
+ value: {
539
+ name: name ?? generatedName,
540
+ value: current,
541
+ setValue: setCurrent,
542
+ disabled
543
+ },
544
+ children: /* @__PURE__ */ jsxRuntime.jsx(
545
+ "div",
546
+ {
547
+ role: "radiogroup",
548
+ ...label && typeof label === "string" ? { "aria-label": label } : null,
549
+ className: chunkSFU5EPSN_cjs.cx("ansh-radio-group", `ansh-radio-group--${orientation}`, className),
550
+ children
551
+ }
552
+ )
553
+ }
554
+ );
555
+ }
556
+ var Radio = react.forwardRef(function Radio2({ value, label, description, size = "md", className, disabled, ...rest }, forwardedRef) {
557
+ const group = react.useContext(RadioGroupContext);
558
+ const generatedId = react.useId();
559
+ const id = rest.id ?? generatedId;
560
+ const descriptionId = `${id}-hint`;
561
+ const isDisabled = disabled || group?.disabled;
562
+ return /* @__PURE__ */ jsxRuntime.jsxs(
563
+ "div",
564
+ {
565
+ className: chunkSFU5EPSN_cjs.cx(
566
+ "ansh-choice",
567
+ `ansh-choice--${size}`,
568
+ isDisabled && "ansh-choice--disabled",
569
+ className
570
+ ),
571
+ children: [
572
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ansh-choice__box", children: [
573
+ /* @__PURE__ */ jsxRuntime.jsx(
574
+ "input",
575
+ {
576
+ ref: forwardedRef,
577
+ type: "radio",
578
+ className: "ansh-choice__input",
579
+ name: group?.name,
580
+ value,
581
+ checked: group ? group.value === value : void 0,
582
+ disabled: isDisabled,
583
+ onChange: () => group?.setValue(value),
584
+ ...description ? { "aria-describedby": descriptionId } : null,
585
+ ...rest,
586
+ id
587
+ }
588
+ ),
589
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-choice__indicator ansh-choice__indicator--dot", "aria-hidden": "true" })
590
+ ] }),
591
+ label || description ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ansh-choice__text", children: [
592
+ label ? /* @__PURE__ */ jsxRuntime.jsx("label", { className: "ansh-choice__label", htmlFor: id, children: label }) : null,
593
+ description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-choice__description", id: descriptionId, children: description }) : null
594
+ ] }) : null
595
+ ]
596
+ }
597
+ );
598
+ });
599
+ var ChoiceCard = react.forwardRef(function ChoiceCard2({ icon, label, description, value, className, ...rest }, forwardedRef) {
600
+ const group = react.useContext(RadioGroupContext);
601
+ const selected = group?.value === value;
602
+ return /* @__PURE__ */ jsxRuntime.jsxs("label", { className: chunkSFU5EPSN_cjs.cx("ansh-choice-card", selected && "ansh-choice-card--selected", className), children: [
603
+ /* @__PURE__ */ jsxRuntime.jsx(Radio, { ref: forwardedRef, value, className: "ansh-choice-card__radio", ...rest }),
604
+ icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-choice-card__icon", children: icon }) : null,
605
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ansh-choice-card__body", children: [
606
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-choice-card__label", children: label }),
607
+ description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-choice-card__description", children: description }) : null
608
+ ] })
609
+ ] });
610
+ });
611
+ function stepActive(options, active, delta, loop = true) {
612
+ if (options.length === 0) return -1;
613
+ let index = active;
614
+ for (let attempts = 0; attempts < options.length; attempts++) {
615
+ index += delta;
616
+ if (index < 0) {
617
+ if (!loop) return active;
618
+ index = options.length - 1;
619
+ }
620
+ if (index >= options.length) {
621
+ if (!loop) return active;
622
+ index = 0;
623
+ }
624
+ if (!options[index]?.disabled) return index;
625
+ }
626
+ return active;
627
+ }
628
+ function firstEnabled(options, from = 0) {
629
+ for (let i = from; i < options.length; i++) {
630
+ if (!options[i]?.disabled) return i;
631
+ }
632
+ return -1;
633
+ }
634
+ function useTypeahead(options, onMatch, timeout = 600) {
635
+ const bufferRef = react.useRef("");
636
+ const timerRef = react.useRef(void 0);
637
+ return react.useCallback(
638
+ (key) => {
639
+ if (key.length !== 1 || key === " ") return false;
640
+ clearTimeout(timerRef.current);
641
+ bufferRef.current += key.toLowerCase();
642
+ timerRef.current = setTimeout(() => {
643
+ bufferRef.current = "";
644
+ }, timeout);
645
+ const buffer = bufferRef.current;
646
+ const index = options.findIndex(
647
+ (option) => !option.disabled && option.label.toLowerCase().startsWith(buffer)
648
+ );
649
+ if (index >= 0) {
650
+ onMatch(index);
651
+ return true;
652
+ }
653
+ return false;
654
+ },
655
+ [options, onMatch, timeout]
656
+ );
657
+ }
658
+ function scoreOption(query, option) {
659
+ if (query.trim() === "") return 0;
660
+ const q = query.toLowerCase();
661
+ const haystacks = [option.label, option.keywords ?? "", option.description ?? ""];
662
+ let best = -1;
663
+ for (let h = 0; h < haystacks.length; h++) {
664
+ const text = haystacks[h].toLowerCase();
665
+ let queryIndex = 0;
666
+ let total = 0;
667
+ let run = 0;
668
+ for (let i = 0; i < text.length && queryIndex < q.length; i++) {
669
+ if (text[i] === q[queryIndex]) {
670
+ run++;
671
+ total += run * 2 + (i === 0 ? 8 : 0);
672
+ queryIndex++;
673
+ } else {
674
+ run = 0;
675
+ }
676
+ }
677
+ if (queryIndex === q.length) best = Math.max(best, total - h * 4);
678
+ }
679
+ return best;
680
+ }
681
+ function filterOptions(options, query) {
682
+ if (query.trim() === "") return options;
683
+ return options.map((option) => ({ option, score: scoreOption(query, option) })).filter((entry) => entry.score >= 0).sort((a, b) => b.score - a.score).map((entry) => entry.option);
684
+ }
685
+ function OptionList({
686
+ options,
687
+ active,
688
+ selected,
689
+ listId,
690
+ multiple = false,
691
+ emptyMessage = "No results",
692
+ onSelect,
693
+ onActiveChange,
694
+ query
695
+ }) {
696
+ const selectedSet = react.useMemo(() => new Set(selected), [selected]);
697
+ if (options.length === 0) {
698
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ansh-listbox__empty", children: emptyMessage });
699
+ }
700
+ let lastGroup;
701
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: options.map((option, index) => {
702
+ const heading = option.group && option.group !== lastGroup ? option.group : null;
703
+ lastGroup = option.group;
704
+ const isSelected = selectedSet.has(option.value);
705
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "presentation", children: [
706
+ heading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ansh-listbox__group", role: "presentation", children: heading }) : null,
707
+ /* @__PURE__ */ jsxRuntime.jsxs(
708
+ "div",
709
+ {
710
+ id: `${listId}-option-${index}`,
711
+ role: "option",
712
+ "aria-selected": isSelected,
713
+ "aria-disabled": option.disabled || void 0,
714
+ className: chunkSFU5EPSN_cjs.cx(
715
+ "ansh-listbox__option",
716
+ index === active && "ansh-listbox__option--active",
717
+ isSelected && "ansh-listbox__option--selected",
718
+ option.disabled && "ansh-listbox__option--disabled"
719
+ ),
720
+ onMouseDown: (event) => event.preventDefault(),
721
+ onMouseEnter: () => !option.disabled && onActiveChange(index),
722
+ onClick: () => !option.disabled && onSelect(option),
723
+ children: [
724
+ multiple ? /* @__PURE__ */ jsxRuntime.jsx(
725
+ "span",
726
+ {
727
+ className: chunkSFU5EPSN_cjs.cx("ansh-listbox__check", isSelected && "ansh-listbox__check--on"),
728
+ "aria-hidden": "true",
729
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 14 14", width: "10", height: "10", children: /* @__PURE__ */ jsxRuntime.jsx(
730
+ "path",
731
+ {
732
+ d: "M2.5 7.5l3 3 6-6.5",
733
+ stroke: "currentColor",
734
+ strokeWidth: "2",
735
+ strokeLinecap: "round",
736
+ strokeLinejoin: "round",
737
+ fill: "none"
738
+ }
739
+ ) })
740
+ }
741
+ ) : null,
742
+ option.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-listbox__icon", children: option.icon }) : null,
743
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ansh-listbox__text", children: [
744
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-listbox__label", children: query ? /* @__PURE__ */ jsxRuntime.jsx(Highlight, { text: option.label, query }) : option.label }),
745
+ option.description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-listbox__description", children: option.description }) : null
746
+ ] }),
747
+ !multiple && isSelected ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-listbox__tick", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 14 14", width: "12", height: "12", children: /* @__PURE__ */ jsxRuntime.jsx(
748
+ "path",
749
+ {
750
+ d: "M2.5 7.5l3 3 6-6.5",
751
+ stroke: "currentColor",
752
+ strokeWidth: "2",
753
+ strokeLinecap: "round",
754
+ strokeLinejoin: "round",
755
+ fill: "none"
756
+ }
757
+ ) }) }) : null
758
+ ]
759
+ }
760
+ )
761
+ ] }, option.value);
762
+ }) });
763
+ }
764
+ function Highlight({ text, query }) {
765
+ const q = query.toLowerCase();
766
+ const lower = text.toLowerCase();
767
+ const parts = [];
768
+ let queryIndex = 0;
769
+ let plain = "";
770
+ for (let i = 0; i < text.length; i++) {
771
+ if (queryIndex < q.length && lower[i] === q[queryIndex]) {
772
+ if (plain) {
773
+ parts.push(plain);
774
+ plain = "";
775
+ }
776
+ parts.push(
777
+ /* @__PURE__ */ jsxRuntime.jsx("mark", { className: "ansh-listbox__mark", children: text[i] }, i)
778
+ );
779
+ queryIndex++;
780
+ } else {
781
+ plain += text[i];
782
+ }
783
+ }
784
+ if (plain) parts.push(plain);
785
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: parts });
786
+ }
787
+ function Select({
788
+ options,
789
+ value,
790
+ defaultValue = null,
791
+ onChange,
792
+ placeholder = "Select\u2026",
793
+ disabled = false,
794
+ invalid = false,
795
+ size = "md",
796
+ clearable = false,
797
+ label,
798
+ className,
799
+ name,
800
+ maxHeight = "18rem",
801
+ emptyMessage
802
+ }) {
803
+ const fieldProps = useFieldControl();
804
+ const [open, setOpen] = react.useState(false);
805
+ const [current, setCurrent] = chunkPO5DU3FU_cjs.useControllableState({
806
+ value,
807
+ defaultValue,
808
+ onChange
809
+ });
810
+ const triggerRef = react.useRef(null);
811
+ const listRef = react.useRef(null);
812
+ const listId = react.useId();
813
+ const selectedIndex = react.useMemo(
814
+ () => options.findIndex((option) => option.value === current),
815
+ [options, current]
816
+ );
817
+ const selected = selectedIndex >= 0 ? options[selectedIndex] : void 0;
818
+ const [active, setActive] = react.useState(0);
819
+ const position = chunkXMXECSQO_cjs.useAnchoredPosition(triggerRef, listRef, open, {
820
+ placement: "bottom-start",
821
+ offset: 6,
822
+ matchWidth: true
823
+ });
824
+ chunkXMXECSQO_cjs.useDismiss(listRef, open, () => setOpen(false), { ignore: [triggerRef] });
825
+ const openList = react.useCallback(() => {
826
+ if (disabled) return;
827
+ setActive(selectedIndex >= 0 ? selectedIndex : firstEnabled(options));
828
+ setOpen(true);
829
+ }, [disabled, selectedIndex, options]);
830
+ const commit = react.useCallback(
831
+ (option) => {
832
+ setCurrent(option.value);
833
+ setOpen(false);
834
+ triggerRef.current?.focus();
835
+ },
836
+ [setCurrent]
837
+ );
838
+ const typeahead = useTypeahead(options, (index) => {
839
+ setActive(index);
840
+ if (!open) setCurrent(options[index].value);
841
+ });
842
+ const onTriggerKeyDown = (event) => {
843
+ if (["ArrowDown", "ArrowUp", "Enter", " "].includes(event.key)) {
844
+ event.preventDefault();
845
+ openList();
846
+ return;
847
+ }
848
+ if (typeahead(event.key)) event.preventDefault();
849
+ };
850
+ const onListKeyDown = (event) => {
851
+ switch (event.key) {
852
+ case "ArrowDown":
853
+ event.preventDefault();
854
+ setActive((i) => stepActive(options, i, 1));
855
+ break;
856
+ case "ArrowUp":
857
+ event.preventDefault();
858
+ setActive((i) => stepActive(options, i, -1));
859
+ break;
860
+ case "Home":
861
+ event.preventDefault();
862
+ setActive(firstEnabled(options));
863
+ break;
864
+ case "End":
865
+ event.preventDefault();
866
+ setActive(stepActive(options, options.length, -1, false));
867
+ break;
868
+ case "Enter":
869
+ case " ": {
870
+ event.preventDefault();
871
+ const option = options[active];
872
+ if (option && !option.disabled) commit(option);
873
+ break;
874
+ }
875
+ case "Escape":
876
+ event.preventDefault();
877
+ setOpen(false);
878
+ triggerRef.current?.focus();
879
+ break;
880
+ case "Tab":
881
+ event.preventDefault();
882
+ setOpen(false);
883
+ triggerRef.current?.focus();
884
+ break;
885
+ default:
886
+ if (typeahead(event.key)) event.preventDefault();
887
+ }
888
+ };
889
+ const attachList = react.useCallback((node) => {
890
+ listRef.current = node;
891
+ node?.focus({ preventScroll: true });
892
+ }, []);
893
+ react.useEffect(() => {
894
+ if (!open) return;
895
+ document.getElementById(`${listId}-option-${active}`)?.scrollIntoView?.({ block: "nearest" });
896
+ }, [active, listId, open]);
897
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkSFU5EPSN_cjs.cx("ansh-select", `ansh-select--${size}`, className), children: [
898
+ /* @__PURE__ */ jsxRuntime.jsxs(
899
+ "button",
900
+ {
901
+ ref: triggerRef,
902
+ type: "button",
903
+ className: chunkSFU5EPSN_cjs.cx(
904
+ "ansh-select__trigger",
905
+ "ansh-focusable",
906
+ open && "ansh-select__trigger--open",
907
+ (invalid || fieldProps["aria-invalid"]) && "ansh-select__trigger--invalid",
908
+ !selected && "ansh-select__trigger--placeholder"
909
+ ),
910
+ disabled: disabled || fieldProps.disabled,
911
+ "aria-haspopup": "listbox",
912
+ "aria-expanded": open,
913
+ "aria-controls": open ? listId : void 0,
914
+ ...label ? { "aria-label": label } : null,
915
+ ...fieldProps,
916
+ onClick: () => open ? setOpen(false) : openList(),
917
+ onKeyDown: onTriggerKeyDown,
918
+ children: [
919
+ selected?.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-select__icon", children: selected.icon }) : null,
920
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-select__value", children: selected?.label ?? placeholder }),
921
+ clearable && selected && !disabled ? (
922
+ // A `<span role="button">` rather than a nested `<button>`: nesting interactive
923
+ // elements is invalid HTML and browsers resolve it by dropping the inner one.
924
+ /* @__PURE__ */ jsxRuntime.jsx(
925
+ "span",
926
+ {
927
+ role: "button",
928
+ tabIndex: -1,
929
+ "aria-label": "Clear selection",
930
+ className: "ansh-select__clear",
931
+ onClick: (event) => {
932
+ event.stopPropagation();
933
+ setCurrent(null);
934
+ },
935
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 16 16", width: "12", height: "12", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(
936
+ "path",
937
+ {
938
+ d: "M4 4l8 8M12 4l-8 8",
939
+ stroke: "currentColor",
940
+ strokeWidth: "1.75",
941
+ strokeLinecap: "round",
942
+ fill: "none"
943
+ }
944
+ ) })
945
+ }
946
+ )
947
+ ) : null,
948
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-select__arrow", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 12 12", width: "12", height: "12", children: /* @__PURE__ */ jsxRuntime.jsx(
949
+ "path",
950
+ {
951
+ d: "M3 4.5L6 7.5l3-3",
952
+ stroke: "currentColor",
953
+ strokeWidth: "1.5",
954
+ fill: "none",
955
+ strokeLinecap: "round",
956
+ strokeLinejoin: "round"
957
+ }
958
+ ) }) })
959
+ ]
960
+ }
961
+ ),
962
+ name ? /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: current ?? "" }) : null,
963
+ open ? /* @__PURE__ */ jsxRuntime.jsx(chunkXMXECSQO_cjs.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
964
+ "div",
965
+ {
966
+ ref: attachList,
967
+ id: listId,
968
+ role: "listbox",
969
+ tabIndex: -1,
970
+ "aria-activedescendant": options[active] ? `${listId}-option-${active}` : void 0,
971
+ ...label ? { "aria-label": label } : null,
972
+ className: "ansh-listbox",
973
+ style: { ...position.style, maxHeight },
974
+ "data-side": position.side,
975
+ onKeyDown: onListKeyDown,
976
+ children: /* @__PURE__ */ jsxRuntime.jsx(
977
+ OptionList,
978
+ {
979
+ options,
980
+ active,
981
+ selected: current ? [current] : [],
982
+ listId,
983
+ onSelect: commit,
984
+ onActiveChange: setActive,
985
+ ...emptyMessage !== void 0 ? { emptyMessage } : null
986
+ }
987
+ )
988
+ }
989
+ ) }) : null
990
+ ] });
991
+ }
992
+ function Combobox({
993
+ options,
994
+ value,
995
+ defaultValue = [],
996
+ onChange,
997
+ multiple = false,
998
+ placeholder = "Search\u2026",
999
+ disabled = false,
1000
+ invalid = false,
1001
+ size = "md",
1002
+ label,
1003
+ className,
1004
+ maxHeight = "18rem",
1005
+ emptyMessage,
1006
+ onCreate,
1007
+ createLabel = (query) => `Create \u201C${query}\u201D`,
1008
+ onSearch,
1009
+ filter = true,
1010
+ maxVisibleChips = Number.POSITIVE_INFINITY
1011
+ }) {
1012
+ const fieldProps = useFieldControl();
1013
+ const [open, setOpen] = react.useState(false);
1014
+ const [query, setQuery] = react.useState("");
1015
+ const [active, setActive] = react.useState(0);
1016
+ const [selected, setSelected] = chunkPO5DU3FU_cjs.useControllableState({
1017
+ value,
1018
+ defaultValue,
1019
+ onChange
1020
+ });
1021
+ const inputRef = react.useRef(null);
1022
+ const wrapRef = react.useRef(null);
1023
+ const listRef = react.useRef(null);
1024
+ const listId = react.useId();
1025
+ const visible = react.useMemo(
1026
+ () => filter ? filterOptions(options, query) : options,
1027
+ [options, query, filter]
1028
+ );
1029
+ const byValue = react.useMemo(() => new Map(options.map((o) => [o.value, o])), [options]);
1030
+ const canCreate = Boolean(onCreate) && query.trim().length > 0 && !options.some((option) => option.label.toLowerCase() === query.trim().toLowerCase());
1031
+ const CREATE_VALUE = "__au_create__";
1032
+ const rows = react.useMemo(
1033
+ () => canCreate ? [...visible, { value: CREATE_VALUE, label: createLabel(query.trim()) }] : visible,
1034
+ [visible, canCreate, createLabel, query]
1035
+ );
1036
+ const position = chunkXMXECSQO_cjs.useAnchoredPosition(wrapRef, listRef, open, {
1037
+ placement: "bottom-start",
1038
+ offset: 6,
1039
+ matchWidth: true
1040
+ });
1041
+ chunkXMXECSQO_cjs.useDismiss(listRef, open, () => setOpen(false), { ignore: [wrapRef] });
1042
+ react.useEffect(() => setActive(firstEnabled(rows)), [rows]);
1043
+ const toggle = react.useCallback(
1044
+ (option) => {
1045
+ let optionValue = option.value;
1046
+ if (optionValue === CREATE_VALUE && onCreate) {
1047
+ optionValue = onCreate(query.trim());
1048
+ }
1049
+ if (multiple) {
1050
+ const next = selected.includes(optionValue) ? selected.filter((v) => v !== optionValue) : [...selected, optionValue];
1051
+ setSelected(next);
1052
+ setQuery("");
1053
+ inputRef.current?.focus();
1054
+ } else {
1055
+ setSelected([optionValue]);
1056
+ setQuery("");
1057
+ setOpen(false);
1058
+ }
1059
+ },
1060
+ [multiple, onCreate, query, selected, setSelected]
1061
+ );
1062
+ const remove = react.useCallback(
1063
+ (optionValue) => setSelected(selected.filter((v) => v !== optionValue)),
1064
+ [selected, setSelected]
1065
+ );
1066
+ const onKeyDown = (event) => {
1067
+ switch (event.key) {
1068
+ case "ArrowDown":
1069
+ event.preventDefault();
1070
+ if (!open) {
1071
+ setOpen(true);
1072
+ return;
1073
+ }
1074
+ setActive((i) => stepActive(rows, i, 1));
1075
+ break;
1076
+ case "ArrowUp":
1077
+ event.preventDefault();
1078
+ if (!open) {
1079
+ setOpen(true);
1080
+ return;
1081
+ }
1082
+ setActive((i) => stepActive(rows, i, -1));
1083
+ break;
1084
+ case "Home":
1085
+ if (!open) return;
1086
+ event.preventDefault();
1087
+ setActive(firstEnabled(rows));
1088
+ break;
1089
+ case "End":
1090
+ if (!open) return;
1091
+ event.preventDefault();
1092
+ setActive(stepActive(rows, rows.length, -1, false));
1093
+ break;
1094
+ case "Enter": {
1095
+ if (!open) return;
1096
+ const option = rows[active];
1097
+ if (option && !option.disabled) {
1098
+ event.preventDefault();
1099
+ toggle(option);
1100
+ }
1101
+ break;
1102
+ }
1103
+ case "Escape":
1104
+ if (!open) return;
1105
+ event.preventDefault();
1106
+ setOpen(false);
1107
+ break;
1108
+ case "Backspace":
1109
+ if (multiple && query === "" && selected.length > 0) {
1110
+ remove(selected[selected.length - 1]);
1111
+ }
1112
+ break;
1113
+ }
1114
+ };
1115
+ react.useEffect(() => {
1116
+ if (!open) return;
1117
+ document.getElementById(`${listId}-option-${active}`)?.scrollIntoView?.({ block: "nearest" });
1118
+ }, [active, listId, open]);
1119
+ const chips = multiple ? selected : [];
1120
+ const overflow = Math.max(0, chips.length - maxVisibleChips);
1121
+ const shownChips = overflow > 0 ? chips.slice(0, maxVisibleChips) : chips;
1122
+ const singleLabel = !multiple && selected[0] ? byValue.get(selected[0])?.label ?? "" : "";
1123
+ const inputValue = open || multiple ? query : singleLabel;
1124
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkSFU5EPSN_cjs.cx("ansh-combobox", `ansh-combobox--${size}`, className), children: [
1125
+ /* @__PURE__ */ jsxRuntime.jsxs(
1126
+ "div",
1127
+ {
1128
+ ref: wrapRef,
1129
+ className: chunkSFU5EPSN_cjs.cx(
1130
+ "ansh-combobox__control",
1131
+ "ansh-focusable-within",
1132
+ open && "ansh-combobox__control--open",
1133
+ (invalid || fieldProps["aria-invalid"]) && "ansh-combobox__control--invalid",
1134
+ disabled && "ansh-combobox__control--disabled"
1135
+ ),
1136
+ onMouseDown: (event) => {
1137
+ if (event.target === event.currentTarget) {
1138
+ event.preventDefault();
1139
+ inputRef.current?.focus();
1140
+ setOpen(true);
1141
+ }
1142
+ },
1143
+ children: [
1144
+ shownChips.map((chipValue) => {
1145
+ const option = byValue.get(chipValue);
1146
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ansh-chip", children: [
1147
+ option?.icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-chip__icon", children: option.icon }) : null,
1148
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-chip__label", children: option?.label ?? chipValue }),
1149
+ /* @__PURE__ */ jsxRuntime.jsx(
1150
+ "button",
1151
+ {
1152
+ type: "button",
1153
+ className: "ansh-chip__remove",
1154
+ "aria-label": `Remove ${option?.label ?? chipValue}`,
1155
+ disabled,
1156
+ onClick: () => remove(chipValue),
1157
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 16 16", width: "10", height: "10", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(
1158
+ "path",
1159
+ {
1160
+ d: "M4 4l8 8M12 4l-8 8",
1161
+ stroke: "currentColor",
1162
+ strokeWidth: "2",
1163
+ strokeLinecap: "round",
1164
+ fill: "none"
1165
+ }
1166
+ ) })
1167
+ }
1168
+ )
1169
+ ] }, chipValue);
1170
+ }),
1171
+ overflow > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ansh-chip ansh-chip--count", children: [
1172
+ "+",
1173
+ overflow
1174
+ ] }) : null,
1175
+ /* @__PURE__ */ jsxRuntime.jsx(
1176
+ "input",
1177
+ {
1178
+ ref: inputRef,
1179
+ type: "text",
1180
+ role: "combobox",
1181
+ className: "ansh-combobox__input",
1182
+ value: inputValue,
1183
+ placeholder: chips.length > 0 ? "" : placeholder,
1184
+ disabled: disabled || fieldProps.disabled,
1185
+ autoComplete: "off",
1186
+ spellCheck: false,
1187
+ "aria-expanded": open,
1188
+ "aria-controls": open ? listId : void 0,
1189
+ "aria-autocomplete": "list",
1190
+ "aria-activedescendant": open && rows[active] ? `${listId}-option-${active}` : void 0,
1191
+ ...label ? { "aria-label": label } : null,
1192
+ ...fieldProps,
1193
+ onChange: (event) => {
1194
+ setQuery(event.target.value);
1195
+ setOpen(true);
1196
+ onSearch?.(event.target.value);
1197
+ },
1198
+ onFocus: () => setOpen(true),
1199
+ onKeyDown
1200
+ }
1201
+ ),
1202
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-select__arrow", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 12 12", width: "12", height: "12", children: /* @__PURE__ */ jsxRuntime.jsx(
1203
+ "path",
1204
+ {
1205
+ d: "M3 4.5L6 7.5l3-3",
1206
+ stroke: "currentColor",
1207
+ strokeWidth: "1.5",
1208
+ fill: "none",
1209
+ strokeLinecap: "round",
1210
+ strokeLinejoin: "round"
1211
+ }
1212
+ ) }) })
1213
+ ]
1214
+ }
1215
+ ),
1216
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-visually-hidden", "aria-live": "polite", children: open ? `${visible.length} result${visible.length === 1 ? "" : "s"} available` : "" }),
1217
+ open ? /* @__PURE__ */ jsxRuntime.jsx(chunkXMXECSQO_cjs.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
1218
+ "div",
1219
+ {
1220
+ ref: listRef,
1221
+ id: listId,
1222
+ role: "listbox",
1223
+ "aria-multiselectable": multiple || void 0,
1224
+ ...label ? { "aria-label": label } : null,
1225
+ className: "ansh-listbox",
1226
+ style: { ...position.style, maxHeight },
1227
+ "data-side": position.side,
1228
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1229
+ OptionList,
1230
+ {
1231
+ options: rows,
1232
+ active,
1233
+ selected,
1234
+ listId,
1235
+ multiple,
1236
+ query,
1237
+ onSelect: toggle,
1238
+ onActiveChange: setActive,
1239
+ ...emptyMessage !== void 0 ? { emptyMessage } : null
1240
+ }
1241
+ )
1242
+ }
1243
+ ) }) : null
1244
+ ] });
1245
+ }
1246
+ function snap(value, min, max, step) {
1247
+ if (step <= 0) return Math.min(Math.max(value, min), max);
1248
+ const stepped = Math.round((value - min) / step) * step + min;
1249
+ const decimals = String(step).includes(".") ? String(step).split(".")[1].length : 0;
1250
+ return Number(Math.min(Math.max(stepped, min), max).toFixed(decimals));
1251
+ }
1252
+ function Slider({
1253
+ value,
1254
+ defaultValue = 0,
1255
+ onChange,
1256
+ onCommit,
1257
+ min = 0,
1258
+ max = 100,
1259
+ step = 1,
1260
+ disabled = false,
1261
+ orientation = "horizontal",
1262
+ marks,
1263
+ showValue = false,
1264
+ formatValue = String,
1265
+ label,
1266
+ className,
1267
+ name
1268
+ }) {
1269
+ const fieldProps = useFieldControl();
1270
+ const [current, setCurrent] = chunkPO5DU3FU_cjs.useControllableState({ value, defaultValue, onChange });
1271
+ const trackRef = react.useRef(null);
1272
+ const [dragging, setDragging] = react.useState(false);
1273
+ const id = react.useId();
1274
+ const percent = (current - min) / (max - min) * 100;
1275
+ const valueFromPointer = react.useCallback(
1276
+ (event) => {
1277
+ const track = trackRef.current;
1278
+ if (!track) return current;
1279
+ const rect = track.getBoundingClientRect();
1280
+ const fraction = orientation === "horizontal" ? (event.clientX - rect.left) / rect.width : (
1281
+ // Inverted: in a vertical slider, up is more.
1282
+ 1 - (event.clientY - rect.top) / rect.height
1283
+ );
1284
+ return snap(min + fraction * (max - min), min, max, step);
1285
+ },
1286
+ [current, min, max, step, orientation]
1287
+ );
1288
+ const onPointerDown = (event) => {
1289
+ if (disabled) return;
1290
+ event.preventDefault();
1291
+ event.currentTarget.setPointerCapture(event.pointerId);
1292
+ setDragging(true);
1293
+ let latest = valueFromPointer(event);
1294
+ setCurrent(latest);
1295
+ const onMove = (moveEvent) => {
1296
+ latest = valueFromPointer(moveEvent);
1297
+ setCurrent(latest);
1298
+ };
1299
+ const onUp = () => {
1300
+ setDragging(false);
1301
+ onCommit?.(latest);
1302
+ window.removeEventListener("pointermove", onMove);
1303
+ window.removeEventListener("pointerup", onUp);
1304
+ window.removeEventListener("pointercancel", onUp);
1305
+ };
1306
+ window.addEventListener("pointermove", onMove);
1307
+ window.addEventListener("pointerup", onUp);
1308
+ window.addEventListener("pointercancel", onUp);
1309
+ };
1310
+ const onKeyDown = (event) => {
1311
+ if (disabled) return;
1312
+ const large = (max - min) / 10;
1313
+ let next = null;
1314
+ switch (event.key) {
1315
+ case "ArrowRight":
1316
+ case "ArrowUp":
1317
+ next = current + step;
1318
+ break;
1319
+ case "ArrowLeft":
1320
+ case "ArrowDown":
1321
+ next = current - step;
1322
+ break;
1323
+ case "PageUp":
1324
+ next = current + large;
1325
+ break;
1326
+ case "PageDown":
1327
+ next = current - large;
1328
+ break;
1329
+ case "Home":
1330
+ next = min;
1331
+ break;
1332
+ case "End":
1333
+ next = max;
1334
+ break;
1335
+ }
1336
+ if (next === null) return;
1337
+ event.preventDefault();
1338
+ const snapped = snap(next, min, max, step);
1339
+ setCurrent(snapped);
1340
+ onCommit?.(snapped);
1341
+ };
1342
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1343
+ "div",
1344
+ {
1345
+ className: chunkSFU5EPSN_cjs.cx(
1346
+ "ansh-slider",
1347
+ `ansh-slider--${orientation}`,
1348
+ disabled && "ansh-slider--disabled",
1349
+ dragging && "ansh-slider--dragging",
1350
+ className
1351
+ ),
1352
+ style: { ["--ansh-slider-percent"]: `${percent}%` },
1353
+ children: [
1354
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: trackRef, className: "ansh-slider__track", onPointerDown, children: [
1355
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ansh-slider__fill" }),
1356
+ marks?.map((mark) => {
1357
+ const markPercent = (mark.value - min) / (max - min) * 100;
1358
+ return /* @__PURE__ */ jsxRuntime.jsx(
1359
+ "span",
1360
+ {
1361
+ className: chunkSFU5EPSN_cjs.cx(
1362
+ "ansh-slider__mark",
1363
+ current >= mark.value && "ansh-slider__mark--passed"
1364
+ ),
1365
+ style: { ["--ansh-mark"]: `${markPercent}%` },
1366
+ children: mark.label ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-slider__mark-label", children: mark.label }) : null
1367
+ },
1368
+ mark.value
1369
+ );
1370
+ }),
1371
+ /* @__PURE__ */ jsxRuntime.jsx(
1372
+ "div",
1373
+ {
1374
+ role: "slider",
1375
+ tabIndex: disabled ? -1 : 0,
1376
+ className: "ansh-slider__thumb ansh-focusable",
1377
+ "aria-valuenow": current,
1378
+ "aria-valuemin": min,
1379
+ "aria-valuemax": max,
1380
+ ...formatValue(current) !== String(current) ? { "aria-valuetext": formatValue(current) } : null,
1381
+ "aria-orientation": orientation,
1382
+ "aria-disabled": disabled || void 0,
1383
+ ...label ? { "aria-label": label } : null,
1384
+ ...fieldProps.id ? { "aria-labelledby": void 0, id: fieldProps.id } : null,
1385
+ ...fieldProps["aria-describedby"] ? { "aria-describedby": fieldProps["aria-describedby"] } : null,
1386
+ onPointerDown,
1387
+ onKeyDown,
1388
+ children: showValue === "always" || showValue && dragging ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-slider__bubble", "aria-hidden": "true", children: formatValue(current) }) : null
1389
+ }
1390
+ )
1391
+ ] }),
1392
+ name ? /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: current, id: `${id}-hidden` }) : null
1393
+ ]
1394
+ }
1395
+ );
1396
+ }
1397
+ function RangeSlider({
1398
+ value,
1399
+ defaultValue = [0, 100],
1400
+ onChange,
1401
+ onCommit,
1402
+ min = 0,
1403
+ max = 100,
1404
+ step = 1,
1405
+ minDistance = 0,
1406
+ disabled = false,
1407
+ marks,
1408
+ showValue = false,
1409
+ formatValue = String,
1410
+ label,
1411
+ className
1412
+ }) {
1413
+ const [range, setRange] = chunkPO5DU3FU_cjs.useControllableState({
1414
+ value,
1415
+ defaultValue,
1416
+ onChange
1417
+ });
1418
+ const trackRef = react.useRef(null);
1419
+ const [dragging, setDragging] = react.useState(null);
1420
+ const [low, high] = range;
1421
+ const lowPercent = (low - min) / (max - min) * 100;
1422
+ const highPercent = (high - min) / (max - min) * 100;
1423
+ const valueFromPointer = (event) => {
1424
+ const track = trackRef.current;
1425
+ if (!track) return low;
1426
+ const rect = track.getBoundingClientRect();
1427
+ return snap(min + (event.clientX - rect.left) / rect.width * (max - min), min, max, step);
1428
+ };
1429
+ const apply = (thumb2, next) => {
1430
+ if (thumb2 === 0) {
1431
+ return next > high - minDistance ? [high - minDistance, high] : [next, high];
1432
+ }
1433
+ return next < low + minDistance ? [low, low + minDistance] : [low, next];
1434
+ };
1435
+ const startDrag = (thumb2) => (event) => {
1436
+ if (disabled) return;
1437
+ event.preventDefault();
1438
+ event.currentTarget.setPointerCapture(event.pointerId);
1439
+ setDragging(thumb2);
1440
+ let latest = range;
1441
+ const onMove = (moveEvent) => {
1442
+ latest = apply(thumb2, valueFromPointer(moveEvent));
1443
+ setRange(latest);
1444
+ };
1445
+ const onUp = () => {
1446
+ setDragging(null);
1447
+ onCommit?.(latest);
1448
+ window.removeEventListener("pointermove", onMove);
1449
+ window.removeEventListener("pointerup", onUp);
1450
+ };
1451
+ window.addEventListener("pointermove", onMove);
1452
+ window.addEventListener("pointerup", onUp);
1453
+ };
1454
+ const keyHandler = (thumb2) => (event) => {
1455
+ if (disabled) return;
1456
+ const currentValue = range[thumb2];
1457
+ const large = (max - min) / 10;
1458
+ let next = null;
1459
+ switch (event.key) {
1460
+ case "ArrowRight":
1461
+ case "ArrowUp":
1462
+ next = currentValue + step;
1463
+ break;
1464
+ case "ArrowLeft":
1465
+ case "ArrowDown":
1466
+ next = currentValue - step;
1467
+ break;
1468
+ case "PageUp":
1469
+ next = currentValue + large;
1470
+ break;
1471
+ case "PageDown":
1472
+ next = currentValue - large;
1473
+ break;
1474
+ case "Home":
1475
+ next = min;
1476
+ break;
1477
+ case "End":
1478
+ next = max;
1479
+ break;
1480
+ }
1481
+ if (next === null) return;
1482
+ event.preventDefault();
1483
+ const applied = apply(thumb2, snap(next, min, max, step));
1484
+ setRange(applied);
1485
+ onCommit?.(applied);
1486
+ };
1487
+ const thumb = (index, thumbLabel) => /* @__PURE__ */ jsxRuntime.jsx(
1488
+ "div",
1489
+ {
1490
+ role: "slider",
1491
+ tabIndex: disabled ? -1 : 0,
1492
+ className: "ansh-slider__thumb ansh-focusable",
1493
+ style: { ["--ansh-thumb"]: `${index === 0 ? lowPercent : highPercent}%` },
1494
+ "aria-label": label ? `${label} ${thumbLabel}` : thumbLabel,
1495
+ "aria-valuenow": range[index],
1496
+ "aria-valuemin": index === 0 ? min : low + minDistance,
1497
+ "aria-valuemax": index === 0 ? high - minDistance : max,
1498
+ ...formatValue(range[index]) !== String(range[index]) ? { "aria-valuetext": formatValue(range[index]) } : null,
1499
+ "aria-disabled": disabled || void 0,
1500
+ onPointerDown: startDrag(index),
1501
+ onKeyDown: keyHandler(index),
1502
+ children: showValue === "always" || showValue && dragging === index ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-slider__bubble", "aria-hidden": "true", children: formatValue(range[index]) }) : null
1503
+ },
1504
+ index
1505
+ );
1506
+ return /* @__PURE__ */ jsxRuntime.jsx(
1507
+ "div",
1508
+ {
1509
+ className: chunkSFU5EPSN_cjs.cx(
1510
+ "ansh-slider",
1511
+ "ansh-slider--horizontal",
1512
+ "ansh-slider--range",
1513
+ disabled && "ansh-slider--disabled",
1514
+ className
1515
+ ),
1516
+ style: {
1517
+ ["--ansh-range-start"]: `${lowPercent}%`,
1518
+ ["--ansh-range-end"]: `${highPercent}%`
1519
+ },
1520
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: trackRef, className: "ansh-slider__track", children: [
1521
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ansh-slider__fill ansh-slider__fill--range" }),
1522
+ marks?.map((mark) => /* @__PURE__ */ jsxRuntime.jsx(
1523
+ "span",
1524
+ {
1525
+ className: chunkSFU5EPSN_cjs.cx(
1526
+ "ansh-slider__mark",
1527
+ mark.value >= low && mark.value <= high && "ansh-slider__mark--passed"
1528
+ ),
1529
+ style: { ["--ansh-mark"]: `${(mark.value - min) / (max - min) * 100}%` },
1530
+ children: mark.label ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-slider__mark-label", children: mark.label }) : null
1531
+ },
1532
+ mark.value
1533
+ )),
1534
+ thumb(0, "minimum"),
1535
+ thumb(1, "maximum")
1536
+ ] })
1537
+ }
1538
+ );
1539
+ }
1540
+ function PinInput({
1541
+ length = 6,
1542
+ value,
1543
+ defaultValue = "",
1544
+ onChange,
1545
+ onComplete,
1546
+ type = "numeric",
1547
+ mask = false,
1548
+ disabled = false,
1549
+ invalid = false,
1550
+ autoFocus = false,
1551
+ label = "Verification code",
1552
+ className
1553
+ }) {
1554
+ const [code, setCode] = chunkPO5DU3FU_cjs.useControllableState({ value, defaultValue, onChange });
1555
+ const inputsRef = react.useRef([]);
1556
+ const id = react.useId();
1557
+ const pattern = type === "numeric" ? /[^0-9]/g : /[^a-zA-Z0-9]/g;
1558
+ const completedRef = react.useRef(false);
1559
+ react.useEffect(() => {
1560
+ if (code.length === length && !completedRef.current) {
1561
+ completedRef.current = true;
1562
+ onComplete?.(code);
1563
+ } else if (code.length < length) {
1564
+ completedRef.current = false;
1565
+ }
1566
+ }, [code, length, onComplete]);
1567
+ const setCharAt = (index, char) => {
1568
+ const chars = code.padEnd(length, " ").split("");
1569
+ chars[index] = char;
1570
+ setCode(chars.join("").trimEnd());
1571
+ };
1572
+ const focusCell = (index) => {
1573
+ const target = inputsRef.current[Math.min(Math.max(index, 0), length - 1)];
1574
+ target?.focus();
1575
+ target?.select();
1576
+ };
1577
+ const onCellChange = (index, raw) => {
1578
+ const cleaned = raw.replace(pattern, "");
1579
+ if (cleaned === "") {
1580
+ setCharAt(index, " ");
1581
+ return;
1582
+ }
1583
+ if (cleaned.length > 1) {
1584
+ const chars = code.padEnd(length, " ").split("");
1585
+ for (let i = 0; i < cleaned.length && index + i < length; i++) {
1586
+ chars[index + i] = cleaned[i];
1587
+ }
1588
+ setCode(chars.join("").trimEnd());
1589
+ focusCell(index + cleaned.length);
1590
+ return;
1591
+ }
1592
+ setCharAt(index, cleaned);
1593
+ focusCell(index + 1);
1594
+ };
1595
+ const onKeyDown = (index) => (event) => {
1596
+ switch (event.key) {
1597
+ case "Backspace": {
1598
+ event.preventDefault();
1599
+ if ((code[index] ?? " ").trim() === "") {
1600
+ setCharAt(index - 1, " ");
1601
+ focusCell(index - 1);
1602
+ } else {
1603
+ setCharAt(index, " ");
1604
+ }
1605
+ break;
1606
+ }
1607
+ case "Delete":
1608
+ event.preventDefault();
1609
+ setCharAt(index, " ");
1610
+ break;
1611
+ case "ArrowLeft":
1612
+ event.preventDefault();
1613
+ focusCell(index - 1);
1614
+ break;
1615
+ case "ArrowRight":
1616
+ event.preventDefault();
1617
+ focusCell(index + 1);
1618
+ break;
1619
+ case "Home":
1620
+ event.preventDefault();
1621
+ focusCell(0);
1622
+ break;
1623
+ case "End":
1624
+ event.preventDefault();
1625
+ focusCell(length - 1);
1626
+ break;
1627
+ }
1628
+ };
1629
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1630
+ "div",
1631
+ {
1632
+ className: chunkSFU5EPSN_cjs.cx(
1633
+ "ansh-pin",
1634
+ invalid && "ansh-pin--invalid",
1635
+ disabled && "ansh-pin--disabled",
1636
+ className
1637
+ ),
1638
+ role: "group",
1639
+ "aria-label": label,
1640
+ "aria-describedby": `${id}-status`,
1641
+ children: [
1642
+ Array.from({ length }, (_, index) => /* @__PURE__ */ jsxRuntime.jsx(
1643
+ "input",
1644
+ {
1645
+ ref: (node) => {
1646
+ inputsRef.current[index] = node;
1647
+ },
1648
+ className: "ansh-pin__cell ansh-focusable",
1649
+ type: mask ? "password" : "text",
1650
+ inputMode: type === "numeric" ? "numeric" : "text",
1651
+ autoComplete: index === 0 ? "one-time-code" : "off",
1652
+ autoFocus: autoFocus && index === 0,
1653
+ maxLength: length,
1654
+ disabled,
1655
+ "aria-label": `Digit ${index + 1} of ${length}`,
1656
+ "aria-invalid": invalid || void 0,
1657
+ value: (code[index] ?? "").trim(),
1658
+ onChange: (event) => onCellChange(index, event.target.value),
1659
+ onKeyDown: onKeyDown(index),
1660
+ onFocus: (event) => event.target.select()
1661
+ },
1662
+ index
1663
+ )),
1664
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-visually-hidden", id: `${id}-status`, "aria-live": "polite", children: code.trim().length === length ? "Code complete" : `${code.trim().length} of ${length} digits entered` })
1665
+ ]
1666
+ }
1667
+ );
1668
+ }
1669
+ function TagsInput({
1670
+ value,
1671
+ defaultValue = [],
1672
+ onChange,
1673
+ placeholder = "Add and press Enter",
1674
+ max = Number.POSITIVE_INFINITY,
1675
+ delimiters = ["Enter", "Tab", ","],
1676
+ validate,
1677
+ dedupe = true,
1678
+ disabled = false,
1679
+ invalid = false,
1680
+ label = "Tags",
1681
+ className
1682
+ }) {
1683
+ const fieldProps = useFieldControl();
1684
+ const [tags, setTags] = chunkPO5DU3FU_cjs.useControllableState({
1685
+ value,
1686
+ defaultValue,
1687
+ onChange
1688
+ });
1689
+ const [draft, setDraft] = react.useState("");
1690
+ const [error, setError] = react.useState(null);
1691
+ const inputRef = react.useRef(null);
1692
+ const tagRefs = react.useRef([]);
1693
+ const commit = (raw) => {
1694
+ const text = raw.trim();
1695
+ if (text === "") return false;
1696
+ if (tags.length >= max) {
1697
+ setError(`Up to ${max} allowed`);
1698
+ return false;
1699
+ }
1700
+ if (dedupe && tags.includes(text)) {
1701
+ setDraft("");
1702
+ return true;
1703
+ }
1704
+ const failure = validate?.(text);
1705
+ if (failure) {
1706
+ setError(failure);
1707
+ return false;
1708
+ }
1709
+ setTags([...tags, text]);
1710
+ setDraft("");
1711
+ setError(null);
1712
+ return true;
1713
+ };
1714
+ const removeAt = (index) => {
1715
+ setTags(tags.filter((_, i) => i !== index));
1716
+ setError(null);
1717
+ queueMicrotask(() => {
1718
+ const next = tagRefs.current[index] ?? tagRefs.current[index - 1];
1719
+ if (next?.isConnected) next.focus();
1720
+ else inputRef.current?.focus();
1721
+ });
1722
+ };
1723
+ const onKeyDown = (event) => {
1724
+ if (event.key === "Tab" && draft.trim() === "") return;
1725
+ if (delimiters.includes(event.key)) {
1726
+ event.preventDefault();
1727
+ commit(draft);
1728
+ return;
1729
+ }
1730
+ if (event.key === "Backspace" && draft === "" && tags.length > 0) {
1731
+ event.preventDefault();
1732
+ removeAt(tags.length - 1);
1733
+ }
1734
+ };
1735
+ const atLimit = tags.length >= max;
1736
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkSFU5EPSN_cjs.cx("ansh-tags", className), children: [
1737
+ /* @__PURE__ */ jsxRuntime.jsxs(
1738
+ "div",
1739
+ {
1740
+ className: chunkSFU5EPSN_cjs.cx(
1741
+ "ansh-tags__control",
1742
+ "ansh-focusable-within",
1743
+ (invalid || error) && "ansh-tags__control--invalid",
1744
+ disabled && "ansh-tags__control--disabled"
1745
+ ),
1746
+ onMouseDown: (event) => {
1747
+ if (event.target === event.currentTarget) {
1748
+ event.preventDefault();
1749
+ inputRef.current?.focus();
1750
+ }
1751
+ },
1752
+ children: [
1753
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "ansh-tags__list", "aria-label": `${label}: selected`, children: tags.map((tag, index) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "ansh-chip", children: [
1754
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-chip__label", children: tag }),
1755
+ /* @__PURE__ */ jsxRuntime.jsx(
1756
+ "button",
1757
+ {
1758
+ ref: (node) => {
1759
+ tagRefs.current[index] = node;
1760
+ },
1761
+ type: "button",
1762
+ className: "ansh-chip__remove",
1763
+ "aria-label": `Remove ${tag}`,
1764
+ disabled,
1765
+ onClick: () => removeAt(index),
1766
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 16 16", width: "10", height: "10", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(
1767
+ "path",
1768
+ {
1769
+ d: "M4 4l8 8M12 4l-8 8",
1770
+ stroke: "currentColor",
1771
+ strokeWidth: "2",
1772
+ strokeLinecap: "round",
1773
+ fill: "none"
1774
+ }
1775
+ ) })
1776
+ }
1777
+ )
1778
+ ] }, `${tag}-${index}`)) }),
1779
+ !atLimit ? /* @__PURE__ */ jsxRuntime.jsx(
1780
+ "input",
1781
+ {
1782
+ ref: inputRef,
1783
+ type: "text",
1784
+ className: "ansh-tags__input",
1785
+ value: draft,
1786
+ placeholder: tags.length === 0 ? placeholder : "",
1787
+ disabled,
1788
+ "aria-label": label,
1789
+ "aria-invalid": invalid || Boolean(error) || void 0,
1790
+ ...fieldProps,
1791
+ onChange: (event) => {
1792
+ setDraft(event.target.value);
1793
+ setError(null);
1794
+ },
1795
+ onKeyDown,
1796
+ onBlur: () => commit(draft),
1797
+ onPaste: (event) => {
1798
+ const text = event.clipboardData.getData("text");
1799
+ if (!/[,\n\t]/.test(text)) return;
1800
+ event.preventDefault();
1801
+ for (const part of text.split(/[,\n\t]+/)) commit(part);
1802
+ }
1803
+ }
1804
+ ) : null
1805
+ ]
1806
+ }
1807
+ ),
1808
+ error ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "ansh-field__error", role: "alert", children: error }) : null
1809
+ ] });
1810
+ }
1811
+ function Rating({
1812
+ value,
1813
+ defaultValue = 0,
1814
+ onChange,
1815
+ max = 5,
1816
+ allowHalf = false,
1817
+ readOnly = false,
1818
+ disabled = false,
1819
+ size = "md",
1820
+ icon,
1821
+ label = "Rating",
1822
+ className,
1823
+ name
1824
+ }) {
1825
+ const [current, setCurrent] = chunkPO5DU3FU_cjs.useControllableState({ value, defaultValue, onChange });
1826
+ const [preview, setPreview] = react.useState(null);
1827
+ const groupName = react.useId();
1828
+ const shown = preview ?? current;
1829
+ const symbol = icon ?? /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 20 20", className: "ansh-rating__glyph", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(
1830
+ "path",
1831
+ {
1832
+ d: "M10 1.6l2.6 5.3 5.8.8-4.2 4.1 1 5.8-5.2-2.7-5.2 2.7 1-5.8L1.6 7.7l5.8-.8z",
1833
+ fill: "currentColor"
1834
+ }
1835
+ ) });
1836
+ if (readOnly) {
1837
+ return /* @__PURE__ */ jsxRuntime.jsx(
1838
+ "span",
1839
+ {
1840
+ className: chunkSFU5EPSN_cjs.cx("ansh-rating", `ansh-rating--${size}`, "ansh-rating--readonly", className),
1841
+ role: "img",
1842
+ "aria-label": `${current} out of ${max}`,
1843
+ children: Array.from({ length: max }, (_, index) => /* @__PURE__ */ jsxRuntime.jsx(
1844
+ "span",
1845
+ {
1846
+ className: "ansh-rating__item",
1847
+ style: {
1848
+ ["--ansh-fill"]: `${Math.min(Math.max(current - index, 0), 1) * 100}%`
1849
+ },
1850
+ children: symbol
1851
+ },
1852
+ index
1853
+ ))
1854
+ }
1855
+ );
1856
+ }
1857
+ const steps = allowHalf ? max * 2 : max;
1858
+ return /* @__PURE__ */ jsxRuntime.jsx(
1859
+ "span",
1860
+ {
1861
+ role: "radiogroup",
1862
+ "aria-label": label,
1863
+ className: chunkSFU5EPSN_cjs.cx(
1864
+ "ansh-rating",
1865
+ `ansh-rating--${size}`,
1866
+ disabled && "ansh-rating--disabled",
1867
+ className
1868
+ ),
1869
+ onMouseLeave: () => setPreview(null),
1870
+ children: Array.from({ length: steps }, (_, step) => {
1871
+ const stepValue = allowHalf ? (step + 1) / 2 : step + 1;
1872
+ const index = Math.ceil(stepValue) - 1;
1873
+ const isHalf = allowHalf && stepValue % 1 !== 0;
1874
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1875
+ "label",
1876
+ {
1877
+ className: chunkSFU5EPSN_cjs.cx("ansh-rating__hit", isHalf && "ansh-rating__hit--half"),
1878
+ onMouseEnter: () => !disabled && setPreview(stepValue),
1879
+ children: [
1880
+ /* @__PURE__ */ jsxRuntime.jsx(
1881
+ "input",
1882
+ {
1883
+ type: "radio",
1884
+ className: "ansh-visually-hidden",
1885
+ name: name ?? groupName,
1886
+ value: stepValue,
1887
+ checked: current === stepValue,
1888
+ disabled,
1889
+ "aria-label": `${stepValue} ${stepValue === 1 ? "star" : "stars"}`,
1890
+ onChange: () => setCurrent(stepValue)
1891
+ }
1892
+ ),
1893
+ !isHalf ? /* @__PURE__ */ jsxRuntime.jsx(
1894
+ "span",
1895
+ {
1896
+ className: "ansh-rating__item",
1897
+ style: {
1898
+ ["--ansh-fill"]: `${Math.min(Math.max(shown - index, 0), 1) * 100}%`
1899
+ },
1900
+ children: symbol
1901
+ }
1902
+ ) : null
1903
+ ]
1904
+ },
1905
+ stepValue
1906
+ );
1907
+ })
1908
+ }
1909
+ );
1910
+ }
1911
+ function formatBytes(bytes) {
1912
+ if (bytes < 1024) return `${bytes} B`;
1913
+ const units = ["KB", "MB", "GB"];
1914
+ let size = bytes / 1024;
1915
+ let unit = 0;
1916
+ while (size >= 1024 && unit < units.length - 1) {
1917
+ size /= 1024;
1918
+ unit++;
1919
+ }
1920
+ return `${size.toFixed(size >= 10 ? 0 : 1)} ${units[unit]}`;
1921
+ }
1922
+ function Dropzone({
1923
+ onFiles,
1924
+ accept,
1925
+ multiple = false,
1926
+ maxSize,
1927
+ maxFiles = Number.POSITIVE_INFINITY,
1928
+ disabled = false,
1929
+ previews = true,
1930
+ label = "Drop files here, or browse",
1931
+ hint,
1932
+ className,
1933
+ children
1934
+ }) {
1935
+ const [files, setFiles] = react.useState([]);
1936
+ const [dragging, setDragging] = react.useState(false);
1937
+ const depthRef = react.useRef(0);
1938
+ const inputRef = react.useRef(null);
1939
+ const id = react.useId();
1940
+ const validate = react.useCallback(
1941
+ (file) => {
1942
+ if (maxSize !== void 0 && file.size > maxSize) {
1943
+ return `Larger than ${formatBytes(maxSize)}`;
1944
+ }
1945
+ if (accept) {
1946
+ const patterns = accept.split(",").map((part) => part.trim().toLowerCase());
1947
+ const name = file.name.toLowerCase();
1948
+ const type = file.type.toLowerCase();
1949
+ const ok = patterns.some((pattern) => {
1950
+ if (pattern.startsWith(".")) return name.endsWith(pattern);
1951
+ if (pattern.endsWith("/*")) return type.startsWith(pattern.slice(0, -1));
1952
+ return type === pattern;
1953
+ });
1954
+ if (!ok) return "Unsupported file type";
1955
+ }
1956
+ return void 0;
1957
+ },
1958
+ [accept, maxSize]
1959
+ );
1960
+ const add = react.useCallback(
1961
+ (incoming) => {
1962
+ if (!incoming || disabled) return;
1963
+ const accepted = [];
1964
+ const room = maxFiles - files.length;
1965
+ for (const file of Array.from(incoming).slice(0, multiple ? room : 1)) {
1966
+ const error = validate(file);
1967
+ accepted.push({
1968
+ file,
1969
+ id: `${file.name}-${file.size}-${file.lastModified}`,
1970
+ ...previews && file.type.startsWith("image/") && !error ? { preview: URL.createObjectURL(file) } : null,
1971
+ ...error ? { error } : null
1972
+ });
1973
+ }
1974
+ const next = multiple ? [...files, ...accepted] : accepted;
1975
+ if (!multiple)
1976
+ for (const previous of files) {
1977
+ if (previous.preview) URL.revokeObjectURL(previous.preview);
1978
+ }
1979
+ setFiles(next);
1980
+ onFiles?.(next);
1981
+ },
1982
+ [disabled, files, maxFiles, multiple, onFiles, previews, validate]
1983
+ );
1984
+ const remove = (fileId) => {
1985
+ const target = files.find((entry) => entry.id === fileId);
1986
+ if (target?.preview) URL.revokeObjectURL(target.preview);
1987
+ const next = files.filter((entry) => entry.id !== fileId);
1988
+ setFiles(next);
1989
+ onFiles?.(next);
1990
+ if (inputRef.current) inputRef.current.value = "";
1991
+ };
1992
+ const rejected = files.filter((entry) => entry.error);
1993
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkSFU5EPSN_cjs.cx("ansh-dropzone-wrap", className), children: [
1994
+ /* @__PURE__ */ jsxRuntime.jsxs(
1995
+ "div",
1996
+ {
1997
+ className: chunkSFU5EPSN_cjs.cx(
1998
+ "ansh-dropzone",
1999
+ dragging && "ansh-dropzone--active",
2000
+ disabled && "ansh-dropzone--disabled"
2001
+ ),
2002
+ onDragEnter: (event) => {
2003
+ event.preventDefault();
2004
+ depthRef.current++;
2005
+ if (!disabled) setDragging(true);
2006
+ },
2007
+ onDragOver: (event) => {
2008
+ event.preventDefault();
2009
+ event.dataTransfer.dropEffect = disabled ? "none" : "copy";
2010
+ },
2011
+ onDragLeave: (event) => {
2012
+ event.preventDefault();
2013
+ depthRef.current--;
2014
+ if (depthRef.current <= 0) {
2015
+ depthRef.current = 0;
2016
+ setDragging(false);
2017
+ }
2018
+ },
2019
+ onDrop: (event) => {
2020
+ event.preventDefault();
2021
+ depthRef.current = 0;
2022
+ setDragging(false);
2023
+ add(event.dataTransfer.files);
2024
+ },
2025
+ children: [
2026
+ /* @__PURE__ */ jsxRuntime.jsx(
2027
+ "input",
2028
+ {
2029
+ ref: inputRef,
2030
+ id,
2031
+ type: "file",
2032
+ className: "ansh-dropzone__input",
2033
+ accept,
2034
+ multiple,
2035
+ disabled,
2036
+ onChange: (event) => add(event.target.files)
2037
+ }
2038
+ ),
2039
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: id, className: "ansh-dropzone__label", children: [
2040
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-dropzone__icon", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsxs(
2041
+ "svg",
2042
+ {
2043
+ viewBox: "0 0 24 24",
2044
+ width: "28",
2045
+ height: "28",
2046
+ fill: "none",
2047
+ stroke: "currentColor",
2048
+ strokeWidth: "1.5",
2049
+ children: [
2050
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 16V4m0 0L8 8m4-4l4 4", strokeLinecap: "round", strokeLinejoin: "round" }),
2051
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 15v3a3 3 0 003 3h12a3 3 0 003-3v-3", strokeLinecap: "round" })
2052
+ ]
2053
+ }
2054
+ ) }),
2055
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-dropzone__text", children: label }),
2056
+ hint ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-dropzone__hint", children: hint }) : null
2057
+ ] }),
2058
+ children
2059
+ ]
2060
+ }
2061
+ ),
2062
+ files.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "ansh-dropzone__files", children: files.map((entry) => /* @__PURE__ */ jsxRuntime.jsxs(
2063
+ "li",
2064
+ {
2065
+ className: chunkSFU5EPSN_cjs.cx("ansh-dropzone__file", entry.error && "ansh-dropzone__file--error"),
2066
+ children: [
2067
+ entry.preview ? (
2068
+ // Decorative: the file name beside it is the accessible content.
2069
+ /* @__PURE__ */ jsxRuntime.jsx("img", { src: entry.preview, alt: "", className: "ansh-dropzone__thumb" })
2070
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
2071
+ "span",
2072
+ {
2073
+ className: "ansh-dropzone__thumb ansh-dropzone__thumb--generic",
2074
+ "aria-hidden": "true",
2075
+ children: entry.file.name.split(".").pop()?.slice(0, 4).toUpperCase()
2076
+ }
2077
+ ),
2078
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ansh-dropzone__meta", children: [
2079
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-dropzone__name", children: entry.file.name }),
2080
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-dropzone__size", children: entry.error ?? formatBytes(entry.file.size) })
2081
+ ] }),
2082
+ /* @__PURE__ */ jsxRuntime.jsx(
2083
+ "button",
2084
+ {
2085
+ type: "button",
2086
+ className: "ansh-dropzone__remove ansh-focusable",
2087
+ "aria-label": `Remove ${entry.file.name}`,
2088
+ onClick: () => remove(entry.id),
2089
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 16 16", width: "12", height: "12", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(
2090
+ "path",
2091
+ {
2092
+ d: "M4 4l8 8M12 4l-8 8",
2093
+ stroke: "currentColor",
2094
+ strokeWidth: "1.75",
2095
+ strokeLinecap: "round",
2096
+ fill: "none"
2097
+ }
2098
+ ) })
2099
+ }
2100
+ )
2101
+ ]
2102
+ },
2103
+ entry.id
2104
+ )) }) : null,
2105
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-visually-hidden", role: "status", "aria-live": "polite", children: rejected.length > 0 ? `${rejected.length} file${rejected.length === 1 ? "" : "s"} rejected` : files.length > 0 ? `${files.length} file${files.length === 1 ? "" : "s"} ready` : "" })
2106
+ ] });
2107
+ }
2108
+ function ColorPicker({
2109
+ value,
2110
+ defaultValue = "#0275f4",
2111
+ onChange,
2112
+ format = "hex",
2113
+ alpha = false,
2114
+ presets,
2115
+ contrastAgainst,
2116
+ disabled = false,
2117
+ label = "Colour",
2118
+ className
2119
+ }) {
2120
+ const [current, setCurrent] = chunkPO5DU3FU_cjs.useControllableState({ value, defaultValue, onChange });
2121
+ const [open, setOpen] = react.useState(false);
2122
+ const triggerRef = react.useRef(null);
2123
+ const panelRef = react.useRef(null);
2124
+ const planeRef = react.useRef(null);
2125
+ const id = react.useId();
2126
+ const parsed = react.useMemo(() => {
2127
+ const rgb = core.tryParseColor(current) ?? core.parseColor(defaultValue);
2128
+ return core.rgbToHsv(rgb);
2129
+ }, [current, defaultValue]);
2130
+ const hueRef = react.useRef(parsed.h);
2131
+ if (parsed.s > 1e-3 && parsed.v > 1e-3) hueRef.current = parsed.h;
2132
+ const hsv = {
2133
+ ...parsed,
2134
+ h: parsed.s < 1e-3 || parsed.v < 1e-3 ? hueRef.current : parsed.h
2135
+ };
2136
+ const emit = react.useCallback(
2137
+ (next) => {
2138
+ const rgb = core.hsvToRgb(next);
2139
+ switch (format) {
2140
+ case "rgb":
2141
+ setCurrent(
2142
+ next.a < 1 ? `rgba(${Math.round(rgb.r * 255)}, ${Math.round(rgb.g * 255)}, ${Math.round(rgb.b * 255)}, ${Number(next.a.toFixed(2))})` : `rgb(${Math.round(rgb.r * 255)}, ${Math.round(rgb.g * 255)}, ${Math.round(rgb.b * 255)})`
2143
+ );
2144
+ break;
2145
+ case "hsl":
2146
+ setCurrent(
2147
+ `hsl(${Math.round(next.h)} ${Math.round(next.s * 100)}% ${Math.round(next.v * (1 - next.s / 2) * 100)}%${next.a < 1 ? ` / ${Number(next.a.toFixed(2))}` : ""})`
2148
+ );
2149
+ break;
2150
+ case "oklch":
2151
+ setCurrent(core.toOklchString(rgb));
2152
+ break;
2153
+ default:
2154
+ setCurrent(core.toHex(rgb, next.a < 1));
2155
+ }
2156
+ },
2157
+ [format, setCurrent]
2158
+ );
2159
+ const position = chunkXMXECSQO_cjs.useAnchoredPosition(triggerRef, panelRef, open, {
2160
+ placement: "bottom-start",
2161
+ offset: 8
2162
+ });
2163
+ chunkXMXECSQO_cjs.useDismiss(panelRef, open, () => setOpen(false), { ignore: [triggerRef] });
2164
+ const dragPlane = (event) => {
2165
+ if (disabled) return;
2166
+ const plane = planeRef.current;
2167
+ if (!plane) return;
2168
+ event.currentTarget.setPointerCapture(event.pointerId);
2169
+ const apply = (clientX, clientY) => {
2170
+ const rect = plane.getBoundingClientRect();
2171
+ const s = Math.min(Math.max((clientX - rect.left) / rect.width, 0), 1);
2172
+ const v = 1 - Math.min(Math.max((clientY - rect.top) / rect.height, 0), 1);
2173
+ emit({ ...hsv, s, v });
2174
+ };
2175
+ apply(event.clientX, event.clientY);
2176
+ const onMove = (moveEvent) => apply(moveEvent.clientX, moveEvent.clientY);
2177
+ const onUp = () => {
2178
+ window.removeEventListener("pointermove", onMove);
2179
+ window.removeEventListener("pointerup", onUp);
2180
+ };
2181
+ window.addEventListener("pointermove", onMove);
2182
+ window.addEventListener("pointerup", onUp);
2183
+ };
2184
+ const onPlaneKeyDown = (event) => {
2185
+ const step = event.shiftKey ? 0.1 : 0.02;
2186
+ let { s, v } = hsv;
2187
+ switch (event.key) {
2188
+ case "ArrowRight":
2189
+ s = Math.min(1, s + step);
2190
+ break;
2191
+ case "ArrowLeft":
2192
+ s = Math.max(0, s - step);
2193
+ break;
2194
+ case "ArrowUp":
2195
+ v = Math.min(1, v + step);
2196
+ break;
2197
+ case "ArrowDown":
2198
+ v = Math.max(0, v - step);
2199
+ break;
2200
+ default:
2201
+ return;
2202
+ }
2203
+ event.preventDefault();
2204
+ emit({ ...hsv, s, v });
2205
+ };
2206
+ const swatch = core.toHex(core.hsvToRgb(hsv), hsv.a < 1);
2207
+ const pureHue = core.toHex(core.hsvToRgb({ h: hsv.h, s: 1, v: 1, a: 1 }));
2208
+ const contrast = contrastAgainst ? core.contrastRatio(core.hsvToRgb(hsv), core.parseColor(contrastAgainst)) : null;
2209
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkSFU5EPSN_cjs.cx("ansh-colorpicker", className), children: [
2210
+ /* @__PURE__ */ jsxRuntime.jsxs(
2211
+ "button",
2212
+ {
2213
+ ref: triggerRef,
2214
+ type: "button",
2215
+ className: "ansh-colorpicker__trigger ansh-focusable",
2216
+ disabled,
2217
+ "aria-haspopup": "dialog",
2218
+ "aria-expanded": open,
2219
+ "aria-label": `${label}: ${swatch}`,
2220
+ onClick: () => setOpen((v) => !v),
2221
+ children: [
2222
+ /* @__PURE__ */ jsxRuntime.jsx(
2223
+ "span",
2224
+ {
2225
+ className: "ansh-colorpicker__swatch",
2226
+ style: { background: swatch },
2227
+ "aria-hidden": "true"
2228
+ }
2229
+ ),
2230
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-colorpicker__value", children: current })
2231
+ ]
2232
+ }
2233
+ ),
2234
+ open ? /* @__PURE__ */ jsxRuntime.jsx(chunkXMXECSQO_cjs.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
2235
+ "div",
2236
+ {
2237
+ ref: panelRef,
2238
+ role: "dialog",
2239
+ "aria-label": label,
2240
+ className: "ansh-colorpicker__panel",
2241
+ style: position.style,
2242
+ children: [
2243
+ /* @__PURE__ */ jsxRuntime.jsx(
2244
+ "div",
2245
+ {
2246
+ ref: planeRef,
2247
+ className: "ansh-colorpicker__plane",
2248
+ style: { ["--ansh-hue"]: pureHue },
2249
+ onPointerDown: dragPlane,
2250
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2251
+ "div",
2252
+ {
2253
+ role: "slider",
2254
+ tabIndex: 0,
2255
+ className: "ansh-colorpicker__knob ansh-focusable",
2256
+ style: {
2257
+ left: `${hsv.s * 100}%`,
2258
+ top: `${(1 - hsv.v) * 100}%`,
2259
+ background: swatch
2260
+ },
2261
+ "aria-label": "Saturation and brightness",
2262
+ "aria-valuetext": `Saturation ${Math.round(hsv.s * 100)}%, brightness ${Math.round(hsv.v * 100)}%`,
2263
+ "aria-valuenow": Math.round(hsv.s * 100),
2264
+ "aria-valuemin": 0,
2265
+ "aria-valuemax": 100,
2266
+ onKeyDown: onPlaneKeyDown
2267
+ }
2268
+ )
2269
+ }
2270
+ ),
2271
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ansh-colorpicker__rails", children: [
2272
+ /* @__PURE__ */ jsxRuntime.jsx(
2273
+ "div",
2274
+ {
2275
+ className: "ansh-colorpicker__preview",
2276
+ style: { background: swatch },
2277
+ "aria-hidden": "true"
2278
+ }
2279
+ ),
2280
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ansh-colorpicker__rail-group", children: [
2281
+ /* @__PURE__ */ jsxRuntime.jsx(
2282
+ "input",
2283
+ {
2284
+ type: "range",
2285
+ className: "ansh-colorpicker__rail ansh-colorpicker__rail--hue ansh-focusable",
2286
+ min: 0,
2287
+ max: 360,
2288
+ step: 1,
2289
+ value: Math.round(hsv.h),
2290
+ "aria-label": "Hue",
2291
+ "aria-valuetext": `${Math.round(hsv.h)} degrees`,
2292
+ onChange: (event) => emit({ ...hsv, h: Number(event.target.value) })
2293
+ }
2294
+ ),
2295
+ alpha ? /* @__PURE__ */ jsxRuntime.jsx(
2296
+ "input",
2297
+ {
2298
+ type: "range",
2299
+ className: "ansh-colorpicker__rail ansh-colorpicker__rail--alpha ansh-focusable",
2300
+ style: { ["--ansh-solid"]: core.toHex(core.hsvToRgb({ ...hsv, a: 1 })) },
2301
+ min: 0,
2302
+ max: 100,
2303
+ step: 1,
2304
+ value: Math.round(hsv.a * 100),
2305
+ "aria-label": "Opacity",
2306
+ "aria-valuetext": `${Math.round(hsv.a * 100)} percent`,
2307
+ onChange: (event) => emit({ ...hsv, a: Number(event.target.value) / 100 })
2308
+ }
2309
+ ) : null
2310
+ ] })
2311
+ ] }),
2312
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ansh-colorpicker__row", children: /* @__PURE__ */ jsxRuntime.jsx(
2313
+ "input",
2314
+ {
2315
+ type: "text",
2316
+ className: "ansh-input ansh-input--sm ansh-colorpicker__text",
2317
+ value: current,
2318
+ "aria-label": `${label} value`,
2319
+ spellCheck: false,
2320
+ onChange: (event) => {
2321
+ const text = event.target.value;
2322
+ setCurrent(text);
2323
+ const rgb = core.tryParseColor(text);
2324
+ if (rgb) hueRef.current = core.rgbToHsv(rgb).h;
2325
+ }
2326
+ }
2327
+ ) }),
2328
+ contrast !== null ? /* @__PURE__ */ jsxRuntime.jsxs(
2329
+ "p",
2330
+ {
2331
+ className: chunkSFU5EPSN_cjs.cx(
2332
+ "ansh-colorpicker__contrast",
2333
+ contrast >= 4.5 && "ansh-colorpicker__contrast--pass",
2334
+ contrast < 3 && "ansh-colorpicker__contrast--fail"
2335
+ ),
2336
+ "aria-live": "polite",
2337
+ children: [
2338
+ contrast.toFixed(2),
2339
+ ":1 against ",
2340
+ contrastAgainst,
2341
+ " \u2014",
2342
+ " ",
2343
+ contrast >= 7 ? "AAA" : contrast >= 4.5 ? "AA" : contrast >= 3 ? "AA large only" : "fails"
2344
+ ]
2345
+ }
2346
+ ) : null,
2347
+ presets && presets.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ansh-colorpicker__presets", role: "group", "aria-label": "Preset colours", children: presets.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
2348
+ "button",
2349
+ {
2350
+ type: "button",
2351
+ className: chunkSFU5EPSN_cjs.cx(
2352
+ "ansh-colorpicker__preset",
2353
+ preset.toLowerCase() === swatch.toLowerCase() && "ansh-colorpicker__preset--on"
2354
+ ),
2355
+ style: { background: preset },
2356
+ "aria-label": preset,
2357
+ "aria-pressed": preset.toLowerCase() === swatch.toLowerCase(),
2358
+ onClick: () => {
2359
+ const rgb = core.tryParseColor(preset);
2360
+ if (rgb) {
2361
+ hueRef.current = core.rgbToHsv(rgb).h;
2362
+ setCurrent(preset);
2363
+ }
2364
+ }
2365
+ },
2366
+ preset
2367
+ )) }) : null,
2368
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-visually-hidden", "aria-live": "polite", id: `${id}-live`, children: swatch })
2369
+ ]
2370
+ }
2371
+ ) }) : null
2372
+ ] });
2373
+ }
2374
+ function startOfDay(date) {
2375
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate());
2376
+ }
2377
+ function addDays(date, days) {
2378
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate() + days);
2379
+ }
2380
+ function addMonths(date, months) {
2381
+ const target = new Date(date.getFullYear(), date.getMonth() + months, 1);
2382
+ const lastDay = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate();
2383
+ return new Date(target.getFullYear(), target.getMonth(), Math.min(date.getDate(), lastDay));
2384
+ }
2385
+ function isSameDay(a, b) {
2386
+ if (!a || !b) return false;
2387
+ return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
2388
+ }
2389
+ function defaultWeekStart(locale) {
2390
+ const region = (locale ?? (typeof navigator !== "undefined" ? navigator.language : "en-GB")).split("-")[1]?.toUpperCase();
2391
+ return region && ["US", "CA", "JP", "IL", "BR", "MX", "PH", "KR"].includes(region) ? 0 : 1;
2392
+ }
2393
+ function isoWeek(date) {
2394
+ const target = new Date(date.getFullYear(), date.getMonth(), date.getDate());
2395
+ target.setDate(target.getDate() + 3 - (target.getDay() + 6) % 7);
2396
+ const firstThursday = new Date(target.getFullYear(), 0, 4);
2397
+ firstThursday.setDate(firstThursday.getDate() + 3 - (firstThursday.getDay() + 6) % 7);
2398
+ return 1 + Math.round((target.getTime() - firstThursday.getTime()) / (7 * 864e5));
2399
+ }
2400
+ function Calendar({
2401
+ mode = "single",
2402
+ value,
2403
+ defaultValue,
2404
+ onChange,
2405
+ min,
2406
+ max,
2407
+ isDateDisabled,
2408
+ weekStartsOn,
2409
+ locale,
2410
+ months = 1,
2411
+ showWeekNumbers = false,
2412
+ className
2413
+ }) {
2414
+ const [selection, setSelection] = chunkPO5DU3FU_cjs.useControllableState({
2415
+ value,
2416
+ defaultValue: defaultValue ?? (mode === "range" ? { start: null, end: null } : null),
2417
+ onChange
2418
+ });
2419
+ const single = mode === "single" ? selection : null;
2420
+ const range = mode === "range" ? selection : { start: null, end: null };
2421
+ const today = react.useMemo(() => startOfDay(/* @__PURE__ */ new Date()), []);
2422
+ const [viewMonth, setViewMonth] = react.useState(() => startOfDay(single ?? range.start ?? /* @__PURE__ */ new Date()));
2423
+ const [cursor, setCursor] = react.useState(() => startOfDay(single ?? range.start ?? /* @__PURE__ */ new Date()));
2424
+ const [hovered, setHovered] = react.useState(null);
2425
+ const gridRef = react.useRef(null);
2426
+ const shouldFocusRef = react.useRef(false);
2427
+ const firstWeekday = weekStartsOn ?? defaultWeekStart(locale);
2428
+ const dayNames = react.useMemo(() => {
2429
+ const formatter = new Intl.DateTimeFormat(locale, { weekday: "short" });
2430
+ const longFormatter = new Intl.DateTimeFormat(locale, { weekday: "long" });
2431
+ return Array.from({ length: 7 }, (_, i) => {
2432
+ const date = new Date(2024, 0, 7 + (firstWeekday + i) % 7);
2433
+ return { short: formatter.format(date), long: longFormatter.format(date) };
2434
+ });
2435
+ }, [locale, firstWeekday]);
2436
+ const monthLabel = react.useMemo(
2437
+ () => new Intl.DateTimeFormat(locale, { month: "long", year: "numeric" }),
2438
+ [locale]
2439
+ );
2440
+ const fullDate = react.useMemo(
2441
+ () => new Intl.DateTimeFormat(locale, {
2442
+ weekday: "long",
2443
+ day: "numeric",
2444
+ month: "long",
2445
+ year: "numeric"
2446
+ }),
2447
+ [locale]
2448
+ );
2449
+ const disabled = (date) => {
2450
+ if (min && date < startOfDay(min)) return true;
2451
+ if (max && date > startOfDay(max)) return true;
2452
+ return isDateDisabled?.(date) ?? false;
2453
+ };
2454
+ const moveCursor = (next) => {
2455
+ shouldFocusRef.current = true;
2456
+ setCursor(next);
2457
+ const firstVisible = new Date(viewMonth.getFullYear(), viewMonth.getMonth(), 1);
2458
+ const lastVisible = new Date(viewMonth.getFullYear(), viewMonth.getMonth() + months, 0);
2459
+ if (next < firstVisible || next > lastVisible) setViewMonth(next);
2460
+ };
2461
+ react.useEffect(() => {
2462
+ if (!shouldFocusRef.current) return;
2463
+ shouldFocusRef.current = false;
2464
+ gridRef.current?.querySelector('[data-ansh-day][tabindex="0"]')?.focus({ preventScroll: true });
2465
+ }, [cursor, viewMonth]);
2466
+ const commit = (date) => {
2467
+ if (disabled(date)) return;
2468
+ if (mode === "single") {
2469
+ setSelection(date);
2470
+ return;
2471
+ }
2472
+ if (!range.start || range.end || date < range.start) {
2473
+ setSelection({ start: date, end: null });
2474
+ } else {
2475
+ setSelection({ start: range.start, end: date });
2476
+ }
2477
+ };
2478
+ const onKeyDown = (event) => {
2479
+ let next = null;
2480
+ switch (event.key) {
2481
+ case "ArrowLeft":
2482
+ next = addDays(cursor, -1);
2483
+ break;
2484
+ case "ArrowRight":
2485
+ next = addDays(cursor, 1);
2486
+ break;
2487
+ case "ArrowUp":
2488
+ next = addDays(cursor, -7);
2489
+ break;
2490
+ case "ArrowDown":
2491
+ next = addDays(cursor, 7);
2492
+ break;
2493
+ case "Home":
2494
+ next = addDays(cursor, -((cursor.getDay() - firstWeekday + 7) % 7));
2495
+ break;
2496
+ case "End":
2497
+ next = addDays(cursor, 6 - (cursor.getDay() - firstWeekday + 7) % 7);
2498
+ break;
2499
+ case "PageUp":
2500
+ next = addMonths(cursor, event.shiftKey ? -12 : -1);
2501
+ break;
2502
+ case "PageDown":
2503
+ next = addMonths(cursor, event.shiftKey ? 12 : 1);
2504
+ break;
2505
+ case "Enter":
2506
+ case " ":
2507
+ event.preventDefault();
2508
+ commit(cursor);
2509
+ return;
2510
+ default:
2511
+ return;
2512
+ }
2513
+ event.preventDefault();
2514
+ moveCursor(next);
2515
+ };
2516
+ const inRange = (date) => {
2517
+ if (mode !== "range" || !range.start) return false;
2518
+ const end = range.end ?? hovered;
2519
+ if (!end) return false;
2520
+ const [low, high] = range.start <= end ? [range.start, end] : [end, range.start];
2521
+ return date > low && date < high;
2522
+ };
2523
+ const renderMonth = (offset) => {
2524
+ const monthDate = new Date(viewMonth.getFullYear(), viewMonth.getMonth() + offset, 1);
2525
+ const firstOfMonth = new Date(monthDate.getFullYear(), monthDate.getMonth(), 1);
2526
+ const leading = (firstOfMonth.getDay() - firstWeekday + 7) % 7;
2527
+ const gridStart = addDays(firstOfMonth, -leading);
2528
+ const days = Array.from({ length: 42 }, (_, i) => addDays(gridStart, i));
2529
+ const weeks = Array.from({ length: 6 }, (_, w) => days.slice(w * 7, w * 7 + 7));
2530
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ansh-calendar__month", children: [
2531
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ansh-calendar__caption", "aria-hidden": "true", children: monthLabel.format(monthDate) }),
2532
+ /* @__PURE__ */ jsxRuntime.jsxs(
2533
+ "table",
2534
+ {
2535
+ className: "ansh-calendar__grid",
2536
+ role: "grid",
2537
+ "aria-label": monthLabel.format(monthDate),
2538
+ children: [
2539
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
2540
+ showWeekNumbers ? /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", className: "ansh-calendar__weekno-head", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-visually-hidden", children: "Week" }) }) : null,
2541
+ dayNames.map((day) => /* @__PURE__ */ jsxRuntime.jsxs("th", { scope: "col", className: "ansh-calendar__weekday", abbr: day.long, children: [
2542
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: day.short }),
2543
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-visually-hidden", children: day.long })
2544
+ ] }, day.long))
2545
+ ] }) }),
2546
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: weeks.map((week) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
2547
+ showWeekNumbers ? /* @__PURE__ */ jsxRuntime.jsx("td", { className: "ansh-calendar__weekno", children: isoWeek(week[0]) }) : null,
2548
+ week.map((date) => {
2549
+ const outside = date.getMonth() !== monthDate.getMonth();
2550
+ const isDisabled = disabled(date);
2551
+ const isSelected = mode === "single" ? isSameDay(date, single) : isSameDay(date, range.start) || isSameDay(date, range.end);
2552
+ const isCursor = isSameDay(date, cursor);
2553
+ return /* @__PURE__ */ jsxRuntime.jsx("td", { className: "ansh-calendar__cell", role: "gridcell", children: /* @__PURE__ */ jsxRuntime.jsx(
2554
+ "button",
2555
+ {
2556
+ type: "button",
2557
+ "data-ansh-day": "",
2558
+ className: chunkSFU5EPSN_cjs.cx(
2559
+ "ansh-calendar__day",
2560
+ outside && "ansh-calendar__day--outside",
2561
+ isSelected && "ansh-calendar__day--selected",
2562
+ inRange(date) && "ansh-calendar__day--in-range",
2563
+ isSameDay(date, today) && "ansh-calendar__day--today"
2564
+ ),
2565
+ tabIndex: isCursor ? 0 : -1,
2566
+ disabled: isDisabled,
2567
+ "aria-selected": isSelected,
2568
+ "aria-current": isSameDay(date, today) ? "date" : void 0,
2569
+ "aria-label": fullDate.format(date),
2570
+ onClick: () => {
2571
+ setCursor(date);
2572
+ commit(date);
2573
+ },
2574
+ onMouseEnter: () => mode === "range" && setHovered(date),
2575
+ onFocus: () => setCursor(date),
2576
+ children: date.getDate()
2577
+ }
2578
+ ) }, date.toISOString());
2579
+ })
2580
+ ] }, week[0].toISOString())) })
2581
+ ]
2582
+ }
2583
+ )
2584
+ ] }, offset);
2585
+ };
2586
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2587
+ "div",
2588
+ {
2589
+ className: chunkSFU5EPSN_cjs.cx("ansh-calendar", months > 1 && "ansh-calendar--multi", className),
2590
+ onKeyDown,
2591
+ onMouseLeave: () => setHovered(null),
2592
+ children: [
2593
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ansh-calendar__header", children: [
2594
+ /* @__PURE__ */ jsxRuntime.jsx(
2595
+ "button",
2596
+ {
2597
+ type: "button",
2598
+ className: "ansh-calendar__nav ansh-focusable",
2599
+ "aria-label": "Previous month",
2600
+ onClick: () => setViewMonth(addMonths(viewMonth, -1)),
2601
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 12 12", width: "14", height: "14", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(
2602
+ "path",
2603
+ {
2604
+ d: "M7.5 2.5L4 6l3.5 3.5",
2605
+ stroke: "currentColor",
2606
+ strokeWidth: "1.5",
2607
+ fill: "none",
2608
+ strokeLinecap: "round",
2609
+ strokeLinejoin: "round"
2610
+ }
2611
+ ) })
2612
+ }
2613
+ ),
2614
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ansh-calendar__title", "aria-live": "polite", children: months > 1 ? `${monthLabel.format(viewMonth)} \u2013 ${monthLabel.format(new Date(viewMonth.getFullYear(), viewMonth.getMonth() + months - 1, 1))}` : monthLabel.format(viewMonth) }),
2615
+ /* @__PURE__ */ jsxRuntime.jsx(
2616
+ "button",
2617
+ {
2618
+ type: "button",
2619
+ className: "ansh-calendar__nav ansh-focusable",
2620
+ "aria-label": "Next month",
2621
+ onClick: () => setViewMonth(addMonths(viewMonth, 1)),
2622
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 12 12", width: "14", height: "14", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(
2623
+ "path",
2624
+ {
2625
+ d: "M4.5 2.5L8 6l-3.5 3.5",
2626
+ stroke: "currentColor",
2627
+ strokeWidth: "1.5",
2628
+ fill: "none",
2629
+ strokeLinecap: "round",
2630
+ strokeLinejoin: "round"
2631
+ }
2632
+ ) })
2633
+ }
2634
+ )
2635
+ ] }),
2636
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ansh-calendar__months", ref: gridRef, children: Array.from({ length: months }, (_, index) => renderMonth(index)) })
2637
+ ]
2638
+ }
2639
+ );
2640
+ }
2641
+ function DatePicker({
2642
+ value,
2643
+ defaultValue = null,
2644
+ onChange,
2645
+ placeholder,
2646
+ disabled = false,
2647
+ invalid = false,
2648
+ clearable = true,
2649
+ format,
2650
+ label = "Date",
2651
+ className,
2652
+ name,
2653
+ locale,
2654
+ ...calendarProps
2655
+ }) {
2656
+ const fieldProps = useFieldControl();
2657
+ const [selected, setSelected] = chunkPO5DU3FU_cjs.useControllableState({
2658
+ value,
2659
+ defaultValue,
2660
+ onChange
2661
+ });
2662
+ const [open, setOpen] = react.useState(false);
2663
+ const [text, setText] = react.useState("");
2664
+ const [editing, setEditing] = react.useState(false);
2665
+ const anchorRef = react.useRef(null);
2666
+ const panelRef = react.useRef(null);
2667
+ const inputRef = react.useRef(null);
2668
+ const formatter = react.useMemo(
2669
+ () => new Intl.DateTimeFormat(locale, { day: "2-digit", month: "2-digit", year: "numeric" }),
2670
+ [locale]
2671
+ );
2672
+ const order = react.useMemo(() => {
2673
+ const parts = formatter.formatToParts(new Date(2026, 2, 14));
2674
+ return parts.filter((p) => ["day", "month", "year"].includes(p.type)).map((p) => p.type);
2675
+ }, [formatter]);
2676
+ const display = format ? selected ? format(selected) : "" : selected ? formatter.format(selected) : "";
2677
+ const parse = (raw) => {
2678
+ const numbers = raw.split(/\D+/).filter(Boolean).map(Number);
2679
+ if (numbers.length < 3) return null;
2680
+ const parts = {};
2681
+ order.forEach((type, index) => {
2682
+ parts[type] = numbers[index];
2683
+ });
2684
+ const { month = 0, day = 0 } = parts;
2685
+ let { year = 0 } = parts;
2686
+ if (year < 100) year += year < 70 ? 2e3 : 1900;
2687
+ const date = new Date(year, month - 1, day);
2688
+ if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) {
2689
+ return null;
2690
+ }
2691
+ return startOfDay(date);
2692
+ };
2693
+ const commitText = () => {
2694
+ setEditing(false);
2695
+ if (text.trim() === "") {
2696
+ setSelected(null);
2697
+ return;
2698
+ }
2699
+ const parsed = parse(text);
2700
+ if (parsed) setSelected(parsed);
2701
+ setText("");
2702
+ };
2703
+ const position = chunkXMXECSQO_cjs.useAnchoredPosition(anchorRef, panelRef, open, {
2704
+ placement: "bottom-start",
2705
+ offset: 6
2706
+ });
2707
+ chunkXMXECSQO_cjs.useDismiss(panelRef, open, () => setOpen(false), { ignore: [anchorRef] });
2708
+ const placeholderText = placeholder ?? order.map((type) => type === "year" ? "yyyy" : type === "month" ? "mm" : "dd").join("/");
2709
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkSFU5EPSN_cjs.cx("ansh-datepicker", className), children: [
2710
+ /* @__PURE__ */ jsxRuntime.jsxs(
2711
+ "div",
2712
+ {
2713
+ ref: anchorRef,
2714
+ className: chunkSFU5EPSN_cjs.cx(
2715
+ "ansh-input-group",
2716
+ "ansh-focusable-within",
2717
+ (invalid || fieldProps["aria-invalid"]) && "ansh-input-group--invalid",
2718
+ disabled && "ansh-input-group--disabled"
2719
+ ),
2720
+ children: [
2721
+ /* @__PURE__ */ jsxRuntime.jsx(
2722
+ "input",
2723
+ {
2724
+ ref: inputRef,
2725
+ type: "text",
2726
+ inputMode: "numeric",
2727
+ className: "ansh-input",
2728
+ value: editing ? text : display,
2729
+ placeholder: placeholderText,
2730
+ disabled: disabled || fieldProps.disabled,
2731
+ "aria-label": label,
2732
+ "aria-invalid": invalid || void 0,
2733
+ autoComplete: "off",
2734
+ ...fieldProps,
2735
+ onChange: (event) => {
2736
+ setEditing(true);
2737
+ setText(event.target.value);
2738
+ },
2739
+ onBlur: commitText,
2740
+ onKeyDown: (event) => {
2741
+ if (event.key === "Enter") {
2742
+ event.preventDefault();
2743
+ commitText();
2744
+ setOpen(false);
2745
+ } else if (event.key === "ArrowDown" && !open) {
2746
+ event.preventDefault();
2747
+ setOpen(true);
2748
+ } else if (event.key === "Escape" && open) {
2749
+ event.preventDefault();
2750
+ setOpen(false);
2751
+ }
2752
+ }
2753
+ }
2754
+ ),
2755
+ clearable && selected && !disabled ? /* @__PURE__ */ jsxRuntime.jsx(
2756
+ "button",
2757
+ {
2758
+ type: "button",
2759
+ className: "ansh-input-group__clear ansh-focusable",
2760
+ "aria-label": "Clear date",
2761
+ onClick: () => {
2762
+ setSelected(null);
2763
+ setText("");
2764
+ inputRef.current?.focus();
2765
+ },
2766
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 16 16", width: "12", height: "12", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(
2767
+ "path",
2768
+ {
2769
+ d: "M4 4l8 8M12 4l-8 8",
2770
+ stroke: "currentColor",
2771
+ strokeWidth: "1.75",
2772
+ strokeLinecap: "round",
2773
+ fill: "none"
2774
+ }
2775
+ ) })
2776
+ }
2777
+ ) : null,
2778
+ /* @__PURE__ */ jsxRuntime.jsx(
2779
+ "button",
2780
+ {
2781
+ type: "button",
2782
+ className: "ansh-input-group__button ansh-focusable",
2783
+ "aria-label": "Open calendar",
2784
+ "aria-haspopup": "dialog",
2785
+ "aria-expanded": open,
2786
+ disabled,
2787
+ onClick: () => setOpen((v) => !v),
2788
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
2789
+ "svg",
2790
+ {
2791
+ viewBox: "0 0 20 20",
2792
+ width: "16",
2793
+ height: "16",
2794
+ fill: "none",
2795
+ stroke: "currentColor",
2796
+ strokeWidth: "1.5",
2797
+ "aria-hidden": "true",
2798
+ children: [
2799
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "4.5", width: "14", height: "13", rx: "2.5" }),
2800
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 8.5h14M7 2.5v3M13 2.5v3", strokeLinecap: "round" })
2801
+ ]
2802
+ }
2803
+ )
2804
+ }
2805
+ )
2806
+ ]
2807
+ }
2808
+ ),
2809
+ name ? (
2810
+ // ISO in the hidden field. A server parsing "14/03/2026" has to guess the locale; an ISO
2811
+ // date is unambiguous everywhere.
2812
+ /* @__PURE__ */ jsxRuntime.jsx(
2813
+ "input",
2814
+ {
2815
+ type: "hidden",
2816
+ name,
2817
+ value: selected ? `${selected.getFullYear()}-${String(selected.getMonth() + 1).padStart(2, "0")}-${String(selected.getDate()).padStart(2, "0")}` : ""
2818
+ }
2819
+ )
2820
+ ) : null,
2821
+ open ? /* @__PURE__ */ jsxRuntime.jsx(chunkXMXECSQO_cjs.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
2822
+ "div",
2823
+ {
2824
+ ref: panelRef,
2825
+ role: "dialog",
2826
+ "aria-label": label,
2827
+ className: "ansh-datepicker__panel",
2828
+ style: position.style,
2829
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2830
+ Calendar,
2831
+ {
2832
+ mode: "single",
2833
+ value: selected,
2834
+ onChange: (next) => {
2835
+ setSelected(next);
2836
+ setOpen(false);
2837
+ inputRef.current?.focus();
2838
+ },
2839
+ ...locale ? { locale } : null,
2840
+ ...calendarProps
2841
+ }
2842
+ )
2843
+ }
2844
+ ) }) : null
2845
+ ] });
2846
+ }
2847
+ function DateRangePicker({
2848
+ value,
2849
+ defaultValue = { start: null, end: null },
2850
+ onChange,
2851
+ disabled = false,
2852
+ invalid = false,
2853
+ label = "Date range",
2854
+ className,
2855
+ months = 2,
2856
+ locale,
2857
+ ...calendarProps
2858
+ }) {
2859
+ const [range, setRange] = chunkPO5DU3FU_cjs.useControllableState({ value, defaultValue, onChange });
2860
+ const [open, setOpen] = react.useState(false);
2861
+ const anchorRef = react.useRef(null);
2862
+ const panelRef = react.useRef(null);
2863
+ const formatter = react.useMemo(
2864
+ () => new Intl.DateTimeFormat(locale, { day: "numeric", month: "short", year: "numeric" }),
2865
+ [locale]
2866
+ );
2867
+ const position = chunkXMXECSQO_cjs.useAnchoredPosition(anchorRef, panelRef, open, {
2868
+ placement: "bottom-start",
2869
+ offset: 6
2870
+ });
2871
+ chunkXMXECSQO_cjs.useDismiss(panelRef, open, () => setOpen(false), { ignore: [anchorRef] });
2872
+ const summary = range.start && range.end ? `${formatter.format(range.start)} \u2013 ${formatter.format(range.end)}` : range.start ? `${formatter.format(range.start)} \u2013 \u2026` : "Select dates";
2873
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunkSFU5EPSN_cjs.cx("ansh-datepicker", className), children: [
2874
+ /* @__PURE__ */ jsxRuntime.jsxs(
2875
+ "button",
2876
+ {
2877
+ ref: anchorRef,
2878
+ type: "button",
2879
+ className: chunkSFU5EPSN_cjs.cx(
2880
+ "ansh-select__trigger",
2881
+ "ansh-focusable",
2882
+ open && "ansh-select__trigger--open",
2883
+ invalid && "ansh-select__trigger--invalid",
2884
+ !range.start && "ansh-select__trigger--placeholder"
2885
+ ),
2886
+ disabled,
2887
+ "aria-haspopup": "dialog",
2888
+ "aria-expanded": open,
2889
+ "aria-label": `${label}: ${summary}`,
2890
+ onClick: () => setOpen((v) => !v),
2891
+ children: [
2892
+ /* @__PURE__ */ jsxRuntime.jsxs(
2893
+ "svg",
2894
+ {
2895
+ viewBox: "0 0 20 20",
2896
+ width: "16",
2897
+ height: "16",
2898
+ fill: "none",
2899
+ stroke: "currentColor",
2900
+ strokeWidth: "1.5",
2901
+ "aria-hidden": "true",
2902
+ children: [
2903
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "4.5", width: "14", height: "13", rx: "2.5" }),
2904
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 8.5h14M7 2.5v3M13 2.5v3", strokeLinecap: "round" })
2905
+ ]
2906
+ }
2907
+ ),
2908
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ansh-select__value", children: summary })
2909
+ ]
2910
+ }
2911
+ ),
2912
+ open ? /* @__PURE__ */ jsxRuntime.jsx(chunkXMXECSQO_cjs.Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
2913
+ "div",
2914
+ {
2915
+ ref: panelRef,
2916
+ role: "dialog",
2917
+ "aria-label": label,
2918
+ className: "ansh-datepicker__panel",
2919
+ style: position.style,
2920
+ children: /* @__PURE__ */ jsxRuntime.jsx(
2921
+ Calendar,
2922
+ {
2923
+ mode: "range",
2924
+ months,
2925
+ value: range,
2926
+ onChange: (next) => {
2927
+ const nextRange = next;
2928
+ setRange(nextRange);
2929
+ if (nextRange.start && nextRange.end) setOpen(false);
2930
+ },
2931
+ ...locale ? { locale } : null,
2932
+ ...calendarProps
2933
+ }
2934
+ )
2935
+ }
2936
+ ) }) : null
2937
+ ] });
2938
+ }
2939
+
2940
+ exports.Calendar = Calendar;
2941
+ exports.Checkbox = Checkbox;
2942
+ exports.ChoiceCard = ChoiceCard;
2943
+ exports.ColorPicker = ColorPicker;
2944
+ exports.Combobox = Combobox;
2945
+ exports.DatePicker = DatePicker;
2946
+ exports.DateRangePicker = DateRangePicker;
2947
+ exports.Dropzone = Dropzone;
2948
+ exports.Field = Field;
2949
+ exports.Fieldset = Fieldset;
2950
+ exports.Input = Input;
2951
+ exports.NumberInput = NumberInput;
2952
+ exports.OptionList = OptionList;
2953
+ exports.PinInput = PinInput;
2954
+ exports.Radio = Radio;
2955
+ exports.RadioGroup = RadioGroup;
2956
+ exports.RangeSlider = RangeSlider;
2957
+ exports.Rating = Rating;
2958
+ exports.Select = Select;
2959
+ exports.Slider = Slider;
2960
+ exports.Switch = Switch;
2961
+ exports.TagsInput = TagsInput;
2962
+ exports.Textarea = Textarea;
2963
+ exports.VisuallyHidden = VisuallyHidden;
2964
+ exports.addDays = addDays;
2965
+ exports.addMonths = addMonths;
2966
+ exports.filterOptions = filterOptions;
2967
+ exports.firstEnabled = firstEnabled;
2968
+ exports.isSameDay = isSameDay;
2969
+ exports.scoreOption = scoreOption;
2970
+ exports.startOfDay = startOfDay;
2971
+ exports.stepActive = stepActive;
2972
+ exports.useFieldContext = useFieldContext;
2973
+ exports.useFieldControl = useFieldControl;
2974
+ exports.useTypeahead = useTypeahead;
2975
+ //# sourceMappingURL=chunk-RHTLNSVW.cjs.map
2976
+ //# sourceMappingURL=chunk-RHTLNSVW.cjs.map