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.d.cts CHANGED
@@ -1,24 +1,288 @@
1
1
  import * as react from 'react';
2
- import { ComponentType, SyntheticEvent, SelectHTMLAttributes, ReactNode, ChangeEvent, InputHTMLAttributes, FormEvent } from 'react';
2
+ import { ReactNode, HTMLAttributes, InputHTMLAttributes, ChangeEvent, ComponentType, SyntheticEvent, TextareaHTMLAttributes, FormEvent, FormHTMLAttributes, ComponentProps, ComponentPropsWithoutRef, MouseEvent, CSSProperties } from 'react';
3
+ import { Label as Label$1, Separator as Separator$1, Switch as Switch$1, Tabs as Tabs$1, Dialog as Dialog$1, Popover as Popover$1, Tooltip as Tooltip$1, DropdownMenu as DropdownMenu$1 } from 'radix-ui';
3
4
 
5
+ type ControlSize = "sm" | "md" | "lg";
6
+ type ControlVariant = "outline" | "filled" | "flushed" | "unstyled";
7
+ type ControlRadius = "none" | "sm" | "md" | "lg" | "pill";
8
+ interface FieldBoxOwnProps {
9
+ size?: ControlSize;
10
+ variant?: ControlVariant;
11
+ radius?: ControlRadius;
12
+ disabled?: boolean;
13
+ invalid?: boolean;
14
+ /** Success / valid visual state. */
15
+ valid?: boolean;
16
+ /** Controlled focus ring. Omit to auto-track via focus-within. */
17
+ focused?: boolean;
18
+ /** Whether the floating label is raised (usually focused || has value). */
19
+ active?: boolean;
20
+ /** Rotates a chevron marked `.orynn-select__chevron`. */
21
+ open?: boolean;
22
+ /** Floating label node (usually a `<label class="orynn-box__label">`). */
23
+ floatingLabel?: ReactNode;
24
+ left?: ReactNode;
25
+ right?: ReactNode;
26
+ /** Segment glued to the start, *outside* the border (e.g. `https://`). */
27
+ addonBefore?: ReactNode;
28
+ /** Segment glued to the end, *outside* the border (e.g. `.com`). */
29
+ addonAfter?: ReactNode;
30
+ /** Adds `.orynn-box--textarea` sizing. */
31
+ textarea?: boolean;
32
+ }
33
+ interface FieldBoxProps extends FieldBoxOwnProps, Omit<HTMLAttributes<HTMLDivElement>, "children"> {
34
+ children: ReactNode;
35
+ }
36
+ declare const FieldBox: react.ForwardRefExoticComponent<FieldBoxProps & react.RefAttributes<HTMLDivElement>>;
37
+
38
+ /** One message, several messages, or nothing. */
39
+ type Feedback = string | string[] | undefined;
40
+ /**
41
+ * Props shared by every labelled control (Input, Textarea, NumberField,
42
+ * Dropdown, DatePicker, …). Individual controls add their own on top.
43
+ */
44
+ interface BaseControlProps {
45
+ label?: ReactNode;
46
+ /** Help text under the label. */
47
+ description?: ReactNode;
48
+ /** Error message(s). Presence puts the control in its invalid state. */
49
+ error?: Feedback;
50
+ /** Success state — `true`, or a confirmation message to show. */
51
+ success?: string | boolean;
52
+ required?: boolean;
53
+ disabled?: boolean;
54
+ readOnly?: boolean;
55
+ size?: ControlSize;
56
+ variant?: ControlVariant;
57
+ radius?: ControlRadius;
58
+ /** Render the label floating inside the control border. */
59
+ floatingLabel?: boolean;
60
+ /** Content before the field (icon, text). */
61
+ startContent?: ReactNode;
62
+ /** Content after the field (icon, text). */
63
+ endContent?: ReactNode;
64
+ /** Show an ✕ button to clear the value. */
65
+ clearable?: boolean;
66
+ onClear?: () => void;
67
+ /** Show a spinner in the end slot. */
68
+ loading?: boolean;
69
+ id?: string;
70
+ name?: string;
71
+ className?: string;
72
+ }
73
+
74
+ type NativeCheckbox = Omit<InputHTMLAttributes<HTMLInputElement>, "type" | "checked" | "defaultChecked" | "onChange" | "size" | "value">;
75
+ interface CheckboxProps extends NativeCheckbox {
76
+ label?: ReactNode;
77
+ description?: ReactNode;
78
+ checked?: boolean;
79
+ defaultChecked?: boolean;
80
+ indeterminate?: boolean;
81
+ onChange?: (checked: boolean, event: ChangeEvent<HTMLInputElement>) => void;
82
+ /** Value used when inside a `<CheckboxGroup>`. */
83
+ value?: string;
84
+ disabled?: boolean;
85
+ readOnly?: boolean;
86
+ required?: boolean;
87
+ invalid?: boolean;
88
+ size?: ControlSize;
89
+ /** `"filled"` (default) paints the box on check; `"outline"` keeps it hollow. */
90
+ variant?: "filled" | "outline";
91
+ /** Put the label before the box. */
92
+ labelPlacement?: "end" | "start";
93
+ /** Bordered selectable card. */
94
+ card?: boolean;
95
+ /** Custom checked / indeterminate glyphs. */
96
+ icon?: ReactNode;
97
+ indeterminateIcon?: ReactNode;
98
+ className?: string;
99
+ }
100
+ declare const Checkbox: react.ForwardRefExoticComponent<CheckboxProps & react.RefAttributes<HTMLInputElement>>;
101
+
102
+ interface CheckboxOption {
103
+ label: ReactNode;
104
+ value: string;
105
+ description?: ReactNode;
106
+ /** Leading icon shown before the label. */
107
+ icon?: ReactNode;
108
+ disabled?: boolean;
109
+ }
110
+ interface CheckboxGroupProps {
111
+ label?: ReactNode;
112
+ description?: ReactNode;
113
+ error?: Feedback;
114
+ success?: string | boolean;
115
+ required?: boolean;
116
+ disabled?: boolean;
117
+ name?: string;
118
+ size?: ControlSize;
119
+ value?: string[];
120
+ defaultValue?: string[];
121
+ onChange?: (value: string[]) => void;
122
+ orientation?: "vertical" | "horizontal";
123
+ /** Lay the options out in an N-column grid. */
124
+ columns?: number;
125
+ /** Minimum selections (blocks unchecking below it). */
126
+ min?: number;
127
+ /** Maximum selections (blocks checking above it). */
128
+ max?: number;
129
+ /** Show a "select all" checkbox above the options. */
130
+ showSelectAll?: boolean;
131
+ selectAllLabel?: ReactNode;
132
+ /** Convenience: render items from data instead of children. */
133
+ options?: CheckboxOption[];
134
+ children?: ReactNode;
135
+ className?: string;
136
+ id?: string;
137
+ }
138
+ declare function CheckboxGroup(props: CheckboxGroupProps): react.JSX.Element;
139
+
140
+ /** A `{ start, end }` selection. Either side may be `null` while picking. */
141
+ interface DateRange {
142
+ start: Date | null;
143
+ end: Date | null;
144
+ }
145
+
146
+ type CalendarView = "day" | "month" | "year";
147
+ type CalendarPrecision = "day" | "month" | "year";
148
+
149
+ /** `{ start, end }` selection returned by `onChange` in `mode="range"`. */
150
+ type DatePickerRange = DateRange;
151
+ type LooseDate = Date | string | null;
152
+ type LooseRange = {
153
+ start?: LooseDate;
154
+ end?: LooseDate;
155
+ } | null;
156
+ /** A one-click shortcut in the picker's side rail (Today, Last 7 days, …). */
157
+ interface DatePickerPreset {
158
+ label: string;
159
+ /** Static value, in the same shape as the picker's `mode`. */
160
+ value?: Date | DatePickerRange | Date[];
161
+ /** Computed on click — wins over `value`. */
162
+ getValue?: () => Date | DatePickerRange | Date[];
163
+ }
164
+ /** Props shared by every `mode`. */
165
+ interface DatePickerCommonProps extends Omit<BaseControlProps, "startContent" | "endContent" | "loading"> {
166
+ /**
167
+ * Display / parse pattern (`yyyy MM dd M d MMM MMMM HH mm a`) or an
168
+ * `Intl.DateTimeFormatOptions` object. Default `"yyyy-MM-dd"`.
169
+ */
170
+ format?: string | Intl.DateTimeFormatOptions;
171
+ minDate?: Date;
172
+ maxDate?: Date;
173
+ disabledDates?: Date[] | ((date: Date) => boolean);
174
+ /** Predicate form of `disabledDates` (react-aria naming). */
175
+ isDateUnavailable?: (date: Date) => boolean;
176
+ firstDayOfWeek?: number;
177
+ locale?: string;
178
+ showWeekNumbers?: boolean;
179
+ showToday?: boolean;
180
+ showClear?: boolean;
181
+ /** Starting inner view of the calendar. Defaults to `precision`. */
182
+ defaultView?: CalendarView;
183
+ /**
184
+ * How far the picker drills: `"day"` (default), `"month"` (select a whole
185
+ * month), or `"year"`.
186
+ */
187
+ precision?: CalendarPrecision;
188
+ /** Always render six week rows. Default true. */
189
+ fixedWeeks?: boolean;
190
+ /** Side-by-side month panels. Default 1. */
191
+ numberOfMonths?: number;
192
+ /** Show an hour / minute picker beside the calendar (`single` mode). */
193
+ showTime?: boolean;
194
+ /** Minute granularity for the time picker. Default 5. */
195
+ timeStep?: number;
196
+ /** Month to show first when there's no value yet. */
197
+ defaultMonth?: Date;
198
+ /** One-click shortcuts rendered in a side rail. */
199
+ presets?: DatePickerPreset[];
200
+ /** Render the calendar always, without a text field. */
201
+ inline?: boolean;
202
+ /** Allow typing a date into the field (`single` mode only). Default true. */
203
+ allowInput?: boolean;
204
+ closeOnSelect?: boolean;
205
+ /** Controlled open state of the popover. */
206
+ open?: boolean;
207
+ defaultOpen?: boolean;
208
+ onOpenChange?: (open: boolean) => void;
209
+ placeholder?: string;
210
+ }
211
+ interface DatePickerSingleProps extends DatePickerCommonProps {
212
+ mode?: "single";
213
+ value?: Date | string | null;
214
+ defaultValue?: Date | string | null;
215
+ onChange?: (value: Date | null) => void;
216
+ }
217
+ interface DatePickerRangeProps extends DatePickerCommonProps {
218
+ mode: "range";
219
+ value?: LooseRange;
220
+ defaultValue?: LooseRange;
221
+ onChange?: (value: DatePickerRange) => void;
222
+ }
223
+ interface DatePickerMultipleProps extends DatePickerCommonProps {
224
+ mode: "multiple";
225
+ value?: Array<Date | string> | null;
226
+ defaultValue?: Array<Date | string> | null;
227
+ onChange?: (value: Date[]) => void;
228
+ }
229
+ type DatePickerProps = DatePickerSingleProps | DatePickerRangeProps | DatePickerMultipleProps;
230
+ declare const DatePicker: react.ForwardRefExoticComponent<DatePickerProps & react.RefAttributes<HTMLInputElement>>;
231
+
232
+ /** `pattern` accepts a RegExp, a source string, or `{ value, flags }`. */
233
+ type PatternRule = RegExp | string | {
234
+ value: string | RegExp;
235
+ flags?: string;
236
+ };
237
+ /** `equals` accepts a literal, or `{ field }` to compare against another field. */
238
+ type EqualsRule = unknown | {
239
+ field: string;
240
+ };
241
+ /** Custom per-field validator. String = message, `false` = generic failure. */
242
+ type CustomValidator = (value: unknown, allValues: Record<string, unknown>) => string | boolean | null | Promise<string | boolean | null>;
4
243
  /**
5
- * Per-field validation config. V1 ships `required` / `minLength` / `maxLength`.
6
- * Future rule keys (regex, email, min, max, validate, ...) are added here without
7
- * a breaking change.
244
+ * Per-field validation config. All keys are optional and additive.
245
+ * Custom rules registered with `registerRule` add their own keys here via
246
+ * module augmentation, or are accepted loosely.
8
247
  */
