orynn 0.1.0 → 0.5.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.
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
- import { useId, forwardRef, useCallback, useMemo, useRef, useReducer, useState, memo } from 'react';
1
+ import { createContext, forwardRef, useContext, useId, useRef, useEffect, useCallback, useMemo, useState, useImperativeHandle, useLayoutEffect, useReducer, memo } from 'react';
2
2
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
+ import { createPortal } from 'react-dom';
4
+ import { Dialog as Dialog$1, Popover as Popover$1, DropdownMenu as DropdownMenu$1, Slot, Label as Label$1, Separator as Separator$1, Switch as Switch$1, Tabs as Tabs$1, Tooltip as Tooltip$1 } from 'radix-ui';
3
5
 
4
6
  var __typeError = (msg) => {
5
7
  throw TypeError(msg);
@@ -12,6 +14,171 @@ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot
12
14
  function cx(...names) {
13
15
  return names.filter(Boolean).join(" ");
14
16
  }
17
+ var base = (props) => ({
18
+ width: "1em",
19
+ height: "1em",
20
+ viewBox: "0 0 24 24",
21
+ fill: "none",
22
+ stroke: "currentColor",
23
+ strokeWidth: 2,
24
+ strokeLinecap: "round",
25
+ strokeLinejoin: "round",
26
+ "aria-hidden": true,
27
+ focusable: false,
28
+ ...props
29
+ });
30
+ var CheckIcon = (p) => /* @__PURE__ */ jsx("svg", { ...base(p), children: /* @__PURE__ */ jsx("path", { d: "M20 6 9 17l-5-5" }) });
31
+ var MinusIcon = (p) => /* @__PURE__ */ jsx("svg", { ...base(p), children: /* @__PURE__ */ jsx("path", { d: "M5 12h14" }) });
32
+ var ChevronDownIcon = (p) => /* @__PURE__ */ jsx("svg", { ...base(p), children: /* @__PURE__ */ jsx("path", { d: "m6 9 6 6 6-6" }) });
33
+ var ChevronUpIcon = (p) => /* @__PURE__ */ jsx("svg", { ...base(p), children: /* @__PURE__ */ jsx("path", { d: "m6 15 6-6 6 6" }) });
34
+ var ChevronLeftIcon = (p) => /* @__PURE__ */ jsx("svg", { ...base(p), children: /* @__PURE__ */ jsx("path", { d: "m15 18-6-6 6-6" }) });
35
+ var ChevronRightIcon = (p) => /* @__PURE__ */ jsx("svg", { ...base(p), children: /* @__PURE__ */ jsx("path", { d: "m9 18 6-6-6-6" }) });
36
+ var XIcon = (p) => /* @__PURE__ */ jsx("svg", { ...base(p), children: /* @__PURE__ */ jsx("path", { d: "M18 6 6 18M6 6l12 12" }) });
37
+ var SpinnerIcon = (p) => /* @__PURE__ */ jsx("svg", { ...base({ className: "orynn-spin", ...p }), children: /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-6.2-8.6" }) });
38
+ var EyeIcon = (p) => /* @__PURE__ */ jsxs("svg", { ...base(p), children: [
39
+ /* @__PURE__ */ jsx("path", { d: "M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7Z" }),
40
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "3" })
41
+ ] });
42
+ var EyeOffIcon = (p) => /* @__PURE__ */ jsxs("svg", { ...base(p), children: [
43
+ /* @__PURE__ */ jsx("path", { d: "M10.7 5.1A9.9 9.9 0 0 1 12 5c6.5 0 10 7 10 7a17 17 0 0 1-3.4 4.2M6.6 6.6A17 17 0 0 0 2 12s3.5 7 10 7a9.7 9.7 0 0 0 5.4-1.6" }),
44
+ /* @__PURE__ */ jsx("path", { d: "M9.9 9.9a3 3 0 0 0 4.2 4.2M2 2l20 20" })
45
+ ] });
46
+ var CalendarIcon = (p) => /* @__PURE__ */ jsxs("svg", { ...base(p), children: [
47
+ /* @__PURE__ */ jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2" }),
48
+ /* @__PURE__ */ jsx("path", { d: "M16 2v4M8 2v4M3 10h18" })
49
+ ] });
50
+ var CircleIcon = (p) => /* @__PURE__ */ jsx("svg", { ...base({ strokeWidth: 0, fill: "currentColor", ...p }), children: /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "6" }) });
51
+ var CheckboxGroupContext = createContext(null);
52
+ var sizePx = {
53
+ sm: "0.875rem",
54
+ // 14px
55
+ md: "1rem",
56
+ // 16px — shadcn size-4
57
+ lg: "1.125rem"
58
+ // 18px
59
+ };
60
+ var Checkbox = /* @__PURE__ */ forwardRef(
61
+ function Checkbox2(props, ref) {
62
+ const group = useContext(CheckboxGroupContext);
63
+ const {
64
+ label,
65
+ description,
66
+ checked: checkedProp,
67
+ defaultChecked,
68
+ indeterminate = false,
69
+ onChange,
70
+ value,
71
+ disabled: disabledProp,
72
+ readOnly,
73
+ required,
74
+ invalid,
75
+ size: sizeProp,
76
+ variant = "filled",
77
+ labelPlacement = "end",
78
+ card,
79
+ icon,
80
+ indeterminateIcon,
81
+ className,
82
+ id: idProp,
83
+ name: nameProp,
84
+ ...rest
85
+ } = props;
86
+ const reactId = useId();
87
+ const id = idProp ?? reactId;
88
+ const innerRef = useRef(null);
89
+ const inGroup = group != null && value != null;
90
+ const groupChecked = inGroup ? group.value.includes(value) : void 0;
91
+ const isControlled = checkedProp !== void 0 || groupChecked !== void 0;
92
+ const checked = checkedProp ?? groupChecked ?? void 0;
93
+ const size = sizeProp ?? group?.size ?? "md";
94
+ const disabled = disabledProp || group?.disabled || inGroup && checked === true && group.isDisabledToUncheck(value) || inGroup && checked !== true && group.isDisabledToCheck(value) || false;
95
+ useEffect(() => {
96
+ if (innerRef.current) innerRef.current.indeterminate = indeterminate;
97
+ }, [indeterminate]);
98
+ const handleChange = (e) => {
99
+ if (readOnly) {
100
+ e.preventDefault();
101
+ return;
102
+ }
103
+ const next = e.target.checked;
104
+ onChange?.(next, e);
105
+ if (inGroup) group.toggle(value, next);
106
+ };
107
+ return /* @__PURE__ */ jsxs(
108
+ "label",
109
+ {
110
+ className: cx(
111
+ "orynn-choice",
112
+ card && "orynn-choice--card",
113
+ variant === "outline" && "orynn-choice--outline",
114
+ labelPlacement === "start" && "orynn-choice--start",
115
+ className
116
+ ),
117
+ "data-disabled": disabled || void 0,
118
+ "data-invalid": invalid || void 0,
119
+ style: { "--orynn-check-size": sizePx[size] },
120
+ children: [
121
+ /* @__PURE__ */ jsx(
122
+ "input",
123
+ {
124
+ ...rest,
125
+ ref: (n) => {
126
+ innerRef.current = n;
127
+ if (typeof ref === "function") ref(n);
128
+ else if (ref) ref.current = n;
129
+ },
130
+ type: "checkbox",
131
+ className: "orynn-choice__native",
132
+ id,
133
+ name: nameProp ?? group?.name,
134
+ value,
135
+ checked: isControlled ? Boolean(checked) : void 0,
136
+ defaultChecked: isControlled ? void 0 : defaultChecked,
137
+ disabled,
138
+ required,
139
+ "aria-invalid": invalid || void 0,
140
+ onChange: handleChange
141
+ }
142
+ ),
143
+ /* @__PURE__ */ jsxs("span", { className: "orynn-choice__control orynn-choice__control--checkbox", "aria-hidden": "true", children: [
144
+ /* @__PURE__ */ jsx("span", { className: "orynn-choice__mark orynn-choice__mark--check", children: icon ?? /* @__PURE__ */ jsx(CheckIcon, {}) }),
145
+ /* @__PURE__ */ jsx("span", { className: "orynn-choice__mark orynn-choice__mark--dash", children: indeterminateIcon ?? /* @__PURE__ */ jsx(MinusIcon, {}) })
146
+ ] }),
147
+ (label != null || description != null) && /* @__PURE__ */ jsxs("span", { className: "orynn-choice__text", children: [
148
+ label != null && /* @__PURE__ */ jsx("span", { className: "orynn-choice__label", children: label }),
149
+ description != null && /* @__PURE__ */ jsx("span", { className: "orynn-choice__desc", children: description })
150
+ ] })
151
+ ]
152
+ }
153
+ );
154
+ }
155
+ );
156
+ function useLatestRef(value) {
157
+ const ref = useRef(value);
158
+ ref.current = value;
159
+ return ref;
160
+ }
161
+
162
+ // src/core/state/use-controllable-state.ts
163
+ function useControllableState({
164
+ value,
165
+ defaultValue,
166
+ onChange
167
+ }) {
168
+ const isControlled = value !== void 0;
169
+ const [uncontrolled, setUncontrolled] = useState(defaultValue);
170
+ const current = isControlled ? value : uncontrolled;
171
+ const currentRef = useLatestRef(current);
172
+ const onChangeRef = useLatestRef(onChange);
173
+ const isControlledRef = useLatestRef(isControlled);
174
+ const setValue = useCallback((next) => {
175
+ const resolved = typeof next === "function" ? next(currentRef.current) : next;
176
+ if (Object.is(resolved, currentRef.current)) return;
177
+ if (!isControlledRef.current) setUncontrolled(resolved);
178
+ onChangeRef.current?.(resolved);
179
+ }, []);
180
+ return [current, setValue];
181
+ }
15
182
  function toMessages(error) {
16
183
  if (error == null) return [];
17
184
  return (Array.isArray(error) ? error : [error]).filter((m) => Boolean(m));
@@ -21,147 +188,2707 @@ function joinIds(...ids) {
21
188
  return list.length > 0 ? list.join(" ") : void 0;
22
189
  }
23
190
  function Field(props) {
24
- const { label, description, error, required, disabled, className, children } = props;
191
+ const { label, description, error, success, required, disabled, hideLabel, className, children } = props;
25
192
  const reactId = useId();
26
193
  const id = props.id ?? reactId;
27
194
  const messages = toMessages(error);
28
195
  const invalid = messages.length > 0;
196
+ const successMsg = !invalid && typeof success === "string" && success ? success : void 0;
197
+ const valid = !invalid && (success === true || Boolean(successMsg));
29
198
  const descriptionId = description != null ? `${id}-description` : void 0;
30
199
  const errorId = invalid ? `${id}-error` : void 0;
31
- const describedById = joinIds(descriptionId, errorId);
32
- const ctx = { id, describedById, invalid, required, disabled };
200
+ const successId = successMsg ? `${id}-success` : void 0;
201
+ const describedById = joinIds(descriptionId, errorId, successId);
202
+ const ctx = { id, describedById, invalid, valid, required, disabled };
33
203
  return /* @__PURE__ */ jsxs(
34
204
  "div",
35
205
  {
36
206
  className: cx("orynn-field", className),
37
207
  "data-invalid": invalid || void 0,
208
+ "data-valid": valid || void 0,
38
209
  "data-disabled": disabled || void 0,
39
210
  "data-required": required || void 0,
40
211
  children: [
41
- label != null && /* @__PURE__ */ jsx("label", { className: "orynn-field__label", htmlFor: id, children: label }),
212
+ label != null && !hideLabel && /* @__PURE__ */ jsx("label", { className: "orynn-field__label", htmlFor: id, id: `${id}-label`, children: label }),
42
213
  description != null && /* @__PURE__ */ jsx("p", { className: "orynn-field__description", id: descriptionId, children: description }),
43
214
  /* @__PURE__ */ jsx("div", { className: "orynn-field__control", children: typeof children === "function" ? children(ctx) : children }),
44
- invalid && /* @__PURE__ */ jsx("p", { className: "orynn-field__error", id: errorId, role: "alert", children: messages.length === 1 ? messages[0] : messages.map((m) => /* @__PURE__ */ jsx("span", { children: m }, m)) })
215
+ invalid && /* @__PURE__ */ jsx("p", { className: "orynn-field__error", id: errorId, role: "alert", children: messages.length === 1 ? messages[0] : messages.map((m) => /* @__PURE__ */ jsx("span", { children: m }, m)) }),
216
+ successMsg && /* @__PURE__ */ jsx("p", { className: "orynn-field__success", id: successId, children: successMsg })
45
217
  ]
46
218
  }
47
219
  );
48
220
  }
49
- var Dropdown = /* @__PURE__ */ forwardRef(
50
- function Dropdown2(props, ref) {
51
- const {
221
+ function CheckboxGroup(props) {
222
+ const {
223
+ label,
224
+ description,
225
+ error,
226
+ success,
227
+ required,
228
+ disabled,
229
+ name: nameProp,
230
+ size,
231
+ value: valueProp,
232
+ defaultValue,
233
+ onChange,
234
+ orientation = "vertical",
235
+ columns,
236
+ min,
237
+ max,
238
+ showSelectAll = false,
239
+ selectAllLabel = "Select all",
240
+ options,
241
+ children,
242
+ className,
243
+ id: idProp
244
+ } = props;
245
+ const reactId = useId();
246
+ const id = idProp ?? reactId;
247
+ const name = nameProp ?? id;
248
+ const [value, setValue] = useControllableState({
249
+ value: valueProp,
250
+ defaultValue: defaultValue ?? [],
251
+ onChange: void 0
252
+ });
253
+ const toggle = useCallback(
254
+ (v, next) => {
255
+ const set = new Set(value);
256
+ if (next) set.add(v);
257
+ else set.delete(v);
258
+ const arr = [...set];
259
+ setValue(arr);
260
+ onChange?.(arr);
261
+ },
262
+ [value, setValue, onChange]
263
+ );
264
+ const selectableValues = (options ?? []).filter((o) => !o.disabled).map((o) => o.value);
265
+ const allSelected = selectableValues.length > 0 && selectableValues.every((v) => value.includes(v));
266
+ const someSelected = selectableValues.some((v) => value.includes(v));
267
+ const toggleAll = () => {
268
+ if (allSelected) {
269
+ setValue([]);
270
+ onChange?.([]);
271
+ } else {
272
+ const next = max != null ? selectableValues.slice(0, max) : selectableValues;
273
+ setValue(next);
274
+ onChange?.(next);
275
+ }
276
+ };
277
+ const ctx = useMemo(
278
+ () => ({
279
+ name,
280
+ value,
281
+ toggle,
282
+ disabled,
283
+ size,
284
+ isDisabledToUncheck: () => min != null && value.length <= min,
285
+ isDisabledToCheck: (v) => max != null && value.length >= max && !value.includes(v)
286
+ }),
287
+ [name, value, toggle, disabled, size, min, max]
288
+ );
289
+ return /* @__PURE__ */ jsx(
290
+ Field,
291
+ {
52
292
  label,
53
293
  description,
54
294
  error,
55
- className,
56
- options,
57
- value,
58
- onChange,
59
- placeholder,
60
- id,
295
+ success,
61
296
  required,
62
297
  disabled,
63
- onBlur,
298
+ id,
299
+ className,
300
+ children: () => /* @__PURE__ */ jsx(CheckboxGroupContext.Provider, { value: ctx, children: /* @__PURE__ */ jsxs(
301
+ "div",
302
+ {
303
+ role: "group",
304
+ "aria-labelledby": label != null ? `${id}-label` : void 0,
305
+ className: cx("orynn-choice-group"),
306
+ "data-orientation": columns ? void 0 : orientation,
307
+ "data-columns": columns ? "" : void 0,
308
+ style: columns ? { "--orynn-choice-columns": columns } : void 0,
309
+ children: [
310
+ showSelectAll && selectableValues.length > 0 && /* @__PURE__ */ jsx("div", { className: "orynn-choice-group__selectall", children: /* @__PURE__ */ jsx(
311
+ Checkbox,
312
+ {
313
+ checked: allSelected,
314
+ indeterminate: !allSelected && someSelected,
315
+ disabled,
316
+ label: selectAllLabel,
317
+ onChange: toggleAll
318
+ }
319
+ ) }),
320
+ options ? options.map((o) => /* @__PURE__ */ jsx(
321
+ Checkbox,
322
+ {
323
+ value: o.value,
324
+ label: o.icon != null ? /* @__PURE__ */ jsxs(Fragment, { children: [
325
+ /* @__PURE__ */ jsx("span", { className: "orynn-choice__icon", children: o.icon }),
326
+ o.label
327
+ ] }) : o.label,
328
+ description: o.description,
329
+ disabled: o.disabled
330
+ },
331
+ o.value
332
+ )) : children
333
+ ]
334
+ }
335
+ ) })
336
+ }
337
+ );
338
+ }
339
+ var FieldBox = /* @__PURE__ */ forwardRef(
340
+ function FieldBox2(props, ref) {
341
+ const {
342
+ size = "md",
343
+ variant = "outline",
344
+ radius,
345
+ disabled,
346
+ invalid,
347
+ valid,
348
+ focused,
349
+ active,
350
+ open,
351
+ floatingLabel,
352
+ left,
353
+ right,
354
+ addonBefore,
355
+ addonAfter,
356
+ textarea,
357
+ className,
358
+ children,
64
359
  onFocus,
360
+ onBlur,
65
361
  ...rest
66
362
  } = props;
67
- const handleChange = useCallback(
68
- (event) => onChange?.(event.target.value, event),
69
- [onChange]
70
- );
71
- const controlled = value !== void 0;
72
- return /* @__PURE__ */ jsx(
73
- Field,
363
+ const [focusWithin, setFocusWithin] = useState(false);
364
+ const isFocused = focused ?? focusWithin;
365
+ const handleFocus = (e) => {
366
+ if (focused === void 0) setFocusWithin(true);
367
+ onFocus?.(e);
368
+ };
369
+ const handleBlur = (e) => {
370
+ if (focused === void 0 && !e.currentTarget.contains(e.relatedTarget)) {
371
+ setFocusWithin(false);
372
+ }
373
+ onBlur?.(e);
374
+ };
375
+ const hasAddon = addonBefore != null || addonAfter != null;
376
+ const box = /* @__PURE__ */ jsxs(
377
+ "div",
74
378
  {
75
- label,
76
- description,
77
- error,
78
- required,
79
- disabled,
80
- id,
81
- className,
82
- children: ({ id: fieldId, describedById, invalid }) => /* @__PURE__ */ jsxs(
83
- "select",
84
- {
85
- ...rest,
86
- ref,
87
- id: fieldId,
88
- className: "orynn-dropdown",
89
- required,
90
- disabled,
91
- "aria-invalid": invalid || void 0,
92
- "aria-describedby": describedById,
93
- ...controlled ? { value } : {},
94
- onChange: handleChange,
95
- onBlur,
96
- onFocus,
97
- children: [
98
- placeholder != null && /* @__PURE__ */ jsx("option", { value: "", disabled: required, children: placeholder }),
99
- options.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, disabled: option.disabled, children: option.label }, option.value))
100
- ]
101
- }
102
- )
379
+ ref,
380
+ className: cx(
381
+ "orynn-box",
382
+ floatingLabel != null && "orynn-box--floating",
383
+ textarea && "orynn-box--textarea",
384
+ className
385
+ ),
386
+ "data-size": size,
387
+ "data-variant": variant,
388
+ "data-radius": radius,
389
+ "data-disabled": disabled || void 0,
390
+ "data-invalid": invalid || void 0,
391
+ "data-valid": valid || void 0,
392
+ "data-focused": isFocused || void 0,
393
+ "data-active": active || isFocused || void 0,
394
+ "data-open": open || void 0,
395
+ "data-addon-before": addonBefore != null || void 0,
396
+ "data-addon-after": addonAfter != null || void 0,
397
+ onFocus: handleFocus,
398
+ onBlur: handleBlur,
399
+ ...rest,
400
+ children: [
401
+ left != null && /* @__PURE__ */ jsx("span", { className: "orynn-box__adornment", children: left }),
402
+ children,
403
+ floatingLabel,
404
+ right != null && /* @__PURE__ */ jsx("span", { className: "orynn-box__adornment", children: right })
405
+ ]
103
406
  }
104
407
  );
408
+ if (!hasAddon) return box;
409
+ return /* @__PURE__ */ jsxs("div", { className: "orynn-box__group", "data-size": size, "data-disabled": disabled || void 0, children: [
410
+ addonBefore != null && /* @__PURE__ */ jsx("span", { className: "orynn-box__addon", "data-side": "before", children: addonBefore }),
411
+ box,
412
+ addonAfter != null && /* @__PURE__ */ jsx("span", { className: "orynn-box__addon", "data-side": "after", children: addonAfter })
413
+ ] });
105
414
  }
106
415
  );
107
- var Input = /* @__PURE__ */ forwardRef(
108
- function Input2(props, ref) {
416
+
417
+ // src/theme/theme.ts
418
+ var len = (v) => typeof v === "number" ? `${v}px` : v;
419
+ var RADIUS_KEYWORDS = {
420
+ none: "0px",
421
+ sm: "0.375rem",
422
+ md: "0.5rem",
423
+ lg: "0.625rem",
424
+ xl: "0.875rem",
425
+ pill: "9999px"
426
+ };
427
+ var DARK_FG = "#0b0d12";
428
+ var LIGHT_FG = "#ffffff";
429
+ function contrastFor(color) {
430
+ const c = color.trim().toLowerCase();
431
+ const hex = /^#?([\da-f]{3}|[\da-f]{6})$/.exec(c)?.[1];
432
+ if (hex) {
433
+ const full = hex.length === 3 ? hex.replace(/./g, "$&$&") : hex;
434
+ const n = Number.parseInt(full, 16);
435
+ const toLin = (v) => {
436
+ const x = v / 255;
437
+ return x <= 0.03928 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4;
438
+ };
439
+ const lum = 0.2126 * toLin(n >> 16 & 255) + 0.7152 * toLin(n >> 8 & 255) + 0.0722 * toLin(n & 255);
440
+ return lum > 0.42 ? DARK_FG : LIGHT_FG;
441
+ }
442
+ const okl = /^oklch\(\s*([\d.]+)(%?)/.exec(c);
443
+ if (okl) {
444
+ const l = Number.parseFloat(okl[1]) / (okl[2] ? 100 : 1);
445
+ return l >= 0.62 ? DARK_FG : LIGHT_FG;
446
+ }
447
+ const hsl = /^hsla?\(\s*[\d.]+(?:deg)?\s*[, ]\s*[\d.]+%\s*[, ]\s*([\d.]+)%/.exec(c)?.[1];
448
+ if (hsl) return Number.parseFloat(hsl) >= 60 ? DARK_FG : LIGHT_FG;
449
+ if (c === "white") return DARK_FG;
450
+ if (c === "black") return LIGHT_FG;
451
+ return LIGHT_FG;
452
+ }
453
+ function normalizeTheme(input) {
454
+ return typeof input === "string" ? { preset: input } : input ?? {};
455
+ }
456
+ function resolveThemeVars(config) {
457
+ const vars = {};
458
+ const primary = config.primary ?? config.accent;
459
+ if (primary) {
460
+ const p = primary;
461
+ vars["--orynn-color-primary"] = p;
462
+ vars["--orynn-color-primary-foreground"] = config.primaryForeground ?? config.accentContrast ?? contrastFor(p);
463
+ if (!config.ring) vars["--orynn-color-ring"] = p;
464
+ }
465
+ if (config.ring) vars["--orynn-color-ring"] = config.ring;
466
+ if (config.font) vars["--orynn-font-family"] = config.font;
467
+ if (config.fontSize != null) vars["--orynn-font-size"] = len(config.fontSize);
468
+ if (config.controlWidth != null) {
469
+ vars["--orynn-control-width"] = len(config.controlWidth);
470
+ vars["--orynn-control-max-width"] = "none";
471
+ }
472
+ if (config.controlMaxWidth != null)
473
+ vars["--orynn-control-max-width"] = len(config.controlMaxWidth);
474
+ if (config.radius != null) {
475
+ const r = config.radius;
476
+ vars["--orynn-radius"] = typeof r === "string" && r in RADIUS_KEYWORDS ? RADIUS_KEYWORDS[r] : len(r);
477
+ }
478
+ Object.assign(vars, config.vars ?? {});
479
+ return vars;
480
+ }
481
+ var OrynnContext = createContext({
482
+ preset: "default",
483
+ density: "comfortable",
484
+ config: {},
485
+ portalContainer: null
486
+ });
487
+ function syncThemeEl(el, preset, density, config, style) {
488
+ const attr = (name, value) => value == null ? el.removeAttribute(name) : el.setAttribute(name, value);
489
+ attr("data-orynn-theme", preset === "default" ? null : preset);
490
+ attr("data-orynn-density", density === "comfortable" ? null : density);
491
+ attr("data-orynn-color-scheme", config.colorScheme ?? null);
492
+ el.classList.toggle("dark", config.colorScheme === "dark");
493
+ el.removeAttribute("style");
494
+ for (const [k, v] of Object.entries(style)) {
495
+ if (v != null) el.style.setProperty(k, String(v));
496
+ }
497
+ }
498
+ function OrynnProvider({ theme, as = "div", className, children }) {
499
+ const config = useMemo(() => normalizeTheme(theme), [theme]);
500
+ const preset = config.preset ?? "default";
501
+ const density = config.density ?? "comfortable";
502
+ const style = useMemo(() => resolveThemeVars(config), [config]);
503
+ const [portalContainer, setPortalContainer] = useState(null);
504
+ useEffect(() => {
505
+ if (typeof document === "undefined") return;
506
+ const el = document.createElement("div");
507
+ el.className = "orynn-portal";
508
+ document.body.appendChild(el);
509
+ setPortalContainer(el);
510
+ return () => {
511
+ el.remove();
512
+ setPortalContainer(null);
513
+ };
514
+ }, []);
515
+ useEffect(() => {
516
+ if (portalContainer)
517
+ syncThemeEl(portalContainer, preset, density, config, style);
518
+ }, [portalContainer, preset, density, config, style]);
519
+ const ctx = useMemo(
520
+ () => ({ preset, density, config, portalContainer }),
521
+ [preset, density, config, portalContainer]
522
+ );
523
+ const dataProps = {
524
+ "data-orynn-theme": preset === "default" ? void 0 : preset,
525
+ "data-orynn-density": density === "comfortable" ? void 0 : density,
526
+ "data-orynn-color-scheme": config.colorScheme
527
+ };
528
+ const darkClass = config.colorScheme === "dark" ? "dark" : void 0;
529
+ return /* @__PURE__ */ jsx(OrynnContext.Provider, { value: ctx, children: as === "contents" ? /* @__PURE__ */ jsx("div", { className: darkClass, style: { display: "contents", ...style }, ...dataProps, children }) : as === "span" ? /* @__PURE__ */ jsx("span", { className: cx("orynn-root", className, darkClass), style, ...dataProps, children }) : /* @__PURE__ */ jsx("div", { className: cx("orynn-root", className, darkClass), style, ...dataProps, children }) });
530
+ }
531
+ function useOrynnTheme() {
532
+ return useContext(OrynnContext);
533
+ }
534
+ function usePortalContainer() {
535
+ const { portalContainer } = useContext(OrynnContext);
536
+ if (portalContainer) return portalContainer;
537
+ return typeof document === "undefined" ? null : document.body;
538
+ }
539
+ var useIsoLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
540
+ function Popover({
541
+ open,
542
+ anchorRef,
543
+ onClose,
544
+ children,
545
+ matchWidth = true,
546
+ offset = 6,
547
+ maxHeight,
548
+ className,
549
+ popoverRef,
550
+ role,
551
+ id
552
+ }) {
553
+ const innerRef = useRef(null);
554
+ const setRef = (el) => {
555
+ innerRef.current = el;
556
+ if (popoverRef) popoverRef.current = el;
557
+ };
558
+ const [pos, setPos] = useState(null);
559
+ const container = usePortalContainer();
560
+ useIsoLayoutEffect(() => {
561
+ if (!open) return;
562
+ const anchor = anchorRef.current;
563
+ if (!anchor) return;
564
+ const update = () => {
565
+ const r = anchor.getBoundingClientRect();
566
+ const vh = window.innerHeight;
567
+ const below = vh - r.bottom - offset;
568
+ const above = r.top - offset;
569
+ const wanted = innerRef.current?.scrollHeight ?? 280;
570
+ const placeTop = below < Math.min(wanted, 240) && above > below;
571
+ const avail = Math.max(140, (placeTop ? above : below) - 4);
572
+ setPos({
573
+ left: r.left,
574
+ top: placeTop ? r.top - offset : r.bottom + offset,
575
+ width: r.width,
576
+ placement: placeTop ? "top" : "bottom",
577
+ maxHeight: maxHeight != null ? Math.min(maxHeight, avail) : avail
578
+ });
579
+ };
580
+ update();
581
+ const ro = typeof ResizeObserver !== "undefined" ? new ResizeObserver(update) : void 0;
582
+ ro?.observe(anchor);
583
+ window.addEventListener("scroll", update, true);
584
+ window.addEventListener("resize", update);
585
+ return () => {
586
+ ro?.disconnect();
587
+ window.removeEventListener("scroll", update, true);
588
+ window.removeEventListener("resize", update);
589
+ };
590
+ }, [open, anchorRef, offset, maxHeight]);
591
+ useEffect(() => {
592
+ if (!open) return;
593
+ const onPointerDown = (e) => {
594
+ const t = e.target;
595
+ if (innerRef.current?.contains(t) || anchorRef.current?.contains(t)) return;
596
+ onClose();
597
+ };
598
+ const onKey = (e) => {
599
+ if (e.key === "Escape") {
600
+ e.stopPropagation();
601
+ onClose();
602
+ }
603
+ };
604
+ document.addEventListener("pointerdown", onPointerDown, true);
605
+ document.addEventListener("keydown", onKey, true);
606
+ return () => {
607
+ document.removeEventListener("pointerdown", onPointerDown, true);
608
+ document.removeEventListener("keydown", onKey, true);
609
+ };
610
+ }, [open, anchorRef, onClose]);
611
+ if (!open || !pos || !container) return null;
612
+ return createPortal(
613
+ /* @__PURE__ */ jsx(
614
+ "div",
615
+ {
616
+ ref: setRef,
617
+ id,
618
+ role,
619
+ className: cx("orynn-popover", className),
620
+ style: {
621
+ left: pos.left,
622
+ top: pos.top,
623
+ width: matchWidth ? pos.width : void 0,
624
+ minWidth: pos.width,
625
+ maxHeight: pos.maxHeight,
626
+ transform: pos.placement === "top" ? "translateY(-100%)" : void 0
627
+ },
628
+ children
629
+ }
630
+ ),
631
+ container
632
+ );
633
+ }
634
+
635
+ // src/controls/DatePicker/date-utils.ts
636
+ var startOfDay = (d) => new Date(d.getFullYear(), d.getMonth(), d.getDate());
637
+ var isSameDay = (a, b) => !!a && !!b && a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
638
+ var addDays = (d, n) => {
639
+ const r = new Date(d);
640
+ r.setDate(r.getDate() + n);
641
+ return r;
642
+ };
643
+ var addMonths = (d, n) => {
644
+ const r = new Date(d.getFullYear(), d.getMonth() + n, 1);
645
+ const day = Math.min(d.getDate(), daysInMonth(r.getFullYear(), r.getMonth()));
646
+ r.setDate(day);
647
+ return r;
648
+ };
649
+ var daysInMonth = (year, month) => new Date(year, month + 1, 0).getDate();
650
+ var clampDate = (d, min, max) => {
651
+ if (min && d < startOfDay(min)) return startOfDay(min);
652
+ if (max && d > startOfDay(max)) return startOfDay(max);
653
+ return d;
654
+ };
655
+ var pad = (n, len2 = 2) => String(n).padStart(len2, "0");
656
+ var FORMAT_TOKENS = /(?<![A-Za-z])(yyyy|yy|MMMM|MMM|MM|M|dd|d|EEEE|EEE|HH|H|hh|h|mm|m|ss|s|aa|a|A)(?![A-Za-z])/g;
657
+ function formatDate(d, fmt = "yyyy-MM-dd", locale) {
658
+ if (typeof fmt !== "string") return new Intl.DateTimeFormat(locale, fmt).format(d);
659
+ const h12 = d.getHours() % 12 || 12;
660
+ const map = {
661
+ yyyy: String(d.getFullYear()),
662
+ yy: pad(d.getFullYear() % 100),
663
+ MMMM: new Intl.DateTimeFormat(locale, { month: "long" }).format(d),
664
+ MMM: new Intl.DateTimeFormat(locale, { month: "short" }).format(d),
665
+ MM: pad(d.getMonth() + 1),
666
+ M: String(d.getMonth() + 1),
667
+ dd: pad(d.getDate()),
668
+ d: String(d.getDate()),
669
+ EEEE: new Intl.DateTimeFormat(locale, { weekday: "long" }).format(d),
670
+ EEE: new Intl.DateTimeFormat(locale, { weekday: "short" }).format(d),
671
+ HH: pad(d.getHours()),
672
+ H: String(d.getHours()),
673
+ hh: pad(h12),
674
+ h: String(h12),
675
+ mm: pad(d.getMinutes()),
676
+ m: String(d.getMinutes()),
677
+ ss: pad(d.getSeconds()),
678
+ s: String(d.getSeconds()),
679
+ aa: d.getHours() < 12 ? "am" : "pm",
680
+ a: d.getHours() < 12 ? "am" : "pm",
681
+ A: d.getHours() < 12 ? "AM" : "PM"
682
+ };
683
+ return fmt.replace(FORMAT_TOKENS, (t) => map[t] ?? t);
684
+ }
685
+ function matchMonthName(input, locale) {
686
+ for (let m = 0; m < 12; m += 1) {
687
+ for (const style of ["long", "short"]) {
688
+ const name = new Intl.DateTimeFormat(locale, { month: style }).format(new Date(2021, m, 1));
689
+ const i = input.toLowerCase().indexOf(name.toLowerCase());
690
+ if (i !== -1) return { month: m, rest: input.slice(0, i) + input.slice(i + name.length) };
691
+ }
692
+ }
693
+ return null;
694
+ }
695
+ function parseDate(input, fmt = "yyyy-MM-dd", locale) {
696
+ const pattern = typeof fmt === "string" ? fmt : "yyyy-MM-dd";
697
+ let text = input;
698
+ let monthFromName;
699
+ if (/MMM/.test(pattern)) {
700
+ const hit = matchMonthName(text, locale);
701
+ if (hit) {
702
+ monthFromName = hit.month;
703
+ text = hit.rest;
704
+ }
705
+ }
706
+ const nums = text.match(/\d+/g);
707
+ if (!nums && monthFromName === void 0) return null;
708
+ const order = (pattern.match(/yyyy|yy|MM|dd|HH|hh|mm|ss|M|d|H|h|m|s/g) ?? ["yyyy", "MM", "dd"]).map((t) => t.length === 2 ? t.charAt(0) + t.charAt(0) : t);
709
+ let y;
710
+ let mo = monthFromName;
711
+ let day;
712
+ let hh = 0;
713
+ let mm = 0;
714
+ let ss = 0;
715
+ let ni = 0;
716
+ for (const tok of order) {
717
+ if ((tok === "MM" || tok === "M") && monthFromName !== void 0) continue;
718
+ const n = Number((nums ?? [])[ni]);
719
+ ni += 1;
720
+ if (Number.isNaN(n)) continue;
721
+ if (tok === "yyyy" || tok === "yy") y = n < 100 ? 2e3 + n : n;
722
+ else if (tok === "MM" || tok === "M") mo = n - 1;
723
+ else if (tok === "dd" || tok === "d") day = n;
724
+ else if (tok === "HH" || tok === "H" || tok === "hh" || tok === "h") hh = n;
725
+ else if (tok === "mm" || tok === "m") mm = n;
726
+ else if (tok === "ss" || tok === "s") ss = n;
727
+ }
728
+ if (/pm/i.test(input) && hh < 12) hh += 12;
729
+ if (/am/i.test(input) && hh === 12) hh = 0;
730
+ if (y == null && day == null && mo == null) return null;
731
+ const d = new Date(y ?? (/* @__PURE__ */ new Date()).getFullYear(), mo ?? 0, day ?? 1, hh, mm, ss);
732
+ return Number.isNaN(d.getTime()) ? null : d;
733
+ }
734
+ function toDate(v) {
735
+ if (v == null) return null;
736
+ if (v instanceof Date) return Number.isNaN(v.getTime()) ? null : startOfDay(v);
737
+ const d = new Date(v);
738
+ return Number.isNaN(d.getTime()) ? null : startOfDay(d);
739
+ }
740
+ function monthMatrix(viewYear, viewMonth, firstDayOfWeek, fixedWeeks = true) {
741
+ const first = new Date(viewYear, viewMonth, 1);
742
+ const offset = (first.getDay() - firstDayOfWeek + 7) % 7;
743
+ const start = addDays(first, -offset);
744
+ if (fixedWeeks) return Array.from({ length: 42 }, (_, i) => addDays(start, i));
745
+ const last = new Date(viewYear, viewMonth + 1, 0);
746
+ const used = Math.ceil((offset + last.getDate()) / 7);
747
+ return Array.from({ length: used * 7 }, (_, i) => addDays(start, i));
748
+ }
749
+ function weekdayLabels(firstDayOfWeek, locale) {
750
+ const fmt = new Intl.DateTimeFormat(locale, { weekday: "short" });
751
+ return Array.from(
752
+ { length: 7 },
753
+ (_, i) => fmt.format(new Date(2023, 0, 1 + (firstDayOfWeek + i) % 7))
754
+ );
755
+ }
756
+ function decadeGrid(year) {
757
+ const start = Math.floor(year / 10) * 10;
758
+ return { start, years: Array.from({ length: 12 }, (_, i) => start - 1 + i) };
759
+ }
760
+ function isoWeek(d) {
761
+ const date = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
762
+ const dayNum = (date.getUTCDay() + 6) % 7;
763
+ date.setUTCDate(date.getUTCDate() - dayNum + 3);
764
+ const firstThursday = new Date(Date.UTC(date.getUTCFullYear(), 0, 4));
765
+ const diff = date.getTime() - firstThursday.getTime();
766
+ return 1 + Math.round(diff / (7 * 24 * 3600 * 1e3));
767
+ }
768
+
769
+ // src/controls/DatePicker/calendar-range.ts
770
+ function normalizeRange(r) {
771
+ if (r.start && r.end && startOfDay(r.start) > startOfDay(r.end)) {
772
+ return { start: r.end, end: r.start };
773
+ }
774
+ return r;
775
+ }
776
+ function isRangeComplete(r) {
777
+ return !!r && !!r.start && !!r.end;
778
+ }
779
+ function isWithinRange(d, r) {
780
+ if (!isRangeComplete(r)) return false;
781
+ const t = startOfDay(d).getTime();
782
+ return t > startOfDay(r.start).getTime() && t < startOfDay(r.end).getTime();
783
+ }
784
+ var isRangeStart = (d, r) => !!r && isSameDay(d, r.start);
785
+ var isRangeEnd = (d, r) => !!r && isSameDay(d, r.end);
786
+ function previewRange(anchor, hover) {
787
+ if (!anchor || !hover) return null;
788
+ return normalizeRange({ start: anchor, end: hover });
789
+ }
790
+ function nextRange(current, d) {
791
+ if (!current.start || current.start && current.end) return { start: startOfDay(d), end: null };
792
+ return normalizeRange({ start: current.start, end: startOfDay(d) });
793
+ }
794
+ function Calendar({
795
+ value,
796
+ onSelect,
797
+ mode = "single",
798
+ selectedDates,
799
+ range,
800
+ previewRange: previewRange2,
801
+ onHoverDate,
802
+ minDate,
803
+ maxDate,
804
+ isDisabled,
805
+ firstDayOfWeek = 0,
806
+ locale,
807
+ showWeekNumbers,
808
+ showToday,
809
+ showClear,
810
+ onClear,
811
+ autoFocus,
812
+ view: viewProp,
813
+ defaultView,
814
+ onViewChange,
815
+ precision = "day",
816
+ fixedWeeks = true,
817
+ defaultMonth,
818
+ numberOfMonths = 1
819
+ }) {
820
+ const panels = Math.max(1, Math.floor(numberOfMonths));
821
+ const today = startOfDay(/* @__PURE__ */ new Date());
822
+ const anchor = value ?? (mode === "range" ? range?.start ?? range?.end ?? null : null) ?? (mode === "multiple" ? selectedDates?.[0] ?? null : null) ?? defaultMonth ?? null;
823
+ const initial = anchor ?? clampDate(today, minDate, maxDate);
824
+ const [nav, setNav] = useState({ y: initial.getFullYear(), m: initial.getMonth() });
825
+ const [focused, setFocused] = useState(initial);
826
+ const [innerView, setInnerView] = useState(
827
+ defaultView ?? (precision === "day" ? "day" : precision)
828
+ );
829
+ const view = viewProp ?? innerView;
830
+ const setView = (v) => {
831
+ if (viewProp === void 0) setInnerView(v);
832
+ onViewChange?.(v);
833
+ };
834
+ const gridRef = useRef(null);
835
+ useEffect(() => {
836
+ if (value) {
837
+ setNav({ y: value.getFullYear(), m: value.getMonth() });
838
+ setFocused(value);
839
+ }
840
+ }, [value]);
841
+ useEffect(() => {
842
+ if (autoFocus) {
843
+ gridRef.current?.querySelector('[data-focused="true"]')?.focus();
844
+ }
845
+ }, [autoFocus]);
846
+ const outOfRange = (d) => minDate != null && d < startOfDay(minDate) || maxDate != null && d > startOfDay(maxDate) || Boolean(isDisabled?.(d));
847
+ const monthOutOfRange = (y, m) => {
848
+ const first = new Date(y, m, 1);
849
+ const last = new Date(y, m + 1, 0);
850
+ return maxDate != null && first > startOfDay(maxDate) || minDate != null && last < startOfDay(minDate);
851
+ };
852
+ const yearOutOfRange = (y) => maxDate != null && new Date(y, 0, 1) > startOfDay(maxDate) || minDate != null && new Date(y, 11, 31) < startOfDay(minDate);
853
+ const focusGrid = () => {
854
+ requestAnimationFrame(() => {
855
+ gridRef.current?.querySelector('[data-focused="true"]')?.focus();
856
+ });
857
+ };
858
+ const navIndex = nav.y * 12 + nav.m;
859
+ const goto = (d) => {
860
+ const c = clampDate(d, minDate, maxDate);
861
+ setFocused(c);
862
+ const ci = c.getFullYear() * 12 + c.getMonth();
863
+ if (ci < navIndex || ci > navIndex + panels - 1) {
864
+ setNav({ y: c.getFullYear(), m: c.getMonth() });
865
+ }
866
+ focusGrid();
867
+ };
868
+ const canDrillUp = view !== "year";
869
+ const dayTitle = () => {
870
+ const first = new Date(nav.y, nav.m, 1);
871
+ if (panels <= 1) {
872
+ return new Intl.DateTimeFormat(locale, { month: "long", year: "numeric" }).format(first);
873
+ }
874
+ const last = new Date(nav.y, nav.m + panels - 1, 1);
875
+ const f = new Intl.DateTimeFormat(locale, { month: "short" }).format(first);
876
+ const l = new Intl.DateTimeFormat(locale, { month: "short", year: "numeric" }).format(last);
877
+ return first.getFullYear() === last.getFullYear() ? `${f} \u2013 ${l}` : `${f} ${first.getFullYear()} \u2013 ${l}`;
878
+ };
879
+ const titleText = view === "day" ? dayTitle() : view === "month" ? String(nav.y) : (() => {
880
+ const g = decadeGrid(nav.y);
881
+ return `${g.start} \u2013 ${g.start + 9}`;
882
+ })();
883
+ const step = (dir) => {
884
+ if (view === "day") setNav((v) => ({ ...addMonthNav(v, dir) }));
885
+ else if (view === "month") setNav((v) => ({ ...v, y: v.y + dir }));
886
+ else setNav((v) => ({ ...v, y: v.y + dir * 10 }));
887
+ };
888
+ const header = /* @__PURE__ */ jsxs("div", { className: "orynn-calendar__header", children: [
889
+ /* @__PURE__ */ jsx(
890
+ "button",
891
+ {
892
+ type: "button",
893
+ className: "orynn-calendar__nav",
894
+ "aria-label": view === "day" ? "Previous month" : view === "month" ? "Previous year" : "Previous decade",
895
+ onClick: () => step(-1),
896
+ children: /* @__PURE__ */ jsx(ChevronLeftIcon, {})
897
+ }
898
+ ),
899
+ /* @__PURE__ */ jsx(
900
+ "button",
901
+ {
902
+ type: "button",
903
+ className: "orynn-calendar__title",
904
+ "aria-live": "polite",
905
+ disabled: !canDrillUp,
906
+ onClick: () => {
907
+ if (!canDrillUp) return;
908
+ setView(view === "day" ? "month" : "year");
909
+ },
910
+ children: titleText
911
+ }
912
+ ),
913
+ /* @__PURE__ */ jsx(
914
+ "button",
915
+ {
916
+ type: "button",
917
+ className: "orynn-calendar__nav",
918
+ "aria-label": view === "day" ? "Next month" : view === "month" ? "Next year" : "Next decade",
919
+ onClick: () => step(1),
920
+ children: /* @__PURE__ */ jsx(ChevronRightIcon, {})
921
+ }
922
+ )
923
+ ] });
924
+ const dayGrid = (monthOffset = 0) => {
925
+ const panelMonth = new Date(nav.y, nav.m + monthOffset, 1);
926
+ const py = panelMonth.getFullYear();
927
+ const pm = panelMonth.getMonth();
928
+ const cells = monthMatrix(py, pm, firstDayOfWeek, fixedWeeks);
929
+ const weeks = cells.length / 7;
930
+ const weekdays = weekdayLabels(firstDayOfWeek, locale);
931
+ const monthName = new Intl.DateTimeFormat(locale, { month: "long", year: "numeric" }).format(
932
+ panelMonth
933
+ );
934
+ const onKeyDown = (e) => {
935
+ const k = e.key;
936
+ let next = null;
937
+ if (k === "ArrowLeft") next = addDays(focused, -1);
938
+ else if (k === "ArrowRight") next = addDays(focused, 1);
939
+ else if (k === "ArrowUp") next = addDays(focused, -7);
940
+ else if (k === "ArrowDown") next = addDays(focused, 7);
941
+ else if (k === "Home")
942
+ next = addDays(focused, -((focused.getDay() - firstDayOfWeek + 7) % 7));
943
+ else if (k === "End")
944
+ next = addDays(focused, 6 - (focused.getDay() - firstDayOfWeek + 7) % 7);
945
+ else if (k === "PageUp") next = addMonths(focused, e.shiftKey ? -12 : -1);
946
+ else if (k === "PageDown") next = addMonths(focused, e.shiftKey ? 12 : 1);
947
+ else if (k === "Enter" || k === " ") {
948
+ e.preventDefault();
949
+ if (!outOfRange(focused)) onSelect(focused);
950
+ return;
951
+ } else return;
952
+ e.preventDefault();
953
+ goto(next);
954
+ };
955
+ return /* @__PURE__ */ jsxs(
956
+ "table",
957
+ {
958
+ className: "orynn-calendar__grid",
959
+ role: "grid",
960
+ "aria-label": monthName,
961
+ onKeyDown,
962
+ children: [
963
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
964
+ showWeekNumbers && /* @__PURE__ */ jsx("th", { "aria-hidden": "true" }),
965
+ weekdays.map((w) => /* @__PURE__ */ jsx("th", { scope: "col", children: w }, w))
966
+ ] }) }),
967
+ /* @__PURE__ */ jsx("tbody", { onMouseLeave: onHoverDate ? () => onHoverDate(null) : void 0, children: Array.from({ length: weeks }, (_, week) => {
968
+ const row = cells.slice(week * 7, week * 7 + 7);
969
+ const firstOfRow = row[0];
970
+ return /* @__PURE__ */ jsxs("tr", { children: [
971
+ showWeekNumbers && /* @__PURE__ */ jsx("td", { className: "orynn-calendar__weeknum", children: isoWeek(firstOfRow) }),
972
+ row.map((d) => {
973
+ const inMonth = d.getMonth() === pm;
974
+ const disabled = outOfRange(d);
975
+ const isFocused = isSameDay(d, focused);
976
+ let selected;
977
+ let rangeStart = false;
978
+ let rangeEnd = false;
979
+ let inRange = false;
980
+ if (mode === "multiple") {
981
+ selected = (selectedDates ?? []).some((x) => isSameDay(x, d));
982
+ } else if (mode === "range") {
983
+ rangeStart = isRangeStart(d, range) || !!previewRange2 && isRangeStart(d, previewRange2);
984
+ rangeEnd = isRangeEnd(d, range) || !!previewRange2 && isRangeEnd(d, previewRange2);
985
+ inRange = isWithinRange(d, range) || !!previewRange2 && isWithinRange(d, previewRange2);
986
+ selected = rangeStart || rangeEnd;
987
+ } else {
988
+ selected = isSameDay(d, value);
989
+ }
990
+ return /* @__PURE__ */ jsx("td", { role: "gridcell", "aria-selected": selected, children: /* @__PURE__ */ jsx(
991
+ "button",
992
+ {
993
+ type: "button",
994
+ className: "orynn-calendar__day",
995
+ tabIndex: isFocused ? 0 : -1,
996
+ "data-focused": isFocused || void 0,
997
+ "data-outside": !inMonth || void 0,
998
+ "data-today": isSameDay(d, today) || void 0,
999
+ "data-selected": selected || void 0,
1000
+ "data-range-start": rangeStart || void 0,
1001
+ "data-range-end": rangeEnd || void 0,
1002
+ "data-in-range": inRange || void 0,
1003
+ disabled,
1004
+ "aria-label": new Intl.DateTimeFormat(locale, { dateStyle: "full" }).format(
1005
+ d
1006
+ ),
1007
+ onMouseEnter: onHoverDate ? () => onHoverDate(d) : void 0,
1008
+ onFocus: onHoverDate ? () => onHoverDate(d) : void 0,
1009
+ onClick: () => {
1010
+ setFocused(d);
1011
+ onSelect(d);
1012
+ },
1013
+ children: d.getDate()
1014
+ }
1015
+ ) }, d.toISOString());
1016
+ })
1017
+ ] }, firstOfRow.toISOString());
1018
+ }) })
1019
+ ]
1020
+ },
1021
+ `${py}-${pm}`
1022
+ );
1023
+ };
1024
+ const monthGrid = () => {
1025
+ const names = Array.from(
1026
+ { length: 12 },
1027
+ (_, i) => new Intl.DateTimeFormat(locale, { month: "short" }).format(new Date(2021, i, 1))
1028
+ );
1029
+ const onKeyDown = (e) => {
1030
+ let m = nav.m;
1031
+ if (e.key === "ArrowLeft") m -= 1;
1032
+ else if (e.key === "ArrowRight") m += 1;
1033
+ else if (e.key === "ArrowUp") m -= 3;
1034
+ else if (e.key === "ArrowDown") m += 3;
1035
+ else if (e.key === "Enter" || e.key === " ") {
1036
+ e.preventDefault();
1037
+ pickMonth(nav.m);
1038
+ return;
1039
+ } else return;
1040
+ e.preventDefault();
1041
+ const d = addMonths(new Date(nav.y, nav.m, 1), m - nav.m);
1042
+ setNav({ y: d.getFullYear(), m: d.getMonth() });
1043
+ focusGrid();
1044
+ };
1045
+ return /* @__PURE__ */ jsx(
1046
+ "div",
1047
+ {
1048
+ className: "orynn-calendar__pickgrid",
1049
+ role: "grid",
1050
+ "aria-label": `Months of ${nav.y}`,
1051
+ onKeyDown,
1052
+ children: [0, 3, 6, 9].map((rowStart) => /* @__PURE__ */ jsx("div", { role: "row", className: "orynn-calendar__pickrow", children: names.slice(rowStart, rowStart + 3).map((name, j) => {
1053
+ const i = rowStart + j;
1054
+ const isFocused = i === nav.m;
1055
+ const selected = value != null && value.getFullYear() === nav.y && value.getMonth() === i;
1056
+ return /* @__PURE__ */ jsx(
1057
+ "button",
1058
+ {
1059
+ type: "button",
1060
+ className: "orynn-calendar__cell",
1061
+ tabIndex: isFocused ? 0 : -1,
1062
+ "data-focused": isFocused || void 0,
1063
+ "data-selected": selected || void 0,
1064
+ disabled: monthOutOfRange(nav.y, i),
1065
+ onClick: () => pickMonth(i),
1066
+ children: name
1067
+ },
1068
+ name
1069
+ );
1070
+ }) }, rowStart))
1071
+ }
1072
+ );
1073
+ };
1074
+ const pickMonth = (m) => {
1075
+ if (monthOutOfRange(nav.y, m)) return;
1076
+ setNav((v) => ({ ...v, m }));
1077
+ if (precision === "month") {
1078
+ onSelect(new Date(nav.y, m, 1));
1079
+ } else {
1080
+ setView("day");
1081
+ setFocused(clampDate(new Date(nav.y, m, 1), minDate, maxDate));
1082
+ focusGrid();
1083
+ }
1084
+ };
1085
+ const yearGrid = () => {
1086
+ const g = decadeGrid(nav.y);
1087
+ const onKeyDown = (e) => {
1088
+ let y = nav.y;
1089
+ if (e.key === "ArrowLeft") y -= 1;
1090
+ else if (e.key === "ArrowRight") y += 1;
1091
+ else if (e.key === "ArrowUp") y -= 3;
1092
+ else if (e.key === "ArrowDown") y += 3;
1093
+ else if (e.key === "Enter" || e.key === " ") {
1094
+ e.preventDefault();
1095
+ pickYear(nav.y);
1096
+ return;
1097
+ } else return;
1098
+ e.preventDefault();
1099
+ setNav((v) => ({ ...v, y }));
1100
+ focusGrid();
1101
+ };
1102
+ return /* @__PURE__ */ jsx(
1103
+ "div",
1104
+ {
1105
+ className: "orynn-calendar__pickgrid",
1106
+ role: "grid",
1107
+ "aria-label": `Years ${g.start}\u2013${g.start + 9}`,
1108
+ onKeyDown,
1109
+ children: [0, 3, 6, 9].map((rowStart) => /* @__PURE__ */ jsx("div", { role: "row", className: "orynn-calendar__pickrow", children: g.years.slice(rowStart, rowStart + 3).map((y) => {
1110
+ const isFocused = y === nav.y;
1111
+ const selected = value != null && value.getFullYear() === y;
1112
+ return /* @__PURE__ */ jsx(
1113
+ "button",
1114
+ {
1115
+ type: "button",
1116
+ className: "orynn-calendar__cell",
1117
+ tabIndex: isFocused ? 0 : -1,
1118
+ "data-focused": isFocused || void 0,
1119
+ "data-outside": y < g.start || y > g.start + 9 || void 0,
1120
+ "data-selected": selected || void 0,
1121
+ disabled: yearOutOfRange(y),
1122
+ onClick: () => pickYear(y),
1123
+ children: y
1124
+ },
1125
+ y
1126
+ );
1127
+ }) }, rowStart))
1128
+ }
1129
+ );
1130
+ };
1131
+ const pickYear = (y) => {
1132
+ if (yearOutOfRange(y)) return;
1133
+ setNav((v) => ({ ...v, y }));
1134
+ if (precision === "year") {
1135
+ onSelect(new Date(y, 0, 1));
1136
+ } else {
1137
+ setView("month");
1138
+ focusGrid();
1139
+ }
1140
+ };
1141
+ const dayView = panels <= 1 ? dayGrid() : /* @__PURE__ */ jsx("div", { className: "orynn-calendar__panels", children: Array.from({ length: panels }, (_, i) => dayGrid(i)) });
1142
+ return /* @__PURE__ */ jsxs(
1143
+ "div",
1144
+ {
1145
+ className: "orynn-calendar",
1146
+ ref: gridRef,
1147
+ "data-view": view,
1148
+ "data-months": panels > 1 ? panels : void 0,
1149
+ children: [
1150
+ header,
1151
+ " ",
1152
+ view === "day" ? dayView : view === "month" ? monthGrid() : yearGrid(),
1153
+ (showToday || showClear) && /* @__PURE__ */ jsxs("div", { className: "orynn-calendar__footer", children: [
1154
+ showToday ? /* @__PURE__ */ jsx(
1155
+ "button",
1156
+ {
1157
+ type: "button",
1158
+ className: "orynn-calendar__action",
1159
+ disabled: outOfRange(today),
1160
+ onClick: () => onSelect(today),
1161
+ children: "Today"
1162
+ }
1163
+ ) : /* @__PURE__ */ jsx("span", {}),
1164
+ showClear && /* @__PURE__ */ jsx("button", { type: "button", className: "orynn-calendar__action", onClick: onClear, children: "Clear" })
1165
+ ] })
1166
+ ]
1167
+ }
1168
+ );
1169
+ }
1170
+ function addMonthNav(v, dir) {
1171
+ const total = v.y * 12 + v.m + dir;
1172
+ return { y: Math.floor(total / 12), m: (total % 12 + 12) % 12 };
1173
+ }
1174
+
1175
+ // src/controls/DatePicker/time-utils.ts
1176
+ var timeParts = (d) => ({
1177
+ h: d.getHours(),
1178
+ m: d.getMinutes(),
1179
+ s: d.getSeconds()
1180
+ });
1181
+ function withTime(date, time) {
1182
+ const r = new Date(date);
1183
+ r.setHours(time.h, time.m, time.s, 0);
1184
+ return r;
1185
+ }
1186
+ function minuteOptions(step) {
1187
+ const s = Math.max(1, Math.min(30, Math.floor(step)));
1188
+ const out = [];
1189
+ for (let m = 0; m < 60; m += s) out.push(m);
1190
+ return out;
1191
+ }
1192
+ var pad2 = (n) => String(n).padStart(2, "0");
1193
+ var normDates = (v) => Array.isArray(v) ? v.map((x) => toDate(x)).filter(Boolean) : [];
1194
+ var normRange = (v) => {
1195
+ const r = v ?? {};
1196
+ return { start: toDate(r.start ?? null), end: toDate(r.end ?? null) };
1197
+ };
1198
+ var DatePicker = /* @__PURE__ */ forwardRef(
1199
+ function DatePicker2(propsIn, ref) {
1200
+ const props = propsIn;
109
1201
  const {
110
1202
  label,
111
1203
  description,
112
1204
  error,
113
- className,
114
- value,
115
- onChange,
116
- type = "text",
117
- id,
1205
+ success,
118
1206
  required,
119
1207
  disabled,
120
1208
  readOnly,
121
- onBlur,
122
- onFocus,
123
- ...rest
1209
+ size,
1210
+ variant,
1211
+ radius,
1212
+ floatingLabel,
1213
+ clearable,
1214
+ onClear,
1215
+ id: idProp,
1216
+ name,
1217
+ className,
1218
+ mode = "single",
1219
+ value: valueProp,
1220
+ defaultValue,
1221
+ onChange,
1222
+ format = "yyyy-MM-dd",
1223
+ minDate,
1224
+ maxDate,
1225
+ disabledDates,
1226
+ isDateUnavailable,
1227
+ firstDayOfWeek = 0,
1228
+ locale,
1229
+ showWeekNumbers,
1230
+ showToday = true,
1231
+ showClear,
1232
+ defaultView,
1233
+ precision = "day",
1234
+ fixedWeeks = true,
1235
+ numberOfMonths,
1236
+ showTime = false,
1237
+ timeStep = 5,
1238
+ defaultMonth,
1239
+ presets,
1240
+ inline = false,
1241
+ allowInput = true,
1242
+ closeOnSelect: closeOnSelectProp,
1243
+ open: openProp,
1244
+ defaultOpen = false,
1245
+ onOpenChange,
1246
+ placeholder
124
1247
  } = props;
125
- const handleChange = useCallback(
126
- (event) => onChange?.(event.target.value, event),
127
- [onChange]
1248
+ const reactId = useId();
1249
+ const id = idProp ?? reactId;
1250
+ const panelId = `${id}-cal`;
1251
+ const withTimePicker = showTime && mode === "single";
1252
+ const closeOnSelect = closeOnSelectProp ?? !withTimePicker;
1253
+ const fmt = withTimePicker && format === "yyyy-MM-dd" ? "yyyy-MM-dd HH:mm" : format;
1254
+ const isControlled = valueProp !== void 0;
1255
+ const [innerRaw, setInnerRaw] = useState(() => defaultValue ?? null);
1256
+ const raw = isControlled ? valueProp : innerRaw;
1257
+ const toDateKeepTime = (v) => {
1258
+ if (v == null) return null;
1259
+ const d = new Date(v);
1260
+ return Number.isNaN(d.getTime()) ? null : d;
1261
+ };
1262
+ const curDate = mode === "single" ? withTimePicker ? toDateKeepTime(raw) : toDate(raw) : null;
1263
+ const curRange = mode === "range" ? normRange(raw) : { start: null, end: null };
1264
+ const curDates = mode === "multiple" ? normDates(raw) : [];
1265
+ const commit = (next) => {
1266
+ if (!isControlled) {
1267
+ setInnerRaw(next);
1268
+ }
1269
+ onChange?.(next);
1270
+ };
1271
+ const openIsControlled = openProp !== void 0;
1272
+ const [innerOpen, setInnerOpen] = useState(defaultOpen);
1273
+ const open = openIsControlled ? openProp : innerOpen;
1274
+ const setOpen = (next) => {
1275
+ if (!openIsControlled) setInnerOpen(next);
1276
+ onOpenChange?.(next);
1277
+ };
1278
+ const [gridFocus, setGridFocus] = useState(false);
1279
+ const [hoverDate, setHoverDate] = useState(null);
1280
+ const displayText = () => {
1281
+ if (mode === "single") return curDate ? formatDate(curDate, fmt, locale) : "";
1282
+ if (mode === "multiple") {
1283
+ if (curDates.length === 0) return "";
1284
+ if (curDates.length === 1) return formatDate(curDates[0], fmt, locale);
1285
+ return `${curDates.length} selected`;
1286
+ }
1287
+ if (!curRange.start && !curRange.end) return "";
1288
+ const s = curRange.start ? formatDate(curRange.start, fmt, locale) : "\u2026";
1289
+ const e = curRange.end ? formatDate(curRange.end, fmt, locale) : "\u2026";
1290
+ return `${s} \u2013 ${e}`;
1291
+ };
1292
+ const [text, setText] = useState(displayText);
1293
+ const boxRef = useRef(null);
1294
+ const inputRef = useRef(null);
1295
+ const skipFocusOpen = useRef(false);
1296
+ const valueKey = [
1297
+ mode,
1298
+ typeof fmt === "string" ? fmt : JSON.stringify(fmt),
1299
+ locale ?? "",
1300
+ curDate?.getTime() ?? "",
1301
+ curRange.start?.getTime() ?? "",
1302
+ curRange.end?.getTime() ?? "",
1303
+ curDates.map((d) => d.getTime()).join(",")
1304
+ ].join("|");
1305
+ useEffect(() => {
1306
+ setText(displayText());
1307
+ }, [valueKey]);
1308
+ const isDisabledDate = (d) => {
1309
+ if (isDateUnavailable?.(d)) return true;
1310
+ if (Array.isArray(disabledDates))
1311
+ return disabledDates.some((x) => isSameDay(startOfDay(x), d));
1312
+ return Boolean(disabledDates?.(d));
1313
+ };
1314
+ const closeAndRefocus = () => {
1315
+ setOpen(false);
1316
+ setGridFocus(false);
1317
+ skipFocusOpen.current = true;
1318
+ inputRef.current?.focus();
1319
+ };
1320
+ const select = (d) => {
1321
+ if (isDisabledDate(d)) return;
1322
+ const day = startOfDay(d);
1323
+ if (mode === "single") {
1324
+ const picked = withTimePicker ? withTime(day, curDate ? timeParts(curDate) : { h: 0, m: 0, s: 0 }) : day;
1325
+ commit(picked);
1326
+ if (closeOnSelect) closeAndRefocus();
1327
+ return;
1328
+ }
1329
+ if (mode === "multiple") {
1330
+ const has = curDates.some((x) => isSameDay(x, day));
1331
+ commit(has ? curDates.filter((x) => !isSameDay(x, day)) : [...curDates, day]);
1332
+ return;
1333
+ }
1334
+ const next = nextRange(curRange, day);
1335
+ commit(next);
1336
+ if (isRangeComplete(next) && closeOnSelect) closeAndRefocus();
1337
+ };
1338
+ const clearValue = () => {
1339
+ if (mode === "single") commit(null);
1340
+ else if (mode === "multiple") commit([]);
1341
+ else commit({ start: null, end: null });
1342
+ onClear?.();
1343
+ };
1344
+ const onKeyDown = (e) => {
1345
+ if (disabled || readOnly) return;
1346
+ if (e.key === "ArrowDown") {
1347
+ e.preventDefault();
1348
+ setOpen(true);
1349
+ setGridFocus(true);
1350
+ } else if (e.key === "Escape" && open) {
1351
+ e.preventDefault();
1352
+ setOpen(false);
1353
+ } else if (e.key === "Enter" && mode === "single") {
1354
+ const parsed = parseDate(text, fmt, locale);
1355
+ if (parsed && !isDisabledDate(startOfDay(parsed))) select(parsed);
1356
+ }
1357
+ };
1358
+ const preview = mode === "range" && curRange.start && !curRange.end ? previewRange(curRange.start, hoverDate) : null;
1359
+ const applyPreset = (p) => {
1360
+ const resolved = p.getValue ? p.getValue() : p.value;
1361
+ if (resolved == null) return;
1362
+ commit(resolved);
1363
+ if (closeOnSelect && !inline) closeAndRefocus();
1364
+ };
1365
+ const setTimeField = (part, n) => {
1366
+ const base2 = curDate ?? startOfDay(/* @__PURE__ */ new Date());
1367
+ const t = timeParts(base2);
1368
+ commit(withTime(base2, { ...t, [part]: n, s: 0 }));
1369
+ };
1370
+ const timeColumn = withTimePicker ? /* @__PURE__ */ jsxs("div", { className: "orynn-datepicker__time", children: [
1371
+ /* @__PURE__ */ jsx("span", { className: "orynn-datepicker__time-label", children: "Time" }),
1372
+ /* @__PURE__ */ jsxs("div", { className: "orynn-datepicker__time-fields", children: [
1373
+ /* @__PURE__ */ jsx(
1374
+ "select",
1375
+ {
1376
+ "aria-label": "Hour",
1377
+ className: "orynn-datepicker__time-select",
1378
+ value: curDate ? curDate.getHours() : 0,
1379
+ onChange: (e) => setTimeField("h", Number(e.target.value)),
1380
+ children: Array.from({ length: 24 }, (_, h) => /* @__PURE__ */ jsx("option", { value: h, children: pad2(h) }, h))
1381
+ }
1382
+ ),
1383
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: ":" }),
1384
+ /* @__PURE__ */ jsx(
1385
+ "select",
1386
+ {
1387
+ "aria-label": "Minute",
1388
+ className: "orynn-datepicker__time-select",
1389
+ value: curDate ? curDate.getMinutes() - curDate.getMinutes() % timeStep : 0,
1390
+ onChange: (e) => setTimeField("m", Number(e.target.value)),
1391
+ children: minuteOptions(timeStep).map((m) => /* @__PURE__ */ jsx("option", { value: m, children: pad2(m) }, m))
1392
+ }
1393
+ )
1394
+ ] })
1395
+ ] }) : null;
1396
+ const calendar = /* @__PURE__ */ jsx(
1397
+ Calendar,
1398
+ {
1399
+ value: curDate,
1400
+ onSelect: select,
1401
+ mode,
1402
+ selectedDates: mode === "multiple" ? curDates : void 0,
1403
+ range: mode === "range" ? curRange : void 0,
1404
+ previewRange: preview,
1405
+ onHoverDate: mode === "range" ? setHoverDate : void 0,
1406
+ minDate,
1407
+ maxDate,
1408
+ isDisabled: isDisabledDate,
1409
+ firstDayOfWeek,
1410
+ locale,
1411
+ showWeekNumbers,
1412
+ showToday: showToday && mode === "single",
1413
+ showClear,
1414
+ defaultView,
1415
+ precision,
1416
+ fixedWeeks,
1417
+ numberOfMonths,
1418
+ defaultMonth,
1419
+ onClear: () => {
1420
+ clearValue();
1421
+ setOpen(false);
1422
+ },
1423
+ autoFocus: open && gridFocus || inline
1424
+ }
128
1425
  );
129
- const controlled = value !== void 0;
1426
+ const body = timeColumn ? /* @__PURE__ */ jsxs("div", { className: "orynn-datepicker__withtime", children: [
1427
+ calendar,
1428
+ timeColumn
1429
+ ] }) : calendar;
1430
+ const cal = presets && presets.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "orynn-datepicker__panel", children: [
1431
+ /* @__PURE__ */ jsx("div", { className: "orynn-datepicker__presets", children: presets.map((p) => /* @__PURE__ */ jsx(
1432
+ "button",
1433
+ {
1434
+ type: "button",
1435
+ className: "orynn-datepicker__preset",
1436
+ onClick: () => applyPreset(p),
1437
+ children: p.label
1438
+ },
1439
+ p.label
1440
+ )) }),
1441
+ body
1442
+ ] }) : body;
1443
+ if (inline) {
1444
+ return /* @__PURE__ */ jsx(
1445
+ Field,
1446
+ {
1447
+ label,
1448
+ description,
1449
+ error,
1450
+ success,
1451
+ required,
1452
+ disabled,
1453
+ id,
1454
+ className,
1455
+ children: () => /* @__PURE__ */ jsx("div", { className: "orynn-popover", style: { position: "static" }, children: cal })
1456
+ }
1457
+ );
1458
+ }
1459
+ const hasValue = mode === "single" ? curDate != null : mode === "multiple" ? curDates.length > 0 : Boolean(curRange.start || curRange.end);
1460
+ const typingAllowed = mode === "single" && allowInput && !readOnly;
130
1461
  return /* @__PURE__ */ jsx(
131
1462
  Field,
132
1463
  {
133
1464
  label,
134
1465
  description,
135
1466
  error,
1467
+ success,
136
1468
  required,
137
1469
  disabled,
1470
+ hideLabel: floatingLabel,
138
1471
  id,
139
1472
  className,
140
- children: ({ id: fieldId, describedById, invalid }) => /* @__PURE__ */ jsx(
141
- "input",
142
- {
143
- ...rest,
144
- ref,
145
- id: fieldId,
146
- className: "orynn-input",
147
- type,
148
- required,
149
- disabled,
150
- readOnly,
151
- "aria-invalid": invalid || void 0,
152
- "aria-describedby": describedById,
153
- ...controlled ? { value } : {},
154
- onChange: handleChange,
155
- onBlur,
156
- onFocus
157
- }
158
- )
1473
+ children: ({ describedById, invalid, valid }) => /* @__PURE__ */ jsxs(Fragment, { children: [
1474
+ /* @__PURE__ */ jsx(
1475
+ FieldBox,
1476
+ {
1477
+ ref: boxRef,
1478
+ size,
1479
+ variant,
1480
+ radius,
1481
+ disabled,
1482
+ invalid,
1483
+ valid,
1484
+ open,
1485
+ active: hasValue || text.length > 0,
1486
+ floatingLabel: floatingLabel ? /* @__PURE__ */ jsx("label", { className: "orynn-box__label", htmlFor: id, children: label }) : void 0,
1487
+ right: /* @__PURE__ */ jsxs(Fragment, { children: [
1488
+ clearable && hasValue && !disabled && !readOnly && /* @__PURE__ */ jsx(
1489
+ "button",
1490
+ {
1491
+ type: "button",
1492
+ className: "orynn-box__iconbtn",
1493
+ "aria-label": "Clear",
1494
+ tabIndex: -1,
1495
+ onClick: clearValue,
1496
+ children: /* @__PURE__ */ jsx(XIcon, {})
1497
+ }
1498
+ ),
1499
+ /* @__PURE__ */ jsx(
1500
+ "button",
1501
+ {
1502
+ type: "button",
1503
+ className: "orynn-box__iconbtn",
1504
+ "aria-label": "Open calendar",
1505
+ "aria-haspopup": "dialog",
1506
+ "aria-expanded": open,
1507
+ disabled,
1508
+ onClick: () => {
1509
+ if (disabled || readOnly) return;
1510
+ setGridFocus(true);
1511
+ setOpen(!open);
1512
+ },
1513
+ children: /* @__PURE__ */ jsx(CalendarIcon, {})
1514
+ }
1515
+ )
1516
+ ] }),
1517
+ children: /* @__PURE__ */ jsx(
1518
+ "input",
1519
+ {
1520
+ ref: (n) => {
1521
+ inputRef.current = n;
1522
+ if (typeof ref === "function") ref(n);
1523
+ else if (ref)
1524
+ ref.current = n;
1525
+ },
1526
+ id,
1527
+ name,
1528
+ className: "orynn-box__field",
1529
+ type: "text",
1530
+ inputMode: typingAllowed ? "numeric" : void 0,
1531
+ autoComplete: "off",
1532
+ role: "combobox",
1533
+ "aria-expanded": open,
1534
+ "aria-controls": panelId,
1535
+ "aria-haspopup": "dialog",
1536
+ "aria-invalid": invalid || void 0,
1537
+ "aria-describedby": describedById,
1538
+ value: text,
1539
+ disabled,
1540
+ readOnly: !typingAllowed,
1541
+ required,
1542
+ placeholder: floatingLabel ? void 0 : placeholder ?? (typeof fmt === "string" ? fmt.toLowerCase() : void 0),
1543
+ onChange: (e) => setText(e.target.value),
1544
+ onKeyDown,
1545
+ onFocus: () => {
1546
+ if (skipFocusOpen.current) {
1547
+ skipFocusOpen.current = false;
1548
+ return;
1549
+ }
1550
+ setOpen(true);
1551
+ },
1552
+ onBlur: () => {
1553
+ if (mode !== "single") return;
1554
+ const parsed = parseDate(text, fmt, locale);
1555
+ if (parsed && !isDisabledDate(startOfDay(parsed))) {
1556
+ commit(startOfDay(parsed));
1557
+ setText(formatDate(startOfDay(parsed), fmt, locale));
1558
+ } else {
1559
+ setText(curDate ? formatDate(curDate, fmt, locale) : "");
1560
+ }
1561
+ }
1562
+ }
1563
+ )
1564
+ }
1565
+ ),
1566
+ /* @__PURE__ */ jsx(
1567
+ Popover,
1568
+ {
1569
+ open,
1570
+ anchorRef: boxRef,
1571
+ onClose: () => {
1572
+ setOpen(false);
1573
+ setGridFocus(false);
1574
+ },
1575
+ matchWidth: false,
1576
+ id: panelId,
1577
+ role: "dialog",
1578
+ children: cal
1579
+ }
1580
+ )
1581
+ ] })
159
1582
  }
160
1583
  );
