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