9
248
  interface FieldValidation {
10
249
  required?: boolean;
250
+ /** String / array length. */
11
251
  minLength?: number;
12
252
  maxLength?: number;
253
+ /** Array item count (checkbox groups, multi-selects). */
254
+ minItems?: number;
255
+ maxItems?: number;
256
+ /** Numeric bounds (value coerced to number). */
257
+ min?: number;
258
+ max?: number;
259
+ integer?: boolean;
260
+ /** Date bounds (value + param coerced to a timestamp). */
261
+ minDate?: string | Date;
262
+ maxDate?: string | Date;
263
+ /** Range-mode day-span bounds (inclusive; a single day counts as 1). */
264
+ minRangeDays?: number;
265
+ maxRangeDays?: number;
266
+ email?: boolean;
267
+ url?: boolean;
268
+ pattern?: PatternRule;
269
+ /** Value must be one of these. */
270
+ oneOf?: unknown[];
271
+ /** Equal to a literal, or to another field's value: `{ field: "password" }`. */
272
+ equals?: EqualsRule;
273
+ /** Custom validator — sync or async. */
274
+ validate?: CustomValidator;
13
275
  /** Per-rule message overrides, e.g. `{ required: "Name is required" }`. */
14
276
  messages?: Partial<Record<string, string>>;
277
+ /** Allow custom `registerRule` keys without a type error. */
278
+ [rule: string]: unknown;
15
279
  }
16
280
  /** A single validation failure. Shape is frozen — new fields must stay optional. */
17
281
  interface FieldError {
18
- /** Rule that failed: `"required"`, `"minLength"`, `"custom"`, `"async"`, ... */
282
+ /** Rule that failed: `"required"`, `"minLength"`, `"pattern"`, `"validate"`, `"schema"`, ... */
19
283
  rule: string;
20
284
  message: string;
21
- /** Reserved for cross-field / nested errors. Unused in V1. */
285
+ /** Dotted path for cross-field / nested errors. */
22
286
  path?: string;
23
287
  }
24
288
  /**
@@ -36,23 +300,29 @@ interface ValidationContext {
36
300
  trigger: ValidationTrigger;
37
301
  }
38
302
  /**
39
- * The single seam through which all validation flows. V1's default resolver is
40
- * rule-based and synchronous; the `Promise` return type keeps async, schema, and
41
- * cross-field validation additive.
303
+ * The single seam through which all validation flows. The default resolver is
304
+ * rule-based; the `Promise` return keeps async, schema, and cross-field
305
+ * validation additive.
42
306
  */
43
307
  type ValidationResolver = (values: Record<string, unknown>, config: FieldsetConfig, context: ValidationContext) => ValidationResult | Promise<ValidationResult>;
44
308
  /**
45
309
  * A single rule implementation. Returns an error message string on failure, or
46
- * `null` on success. `allValues` is passed so cross-field rules need no
47
- * signature change later.
310
+ * `null` on success — synchronously or as a Promise. `allValues` is passed so
311
+ * cross-field rules need no signature change.
48
312
  */
49
- type RuleFn = (value: unknown, param: unknown, allValues: Record<string, unknown>) => string | null;
313
+ type RuleFn = (value: unknown, param: unknown, allValues: Record<string, unknown>) => string | null | Promise<string | null>;
50
314
 
51
- /** A single selectable option in a {@link DropdownFieldConfig}. */
315
+ /** A single selectable option for `Dropdown` / a {@link DropdownFieldConfig}. */
52
316
  interface DropdownOption {
53
317
  label: string;
54
318
  value: string;
55
319
  disabled?: boolean;
320
+ /** Secondary line under the label. */
321
+ description?: ReactNode;
322
+ /** Leading icon / flag. */
323
+ icon?: ReactNode;
324
+ /** Group heading this option is listed under. */
325
+ group?: string;
56
326
  }
57
327
  /** Number of columns at each responsive breakpoint. */
