orynn 0.2.0 → 0.6.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,5 +1,6 @@
1
1
  import * as react from 'react';
2
- import { ReactNode, HTMLAttributes, InputHTMLAttributes, ChangeEvent, ComponentType, SyntheticEvent, TextareaHTMLAttributes, CSSProperties, FormEvent } from 'react';
2
+ import { ReactNode, HTMLAttributes, InputHTMLAttributes, ChangeEvent, ComponentType, SyntheticEvent, TextareaHTMLAttributes, FormEvent, FormHTMLAttributes, ComponentPropsWithoutRef, ComponentProps, MouseEvent, CSSProperties } from 'react';
3
+ import { Accordion as Accordion$1, Slider as Slider$1, Progress as Progress$1, 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
 
4
5
  type ControlSize = "sm" | "md" | "lg";
5
6
  type ControlVariant = "outline" | "filled" | "flushed" | "unstyled";
@@ -22,6 +23,10 @@ interface FieldBoxOwnProps {
22
23
  floatingLabel?: ReactNode;
23
24
  left?: ReactNode;
24
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;
25
30
  /** Adds `.orynn-box--textarea` sizing. */
26
31
  textarea?: boolean;
27
32
  }
@@ -98,6 +103,8 @@ interface CheckboxOption {
98
103
  label: ReactNode;
99
104
  value: string;
100
105
  description?: ReactNode;
106
+ /** Leading icon shown before the label. */
107
+ icon?: ReactNode;
101
108
  disabled?: boolean;
102
109
  }
103
110
  interface CheckboxGroupProps {
@@ -113,10 +120,15 @@ interface CheckboxGroupProps {
113
120
  defaultValue?: string[];
114
121
  onChange?: (value: string[]) => void;
115
122
  orientation?: "vertical" | "horizontal";
123
+ /** Lay the options out in an N-column grid. */
124
+ columns?: number;
116
125
  /** Minimum selections (blocks unchecking below it). */
117
126
  min?: number;
118
127
  /** Maximum selections (blocks checking above it). */
119
128
  max?: number;
129
+ /** Show a "select all" checkbox above the options. */
130
+ showSelectAll?: boolean;
131
+ selectAllLabel?: ReactNode;
120
132
  /** Convenience: render items from data instead of children. */
121
133
  options?: CheckboxOption[];
122
134
  children?: ReactNode;
@@ -125,47 +137,159 @@ interface CheckboxGroupProps {
125
137
  }
126
138
  declare function CheckboxGroup(props: CheckboxGroupProps): react.JSX.Element;
127
139
 
128
- interface DatePickerProps extends Omit<BaseControlProps, "startContent" | "endContent" | "loading"> {
129
- value?: Date | string | null;
130
- defaultValue?: Date | string | null;
131
- onChange?: (value: Date | null) => void;
132
- /** Display / parse pattern (`yyyy MM dd M d MMM MMMM`). Default `"yyyy-MM-dd"`. */
133
- format?: string;
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 `"dd-MMM-yyyy"` (renders e.g.
169
+ * `12-Jan-2020`); pass `"yyyy-MM-dd"` for ISO.
170
+ */
171
+ format?: string | Intl.DateTimeFormatOptions;
134
172
  minDate?: Date;
135
173
  maxDate?: Date;
136
174
  disabledDates?: Date[] | ((date: Date) => boolean);
175
+ /** Predicate form of `disabledDates` (react-aria naming). */
176
+ isDateUnavailable?: (date: Date) => boolean;
137
177
  firstDayOfWeek?: number;
138
178
  locale?: string;
139
179
  showWeekNumbers?: boolean;
140
180
  showToday?: boolean;
141
181
  showClear?: boolean;
182
+ /** Starting inner view of the calendar. Defaults to `precision`. */
183
+ defaultView?: CalendarView;
184
+ /**
185
+ * How far the picker drills: `"day"` (default), `"month"` (select a whole
186
+ * month), or `"year"`.
187
+ */
188
+ precision?: CalendarPrecision;
189
+ /** Always render six week rows. Default true. */
190
+ fixedWeeks?: boolean;
191
+ /** Side-by-side month panels. Default 1. */
192
+ numberOfMonths?: number;
193
+ /**
194
+ * Lower bound for the calendar's width (`--orynn-calendar-min-width`). The
195
+ * calendar otherwise fills the popover, which tracks the trigger width.
196
+ * Number = px.
197
+ */
198
+ calendarWidth?: number | string;
199
+ /** Show an hour / minute picker beside the calendar (`single` mode). */
200
+ showTime?: boolean;
201
+ /** Minute granularity for the time picker. Default 5. */
202
+ timeStep?: number;
203
+ /** Month to show first when there's no value yet. */
204
+ defaultMonth?: Date;
205
+ /** One-click shortcuts rendered in a side rail. */
206
+ presets?: DatePickerPreset[];
142
207
  /** Render the calendar always, without a text field. */
143
208
  inline?: boolean;
144
- /** Allow typing a date into the field. Default true. */
209
+ /** Allow typing a date into the field (`single` mode only). Default true. */
145
210
  allowInput?: boolean;
146
211
  closeOnSelect?: boolean;
212
+ /** Controlled open state of the popover. */
213
+ open?: boolean;
214
+ defaultOpen?: boolean;
215
+ onOpenChange?: (open: boolean) => void;
147
216
  placeholder?: string;
148
217
  }
218
+ interface DatePickerSingleProps extends DatePickerCommonProps {
219
+ mode?: "single";
220
+ value?: Date | string | null;
221
+ defaultValue?: Date | string | null;
222
+ onChange?: (value: Date | null) => void;
223
+ }
224
+ interface DatePickerRangeProps extends DatePickerCommonProps {
225
+ mode: "range";
226
+ value?: LooseRange;
227
+ defaultValue?: LooseRange;
228
+ onChange?: (value: DatePickerRange) => void;
229
+ }
230
+ interface DatePickerMultipleProps extends DatePickerCommonProps {
231
+ mode: "multiple";
232
+ value?: Array<Date | string> | null;
233
+ defaultValue?: Array<Date | string> | null;
234
+ onChange?: (value: Date[]) => void;
235
+ }
236
+ type DatePickerProps = DatePickerSingleProps | DatePickerRangeProps | DatePickerMultipleProps;
149
237
  declare const DatePicker: react.ForwardRefExoticComponent<DatePickerProps & react.RefAttributes<HTMLInputElement>>;
150
238
 
239
+ /** `pattern` accepts a RegExp, a source string, or `{ value, flags }`. */
240
+ type PatternRule = RegExp | string | {
241
+ value: string | RegExp;
242
+ flags?: string;
243
+ };
244
+ /** `equals` accepts a literal, or `{ field }` to compare against another field. */
245
+ type EqualsRule = unknown | {
246
+ field: string;
247
+ };
248
+ /** Custom per-field validator. String = message, `false` = generic failure. */
249
+ type CustomValidator = (value: unknown, allValues: Record<string, unknown>) => string | boolean | null | Promise<string | boolean | null>;
151
250
  /**
152
- * Per-field validation config. V1 ships `required` / `minLength` / `maxLength`.
153
- * Future rule keys (regex, email, min, max, validate, ...) are added here without
154
- * a breaking change.
251
+ * Per-field validation config. All keys are optional and additive.
252
+ * Custom rules registered with `registerRule` add their own keys here via
253
+ * module augmentation, or are accepted loosely.
155
254
  */
156
255
  interface FieldValidation {
157
256
  required?: boolean;
257
+ /** String / array length. */
158
258
  minLength?: number;
159
259
  maxLength?: number;
260
+ /** Array item count (checkbox groups, multi-selects). */
261
+ minItems?: number;
262
+ maxItems?: number;
263
+ /** Numeric bounds (value coerced to number). */
264
+ min?: number;
265
+ max?: number;
266
+ integer?: boolean;
267
+ /** Date bounds (value + param coerced to a timestamp). */
268
+ minDate?: string | Date;
269
+ maxDate?: string | Date;
270
+ /** Range-mode day-span bounds (inclusive; a single day counts as 1). */
271
+ minRangeDays?: number;
272
+ maxRangeDays?: number;
273
+ email?: boolean;
274
+ url?: boolean;
275
+ pattern?: PatternRule;
276
+ /** Value must be one of these. */
277
+ oneOf?: unknown[];
278
+ /** Equal to a literal, or to another field's value: `{ field: "password" }`. */
279
+ equals?: EqualsRule;
280
+ /** Custom validator — sync or async. */
281
+ validate?: CustomValidator;
160
282
  /** Per-rule message overrides, e.g. `{ required: "Name is required" }`. */
161
283
  messages?: Partial<Record<string, string>>;
284
+ /** Allow custom `registerRule` keys without a type error. */
285
+ [rule: string]: unknown;
162
286
  }
163
287
  /** A single validation failure. Shape is frozen — new fields must stay optional. */
164
288
  interface FieldError {
165
- /** Rule that failed: `"required"`, `"minLength"`, `"custom"`, `"async"`, ... */
289
+ /** Rule that failed: `"required"`, `"minLength"`, `"pattern"`, `"validate"`, `"schema"`, ... */
166
290
  rule: string;
167
291
  message: string;
168
- /** Reserved for cross-field / nested errors. Unused in V1. */
292
+ /** Dotted path for cross-field / nested errors. */
169
293
  path?: string;
170
294
  }
171
295
  /**
@@ -183,17 +307,17 @@ interface ValidationContext {
183
307
  trigger: ValidationTrigger;
184
308
  }
185
309
  /**
186
- * The single seam through which all validation flows. V1's default resolver is
187
- * rule-based and synchronous; the `Promise` return type keeps async, schema, and
188
- * cross-field validation additive.
310
+ * The single seam through which all validation flows. The default resolver is
311
+ * rule-based; the `Promise` return keeps async, schema, and cross-field
312
+ * validation additive.
189
313
  */
190
314
  type ValidationResolver = (values: Record<string, unknown>, config: FieldsetConfig, context: ValidationContext) => ValidationResult | Promise<ValidationResult>;
191
315
  /**
192
316
  * A single rule implementation. Returns an error message string on failure, or
193
- * `null` on success. `allValues` is passed so cross-field rules need no
194
- * signature change later.
317
+ * `null` on success — synchronously or as a Promise. `allValues` is passed so
318
+ * cross-field rules need no signature change.
195
319
  */
196
- type RuleFn = (value: unknown, param: unknown, allValues: Record<string, unknown>) => string | null;
320
+ type RuleFn = (value: unknown, param: unknown, allValues: Record<string, unknown>) => string | null | Promise<string | null>;
197
321
 
198
322
  /** A single selectable option for `Dropdown` / a {@link DropdownFieldConfig}. */
199
323
  interface DropdownOption {
@@ -213,6 +337,18 @@ interface ColumnSpec {
213
337
  tablet: number;
214
338
  mobile: number;
215
339
  }
340
+ /**
341
+ * Show / validate a field only when a condition holds. An object targets one
342
+ * other field; a function gets all values.
343
+ */
344
+ type FieldCondition = {
345
+ field: string;
346
+ eq?: unknown;
347
+ ne?: unknown;
348
+ in?: unknown[];
349
+ notIn?: unknown[];
350
+ truthy?: boolean;
351
+ } | ((values: Record<string, unknown>) => boolean);
216
352
  /** Fields common to every field type. */
217
353
  interface BaseFieldConfig {
218
354
  /** Unique key within the fieldset; also the key in the values object. */
@@ -224,20 +360,143 @@ interface BaseFieldConfig {
224
360
  readOnly?: boolean;
225
361
  defaultValue?: unknown;
226
362
  validation?: FieldValidation;
363
+ /** Render + validate this field only when the condition holds. */
364
+ when?: FieldCondition;
227
365
  /** Field-level column span, overriding the fieldset's `columns`. */
228
366
  layout?: Partial<ColumnSpec>;
367
+ /** `sm` / `md` / `lg`. */
368
+ size?: "sm" | "md" | "lg";
369
+ /** `outline` / `filled` / `flushed` / `unstyled`. */
370
+ variant?: "outline" | "filled" | "flushed" | "unstyled";
371
+ /** Float the label into the control border. */
372
+ floatingLabel?: boolean;
229
373
  /** Escape hatch: spread verbatim onto the underlying control. */
230
374
  props?: Record<string, unknown>;
231
375
  }
232
- /** Native `<input>` field. `inputType` maps to the DOM `type` attribute. */
376
+ /** Single-line text field. */
233
377
  interface InputFieldConfig extends BaseFieldConfig {
234
378
  type: "input";
235
- inputType?: "text" | "email" | "password" | "number" | "tel" | "url";
379
+ inputType?: "text" | "email" | "password" | "search" | "tel" | "url";
380
+ prefix?: string;
381
+ suffix?: string;
382
+ /** Segments attached outside the border. */
383
+ addonBefore?: string;
384
+ addonAfter?: string;
385
+ clearable?: boolean;
386
+ maxLength?: number;
387
+ /** Live character counter. */
388
+ showCount?: boolean;
389
+ /** Debounce `onChange` by N ms. */
390
+ debounce?: number;
391
+ /** Virtual-keyboard hint. */
392
+ inputMode?: "text" | "numeric" | "decimal" | "tel" | "email" | "url" | "search";
393
+ /** HTML `pattern` for native validation. */
394
+ pattern?: string;
395
+ }
396
+ /** Multi-line text field. */
397
+ interface TextareaFieldConfig extends BaseFieldConfig {
398
+ type: "textarea";
399
+ rows?: number;
400
+ maxRows?: number;
401
+ autoResize?: boolean;
402
+ resize?: "none" | "vertical" | "both";
403
+ maxLength?: number;
404
+ showCount?: boolean;
405
+ /** Enter (no Shift) submits and suppresses the newline. */
406
+ submitOnEnter?: boolean;
236
407
  }
237
- /** Native `<select>` field. */
408
+ /** Numeric field with steppers + Intl formatting. Value is `number | null`. */
409
+ interface NumberFieldConfig extends BaseFieldConfig {
410
+ type: "number";
411
+ min?: number;
412
+ max?: number;
413
+ step?: number;
414
+ precision?: number;
415
+ /** Alias for `precision`. */
416
+ decimalScale?: number;
417
+ currency?: string;
418
+ /** `decimal` | `currency` | `percent` | `unit`. */
419
+ style?: "decimal" | "currency" | "percent" | "unit";
420
+ locale?: string;
421
+ prefix?: string;
422
+ suffix?: string;
423
+ /** Override the locale thousands separator. */
424
+ thousandSeparator?: string;
425
+ /** Allow values below zero. Default true. */
426
+ allowNegative?: boolean;
427
+ /** `strict` | `blur` | `none`. */
428
+ clampBehavior?: "strict" | "blur" | "none";
429
+ /** Hide the stepper buttons. */
430
+ hideControls?: boolean;
431
+ }
432
+ /** Combobox (searchable listbox). */
238
433
  interface DropdownFieldConfig extends BaseFieldConfig {
239
434
  type: "dropdown";
240
435
  options: DropdownOption[];
436
+ searchable?: boolean;
437
+ multiple?: boolean;
438
+ clearable?: boolean;
439
+ /** Allow inventing an option from the query (needs `searchable`). */
440
+ creatable?: boolean;
441
+ /** Multiple: cap how many options can be chosen. */
442
+ maxValues?: number;
443
+ /** Multiple: hide options already selected. */
444
+ hidePickedOptions?: boolean;
445
+ /** Multiple: show a Select all / Clear row. */
446
+ showSelectAll?: boolean;
447
+ /** Debounce, in ms, before the field's search would hit a server. */
448
+ searchDebounce?: number;
449
+ }
450
+ /**
451
+ * Calendar date field. Value is an ISO date string (`yyyy-MM-dd`) for `single`,
452
+ * `{ start, end }` ISO strings for `range`, or `string[]` for `multiple`.
453
+ */
454
+ interface DateFieldConfig extends BaseFieldConfig {
455
+ type: "date";
456
+ format?: string;
457
+ /** Selection model. Default `"single"`. */
458
+ mode?: "single" | "range" | "multiple";
459
+ /** Drill depth: `"day"` (default), `"month"`, or `"year"`. */
460
+ precision?: "day" | "month" | "year";
461
+ minDate?: string | Date;
462
+ maxDate?: string | Date;
463
+ showToday?: boolean;
464
+ clearable?: boolean;
465
+ /** Side-rail shortcuts. `value` matches `mode` (ISO strings). */
466
+ presets?: Array<{
467
+ label: string;
468
+ value: string | {
469
+ start: string;
470
+ end: string;
471
+ } | string[];
472
+ }>;
473
+ }
474
+ /** A single boolean checkbox. Value is `boolean`. */
475
+ interface CheckboxFieldConfig extends BaseFieldConfig {
476
+ type: "checkbox";
477
+ /** Text shown next to the box (falls back to `label`). */
478
+ checkboxLabel?: string;
479
+ }
480
+ /** A set of checkboxes. Value is `string[]`. */
481
+ interface CheckboxGroupFieldConfig extends BaseFieldConfig {
482
+ type: "checkbox-group";
483
+ options: DropdownOption[];
484
+ orientation?: "vertical" | "horizontal";
485
+ /** Lay the options out in an N-column grid. */
486
+ columns?: number;
487
+ /** Show a "select all" checkbox. */
488
+ showSelectAll?: boolean;
489
+ min?: number;
490
+ max?: number;
491
+ }
492
+ /** A radio group. Value is `string`. */
493
+ interface RadioFieldConfig extends BaseFieldConfig {
494
+ type: "radio";
495
+ options: DropdownOption[];
496
+ orientation?: "vertical" | "horizontal";
497
+ /** Lay the options out in an N-column grid. */
498
+ columns?: number;
499
+ radioVariant?: "default" | "card";
241
500
  }
242
501
  /**
243
502
  * Maps a field `type` string to its config shape. Consumers register custom
@@ -253,7 +512,13 @@ interface DropdownFieldConfig extends BaseFieldConfig {
253
512
  */
254
513
  interface FieldConfigRegistry {
255
514
  input: InputFieldConfig;
515
+ textarea: TextareaFieldConfig;
516
+ number: NumberFieldConfig;
256
517
  dropdown: DropdownFieldConfig;
518
+ date: DateFieldConfig;
519
+ checkbox: CheckboxFieldConfig;
520
+ "checkbox-group": CheckboxGroupFieldConfig;
521
+ radio: RadioFieldConfig;
257
522
  }
258
523
  /** Discriminated union of every registered field config. */
259
524
  type FieldConfig = FieldConfigRegistry[keyof FieldConfigRegistry];
@@ -264,13 +529,27 @@ interface FieldsetConfig {
264
529
  fields: FieldConfig[];
265
530
  /** Rendered in a `<legend>` when present. */
266
531
  legend?: string;
267
- /** Columns per breakpoint. Defaults to `{ desktop: 3, tablet: 2, mobile: 1 }`. */
268
- columns?: Partial<ColumnSpec>;
532
+ /**
533
+ * Column layout. A **number** means "use up to N columns, fluidly, down to
534
+ * one when narrow". An **object** snaps to exact counts at wide / medium /
535
+ * narrow container widths. Defaults to `{ desktop: 3, tablet: 2, mobile: 1 }`.
536
+ */
537
+ columns?: Partial<ColumnSpec> | number;
538
+ /**
539
+ * Minimum comfortable width for a single column (number = px, or a CSS length
540
+ * like `"14rem"`). Drives when the grid adds/removes columns. Default `192`.
541
+ */
542
+ minColumnWidth?: string | number;
269
543
  /** Grid gap; a number is treated as pixels. */
270
544
  gap?: string | number;
271
545
  id?: string;
272
546
  }
273
547
 
548
+ /** Options may also be passed pre-grouped. */
549
+ interface DropdownOptionGroup {
550
+ group: string;
551
+ items: DropdownOption[];
552
+ }
274
553
  interface OptionState {
275
554
  selected: boolean;
276
555
  active: boolean;
@@ -279,7 +558,7 @@ interface OptionState {
279
558
  query: string;
280
559
  }
281
560
  interface DropdownProps extends Omit<BaseControlProps, "startContent" | "endContent"> {
282
- options: DropdownOption[];
561
+ options: DropdownOption[] | DropdownOptionGroup[];
283
562
  value?: string | string[] | null;
284
563
  defaultValue?: string | string[] | null;
285
564
  onChange?: (value: string | string[] | null) => void;
@@ -292,15 +571,40 @@ interface DropdownProps extends Omit<BaseControlProps, "startContent" | "endCont
292
571
  highlightMatch?: boolean;
293
572
  renderOption?: (option: DropdownOption, state: OptionState) => ReactNode;
294
573
  renderValue?: (selected: DropdownOption[]) => ReactNode;
574
+ renderGroupLabel?: (label: string) => ReactNode;
295
575
  placeholder?: string;
296
576
  emptyMessage?: ReactNode;
577
+ /** Shown in place of `emptyMessage` while `loading` and there are no options. */
578
+ loadingMessage?: ReactNode;
297
579
  /** Close the panel after a pick. Default true for single, false for multiple. */
298
580
  closeOnSelect?: boolean;
299
581
  /** Cap the chips shown before "+N". */
300
582
  maxSelectedLabels?: number;
583
+ /** Multiple: cap how many options can be selected. */
584
+ maxValues?: number;
585
+ /** Multiple: drop already-selected options from the list. */
586
+ hidePickedOptions?: boolean;
587
+ /** Multiple: show a "Select all / Clear" action row. */
588
+ showSelectAll?: boolean;
301
589
  /** Fall back to a native `<select>` (single, no search). */
302
590
  native?: boolean;
303
591
  startContent?: ReactNode;
592
+ /** Allow creating an option from the current query (needs `searchable`). */
593
+ creatable?: boolean;
594
+ onCreate?: (inputValue: string) => void;
595
+ /** Gate the create row. Default: non-empty query with no exact label match. */
596
+ isValidNewOption?: (inputValue: string, options: DropdownOption[]) => boolean;
597
+ formatCreateLabel?: (inputValue: string) => ReactNode;
598
+ createPosition?: "first" | "last";
599
+ /** Fires (debounced) as the query changes; disables local filtering. */
600
+ onSearch?: (query: string) => void;
601
+ searchDebounce?: number;
602
+ /** Controlled panel open state. */
603
+ open?: boolean;
604
+ defaultOpen?: boolean;
605
+ onOpenChange?: (open: boolean) => void;
606
+ /** Cap the listbox height, px. */
607
+ maxHeight?: number;
304
608
  }
305
609
  declare const Dropdown: react.ForwardRefExoticComponent<DropdownProps & react.RefAttributes<HTMLInputElement>>;
306
610
 
@@ -325,12 +629,25 @@ interface ControlProps<TValue = unknown> {
325
629
  describedById?: string;
326
630
  /** The full field config, for type-specific data (e.g. dropdown `options`). */
327
631
  config: FieldConfig;
632
+ /**
633
+ * Only set for `selfContained` registrations (the component renders its own
634
+ * `<Field>`): the field's label / description, and the current error messages.
635
+ */
636
+ label?: string;
637
+ description?: string;
638
+ errors?: string[];
328
639
  }
329
640
  /** A React component that satisfies {@link ControlProps}. */
330
641
  type ControlComponent<TValue = any> = ComponentType<ControlProps<TValue>>;
331
642
  /** A registry entry for one field `type`. */
332
643
  interface FieldRegistration<TValue = any> {
333
644
  component: ControlComponent<TValue>;
645
+ /**
646
+ * The component renders its own `<Field>` (label / description / error). When
647
+ * true, `FieldRenderer` does not wrap it, and passes `label` / `description` /
648
+ * `errors` on {@link ControlProps} instead of `describedById`.
649
+ */
650
+ selfContained?: boolean;
334
651
  /** Value used when neither the config nor the form supplies one. */
335
652
  defaultValue?: TValue;
336
653
  /** Normalize an incoming value before it reaches the control. */
@@ -423,6 +740,11 @@ interface FieldsetProps<TValues extends Record<string, unknown> = Record<string,
423
740
  declare function Field(props: FieldProps): react.JSX.Element;
424
741
 
425
742
  type NativeInput = Omit<InputHTMLAttributes<HTMLInputElement>, "value" | "defaultValue" | "onChange" | "type" | "size" | "prefix">;
743
+ /** `showCount` config: `true`, or an object with a cap + a custom formatter. */
744
+ type ShowCount = boolean | {
745
+ max?: number;
746
+ formatter?: (count: number, max?: number) => ReactNode;
747
+ };
426
748
  interface InputProps extends BaseControlProps, NativeInput {
427
749
  value?: string;
428
750
  defaultValue?: string;
@@ -434,41 +756,91 @@ interface InputProps extends BaseControlProps, NativeInput {
434
756
  prefix?: ReactNode;
435
757
  /** Static text glued to the end (e.g. `.com`). */
436
758
  suffix?: ReactNode;
759
+ /** Segment attached before the field, outside the border. */
760
+ addonBefore?: ReactNode;
761
+ /** Segment attached after the field, outside the border. */
762
+ addonAfter?: ReactNode;
437
763
  /** Show a show/hide toggle (implied for `type="password"`). */
438
764
  passwordToggle?: boolean;
439
- /** Show a live character counter. Pairs well with `maxLength`. */
440
- showCount?: boolean;
765
+ /** Controlled reveal state for a password field. */
766
+ passwordVisible?: boolean;
767
+ onPasswordVisibleChange?: (visible: boolean) => void;
768
+ /** Custom toggle icon; gets the current reveal state. */
769
+ visibilityToggleIcon?: (revealed: boolean) => ReactNode;
770
+ /** Show a live character counter. Pass an object for a cap / custom render. */
771
+ showCount?: ShowCount;
772
+ /** Debounce `onChange` by this many ms (drive uncontrolled to avoid lag). */
773
+ debounce?: number;
441
774
  }
442
775
  declare const Input: react.ForwardRefExoticComponent<InputProps & react.RefAttributes<HTMLInputElement>>;
443
776
 
444
- type NativeNumberInput = Omit<InputHTMLAttributes<HTMLInputElement>, "value" | "defaultValue" | "onChange" | "type" | "min" | "max" | "step" | "size" | "prefix">;
777
+ type NativeNumberInput = Omit<InputHTMLAttributes<HTMLInputElement>, "value" | "defaultValue" | "onChange" | "type" | "min" | "max" | "step" | "size" | "prefix" | "style">;
778
+ type ClampBehavior = "strict" | "blur" | "none";
445
779
  interface NumberFieldProps extends BaseControlProps, NativeNumberInput {
446
780
  value?: number | null;
447
781
  defaultValue?: number | null;
448
782
  onChange?: (value: number | null) => void;
783
+ /** Fires alongside `onChange` with the formatted string too. */
784
+ onValueChange?: (payload: {
785
+ value: number | null;
786
+ formatted: string;
787
+ }) => void;
449
788
  min?: number;
450
789
  max?: number;
451
790
  step?: number;
452
791
  /** Larger step for Shift+Arrow / PageUp-Down. Default `step * 10`. */
453
792
  shiftStep?: number;
454
- /** Decimal places to keep. */
793
+ /** Smaller step for Alt+Arrow. Default `step / 10`. */
794
+ smallStep?: number;
795
+ /** Decimal places to keep. Alias: `decimalScale`. */
455
796
  precision?: number;
797
+ decimalScale?: number;
798
+ /** Pad to `decimalScale` with trailing zeros. */
799
+ fixedDecimalScale?: boolean;
456
800
  /** Stepper buttons. Default `"stacked"`. */
457
801
  buttons?: "stacked" | "horizontal" | false;
802
+ /** Alias for `buttons={false}`. */
803
+ hideControls?: boolean;
458
804
  /** Group thousands (`1,000`). */
459
805
  grouping?: boolean;
806
+ /** Override the locale's thousands separator. */
807
+ thousandSeparator?: string;
808
+ /** Override the locale's decimal separator. */
809
+ decimalSeparator?: string;
460
810
  /** BCP-47 locale for formatting. */
461
811
  locale?: string;
462
- /** ISO currency code renders as currency. */
812
+ /** Number style. `currency` needs `currency`; `unit` needs `unit`. */
813
+ style?: "decimal" | "currency" | "percent" | "unit";
814
+ /** ISO currency code (implies `style="currency"`). */
463
815
  currency?: string;
816
+ /** Intl unit identifier for `style="unit"` (e.g. `"kilogram"`). */
817
+ unit?: string;
818
+ /** Raw `Intl.NumberFormatOptions` — wins over the individual knobs. */
819
+ formatOptions?: Intl.NumberFormatOptions;
820
+ /** Fully custom display. */
821
+ format?: (value: number) => string;
822
+ /** Fully custom parse. */
823
+ parse?: (text: string) => number | null;
464
824
  /** Text before the number. */
465
825
  prefix?: string;
466
826
  /** Text after the number (e.g. `%`, `kg`). */
467
827
  suffix?: string;
468
- /** Clamp to `[min, max]` on blur. Default true. */
828
+ /** Allow values below zero. Default true. */
829
+ allowNegative?: boolean;
830
+ /** `"strict"` (never leaves range) · `"blur"` (default) · `"none"`. */
831
+ clampBehavior?: ClampBehavior;
832
+ /** Deprecated alias — `false` maps to `clampBehavior="none"`. */
469
833
  clampOnBlur?: boolean;
834
+ /** Value committed for an empty field. Default `null`. */
835
+ emptyValue?: number | null;
470
836
  /** Step with the mouse wheel while focused. Default false. */
471
837
  allowMouseWheel?: boolean;
838
+ /** Inverse of `allowMouseWheel`. */
839
+ isWheelDisabled?: boolean;
840
+ /** Delay before hold-to-repeat kicks in, ms. Default 300. */
841
+ stepHoldDelay?: number;
842
+ /** Interval between repeats while held, ms. Default 60. */
843
+ stepHoldInterval?: number;
472
844
  }
473
845
  declare const NumberField: react.ForwardRefExoticComponent<NumberFieldProps & react.RefAttributes<HTMLInputElement>>;
474
846
 
@@ -488,6 +860,8 @@ interface RadioOption {
488
860
  label: ReactNode;
489
861
  value: string;
490
862
  description?: ReactNode;
863
+ /** Leading icon shown before the label. */
864
+ icon?: ReactNode;
491
865
  disabled?: boolean;
492
866
  }
493
867
  interface RadioGroupProps {
@@ -504,6 +878,8 @@ interface RadioGroupProps {
504
878
  defaultValue?: string | null;
505
879
  onChange?: (value: string) => void;
506
880
  orientation?: "vertical" | "horizontal";
881
+ /** Lay the options out in an N-column grid. */
882
+ columns?: number;
507
883
  options?: RadioOption[];
508
884
  children?: ReactNode;
509
885
  className?: string;
@@ -512,17 +888,22 @@ interface RadioGroupProps {
512
888
  declare function RadioGroup(props: RadioGroupProps): react.JSX.Element;
513
889
 
514
890
  type NativeTextarea = Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, "value" | "defaultValue" | "onChange" | "rows" | "cols">;
515
- interface TextareaProps extends Omit<BaseControlProps, "startContent" | "endContent" | "loading">, NativeTextarea {
891
+ interface TextareaProps extends Omit<BaseControlProps, "startContent">, NativeTextarea {
516
892
  value?: string;
517
893
  defaultValue?: string;
518
894
  onChange?: (value: string, event: ChangeEvent<HTMLTextAreaElement>) => void;
895
+ /** Fired on Enter (without Shift). */
896
+ onEnter?: (value: string) => void;
897
+ /** Enter (no Shift) fires `onEnter` and suppresses the newline. */
898
+ submitOnEnter?: boolean;
519
899
  /** Grow with content between `minRows` and `maxRows`. */
520
900
  autoResize?: boolean;
521
901
  minRows?: number;
522
902
  maxRows?: number;
523
903
  /** Native resize handle. Default `"vertical"` (`"none"` when `autoResize`). */
524
904
  resize?: "none" | "vertical" | "both";
525
- showCount?: boolean;
905
+ /** Live counter — `true`, or `{ max?, formatter?(count, max) }`. */
906
+ showCount?: ShowCount;
526
907
  }
527
908
  declare const Textarea: react.ForwardRefExoticComponent<TextareaProps & react.RefAttributes<HTMLTextAreaElement>>;
528
909
 
@@ -530,66 +911,10 @@ declare const Textarea: react.ForwardRefExoticComponent<TextareaProps & react.Re
530
911
  * Renders a form (or a form section) from a `FieldsetConfig`. Controlled when
531
912
  * `value` is passed, uncontrolled otherwise. Renders a native `<fieldset>` — so
532
913
  * `disabled` cascades to every control — and does not render its own `<form>`;
533
- * wrap it in one and use `useFieldsetState().handleSubmit` for submission.
914
+ * wrap it in one and use `useFieldsetState().handleSubmit`, or use `<Form>`.
534
915
  */
535
916
  declare function Fieldset<TValues extends Record<string, unknown> = Record<string, unknown>>(props: FieldsetProps<TValues>): react.JSX.Element;
536
917
 
537
- /** Built-in colour presets. Each maps to `[data-orynn-theme="…"]` in the stylesheet. */
538
- type OrynnPreset = "default" | "slate" | "teal" | "violet" | "rose" | "emerald";
539
- /** Vertical rhythm / sizing. Maps to `[data-orynn-density="…"]`. */
540
- type OrynnDensity = "compact" | "comfortable" | "spacious";
541
- type OrynnRadius = "none" | "sm" | "md" | "lg" | "pill" | (string & {}) | number;
542
- /** Any `--orynn-*` custom property. */
543
- type OrynnVarOverrides = Partial<Record<`--orynn-${string}`, string | number>>;
544
- interface OrynnThemeConfig {
545
- /** Colour preset. Defaults to `"default"` (indigo). */
546
- preset?: OrynnPreset;
547
- density?: OrynnDensity;
548
- /** Highlight / accent colour. Any CSS colour — overrides the preset's accent. */
549
- accent?: string;
550
- /** Foreground colour to pair with a custom `accent` (auto-picked from luminance if omitted). */
551
- accentContrast?: string;
552
- /** `--orynn-font-family`. */
553
- font?: string;
554
- /** Base font size, e.g. `"15px"` or `"0.95rem"`. */
555
- fontSize?: string | number;
556
- /** Corner radius applied to controls. Keyword, CSS length, or px number. */
557
- radius?: OrynnRadius;
558
- /** Default control width. `"100%"` by default; e.g. `"20rem"` or `320`. */
559
- controlWidth?: string | number;
560
- /** Focus-ring colour. */
561
- ring?: string;
562
- /** Escape hatch: any `--orynn-*` variables verbatim. */
563
- vars?: OrynnVarOverrides;
564
- }
565
- /** `theme` prop accepts a preset name shorthand or a full config. */
566
- type OrynnThemeInput = OrynnPreset | OrynnThemeConfig;
567
- /** Build the inline CSS-variable style object for a theme config. */
568
- declare function resolveThemeVars(config: OrynnThemeConfig): CSSProperties;
569
-
570
- interface OrynnContextValue {
571
- preset: OrynnPreset;
572
- density: OrynnDensity;
573
- config: OrynnThemeConfig;
574
- }
575
- interface OrynnProviderProps {
576
- /** Preset name (`"teal"`) or a full config object. */
577
- theme?: OrynnThemeInput;
578
- /** Render a `<div>` (default) or a different element / no wrapper (`"contents"`). */
579
- as?: "div" | "span" | "contents";
580
- className?: string;
581
- children: ReactNode;
582
- }
583
- /**
584
- * Scopes an Orynn theme to its subtree by setting `data-orynn-theme`,
585
- * `data-orynn-density` and any custom `--orynn-*` variables on a wrapper element.
586
- * Purely CSS custom properties — no runtime styling engine. Nesting is supported;
587
- * an inner provider overrides only what it sets.
588
- */
589
- declare function OrynnProvider({ theme, as, className, children }: OrynnProviderProps): react.JSX.Element;
590
- /** Read the nearest Orynn theme config. */
591
- declare function useOrynnTheme(): OrynnContextValue;
592
-
593
918
  /** Form-level validation roll-up. */
594
919
  type FieldStatus = "idle" | "validating" | "valid" | "invalid";
595
920
  /** The complete state a fieldset tracks. New keys must be additive. */
@@ -607,6 +932,8 @@ interface FieldsetState {
607
932
  interface NormalizedFieldsetConfig {
608
933
  fields: FieldConfig[];
609
934
  columns: ColumnSpec;
935
+ /** Minimum comfortable width for one column, in px. */
936
+ minColWidth: number;
610
937
  /** CSS length for the grid gap, or `undefined` to use the token default. */
611
938
  gap: string | undefined;
612
939
  legend: string | undefined;
@@ -622,8 +949,8 @@ interface NormalizedFieldsetConfig {
622
949
  */
623
950
  declare function normalizeConfig(config: FieldsetConfig, registry?: FieldRegistry): NormalizedFieldsetConfig;
624
951
 
625
- type Values = Record<string, unknown>;
626
- interface UseFieldsetStateOptions<TValues extends Values = Values> {
952
+ type Values$1 = Record<string, unknown>;
953
+ interface UseFieldsetStateOptions<TValues extends Values$1 = Values$1> {
627
954
  /** Controlled values. Omit and pass `defaultValue` for uncontrolled. */
628
955
  value?: TValues;
629
956
  defaultValue?: Partial<TValues>;
@@ -645,7 +972,7 @@ interface FieldSlice {
645
972
  setValue: (value: unknown) => void;
646
973
  markTouched: () => void;
647
974
  }
648
- interface UseFieldsetStateReturn<TValues extends Values = Values> {
975
+ interface UseFieldsetStateReturn<TValues extends Values$1 = Values$1> {
649
976
  config: NormalizedFieldsetConfig;
650
977
  state: FieldsetState;
651
978
  values: TValues;
@@ -666,7 +993,615 @@ interface UseFieldsetStateReturn<TValues extends Values = Values> {
666
993
  * markup. Manages values (controlled or uncontrolled), touched/dirty tracking,
667
994
  * and validation through a pluggable resolver.
668
995
  */
669
- declare function useFieldsetState<TValues extends Values = Values>(config: FieldsetConfig, options?: UseFieldsetStateOptions<TValues>): UseFieldsetStateReturn<TValues>;
996
+ declare function useFieldsetState<TValues extends Values$1 = Values$1>(config: FieldsetConfig, options?: UseFieldsetStateOptions<TValues>): UseFieldsetStateReturn<TValues>;
997
+
998
+ interface FieldsetViewProps {
999
+ /** The return of `useFieldsetState`. */
1000
+ state: UseFieldsetStateReturn;
1001
+ registry?: FieldRegistry;
1002
+ disabled?: boolean;
1003
+ className?: string;
1004
+ id?: string;
1005
+ }
1006
+ /**
1007
+ * Presentational half of `<Fieldset>` — renders the grid of fields from an
1008
+ * existing `useFieldsetState` instance. Used by `<Fieldset>` and `<Form>` so
1009
+ * they never run the state hook twice.
1010
+ */
1011
+ declare function FieldsetView({ state, registry, disabled, className, id }: FieldsetViewProps): react.JSX.Element;
1012
+
1013
+ type Values = Record<string, unknown>;
1014
+ interface FormProps<TValues extends Values = Values> extends Omit<FormHTMLAttributes<HTMLFormElement>, "onSubmit" | "onInvalid" | "children" | "onChange" | "defaultValue"> {
1015
+ config: FieldsetConfig;
1016
+ value?: TValues;
1017
+ defaultValue?: Partial<TValues>;
1018
+ onChange?: (values: TValues) => void;
1019
+ /** Called with the values when the form passes validation. */
1020
+ onSubmit: (values: TValues, fs: UseFieldsetStateReturn<TValues>) => void;
1021
+ /** Called with the errors when submit is blocked. */
1022
+ onInvalid?: (errors: ValidationResult) => void;
1023
+ resolver?: ValidationResolver;
1024
+ validateOn?: ValidationTrigger;
1025
+ disabled?: boolean;
1026
+ /** Content after the fieldset — usually a submit button. Gets `fs`. */
1027
+ children?: ReactNode | ((fs: UseFieldsetStateReturn<TValues>) => ReactNode);
1028
+ }
1029
+ /**
1030
+ * A `<form>` that owns its state: renders `<Fieldset>` from `config`, and calls
1031
+ * `onSubmit(values)` only when validation passes. `children` (or a render
1032
+ * function receiving the `useFieldsetState` return) is where the submit button
1033
+ * goes.
1034
+ *
1035
+ * ```tsx
1036
+ * <Form config={config} onSubmit={(v) => save(v)}>
1037
+ * {(fs) => <button type="submit" disabled={!fs.isValid}>Save</button>}
1038
+ * </Form>
1039
+ * ```
1040
+ */
1041
+ declare function Form<TValues extends Values = Values>(props: FormProps<TValues>): react.JSX.Element;
1042
+
1043
+ type AccordionVariant = "bordered" | "separated" | "ghost";
1044
+ type AccordionSize = "sm" | "md" | "lg";
1045
+ type RootProps$2 = ComponentPropsWithoutRef<typeof Accordion$1.Root>;
1046
+ type AccordionProps = RootProps$2 & {
1047
+ /** `bordered` (default, dividers) · `separated` (each item a card) · `ghost` (no chrome). */
1048
+ variant?: AccordionVariant;
1049
+ /** Trigger padding + type scale. Default `md`. */
1050
+ size?: AccordionSize;
1051
+ };
1052
+ /**
1053
+ * A stack of collapsible sections. Thin wrapper over Radix Accordion — every
1054
+ * Root prop (`type`, `collapsible`, `value` / `defaultValue`, `onValueChange`,
1055
+ * `disabled`, `orientation`, `dir`) passes straight through.
1056
+ */
1057
+ declare const Accordion: react.ForwardRefExoticComponent<AccordionProps & react.RefAttributes<HTMLDivElement>>;
1058
+ declare const AccordionItem: react.ForwardRefExoticComponent<Omit<Accordion$1.AccordionItemProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1059
+ interface AccordionTriggerProps extends ComponentPropsWithoutRef<typeof Accordion$1.Trigger> {
1060
+ /** Indicator icon. Defaults to a chevron that rotates on open. */
1061
+ icon?: ReactNode;
1062
+ /** Which side the icon sits on. Default `end`. */
1063
+ iconPosition?: "start" | "end";
1064
+ /** Drop the indicator entirely. */
1065
+ hideIcon?: boolean;
1066
+ }
1067
+ declare const AccordionTrigger: react.ForwardRefExoticComponent<AccordionTriggerProps & react.RefAttributes<HTMLButtonElement>>;
1068
+ declare const AccordionContent: react.ForwardRefExoticComponent<Omit<Accordion$1.AccordionContentProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1069
+
1070
+ type ButtonVariant = "default" | "secondary" | "destructive" | "outline" | "ghost" | "link";
1071
+ type ButtonSize = "default" | "sm" | "lg" | "icon";
1072
+ type ButtonHoverEffect = "darken" | "lift" | "glow" | "outline-fill" | "none";
1073
+ type ButtonFocusStyle = "ring" | "solid" | "ring-inset" | "none";
1074
+ type ButtonCursor = "pointer" | "default" | "auto";
1075
+ type BadgeVariant = "default" | "secondary" | "destructive" | "outline";
1076
+ /**
1077
+ * Class list for a shadcn-style button. Exported so a non-`<button>` element can
1078
+ * be styled as one: `<a className={buttonClasses("outline")}>…</a>`.
1079
+ */
1080
+ declare function buttonClasses(variant?: ButtonVariant, size?: ButtonSize): string;
1081
+ /** Class list for a badge — same idea as {@link buttonClasses}. */
1082
+ declare function badgeClasses(variant?: BadgeVariant): string;
1083
+
1084
+ interface ButtonProps extends ComponentProps<"button"> {
1085
+ /** default · secondary · destructive · outline · ghost · link */
1086
+ variant?: ButtonVariant;
1087
+ /** default (h-9) · sm (h-8) · lg (h-10) · icon (square) */
1088
+ size?: ButtonSize;
1089
+ /** Render `children` as the button, merging button props/classes onto it. */
1090
+ asChild?: boolean;
1091
+ /** Show a spinner and disable the button. */
1092
+ loading?: boolean;
1093
+ /** Replaces the label while `loading`. */
1094
+ loadingText?: ReactNode;
1095
+ /** Icon before the label (ignored with `asChild`). */
1096
+ leftIcon?: ReactNode;
1097
+ /** Icon after the label (ignored with `asChild`). */
1098
+ rightIcon?: ReactNode;
1099
+ /** Stretch to the container width. */
1100
+ fullWidth?: boolean;
1101
+ /**
1102
+ * Hover treatment. `"darken"` (default) shades the fill; `"lift"` adds a
1103
+ * raise + shadow; `"glow"` adds a soft ring; `"outline-fill"` floods the
1104
+ * fill on hover (nice on `ghost` / `outline`); `"none"` disables the hover
1105
+ * change. Retune via `--orynn-button-hover-*` / `--orynn-button-glow`.
1106
+ */
1107
+ hoverEffect?: ButtonHoverEffect;
1108
+ /**
1109
+ * Focus-visible treatment. `"ring"` (default) = border + soft ring halo;
1110
+ * `"solid"` = a crisp outline; `"ring-inset"` = the halo drawn inside the
1111
+ * edge; `"none"` = no focus styling (supply your own).
1112
+ */
1113
+ focusStyle?: ButtonFocusStyle;
1114
+ /**
1115
+ * Pressed / active state — a token-styled toggle look. Also sets
1116
+ * `aria-pressed`. Retune via `--orynn-button-selected-*`.
1117
+ */
1118
+ selected?: boolean;
1119
+ /** Idle cursor. `"pointer"` (default) · `"default"` · `"auto"`. */
1120
+ cursor?: ButtonCursor;
1121
+ }
1122
+ declare const Button: react.ForwardRefExoticComponent<Omit<ButtonProps, "ref"> & react.RefAttributes<HTMLButtonElement>>;
1123
+
1124
+ type RootProps$1 = ComponentPropsWithoutRef<typeof Slider$1.Root>;
1125
+ interface SliderMark {
1126
+ value: number;
1127
+ label?: ReactNode;
1128
+ }
1129
+ interface SliderProps extends Omit<RootProps$1, "value" | "defaultValue" | "asChild"> {
1130
+ /** Controlled value. A scalar is treated as a single-thumb slider. */
1131
+ value?: number | number[];
1132
+ /** Uncontrolled initial value. Scalar → one thumb. Default `min`. */
1133
+ defaultValue?: number | number[];
1134
+ /** Track / thumb scale. Default `md`. */
1135
+ size?: "sm" | "md" | "lg";
1136
+ /** Ticks + labels pinned under the track at these values. */
1137
+ marks?: SliderMark[];
1138
+ /** Render a tick at every `step` (skipped when that would be > 60 ticks). */
1139
+ showTicks?: boolean;
1140
+ /** Value bubble over the thumb. Default `"none"`. */
1141
+ tooltip?: "always" | "hover" | "none";
1142
+ /** Format the tooltip / aria value text. */
1143
+ formatValue?: (value: number) => ReactNode;
1144
+ }
1145
+ declare const Slider: react.ForwardRefExoticComponent<SliderProps & react.RefAttributes<HTMLSpanElement>>;
1146
+
1147
+ type RootProps = ComponentPropsWithoutRef<typeof Progress$1.Root>;
1148
+ interface ProgressProps extends Omit<RootProps, "value" | "getValueLabel"> {
1149
+ /** 0–`max`, or `null` / omitted for an indeterminate bar. */
1150
+ value?: number | null;
1151
+ max?: number;
1152
+ /** `line` (default) or `circle`. */
1153
+ shape?: "line" | "circle";
1154
+ /** Thickness / diameter scale. Default `md`. */
1155
+ size?: "sm" | "md" | "lg";
1156
+ /** Colour role. Default `default` (primary). */
1157
+ variant?: "default" | "success" | "warning" | "destructive";
1158
+ /** Render the percentage (line: trailing; circle: centred). */
1159
+ showValue?: boolean;
1160
+ /** Text shown alongside the bar (line only). */
1161
+ label?: ReactNode;
1162
+ /** Diagonal stripes (line only). */
1163
+ striped?: boolean;
1164
+ /** Animate the stripes (implies `striped`, line only). */
1165
+ animated?: boolean;
1166
+ /** Corner radius override for the line track. */
1167
+ radius?: string | number;
1168
+ /** Ring stroke width, px (circle only). Default 4 / 5 / 6 by size. */
1169
+ circleThickness?: number;
1170
+ /** Ring diameter, px (circle only). Default 40 / 56 / 72 by size. */
1171
+ circleSize?: number;
1172
+ /** Format the value text. */
1173
+ formatValue?: (value: number, max: number) => ReactNode;
1174
+ }
1175
+ declare const Progress: react.ForwardRefExoticComponent<ProgressProps & react.RefAttributes<HTMLDivElement>>;
1176
+
1177
+ type ToastVariant = "default" | "success" | "error" | "warning" | "info" | "loading";
1178
+ interface ToastAction {
1179
+ label: ReactNode;
1180
+ onClick: () => void;
1181
+ /** Screen-reader text for the action (Radix requires it). Defaults to the label if it's a string. */
1182
+ altText?: string;
1183
+ }
1184
+ interface ToastOptions {
1185
+ id?: string;
1186
+ title?: ReactNode;
1187
+ description?: ReactNode;
1188
+ variant?: ToastVariant;
1189
+ /** ms before auto-dismiss. `0` / `Infinity` = sticky. Falls back to the Toaster's `duration`. */
1190
+ duration?: number;
1191
+ action?: ToastAction;
1192
+ /** Custom leading icon. `null` hides the default variant icon. */
1193
+ icon?: ReactNode | null;
1194
+ /** Show the close button for this toast (defaults to the Toaster setting). */
1195
+ dismissible?: boolean;
1196
+ onOpenChange?: (open: boolean) => void;
1197
+ }
1198
+ interface ToastRecord extends ToastOptions {
1199
+ id: string;
1200
+ createdAt: number;
1201
+ }
1202
+ type ToastInput = ReactNode | ToastOptions;
1203
+ interface ToastFn {
1204
+ (message: ToastInput, opts?: ToastOptions): string;
1205
+ success: (message: ToastInput, opts?: ToastOptions) => string;
1206
+ error: (message: ToastInput, opts?: ToastOptions) => string;
1207
+ warning: (message: ToastInput, opts?: ToastOptions) => string;
1208
+ info: (message: ToastInput, opts?: ToastOptions) => string;
1209
+ loading: (message: ToastInput, opts?: ToastOptions) => string;
1210
+ dismiss: (id?: string) => void;
1211
+ promise: <T>(promise: Promise<T>, msgs: {
1212
+ loading: ToastInput;
1213
+ success: ToastInput | ((value: T) => ToastInput);
1214
+ error: ToastInput | ((err: unknown) => ToastInput);
1215
+ }, opts?: ToastOptions) => Promise<T>;
1216
+ }
1217
+ declare const toast: ToastFn;
1218
+
1219
+ type ToastPosition = "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right";
1220
+ interface ToasterProps {
1221
+ /** Corner / edge the stack lives in. Default `"bottom-right"`. */
1222
+ position?: ToastPosition;
1223
+ /** Default auto-dismiss in ms. Default `4000`. */
1224
+ duration?: number;
1225
+ /** Max toasts shown at once (older ones wait). Default `4`. */
1226
+ visibleToasts?: number;
1227
+ /** Show a close button on every toast. Default `true`. */
1228
+ closeButton?: boolean;
1229
+ /** Tint the whole toast by variant instead of just the icon. Default `false`. */
1230
+ richColors?: boolean;
1231
+ /** Gap between stacked toasts, px. Default `12`. */
1232
+ gap?: number;
1233
+ /** Offset from the viewport edge, px. Default `24`. */
1234
+ offset?: number;
1235
+ className?: string;
1236
+ }
1237
+ /**
1238
+ * Drop one `<Toaster />` near the app root. Fire toasts imperatively from
1239
+ * anywhere with `toast("Saved")`, `toast.success(...)`, `toast.promise(...)`.
1240
+ */
1241
+ declare function Toaster({ position, duration, visibleToasts, closeButton, richColors, gap, offset, className, }: ToasterProps): react.JSX.Element;
1242
+ /** Hook form of the imperative API, plus the live toast list. */
1243
+ declare function useToast(): {
1244
+ toast: ToastFn;
1245
+ dismiss: (id?: string) => void;
1246
+ toasts: ToastRecord[];
1247
+ };
1248
+
1249
+ interface UsePaginationOptions {
1250
+ /** 1-based current page. */
1251
+ page: number;
1252
+ /** Total number of pages. Or give `total` + `pageSize`. */
1253
+ count?: number;
1254
+ /** Total item count — used with `pageSize` when `count` is absent. */
1255
+ total?: number;
1256
+ /** Items per page — used with `total`. Default 10. */
1257
+ pageSize?: number;
1258
+ /** Pages shown either side of the current one. Default 1. */
1259
+ siblingCount?: number;
1260
+ /** Pages pinned at each end. Default 1. */
1261
+ boundaryCount?: number;
1262
+ }
1263
+ type PaginationSlot = number | "ellipsis-start" | "ellipsis-end";
1264
+ interface UsePaginationResult {
1265
+ /** Resolved total page count (>= 1). */
1266
+ pageCount: number;
1267
+ /** Clamped current page. */
1268
+ page: number;
1269
+ hasPrev: boolean;
1270
+ hasNext: boolean;
1271
+ /** The row to render: page numbers with `"ellipsis-*"` gaps. */
1272
+ slots: PaginationSlot[];
1273
+ }
1274
+ /**
1275
+ * Pure model for a pagination control — the page numbers to show, where the
1276
+ * gaps go, and whether prev/next are live. UI-agnostic; drive any markup with it.
1277
+ */
1278
+ declare function usePagination({ page, count, total, pageSize, siblingCount, boundaryCount, }: UsePaginationOptions): UsePaginationResult;
1279
+
1280
+ type PaginationSize = "sm" | "md" | "lg";
1281
+ type PaginationVariant = "outline" | "ghost" | "solid";
1282
+ declare const PaginationContent: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLUListElement>, HTMLUListElement>, "ref"> & react.RefAttributes<HTMLUListElement>>;
1283
+ declare const PaginationItem: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>, "ref"> & react.RefAttributes<HTMLLIElement>>;
1284
+ interface PaginationLinkProps extends ComponentProps<"button"> {
1285
+ /** Marks the current page. */
1286
+ isActive?: boolean;
1287
+ /** Corner treatment for the item. */
1288
+ size?: PaginationSize;
1289
+ }
1290
+ declare const PaginationLink: react.ForwardRefExoticComponent<Omit<PaginationLinkProps, "ref"> & react.RefAttributes<HTMLButtonElement>>;
1291
+ declare const PaginationEllipsis: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & react.RefAttributes<HTMLSpanElement>>;
1292
+ interface PaginationLabels {
1293
+ previous?: string;
1294
+ next?: string;
1295
+ first?: string;
1296
+ last?: string;
1297
+ page?: (n: number) => string;
1298
+ ariaLabel?: string;
1299
+ }
1300
+ interface PaginationProps extends Omit<ComponentProps<"nav">, "onChange">, UsePaginationOptions {
1301
+ onPageChange: (page: number) => void;
1302
+ /** Show jump-to-first / jump-to-last controls. Default `false`. */
1303
+ showFirstLast?: boolean;
1304
+ /** Show the prev / next controls. Default `true`. */
1305
+ showPrevNext?: boolean;
1306
+ /** Render prev/next as bare arrows (no text). Default `false`. */
1307
+ iconOnly?: boolean;
1308
+ size?: PaginationSize;
1309
+ variant?: PaginationVariant;
1310
+ disabled?: boolean;
1311
+ labels?: PaginationLabels;
1312
+ /** Custom prev / next glyphs. */
1313
+ prevIcon?: ReactNode;
1314
+ nextIcon?: ReactNode;
1315
+ }
1316
+ declare const Pagination: react.ForwardRefExoticComponent<Omit<PaginationProps, "ref"> & react.RefAttributes<HTMLElement>>;
1317
+
1318
+ interface LabelProps extends ComponentPropsWithoutRef<typeof Label$1.Root> {
1319
+ /** Append a required asterisk. */
1320
+ required?: boolean;
1321
+ /** Append an "(optional)" hint (ignored when `required`). */
1322
+ optional?: boolean | ReactNode;
1323
+ }
1324
+ declare const Label: react.ForwardRefExoticComponent<LabelProps & react.RefAttributes<HTMLLabelElement>>;
1325
+
1326
+ type DivProps = ComponentProps<"div">;
1327
+ interface CardProps extends DivProps {
1328
+ /** Render `children` as the card element (e.g. an `<a>` or `<button>`). */
1329
+ asChild?: boolean;
1330
+ /** Hover / focus-visible affordance for a clickable card. */
1331
+ interactive?: boolean;
1332
+ }
1333
+ declare const Card: react.ForwardRefExoticComponent<Omit<CardProps, "ref"> & react.RefAttributes<HTMLDivElement>>;
1334
+ declare const CardHeader: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1335
+ declare const CardTitle: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1336
+ declare const CardDescription: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1337
+ declare const CardAction: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1338
+ declare const CardContent: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1339
+ declare const CardFooter: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1340
+
1341
+ interface BadgeProps extends ComponentProps<"span"> {
1342
+ /** default · secondary · destructive · outline */
1343
+ variant?: BadgeVariant;
1344
+ /** `sm` or `md` (default). */
1345
+ size?: "sm" | "md";
1346
+ /** Leading status dot. */
1347
+ dot?: boolean;
1348
+ /** Leading icon (ignored with `asChild`). */
1349
+ icon?: ReactNode;
1350
+ /** Render a trailing ✕ that calls `onRemove`. */
1351
+ removable?: boolean;
1352
+ onRemove?: (e: MouseEvent<HTMLButtonElement>) => void;
1353
+ /** Render `children` as the badge element (drops the extras). */
1354
+ asChild?: boolean;
1355
+ }
1356
+ declare const Badge: react.ForwardRefExoticComponent<Omit<BadgeProps, "ref"> & react.RefAttributes<HTMLSpanElement>>;
1357
+
1358
+ type AlertVariant = "default" | "destructive" | "success" | "warning" | "info";
1359
+ interface AlertProps extends Omit<ComponentProps<"div">, "title"> {
1360
+ /** default · destructive · success · warning · info */
1361
+ variant?: AlertVariant;
1362
+ /** Leading icon. */
1363
+ icon?: ReactNode;
1364
+ /** Shorthand for a leading `<AlertTitle>`. */
1365
+ title?: ReactNode;
1366
+ /** Render a top-right ✕ that calls `onDismiss`. */
1367
+ dismissible?: boolean;
1368
+ onDismiss?: () => void;
1369
+ }
1370
+ declare const Alert: react.ForwardRefExoticComponent<Omit<AlertProps, "ref"> & react.RefAttributes<HTMLDivElement>>;
1371
+ declare const AlertTitle: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1372
+ declare const AlertDescription: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1373
+
1374
+ interface SeparatorProps extends ComponentPropsWithoutRef<typeof Separator$1.Root> {
1375
+ /** `solid` (default) or `dashed`. */
1376
+ variant?: "solid" | "dashed";
1377
+ /** Centered text inside the rule (horizontal only). */
1378
+ children?: ReactNode;
1379
+ }
1380
+ declare const Separator: react.ForwardRefExoticComponent<SeparatorProps & react.RefAttributes<HTMLDivElement>>;
1381
+
1382
+ interface TableProps extends ComponentProps<"table"> {
1383
+ /** Cell padding. `md` (default) or `sm` (compact). `dense` is an alias for `sm`. */
1384
+ size?: "sm" | "md";
1385
+ dense?: boolean;
1386
+ }
1387
+ declare const Table: react.ForwardRefExoticComponent<Omit<TableProps, "ref"> & react.RefAttributes<HTMLTableElement>>;
1388
+ interface TableHeaderProps extends ComponentProps<"thead"> {
1389
+ /** Stick the header to the top of the scroll container. */
1390
+ sticky?: boolean;
1391
+ }
1392
+ declare const TableHeader: react.ForwardRefExoticComponent<Omit<TableHeaderProps, "ref"> & react.RefAttributes<HTMLTableSectionElement>>;
1393
+ declare const TableBody: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>, "ref"> & react.RefAttributes<HTMLTableSectionElement>>;
1394
+ declare const TableFooter: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>, "ref"> & react.RefAttributes<HTMLTableSectionElement>>;
1395
+ interface TableRowProps extends ComponentProps<"tr"> {
1396
+ /** Highlight the row (maps to `data-state="selected"`). */
1397
+ selected?: boolean;
1398
+ }
1399
+ declare const TableRow: react.ForwardRefExoticComponent<Omit<TableRowProps, "ref"> & react.RefAttributes<HTMLTableRowElement>>;
1400
+ declare const TableHead: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>, "ref"> & react.RefAttributes<HTMLTableCellElement>>;
1401
+ declare const TableCell: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>, "ref"> & react.RefAttributes<HTMLTableCellElement>>;
1402
+ declare const TableCaption: react.ForwardRefExoticComponent<Omit<react.DetailedHTMLProps<react.HTMLAttributes<HTMLElement>, HTMLElement>, "ref"> & react.RefAttributes<HTMLTableCaptionElement>>;
1403
+
1404
+ interface SwitchProps extends ComponentPropsWithoutRef<typeof Switch$1.Root> {
1405
+ /** `sm` · `default` · `lg`. */
1406
+ size?: "sm" | "default" | "lg";
1407
+ /** Text beside the switch — wraps it in a `<label>` layout. */
1408
+ label?: ReactNode;
1409
+ /** Help text under the label. */
1410
+ description?: ReactNode;
1411
+ /** `end` (default) or `start`. */
1412
+ labelPlacement?: "end" | "start";
1413
+ /** Tiny text inside the track when on / off. */
1414
+ onLabel?: ReactNode;
1415
+ offLabel?: ReactNode;
1416
+ /** Icon rendered inside the thumb. */
1417
+ thumbIcon?: ReactNode;
1418
+ }
1419
+ declare const Switch: react.ForwardRefExoticComponent<SwitchProps & react.RefAttributes<HTMLButtonElement>>;
1420
+
1421
+ interface TabsProps extends ComponentPropsWithoutRef<typeof Tabs$1.Root> {
1422
+ /** `pill` (default, muted rounded bar) · `underline` · `enclosed` (folder tabs). */
1423
+ variant?: "pill" | "underline" | "enclosed";
1424
+ /** Trigger sizing. Default `md`. */
1425
+ size?: "sm" | "md" | "lg";
1426
+ /** Triggers stretch to fill the list width. */
1427
+ fitted?: boolean;
1428
+ }
1429
+ declare const Tabs: react.ForwardRefExoticComponent<TabsProps & react.RefAttributes<HTMLDivElement>>;
1430
+ declare const TabsList: react.ForwardRefExoticComponent<Omit<Tabs$1.TabsListProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1431
+ declare const TabsTrigger: react.ForwardRefExoticComponent<Omit<Tabs$1.TabsTriggerProps & react.RefAttributes<HTMLButtonElement>, "ref"> & react.RefAttributes<HTMLButtonElement>>;
1432
+ declare const TabsContent: react.ForwardRefExoticComponent<Omit<Tabs$1.TabsContentProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1433
+
1434
+ declare const Dialog: (props: ComponentProps<typeof Dialog$1.Root>) => react.JSX.Element;
1435
+ declare const DialogTrigger: (props: ComponentProps<typeof Dialog$1.Trigger>) => react.JSX.Element;
1436
+ declare const DialogClose: (props: ComponentProps<typeof Dialog$1.Close>) => react.JSX.Element;
1437
+ declare const DialogPortal: react.FC<Dialog$1.DialogPortalProps>;
1438
+ interface DialogContentProps extends ComponentPropsWithoutRef<typeof Dialog$1.Content> {
1439
+ /** Render the built-in top-right close button. Default `true`. */
1440
+ showCloseButton?: boolean;
1441
+ /** Max width. Default `lg`. */
1442
+ size?: "sm" | "md" | "lg" | "xl" | "full";
1443
+ /** Cap the height and scroll the body. */
1444
+ scrollable?: boolean;
1445
+ /** Override the portal container. */
1446
+ container?: Element | DocumentFragment | null;
1447
+ }
1448
+ declare const DialogContent: react.ForwardRefExoticComponent<DialogContentProps & react.RefAttributes<HTMLDivElement>>;
1449
+ declare function DialogHeader({ className, ...props }: ComponentProps<"div">): react.JSX.Element;
1450
+ declare function DialogFooter({ className, ...props }: ComponentProps<"div">): react.JSX.Element;
1451
+ declare const DialogTitle: react.ForwardRefExoticComponent<Omit<Dialog$1.DialogTitleProps & react.RefAttributes<HTMLHeadingElement>, "ref"> & react.RefAttributes<HTMLHeadingElement>>;
1452
+ declare const DialogDescription: react.ForwardRefExoticComponent<Omit<Dialog$1.DialogDescriptionProps & react.RefAttributes<HTMLParagraphElement>, "ref"> & react.RefAttributes<HTMLParagraphElement>>;
1453
+
1454
+ declare const Popover: (props: ComponentProps<typeof Popover$1.Root>) => react.JSX.Element;
1455
+ declare const PopoverTrigger: (props: ComponentProps<typeof Popover$1.Trigger>) => react.JSX.Element;
1456
+ declare const PopoverAnchor: (props: ComponentProps<typeof Popover$1.Anchor>) => react.JSX.Element;
1457
+ declare const PopoverClose: react.ForwardRefExoticComponent<Popover$1.PopoverCloseProps & react.RefAttributes<HTMLButtonElement>>;
1458
+ declare const PopoverArrow: (props: ComponentProps<typeof Popover$1.Arrow>) => react.JSX.Element;
1459
+ interface PopoverContentProps extends ComponentPropsWithoutRef<typeof Popover$1.Content> {
1460
+ /** Show a pointing arrow. */
1461
+ arrow?: boolean;
1462
+ /** Override the portal container. */
1463
+ container?: Element | DocumentFragment | null;
1464
+ }
1465
+ declare const PopoverContent: react.ForwardRefExoticComponent<PopoverContentProps & react.RefAttributes<HTMLDivElement>>;
1466
+
1467
+ declare function TooltipProvider({ delayDuration, ...props }: ComponentPropsWithoutRef<typeof Tooltip$1.Provider>): react.JSX.Element;
1468
+ interface TooltipProps extends ComponentPropsWithoutRef<typeof Tooltip$1.Root> {
1469
+ /** Hover delay before opening, ms. Default 0. */
1470
+ delayDuration?: number;
1471
+ /** Window after closing where the next tip opens instantly. */
1472
+ skipDelayDuration?: number;
1473
+ /** Don't keep the tip open while the pointer is over it. */
1474
+ disableHoverableContent?: boolean;
1475
+ /** Skip the auto-wrapped provider (a parent already renders one). */
1476
+ disableProvider?: boolean;
1477
+ }
1478
+ declare function Tooltip({ delayDuration, skipDelayDuration, disableHoverableContent, disableProvider, ...props }: TooltipProps): react.JSX.Element;
1479
+ declare const TooltipTrigger: (props: ComponentPropsWithoutRef<typeof Tooltip$1.Trigger>) => react.JSX.Element;
1480
+ interface TooltipContentProps extends ComponentPropsWithoutRef<typeof Tooltip$1.Content> {
1481
+ /** Show the pointing arrow. Default `true`. */
1482
+ arrow?: boolean;
1483
+ /** Arrow width in px (height is ~half). Default 11. */
1484
+ arrowSize?: number;
1485
+ /** Override the portal container. */
1486
+ container?: Element | DocumentFragment | null;
1487
+ }
1488
+ declare const TooltipContent: react.ForwardRefExoticComponent<TooltipContentProps & react.RefAttributes<HTMLDivElement>>;
1489
+
1490
+ declare const DropdownMenu: (props: ComponentProps<typeof DropdownMenu$1.Root>) => react.JSX.Element;
1491
+ declare const DropdownMenuTrigger: (props: ComponentProps<typeof DropdownMenu$1.Trigger>) => react.JSX.Element;
1492
+ declare const DropdownMenuGroup: react.ForwardRefExoticComponent<DropdownMenu$1.DropdownMenuGroupProps & react.RefAttributes<HTMLDivElement>>;
1493
+ declare const DropdownMenuPortal: react.FC<DropdownMenu$1.DropdownMenuPortalProps>;
1494
+ declare const DropdownMenuSub: react.FC<DropdownMenu$1.DropdownMenuSubProps>;
1495
+ declare const DropdownMenuRadioGroup: react.ForwardRefExoticComponent<DropdownMenu$1.DropdownMenuRadioGroupProps & react.RefAttributes<HTMLDivElement>>;
1496
+ interface DropdownMenuContentProps extends ComponentPropsWithoutRef<typeof DropdownMenu$1.Content> {
1497
+ /** Override the portal container. */
1498
+ container?: Element | DocumentFragment | null;
1499
+ }
1500
+ declare const DropdownMenuContent: react.ForwardRefExoticComponent<DropdownMenuContentProps & react.RefAttributes<HTMLDivElement>>;
1501
+ interface DropdownMenuItemProps extends ComponentPropsWithoutRef<typeof DropdownMenu$1.Item> {
1502
+ inset?: boolean;
1503
+ variant?: "default" | "destructive";
1504
+ /** Leading icon. */
1505
+ icon?: ReactNode;
1506
+ /** Trailing shortcut hint (rendered right-aligned). */
1507
+ shortcut?: ReactNode;
1508
+ }
1509
+ declare const DropdownMenuItem: react.ForwardRefExoticComponent<DropdownMenuItemProps & react.RefAttributes<HTMLDivElement>>;
1510
+ declare const DropdownMenuCheckboxItem: react.ForwardRefExoticComponent<Omit<DropdownMenu$1.DropdownMenuCheckboxItemProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1511
+ declare const DropdownMenuRadioItem: react.ForwardRefExoticComponent<Omit<DropdownMenu$1.DropdownMenuRadioItemProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1512
+ interface DropdownMenuLabelProps extends ComponentPropsWithoutRef<typeof DropdownMenu$1.Label> {
1513
+ inset?: boolean;
1514
+ }
1515
+ declare const DropdownMenuLabel: react.ForwardRefExoticComponent<DropdownMenuLabelProps & react.RefAttributes<HTMLDivElement>>;
1516
+ declare const DropdownMenuSeparator: react.ForwardRefExoticComponent<Omit<DropdownMenu$1.DropdownMenuSeparatorProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1517
+ declare function DropdownMenuShortcut({ className, ...props }: ComponentProps<"span">): react.JSX.Element;
1518
+ interface DropdownMenuSubTriggerProps extends ComponentPropsWithoutRef<typeof DropdownMenu$1.SubTrigger> {
1519
+ inset?: boolean;
1520
+ }
1521
+ declare const DropdownMenuSubTrigger: react.ForwardRefExoticComponent<DropdownMenuSubTriggerProps & react.RefAttributes<HTMLDivElement>>;
1522
+ declare const DropdownMenuSubContent: react.ForwardRefExoticComponent<Omit<DropdownMenu$1.DropdownMenuSubContentProps & react.RefAttributes<HTMLDivElement>, "ref"> & react.RefAttributes<HTMLDivElement>>;
1523
+
1524
+ /** Built-in colour presets. Each maps to `[data-orynn-theme="…"]` in the stylesheet
1525
+ * and now recolours only the primary/ring — backgrounds stay neutral (shadcn style). */
1526
+ type OrynnPreset = "default" | "slate" | "teal" | "violet" | "rose" | "emerald";
1527
+ /** Vertical rhythm / sizing. Maps to `[data-orynn-density="…"]`. */
1528
+ type OrynnDensity = "compact" | "comfortable" | "spacious";
1529
+ type OrynnRadius = "none" | "sm" | "md" | "lg" | "xl" | "pill" | (string & {}) | number;
1530
+ /** Any `--orynn-*` custom property. */
1531
+ type OrynnVarOverrides = Partial<Record<`--orynn-${string}`, string | number>>;
1532
+ interface OrynnThemeConfig {
1533
+ /** Colour preset. Defaults to `"default"` (neutral). */
1534
+ preset?: OrynnPreset;
1535
+ density?: OrynnDensity;
1536
+ /** `"dark"` swaps the base palette to the dark token set (also sets the `.dark` class). */
1537
+ colorScheme?: "light" | "dark";
1538
+ /** The solid action colour (`--orynn-color-primary`). Any CSS colour. */
1539
+ primary?: string;
1540
+ /** Foreground to pair with a custom `primary`. Auto-derived from the lightness
1541
+ * of `primary` when omitted (understands hex, `oklch()`, `hsl()`). */
1542
+ primaryForeground?: string;
1543
+ /** @deprecated alias for `primary`. */
1544
+ accent?: string;
1545
+ /** @deprecated alias for `primaryForeground`. */
1546
+ accentContrast?: string;
1547
+ /** `--orynn-font-family`. */
1548
+ font?: string;
1549
+ /** Base font size, e.g. `"15px"` or `"0.95rem"`. */
1550
+ fontSize?: string | number;
1551
+ /** Corner radius base (`--orynn-radius`). Keyword, CSS length, or px number. */
1552
+ radius?: OrynnRadius;
1553
+ /** Default control width. `"100%"` by default. */
1554
+ controlWidth?: string | number;
1555
+ /** Cap on control width. `"450px"` by default; number = px; `"none"` to uncap. */
1556
+ controlMaxWidth?: string | number;
1557
+ /** Focus-ring colour (`--orynn-color-ring`). */
1558
+ ring?: string;
1559
+ /** Escape hatch: any `--orynn-*` variables verbatim. */
1560
+ vars?: OrynnVarOverrides;
1561
+ }
1562
+ /** `theme` prop accepts a preset name shorthand or a full config. */
1563
+ type OrynnThemeInput = OrynnPreset | OrynnThemeConfig;
1564
+ /** Build the inline CSS-variable style object for a theme config. */
1565
+ declare function resolveThemeVars(config: OrynnThemeConfig): CSSProperties;
1566
+
1567
+ interface OrynnContextValue {
1568
+ preset: OrynnPreset;
1569
+ density: OrynnDensity;
1570
+ config: OrynnThemeConfig;
1571
+ /**
1572
+ * A themed `<div class="orynn-portal">` appended to `document.body` (or `null`
1573
+ * before the mount effect / on the server). Radix `*.Portal`s and the internal
1574
+ * `<Popover>` render into it so portalled content inherits this provider's
1575
+ * theme even though it sits outside the provider's DOM subtree.
1576
+ */
1577
+ portalContainer: HTMLElement | null;
1578
+ }
1579
+ interface OrynnProviderProps {
1580
+ /** Preset name (`"teal"`) or a full config object. */
1581
+ theme?: OrynnThemeInput;
1582
+ /** Render a `<div>` (default) or a different element / no wrapper (`"contents"`). */
1583
+ as?: "div" | "span" | "contents";
1584
+ className?: string;
1585
+ children: ReactNode;
1586
+ }
1587
+ /**
1588
+ * Scopes an Orynn theme to its subtree by setting `data-orynn-theme`,
1589
+ * `data-orynn-density`, a `.dark` class and any custom `--orynn-*` variables on a
1590
+ * wrapper element. Purely CSS custom properties — no runtime styling engine.
1591
+ * Nesting is supported; an inner provider overrides only what it sets. Also
1592
+ * mounts a matching `<div class="orynn-portal">` on `document.body` so portalled
1593
+ * overlays (Dialog, Popover, Tooltip, menus) render with the same theme.
1594
+ */
1595
+ declare function OrynnProvider({ theme, as, className, children }: OrynnProviderProps): react.JSX.Element;
1596
+ /** Read the nearest Orynn theme config. */
1597
+ declare function useOrynnTheme(): OrynnContextValue;
1598
+ /**
1599
+ * The DOM node Radix portals / the internal `<Popover>` should render into so
1600
+ * portalled content stays themed. Falls back to `document.body` when there is no
1601
+ * `<OrynnProvider>` (the theme then lives on `:root` / `html` and body inherits
1602
+ * it anyway). `null` only on the server.
1603
+ */
1604
+ declare function usePortalContainer(): HTMLElement | null;
670
1605
 
671
1606
  /**
672
1607
  * Create an isolated field registry. Use this to give a `<Fieldset>` its own set
@@ -692,21 +1627,29 @@ declare const defaultRegistry: FieldRegistry;
692
1627
  */
693
1628
  declare function registerField(type: string, registration: FieldRegistration): void;
694
1629
 
695
- /** A synchronous resolver — the built-in resolver's precise return type. */
1630
+ /** A synchronous resolver — the built-in resolver's return type when no rule is async. */
696
1631
  type SyncResolver = (values: Record<string, unknown>, config: FieldsetConfig, context: ValidationContext) => ValidationResult;
697
1632
  /**
698
- * The default, rule-based {@link ValidationResolver}. For every field with a
699
- * `validation` block, each key (other than `messages`) is looked up in the rule
700
- * registry and run against the field's current value. All fields are validated
701
- * on every call; callers decide which errors to surface.
702
- *
703
- * Synchronous today. Async, schema-based, and cross-field resolvers plug in at
704
- * the same seam without an API change.
1633
+ * The default, rule-based {@link ValidationResolver}. For every visible field
1634
+ * with a `validation` block, each key (other than `messages`) is looked up in
1635
+ * the rule registry and run against the field's current value. Fields whose
1636
+ * `when` condition is false are skipped. Returns synchronously unless a rule
1637
+ * (e.g. `validate`) resolves asynchronously.
705
1638
  */
706
- declare function createRuleResolver(): SyncResolver;
1639
+ declare function createRuleResolver(): ValidationResolver;
707
1640
  /** Shared default instance. */
708
1641
  declare const defaultResolver: ValidationResolver;
709
1642
 
1643
+ /**
1644
+ * Built-in rules. Each returns a token (rule name) on failure or `null` on
1645
+ * success; the resolver turns the token into a user-facing message. Rules other
1646
+ * than `required` skip empty values so `required` owns that error.
1647
+ *
1648
+ * `validate` is special: its param is a function `(value, allValues) => string |
1649
+ * boolean | null | Promise<…>`; a string is the message, `false` a generic
1650
+ * failure, `true` / `null` a pass.
1651
+ */
1652
+ declare const builtInRules: Record<string, RuleFn>;
710
1653
  /**
711
1654
  * Register a validation rule for the built-in resolver. A field opts in by
712
1655
  * adding a key of the same name to its `validation` config.
@@ -715,4 +1658,44 @@ declare const defaultResolver: ValidationResolver;
715
1658
  */
716
1659
  declare function registerRule(name: string, fn: RuleFn): void;
717
1660
 
718
- export { type BaseControlProps, type BaseFieldConfig, Checkbox, CheckboxGroup, type CheckboxGroupProps, type CheckboxOption, type CheckboxProps, type ColumnSpec, type ControlComponent, type ControlProps, type ControlRadius, type ControlSize, type ControlVariant, DatePicker, type DatePickerProps, Dropdown, type DropdownFieldConfig, type DropdownOption, type DropdownProps, type ErrorProp, FORM_ERROR_KEY, type Feedback, Field, FieldBox, type FieldBoxProps, 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, NumberField, type NumberFieldProps, type OrynnDensity, type OrynnPreset, OrynnProvider, type OrynnProviderProps, type OrynnRadius, type OrynnThemeConfig, type OrynnThemeInput, type OrynnVarOverrides, Radio, RadioGroup, type RadioGroupProps, type RadioOption, type RadioProps, type RuleFn, Dropdown as Select, type SyncResolver, Textarea, type TextareaProps, type UseFieldsetStateOptions, type UseFieldsetStateReturn, type ValidationContext, type ValidationResolver, type ValidationResult, type ValidationTrigger, createRegistry, createRuleResolver, defaultRegistry, defaultResolver, normalizeConfig, registerField, registerRule, resolveThemeVars, useFieldsetState, useOrynnTheme };
1661
+ /**
1662
+ * Minimal shape of the [Standard Schema](https://standardschema.dev) `v1`
1663
+ * contract — implemented by Zod 3.24+, Valibot 1.0+, ArkType 2+, and others.
1664
+ * Inlined so Orynn needs no dependency.
1665
+ */
1666
+ interface StandardSchemaV1<Output = unknown> {
1667
+ readonly "~standard": {
1668
+ readonly version: 1;
1669
+ readonly vendor: string;
1670
+ readonly validate: (value: unknown) => StandardResult<Output> | Promise<StandardResult<Output>>;
1671
+ };
1672
+ }
1673
+ type StandardResult<Output> = {
1674
+ readonly value: Output;
1675
+ readonly issues?: undefined;
1676
+ } | {
1677
+ readonly issues: ReadonlyArray<StandardIssue>;
1678
+ };
1679
+ interface StandardIssue {
1680
+ readonly message: string;
1681
+ readonly path?: ReadonlyArray<PropertyKey | {
1682
+ readonly key: PropertyKey;
1683
+ }>;
1684
+ }
1685
+ /**
1686
+ * Turn a Standard Schema (Zod / Valibot / ArkType / …) into an Orynn
1687
+ * {@link ValidationResolver}. Pass it to `<Fieldset resolver={…}>` or
1688
+ * `useFieldsetState({ resolver })`.
1689
+ *
1690
+ * ```ts
1691
+ * import { z } from "zod";
1692
+ * const schema = z.object({ email: z.string().email(), age: z.number().min(18) });
1693
+ * <Fieldset config={config} resolver={standardSchemaResolver(schema)} />
1694
+ * ```
1695
+ *
1696
+ * Issues are keyed by the first path segment (the field name); path-less issues
1697
+ * land under `"$form"`.
1698
+ */
1699
+ declare function standardSchemaResolver(schema: StandardSchemaV1): ValidationResolver;
1700
+
1701
+ export { Accordion, AccordionContent, AccordionItem, type AccordionProps, type AccordionSize, AccordionTrigger, type AccordionTriggerProps, type AccordionVariant, Alert, AlertDescription, type AlertProps, AlertTitle, type AlertVariant, Badge, type BadgeProps, type BadgeVariant, type BaseControlProps, type BaseFieldConfig, Button, type ButtonCursor, type ButtonFocusStyle, type ButtonHoverEffect, 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, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, type PaginationLabels, PaginationLink, type PaginationLinkProps, type PaginationProps, type PaginationSize, type PaginationSlot, type PaginationVariant, type PatternRule, Popover, PopoverAnchor, PopoverArrow, PopoverClose, PopoverContent, type PopoverContentProps, PopoverTrigger, Progress, type ProgressProps, Radio, type RadioFieldConfig, RadioGroup, type RadioGroupProps, type RadioOption, type RadioProps, type RuleFn, Dropdown as Select, Separator, type SeparatorProps, Slider, type SliderMark, type SliderProps, 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, type ToastAction, type ToastFn, type ToastOptions, type ToastPosition, type ToastRecord, type ToastVariant, Toaster, type ToasterProps, Tooltip, TooltipContent, type TooltipContentProps, type TooltipProps, TooltipProvider, TooltipTrigger, type UseFieldsetStateOptions, type UseFieldsetStateReturn, type UsePaginationOptions, type UsePaginationResult, type ValidationContext, type ValidationResolver, type ValidationResult, type ValidationTrigger, badgeClasses, builtInRules, buttonClasses, createRegistry, createRuleResolver, defaultRegistry, defaultResolver, normalizeConfig, registerField, registerRule, resolveThemeVars, standardSchemaResolver, toast, useFieldsetState, useOrynnTheme, usePagination, usePortalContainer, useToast };