161
1584
  }
162
1585
  );
163
-
164
- // src/internal/dev.ts
1586
+ var CREATE_VALUE = "\0orynn-create";
1587
+ var toArray = (v) => v == null ? [] : Array.isArray(v) ? v : [v];
1588
+ var isGrouped = (o) => {
1589
+ const first = o[0];
1590
+ return first != null && "items" in first && Array.isArray(first.items);
1591
+ };
1592
+ var flattenOptions = (o) => isGrouped(o) ? o.flatMap((g) => g.items.map((it) => ({ ...it, group: it.group ?? g.group }))) : o;
1593
+ function Highlight({ text, query }) {
1594
+ if (!query) return /* @__PURE__ */ jsx(Fragment, { children: text });
1595
+ const i = text.toLowerCase().indexOf(query.toLowerCase());
1596
+ if (i < 0) return /* @__PURE__ */ jsx(Fragment, { children: text });
1597
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1598
+ text.slice(0, i),
1599
+ /* @__PURE__ */ jsx("mark", { children: text.slice(i, i + query.length) }),
1600
+ text.slice(i + query.length)
1601
+ ] });
1602
+ }
1603
+ var Dropdown = /* @__PURE__ */ forwardRef(
1604
+ function Dropdown2(props, ref) {
1605
+ const {
1606
+ label,
1607
+ description,
1608
+ error,
1609
+ success,
1610
+ required,
1611
+ disabled,
1612
+ readOnly,
1613
+ size,
1614
+ variant,
1615
+ radius,
1616
+ floatingLabel,
1617
+ clearable,
1618
+ onClear,
1619
+ loading,
1620
+ id: idProp,
1621
+ name,
1622
+ className,
1623
+ options,
1624
+ value: valueProp,
1625
+ defaultValue,
1626
+ onChange,
1627
+ multiple = false,
1628
+ searchable = false,
1629
+ filterMode = "contains",
1630
+ filterFn,
1631
+ highlightMatch,
1632
+ renderOption,
1633
+ renderValue,
1634
+ renderGroupLabel,
1635
+ placeholder,
1636
+ emptyMessage = "No results",
1637
+ loadingMessage = "Loading\u2026",
1638
+ closeOnSelect = !multiple,
1639
+ maxSelectedLabels,
1640
+ maxValues,
1641
+ hidePickedOptions = false,
1642
+ showSelectAll = false,
1643
+ native = false,
1644
+ startContent,
1645
+ creatable = false,
1646
+ onCreate,
1647
+ isValidNewOption,
1648
+ formatCreateLabel,
1649
+ createPosition = "last",
1650
+ onSearch,
1651
+ searchDebounce = 0,
1652
+ open: openProp,
1653
+ defaultOpen = false,
1654
+ onOpenChange,
1655
+ maxHeight
1656
+ } = props;
1657
+ const reactId = useId();
1658
+ const id = idProp ?? reactId;
1659
+ const listId = `${id}-listbox`;
1660
+ const baseOptions = useMemo(() => flattenOptions(options), [options]);
1661
+ const [createdOptions, setCreatedOptions] = useState([]);
1662
+ const allOptions = useMemo(
1663
+ () => [...baseOptions, ...createdOptions],
1664
+ [baseOptions, createdOptions]
1665
+ );
1666
+ const [selectedValues, setSelectedValues] = useControllableState({
1667
+ value: valueProp === void 0 ? void 0 : toArray(valueProp),
1668
+ defaultValue: toArray(defaultValue),
1669
+ onChange: void 0
1670
+ });
1671
+ const commit = (next) => {
1672
+ setSelectedValues(next);
1673
+ onChange?.(multiple ? next : next[0] ?? null);
1674
+ };
1675
+ const openIsControlled = openProp !== void 0;
1676
+ const [innerOpen, setInnerOpen] = useState(defaultOpen);
1677
+ const open = openIsControlled ? openProp : innerOpen;
1678
+ const setOpen = (next) => {
1679
+ if (!openIsControlled) setInnerOpen(next);
1680
+ onOpenChange?.(next);
1681
+ };
1682
+ const [query, setQuery] = useState("");
1683
+ const [activeIndex, setActiveIndex] = useState(0);
1684
+ const boxRef = useRef(null);
1685
+ const inputRef = useRef(null);
1686
+ const listRef = useRef(null);
1687
+ const byValue = useMemo(() => new Map(allOptions.map((o) => [o.value, o])), [allOptions]);
1688
+ const selectedOptions = selectedValues.map((v) => byValue.get(v) ?? { label: v, value: v }).filter(Boolean);
1689
+ useEffect(() => {
1690
+ if (!onSearch) return;
1691
+ const t = setTimeout(() => onSearch(query), searchDebounce);
1692
+ return () => clearTimeout(t);
1693
+ }, [query, onSearch, searchDebounce]);
1694
+ const filtered = useMemo(() => {
1695
+ let list = allOptions;
1696
+ if (searchable && query && !onSearch) {
1697
+ const q = query.toLowerCase();
1698
+ const match = filterFn ?? ((o) => filterMode === "startsWith" ? o.label.toLowerCase().startsWith(q) : o.label.toLowerCase().includes(q));
1699
+ list = list.filter((o) => match(o, query));
1700
+ }
1701
+ if (multiple && hidePickedOptions) {
1702
+ list = list.filter((o) => !selectedValues.includes(o.value));
1703
+ }
1704
+ return list;
1705
+ }, [
1706
+ allOptions,
1707
+ searchable,
1708
+ query,
1709
+ onSearch,
1710
+ filterMode,
1711
+ filterFn,
1712
+ multiple,
1713
+ hidePickedOptions,
1714
+ selectedValues
1715
+ ]);
1716
+ const showCreateRow = creatable && searchable && query.trim().length > 0 && (isValidNewOption ? isValidNewOption(query.trim(), allOptions) : !allOptions.some((o) => o.label.toLowerCase() === query.trim().toLowerCase()));
1717
+ const createRow = { value: CREATE_VALUE, label: query.trim() };
1718
+ const selectableOptions = showCreateRow ? createPosition === "first" ? [createRow, ...filtered] : [...filtered, createRow] : filtered;
1719
+ const rows = useMemo(() => {
1720
+ const out = [];
1721
+ let seenGroup;
1722
+ selectableOptions.forEach((o, optionIndex) => {
1723
+ if (o.value !== CREATE_VALUE && o.group && o.group !== seenGroup) {
1724
+ seenGroup = o.group;
1725
+ out.push({ type: "group", label: o.group });
1726
+ }
1727
+ out.push({ type: "option", option: o, optionIndex });
1728
+ });
1729
+ return out;
1730
+ }, [selectableOptions]);
1731
+ useEffect(() => {
1732
+ setActiveIndex((i) => Math.min(Math.max(0, i), Math.max(0, selectableOptions.length - 1)));
1733
+ }, [selectableOptions.length]);
1734
+ useEffect(() => {
1735
+ if (!open) setQuery("");
1736
+ }, [open]);
1737
+ const firstRelevantIndex = () => {
1738
+ const sel = selectableOptions.findIndex((o) => selectedValues.includes(o.value));
1739
+ return sel >= 0 ? sel : 0;
1740
+ };
1741
+ useEffect(() => {
1742
+ if (!open) return;
1743
+ const el = listRef.current?.querySelector('[data-active="true"]');
1744
+ el?.scrollIntoView?.({ block: "nearest" });
1745
+ }, [activeIndex, open]);
1746
+ const openPanel = () => {
1747
+ if (disabled || readOnly || open) return;
1748
+ setActiveIndex(firstRelevantIndex());
1749
+ setOpen(true);
1750
+ };
1751
+ const handleCreate = (raw) => {
1752
+ const input = raw.trim();
1753
+ if (!input) return;
1754
+ onCreate?.(input);
1755
+ setCreatedOptions(
1756
+ (prev) => prev.some((o) => o.value === input) || baseOptions.some((o) => o.value === input) ? prev : [...prev, { label: input, value: input }]
1757
+ );
1758
+ if (multiple) {
1759
+ if (maxValues != null && selectedValues.length >= maxValues) return;
1760
+ commit([...selectedValues, input]);
1761
+ } else {
1762
+ commit([input]);
1763
+ }
1764
+ setQuery("");
1765
+ if (closeOnSelect) {
1766
+ setOpen(false);
1767
+ inputRef.current?.focus();
1768
+ }
1769
+ };
1770
+ const pick = (opt) => {
1771
+ if (opt.value === CREATE_VALUE) {
1772
+ handleCreate(opt.label);
1773
+ return;
1774
+ }
1775
+ if (opt.disabled) return;
1776
+ if (multiple) {
1777
+ const has = selectedValues.includes(opt.value);
1778
+ if (!has && maxValues != null && selectedValues.length >= maxValues) return;
1779
+ commit(
1780
+ has ? selectedValues.filter((v) => v !== opt.value) : [...selectedValues, opt.value]
1781
+ );
1782
+ setQuery("");
1783
+ } else {
1784
+ commit([opt.value]);
1785
+ }
1786
+ if (closeOnSelect) {
1787
+ setOpen(false);
1788
+ inputRef.current?.focus();
1789
+ }
1790
+ };
1791
+ const clearAll = () => {
1792
+ commit([]);
1793
+ onClear?.();
1794
+ setQuery("");
1795
+ };
1796
+ const selectAllTargets = filtered.filter((o) => !o.disabled).map((o) => o.value);
1797
+ const allSelected = selectAllTargets.length > 0 && selectAllTargets.every((v) => selectedValues.includes(v));
1798
+ const toggleSelectAll = () => {
1799
+ if (allSelected) {
1800
+ commit(selectedValues.filter((v) => !selectAllTargets.includes(v)));
1801
+ } else {
1802
+ const merged = Array.from(/* @__PURE__ */ new Set([...selectedValues, ...selectAllTargets]));
1803
+ commit(maxValues != null ? merged.slice(0, maxValues) : merged);
1804
+ }
1805
+ };
1806
+ const onKeyDown = (e) => {
1807
+ if (disabled || readOnly) return;
1808
+ switch (e.key) {
1809
+ case "ArrowDown":
1810
+ e.preventDefault();
1811
+ if (!open) {
1812
+ openPanel();
1813
+ setActiveIndex(firstRelevantIndex());
1814
+ } else {
1815
+ setActiveIndex((i) => Math.min(selectableOptions.length - 1, i + 1));
1816
+ }
1817
+ break;
1818
+ case "ArrowUp":
1819
+ e.preventDefault();
1820
+ if (!open) {
1821
+ openPanel();
1822
+ setActiveIndex(firstRelevantIndex());
1823
+ } else {
1824
+ setActiveIndex((i) => Math.max(0, i - 1));
1825
+ }
1826
+ break;
1827
+ case "Home":
1828
+ if (open) {
1829
+ e.preventDefault();
1830
+ setActiveIndex(0);
1831
+ }
1832
+ break;
1833
+ case "End":
1834
+ if (open) {
1835
+ e.preventDefault();
1836
+ setActiveIndex(selectableOptions.length - 1);
1837
+ }
1838
+ break;
1839
+ case "Enter":
1840
+ if (open && selectableOptions[activeIndex]) {
1841
+ e.preventDefault();
1842
+ pick(selectableOptions[activeIndex]);
1843
+ }
1844
+ break;
1845
+ case "Escape":
1846
+ if (open) {
1847
+ e.preventDefault();
1848
+ setOpen(false);
1849
+ }
1850
+ break;
1851
+ case " ":
1852
+ if (!searchable) {
1853
+ e.preventDefault();
1854
+ if (!open) openPanel();
1855
+ else if (selectableOptions[activeIndex]) pick(selectableOptions[activeIndex]);
1856
+ }
1857
+ break;
1858
+ case "Backspace":
1859
+ if (multiple && query === "" && selectedValues.length > 0) {
1860
+ commit(selectedValues.slice(0, -1));
1861
+ }
1862
+ break;
1863
+ case "Tab":
1864
+ setOpen(false);
1865
+ break;
1866
+ }
1867
+ };
1868
+ const hasValue = selectedValues.length > 0;
1869
+ const doHighlight = highlightMatch ?? searchable;
1870
+ const isLoadingEmpty = Boolean(loading) && selectableOptions.length === 0;
1871
+ if (native && !multiple && !searchable) {
1872
+ return /* @__PURE__ */ jsx(
1873
+ Field,
1874
+ {
1875
+ label,
1876
+ description,
1877
+ error,
1878
+ success,
1879
+ required,
1880
+ disabled,
1881
+ id,
1882
+ className,
1883
+ children: ({ describedById, invalid }) => /* @__PURE__ */ jsxs(
1884
+ "select",
1885
+ {
1886
+ id,
1887
+ name,
1888
+ className: "orynn-dropdown",
1889
+ value: selectedValues[0] ?? "",
1890
+ disabled,
1891
+ required,
1892
+ "aria-invalid": invalid || void 0,
1893
+ "aria-describedby": describedById,
1894
+ onChange: (e) => commit(e.target.value ? [e.target.value] : []),
1895
+ children: [
1896
+ placeholder != null && /* @__PURE__ */ jsx("option", { value: "", disabled: required, children: placeholder }),
1897
+ baseOptions.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, disabled: o.disabled, children: o.label }, o.value))
1898
+ ]
1899
+ }
1900
+ )
1901
+ }
1902
+ );
1903
+ }
1904
+ return /* @__PURE__ */ jsx(
1905
+ Field,
1906
+ {
1907
+ label,
1908
+ description,
1909
+ error,
1910
+ success,
1911
+ required,
1912
+ disabled,
1913
+ hideLabel: floatingLabel,
1914
+ id,
1915
+ className,
1916
+ children: ({ describedById, invalid, valid }) => /* @__PURE__ */ jsxs(Fragment, { children: [
1917
+ /* @__PURE__ */ jsx(
1918
+ FieldBox,
1919
+ {
1920
+ ref: boxRef,
1921
+ size,
1922
+ variant,
1923
+ radius,
1924
+ disabled,
1925
+ invalid,
1926
+ valid,
1927
+ open,
1928
+ active: hasValue,
1929
+ onClick: () => {
1930
+ inputRef.current?.focus();
1931
+ openPanel();
1932
+ },
1933
+ floatingLabel: floatingLabel ? /* @__PURE__ */ jsx("label", { className: "orynn-box__label", htmlFor: id, children: label }) : void 0,
1934
+ right: /* @__PURE__ */ jsxs(Fragment, { children: [
1935
+ loading && /* @__PURE__ */ jsx(SpinnerIcon, {}),
1936
+ clearable && hasValue && !disabled && !readOnly && /* @__PURE__ */ jsx(
1937
+ "button",
1938
+ {
1939
+ type: "button",
1940
+ className: "orynn-box__iconbtn",
1941
+ "aria-label": "Clear",
1942
+ tabIndex: -1,
1943
+ onClick: (e) => {
1944
+ e.stopPropagation();
1945
+ clearAll();
1946
+ },
1947
+ children: /* @__PURE__ */ jsx(XIcon, {})
1948
+ }
1949
+ ),
1950
+ valid && !loading && /* @__PURE__ */ jsx(CheckIcon, { className: "orynn-icon-success" }),
1951
+ /* @__PURE__ */ jsx(ChevronDownIcon, { className: "orynn-select__chevron" })
1952
+ ] }),
1953
+ children: /* @__PURE__ */ jsxs("div", { className: "orynn-select__value", children: [
1954
+ startContent,
1955
+ multiple && selectedOptions.length > 0 && /* @__PURE__ */ jsxs("span", { className: "orynn-select__chips", children: [
1956
+ (maxSelectedLabels ? selectedOptions.slice(0, maxSelectedLabels) : selectedOptions).map((o) => /* @__PURE__ */ jsxs("span", { className: "orynn-select__chip", children: [
1957
+ /* @__PURE__ */ jsx("span", { children: o.label }),
1958
+ /* @__PURE__ */ jsx(
1959
+ "button",
1960
+ {
1961
+ type: "button",
1962
+ "aria-label": `Remove ${o.label}`,
1963
+ tabIndex: -1,
1964
+ onClick: (e) => {
1965
+ e.stopPropagation();
1966
+ commit(selectedValues.filter((v) => v !== o.value));
1967
+ },
1968
+ children: /* @__PURE__ */ jsx(XIcon, {})
1969
+ }
1970
+ )
1971
+ ] }, o.value)),
1972
+ maxSelectedLabels && selectedOptions.length > maxSelectedLabels && /* @__PURE__ */ jsx("span", { className: "orynn-select__chip", children: /* @__PURE__ */ jsxs("span", { children: [
1973
+ "+",
1974
+ selectedOptions.length - maxSelectedLabels
1975
+ ] }) })
1976
+ ] }),
1977
+ !multiple && hasValue && query === "" && /* @__PURE__ */ jsx("span", { className: "orynn-select__single", children: renderValue ? renderValue(selectedOptions) : selectedOptions[0]?.label }),
1978
+ !hasValue && !searchable && query === "" && /* @__PURE__ */ jsx("span", { className: "orynn-select__value--placeholder orynn-select__single", children: floatingLabel ? "" : placeholder }),
1979
+ /* @__PURE__ */ jsx(
1980
+ "input",
1981
+ {
1982
+ ...ref ? { ref: setRefs(ref, inputRef) } : { ref: inputRef },
1983
+ id,
1984
+ className: "orynn-select__search",
1985
+ role: "combobox",
1986
+ "aria-expanded": open,
1987
+ "aria-controls": listId,
1988
+ "aria-autocomplete": searchable ? "list" : "none",
1989
+ "aria-activedescendant": open && selectableOptions[activeIndex] ? `${id}-opt-${selectableOptions[activeIndex].value}` : void 0,
1990
+ "aria-invalid": invalid || void 0,
1991
+ "aria-describedby": describedById,
1992
+ autoComplete: "off",
1993
+ readOnly: !searchable || readOnly,
1994
+ disabled,
1995
+ placeholder: (
1996
+ // only the search input shows the placeholder; when not
1997
+ // searchable the sibling span owns it (avoids a double render)
1998
+ !hasValue && searchable ? placeholder : void 0
1999
+ ),
2000
+ value: query,
2001
+ size: 1,
2002
+ onChange: (e) => {
2003
+ setQuery(e.target.value);
2004
+ if (!open) setOpen(true);
2005
+ },
2006
+ onKeyDown,
2007
+ onFocus: openPanel
2008
+ }
2009
+ ),
2010
+ name != null && (multiple ? selectedValues.map((v) => /* @__PURE__ */ jsx("input", { type: "hidden", name, value: v }, v)) : /* @__PURE__ */ jsx("input", { type: "hidden", name, value: selectedValues[0] ?? "" }))
2011
+ ] })
2012
+ }
2013
+ ),
2014
+ /* @__PURE__ */ jsx(
2015
+ Popover,
2016
+ {
2017
+ open,
2018
+ anchorRef: boxRef,
2019
+ onClose: () => setOpen(false),
2020
+ popoverRef: listRef,
2021
+ maxHeight,
2022
+ children: /* @__PURE__ */ jsxs(
2023
+ "div",
2024
+ {
2025
+ className: "orynn-listbox",
2026
+ id: listId,
2027
+ role: "listbox",
2028
+ "aria-multiselectable": multiple || void 0,
2029
+ children: [
2030
+ multiple && showSelectAll && selectAllTargets.length > 0 && /* @__PURE__ */ jsx("button", { type: "button", className: "orynn-listbox__action", onClick: toggleSelectAll, children: allSelected ? "Clear all" : "Select all" }),
2031
+ isLoadingEmpty ? /* @__PURE__ */ jsx("div", { className: "orynn-listbox__empty", children: loadingMessage }) : selectableOptions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "orynn-listbox__empty", children: emptyMessage }) : rows.map(
2032
+ (row) => row.type === "group" ? /* @__PURE__ */ jsx("div", { className: "orynn-listbox__group", children: renderGroupLabel ? renderGroupLabel(row.label) : row.label }, `g-${row.label}`) : row.option.value === CREATE_VALUE ? /* @__PURE__ */ jsx(
2033
+ "div",
2034
+ {
2035
+ id: `${id}-opt-${CREATE_VALUE}`,
2036
+ role: "option",
2037
+ "aria-selected": false,
2038
+ className: "orynn-option orynn-option--create",
2039
+ "data-active": row.optionIndex === activeIndex || void 0,
2040
+ onMouseEnter: () => setActiveIndex(row.optionIndex),
2041
+ onClick: () => pick(row.option),
2042
+ children: /* @__PURE__ */ jsx("span", { className: "orynn-option__body", children: /* @__PURE__ */ jsx("span", { className: "orynn-option__label", children: formatCreateLabel ? formatCreateLabel(row.option.label) : `Create "${row.option.label}"` }) })
2043
+ },
2044
+ CREATE_VALUE
2045
+ ) : /* @__PURE__ */ jsx(
2046
+ "div",
2047
+ {
2048
+ id: `${id}-opt-${row.option.value}`,
2049
+ role: "option",
2050
+ "aria-selected": selectedValues.includes(row.option.value),
2051
+ "aria-disabled": row.option.disabled || void 0,
2052
+ className: "orynn-option",
2053
+ "data-active": row.optionIndex === activeIndex || void 0,
2054
+ "data-selected": selectedValues.includes(row.option.value) || void 0,
2055
+ "data-disabled": row.option.disabled || void 0,
2056
+ onMouseEnter: () => setActiveIndex(row.optionIndex),
2057
+ onClick: () => pick(row.option),
2058
+ children: renderOption ? renderOption(row.option, {
2059
+ selected: selectedValues.includes(row.option.value),
2060
+ active: row.optionIndex === activeIndex,
2061
+ disabled: Boolean(row.option.disabled),
2062
+ query
2063
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2064
+ row.option.icon,
2065
+ /* @__PURE__ */ jsxs("span", { className: "orynn-option__body", children: [
2066
+ /* @__PURE__ */ jsx("span", { className: "orynn-option__label", children: doHighlight ? /* @__PURE__ */ jsx(Highlight, { text: row.option.label, query }) : row.option.label }),
2067
+ row.option.description != null && /* @__PURE__ */ jsx("span", { className: "orynn-option__desc", children: row.option.description })
2068
+ ] }),
2069
+ selectedValues.includes(row.option.value) && /* @__PURE__ */ jsx(CheckIcon, { className: "orynn-option__check" })
2070
+ ] })
2071
+ },
2072
+ row.option.value
2073
+ )
2074
+ )
2075
+ ]
2076
+ }
2077
+ )
2078
+ }
2079
+ )
2080
+ ] })
2081
+ }
2082
+ );
2083
+ }
2084
+ );
2085
+ function setRefs(...refs) {
2086
+ return (node) => {
2087
+ for (const r of refs) {
2088
+ if (typeof r === "function") r(node);
2089
+ else if (r && typeof r === "object") r.current = node;
2090
+ }
2091
+ };
2092
+ }
2093
+ var Input = /* @__PURE__ */ forwardRef(
2094
+ function Input2(props, ref) {
2095
+ const {
2096
+ label,
2097
+ description,
2098
+ error,
2099
+ success,
2100
+ required,
2101
+ disabled,
2102
+ readOnly,
2103
+ size,
2104
+ variant,
2105
+ radius,
2106
+ floatingLabel,
2107
+ startContent,
2108
+ endContent,
2109
+ clearable,
2110
+ onClear,
2111
+ loading,
2112
+ id: idProp,
2113
+ name,
2114
+ className,
2115
+ value: valueProp,
2116
+ defaultValue,
2117
+ onChange,
2118
+ onEnter,
2119
+ onKeyDown,
2120
+ type = "text",
2121
+ prefix,
2122
+ suffix,
2123
+ addonBefore,
2124
+ addonAfter,
2125
+ passwordToggle,
2126
+ passwordVisible,
2127
+ onPasswordVisibleChange,
2128
+ visibilityToggleIcon,
2129
+ showCount,
2130
+ debounce,
2131
+ maxLength,
2132
+ placeholder,
2133
+ ...rest
2134
+ } = props;
2135
+ const reactId = useId();
2136
+ const id = idProp ?? reactId;
2137
+ const [value, setValue] = useControllableState({
2138
+ value: valueProp,
2139
+ defaultValue: defaultValue ?? "",
2140
+ onChange: void 0
2141
+ });
2142
+ const revealIsControlled = passwordVisible !== void 0;
2143
+ const [innerReveal, setInnerReveal] = useState(false);
2144
+ const reveal = revealIsControlled ? passwordVisible : innerReveal;
2145
+ const setReveal = (next) => {
2146
+ if (!revealIsControlled) setInnerReveal(next);
2147
+ onPasswordVisibleChange?.(next);
2148
+ };
2149
+ const debounceTimer = useRef();
2150
+ useEffect(() => () => clearTimeout(debounceTimer.current), []);
2151
+ const emitChange = (v, e) => {
2152
+ if (debounce && debounce > 0) {
2153
+ clearTimeout(debounceTimer.current);
2154
+ debounceTimer.current = setTimeout(() => onChange?.(v, e), debounce);
2155
+ } else {
2156
+ onChange?.(v, e);
2157
+ }
2158
+ };
2159
+ const showToggle = (passwordToggle ?? type === "password") && !disabled && !readOnly;
2160
+ const effectiveType = type === "password" && reveal ? "text" : type;
2161
+ const hasValue = value.length > 0;
2162
+ const showClear = clearable && hasValue && !disabled && !readOnly;
2163
+ const countMax = showCount && typeof showCount === "object" ? showCount.max ?? maxLength : maxLength;
2164
+ const countNode = showCount && typeof showCount === "object" && showCount.formatter ? showCount.formatter(value.length, countMax) : `${value.length}${countMax ? `/${countMax}` : ""}`;
2165
+ const handleChange = (e) => {
2166
+ setValue(e.target.value);
2167
+ emitChange(e.target.value, e);
2168
+ };
2169
+ const handleKeyDown = (e) => {
2170
+ if (e.key === "Enter") onEnter?.(value);
2171
+ onKeyDown?.(e);
2172
+ };
2173
+ const clear = () => {
2174
+ setValue("");
2175
+ onClear?.();
2176
+ };
2177
+ return /* @__PURE__ */ jsx(
2178
+ Field,
2179
+ {
2180
+ label,
2181
+ description,
2182
+ error,
2183
+ success,
2184
+ required,
2185
+ disabled,
2186
+ hideLabel: floatingLabel,
2187
+ id,
2188
+ className,
2189
+ children: ({ describedById, invalid, valid }) => /* @__PURE__ */ jsx(
2190
+ FieldBox,
2191
+ {
2192
+ size,
2193
+ variant,
2194
+ radius,
2195
+ disabled,
2196
+ invalid,
2197
+ valid,
2198
+ active: hasValue,
2199
+ addonBefore,
2200
+ addonAfter,
2201
+ left: startContent != null || prefix != null ? /* @__PURE__ */ jsxs(Fragment, { children: [
2202
+ startContent,
2203
+ prefix != null && /* @__PURE__ */ jsx("span", { className: "orynn-box__adornment--affix", children: prefix })
2204
+ ] }) : void 0,
2205
+ right: /* @__PURE__ */ jsxs(Fragment, { children: [
2206
+ suffix != null && /* @__PURE__ */ jsx("span", { className: "orynn-box__adornment--affix", children: suffix }),
2207
+ showCount && /* @__PURE__ */ jsx("span", { className: "orynn-box__adornment--affix", children: countNode }),
2208
+ showClear && /* @__PURE__ */ jsx(
2209
+ "button",
2210
+ {
2211
+ type: "button",
2212
+ className: "orynn-box__iconbtn",
2213
+ "aria-label": "Clear",
2214
+ tabIndex: -1,
2215
+ onClick: clear,
2216
+ children: /* @__PURE__ */ jsx(XIcon, {})
2217
+ }
2218
+ ),
2219
+ showToggle && /* @__PURE__ */ jsx(
2220
+ "button",
2221
+ {
2222
+ type: "button",
2223
+ className: "orynn-box__iconbtn",
2224
+ "aria-label": reveal ? "Hide" : "Show",
2225
+ "aria-pressed": reveal,
2226
+ tabIndex: -1,
2227
+ onClick: () => setReveal(!reveal),
2228
+ children: visibilityToggleIcon ? visibilityToggleIcon(reveal) : reveal ? /* @__PURE__ */ jsx(EyeOffIcon, {}) : /* @__PURE__ */ jsx(EyeIcon, {})
2229
+ }
2230
+ ),
2231
+ loading && /* @__PURE__ */ jsx(SpinnerIcon, {}),
2232
+ endContent,
2233
+ valid && !loading && /* @__PURE__ */ jsx(CheckIcon, { className: "orynn-icon-success" })
2234
+ ] }),
2235
+ floatingLabel: floatingLabel ? /* @__PURE__ */ jsx("label", { className: "orynn-box__label", htmlFor: id, children: label }) : void 0,
2236
+ children: /* @__PURE__ */ jsx(
2237
+ "input",
2238
+ {
2239
+ ...rest,
2240
+ ref,
2241
+ id,
2242
+ name,
2243
+ className: "orynn-box__field",
2244
+ type: effectiveType,
2245
+ value,
2246
+ disabled,
2247
+ readOnly,
2248
+ required,
2249
+ maxLength,
2250
+ placeholder: floatingLabel ? void 0 : placeholder,
2251
+ "aria-invalid": invalid || void 0,
2252
+ "aria-describedby": describedById,
2253
+ onChange: handleChange,
2254
+ onKeyDown: handleKeyDown
2255
+ }
2256
+ )
2257
+ }
2258
+ )
2259
+ }
2260
+ );
2261
+ }
2262
+ );
2263
+ var clamp = (n, min, max) => Math.min(max ?? Number.POSITIVE_INFINITY, Math.max(min ?? Number.NEGATIVE_INFINITY, n));
2264
+ var round = (n, p) => p == null ? n : Math.round(n * 10 ** p) / 10 ** p;
2265
+ var SENTINEL_GROUP = "[[g]]";
2266
+ var SENTINEL_DECIMAL = "[[d]]";
2267
+ function swapSeparators(out, seps, thousandSeparator, decimalSeparator) {
2268
+ return out.split(seps.group).join(SENTINEL_GROUP).split(seps.decimal).join(SENTINEL_DECIMAL).split(SENTINEL_GROUP).join(thousandSeparator ?? seps.group).split(SENTINEL_DECIMAL).join(decimalSeparator ?? seps.decimal);
2269
+ }
2270
+ var NumberField = /* @__PURE__ */ forwardRef(
2271
+ function NumberField2(props, ref) {
2272
+ const {
2273
+ label,
2274
+ description,
2275
+ error,
2276
+ success,
2277
+ required,
2278
+ disabled,
2279
+ readOnly,
2280
+ size,
2281
+ variant,
2282
+ radius,
2283
+ floatingLabel,
2284
+ startContent,
2285
+ endContent,
2286
+ id: idProp,
2287
+ name,
2288
+ className,
2289
+ value: valueProp,
2290
+ defaultValue = null,
2291
+ onChange,
2292
+ onValueChange,
2293
+ min,
2294
+ max,
2295
+ step = 1,
2296
+ shiftStep,
2297
+ smallStep,
2298
+ precision,
2299
+ decimalScale,
2300
+ fixedDecimalScale,
2301
+ buttons = "stacked",
2302
+ hideControls,
2303
+ grouping,
2304
+ thousandSeparator,
2305
+ decimalSeparator,
2306
+ locale,
2307
+ style,
2308
+ currency,
2309
+ unit,
2310
+ formatOptions,
2311
+ format: formatFn,
2312
+ parse: parseFn,
2313
+ prefix,
2314
+ suffix,
2315
+ allowNegative = true,
2316
+ clampBehavior,
2317
+ clampOnBlur,
2318
+ emptyValue = null,
2319
+ allowMouseWheel,
2320
+ isWheelDisabled,
2321
+ stepHoldDelay = 300,
2322
+ stepHoldInterval = 60,
2323
+ placeholder,
2324
+ ...rest
2325
+ } = props;
2326
+ const reactId = useId();
2327
+ const id = idProp ?? reactId;
2328
+ const [value, setValue] = useControllableState({
2329
+ value: valueProp,
2330
+ defaultValue,
2331
+ onChange: void 0
2332
+ });
2333
+ const resolvedStyle = style ?? (currency ? "currency" : "decimal");
2334
+ const scale = decimalScale ?? precision;
2335
+ const clampMode = clampBehavior ?? (clampOnBlur === false ? "none" : "blur");
2336
+ const effMin = allowNegative ? min : Math.max(0, min ?? 0);
2337
+ const showButtons = hideControls ? false : buttons;
2338
+ const wheelEnabled = isWheelDisabled != null ? !isWheelDisabled : Boolean(allowMouseWheel);
2339
+ const fmt = useMemo(() => {
2340
+ if (formatOptions) return new Intl.NumberFormat(locale, formatOptions);
2341
+ const opts = {
2342
+ useGrouping: grouping ?? (thousandSeparator != null || resolvedStyle === "currency")
2343
+ };
2344
+ if (resolvedStyle === "currency") {
2345
+ opts.style = "currency";
2346
+ opts.currency = currency ?? "USD";
2347
+ } else if (resolvedStyle === "percent") {
2348
+ opts.style = "percent";
2349
+ } else if (resolvedStyle === "unit" && unit) {
2350
+ opts.style = "unit";
2351
+ opts.unit = unit;
2352
+ }
2353
+ if (scale != null) {
2354
+ opts.maximumFractionDigits = scale;
2355
+ if (fixedDecimalScale) opts.minimumFractionDigits = scale;
2356
+ } else {
2357
+ opts.maximumFractionDigits = resolvedStyle === "currency" ? 2 : 20;
2358
+ opts.minimumFractionDigits = resolvedStyle === "currency" ? 2 : 0;
2359
+ }
2360
+ return new Intl.NumberFormat(locale, opts);
2361
+ }, [
2362
+ locale,
2363
+ formatOptions,
2364
+ grouping,
2365
+ thousandSeparator,
2366
+ resolvedStyle,
2367
+ currency,
2368
+ unit,
2369
+ scale,
2370
+ fixedDecimalScale
2371
+ ]);
2372
+ const seps = useMemo(() => {
2373
+ const parts = new Intl.NumberFormat(locale).formatToParts(11111.1);
2374
+ return {
2375
+ group: parts.find((p) => p.type === "group")?.value ?? ",",
2376
+ decimal: parts.find((p) => p.type === "decimal")?.value ?? "."
2377
+ };
2378
+ }, [locale]);
2379
+ const display = useCallback(
2380
+ (n) => {
2381
+ if (n == null || Number.isNaN(n)) return "";
2382
+ if (formatFn) return formatFn(n);
2383
+ let out = fmt.format(n);
2384
+ if (thousandSeparator != null || decimalSeparator != null) {
2385
+ out = swapSeparators(out, seps, thousandSeparator, decimalSeparator);
2386
+ }
2387
+ return `${prefix ?? ""}${out}${suffix ?? ""}`;
2388
+ },
2389
+ [fmt, formatFn, prefix, suffix, seps, thousandSeparator, decimalSeparator]
2390
+ );
2391
+ const parse = useCallback(
2392
+ (raw) => {
2393
+ if (parseFn) return parseFn(raw);
2394
+ let s = raw;
2395
+ if (prefix) s = s.split(prefix).join("");
2396
+ if (suffix) s = s.split(suffix).join("");
2397
+ const grp = thousandSeparator ?? seps.group;
2398
+ const dec = decimalSeparator ?? seps.decimal;
2399
+ s = s.split(grp).join("").split(dec).join(".");
2400
+ s = s.replace(/[^\d.\-]/g, "");
2401
+ if (!allowNegative) s = s.replace(/-/g, "");
2402
+ if (s === "" || s === "-" || s === ".") return null;
2403
+ const first = s.indexOf(".");
2404
+ if (first !== -1) s = s.slice(0, first + 1) + s.slice(first + 1).replace(/\./g, "");
2405
+ let n = Number(s);
2406
+ if (Number.isNaN(n)) return null;
2407
+ if (resolvedStyle === "percent" && !formatFn) n = n / 100;
2408
+ return n;
2409
+ },
2410
+ [
2411
+ parseFn,
2412
+ prefix,
2413
+ suffix,
2414
+ seps,
2415
+ thousandSeparator,
2416
+ decimalSeparator,
2417
+ allowNegative,
2418
+ resolvedStyle,
2419
+ formatFn
2420
+ ]
2421
+ );
2422
+ const [text, setText] = useState(() => display(value));
2423
+ const [editing, setEditing] = useState(false);
2424
+ useEffect(() => {
2425
+ if (!editing) setText(display(value));
2426
+ }, [value, editing, display]);
2427
+ const commit = (n) => {
2428
+ setValue(n);
2429
+ onChange?.(n);
2430
+ onValueChange?.({ value: n, formatted: display(n) });
2431
+ };
2432
+ const setNumber = (n) => {
2433
+ commit(n);
2434
+ setText(display(n));
2435
+ };
2436
+ const bump = (dir, mode = "n") => {
2437
+ const amount = mode === "l" ? shiftStep ?? step * 10 : mode === "s" ? smallStep ?? step / 10 : step;
2438
+ const base2 = value ?? (dir > 0 ? effMin ?? 0 : max ?? 0);
2439
+ let next = round(base2 + amount * dir, scale);
2440
+ if (clampMode !== "none") next = clamp(next, effMin, max);
2441
+ else if (!allowNegative && next < 0) next = 0;
2442
+ setNumber(next);
2443
+ };
2444
+ const innerRef = useRef(null);
2445
+ useEffect(() => {
2446
+ const el = innerRef.current;
2447
+ if (!el || !wheelEnabled) return;
2448
+ const onWheel = (e) => {
2449
+ if (document.activeElement !== el) return;
2450
+ e.preventDefault();
2451
+ bump(e.deltaY < 0 ? 1 : -1, e.shiftKey ? "l" : e.altKey ? "s" : "n");
2452
+ };
2453
+ el.addEventListener("wheel", onWheel, { passive: false });
2454
+ return () => el.removeEventListener("wheel", onWheel);
2455
+ });
2456
+ const onKeyDown = (e) => {
2457
+ if (disabled || readOnly) return;
2458
+ const mode = e.shiftKey ? "l" : e.altKey ? "s" : "n";
2459
+ if (e.key === "ArrowUp") {
2460
+ e.preventDefault();
2461
+ bump(1, mode);
2462
+ } else if (e.key === "ArrowDown") {
2463
+ e.preventDefault();
2464
+ bump(-1, mode);
2465
+ } else if (e.key === "PageUp") {
2466
+ e.preventDefault();
2467
+ bump(1, "l");
2468
+ } else if (e.key === "PageDown") {
2469
+ e.preventDefault();
2470
+ bump(-1, "l");
2471
+ } else if (e.key === "Home" && effMin != null) {
2472
+ e.preventDefault();
2473
+ setNumber(effMin);
2474
+ } else if (e.key === "End" && max != null) {
2475
+ e.preventDefault();
2476
+ setNumber(max);
2477
+ }
2478
+ };
2479
+ const holdTimer = useRef();
2480
+ const holdDelay = useRef();
2481
+ const startHold = (dir) => {
2482
+ bump(dir);
2483
+ let count = 0;
2484
+ holdDelay.current = setTimeout(() => {
2485
+ holdTimer.current = setInterval(() => {
2486
+ count += 1;
2487
+ bump(dir, count > 6 ? "l" : "n");
2488
+ }, stepHoldInterval);
2489
+ }, stepHoldDelay);
2490
+ };
2491
+ const stopHold = () => {
2492
+ clearTimeout(holdDelay.current);
2493
+ clearInterval(holdTimer.current);
2494
+ };
2495
+ useEffect(() => stopHold, []);
2496
+ const StepButtons = showButtons && /* @__PURE__ */ jsxs(
2497
+ "div",
2498
+ {
2499
+ className: `orynn-number__buttons${showButtons === "horizontal" ? " orynn-number__buttons--horizontal" : ""}`,
2500
+ children: [
2501
+ /* @__PURE__ */ jsx(
2502
+ "button",
2503
+ {
2504
+ type: "button",
2505
+ className: "orynn-number__btn",
2506
+ "aria-label": "Increment",
2507
+ tabIndex: -1,
2508
+ disabled: disabled || readOnly || max != null && (value ?? 0) >= max,
2509
+ onPointerDown: () => startHold(1),
2510
+ onPointerUp: stopHold,
2511
+ onPointerLeave: stopHold,
2512
+ children: /* @__PURE__ */ jsx(ChevronUpIcon, { className: "orynn-number__caret" })
2513
+ }
2514
+ ),
2515
+ /* @__PURE__ */ jsx(
2516
+ "button",
2517
+ {
2518
+ type: "button",
2519
+ className: "orynn-number__btn",
2520
+ "aria-label": "Decrement",
2521
+ tabIndex: -1,
2522
+ disabled: disabled || readOnly || effMin != null && (value ?? 0) <= effMin,
2523
+ onPointerDown: () => startHold(-1),
2524
+ onPointerUp: stopHold,
2525
+ onPointerLeave: stopHold,
2526
+ children: /* @__PURE__ */ jsx(ChevronDownIcon, { className: "orynn-number__caret" })
2527
+ }
2528
+ )
2529
+ ]
2530
+ }
2531
+ );
2532
+ const hasValue = value != null;
2533
+ return /* @__PURE__ */ jsx(
2534
+ Field,
2535
+ {
2536
+ label,
2537
+ description,
2538
+ error,
2539
+ success,
2540
+ required,
2541
+ disabled,
2542
+ hideLabel: floatingLabel,
2543
+ id,
2544
+ className,
2545
+ children: ({ describedById, invalid, valid }) => /* @__PURE__ */ jsx(
2546
+ FieldBox,
2547
+ {
2548
+ size,
2549
+ variant,
2550
+ radius,
2551
+ disabled,
2552
+ invalid,
2553
+ valid,
2554
+ active: hasValue,
2555
+ left: startContent,
2556
+ right: /* @__PURE__ */ jsxs(Fragment, { children: [
2557
+ endContent,
2558
+ StepButtons
2559
+ ] }),
2560
+ floatingLabel: floatingLabel ? /* @__PURE__ */ jsx("label", { className: "orynn-box__label", htmlFor: id, children: label }) : void 0,
2561
+ children: /* @__PURE__ */ jsx(
2562
+ "input",
2563
+ {
2564
+ ...rest,
2565
+ ref: (n) => {
2566
+ innerRef.current = n;
2567
+ if (typeof ref === "function") ref(n);
2568
+ else if (ref) ref.current = n;
2569
+ },
2570
+ id,
2571
+ name,
2572
+ className: "orynn-box__field",
2573
+ type: "text",
2574
+ inputMode: "decimal",
2575
+ role: "spinbutton",
2576
+ "aria-valuenow": value ?? void 0,
2577
+ "aria-valuemin": effMin,
2578
+ "aria-valuemax": max,
2579
+ value: text,
2580
+ disabled,
2581
+ readOnly,
2582
+ required,
2583
+ placeholder: floatingLabel ? void 0 : placeholder,
2584
+ "aria-invalid": invalid || void 0,
2585
+ "aria-describedby": describedById,
2586
+ onFocus: () => setEditing(true),
2587
+ onChange: (e) => {
2588
+ setText(e.target.value);
2589
+ const parsed = parse(e.target.value);
2590
+ commit(
2591
+ parsed == null ? null : clampMode === "strict" ? clamp(parsed, effMin, max) : parsed
2592
+ );
2593
+ },
2594
+ onKeyDown,
2595
+ onBlur: () => {
2596
+ setEditing(false);
2597
+ const parsed = parse(text);
2598
+ const final = parsed == null ? emptyValue : round(clampMode !== "none" ? clamp(parsed, effMin, max) : parsed, scale);
2599
+ if (final !== value) commit(final);
2600
+ setText(display(final));
2601
+ }
2602
+ }
2603
+ )
2604
+ }
2605
+ )
2606
+ }
2607
+ );
2608
+ }
2609
+ );
2610
+ var RadioGroupContext = createContext(null);
2611
+ var sizePx2 = { sm: "0.875rem", md: "1rem", lg: "1.125rem" };
2612
+ var Radio = /* @__PURE__ */ forwardRef(
2613
+ function Radio2(props, ref) {
2614
+ const group = useContext(RadioGroupContext);
2615
+ const {
2616
+ value,
2617
+ label,
2618
+ description,
2619
+ disabled: disabledProp,
2620
+ size: sizeProp,
2621
+ card: cardProp,
2622
+ labelPlacement = "end",
2623
+ className,
2624
+ id: idProp,
2625
+ ...rest
2626
+ } = props;
2627
+ const reactId = useId();
2628
+ const id = idProp ?? reactId;
2629
+ const checked = group ? group.value === value : void 0;
2630
+ const disabled = disabledProp || group?.disabled || false;
2631
+ const size = sizeProp ?? group?.size ?? "md";
2632
+ const card = cardProp ?? group?.variant === "card";
2633
+ const onChange = (e) => {
2634
+ if (e.target.checked) group?.select(value);
2635
+ };
2636
+ return /* @__PURE__ */ jsxs(
2637
+ "label",
2638
+ {
2639
+ className: cx(
2640
+ "orynn-choice",
2641
+ card && "orynn-choice--card",
2642
+ labelPlacement === "start" && "orynn-choice--start",
2643
+ className
2644
+ ),
2645
+ "data-disabled": disabled || void 0,
2646
+ style: { "--orynn-check-size": sizePx2[size] },
2647
+ children: [
2648
+ /* @__PURE__ */ jsx(
2649
+ "input",
2650
+ {
2651
+ ...rest,
2652
+ ref,
2653
+ type: "radio",
2654
+ className: "orynn-choice__native",
2655
+ id,
2656
+ name: group?.name,
2657
+ value,
2658
+ checked: group ? checked : void 0,
2659
+ disabled,
2660
+ onChange
2661
+ }
2662
+ ),
2663
+ /* @__PURE__ */ jsx("span", { className: "orynn-choice__control orynn-choice__control--radio", "aria-hidden": "true", children: /* @__PURE__ */ jsx("span", { className: "orynn-choice__mark orynn-choice__mark--dot" }) }),
2664
+ (label != null || description != null) && /* @__PURE__ */ jsxs("span", { className: "orynn-choice__text", children: [
2665
+ label != null && /* @__PURE__ */ jsx("span", { className: "orynn-choice__label", children: label }),
2666
+ description != null && /* @__PURE__ */ jsx("span", { className: "orynn-choice__desc", children: description })
2667
+ ] })
2668
+ ]
2669
+ }
2670
+ );
2671
+ }
2672
+ );
2673
+ function RadioGroup(props) {
2674
+ const {
2675
+ label,
2676
+ description,
2677
+ error,
2678
+ success,
2679
+ required,
2680
+ disabled,
2681
+ name: nameProp,
2682
+ size,
2683
+ variant = "default",
2684
+ value: valueProp,
2685
+ defaultValue = null,
2686
+ onChange,
2687
+ orientation = "vertical",
2688
+ columns,
2689
+ options,
2690
+ children,
2691
+ className,
2692
+ id: idProp
2693
+ } = props;
2694
+ const reactId = useId();
2695
+ const id = idProp ?? reactId;
2696
+ const name = nameProp ?? id;
2697
+ const [value, setValue] = useControllableState({
2698
+ value: valueProp,
2699
+ defaultValue,
2700
+ onChange: void 0
2701
+ });
2702
+ const select = (v) => {
2703
+ setValue(v);
2704
+ onChange?.(v);
2705
+ };
2706
+ return /* @__PURE__ */ jsx(
2707
+ Field,
2708
+ {
2709
+ label,
2710
+ description,
2711
+ error,
2712
+ success,
2713
+ required,
2714
+ disabled,
2715
+ id,
2716
+ className,
2717
+ children: () => /* @__PURE__ */ jsx(RadioGroupContext.Provider, { value: { name, value, select, disabled, size, variant }, children: /* @__PURE__ */ jsx(
2718
+ "div",
2719
+ {
2720
+ role: "radiogroup",
2721
+ "aria-labelledby": label != null ? `${id}-label` : void 0,
2722
+ "aria-required": required || void 0,
2723
+ className: "orynn-choice-group",
2724
+ "data-orientation": columns ? void 0 : orientation,
2725
+ "data-columns": columns ? "" : void 0,
2726
+ style: columns ? { "--orynn-choice-columns": columns } : void 0,
2727
+ children: options ? options.map((o) => /* @__PURE__ */ jsx(
2728
+ Radio,
2729
+ {
2730
+ value: o.value,
2731
+ label: o.icon != null ? /* @__PURE__ */ jsxs(Fragment, { children: [
2732
+ /* @__PURE__ */ jsx("span", { className: "orynn-choice__icon", children: o.icon }),
2733
+ o.label
2734
+ ] }) : o.label,
2735
+ description: o.description,
2736
+ disabled: o.disabled
2737
+ },
2738
+ o.value
2739
+ )) : children
2740
+ }
2741
+ ) })
2742
+ }
2743
+ );
2744
+ }
2745
+ var Textarea = /* @__PURE__ */ forwardRef(
2746
+ function Textarea2(props, ref) {
2747
+ const {
2748
+ label,
2749
+ description,
2750
+ error,
2751
+ success,
2752
+ required,
2753
+ disabled,
2754
+ readOnly,
2755
+ size,
2756
+ variant,
2757
+ radius,
2758
+ floatingLabel,
2759
+ clearable,
2760
+ onClear,
2761
+ loading,
2762
+ endContent,
2763
+ id: idProp,
2764
+ name,
2765
+ className,
2766
+ value: valueProp,
2767
+ defaultValue,
2768
+ onChange,
2769
+ onEnter,
2770
+ submitOnEnter,
2771
+ onKeyDown,
2772
+ autoResize,
2773
+ minRows = 3,
2774
+ maxRows = 10,
2775
+ resize,
2776
+ showCount,
2777
+ maxLength,
2778
+ placeholder,
2779
+ ...rest
2780
+ } = props;
2781
+ const reactId = useId();
2782
+ const id = idProp ?? reactId;
2783
+ const [value, setValue] = useControllableState({
2784
+ value: valueProp,
2785
+ defaultValue: defaultValue ?? "",
2786
+ onChange: void 0
2787
+ });
2788
+ const innerRef = useRef(null);
2789
+ useImperativeHandle(ref, () => innerRef.current);
2790
+ const resizeToFit = useCallback(() => {
2791
+ const el = innerRef.current;
2792
+ if (!el || !autoResize) return;
2793
+ el.style.height = "auto";
2794
+ const cs = getComputedStyle(el);
2795
+ const line = Number.parseFloat(cs.lineHeight) || 20;
2796
+ const pad3 = Number.parseFloat(cs.paddingTop) + Number.parseFloat(cs.paddingBottom);
2797
+ const min = line * minRows + pad3;
2798
+ const max = line * maxRows + pad3;
2799
+ el.style.height = `${Math.min(Math.max(el.scrollHeight, min), max)}px`;
2800
+ el.style.overflowY = el.scrollHeight > max ? "auto" : "hidden";
2801
+ }, [autoResize, minRows, maxRows]);
2802
+ useLayoutEffect(resizeToFit, [value, resizeToFit]);
2803
+ const handleChange = (e) => {
2804
+ setValue(e.target.value);
2805
+ onChange?.(e.target.value, e);
2806
+ };
2807
+ const handleKeyDown = (e) => {
2808
+ if (e.key === "Enter" && !e.shiftKey && (onEnter || submitOnEnter)) {
2809
+ if (submitOnEnter) e.preventDefault();
2810
+ onEnter?.(value);
2811
+ }
2812
+ onKeyDown?.(e);
2813
+ };
2814
+ const hasValue = value.length > 0;
2815
+ const countMax = showCount && typeof showCount === "object" ? showCount.max ?? maxLength : maxLength;
2816
+ const countNode = showCount && typeof showCount === "object" && showCount.formatter ? showCount.formatter(value.length, countMax) : `${value.length}${countMax ? `/${countMax}` : ""}`;
2817
+ return /* @__PURE__ */ jsx(
2818
+ Field,
2819
+ {
2820
+ label,
2821
+ description,
2822
+ error,
2823
+ success,
2824
+ required,
2825
+ disabled,
2826
+ hideLabel: floatingLabel,
2827
+ id,
2828
+ className,
2829
+ children: ({ describedById, invalid, valid }) => /* @__PURE__ */ jsxs(
2830
+ FieldBox,
2831
+ {
2832
+ textarea: true,
2833
+ size,
2834
+ variant,
2835
+ radius,
2836
+ disabled,
2837
+ invalid,
2838
+ valid,
2839
+ active: hasValue,
2840
+ floatingLabel: floatingLabel ? /* @__PURE__ */ jsx("label", { className: "orynn-box__label", htmlFor: id, children: label }) : void 0,
2841
+ right: clearable && hasValue || loading || endContent != null ? /* @__PURE__ */ jsxs(Fragment, { children: [
2842
+ clearable && hasValue && !disabled && !readOnly && /* @__PURE__ */ jsx(
2843
+ "button",
2844
+ {
2845
+ type: "button",
2846
+ className: "orynn-box__iconbtn",
2847
+ "aria-label": "Clear",
2848
+ tabIndex: -1,
2849
+ onClick: () => {
2850
+ setValue("");
2851
+ onClear?.();
2852
+ },
2853
+ children: /* @__PURE__ */ jsx(XIcon, {})
2854
+ }
2855
+ ),
2856
+ loading && /* @__PURE__ */ jsx(SpinnerIcon, {}),
2857
+ endContent
2858
+ ] }) : void 0,
2859
+ children: [
2860
+ /* @__PURE__ */ jsx(
2861
+ "textarea",
2862
+ {
2863
+ ...rest,
2864
+ ref: innerRef,
2865
+ id,
2866
+ name,
2867
+ className: "orynn-textarea",
2868
+ "data-resize": resize ?? (autoResize ? "none" : "vertical"),
2869
+ rows: minRows,
2870
+ value,
2871
+ disabled,
2872
+ readOnly,
2873
+ required,
2874
+ maxLength,
2875
+ placeholder: floatingLabel ? void 0 : placeholder,
2876
+ "aria-invalid": invalid || void 0,
2877
+ "aria-describedby": describedById,
2878
+ onChange: handleChange,
2879
+ onKeyDown: handleKeyDown
2880
+ }
2881
+ ),
2882
+ showCount && /* @__PURE__ */ jsx("span", { className: "orynn-box__footer", children: countNode })
2883
+ ]
2884
+ }
2885
+ )
2886
+ }
2887
+ );
2888
+ }
2889
+ );
2890
+
2891
+ // src/internal/dev.ts
165
2892
  var __DEV__ = typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