58
328
  interface ColumnSpec {
@@ -60,6 +330,18 @@ interface ColumnSpec {
60
330
  tablet: number;
61
331
  mobile: number;
62
332
  }
333
+ /**
334
+ * Show / validate a field only when a condition holds. An object targets one
335
+ * other field; a function gets all values.
336
+ */
337
+ type FieldCondition = {
338
+ field: string;
339
+ eq?: unknown;
340
+ ne?: unknown;
341
+ in?: unknown[];
342
+ notIn?: unknown[];
343
+ truthy?: boolean;
344
+ } | ((values: Record<string, unknown>) => boolean);
63
345
  /** Fields common to every field type. */
64
346
  interface BaseFieldConfig {
65
347
  /** Unique key within the fieldset; also the key in the values object. */
@@ -71,20 +353,143 @@ interface BaseFieldConfig {
71
353
  readOnly?: boolean;
72
354
  defaultValue?: unknown;
73
355
  validation?: FieldValidation;
356
+ /** Render + validate this field only when the condition holds. */
357
+ when?: FieldCondition;
74
358
  /** Field-level column span, overriding the fieldset's `columns`. */
75
359
  layout?: Partial<ColumnSpec>;
360
+ /** `sm` / `md` / `lg`. */
361
+ size?: "sm" | "md" | "lg";
362
+ /** `outline` / `filled` / `flushed` / `unstyled`. */
363
+ variant?: "outline" | "filled" | "flushed" | "unstyled";
364
+ /** Float the label into the control border. */
365
+ floatingLabel?: boolean;
76
366
  /** Escape hatch: spread verbatim onto the underlying control. */
77
367
  props?: Record<string, unknown>;
78
368
  }
79
- /** Native `<input>` field. `inputType` maps to the DOM `type` attribute. */
369
+ /** Single-line text field. */
80
370
  interface InputFieldConfig extends BaseFieldConfig {
81
371
  type: "input";
82
- inputType?: "text" | "email" | "password" | "number" | "tel" | "url";
372
+ inputType?: "text" | "email" | "password" | "search" | "tel" | "url";
373
+ prefix?: string;
374
+ suffix?: string;
375
+ /** Segments attached outside the border. */
376
+ addonBefore?: string;
377
+ addonAfter?: string;
378
+ clearable?: boolean;
379
+ maxLength?: number;
380
+ /** Live character counter. */
381
+ showCount?: boolean;
382
+ /** Debounce `onChange` by N ms. */
383
+ debounce?: number;
384
+ /** Virtual-keyboard hint. */
385
+ inputMode?: "text" | "numeric" | "decimal" | "tel" | "email" | "url" | "search";
386
+ /** HTML `pattern` for native validation. */
387
+ pattern?: string;
83
388
  }
84
- /** Native `<select>` field. */
389
+ /** Multi-line text field. */
390
+ interface TextareaFieldConfig extends BaseFieldConfig {
391
+ type: "textarea";
392
+ rows?: number;
393
+ maxRows?: number;
394
+ autoResize?: boolean;
395
+ resize?: "none" | "vertical" | "both";
396
+ maxLength?: number;
397
+ showCount?: boolean;
398
+ /** Enter (no Shift) submits and suppresses the newline. */
399
+ submitOnEnter?: boolean;
400
+ }
401
+ /** Numeric field with steppers + Intl formatting. Value is `number | null`. */
402
+ interface NumberFieldConfig extends BaseFieldConfig {
403
+ type: "number";
404
+ min?: number;
405
+ max?: number;
406
+ step?: number;
407
+ precision?: number;
408
+ /** Alias for `precision`. */
409
+ decimalScale?: number;
410
+ currency?: string;
411
+ /** `decimal` | `currency` | `percent` | `unit`. */
412
+ style?: "decimal" | "currency" | "percent" | "unit";
413
+ locale?: string;
414
+ prefix?: string;
415
+ suffix?: string;
416
+ /** Override the locale thousands separator. */
417
+ thousandSeparator?: string;
418
+ /** Allow values below zero. Default true. */
419
+ allowNegative?: boolean;
420
+ /** `strict` | `blur` | `none`. */
421
+ clampBehavior?: "strict" | "blur" | "none";
422
+ /** Hide the stepper buttons. */
423
+ hideControls?: boolean;
424
+ }
425
+ /** Combobox (searchable listbox). */
85
426
  interface DropdownFieldConfig extends BaseFieldConfig {
86
427
  type: "dropdown";
87
428
  options: DropdownOption[];
429
+ searchable?: boolean;
430
+ multiple?: boolean;
431
+ clearable?: boolean;
432
+ /** Allow inventing an option from the query (needs `searchable`). */
433
+ creatable?: boolean;
434
+ /** Multiple: cap how many options can be chosen. */
435
+ maxValues?: number;
436
+ /** Multiple: hide options already selected. */
437
+ hidePickedOptions?: boolean;
438
+ /** Multiple: show a Select all / Clear row. */
439
+ showSelectAll?: boolean;
440
+ /** Debounce, in ms, before the field's search would hit a server. */
441
+ searchDebounce?: number;
442
+ }
443
+ /**
444
+ * Calendar date field. Value is an ISO date string (`yyyy-MM-dd`) for `single`,
445
+ * `{ start, end }` ISO strings for `range`, or `string[]` for `multiple`.
446
+ */
447
+ interface DateFieldConfig extends BaseFieldConfig {
448
+ type: "date";
449
+ format?: string;
450
+ /** Selection model. Default `"single"`. */
451
+ mode?: "single" | "range" | "multiple";
452
+ /** Drill depth: `"day"` (default), `"month"`, or `"year"`. */
453
+ precision?: "day" | "month" | "year";
454
+ minDate?: string | Date;
455
+ maxDate?: string | Date;
456
+ showToday?: boolean;
457
+ clearable?: boolean;
458
+ /** Side-rail shortcuts. `value` matches `mode` (ISO strings). */
459
+ presets?: Array<{
460
+ label: string;
461
+ value: string | {
462
+ start: string;
463
+ end: string;
464
+ } | string[];
465
+ }>;
466
+ }
467
+ /** A single boolean checkbox. Value is `boolean`. */
468
+ interface CheckboxFieldConfig extends BaseFieldConfig {
469
+ type: "checkbox";
470
+ /** Text shown next to the box (falls back to `label`). */
471
+ checkboxLabel?: string;
472
+ }
473
+ /** A set of checkboxes. Value is `string[]`. */
474
+ interface CheckboxGroupFieldConfig extends BaseFieldConfig {
475
+ type: "checkbox-group";
476
+ options: DropdownOption[];
477
+ orientation?: "vertical" | "horizontal";
478
+ /** Lay the options out in an N-column grid. */
479
+ columns?: number;
480
+ /** Show a "select all" checkbox. */
481
+ showSelectAll?: boolean;
482
+ min?: number;
483
+ max?: number;
484
+ }
485
+ /** A radio group. Value is `string`. */
486
+ interface RadioFieldConfig extends BaseFieldConfig {
487
+ type: "radio";
488
+ options: DropdownOption[];
489
+ orientation?: "vertical" | "horizontal";
490
+ /** Lay the options out in an N-column grid. */
491
+ columns?: number;
492
+ radioVariant?: "default" | "card";
88
493
  }
89
494
  /**
90
495
  * Maps a field `type` string to its config shape. Consumers register custom
@@ -100,7 +505,13 @@ interface DropdownFieldConfig extends BaseFieldConfig {
100
505
  */
101
506
  interface FieldConfigRegistry {
102
507
  input: InputFieldConfig;
508
+ textarea: TextareaFieldConfig;
509
+ number: NumberFieldConfig;
103
510
  dropdown: DropdownFieldConfig;
511
+ date: DateFieldConfig;
512
+ checkbox: CheckboxFieldConfig;
513
+ "checkbox-group": CheckboxGroupFieldConfig;
514
+ radio: RadioFieldConfig;
104
515
  }
105
516
  /** Discriminated union of every registered field config. */
106
517
  type FieldConfig = FieldConfigRegistry[keyof FieldConfigRegistry];
@@ -111,13 +522,85 @@ interface FieldsetConfig {
111
522
  fields: FieldConfig[];
112
523
  /** Rendered in a `<legend>` when present. */
113
524
  legend?: string;
114
- /** Columns per breakpoint. Defaults to `{ desktop: 3, tablet: 2, mobile: 1 }`. */
115
- columns?: Partial<ColumnSpec>;
525
+ /**
526
+ * Column layout. A **number** means "use up to N columns, fluidly, down to
527
+ * one when narrow". An **object** snaps to exact counts at wide / medium /
528
+ * narrow container widths. Defaults to `{ desktop: 3, tablet: 2, mobile: 1 }`.
529
+ */
530
+ columns?: Partial<ColumnSpec> | number;
531
+ /**
532
+ * Minimum comfortable width for a single column (number = px, or a CSS length
533
+ * like `"14rem"`). Drives when the grid adds/removes columns. Default `192`.
534
+ */
535
+ minColumnWidth?: string | number;
116
536
  /** Grid gap; a number is treated as pixels. */
117
537
  gap?: string | number;
118
538
  id?: string;
119
539
  }
120
540
 
541
+ /** Options may also be passed pre-grouped. */
542
+ interface DropdownOptionGroup {
543
+ group: string;
544
+ items: DropdownOption[];
545
+ }
546
+ interface OptionState {
547
+ selected: boolean;
548
+ active: boolean;
549
+ disabled: boolean;
550
+ /** Query the option matched, for highlighting. */
551
+ query: string;
552
+ }
553
+ interface DropdownProps extends Omit<BaseControlProps, "startContent" | "endContent"> {
554
+ options: DropdownOption[] | DropdownOptionGroup[];
555
+ value?: string | string[] | null;
556
+ defaultValue?: string | string[] | null;
557
+ onChange?: (value: string | string[] | null) => void;
558
+ multiple?: boolean;
559
+ /** Type in the control to filter options. */
560
+ searchable?: boolean;
561
+ filterMode?: "contains" | "startsWith";
562
+ filterFn?: (option: DropdownOption, query: string) => boolean;
563
+ /** Bold the matched substring in option labels. Default true when searchable. */
564
+ highlightMatch?: boolean;
565
+ renderOption?: (option: DropdownOption, state: OptionState) => ReactNode;
566
+ renderValue?: (selected: DropdownOption[]) => ReactNode;
567
+ renderGroupLabel?: (label: string) => ReactNode;
568
+ placeholder?: string;
569
+ emptyMessage?: ReactNode;
570
+ /** Shown in place of `emptyMessage` while `loading` and there are no options. */
571
+ loadingMessage?: ReactNode;
572
+ /** Close the panel after a pick. Default true for single, false for multiple. */
573
+ closeOnSelect?: boolean;
574
+ /** Cap the chips shown before "+N". */
575
+ maxSelectedLabels?: number;
576
+ /** Multiple: cap how many options can be selected. */
577
+ maxValues?: number;
578
+ /** Multiple: drop already-selected options from the list. */
579
+ hidePickedOptions?: boolean;
580
+ /** Multiple: show a "Select all / Clear" action row. */
581
+ showSelectAll?: boolean;
582
+ /** Fall back to a native `<select>` (single, no search). */
583
+ native?: boolean;
584
+ startContent?: ReactNode;
585
+ /** Allow creating an option from the current query (needs `searchable`). */
586
+ creatable?: boolean;
587
+ onCreate?: (inputValue: string) => void;
588
+ /** Gate the create row. Default: non-empty query with no exact label match. */
589
+ isValidNewOption?: (inputValue: string, options: DropdownOption[]) => boolean;
590
+ formatCreateLabel?: (inputValue: string) => ReactNode;
591
+ createPosition?: "first" | "last";
592
+ /** Fires (debounced) as the query changes; disables local filtering. */
593
+ onSearch?: (query: string) => void;
594
+ searchDebounce?: number;
595
+ /** Controlled panel open state. */
596
+ open?: boolean;
597
+ defaultOpen?: boolean;
598
+ onOpenChange?: (open: boolean) => void;
599
+ /** Cap the listbox height, px. */
600
+ maxHeight?: number;
601
+ }
602
+ declare const Dropdown: react.ForwardRefExoticComponent<DropdownProps & react.RefAttributes<HTMLInputElement>>;
603
+
121
604
  /**
122
605
  * The contract every control receives from `Fieldset`. This is the stability
123
606
  * boundary between the orchestrator and the controls: as long as this holds,
@@ -139,12 +622,25 @@ interface ControlProps<TValue = unknown> {
139
622
  describedById?: string;
140
623
  /** The full field config, for type-specific data (e.g. dropdown `options`). */
141
624
  config: FieldConfig;
625
+ /**
626
+ * Only set for `selfContained` registrations (the component renders its own
627
+ * `<Field>`): the field's label / description, and the current error messages.
628
+ */
629
+ label?: string;
630
+ description?: string;
631
+ errors?: string[];
142
632
  }
143
633
  /** A React component that satisfies {@link ControlProps}. */
144
634
  type ControlComponent<TValue = any> = ComponentType<ControlProps<TValue>>;
145
635
  /** A registry entry for one field `type`. */
146
636
  interface FieldRegistration<TValue = any> {
147
637
  component: ControlComponent<TValue>;
638
+ /**
639
+ * The component renders its own `<Field>` (label / description / error). When
640
+ * true, `FieldRenderer` does not wrap it, and passes `label` / `description` /
641
+ * `errors` on {@link ControlProps} instead of `describedById`.
642
+ */
643
+ selfContained?: boolean;
148
644
  /** Value used when neither the config nor the form supplies one. */
149
645
  defaultValue?: TValue;
150
646
  /** Normalize an incoming value before it reaches the control. */
@@ -178,43 +674,30 @@ interface FieldRenderContext {
178
674
  /** Value for the control's `aria-describedby`, or `undefined`. */
179
675
  describedById: string | undefined;
180
676
  invalid: boolean;
677
+ valid: boolean;
181
678
  required: boolean | undefined;
182
679
  disabled: boolean | undefined;
183
680
  }
184
681
  /**
185
- * Low-level layout + a11y wrapper. Renders label, description and error region
186
- * and wires the ARIA relationships. `Input` and `Dropdown` are built on it, and
187
- * it is exported for custom control authors.
682
+ * Low-level layout + a11y wrapper. Renders label, description and an
683
+ * error / success region and wires the ARIA relationships. Every control is
684
+ * built on it, and it is exported for custom control authors.
188
685
  */
189
686
  interface FieldProps {
190
687
  label?: ReactNode;
191
688
  description?: ReactNode;
192
689
  error?: ErrorProp;
690
+ /** `true`, or a confirmation message, to show the success state. */
691
+ success?: string | boolean;
193
692
  required?: boolean;
194
693
  disabled?: boolean;
694
+ /** Skip rendering the `<label>` (e.g. the control floats its own). */
695
+ hideLabel?: boolean;
195
696
  /** Control id; generated with `useId` when omitted. */
196
697
  id?: string;
197
698
  className?: string;
198
699
  children: ReactNode | ((ctx: FieldRenderContext) => ReactNode);
199
700
  }
200
- /** Props shared by the standalone controls. */
201
- interface SharedControlProps {
202
- label?: ReactNode;
203
- description?: ReactNode;
204
- error?: ErrorProp;
205
- }
206
- interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "onChange" | "value" | "type">, SharedControlProps {
207
- value?: string;
208
- onChange?: (value: string, event?: ChangeEvent<HTMLInputElement>) => void;
209
- type?: "text" | "email" | "password" | "number" | "tel" | "url";
210
- }
211
- interface DropdownProps extends Omit<SelectHTMLAttributes<HTMLSelectElement>, "onChange" | "value">, SharedControlProps {
212
- options: DropdownOption[];
213
- value?: string;
214
- onChange?: (value: string, event?: ChangeEvent<HTMLSelectElement>) => void;
215
- /** Renders a non-selectable prompt option when the value is empty. */
216
- placeholder?: string;
217
- }
218
701
  interface FieldsetProps<TValues extends Record<string, unknown> = Record<string, unknown>> {
219
702
  config: FieldsetConfig;
220
703
  /** Controlled values. Omit and use `defaultValue` for uncontrolled. */
@@ -234,18 +717,10 @@ interface FieldsetProps<TValues extends Record<string, unknown> = Record<string,
234
717
  id?: string;
235
718
  }
236
719
 
237
- /**
238
- * A labelled single-select built on the native `<select>` element (accessible
239
- * and keyboard-navigable out of the box). Works with or without `<Fieldset>`.
240
- */
241
- declare const Dropdown: react.ForwardRefExoticComponent<DropdownProps & react.RefAttributes<HTMLSelectElement>>;
242
-
243
720
  /**
244
721
  * Layout + accessibility wrapper for a single control. Renders the label,
245
- * optional description, and an error region, and wires the ARIA relationships
246
- * (`htmlFor`, `aria-describedby`, `aria-invalid`, `aria-required`).
247
- *
248
- * Pass a render function as `children` to receive the resolved ids:
722
+ * optional description, and an error/success region, and wires the ARIA
723
+ * relationships (`htmlFor`, `aria-describedby`, `aria-invalid`, `aria-required`).
249
724
  *
250
725
  * ```tsx
251
726
  * <Field label="Name" error={error}>
@@ -257,18 +732,179 @@ declare const Dropdown: react.ForwardRefExoticComponent<DropdownProps & react.Re
257
732
  */
258
733
  declare function Field(props: FieldProps): react.JSX.Element;
259
734
 
260
- /**
261
- * A labelled text input. Controlled when `value` is passed, uncontrolled
262
- * otherwise (`defaultValue` flows through to the native element). Works with or
263
- * without `<Fieldset>`.
264
- */
735
+ type NativeInput = Omit<InputHTMLAttributes<HTMLInputElement>, "value" | "defaultValue" | "onChange" | "type" | "size" | "prefix">;
736
+ /** `showCount` config: `true`, or an object with a cap + a custom formatter. */
737
+ type ShowCount = boolean | {
738
+ max?: number;
739
+ formatter?: (count: number, max?: number) => ReactNode;
740
+ };
741
+ interface InputProps extends BaseControlProps, NativeInput {
742
+ value?: string;
743
+ defaultValue?: string;
744
+ onChange?: (value: string, event: ChangeEvent<HTMLInputElement>) => void;
745
+ /** Fired on Enter. */
746
+ onEnter?: (value: string) => void;
747
+ type?: "text" | "email" | "password" | "search" | "tel" | "url";
748
+ /** Static text glued to the start (e.g. `https://`). */
749
+ prefix?: ReactNode;
750
+ /** Static text glued to the end (e.g. `.com`). */
751
+ suffix?: ReactNode;
752
+ /** Segment attached before the field, outside the border. */
753
+ addonBefore?: ReactNode;
754
+ /** Segment attached after the field, outside the border. */
755
+ addonAfter?: ReactNode;
756
+ /** Show a show/hide toggle (implied for `type="password"`). */
757
+ passwordToggle?: boolean;
758
+ /** Controlled reveal state for a password field. */
759
+ passwordVisible?: boolean;
760
+ onPasswordVisibleChange?: (visible: boolean) => void;
761
+ /** Custom toggle icon; gets the current reveal state. */
762
+ visibilityToggleIcon?: (revealed: boolean) => ReactNode;
763
+ /** Show a live character counter. Pass an object for a cap / custom render. */
764
+ showCount?: ShowCount;
765
+ /** Debounce `onChange` by this many ms (drive uncontrolled to avoid lag). */
766
+ debounce?: number;
767
+ }
265
768
  declare const Input: react.ForwardRefExoticComponent<InputProps & react.RefAttributes<HTMLInputElement>>;
266
769
 
770
+ type NativeNumberInput = Omit<InputHTMLAttributes<HTMLInputElement>, "value" | "defaultValue" | "onChange" | "type" | "min" | "max" | "step" | "size" | "prefix" | "style">;
771
+ type ClampBehavior = "strict" | "blur" | "none";
772
+ interface NumberFieldProps extends BaseControlProps, NativeNumberInput {
773
+ value?: number | null;
774
+ defaultValue?: number | null;
775
+ onChange?: (value: number | null) => void;
776
+ /** Fires alongside `onChange` with the formatted string too. */
777
+ onValueChange?: (payload: {
778
+ value: number | null;
779
+ formatted: string;
780
+ }) => void;
781
+ min?: number;
782
+ max?: number;
783
+ step?: number;
784
+ /** Larger step for Shift+Arrow / PageUp-Down. Default `step * 10`. */
785
+ shiftStep?: number;
786
+ /** Smaller step for Alt+Arrow. Default `step / 10`. */
787
+ smallStep?: number;
788
+ /** Decimal places to keep. Alias: `decimalScale`. */
789
+ precision?: number;
790
+ decimalScale?: number;
791
+ /** Pad to `decimalScale` with trailing zeros. */
792
+ fixedDecimalScale?: boolean;
793
+ /** Stepper buttons. Default `"stacked"`. */
794
+ buttons?: "stacked" | "horizontal" | false;
795
+ /** Alias for `buttons={false}`. */
796
+ hideControls?: boolean;
797
+ /** Group thousands (`1,000`). */
798
+ grouping?: boolean;
799
+ /** Override the locale's thousands separator. */
800
+ thousandSeparator?: string;
801
+ /** Override the locale's decimal separator. */
802
+ decimalSeparator?: string;
803
+ /** BCP-47 locale for formatting. */
804
+ locale?: string;
805
+ /** Number style. `currency` needs `currency`; `unit` needs `unit`. */
806
+ style?: "decimal" | "currency" | "percent" | "unit";
807
+ /** ISO currency code (implies `style="currency"`). */
808
+ currency?: string;
809
+ /** Intl unit identifier for `style="unit"` (e.g. `"kilogram"`). */
810
+ unit?: string;
811
+ /** Raw `Intl.NumberFormatOptions` — wins over the individual knobs. */
812
+ formatOptions?: Intl.NumberFormatOptions;
813
+ /** Fully custom display. */
814
+ format?: (value: number) => string;
815
+ /** Fully custom parse. */
816
+ parse?: (text: string) => number | null;
817
+ /** Text before the number. */
818
+ prefix?: string;
819
+ /** Text after the number (e.g. `%`, `kg`). */
820
+ suffix?: string;
821
+ /** Allow values below zero. Default true. */
822
+ allowNegative?: boolean;
823
+ /** `"strict"` (never leaves range) · `"blur"` (default) · `"none"`. */
824
+ clampBehavior?: ClampBehavior;
825
+ /** Deprecated alias — `false` maps to `clampBehavior="none"`. */
826
+ clampOnBlur?: boolean;
827
+ /** Value committed for an empty field. Default `null`. */
828
+ emptyValue?: number | null;
829
+ /** Step with the mouse wheel while focused. Default false. */
830
+ allowMouseWheel?: boolean;
831
+ /** Inverse of `allowMouseWheel`. */
832
+ isWheelDisabled?: boolean;
833
+ /** Delay before hold-to-repeat kicks in, ms. Default 300. */
834
+ stepHoldDelay?: number;
835
+ /** Interval between repeats while held, ms. Default 60. */
836
+ stepHoldInterval?: number;
837
+ }
838
+ declare const NumberField: react.ForwardRefExoticComponent<NumberFieldProps & react.RefAttributes<HTMLInputElement>>;
839
+
840
+ type NativeRadio = Omit<InputHTMLAttributes<HTMLInputElement>, "type" | "checked" | "defaultChecked" | "onChange" | "size" | "value">;
841
+ interface RadioProps extends NativeRadio {
842
+ value: string;
843
+ label?: ReactNode;
844
+ description?: ReactNode;
845
+ disabled?: boolean;
846
+ size?: ControlSize;
847
+ card?: boolean;
848
+ labelPlacement?: "end" | "start";
849
+ className?: string;
850
+ }
851
+ declare const Radio: react.ForwardRefExoticComponent<RadioProps & react.RefAttributes<HTMLInputElement>>;
852
+ interface RadioOption {
853
+ label: ReactNode;
854
+ value: string;
855
+ description?: ReactNode;
856
+ /** Leading icon shown before the label. */
857
+ icon?: ReactNode;
858
+ disabled?: boolean;
859
+ }
860
+ interface RadioGroupProps {
861
+ label?: ReactNode;
862
+ description?: ReactNode;
863
+ error?: Feedback;
864
+ success?: string | boolean;
865
+ required?: boolean;
866
+ disabled?: boolean;
867
+ name?: string;
868
+ size?: ControlSize;
869
+ variant?: "default" | "card";
870
+ value?: string | null;
871
+ defaultValue?: string | null;
872
+ onChange?: (value: string) => void;
873
+ orientation?: "vertical" | "horizontal";
874
+ /** Lay the options out in an N-column grid. */
875
+ columns?: number;
876
+ options?: RadioOption[];
877
+ children?: ReactNode;
878
+ className?: string;
879
+ id?: string;
880
+ }
881
+ declare function RadioGroup(props: RadioGroupProps): react.JSX.Element;
882
+
883
+ type NativeTextarea = Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, "value" | "defaultValue" | "onChange" | "rows" | "cols">;
884
+ interface TextareaProps extends Omit<BaseControlProps, "startContent">, NativeTextarea {
885
+ value?: string;
886
+ defaultValue?: string;
887
+ onChange?: (value: string, event: ChangeEvent<HTMLTextAreaElement>) => void;
888
+ /** Fired on Enter (without Shift). */
889
+ onEnter?: (value: string) => void;
890
+ /** Enter (no Shift) fires `onEnter` and suppresses the newline. */
891
+ submitOnEnter?: boolean;
892
+ /** Grow with content between `minRows` and `maxRows`. */
893
+ autoResize?: boolean;
894
+ minRows?: number;
895
+ maxRows?: number;
896
+ /** Native resize handle. Default `"vertical"` (`"none"` when `autoResize`). */
897
+ resize?: "none" | "vertical" | "both";
898
+ /** Live counter — `true`, or `{ max?, formatter?(count, max) }`. */
899
+ showCount?: ShowCount;
900
+ }
901
+ declare const Textarea: react.ForwardRefExoticComponent<TextareaProps & react.RefAttributes<HTMLTextAreaElement>>;
902
+
267
903
  /**
268
904
  * Renders a form (or a form section) from a `FieldsetConfig`. Controlled when
269
905
  * `value` is passed, uncontrolled otherwise. Renders a native `<fieldset>` — so
270
906
  * `disabled` cascades to every control — and does not render its own `<form>`;
271
- * wrap it in one and use `useFieldsetState().handleSubmit` for submission.
907
+ * wrap it in one and use `useFieldsetState().handleSubmit`, or use `<Form>`.
272
908
  */
273
909
  declare function Fieldset<TValues extends Record<string, unknown> = Record<string, unknown>>(props: FieldsetProps<TValues>): react.JSX.Element;
274
910
 
@@ -289,6 +925,8 @@ interface FieldsetState {
289
925
  interface NormalizedFieldsetConfig {
290
926
  fields: FieldConfig[];
291
927
  columns: ColumnSpec;
928
+ /** Minimum comfortable width for one column, in px. */
929
+ minColWidth: number;
292
930
  /** CSS length for the grid gap, or `undefined` to use the token default. */
293
931
  gap: string | undefined;
294
932
  legend: string | undefined;
@@ -304,8 +942,8 @@ interface NormalizedFieldsetConfig {
304
942
  */
305
943
  declare function normalizeConfig(config: FieldsetConfig, registry?: FieldRegistry): NormalizedFieldsetConfig;
306
944
 
307
- type Values = Record<string, unknown>;
308
- interface UseFieldsetStateOptions<TValues extends Values = Values> {
945
+ type Values$1 = Record<string, unknown>;
946
+ interface UseFieldsetStateOptions<TValues extends Values$1 = Values$1> {
309
947
  /** Controlled values. Omit and pass `defaultValue` for uncontrolled. */
310
948
  value?: TValues;
311
949
  defaultValue?: Partial<TValues>;
@@ -327,7 +965,7 @@ interface FieldSlice {
327
965
  setValue: (value: unknown) => void;
328
966
  markTouched: () => void;
329
967
  }
330
- interface UseFieldsetStateReturn<TValues extends Values = Values> {
968
+ interface UseFieldsetStateReturn<TValues extends Values$1 = Values$1> {
331
969
  config: NormalizedFieldsetConfig;
332
970
  state: FieldsetState;
333
971
  values: TValues;
@@ -348,7 +986,371 @@ interface UseFieldsetStateReturn<TValues extends Values = Values> {
348
986
  * markup. Manages values (controlled or uncontrolled), touched/dirty tracking,
349
987
  * and validation through a pluggable resolver.
350
988
  */
351
- declare function useFieldsetState<TValues extends Values = Values>(config: FieldsetConfig, options?: UseFieldsetStateOptions<TValues>): UseFieldsetStateReturn<TValues>;
989
+ declare function useFieldsetState<TValues extends Values$1 = Values$1>(config: FieldsetConfig, options?: UseFieldsetStateOptions<TValues>): UseFieldsetStateReturn<TValues>;
990
+
991
+ interface FieldsetViewProps {
992
+ /** The return of `useFieldsetState`. */
993
+ state: UseFieldsetStateReturn;
994
+ registry?: FieldRegistry;
995
+ disabled?: boolean;
996
+ className?: string;
997
+ id?: string;
998
+ }
999
+ /**
1000
+ * Presentational half of `<Fieldset>` — renders the grid of fields from an
1001
+ * existing `useFieldsetState` instance. Used by `<Fieldset>` and `<Form>` so
1002
+ * they never run the state hook twice.
1003
+ */
1004
+ declare function FieldsetView({ state, registry, disabled, className, id }: FieldsetViewProps): react.JSX.Element;
1005
+
1006
+ type Values = Record<string, unknown>;
1007
+ interface FormProps<TValues extends Values = Values> extends Omit<FormHTMLAttributes<HTMLFormElement>, "onSubmit" | "onInvalid" | "children" | "onChange" | "defaultValue"> {
1008
+ config: FieldsetConfig;
1009
+ value?: TValues;
1010
+ defaultValue?: Partial<TValues>;
1011
+ onChange?: (values: TValues) => void;
1012
+ /** Called with the values when the form passes validation. */
1013
+ onSubmit: (values: TValues, fs: UseFieldsetStateReturn<TValues>) => void;
1014
+ /** Called with the errors when submit is blocked. */
1015
+ onInvalid?: (errors: ValidationResult) => void;
1016
+ resolver?: ValidationResolver;
1017
+ validateOn?: ValidationTrigger;
1018
+ disabled?: boolean;
1019
+ /** Content after the fieldset — usually a submit button. Gets `fs`. */
1020
+ children?: ReactNode | ((fs: UseFieldsetStateReturn<TValues>) => ReactNode);
1021
+ }
1022
+ /**
1023
+ * A `<form>` that owns its state: renders `<Fieldset>` from `config`, and calls
1024
+ * `onSubmit(values)` only when validation passes. `children` (or a render
1025
+ * function receiving the `useFieldsetState` return) is where the submit button
1026
+ * goes.
1027
+ *
1028
+ * ```tsx
1029
+ * <Form config={config} onSubmit={(v) => save(v)}>
1030
+ * {(fs) => <button type="submit" disabled={!fs.isValid}>Save</button>}
1031
+ * </Form>
1032
+ * ```
1033
+ */
1034
+ declare function Form<TValues extends Values = Values>(props: FormProps<TValues>): react.JSX.Element;
1035
+
1036
+ type ButtonVariant = "default" | "secondary" | "destructive" | "outline" | "ghost" | "link";
1037
+ type ButtonSize = "default" | "sm" | "lg" | "icon";
1038
+ type BadgeVariant = "default" | "secondary" | "destructive" | "outline";
1039
+ /**
1040
+ * Class list for a shadcn-style button. Exported so a non-`<button>` element can
1041
+ * be styled as one: `<a className={buttonClasses("outline")}>…</a>`.
1042
+ */
1043
+ declare function buttonClasses(variant?: ButtonVariant, size?: ButtonSize): string;
1044
+ /** Class list for a badge — same idea as {@link buttonClasses}. */
1045
+ declare function badgeClasses(variant?: BadgeVariant): string;
1046
+
1047
+ interface ButtonProps extends ComponentProps<"button"> {
1048
+ /** default · secondary · destructive · outline · ghost · link */
1049
+ variant?: ButtonVariant;
1050
+ /** default (h-9) · sm (h-8) · lg (h-10) · icon (square) */
1051
+ size?: ButtonSize;
1052
+ /** Render `children` as the button, merging button props/classes onto it. */
1053
+ asChild?: boolean;
1054
+ /** Show a spinner and disable the button. */
1055
+ loading?: boolean;
1056
+ /** Replaces the label while `loading`. */
1057
+ loadingText?: ReactNode;
1058
+ /** Icon before the label (ignored with `asChild`). */
1059
+ leftIcon?: ReactNode;
1060
+ /** Icon after the label (ignored with `asChild`). */
1061
+ rightIcon?: ReactNode;
1062
+ /** Stretch to the container width. */
1063
+ fullWidth?: boolean;
1064
+ }
1065
+ declare const Button: react.ForwardRefExoticComponent<Omit<ButtonProps, "ref"> & react.RefAttributes<HTMLButtonElement>>;
1066
+
1067
+ interface LabelProps extends ComponentPropsWithoutRef<typeof Label$1.Root> {
1068
+ /** Append a required asterisk. */
1069
+ required?: boolean;
1070
+ /** Append an "(optional)" hint (ignored when `required`). */
1071
+ optional?: boolean | ReactNode;
1072
+ }
1073
+ declare const Label: react.ForwardRefExoticComponent<LabelProps & react.RefAttributes<HTMLLabelElement>>;
1074
+
1075
+ type DivProps = ComponentProps<"div">;
1076
+ interface CardProps extends DivProps {
1077
+ /** Render `children` as the card element (e.g. an `<a>` or `<button>`). */
1078
+ asChild?: boolean;
1079
+ /** Hover / focus-visible affordance for a clickable card. */
1080
+ interactive?: boolean;
1081
+ }
1082
+ declare const Card: react.ForwardRefExoticComponent<Omit<CardProps, "ref"> & react.RefAttributes<HTMLDivElement>>;
1083
+ declare const CardHeader: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1084
+ declare const CardTitle: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1085
+ declare const CardDescription: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1086
+ declare const CardAction: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1087
+ declare const CardContent: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1088
+ declare const CardFooter: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1089
+
1090
+ interface BadgeProps extends ComponentProps<"span"> {
1091
+ /** default · secondary · destructive · outline */
1092
+ variant?: BadgeVariant;
1093
+ /** `sm` or `md` (default). */
1094
+ size?: "sm" | "md";
1095
+ /** Leading status dot. */
1096
+ dot?: boolean;
1097
+ /** Leading icon (ignored with `asChild`). */
1098
+ icon?: ReactNode;
1099
+ /** Render a trailing ✕ that calls `onRemove`. */
1100
+ removable?: boolean;
1101
+ onRemove?: (e: MouseEvent<HTMLButtonElement>) => void;
1102
+ /** Render `children` as the badge element (drops the extras). */
1103
+ asChild?: boolean;
1104
+ }
1105
+ declare const Badge: react.ForwardRefExoticComponent<Omit<BadgeProps, "ref"> & react.RefAttributes<HTMLSpanElement>>;
1106
+
1107
+ type AlertVariant = "default" | "destructive" | "success" | "warning" | "info";
1108
+ interface AlertProps extends Omit<ComponentProps<"div">, "title"> {
1109
+ /** default · destructive · success · warning · info */
1110
+ variant?: AlertVariant;
1111
+ /** Leading icon. */
1112
+ icon?: ReactNode;
1113
+ /** Shorthand for a leading `<AlertTitle>`. */
1114
+ title?: ReactNode;
1115
+ /** Render a top-right ✕ that calls `onDismiss`. */
1116
+ dismissible?: boolean;
1117
+ onDismiss?: () => void;
1118
+ }
1119
+ declare const Alert: react.ForwardRefExoticComponent<Omit<AlertProps, "ref"> & react.RefAttributes<HTMLDivElement>>;
1120
+ declare const AlertTitle: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1121
+ declare const AlertDescription: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1122
+
1123
+ interface SeparatorProps extends ComponentPropsWithoutRef<typeof Separator$1.Root> {
1124
+ /** `solid` (default) or `dashed`. */
1125
+ variant?: "solid" | "dashed";
1126
+ /** Centered text inside the rule (horizontal only). */
1127
+ children?: ReactNode;
1128
+ }
1129
+ declare const Separator: react.ForwardRefExoticComponent<SeparatorProps & react.RefAttributes<HTMLDivElement>>;
1130
+
1131
+ interface TableProps extends ComponentProps<"table"> {
1132
+ /** Cell padding. `md` (default) or `sm` (compact). `dense` is an alias for `sm`. */
1133
+ size?: "sm" | "md";
1134
+ dense?: boolean;
1135
+ }
1136
+ declare const Table: react.ForwardRefExoticComponent<Omit<TableProps, "ref"> & react.RefAttributes<HTMLTableElement>>;
1137
+ interface TableHeaderProps extends ComponentProps<"thead"> {
1138
+ /** Stick the header to the top of the scroll container. */
1139
+ sticky?: boolean;
1140
+ }
1141
+ declare const TableHeader: react.ForwardRefExoticComponent<Omit<TableHeaderProps, "ref"> & react.RefAttributes<HTMLTableSectionElement>>;
1142
+ declare const TableBody: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>, "ref"> & react.RefAttributes<HTMLTableSectionElement>>;
1143
+ declare const TableFooter: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>, "ref"> & react.RefAttributes<HTMLTableSectionElement>>;
1144
+ interface TableRowProps extends ComponentProps<"tr"> {
1145
+ /** Highlight the row (maps to `data-state="selected"`). */
1146
+ selected?: boolean;
1147
+ }
1148
+ declare const TableRow: react.ForwardRefExoticComponent<Omit<TableRowProps, "ref"> & react.RefAttributes<HTMLTableRowElement>>;
1149
+ declare const TableHead: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>, "ref"> & react.RefAttributes<HTMLTableCellElement>>;
1150
+ declare const TableCell: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>, "ref"> & react.RefAttributes<HTMLTableCellElement>>;
1151
+ declare const TableCaption: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLElement>, HTMLElement>, "ref"> & react.RefAttributes<HTMLTableCaptionElement>>;
1152
+
1153
+ interface SwitchProps extends ComponentPropsWithoutRef<typeof Switch$1.Root> {
1154
+ /** `sm` · `default` · `lg`. */
1155
+ size?: "sm" | "default" | "lg";
1156
+ /** Text beside the switch — wraps it in a `<label>` layout. */
1157
+ label?: ReactNode;
1158
+ /** Help text under the label. */
1159
+ description?: ReactNode;
1160
+ /** `end` (default) or `start`. */
1161
+ labelPlacement?: "end" | "start";
1162
+ /** Tiny text inside the track when on / off. */
1163
+ onLabel?: ReactNode;
1164
+ offLabel?: ReactNode;
1165
+ /** Icon rendered inside the thumb. */
1166
+ thumbIcon?: ReactNode;
1167
+ }
1168
+ declare const Switch: react.ForwardRefExoticComponent<SwitchProps & react.RefAttributes<HTMLButtonElement>>;
1169
+
1170
+ interface TabsProps extends ComponentPropsWithoutRef<typeof Tabs$1.Root> {
1171
+ /** `pill` (default, muted rounded bar) · `underline` · `enclosed` (folder tabs). */
1172
+ variant?: "pill" | "underline" | "enclosed";
1173
+ /** Trigger sizing. Default `md`. */
1174
+ size?: "sm" | "md" | "lg";
1175
+ /** Triggers stretch to fill the list width. */
1176
+ fitted?: boolean;
1177
+ }
1178
+ declare const Tabs: react.ForwardRefExoticComponent<TabsProps & react.RefAttributes<HTMLDivElement>>;
1179
+ declare const TabsList: react.ForwardRefExoticComponent<Omit<Tabs$1.TabsListProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1180
+ declare const TabsTrigger: react.ForwardRefExoticComponent<Omit<Tabs$1.TabsTriggerProps & react.RefAttributes<HTMLButtonElement>, "ref"> & react.RefAttributes<HTMLButtonElement>>;
1181
+ declare const TabsContent: react.ForwardRefExoticComponent<Omit<Tabs$1.TabsContentProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1182
+
1183
+ declare const Dialog: (props: ComponentProps<typeof Dialog$1.Root>) => react.JSX.Element;
1184
+ declare const DialogTrigger: (props: ComponentProps<typeof Dialog$1.Trigger>) => react.JSX.Element;
1185
+ declare const DialogClose: (props: ComponentProps<typeof Dialog$1.Close>) => react.JSX.Element;
1186
+ declare const DialogPortal: react.FC<Dialog$1.DialogPortalProps>;
1187
+ interface DialogContentProps extends ComponentPropsWithoutRef<typeof Dialog$1.Content> {
1188
+ /** Render the built-in top-right close button. Default `true`. */
1189
+ showCloseButton?: boolean;
1190
+ /** Max width. Default `lg`. */
1191
+ size?: "sm" | "md" | "lg" | "xl" | "full";
1192
+ /** Cap the height and scroll the body. */
1193
+ scrollable?: boolean;
1194
+ /** Override the portal container. */
1195
+ container?: Element | DocumentFragment | null;
1196
+ }
1197
+ declare const DialogContent: react.ForwardRefExoticComponent<DialogContentProps & react.RefAttributes<HTMLDivElement>>;
1198
+ declare function DialogHeader({ className, ...props }: ComponentProps<"div">): react.JSX.Element;
1199
+ declare function DialogFooter({ className, ...props }: ComponentProps<"div">): react.JSX.Element;
1200
+ declare const DialogTitle: react.ForwardRefExoticComponent<Omit<Dialog$1.DialogTitleProps & react.RefAttributes<HTMLHeadingElement>, "ref"> & react.RefAttributes<HTMLHeadingElement>>;
1201
+ declare const DialogDescription: react.ForwardRefExoticComponent<Omit<Dialog$1.DialogDescriptionProps & react.RefAttributes<HTMLParagraphElement>, "ref"> & react.RefAttributes<HTMLParagraphElement>>;
1202
+
1203
+ declare const Popover: (props: ComponentProps<typeof Popover$1.Root>) => react.JSX.Element;
1204
+ declare const PopoverTrigger: (props: ComponentProps<typeof Popover$1.Trigger>) => react.JSX.Element;
1205
+ declare const PopoverAnchor: (props: ComponentProps<typeof Popover$1.Anchor>) => react.JSX.Element;
1206
+ declare const PopoverClose: react.ForwardRefExoticComponent<Popover$1.PopoverCloseProps & react.RefAttributes<HTMLButtonElement>>;
1207
+ declare const PopoverArrow: (props: ComponentProps<typeof Popover$1.Arrow>) => react.JSX.Element;
1208
+ interface PopoverContentProps extends ComponentPropsWithoutRef<typeof Popover$1.Content> {
1209
+ /** Show a pointing arrow. */
1210
+ arrow?: boolean;
1211
+ /** Override the portal container. */
1212
+ container?: Element | DocumentFragment | null;
1213
+ }
1214
+ declare const PopoverContent: react.ForwardRefExoticComponent<PopoverContentProps & react.RefAttributes<HTMLDivElement>>;
1215
+
1216
+ declare function TooltipProvider({ delayDuration, ...props }: ComponentPropsWithoutRef<typeof Tooltip$1.Provider>): react.JSX.Element;
1217
+ interface TooltipProps extends ComponentPropsWithoutRef<typeof Tooltip$1.Root> {
1218
+ /** Hover delay before opening, ms. Default 0. */
1219
+ delayDuration?: number;
1220
+ /** Window after closing where the next tip opens instantly. */
1221
+ skipDelayDuration?: number;
1222
+ /** Don't keep the tip open while the pointer is over it. */
1223
+ disableHoverableContent?: boolean;
1224
+ /** Skip the auto-wrapped provider (a parent already renders one). */
1225
+ disableProvider?: boolean;
1226
+ }
1227
+ declare function Tooltip({ delayDuration, skipDelayDuration, disableHoverableContent, disableProvider, ...props }: TooltipProps): react.JSX.Element;
1228
+ declare const TooltipTrigger: (props: ComponentPropsWithoutRef<typeof Tooltip$1.Trigger>) => react.JSX.Element;
1229
+ interface TooltipContentProps extends ComponentPropsWithoutRef<typeof Tooltip$1.Content> {
1230
+ /** Show the pointing arrow. Default `true`. */
1231
+ arrow?: boolean;
1232
+ /** Arrow width in px (height is ~half). Default 11. */
1233
+ arrowSize?: number;
1234
+ /** Override the portal container. */
1235
+ container?: Element | DocumentFragment | null;
1236
+ }
1237
+ declare const TooltipContent: react.ForwardRefExoticComponent<TooltipContentProps & react.RefAttributes<HTMLDivElement>>;
1238
+
1239
+ declare const DropdownMenu: (props: ComponentProps<typeof DropdownMenu$1.Root>) => react.JSX.Element;
1240
+ declare const DropdownMenuTrigger: (props: ComponentProps<typeof DropdownMenu$1.Trigger>) => react.JSX.Element;
1241
+ declare const DropdownMenuGroup: react.ForwardRefExoticComponent<DropdownMenu$1.DropdownMenuGroupProps & react.RefAttributes<HTMLDivElement>>;
1242
+ declare const DropdownMenuPortal: react.FC<DropdownMenu$1.DropdownMenuPortalProps>;
1243
+ declare const DropdownMenuSub: react.FC<DropdownMenu$1.DropdownMenuSubProps>;
1244
+ declare const DropdownMenuRadioGroup: react.ForwardRefExoticComponent<DropdownMenu$1.DropdownMenuRadioGroupProps & react.RefAttributes<HTMLDivElement>>;
1245
+ interface DropdownMenuContentProps extends ComponentPropsWithoutRef<typeof DropdownMenu$1.Content> {
1246
+ /** Override the portal container. */
1247
+ container?: Element | DocumentFragment | null;
1248
+ }
1249
+ declare const DropdownMenuContent: react.ForwardRefExoticComponent<DropdownMenuContentProps & react.RefAttributes<HTMLDivElement>>;
1250
+ interface DropdownMenuItemProps extends ComponentPropsWithoutRef<typeof DropdownMenu$1.Item> {
1251
+ inset?: boolean;
1252
+ variant?: "default" | "destructive";
1253
+ /** Leading icon. */
1254
+ icon?: ReactNode;
1255
+ /** Trailing shortcut hint (rendered right-aligned). */
1256
+ shortcut?: ReactNode;
1257
+ }
1258
+ declare const DropdownMenuItem: react.ForwardRefExoticComponent<DropdownMenuItemProps & react.RefAttributes<HTMLDivElement>>;
1259
+ declare const DropdownMenuCheckboxItem: react.ForwardRefExoticComponent<Omit<DropdownMenu$1.DropdownMenuCheckboxItemProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1260
+ declare const DropdownMenuRadioItem: react.ForwardRefExoticComponent<Omit<DropdownMenu$1.DropdownMenuRadioItemProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1261
+ interface DropdownMenuLabelProps extends ComponentPropsWithoutRef<typeof DropdownMenu$1.Label> {
1262
+ inset?: boolean;
1263
+ }
1264
+ declare const DropdownMenuLabel: react.ForwardRefExoticComponent<DropdownMenuLabelProps & react.RefAttributes<HTMLDivElement>>;
1265
+ declare const DropdownMenuSeparator: react.ForwardRefExoticComponent<Omit<DropdownMenu$1.DropdownMenuSeparatorProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1266
+ declare function DropdownMenuShortcut({ className, ...props }: ComponentProps<"span">): react.JSX.Element;
1267
+ interface DropdownMenuSubTriggerProps extends ComponentPropsWithoutRef<typeof DropdownMenu$1.SubTrigger> {
1268
+ inset?: boolean;
1269
+ }
1270
+ declare const DropdownMenuSubTrigger: react.ForwardRefExoticComponent<DropdownMenuSubTriggerProps & react.RefAttributes<HTMLDivElement>>;
1271
+ declare const DropdownMenuSubContent: react.ForwardRefExoticComponent<Omit<DropdownMenu$1.DropdownMenuSubContentProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1272
+
1273
+ /** Built-in colour presets. Each maps to `[data-orynn-theme="…"]` in the stylesheet
1274
+ * and now recolours only the primary/ring — backgrounds stay neutral (shadcn style). */
1275
+ type OrynnPreset = "default" | "slate" | "teal" | "violet" | "rose" | "emerald";
1276
+ /** Vertical rhythm / sizing. Maps to `[data-orynn-density="…"]`. */
1277
+ type OrynnDensity = "compact" | "comfortable" | "spacious";
1278
+ type OrynnRadius = "none" | "sm" | "md" | "lg" | "xl" | "pill" | (string & {}) | number;
1279
+ /** Any `--orynn-*` custom property. */
1280
+ type OrynnVarOverrides = Partial<Record<`--orynn-${string}`, string | number>>;
1281
+ interface OrynnThemeConfig {
1282
+ /** Colour preset. Defaults to `"default"` (neutral). */
1283
+ preset?: OrynnPreset;
1284
+ density?: OrynnDensity;
1285
+ /** `"dark"` swaps the base palette to the dark token set (also sets the `.dark` class). */
1286
+ colorScheme?: "light" | "dark";
1287
+ /** The solid action colour (`--orynn-color-primary`). Any CSS colour. */
1288
+ primary?: string;
1289
+ /** Foreground to pair with a custom `primary`. Auto-derived from the lightness
1290
+ * of `primary` when omitted (understands hex, `oklch()`, `hsl()`). */
1291
+ primaryForeground?: string;
1292
+ /** @deprecated alias for `primary`. */
1293
+ accent?: string;
1294
+ /** @deprecated alias for `primaryForeground`. */
1295
+ accentContrast?: string;
1296
+ /** `--orynn-font-family`. */
1297
+ font?: string;
1298
+ /** Base font size, e.g. `"15px"` or `"0.95rem"`. */
1299
+ fontSize?: string | number;
1300
+ /** Corner radius base (`--orynn-radius`). Keyword, CSS length, or px number. */
1301
+ radius?: OrynnRadius;
1302
+ /** Default control width. `"100%"` by default. */
1303
+ controlWidth?: string | number;
1304
+ /** Cap on control width. `"450px"` by default; number = px; `"none"` to uncap. */
1305
+ controlMaxWidth?: string | number;
1306
+ /** Focus-ring colour (`--orynn-color-ring`). */
1307
+ ring?: string;
1308
+ /** Escape hatch: any `--orynn-*` variables verbatim. */
1309
+ vars?: OrynnVarOverrides;
1310
+ }
1311
+ /** `theme` prop accepts a preset name shorthand or a full config. */
1312
+ type OrynnThemeInput = OrynnPreset | OrynnThemeConfig;
1313
+ /** Build the inline CSS-variable style object for a theme config. */
1314
+ declare function resolveThemeVars(config: OrynnThemeConfig): CSSProperties;
1315
+
1316
+ interface OrynnContextValue {
1317
+ preset: OrynnPreset;
1318
+ density: OrynnDensity;
1319
+ config: OrynnThemeConfig;
1320
+ /**
1321
+ * A themed `<div class="orynn-portal">` appended to `document.body` (or `null`
1322
+ * before the mount effect / on the server). Radix `*.Portal`s and the internal
1323
+ * `<Popover>` render into it so portalled content inherits this provider's
1324
+ * theme even though it sits outside the provider's DOM subtree.
1325
+ */
1326
+ portalContainer: HTMLElement | null;
1327
+ }
1328
+ interface OrynnProviderProps {
1329
+ /** Preset name (`"teal"`) or a full config object. */
1330
+ theme?: OrynnThemeInput;
1331
+ /** Render a `<div>` (default) or a different element / no wrapper (`"contents"`). */
1332
+ as?: "div" | "span" | "contents";
1333
+ className?: string;
1334
+ children: ReactNode;
1335
+ }
1336
+ /**
1337
+ * Scopes an Orynn theme to its subtree by setting `data-orynn-theme`,
1338
+ * `data-orynn-density`, a `.dark` class and any custom `--orynn-*` variables on a
1339
+ * wrapper element. Purely CSS custom properties — no runtime styling engine.
1340
+ * Nesting is supported; an inner provider overrides only what it sets. Also
1341
+ * mounts a matching `<div class="orynn-portal">` on `document.body` so portalled
1342
+ * overlays (Dialog, Popover, Tooltip, menus) render with the same theme.
1343
+ */
1344
+ declare function OrynnProvider({ theme, as, className, children }: OrynnProviderProps): react.JSX.Element;
1345
+ /** Read the nearest Orynn theme config. */
1346
+ declare function useOrynnTheme(): OrynnContextValue;
1347
+ /**
1348
+ * The DOM node Radix portals / the internal `<Popover>` should render into so
1349
+ * portalled content stays themed. Falls back to `document.body` when there is no
1350
+ * `<OrynnProvider>` (the theme then lives on `:root` / `html` and body inherits
1351
+ * it anyway). `null` only on the server.
1352
+ */
1353
+ declare function usePortalContainer(): HTMLElement | null;
352
1354
 
353
1355
  /**
354
1356
  * Create an isolated field registry. Use this to give a `<Fieldset>` its own set
@@ -374,21 +1376,29 @@ declare const defaultRegistry: FieldRegistry;
374
1376
  */
375
1377
  declare function registerField(type: string, registration: FieldRegistration): void;
376
1378
 
377
- /** A synchronous resolver — the built-in resolver's precise return type. */
1379
+ /** A synchronous resolver — the built-in resolver's return type when no rule is async. */
378
1380
  type SyncResolver = (values: Record<string, unknown>, config: FieldsetConfig, context: ValidationContext) => ValidationResult;
379
1381
  /**
380
- * The default, rule-based {@link ValidationResolver}. For every field with a
381
- * `validation` block, each key (other than `messages`) is looked up in the rule
382
- * registry and run against the field's current value. All fields are validated
383
- * on every call; callers decide which errors to surface.
384
- *
385
- * Synchronous today. Async, schema-based, and cross-field resolvers plug in at
386
- * the same seam without an API change.
1382
+ * The default, rule-based {@link ValidationResolver}. For every visible field
1383
+ * with a `validation` block, each key (other than `messages`) is looked up in
1384
+ * the rule registry and run against the field's current value. Fields whose
1385
+ * `when` condition is false are skipped. Returns synchronously unless a rule
1386
+ * (e.g. `validate`) resolves asynchronously.
387
1387
  */
388
- declare function createRuleResolver(): SyncResolver;
1388
+ declare function createRuleResolver(): ValidationResolver;
389
1389
  /** Shared default instance. */
390
1390
  declare const defaultResolver: ValidationResolver;
391
1391
 
1392
+ /**
1393
+ * Built-in rules. Each returns a token (rule name) on failure or `null` on
1394
+ * success; the resolver turns the token into a user-facing message. Rules other
1395
+ * than `required` skip empty values so `required` owns that error.
1396
+ *
1397
+ * `validate` is special: its param is a function `(value, allValues) => string |
1398
+ * boolean | null | Promise<…>`; a string is the message, `false` a generic
1399
+ * failure, `true` / `null` a pass.
1400
+ */
1401
+ declare const builtInRules: Record<string, RuleFn>;
392
1402
  /**
393
1403
  * Register a validation rule for the built-in resolver. A field opts in by
394
1404
  * adding a key of the same name to its `validation` config.
@@ -397,4 +1407,44 @@ declare const defaultResolver: ValidationResolver;
397
1407
  */
398
1408
  declare function registerRule(name: string, fn: RuleFn): void;
399
1409
 
400
- export { type BaseFieldConfig, type ColumnSpec, type ControlComponent, type ControlProps, Dropdown, type DropdownFieldConfig, type DropdownOption, type DropdownProps, type ErrorProp, FORM_ERROR_KEY, Field, type FieldConfig, type FieldConfigRegistry, type FieldError, type FieldProps, type FieldRegistration, type FieldRegistry, type FieldRenderContext, type FieldSlice, type FieldStatus, type FieldType, type FieldValidation, Fieldset, type FieldsetConfig, type FieldsetProps, type FieldsetState, Input, type InputFieldConfig, type InputProps, type NormalizedFieldsetConfig, type RuleFn, type SyncResolver, type UseFieldsetStateOptions, type UseFieldsetStateReturn, type ValidationContext, type ValidationResolver, type ValidationResult, type ValidationTrigger, createRegistry, createRuleResolver, defaultRegistry, defaultResolver, normalizeConfig, registerField, registerRule, useFieldsetState };
1410
+ /**
1411
+ * Minimal shape of the [Standard Schema](https://standardschema.dev) `v1`
1412
+ * contract — implemented by Zod 3.24+, Valibot 1.0+, ArkType 2+, and others.
1413
+ * Inlined so Orynn needs no dependency.
1414
+ */
1415
+ interface StandardSchemaV1<Output = unknown> {
1416
+ readonly "~standard": {
1417
+ readonly version: 1;
1418
+ readonly vendor: string;
1419
+ readonly validate: (value: unknown) => StandardResult<Output> | Promise<StandardResult<Output>>;
1420
+ };
1421
+ }
1422
+ type StandardResult<Output> = {
1423
+ readonly value: Output;
1424
+ readonly issues?: undefined;
1425
+ } | {
1426
+ readonly issues: ReadonlyArray<StandardIssue>;
1427
+ };
1428
+ interface StandardIssue {
1429
+ readonly message: string;
1430
+ readonly path?: ReadonlyArray<PropertyKey | {
1431
+ readonly key: PropertyKey;
1432
+ }>;
1433
+ }
1434
+ /**
1435
+ * Turn a Standard Schema (Zod / Valibot / ArkType / …) into an Orynn
1436
+ * {@link ValidationResolver}. Pass it to `<Fieldset resolver={…}>` or
1437
+ * `useFieldsetState({ resolver })`.
1438
+ *
1439
+ * ```ts
1440
+ * import { z } from "zod";
1441
+ * const schema = z.object({ email: z.string().email(), age: z.number().min(18) });
1442
+ * <Fieldset config={config} resolver={standardSchemaResolver(schema)} />
1443
+ * ```
1444
+ *
1445
+ * Issues are keyed by the first path segment (the field name); path-less issues
1446
+ * land under `"$form"`.
1447
+ */
1448
+ declare function standardSchemaResolver(schema: StandardSchemaV1): ValidationResolver;
1449
+
1450
+ export { Alert, AlertDescription, type AlertProps, AlertTitle, type AlertVariant, Badge, type BadgeProps, type BadgeVariant, type BaseControlProps, type BaseFieldConfig, Button, type ButtonProps, type ButtonSize, type ButtonVariant, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, type CardProps, CardTitle, Checkbox, type CheckboxFieldConfig, CheckboxGroup, type CheckboxGroupFieldConfig, type CheckboxGroupProps, type CheckboxOption, type CheckboxProps, type ColumnSpec, type ControlComponent, type ControlProps, type ControlRadius, type ControlSize, type ControlVariant, type CustomValidator, type DateFieldConfig, DatePicker, type DatePickerProps, Dialog, DialogClose, DialogContent, type DialogContentProps, DialogDescription, DialogFooter, DialogHeader, DialogPortal, DialogTitle, DialogTrigger, Dropdown, type DropdownFieldConfig, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, type DropdownMenuContentProps, DropdownMenuGroup, DropdownMenuItem, type DropdownMenuItemProps, DropdownMenuLabel, type DropdownMenuLabelProps, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, type DropdownMenuSubTriggerProps, DropdownMenuTrigger, type DropdownOption, type DropdownProps, type EqualsRule, type ErrorProp, FORM_ERROR_KEY, type Feedback, Field, FieldBox, type FieldBoxProps, type FieldCondition, type FieldConfig, type FieldConfigRegistry, type FieldError, type FieldProps, type FieldRegistration, type FieldRegistry, type FieldRenderContext, type FieldSlice, type FieldStatus, type FieldType, type FieldValidation, Fieldset, type FieldsetConfig, type FieldsetProps, type FieldsetState, FieldsetView, type FieldsetViewProps, Form, type FormProps, Input, type InputFieldConfig, type InputProps, Label, type LabelProps, type NormalizedFieldsetConfig, NumberField, type NumberFieldConfig, type NumberFieldProps, type OrynnDensity, type OrynnPreset, OrynnProvider, type OrynnProviderProps, type OrynnRadius, type OrynnThemeConfig, type OrynnThemeInput, type OrynnVarOverrides, type PatternRule, Popover, PopoverAnchor, PopoverArrow, PopoverClose, PopoverContent, type PopoverContentProps, PopoverTrigger, Radio, type RadioFieldConfig, RadioGroup, type RadioGroupProps, type RadioOption, type RadioProps, type RuleFn, Dropdown as Select, Separator, type SeparatorProps, type StandardSchemaV1, Switch, type SwitchProps, type SyncResolver, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, type TableHeaderProps, type TableProps, TableRow, type TableRowProps, Tabs, TabsContent, TabsList, type TabsProps, TabsTrigger, Textarea, type TextareaFieldConfig, type TextareaProps, Tooltip, TooltipContent, type TooltipContentProps, type TooltipProps, TooltipProvider, TooltipTrigger, type UseFieldsetStateOptions, type UseFieldsetStateReturn, type ValidationContext, type ValidationResolver, type ValidationResult, type ValidationTrigger, badgeClasses, builtInRules, buttonClasses, createRegistry, createRuleResolver, defaultRegistry, defaultResolver, normalizeConfig, registerField, registerRule, resolveThemeVars, standardSchemaResolver, useFieldsetState, useOrynnTheme, usePortalContainer };