166
2893
  function invariant(condition, message) {
167
2894
  if (condition) return;
@@ -209,24 +2936,63 @@ function registerField(type, registration) {
209
2936
 
210
2937
  // src/layout/resolve-columns.ts
211
2938
  var DEFAULT_COLUMNS = { desktop: 3, tablet: 2, mobile: 1 };
2939
+ var DEFAULT_MIN_COL = 192;
212
2940
  var clampCount = (n, fallback) => typeof n === "number" && Number.isFinite(n) && n >= 1 ? Math.floor(n) : fallback;
213
- function resolveColumns(partial) {
2941
+ function resolveColumns(input) {
2942
+ if (typeof input === "number") {
2943
+ const n = clampCount(input, DEFAULT_COLUMNS.desktop);
2944
+ return { desktop: n, tablet: n, mobile: n };
2945
+ }
214
2946
  return {
215
- desktop: clampCount(partial?.desktop, DEFAULT_COLUMNS.desktop),
216
- tablet: clampCount(partial?.tablet, DEFAULT_COLUMNS.tablet),
217
- mobile: clampCount(partial?.mobile, DEFAULT_COLUMNS.mobile)
2947
+ desktop: clampCount(input?.desktop, DEFAULT_COLUMNS.desktop),
2948
+ tablet: clampCount(input?.tablet, DEFAULT_COLUMNS.tablet),
2949
+ mobile: clampCount(input?.mobile, DEFAULT_COLUMNS.mobile)
218
2950
  };
219
2951
  }
2952
+ function resolveGrid(width, cols, minColWidth = DEFAULT_MIN_COL) {
2953
+ const { desktop: d, tablet: t, mobile: m } = cols;
2954
+ if (!width || !Number.isFinite(width) || width <= 0) {
2955
+ return { count: d, tier: "desktop" };
2956
+ }
2957
+ const per = minColWidth > 0 ? minColWidth : DEFAULT_MIN_COL;
2958
+ const maxFit = Math.max(1, Math.floor(width / per));
2959
+ if (d === t && t === m) {
2960
+ const count = Math.min(d, maxFit);
2961
+ return { count, tier: count >= d ? "desktop" : count > 1 ? "tablet" : "mobile" };
2962
+ }
2963
+ if (maxFit >= d) return { count: d, tier: "desktop" };
2964
+ if (t < d && maxFit >= t) return { count: t, tier: "tablet" };
2965
+ if (maxFit >= m) return { count: m, tier: "mobile" };
2966
+ return { count: Math.min(m, maxFit), tier: "mobile" };
2967
+ }
220
2968
  function clampSpan(span, columnCount) {
221
2969
  const n = clampCount(span, 1);
222
2970
  return Math.min(n, Math.max(columnCount, 1));
223
2971
  }
2972
+ function pickSpan(layout, tier) {
2973
+ if (!layout) return 1;
2974
+ const v = layout[tier] ?? layout.desktop ?? layout.tablet ?? layout.mobile;
2975
+ return typeof v === "number" && Number.isFinite(v) && v >= 1 ? Math.floor(v) : 1;
2976
+ }
224
2977
 
225
2978
  // src/core/config/normalize.ts
226
2979
  function normalizeGap(gap) {
227
2980
  if (gap == null) return void 0;
228
2981
  return typeof gap === "number" ? `${gap}px` : gap;
229
2982
  }
2983
+ function normalizeMinColWidth(value) {
2984
+ if (typeof value === "number") return value > 0 ? value : DEFAULT_MIN_COL;
2985
+ if (typeof value === "string") {
2986
+ const n = Number.parseFloat(value);
2987
+ if (!Number.isFinite(n) || n <= 0) return DEFAULT_MIN_COL;
2988
+ if (/rem|em/i.test(value)) {
2989
+ const root = typeof document !== "undefined" ? Number.parseFloat(getComputedStyle(document.documentElement).fontSize) || 16 : 16;
2990
+ return n * root;
2991
+ }
2992
+ return n;
2993
+ }
2994
+ return DEFAULT_MIN_COL;
2995
+ }
230
2996
  function normalizeConfig(config, registry2) {
231
2997
  invariant(
232
2998
  config != null && typeof config === "object" && Array.isArray(config.fields),
@@ -260,18 +3026,52 @@ function normalizeConfig(config, registry2) {
260
3026
  return {
261
3027
  fields: config.fields,
262
3028
  columns: resolveColumns(config.columns),
3029
+ minColWidth: normalizeMinColWidth(config.minColumnWidth),
263
3030
  gap: normalizeGap(config.gap),
264
3031
  legend: config.legend,
265
3032
  id: config.id
266
3033
  };
267
3034
  }
268
3035
 
3036
+ // src/core/config/conditions.ts
3037
+ function evalCondition(when, values) {
3038
+ if (when == null) return true;
3039
+ if (typeof when === "function") return Boolean(when(values));
3040
+ const actual = values[when.field];
3041
+ if ("eq" in when) return actual === when.eq;
3042
+ if ("ne" in when) return actual !== when.ne;
3043
+ if ("in" in when) return Array.isArray(when.in) && when.in.includes(actual);
3044
+ if ("notIn" in when) return Array.isArray(when.notIn) && !when.notIn.includes(actual);
3045
+ if ("truthy" in when) return Boolean(actual) === Boolean(when.truthy);
3046
+ return Boolean(actual);
3047
+ }
3048
+
269
3049
  // src/core/validation/messages.ts
270
3050
  var plural = (n, word) => `${n} ${word}${n === 1 ? "" : "s"}`;
3051
+ var dateStr = (p) => {
3052
+ const d = p instanceof Date ? p : new Date(String(p));
3053
+ return Number.isNaN(d.getTime()) ? String(p) : d.toLocaleDateString();
3054
+ };
271
3055
  var defaultMessages = {
272
3056
  required: ({ label }) => `${label} is required`,
273
3057
  minLength: ({ param, label }) => `${label} must be at least ${plural(param, "character")}`,
274
- maxLength: ({ param, label }) => `${label} must be at most ${plural(param, "character")}`
3058
+ maxLength: ({ param, label }) => `${label} must be at most ${plural(param, "character")}`,
3059
+ minItems: ({ param, label }) => `Select at least ${plural(param, "option")} for ${label}`,
3060
+ maxItems: ({ param, label }) => `Select at most ${plural(param, "option")} for ${label}`,
3061
+ min: ({ param, label }) => `${label} must be at least ${param}`,
3062
+ max: ({ param, label }) => `${label} must be at most ${param}`,
3063
+ integer: ({ label }) => `${label} must be a whole number`,
3064
+ minDate: ({ param, label }) => `${label} must be on or after ${dateStr(param)}`,
3065
+ maxDate: ({ param, label }) => `${label} must be on or before ${dateStr(param)}`,
3066
+ minRangeDays: ({ param, label }) => `${label} must span at least ${plural(param, "day")}`,
3067
+ maxRangeDays: ({ param, label }) => `${label} must span at most ${plural(param, "day")}`,
3068
+ email: ({ label }) => `${label} must be a valid email address`,
3069
+ url: ({ label }) => `${label} must be a valid URL`,
3070
+ pattern: ({ label }) => `${label} is not in the expected format`,
3071
+ oneOf: ({ label }) => `${label} is not an allowed value`,
3072
+ equals: ({ label }) => `${label} does not match`,
3073
+ validate: ({ label }) => `${label} is invalid`,
3074
+ schema: ({ label }) => `${label} is invalid`
275
3075
  };
276
3076
  var FALLBACK_LABEL = "This field";
277
3077
  function resolveMessage(token, param, label, overrides) {
@@ -285,6 +3085,50 @@ function resolveMessage(token, param, label, overrides) {
285
3085
  // src/core/validation/rules.ts
286
3086
  var isEmpty = (value) => value == null || value === "" || Array.isArray(value) && value.length === 0;
287
3087
  var asLength = (value) => typeof value === "string" || Array.isArray(value) ? value.length : String(value ?? "").length;
3088
+ var toNumber = (value) => {
3089
+ if (typeof value === "number") return Number.isNaN(value) ? null : value;
3090
+ if (typeof value === "string" && value.trim() !== "") {
3091
+ const n = Number(value);
3092
+ return Number.isNaN(n) ? null : n;
3093
+ }
3094
+ return null;
3095
+ };
3096
+ var toTime = (value) => {
3097
+ if (value == null || value === "") return null;
3098
+ const d = value instanceof Date ? value : new Date(value);
3099
+ const t = d.getTime();
3100
+ return Number.isNaN(t) ? null : t;
3101
+ };
3102
+ var rangeSpanDays = (value) => {
3103
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
3104
+ const { start, end } = value;
3105
+ const s = toTime(start);
3106
+ const e = toTime(end);
3107
+ if (s == null || e == null) return null;
3108
+ return Math.abs(Math.round((e - s) / 864e5)) + 1;
3109
+ };
3110
+ var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
3111
+ var URL_RE = /^(https?:\/\/)[^\s.]+\.\S{2,}$/i;
3112
+ function toRegExp(param) {
3113
+ if (param instanceof RegExp) return param;
3114
+ if (typeof param === "string") {
3115
+ try {
3116
+ return new RegExp(param);
3117
+ } catch {
3118
+ return null;
3119
+ }
3120
+ }
3121
+ if (param && typeof param === "object" && "value" in param) {
3122
+ const { value, flags } = param;
3123
+ if (value instanceof RegExp) return value;
3124
+ try {
3125
+ return new RegExp(value, flags);
3126
+ } catch {
3127
+ return null;
3128
+ }
3129
+ }
3130
+ return null;
3131
+ }
288
3132
  var builtInRules = {
289
3133
  required: (value, param) => {
290
3134
  if (param === false) return null;
@@ -297,25 +3141,103 @@ var builtInRules = {
297
3141
  maxLength: (value, param) => {
298
3142
  if (typeof param !== "number" || isEmpty(value)) return null;
299
3143
  return asLength(value) > param ? "maxLength" : null;
300
- }
301
- };
302
- var registry = new Map(Object.entries(builtInRules));
303
- function registerRule(name, fn) {
304
- registry.set(name, fn);
305
- }
306
- function getRule(name) {
307
- return registry.get(name);
308
- }
309
-
310
- // src/core/validation/resolver.ts
311
- function createRuleResolver() {
312
- return (values, config) => {
313
- const result = {};
314
- for (const field of config.fields) {
315
- const validation = field.validation;
316
- if (!validation) continue;
317
- const value = values[field.name];
318
- const errors = [];
3144
+ },
3145
+ minItems: (value, param) => {
3146
+ if (typeof param !== "number" || !Array.isArray(value)) return null;
3147
+ return value.length < param ? "minItems" : null;
3148
+ },
3149
+ maxItems: (value, param) => {
3150
+ if (typeof param !== "number" || !Array.isArray(value)) return null;
3151
+ return value.length > param ? "maxItems" : null;
3152
+ },
3153
+ email: (value, param) => {
3154
+ if (param === false || isEmpty(value)) return null;
3155
+ return EMAIL_RE.test(String(value)) ? null : "email";
3156
+ },
3157
+ url: (value, param) => {
3158
+ if (param === false || isEmpty(value)) return null;
3159
+ return URL_RE.test(String(value)) ? null : "url";
3160
+ },
3161
+ pattern: (value, param) => {
3162
+ if (isEmpty(value)) return null;
3163
+ const re = toRegExp(param);
3164
+ if (!re) return null;
3165
+ return re.test(String(value)) ? null : "pattern";
3166
+ },
3167
+ integer: (value, param) => {
3168
+ if (param === false || isEmpty(value)) return null;
3169
+ const n = toNumber(value);
3170
+ return n != null && Number.isInteger(n) ? null : "integer";
3171
+ },
3172
+ min: (value, param) => {
3173
+ if (typeof param !== "number" || isEmpty(value)) return null;
3174
+ const n = toNumber(value);
3175
+ return n != null && n < param ? "min" : null;
3176
+ },
3177
+ max: (value, param) => {
3178
+ if (typeof param !== "number" || isEmpty(value)) return null;
3179
+ const n = toNumber(value);
3180
+ return n != null && n > param ? "max" : null;
3181
+ },
3182
+ minDate: (value, param) => {
3183
+ if (isEmpty(value)) return null;
3184
+ const v = toTime(value);
3185
+ const p = toTime(param);
3186
+ return v != null && p != null && v < p ? "minDate" : null;
3187
+ },
3188
+ maxDate: (value, param) => {
3189
+ if (isEmpty(value)) return null;
3190
+ const v = toTime(value);
3191
+ const p = toTime(param);
3192
+ return v != null && p != null && v > p ? "maxDate" : null;
3193
+ },
3194
+ minRangeDays: (value, param) => {
3195
+ if (typeof param !== "number") return null;
3196
+ const span = rangeSpanDays(value);
3197
+ return span != null && span < param ? "minRangeDays" : null;
3198
+ },
3199
+ maxRangeDays: (value, param) => {
3200
+ if (typeof param !== "number") return null;
3201
+ const span = rangeSpanDays(value);
3202
+ return span != null && span > param ? "maxRangeDays" : null;
3203
+ },
3204
+ oneOf: (value, param) => {
3205
+ if (isEmpty(value) || !Array.isArray(param)) return null;
3206
+ return param.includes(value) ? null : "oneOf";
3207
+ },
3208
+ equals: (value, param, allValues) => {
3209
+ if (isEmpty(value)) return null;
3210
+ const target = param && typeof param === "object" && "field" in param ? allValues[param.field] : param;
3211
+ return value == target ? null : "equals";
3212
+ },
3213
+ validate: (value, param, allValues) => {
3214
+ if (typeof param !== "function") return null;
3215
+ const out = param(value, allValues);
3216
+ if (out instanceof Promise) {
3217
+ return out.then(
3218
+ (r) => typeof r === "string" ? r : r === false ? "validate" : null
3219
+ );
3220
+ }
3221
+ return typeof out === "string" ? out : out === false ? "validate" : null;
3222
+ }
3223
+ };
3224
+ var registry = new Map(Object.entries(builtInRules));
3225
+ function registerRule(name, fn) {
3226
+ registry.set(name, fn);
3227
+ }
3228
+ function getRule(name) {
3229
+ return registry.get(name);
3230
+ }
3231
+
3232
+ // src/core/validation/resolver.ts
3233
+ function createRuleResolver() {
3234
+ return (values, config) => {
3235
+ const pending = [];
3236
+ for (const field of config.fields) {
3237
+ const validation = field.validation;
3238
+ if (!validation) continue;
3239
+ if (!evalCondition(field.when, values)) continue;
3240
+ const value = values[field.name];
319
3241
  for (const key of Object.keys(validation)) {
320
3242
  if (key === "messages") continue;
321
3243
  const param = validation[key];
@@ -327,16 +3249,34 @@ function createRuleResolver() {
327
3249
  }
328
3250
  continue;
329
3251
  }
330
- const token = rule(value, param, values);
331
- if (token == null) continue;
332
- errors.push({
3252
+ pending.push({
3253
+ field: field.name,
333
3254
  rule: key,
334
- message: resolveMessage(token, param, field.label, validation.messages)
3255
+ param,
3256
+ label: field.label,
3257
+ overrides: validation.messages,
3258
+ token: rule(value, param, values)
335
3259
  });
336
3260
  }
337
- if (errors.length > 0) result[field.name] = errors;
338
3261
  }
339
- return result;
3262
+ const collect = (settled) => {
3263
+ const result = {};
3264
+ pending.forEach((p, i) => {
3265
+ const token = settled[i];
3266
+ if (token == null) return;
3267
+ const bucket = result[p.field] ?? [];
3268
+ bucket.push({
3269
+ rule: p.rule,
3270
+ message: resolveMessage(token, p.param, p.label, p.overrides)
3271
+ });
3272
+ result[p.field] = bucket;
3273
+ });
3274
+ return result;
3275
+ };
3276
+ if (pending.some((p) => p.token instanceof Promise)) {
3277
+ return Promise.all(pending.map((p) => Promise.resolve(p.token))).then(collect);
3278
+ }
3279
+ return collect(pending.map((p) => p.token));
340
3280
  };
341
3281
  }
342
3282
  var defaultResolver = /* @__PURE__ */ createRuleResolver();
@@ -387,32 +3327,6 @@ function computeDirty(values, initial) {
387
3327
  }
388
3328
  return dirty;
389
3329
  }
390
- function useLatestRef(value) {
391
- const ref = useRef(value);
392
- ref.current = value;
393
- return ref;
394
- }
395
-
396
- // src/core/state/use-controllable-state.ts
397
- function useControllableState({
398
- value,
399
- defaultValue,
400
- onChange
401
- }) {
402
- const isControlled = value !== void 0;
403
- const [uncontrolled, setUncontrolled] = useState(defaultValue);
404
- const current = isControlled ? value : uncontrolled;
405
- const currentRef = useLatestRef(current);
406
- const onChangeRef = useLatestRef(onChange);
407
- const isControlledRef = useLatestRef(isControlled);
408
- const setValue = useCallback((next) => {
409
- const resolved = typeof next === "function" ? next(currentRef.current) : next;
410
- if (Object.is(resolved, currentRef.current)) return;
411
- if (!isControlledRef.current) setUncontrolled(resolved);
412
- onChangeRef.current?.(resolved);
413
- }, []);
414
- return [current, setValue];
415
- }
416
3330
 
417
3331
  // src/core/state/use-fieldset-state.ts
418
3332
  var NO_ERRORS = Object.freeze([]);
@@ -594,23 +3508,43 @@ function useFieldsetState(config, options = {}) {
594
3508
  getFieldProps
595
3509
  };
596
3510
  }
597
- function FieldGrid({ columns, gap, className, children }) {
3511
+ var useBrowserLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
3512
+ var GridContext = createContext({ count: 1, tier: "desktop" });
3513
+ function FieldGrid({ columns, minColWidth, gap, className, children }) {
3514
+ const ref = useRef(null);
3515
+ const per = minColWidth && minColWidth > 0 ? minColWidth : DEFAULT_MIN_COL;
3516
+ const { desktop, tablet, mobile } = columns;
3517
+ const [grid, setGrid] = useState(() => resolveGrid(0, columns, per));
3518
+ useBrowserLayoutEffect(() => {
3519
+ const el = ref.current;
3520
+ if (!el) return;
3521
+ const cols = { desktop, tablet, mobile };
3522
+ const apply = (width) => {
3523
+ const next = resolveGrid(width, cols, per);
3524
+ setGrid((cur) => cur.count === next.count && cur.tier === next.tier ? cur : next);
3525
+ };
3526
+ apply(el.getBoundingClientRect().width);
3527
+ if (typeof ResizeObserver === "undefined") return;
3528
+ const ro = new ResizeObserver((entries) => {
3529
+ for (const entry of entries) {
3530
+ const box = entry.contentBoxSize?.[0];
3531
+ apply(box ? box.inlineSize : entry.contentRect.width);
3532
+ }
3533
+ });
3534
+ ro.observe(el);
3535
+ return () => ro.disconnect();
3536
+ }, [desktop, tablet, mobile, per]);
598
3537
  const style = {
599
- "--orynn-cols-desktop": columns.desktop,
600
- "--orynn-cols-tablet": columns.tablet,
601
- "--orynn-cols-mobile": columns.mobile,
3538
+ "--orynn-cols": grid.count,
602
3539
  ...gap ? { "--orynn-grid-gap": gap } : {}
603
3540
  };
604
- return /* @__PURE__ */ jsx("div", { className: cx("orynn-grid", className), style, children: /* @__PURE__ */ jsx("div", { className: "orynn-grid__track", children }) });
3541
+ return /* @__PURE__ */ jsx("div", { ref, className: cx("orynn-grid", className), style, children: /* @__PURE__ */ jsx(GridContext.Provider, { value: grid, children: /* @__PURE__ */ jsx("div", { className: "orynn-grid__track", children }) }) });
605
3542
  }
606
- function FieldGridItem({ span, columns, children }) {
607
- if (!span) return /* @__PURE__ */ jsx(Fragment, { children });
608
- const style = {
609
- "--orynn-span-desktop": clampSpan(span.desktop, columns.desktop),
610
- "--orynn-span-tablet": clampSpan(span.tablet, columns.tablet),
611
- "--orynn-span-mobile": clampSpan(span.mobile, columns.mobile)
612
- };
613
- return /* @__PURE__ */ jsx("div", { className: "orynn-grid__item", style, children });
3543
+ function FieldGridItem({ span, children }) {
3544
+ const { count, tier } = useContext(GridContext);
3545
+ const effective = span ? clampSpan(pickSpan(span, tier), count) : 1;
3546
+ if (effective <= 1) return /* @__PURE__ */ jsx(Fragment, { children });
3547
+ return /* @__PURE__ */ jsx("div", { className: "orynn-grid__item", style: { "--orynn-span": effective }, children });
614
3548
  }
615
3549
  var noop = () => {
616
3550
  };
@@ -620,6 +3554,7 @@ function FieldRendererImpl({ field, registry: registry2, slice, disabled }) {
620
3554
  registration,
621
3555
  `No control registered for field type "${field.type}" (field "${field.name}").`
622
3556
  );
3557
+ const fallbackId = useId();
623
3558
  if (!registration) return null;
624
3559
  const Control = registration.component;
625
3560
  const required = field.validation?.required === true;
@@ -629,6 +3564,36 @@ function FieldRendererImpl({ field, registry: registry2, slice, disabled }) {
629
3564
  const handleChange = (next) => {
630
3565
  slice.setValue(registration.formatValue ? registration.formatValue(next) : next);
631
3566
  };
3567
+ if (registration.selfContained) {
3568
+ return /* @__PURE__ */ jsx(
3569
+ "div",
3570
+ {
3571
+ style: { display: "contents" },
3572
+ onBlur: (e) => {
3573
+ if (!e.currentTarget.contains(e.relatedTarget)) slice.markTouched();
3574
+ },
3575
+ children: /* @__PURE__ */ jsx(
3576
+ Control,
3577
+ {
3578
+ id: fallbackId,
3579
+ name: field.name,
3580
+ value,
3581
+ onChange: handleChange,
3582
+ onBlur: slice.markTouched,
3583
+ onFocus: noop,
3584
+ disabled: isDisabled,
3585
+ readOnly: field.readOnly === true,
3586
+ required,
3587
+ invalid: messages.length > 0,
3588
+ label: field.label,
3589
+ description: field.description,
3590
+ errors: messages,
3591
+ config: field
3592
+ }
3593
+ )
3594
+ }
3595
+ );
3596
+ }
632
3597
  return /* @__PURE__ */ jsx(
633
3598
  Field,
634
3599
  {
@@ -661,90 +3626,290 @@ var FieldRenderer = /* @__PURE__ */ memo(
661
3626
  FieldRendererImpl,
662
3627
  (prev, next) => prev.field === next.field && prev.registry === next.registry && prev.disabled === next.disabled && prev.slice.value === next.slice.value && prev.slice.touched === next.slice.touched && prev.slice.errors === next.slice.errors && prev.slice.setValue === next.slice.setValue && prev.slice.markTouched === next.slice.markTouched
663
3628
  );
664
- var toStringValue = (value) => typeof value === "string" ? value : value == null ? "" : String(value);
665
- var InputControl = ({
666
- id,
667
- name,
668
- value,
669
- onChange,
670
- onBlur,
671
- onFocus,
672
- disabled,
673
- readOnly,
674
- required,
675
- invalid,
676
- describedById,
677
- config
678
- }) => {
679
- const field = config;
3629
+ function FieldsetView({ state, registry: registry2, disabled, className, id }) {
3630
+ const activeRegistry = registry2 ?? defaultRegistry;
3631
+ const { columns, minColWidth, gap, legend, fields, id: configId } = state.config;
3632
+ const visible = fields.filter((f) => evalCondition(f.when, state.values));
3633
+ return /* @__PURE__ */ jsxs(
3634
+ "fieldset",
3635
+ {
3636
+ className: cx("orynn-fieldset", className),
3637
+ id: id ?? configId,
3638
+ disabled: disabled || void 0,
3639
+ children: [
3640
+ legend != null && /* @__PURE__ */ jsx("legend", { className: "orynn-fieldset__legend", children: legend }),
3641
+ /* @__PURE__ */ jsx(FieldGrid, { columns, minColWidth, gap, children: visible.map((field) => /* @__PURE__ */ jsx(FieldGridItem, { span: field.layout, children: /* @__PURE__ */ jsx(
3642
+ FieldRenderer,
3643
+ {
3644
+ field,
3645
+ registry: activeRegistry,
3646
+ slice: state.getFieldProps(field.name),
3647
+ disabled: disabled === true
3648
+ }
3649
+ ) }, field.name)) })
3650
+ ]
3651
+ }
3652
+ );
3653
+ }
3654
+ var str = (v) => typeof v === "string" ? v : v == null ? "" : String(v);
3655
+ var toISO = (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
3656
+ function shell(p) {
3657
+ const c = p.config;
3658
+ return {
3659
+ id: p.id,
3660
+ name: p.name,
3661
+ label: p.label,
3662
+ description: p.description,
3663
+ error: p.errors,
3664
+ required: p.required,
3665
+ disabled: p.disabled,
3666
+ readOnly: p.readOnly,
3667
+ size: c.size,
3668
+ variant: c.variant,
3669
+ floatingLabel: c.floatingLabel
3670
+ };
3671
+ }
3672
+ var InputControl = (p) => {
3673
+ const c = p.config;
680
3674
  return /* @__PURE__ */ jsx(
681
- "input",
3675
+ Input,
682
3676
  {
683
- id,
684
- name,
685
- className: "orynn-input",
686
- type: field.inputType ?? "text",
687
- value: toStringValue(value),
688
- placeholder: field.placeholder,
689
- required,
690
- disabled,
691
- readOnly,
692
- "aria-invalid": invalid || void 0,
693
- "aria-describedby": describedById,
694
- onChange: (event) => onChange(event.target.value, event),
695
- onBlur,
696
- onFocus,
697
- ...field.props
3677
+ ...shell(p),
3678
+ type: c.inputType ?? "text",
3679
+ prefix: c.prefix,
3680
+ suffix: c.suffix,
3681
+ addonBefore: c.addonBefore,
3682
+ addonAfter: c.addonAfter,
3683
+ clearable: c.clearable,
3684
+ maxLength: c.maxLength,
3685
+ showCount: c.showCount,
3686
+ debounce: c.debounce,
3687
+ inputMode: c.inputMode,
3688
+ pattern: c.pattern,
3689
+ placeholder: c.placeholder,
3690
+ value: str(p.value),
3691
+ onChange: (v) => p.onChange(v),
3692
+ ...c.props
698
3693
  }
699
3694
  );
700
3695
  };
701
- var DropdownControl = ({
702
- id,
703
- name,
704
- value,
705
- onChange,
706
- onBlur,
707
- onFocus,
708
- disabled,
709
- required,
710
- invalid,
711
- describedById,
712
- config
713
- }) => {
714
- const field = config;
715
- return /* @__PURE__ */ jsxs(
716
- "select",
3696
+ var TextareaControl = (p) => {
3697
+ const c = p.config;
3698
+ return /* @__PURE__ */ jsx(
3699
+ Textarea,
717
3700
  {
718
- id,
719
- name,
720
- className: "orynn-dropdown",
721
- value: toStringValue(value),
722
- required,
723
- disabled,
724
- "aria-invalid": invalid || void 0,
725
- "aria-describedby": describedById,
726
- onChange: (event) => onChange(event.target.value, event),
727
- onBlur,
728
- onFocus,
729
- ...field.props,
730
- children: [
731
- field.placeholder != null && /* @__PURE__ */ jsx("option", { value: "", disabled: required, children: field.placeholder }),
732
- field.options.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, disabled: option.disabled, children: option.label }, option.value))
733
- ]
3701
+ ...shell(p),
3702
+ minRows: c.rows,
3703
+ maxRows: c.maxRows,
3704
+ autoResize: c.autoResize,
3705
+ resize: c.resize,
3706
+ submitOnEnter: c.submitOnEnter,
3707
+ maxLength: c.maxLength,
3708
+ showCount: c.showCount,
3709
+ placeholder: c.placeholder,
3710
+ value: str(p.value),
3711
+ onChange: (v) => p.onChange(v),
3712
+ ...c.props
734
3713
  }
735
3714
  );
736
3715
  };
737
- function registerBuiltins(registry2) {
738
- if (!registry2.has("input")) {
739
- registry2.register("input", { component: InputControl, defaultValue: "" });
740
- }
741
- if (!registry2.has("dropdown")) {
742
- registry2.register("dropdown", {
743
- component: DropdownControl,
744
- defaultValue: "",
745
- validateConfig: (config) => Array.isArray(config.options) ? null : "a dropdown field requires an `options` array"
746
- });
3716
+ var NumberFieldControl = (p) => {
3717
+ const c = p.config;
3718
+ return /* @__PURE__ */ jsx(
3719
+ NumberField,
3720
+ {
3721
+ ...shell(p),
3722
+ min: c.min,
3723
+ max: c.max,
3724
+ step: c.step,
3725
+ precision: c.precision,
3726
+ decimalScale: c.decimalScale,
3727
+ currency: c.currency,
3728
+ style: c.style,
3729
+ locale: c.locale,
3730
+ prefix: c.prefix,
3731
+ suffix: c.suffix,
3732
+ thousandSeparator: c.thousandSeparator,
3733
+ allowNegative: c.allowNegative,
3734
+ clampBehavior: c.clampBehavior,
3735
+ hideControls: c.hideControls,
3736
+ placeholder: c.placeholder,
3737
+ value: typeof p.value === "number" ? p.value : null,
3738
+ onChange: (v) => p.onChange(v),
3739
+ ...c.props
3740
+ }
3741
+ );
3742
+ };
3743
+ var DropdownControl = (p) => {
3744
+ const c = p.config;
3745
+ const value = c.multiple ? Array.isArray(p.value) ? p.value : [] : Array.isArray(p.value) ? p.value[0] ?? "" : str(p.value);
3746
+ return /* @__PURE__ */ jsx(
3747
+ Dropdown,
3748
+ {
3749
+ ...shell(p),
3750
+ options: c.options,
3751
+ searchable: c.searchable,
3752
+ multiple: c.multiple,
3753
+ clearable: c.clearable,
3754
+ creatable: c.creatable,
3755
+ maxValues: c.maxValues,
3756
+ hidePickedOptions: c.hidePickedOptions,
3757
+ showSelectAll: c.showSelectAll,
3758
+ searchDebounce: c.searchDebounce,
3759
+ placeholder: c.placeholder,
3760
+ value,
3761
+ onChange: (v) => p.onChange(v ?? (c.multiple ? [] : "")),
3762
+ ...c.props
3763
+ }
3764
+ );
3765
+ };
3766
+ var DateControl = (p) => {
3767
+ const c = p.config;
3768
+ const toDate2 = (x) => x == null ? void 0 : x instanceof Date ? x : new Date(x);
3769
+ const mode = c.mode ?? "single";
3770
+ const common = {
3771
+ ...shell(p),
3772
+ format: c.format,
3773
+ precision: c.precision,
3774
+ minDate: toDate2(c.minDate),
3775
+ maxDate: toDate2(c.maxDate),
3776
+ showToday: c.showToday,
3777
+ clearable: c.clearable,
3778
+ placeholder: c.placeholder,
3779
+ presets: c.presets,
3780
+ ...c.props
3781
+ };
3782
+ if (mode === "range") {
3783
+ const v = p.value ?? {};
3784
+ return /* @__PURE__ */ jsx(
3785
+ DatePicker,
3786
+ {
3787
+ ...common,
3788
+ mode: "range",
3789
+ value: { start: v.start ?? null, end: v.end ?? null },
3790
+ onChange: (r) => p.onChange({
3791
+ start: r.start ? toISO(r.start) : "",
3792
+ end: r.end ? toISO(r.end) : ""
3793
+ })
3794
+ }
3795
+ );
3796
+ }
3797
+ if (mode === "multiple") {
3798
+ return /* @__PURE__ */ jsx(
3799
+ DatePicker,
3800
+ {
3801
+ ...common,
3802
+ mode: "multiple",
3803
+ value: Array.isArray(p.value) ? p.value : [],
3804
+ onChange: (arr) => p.onChange(arr.map(toISO))
3805
+ }
3806
+ );
747
3807
  }
3808
+ return /* @__PURE__ */ jsx(
3809
+ DatePicker,
3810
+ {
3811
+ ...common,
3812
+ value: typeof p.value === "string" && p.value ? p.value : null,
3813
+ onChange: (d) => p.onChange(d instanceof Date ? toISO(d) : "")
3814
+ }
3815
+ );
3816
+ };
3817
+ var CheckboxControl = (p) => {
3818
+ const c = p.config;
3819
+ return /* @__PURE__ */ jsxs("div", { className: "orynn-field", children: [
3820
+ /* @__PURE__ */ jsx(
3821
+ Checkbox,
3822
+ {
3823
+ id: p.id,
3824
+ name: p.name,
3825
+ label: c.checkboxLabel ?? c.label,
3826
+ description: c.description,
3827
+ checked: Boolean(p.value),
3828
+ onChange: (v) => p.onChange(v),
3829
+ disabled: p.disabled,
3830
+ required: p.required,
3831
+ invalid: (p.errors?.length ?? 0) > 0,
3832
+ ...c.props
3833
+ }
3834
+ ),
3835
+ p.errors?.[0] && /* @__PURE__ */ jsx("p", { className: "orynn-field__error", role: "alert", children: p.errors[0] })
3836
+ ] });
3837
+ };
3838
+ var CheckboxGroupControl = (p) => {
3839
+ const c = p.config;
3840
+ return /* @__PURE__ */ jsx(
3841
+ CheckboxGroup,
3842
+ {
3843
+ id: p.id,
3844
+ name: p.name,
3845
+ label: p.label,
3846
+ description: p.description,
3847
+ error: p.errors,
3848
+ required: p.required,
3849
+ disabled: p.disabled,
3850
+ options: c.options.map((o) => ({
3851
+ label: o.label,
3852
+ value: o.value,
3853
+ description: o.description,
3854
+ icon: o.icon,
3855
+ disabled: o.disabled
3856
+ })),
3857
+ orientation: c.orientation,
3858
+ columns: c.columns,
3859
+ showSelectAll: c.showSelectAll,
3860
+ min: c.min,
3861
+ max: c.max,
3862
+ value: Array.isArray(p.value) ? p.value : [],
3863
+ onChange: (v) => p.onChange(v),
3864
+ ...c.props
3865
+ }
3866
+ );
3867
+ };
3868
+ var RadioControl = (p) => {
3869
+ const c = p.config;
3870
+ return /* @__PURE__ */ jsx(
3871
+ RadioGroup,
3872
+ {
3873
+ id: p.id,
3874
+ name: p.name,
3875
+ label: p.label,
3876
+ description: p.description,
3877
+ error: p.errors,
3878
+ required: p.required,
3879
+ disabled: p.disabled,
3880
+ options: c.options.map((o) => ({
3881
+ label: o.label,
3882
+ value: o.value,
3883
+ description: o.description,
3884
+ icon: o.icon,
3885
+ disabled: o.disabled
3886
+ })),
3887
+ orientation: c.orientation,
3888
+ columns: c.columns,
3889
+ variant: c.radioVariant,
3890
+ value: typeof p.value === "string" && p.value ? p.value : null,
3891
+ onChange: (v) => p.onChange(v),
3892
+ ...c.props
3893
+ }
3894
+ );
3895
+ };
3896
+ var needsOptions = (config) => Array.isArray(config.options) ? null : "requires an `options` array";
3897
+ function registerBuiltins(registry2) {
3898
+ const add = (type, component, extra = {}) => {
3899
+ if (!registry2.has(type)) {
3900
+ registry2.register(type, { component, selfContained: true, defaultValue: "", ...extra });
3901
+ }
3902
+ };
3903
+ add("input", InputControl);
3904
+ add("textarea", TextareaControl);
3905
+ add("number", NumberFieldControl, {
3906
+ parseValue: (raw) => typeof raw === "number" ? raw : raw === "" || raw == null ? null : Number(raw)
3907
+ });
3908
+ add("dropdown", DropdownControl, { validateConfig: needsOptions });
3909
+ add("date", DateControl);
3910
+ add("checkbox", CheckboxControl, { defaultValue: false });
3911
+ add("checkbox-group", CheckboxGroupControl, { defaultValue: [], validateConfig: needsOptions });
3912
+ add("radio", RadioControl, { validateConfig: needsOptions });
748
3913
  }
749
3914
  var seeded = false;
750
3915
  function ensureBuiltins(defaultRegistry2) {
@@ -778,32 +3943,857 @@ function Fieldset(props) {
778
3943
  ...validateOn ? { validateOn } : {}
779
3944
  };
780
3945
  const fs = useFieldsetState(config, options);
781
- const { columns, gap, legend, fields, id: configId } = fs.config;
3946
+ return /* @__PURE__ */ jsx(
3947
+ FieldsetView,
3948
+ {
3949
+ state: fs,
3950
+ registry: activeRegistry,
3951
+ disabled: disabled === true,
3952
+ className,
3953
+ id
3954
+ }
3955
+ );
3956
+ }
3957
+ function Form(props) {
3958
+ const {
3959
+ config,
3960
+ value,
3961
+ defaultValue,
3962
+ onChange,
3963
+ onSubmit,
3964
+ onInvalid,
3965
+ resolver,
3966
+ validateOn,
3967
+ disabled,
3968
+ children,
3969
+ className,
3970
+ ...rest
3971
+ } = props;
3972
+ ensureBuiltins(defaultRegistry);
3973
+ const fs = useFieldsetState(config, {
3974
+ registry: defaultRegistry,
3975
+ ...value !== void 0 ? { value } : {},
3976
+ ...defaultValue !== void 0 ? { defaultValue } : {},
3977
+ ...onChange ? { onChange } : {},
3978
+ ...resolver ? { resolver } : {},
3979
+ ...validateOn ? { validateOn } : {}
3980
+ });
782
3981
  return /* @__PURE__ */ jsxs(
783
- "fieldset",
3982
+ "form",
784
3983
  {
785
- className: cx("orynn-fieldset", className),
786
- id: id ?? configId,
787
- disabled: disabled || void 0,
3984
+ ...rest,
3985
+ className: cx("orynn-form", className),
3986
+ noValidate: true,
3987
+ onSubmit: fs.handleSubmit(
3988
+ (values) => onSubmit(values, fs),
3989
+ (errors) => onInvalid?.(errors)
3990
+ ),
788
3991
  children: [
789
- legend != null && /* @__PURE__ */ jsx("legend", { className: "orynn-fieldset__legend", children: legend }),
790
- /* @__PURE__ */ jsx(FieldGrid, { columns, gap, children: fields.map((field) => /* @__PURE__ */ jsx(FieldGridItem, { span: field.layout, columns, children: /* @__PURE__ */ jsx(
791
- FieldRenderer,
3992
+ /* @__PURE__ */ jsx(FieldsetView, { state: fs, disabled }),
3993
+ typeof children === "function" ? children(fs) : children
3994
+ ]
3995
+ }
3996
+ );
3997
+ }
3998
+
3999
+ // src/primitives/shared/classes.ts
4000
+ var mod = (base2, key, fallback) => key === fallback ? void 0 : `${base2}--${key}`;
4001
+ function buttonClasses(variant = "default", size = "default") {
4002
+ return cx(
4003
+ "orynn-button",
4004
+ mod("orynn-button", variant, "default"),
4005
+ mod("orynn-button", size, "default")
4006
+ );
4007
+ }
4008
+ function badgeClasses(variant = "default") {
4009
+ return cx("orynn-badge", mod("orynn-badge", variant, "default"));
4010
+ }
4011
+ var Button = /* @__PURE__ */ forwardRef(function Button2({
4012
+ className,
4013
+ variant = "default",
4014
+ size = "default",
4015
+ asChild = false,
4016
+ type,
4017
+ loading = false,
4018
+ loadingText,
4019
+ leftIcon,
4020
+ rightIcon,
4021
+ fullWidth = false,
4022
+ disabled,
4023
+ children,
4024
+ ...props
4025
+ }, ref) {
4026
+ const shared = {
4027
+ "data-slot": "button",
4028
+ "data-variant": variant,
4029
+ "data-size": size,
4030
+ "data-loading": loading || void 0,
4031
+ "data-full-width": fullWidth || void 0,
4032
+ className: cx(buttonClasses(variant, size), className),
4033
+ ...props
4034
+ };
4035
+ if (asChild) {
4036
+ return /* @__PURE__ */ jsx(Slot.Root, { ref, "aria-busy": loading || void 0, ...shared, children });
4037
+ }
4038
+ return /* @__PURE__ */ jsxs(
4039
+ "button",
4040
+ {
4041
+ ref,
4042
+ type: type ?? "button",
4043
+ disabled: disabled || loading,
4044
+ "aria-busy": loading || void 0,
4045
+ ...shared,
4046
+ children: [
4047
+ loading ? /* @__PURE__ */ jsx(SpinnerIcon, { className: "orynn-button__spinner" }) : leftIcon,
4048
+ loading && loadingText != null ? loadingText : children,
4049
+ !loading && rightIcon
4050
+ ]
4051
+ }
4052
+ );
4053
+ });
4054
+ var Label = /* @__PURE__ */ forwardRef(function Label2({ className, required, optional, children, ...props }, ref) {
4055
+ return /* @__PURE__ */ jsxs(
4056
+ Label$1.Root,
4057
+ {
4058
+ ref,
4059
+ "data-slot": "label",
4060
+ className: cx("orynn-label", className),
4061
+ ...props,
4062
+ children: [
4063
+ children,
4064
+ required && /* @__PURE__ */ jsx("span", { className: "orynn-label__required", "aria-hidden": "true", children: "*" }),
4065
+ !required && optional && /* @__PURE__ */ jsx("span", { className: "orynn-label__optional", children: optional === true ? "(optional)" : optional })
4066
+ ]
4067
+ }
4068
+ );
4069
+ });
4070
+ var Card = /* @__PURE__ */ forwardRef(function Card2({ className, asChild = false, interactive = false, ...props }, ref) {
4071
+ const shared = {
4072
+ "data-slot": "card",
4073
+ "data-interactive": interactive || void 0,
4074
+ className: cx("orynn-card", className),
4075
+ ...props
4076
+ };
4077
+ return asChild ? /* @__PURE__ */ jsx(Slot.Root, { ref, ...shared }) : /* @__PURE__ */ jsx("div", { ref, ...shared });
4078
+ });
4079
+ var CardHeader = /* @__PURE__ */ forwardRef(function CardHeader2({ className, ...props }, ref) {
4080
+ return /* @__PURE__ */ jsx(
4081
+ "div",
4082
+ {
4083
+ ref,
4084
+ "data-slot": "card-header",
4085
+ className: cx("orynn-card__header", className),
4086
+ ...props
4087
+ }
4088
+ );
4089
+ });
4090
+ var CardTitle = /* @__PURE__ */ forwardRef(function CardTitle2({ className, ...props }, ref) {
4091
+ return /* @__PURE__ */ jsx(
4092
+ "div",
4093
+ {
4094
+ ref,
4095
+ "data-slot": "card-title",
4096
+ className: cx("orynn-card__title", className),
4097
+ ...props
4098
+ }
4099
+ );
4100
+ });
4101
+ var CardDescription = /* @__PURE__ */ forwardRef(
4102
+ function CardDescription2({ className, ...props }, ref) {
4103
+ return /* @__PURE__ */ jsx(
4104
+ "div",
4105
+ {
4106
+ ref,
4107
+ "data-slot": "card-description",
4108
+ className: cx("orynn-card__description", className),
4109
+ ...props
4110
+ }
4111
+ );
4112
+ }
4113
+ );
4114
+ var CardAction = /* @__PURE__ */ forwardRef(function CardAction2({ className, ...props }, ref) {
4115
+ return /* @__PURE__ */ jsx(
4116
+ "div",
4117
+ {
4118
+ ref,
4119
+ "data-slot": "card-action",
4120
+ className: cx("orynn-card__action", className),
4121
+ ...props
4122
+ }
4123
+ );
4124
+ });
4125
+ var CardContent = /* @__PURE__ */ forwardRef(
4126
+ function CardContent2({ className, ...props }, ref) {
4127
+ return /* @__PURE__ */ jsx(
4128
+ "div",
4129
+ {
4130
+ ref,
4131
+ "data-slot": "card-content",
4132
+ className: cx("orynn-card__content", className),
4133
+ ...props
4134
+ }
4135
+ );
4136
+ }
4137
+ );
4138
+ var CardFooter = /* @__PURE__ */ forwardRef(function CardFooter2({ className, ...props }, ref) {
4139
+ return /* @__PURE__ */ jsx(
4140
+ "div",
4141
+ {
4142
+ ref,
4143
+ "data-slot": "card-footer",
4144
+ className: cx("orynn-card__footer", className),
4145
+ ...props
4146
+ }
4147
+ );
4148
+ });
4149
+ var Badge = /* @__PURE__ */ forwardRef(function Badge2({
4150
+ className,
4151
+ variant = "default",
4152
+ size = "md",
4153
+ dot = false,
4154
+ icon,
4155
+ removable = false,
4156
+ onRemove,
4157
+ asChild = false,
4158
+ children,
4159
+ ...props
4160
+ }, ref) {
4161
+ const shared = {
4162
+ "data-slot": "badge",
4163
+ "data-variant": variant,
4164
+ "data-size": size,
4165
+ className: cx(badgeClasses(variant), className),
4166
+ ...props
4167
+ };
4168
+ if (asChild) {
4169
+ return /* @__PURE__ */ jsx(Slot.Root, { ref, ...shared, children });
4170
+ }
4171
+ return /* @__PURE__ */ jsxs("span", { ref, ...shared, children: [
4172
+ dot && /* @__PURE__ */ jsx("span", { className: "orynn-badge__dot", "aria-hidden": "true" }),
4173
+ icon,
4174
+ children,
4175
+ removable && /* @__PURE__ */ jsx(
4176
+ "button",
4177
+ {
4178
+ type: "button",
4179
+ className: "orynn-badge__remove",
4180
+ "aria-label": "Remove",
4181
+ onClick: onRemove,
4182
+ children: /* @__PURE__ */ jsx(XIcon, {})
4183
+ }
4184
+ )
4185
+ ] });
4186
+ });
4187
+ var Alert = /* @__PURE__ */ forwardRef(function Alert2({ className, variant = "default", icon, title, dismissible, onDismiss, children, ...props }, ref) {
4188
+ return /* @__PURE__ */ jsxs(
4189
+ "div",
4190
+ {
4191
+ ref,
4192
+ "data-slot": "alert",
4193
+ "data-variant": variant,
4194
+ "data-dismissible": dismissible || void 0,
4195
+ role: "alert",
4196
+ className: cx("orynn-alert", variant !== "default" && `orynn-alert--${variant}`, className),
4197
+ ...props,
4198
+ children: [
4199
+ icon,
4200
+ title != null && /* @__PURE__ */ jsx(AlertTitle, { children: title }),
4201
+ children,
4202
+ dismissible && /* @__PURE__ */ jsx(
4203
+ "button",
792
4204
  {
793
- field,
794
- registry: activeRegistry,
795
- slice: fs.getFieldProps(field.name),
796
- disabled: disabled === true
4205
+ type: "button",
4206
+ className: "orynn-alert__dismiss",
4207
+ "aria-label": "Dismiss",
4208
+ onClick: onDismiss,
4209
+ children: /* @__PURE__ */ jsx(XIcon, {})
797
4210
  }
798
- ) }, field.name)) })
4211
+ )
4212
+ ]
4213
+ }
4214
+ );
4215
+ });
4216
+ var AlertTitle = /* @__PURE__ */ forwardRef(
4217
+ function AlertTitle2({ className, ...props }, ref) {
4218
+ return /* @__PURE__ */ jsx(
4219
+ "div",
4220
+ {
4221
+ ref,
4222
+ "data-slot": "alert-title",
4223
+ className: cx("orynn-alert__title", className),
4224
+ ...props
4225
+ }
4226
+ );
4227
+ }
4228
+ );
4229
+ var AlertDescription = /* @__PURE__ */ forwardRef(
4230
+ function AlertDescription2({ className, ...props }, ref) {
4231
+ return /* @__PURE__ */ jsx(
4232
+ "div",
4233
+ {
4234
+ ref,
4235
+ "data-slot": "alert-description",
4236
+ className: cx("orynn-alert__description", className),
4237
+ ...props
4238
+ }
4239
+ );
4240
+ }
4241
+ );
4242
+ var Separator = /* @__PURE__ */ forwardRef(
4243
+ function Separator2({
4244
+ className,
4245
+ orientation = "horizontal",
4246
+ decorative = true,
4247
+ variant = "solid",
4248
+ children,
4249
+ ...props
4250
+ }, ref) {
4251
+ if (children != null && orientation === "horizontal") {
4252
+ return /* @__PURE__ */ jsx(
4253
+ "div",
4254
+ {
4255
+ ref,
4256
+ role: "separator",
4257
+ "aria-orientation": "horizontal",
4258
+ "data-slot": "separator",
4259
+ "data-orientation": "horizontal",
4260
+ "data-variant": variant,
4261
+ className: cx("orynn-separator", "orynn-separator--labelled", className),
4262
+ ...props,
4263
+ children: /* @__PURE__ */ jsx("span", { className: "orynn-separator__label", children })
4264
+ }
4265
+ );
4266
+ }
4267
+ return /* @__PURE__ */ jsx(
4268
+ Separator$1.Root,
4269
+ {
4270
+ ref,
4271
+ "data-slot": "separator",
4272
+ "data-variant": variant,
4273
+ orientation,
4274
+ decorative,
4275
+ className: cx("orynn-separator", className),
4276
+ ...props
4277
+ }
4278
+ );
4279
+ }
4280
+ );
4281
+ var Table = /* @__PURE__ */ forwardRef(function Table2({ className, size, dense, ...props }, ref) {
4282
+ return /* @__PURE__ */ jsx("div", { "data-slot": "table-container", className: "orynn-table__wrap", children: /* @__PURE__ */ jsx(
4283
+ "table",
4284
+ {
4285
+ ref,
4286
+ "data-slot": "table",
4287
+ "data-size": dense ? "sm" : size,
4288
+ className: cx("orynn-table", className),
4289
+ ...props
4290
+ }
4291
+ ) });
4292
+ });
4293
+ var TableHeader = /* @__PURE__ */ forwardRef(
4294
+ function TableHeader2({ className, sticky, ...props }, ref) {
4295
+ return /* @__PURE__ */ jsx(
4296
+ "thead",
4297
+ {
4298
+ ref,
4299
+ "data-slot": "table-header",
4300
+ "data-sticky": sticky || void 0,
4301
+ className: cx("orynn-table__header", className),
4302
+ ...props
4303
+ }
4304
+ );
4305
+ }
4306
+ );
4307
+ var TableBody = /* @__PURE__ */ forwardRef(function TableBody2({ className, ...props }, ref) {
4308
+ return /* @__PURE__ */ jsx(
4309
+ "tbody",
4310
+ {
4311
+ ref,
4312
+ "data-slot": "table-body",
4313
+ className: cx("orynn-table__body", className),
4314
+ ...props
4315
+ }
4316
+ );
4317
+ });
4318
+ var TableFooter = /* @__PURE__ */ forwardRef(function TableFooter2({ className, ...props }, ref) {
4319
+ return /* @__PURE__ */ jsx(
4320
+ "tfoot",
4321
+ {
4322
+ ref,
4323
+ "data-slot": "table-footer",
4324
+ className: cx("orynn-table__footer", className),
4325
+ ...props
4326
+ }
4327
+ );
4328
+ });
4329
+ var TableRow = /* @__PURE__ */ forwardRef(
4330
+ function TableRow2({ className, selected, ...props }, ref) {
4331
+ return /* @__PURE__ */ jsx(
4332
+ "tr",
4333
+ {
4334
+ ref,
4335
+ "data-slot": "table-row",
4336
+ "data-state": selected ? "selected" : void 0,
4337
+ className: cx("orynn-table__row", className),
4338
+ ...props
4339
+ }
4340
+ );
4341
+ }
4342
+ );
4343
+ var TableHead = /* @__PURE__ */ forwardRef(
4344
+ function TableHead2({ className, ...props }, ref) {
4345
+ return /* @__PURE__ */ jsx(
4346
+ "th",
4347
+ {
4348
+ ref,
4349
+ "data-slot": "table-head",
4350
+ className: cx("orynn-table__head", className),
4351
+ ...props
4352
+ }
4353
+ );
4354
+ }
4355
+ );
4356
+ var TableCell = /* @__PURE__ */ forwardRef(
4357
+ function TableCell2({ className, ...props }, ref) {
4358
+ return /* @__PURE__ */ jsx(
4359
+ "td",
4360
+ {
4361
+ ref,
4362
+ "data-slot": "table-cell",
4363
+ className: cx("orynn-table__cell", className),
4364
+ ...props
4365
+ }
4366
+ );
4367
+ }
4368
+ );
4369
+ var TableCaption = /* @__PURE__ */ forwardRef(function TableCaption2({ className, ...props }, ref) {
4370
+ return /* @__PURE__ */ jsx(
4371
+ "caption",
4372
+ {
4373
+ ref,
4374
+ "data-slot": "table-caption",
4375
+ className: cx("orynn-table__caption", className),
4376
+ ...props
4377
+ }
4378
+ );
4379
+ });
4380
+ var Switch = /* @__PURE__ */ forwardRef(function Switch2({
4381
+ className,
4382
+ size = "default",
4383
+ label,
4384
+ description,
4385
+ labelPlacement = "end",
4386
+ onLabel,
4387
+ offLabel,
4388
+ thumbIcon,
4389
+ id: idProp,
4390
+ ...props
4391
+ }, ref) {
4392
+ const reactId = useId();
4393
+ const id = idProp ?? reactId;
4394
+ const control = /* @__PURE__ */ jsxs(
4395
+ Switch$1.Root,
4396
+ {
4397
+ ref,
4398
+ id,
4399
+ "data-slot": "switch",
4400
+ "data-size": size,
4401
+ className: cx("orynn-switch", className),
4402
+ ...props,
4403
+ children: [
4404
+ offLabel != null && /* @__PURE__ */ jsx("span", { className: "orynn-switch__text orynn-switch__text--off", "aria-hidden": "true", children: offLabel }),
4405
+ onLabel != null && /* @__PURE__ */ jsx("span", { className: "orynn-switch__text orynn-switch__text--on", "aria-hidden": "true", children: onLabel }),
4406
+ /* @__PURE__ */ jsx(Switch$1.Thumb, { "data-slot": "switch-thumb", className: "orynn-switch__thumb", children: thumbIcon })
4407
+ ]
4408
+ }
4409
+ );
4410
+ if (label == null && description == null) return control;
4411
+ return /* @__PURE__ */ jsxs(
4412
+ "label",
4413
+ {
4414
+ className: "orynn-switch-field",
4415
+ "data-slot": "switch-field",
4416
+ "data-placement": labelPlacement,
4417
+ htmlFor: id,
4418
+ children: [
4419
+ control,
4420
+ /* @__PURE__ */ jsxs("span", { className: "orynn-switch-field__text", children: [
4421
+ /* @__PURE__ */ jsx("span", { className: "orynn-switch-field__label", children: label }),
4422
+ description != null && /* @__PURE__ */ jsx("span", { className: "orynn-switch-field__description", children: description })
4423
+ ] })
799
4424
  ]
800
4425
  }
801
4426
  );
4427
+ });
4428
+ var Tabs = /* @__PURE__ */ forwardRef(function Tabs2({ className, variant = "pill", size = "md", fitted = false, ...props }, ref) {
4429
+ return /* @__PURE__ */ jsx(
4430
+ Tabs$1.Root,
4431
+ {
4432
+ ref,
4433
+ "data-slot": "tabs",
4434
+ "data-variant": variant,
4435
+ "data-size": size,
4436
+ "data-fitted": fitted || void 0,
4437
+ className: cx("orynn-tabs", className),
4438
+ ...props
4439
+ }
4440
+ );
4441
+ });
4442
+ var TabsList = /* @__PURE__ */ forwardRef(function TabsList2({ className, ...props }, ref) {
4443
+ return /* @__PURE__ */ jsx(
4444
+ Tabs$1.List,
4445
+ {
4446
+ ref,
4447
+ "data-slot": "tabs-list",
4448
+ className: cx("orynn-tabs__list", className),
4449
+ ...props
4450
+ }
4451
+ );
4452
+ });
4453
+ var TabsTrigger = /* @__PURE__ */ forwardRef(function TabsTrigger2({ className, ...props }, ref) {
4454
+ return /* @__PURE__ */ jsx(
4455
+ Tabs$1.Trigger,
4456
+ {
4457
+ ref,
4458
+ "data-slot": "tabs-trigger",
4459
+ className: cx("orynn-tabs__trigger", className),
4460
+ ...props
4461
+ }
4462
+ );
4463
+ });
4464
+ var TabsContent = /* @__PURE__ */ forwardRef(function TabsContent2({ className, ...props }, ref) {
4465
+ return /* @__PURE__ */ jsx(
4466
+ Tabs$1.Content,
4467
+ {
4468
+ ref,
4469
+ "data-slot": "tabs-content",
4470
+ className: cx("orynn-tabs__content", className),
4471
+ ...props
4472
+ }
4473
+ );
4474
+ });
4475
+ var Dialog = (props) => /* @__PURE__ */ jsx(Dialog$1.Root, { "data-slot": "dialog", ...props });
4476
+ var DialogTrigger = (props) => /* @__PURE__ */ jsx(Dialog$1.Trigger, { "data-slot": "dialog-trigger", ...props });
4477
+ var DialogClose = (props) => /* @__PURE__ */ jsx(Dialog$1.Close, { "data-slot": "dialog-close", ...props });
4478
+ var DialogPortal = Dialog$1.Portal;
4479
+ var DialogContent = /* @__PURE__ */ forwardRef(
4480
+ function DialogContent2({ className, children, showCloseButton = true, size = "lg", scrollable, container, ...props }, ref) {
4481
+ const themed = usePortalContainer();
4482
+ return /* @__PURE__ */ jsxs(Dialog$1.Portal, { container: container ?? themed ?? void 0, children: [
4483
+ /* @__PURE__ */ jsx(
4484
+ Dialog$1.Overlay,
4485
+ {
4486
+ "data-slot": "dialog-overlay",
4487
+ className: "orynn-overlay orynn-dialog__overlay"
4488
+ }
4489
+ ),
4490
+ /* @__PURE__ */ jsxs(
4491
+ Dialog$1.Content,
4492
+ {
4493
+ ref,
4494
+ "data-slot": "dialog-content",
4495
+ "data-size": size,
4496
+ "data-scrollable": scrollable || void 0,
4497
+ className: cx("orynn-dialog__content", className),
4498
+ ...props,
4499
+ children: [
4500
+ children,
4501
+ showCloseButton && /* @__PURE__ */ jsx(
4502
+ Dialog$1.Close,
4503
+ {
4504
+ "data-slot": "dialog-close",
4505
+ className: "orynn-dialog__close",
4506
+ "aria-label": "Close",
4507
+ children: /* @__PURE__ */ jsx(XIcon, {})
4508
+ }
4509
+ )
4510
+ ]
4511
+ }
4512
+ )
4513
+ ] });
4514
+ }
4515
+ );
4516
+ function DialogHeader({ className, ...props }) {
4517
+ return /* @__PURE__ */ jsx("div", { "data-slot": "dialog-header", className: cx("orynn-dialog__header", className), ...props });
4518
+ }
4519
+ function DialogFooter({ className, ...props }) {
4520
+ return /* @__PURE__ */ jsx("div", { "data-slot": "dialog-footer", className: cx("orynn-dialog__footer", className), ...props });
4521
+ }
4522
+ var DialogTitle = /* @__PURE__ */ forwardRef(function DialogTitle2({ className, ...props }, ref) {
4523
+ return /* @__PURE__ */ jsx(
4524
+ Dialog$1.Title,
4525
+ {
4526
+ ref,
4527
+ "data-slot": "dialog-title",
4528
+ className: cx("orynn-dialog__title", className),
4529
+ ...props
4530
+ }
4531
+ );
4532
+ });
4533
+ var DialogDescription = /* @__PURE__ */ forwardRef(function DialogDescription2({ className, ...props }, ref) {
4534
+ return /* @__PURE__ */ jsx(
4535
+ Dialog$1.Description,
4536
+ {
4537
+ ref,
4538
+ "data-slot": "dialog-description",
4539
+ className: cx("orynn-dialog__description", className),
4540
+ ...props
4541
+ }
4542
+ );
4543
+ });
4544
+ var Popover2 = (props) => /* @__PURE__ */ jsx(Popover$1.Root, { "data-slot": "popover", ...props });
4545
+ var PopoverTrigger = (props) => /* @__PURE__ */ jsx(Popover$1.Trigger, { "data-slot": "popover-trigger", ...props });
4546
+ var PopoverAnchor = (props) => /* @__PURE__ */ jsx(Popover$1.Anchor, { "data-slot": "popover-anchor", ...props });
4547
+ var PopoverClose = Popover$1.Close;
4548
+ var PopoverArrow = (props) => /* @__PURE__ */ jsx(Popover$1.Arrow, { "data-slot": "popover-arrow", className: "orynn-popover__arrow", ...props });
4549
+ var PopoverContent = /* @__PURE__ */ forwardRef(
4550
+ function PopoverContent2({ className, align = "center", sideOffset = 4, arrow = false, container, children, ...props }, ref) {
4551
+ const themed = usePortalContainer();
4552
+ return /* @__PURE__ */ jsx(Popover$1.Portal, { container: container ?? themed ?? void 0, children: /* @__PURE__ */ jsxs(
4553
+ Popover$1.Content,
4554
+ {
4555
+ ref,
4556
+ "data-slot": "popover-content",
4557
+ align,
4558
+ sideOffset,
4559
+ className: cx("orynn-content orynn-popover__content", className),
4560
+ ...props,
4561
+ children: [
4562
+ children,
4563
+ arrow && /* @__PURE__ */ jsx(PopoverArrow, {})
4564
+ ]
4565
+ }
4566
+ ) });
4567
+ }
4568
+ );
4569
+ function TooltipProvider({
4570
+ delayDuration = 0,
4571
+ ...props
4572
+ }) {
4573
+ return /* @__PURE__ */ jsx(
4574
+ Tooltip$1.Provider,
4575
+ {
4576
+ "data-slot": "tooltip-provider",
4577
+ delayDuration,
4578
+ ...props
4579
+ }
4580
+ );
802
4581
  }
4582
+ function Tooltip({
4583
+ delayDuration = 0,
4584
+ skipDelayDuration,
4585
+ disableHoverableContent,
4586
+ disableProvider = false,
4587
+ ...props
4588
+ }) {
4589
+ const root = /* @__PURE__ */ jsx(
4590
+ Tooltip$1.Root,
4591
+ {
4592
+ "data-slot": "tooltip",
4593
+ delayDuration,
4594
+ disableHoverableContent,
4595
+ ...props
4596
+ }
4597
+ );
4598
+ if (disableProvider) return root;
4599
+ return /* @__PURE__ */ jsx(
4600
+ TooltipProvider,
4601
+ {
4602
+ delayDuration,
4603
+ skipDelayDuration,
4604
+ disableHoverableContent,
4605
+ children: root
4606
+ }
4607
+ );
4608
+ }
4609
+ var TooltipTrigger = (props) => /* @__PURE__ */ jsx(Tooltip$1.Trigger, { "data-slot": "tooltip-trigger", ...props });
4610
+ var TooltipContent = /* @__PURE__ */ forwardRef(
4611
+ function TooltipContent2({ className, sideOffset = 0, arrow = true, arrowSize = 11, container, children, ...props }, ref) {
4612
+ const themed = usePortalContainer();
4613
+ return /* @__PURE__ */ jsx(Tooltip$1.Portal, { container: container ?? themed ?? void 0, children: /* @__PURE__ */ jsxs(
4614
+ Tooltip$1.Content,
4615
+ {
4616
+ ref,
4617
+ "data-slot": "tooltip-content",
4618
+ sideOffset,
4619
+ className: cx("orynn-content orynn-tooltip__content", className),
4620
+ ...props,
4621
+ children: [
4622
+ children,
4623
+ arrow && /* @__PURE__ */ jsx(
4624
+ Tooltip$1.Arrow,
4625
+ {
4626
+ width: arrowSize,
4627
+ height: Math.round(arrowSize / 2.2),
4628
+ className: "orynn-tooltip__arrow"
4629
+ }
4630
+ )
4631
+ ]
4632
+ }
4633
+ ) });
4634
+ }
4635
+ );
4636
+ var DropdownMenu = (props) => /* @__PURE__ */ jsx(DropdownMenu$1.Root, { "data-slot": "dropdown-menu", ...props });
4637
+ var DropdownMenuTrigger = (props) => /* @__PURE__ */ jsx(DropdownMenu$1.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
4638
+ var DropdownMenuGroup = DropdownMenu$1.Group;
4639
+ var DropdownMenuPortal = DropdownMenu$1.Portal;
4640
+ var DropdownMenuSub = DropdownMenu$1.Sub;
4641
+ var DropdownMenuRadioGroup = DropdownMenu$1.RadioGroup;
4642
+ var DropdownMenuContent = /* @__PURE__ */ forwardRef(function DropdownMenuContent2({ className, sideOffset = 4, container, ...props }, ref) {
4643
+ const themed = usePortalContainer();
4644
+ return /* @__PURE__ */ jsx(DropdownMenu$1.Portal, { container: container ?? themed ?? void 0, children: /* @__PURE__ */ jsx(
4645
+ DropdownMenu$1.Content,
4646
+ {
4647
+ ref,
4648
+ "data-slot": "dropdown-menu-content",
4649
+ sideOffset,
4650
+ className: cx("orynn-content orynn-menu__content", className),
4651
+ ...props
4652
+ }
4653
+ ) });
4654
+ });
4655
+ var DropdownMenuItem = /* @__PURE__ */ forwardRef(
4656
+ function DropdownMenuItem2({ className, inset, variant = "default", icon, shortcut, children, ...props }, ref) {
4657
+ return /* @__PURE__ */ jsxs(
4658
+ DropdownMenu$1.Item,
4659
+ {
4660
+ ref,
4661
+ "data-slot": "dropdown-menu-item",
4662
+ "data-inset": inset || void 0,
4663
+ "data-variant": variant,
4664
+ className: cx("orynn-menu__item", className),
4665
+ ...props,
4666
+ children: [
4667
+ icon,
4668
+ children,
4669
+ shortcut != null && /* @__PURE__ */ jsx("span", { className: "orynn-menu__shortcut", children: shortcut })
4670
+ ]
4671
+ }
4672
+ );
4673
+ }
4674
+ );
4675
+ var DropdownMenuCheckboxItem = /* @__PURE__ */ forwardRef(function DropdownMenuCheckboxItem2({ className, children, checked, ...props }, ref) {
4676
+ return /* @__PURE__ */ jsxs(
4677
+ DropdownMenu$1.CheckboxItem,
4678
+ {
4679
+ ref,
4680
+ "data-slot": "dropdown-menu-checkbox-item",
4681
+ className: cx("orynn-menu__item", "orynn-menu__item--check", className),
4682
+ checked,
4683
+ ...props,
4684
+ children: [
4685
+ /* @__PURE__ */ jsx("span", { className: "orynn-menu__indicator", children: /* @__PURE__ */ jsx(DropdownMenu$1.ItemIndicator, { children: /* @__PURE__ */ jsx(CheckIcon, {}) }) }),
4686
+ children
4687
+ ]
4688
+ }
4689
+ );
4690
+ });
4691
+ var DropdownMenuRadioItem = /* @__PURE__ */ forwardRef(function DropdownMenuRadioItem2({ className, children, ...props }, ref) {
4692
+ return /* @__PURE__ */ jsxs(
4693
+ DropdownMenu$1.RadioItem,
4694
+ {
4695
+ ref,
4696
+ "data-slot": "dropdown-menu-radio-item",
4697
+ className: cx("orynn-menu__item", "orynn-menu__item--check", className),
4698
+ ...props,
4699
+ children: [
4700
+ /* @__PURE__ */ jsx("span", { className: "orynn-menu__indicator", children: /* @__PURE__ */ jsx(DropdownMenu$1.ItemIndicator, { children: /* @__PURE__ */ jsx(CircleIcon, { className: "orynn-menu__dot" }) }) }),
4701
+ children
4702
+ ]
4703
+ }
4704
+ );
4705
+ });
4706
+ var DropdownMenuLabel = /* @__PURE__ */ forwardRef(
4707
+ function DropdownMenuLabel2({ className, inset, ...props }, ref) {
4708
+ return /* @__PURE__ */ jsx(
4709
+ DropdownMenu$1.Label,
4710
+ {
4711
+ ref,
4712
+ "data-slot": "dropdown-menu-label",
4713
+ "data-inset": inset || void 0,
4714
+ className: cx("orynn-menu__label", className),
4715
+ ...props
4716
+ }
4717
+ );
4718
+ }
4719
+ );
4720
+ var DropdownMenuSeparator = /* @__PURE__ */ forwardRef(function DropdownMenuSeparator2({ className, ...props }, ref) {
4721
+ return /* @__PURE__ */ jsx(
4722
+ DropdownMenu$1.Separator,
4723
+ {
4724
+ ref,
4725
+ "data-slot": "dropdown-menu-separator",
4726
+ className: cx("orynn-menu__separator", className),
4727
+ ...props
4728
+ }
4729
+ );
4730
+ });
4731
+ function DropdownMenuShortcut({ className, ...props }) {
4732
+ return /* @__PURE__ */ jsx(
4733
+ "span",
4734
+ {
4735
+ "data-slot": "dropdown-menu-shortcut",
4736
+ className: cx("orynn-menu__shortcut", className),
4737
+ ...props
4738
+ }
4739
+ );
4740
+ }
4741
+ var DropdownMenuSubTrigger = /* @__PURE__ */ forwardRef(function DropdownMenuSubTrigger2({ className, inset, children, ...props }, ref) {
4742
+ return /* @__PURE__ */ jsxs(
4743
+ DropdownMenu$1.SubTrigger,
4744
+ {
4745
+ ref,
4746
+ "data-slot": "dropdown-menu-sub-trigger",
4747
+ "data-inset": inset || void 0,
4748
+ className: cx("orynn-menu__item", "orynn-menu__sub-trigger", className),
4749
+ ...props,
4750
+ children: [
4751
+ children,
4752
+ /* @__PURE__ */ jsx(ChevronRightIcon, { className: "orynn-menu__sub-chevron" })
4753
+ ]
4754
+ }
4755
+ );
4756
+ });
4757
+ var DropdownMenuSubContent = /* @__PURE__ */ forwardRef(function DropdownMenuSubContent2({ className, ...props }, ref) {
4758
+ return /* @__PURE__ */ jsx(
4759
+ DropdownMenu$1.SubContent,
4760
+ {
4761
+ ref,
4762
+ "data-slot": "dropdown-menu-sub-content",
4763
+ className: cx("orynn-content", "orynn-menu__content", "orynn-menu__sub-content", className),
4764
+ ...props
4765
+ }
4766
+ );
4767
+ });
803
4768
 
804
4769
  // src/types/validation.ts
805
4770
  var FORM_ERROR_KEY = "$form";
806
4771
 
807
- export { Dropdown, FORM_ERROR_KEY, Field, Fieldset, Input, createRegistry, createRuleResolver, defaultRegistry, defaultResolver, normalizeConfig, registerField, registerRule, useFieldsetState };
4772
+ // src/core/validation/standard-schema.ts
4773
+ function pathToField(path) {
4774
+ if (!path || path.length === 0) return { field: FORM_ERROR_KEY, rest: "" };
4775
+ const seg = (p) => String(typeof p === "object" && p !== null && "key" in p ? p.key : p);
4776
+ const parts = path.map(seg);
4777
+ return { field: parts[0] ?? FORM_ERROR_KEY, rest: parts.slice(1).join(".") };
4778
+ }
4779
+ function standardSchemaResolver(schema) {
4780
+ return (values) => {
4781
+ const out = schema["~standard"].validate(values);
4782
+ const toResult = (r) => {
4783
+ const result = {};
4784
+ if (!("issues" in r) || !r.issues) return result;
4785
+ for (const issue of r.issues) {
4786
+ const { field, rest } = pathToField(issue.path);
4787
+ const bucket = result[field] ?? [];
4788
+ bucket.push({ rule: "schema", message: issue.message, ...rest ? { path: rest } : {} });
4789
+ result[field] = bucket;
4790
+ }
4791
+ return result;
4792
+ };
4793
+ return out instanceof Promise ? out.then(toResult) : toResult(out);
4794
+ };
4795
+ }
4796
+
4797
+ export { Alert, AlertDescription, AlertTitle, Badge, Button, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, CheckboxGroup, DatePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogPortal, DialogTitle, DialogTrigger, Dropdown, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, FORM_ERROR_KEY, Field, FieldBox, Fieldset, FieldsetView, Form, Input, Label, NumberField, OrynnProvider, Popover2 as Popover, PopoverAnchor, PopoverArrow, PopoverClose, PopoverContent, PopoverTrigger, Radio, RadioGroup, Dropdown as Select, Separator, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, badgeClasses, builtInRules, buttonClasses, createRegistry, createRuleResolver, defaultRegistry, defaultResolver, normalizeConfig, registerField, registerRule, resolveThemeVars, standardSchemaResolver, useFieldsetState, useOrynnTheme, usePortalContainer };
808
4798
  //# sourceMappingURL=index.js.map
809
4799
  //# sourceMappingURL=index.js.map