@godxjp/ui 20.0.0 → 20.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. package/README.md +8 -2
  2. package/dist/app/theme-axes.d.ts +2 -0
  3. package/dist/app/theme-axes.js +45 -0
  4. package/dist/components/charts/chart-cartesian.d.ts +2 -1
  5. package/dist/components/charts/chart-cartesian.js +52 -3
  6. package/dist/components/charts/chart-category-axis.d.ts +55 -0
  7. package/dist/components/charts/chart-category-axis.js +93 -0
  8. package/dist/components/charts/chart-frame.d.ts +10 -1
  9. package/dist/components/charts/chart-frame.js +19 -3
  10. package/dist/components/charts/compact-bar-trend.d.ts +1 -1
  11. package/dist/components/charts/compact-bar-trend.js +2 -0
  12. package/dist/components/charts/pie-chart.d.ts +1 -1
  13. package/dist/components/charts/pie-chart.js +12 -1
  14. package/dist/components/charts/recharts-peer.d.ts +49 -0
  15. package/dist/components/charts/recharts-peer.js +45 -0
  16. package/dist/components/data-display/card.d.ts +12 -1
  17. package/dist/components/data-display/card.js +22 -4
  18. package/dist/components/data-display/code-block.js +6 -2
  19. package/dist/components/data-display/data-table.d.ts +39 -4
  20. package/dist/components/data-display/data-table.js +802 -270
  21. package/dist/components/data-display/descriptions.d.ts +27 -6
  22. package/dist/components/data-display/descriptions.js +58 -17
  23. package/dist/components/data-display/index.d.ts +2 -0
  24. package/dist/components/data-display/index.js +2 -0
  25. package/dist/components/data-display/list-row.d.ts +10 -1
  26. package/dist/components/data-display/list-row.js +7 -1
  27. package/dist/components/data-display/popover.d.ts +2 -2
  28. package/dist/components/data-display/popover.js +61 -11
  29. package/dist/components/data-display/range-timeline.d.ts +38 -0
  30. package/dist/components/data-display/range-timeline.js +161 -0
  31. package/dist/components/data-display/scroll-area.js +13 -2
  32. package/dist/components/data-display/service-launcher-card.js +10 -10
  33. package/dist/components/data-display/table.d.ts +11 -3
  34. package/dist/components/data-display/table.js +48 -18
  35. package/dist/components/data-display/tree-list.js +4 -9
  36. package/dist/components/data-entry/calendar.d.ts +2 -2
  37. package/dist/components/data-entry/calendar.js +12 -1
  38. package/dist/components/data-entry/cascader.d.ts +1 -1
  39. package/dist/components/data-entry/cascader.js +188 -24
  40. package/dist/components/data-entry/color-picker.d.ts +1 -1
  41. package/dist/components/data-entry/color-picker.js +17 -5
  42. package/dist/components/data-entry/control-appearance.d.ts +64 -0
  43. package/dist/components/data-entry/control-appearance.js +39 -0
  44. package/dist/components/data-entry/control-surface.d.ts +61 -0
  45. package/dist/components/data-entry/control-surface.js +39 -0
  46. package/dist/components/data-entry/date-picker.d.ts +1 -1
  47. package/dist/components/data-entry/date-picker.js +344 -113
  48. package/dist/components/data-entry/date-range-picker.d.ts +1 -1
  49. package/dist/components/data-entry/date-range-picker.js +278 -140
  50. package/dist/components/data-entry/form-field.d.ts +1 -1
  51. package/dist/components/data-entry/form-field.js +39 -4
  52. package/dist/components/data-entry/form.d.ts +4 -0
  53. package/dist/components/data-entry/form.js +4 -2
  54. package/dist/components/data-entry/index.d.ts +7 -3
  55. package/dist/components/data-entry/index.js +10 -1
  56. package/dist/components/data-entry/input-otp.d.ts +1 -1
  57. package/dist/components/data-entry/input.d.ts +12 -34
  58. package/dist/components/data-entry/input.js +92 -24
  59. package/dist/components/data-entry/month-picker.d.ts +1 -1
  60. package/dist/components/data-entry/month-picker.js +47 -10
  61. package/dist/components/data-entry/month-range-picker.d.ts +1 -1
  62. package/dist/components/data-entry/month-range-picker.js +51 -11
  63. package/dist/components/data-entry/number-input.d.ts +7 -0
  64. package/dist/components/data-entry/number-input.js +147 -98
  65. package/dist/components/data-entry/password-input.d.ts +1 -1
  66. package/dist/components/data-entry/radio.d.ts +1 -1
  67. package/dist/components/data-entry/radio.js +61 -13
  68. package/dist/components/data-entry/search-input.d.ts +1 -1
  69. package/dist/components/data-entry/search-input.js +16 -2
  70. package/dist/components/data-entry/search-select.d.ts +2 -2
  71. package/dist/components/data-entry/search-select.js +209 -78
  72. package/dist/components/data-entry/select.d.ts +22 -4
  73. package/dist/components/data-entry/select.js +215 -163
  74. package/dist/components/data-entry/slider.d.ts +9 -1
  75. package/dist/components/data-entry/slider.js +87 -9
  76. package/dist/components/data-entry/switch.d.ts +3 -0
  77. package/dist/components/data-entry/switch.js +29 -3
  78. package/dist/components/data-entry/textarea.d.ts +14 -56
  79. package/dist/components/data-entry/textarea.js +80 -33
  80. package/dist/components/data-entry/time-picker.d.ts +2 -2
  81. package/dist/components/data-entry/time-picker.js +333 -109
  82. package/dist/components/data-entry/time-range-picker.d.ts +5 -0
  83. package/dist/components/data-entry/time-range-picker.js +89 -0
  84. package/dist/components/data-entry/transfer.d.ts +1 -1
  85. package/dist/components/data-entry/transfer.js +86 -28
  86. package/dist/components/data-entry/tree-select.d.ts +1 -1
  87. package/dist/components/data-entry/tree-select.js +201 -113
  88. package/dist/components/data-entry/tree-utils.js +7 -14
  89. package/dist/components/data-entry/upload-files.d.ts +2 -0
  90. package/dist/components/data-entry/upload-files.js +31 -0
  91. package/dist/components/data-entry/upload-request.d.ts +4 -0
  92. package/dist/components/data-entry/upload-request.js +53 -0
  93. package/dist/components/data-entry/upload-types.d.ts +28 -0
  94. package/dist/components/data-entry/upload-types.js +2 -0
  95. package/dist/components/data-entry/upload.d.ts +2 -2
  96. package/dist/components/data-entry/upload.js +475 -115
  97. package/dist/components/feedback/dialog.js +16 -19
  98. package/dist/components/general/button.d.ts +1 -1
  99. package/dist/components/general/button.js +5 -1
  100. package/dist/components/general/index.d.ts +1 -0
  101. package/dist/components/general/index.js +2 -0
  102. package/dist/components/general/typography.d.ts +3 -0
  103. package/dist/components/general/typography.js +15 -1
  104. package/dist/components/general/visually-hidden.d.ts +3 -0
  105. package/dist/components/general/visually-hidden.js +9 -0
  106. package/dist/components/layout/app-launcher.d.ts +34 -0
  107. package/dist/components/layout/app-launcher.js +228 -0
  108. package/dist/components/layout/app-shell.d.ts +2 -0
  109. package/dist/components/layout/app-shell.js +20 -7
  110. package/dist/components/layout/breadcrumb.d.ts +14 -2
  111. package/dist/components/layout/breadcrumb.js +46 -4
  112. package/dist/components/layout/flex.d.ts +1 -1
  113. package/dist/components/layout/flex.js +23 -2
  114. package/dist/components/layout/index.d.ts +3 -0
  115. package/dist/components/layout/index.js +5 -1
  116. package/dist/components/layout/org-switcher.js +20 -1
  117. package/dist/components/layout/page-container.d.ts +1 -1
  118. package/dist/components/layout/page-container.js +5 -3
  119. package/dist/components/layout/responsive-grid.d.ts +16 -2
  120. package/dist/components/layout/responsive-grid.js +29 -2
  121. package/dist/components/layout/topbar-item.d.ts +3 -0
  122. package/dist/components/layout/topbar-item.js +18 -3
  123. package/dist/components/layout/topbar.d.ts +1 -1
  124. package/dist/components/layout/topbar.js +27 -6
  125. package/dist/components/navigation/dropdown-menu.d.ts +30 -2
  126. package/dist/components/navigation/dropdown-menu.js +68 -11
  127. package/dist/components/navigation/pagination.d.ts +2 -2
  128. package/dist/components/navigation/pagination.js +155 -83
  129. package/dist/components/navigation/steps.d.ts +2 -2
  130. package/dist/components/navigation/steps.js +29 -4
  131. package/dist/components/navigation/tabs.d.ts +5 -33
  132. package/dist/components/navigation/tabs.js +232 -64
  133. package/dist/components/ui/input-otp.d.ts +26 -28
  134. package/dist/components/ui/input-otp.js +50 -7
  135. package/dist/components/ui/password-input.d.ts +36 -2
  136. package/dist/components/ui/password-input.js +27 -7
  137. package/dist/components/ui/rating.d.ts +25 -0
  138. package/dist/components/ui/rating.js +67 -27
  139. package/dist/components/ui/segmented.d.ts +9 -0
  140. package/dist/components/ui/segmented.js +17 -2
  141. package/dist/components/ui/separator.d.ts +4 -0
  142. package/dist/components/ui/separator.js +13 -0
  143. package/dist/components/ui/tag-input.d.ts +45 -0
  144. package/dist/components/ui/tag-input.js +109 -27
  145. package/dist/form/form-context.d.ts +29 -0
  146. package/dist/form/form-context.js +44 -4
  147. package/dist/form/form-field-array.d.ts +22 -0
  148. package/dist/form/form-field-array.js +50 -0
  149. package/dist/form/form-field-control.d.ts +2 -1
  150. package/dist/form/form-field-control.js +116 -40
  151. package/dist/form/form-root.d.ts +2 -1
  152. package/dist/form/form-root.js +142 -23
  153. package/dist/form/index.d.ts +3 -1
  154. package/dist/form/index.js +12 -1
  155. package/dist/i18n/messages/en.json +56 -5
  156. package/dist/i18n/messages/ja.json +56 -5
  157. package/dist/i18n/messages/vi.json +56 -5
  158. package/dist/inertia/index.d.ts +20 -0
  159. package/dist/inertia/index.js +60 -1
  160. package/dist/lib/control-styles.d.ts +25 -3
  161. package/dist/lib/control-styles.js +9 -3
  162. package/dist/lib/datetime/picker-format.d.ts +8 -0
  163. package/dist/lib/datetime/picker-format.js +54 -0
  164. package/dist/props/components/charts.prop.d.ts +21 -0
  165. package/dist/props/components/data-display.prop.d.ts +55 -4
  166. package/dist/props/components/data-entry.prop.d.ts +687 -43
  167. package/dist/props/components/form.prop.d.ts +142 -4
  168. package/dist/props/components/general.prop.d.ts +17 -1
  169. package/dist/props/components/index.d.ts +2 -2
  170. package/dist/props/components/layout.prop.d.ts +163 -6
  171. package/dist/props/components/navigation.prop.d.ts +113 -3
  172. package/dist/props/registry.d.ts +376 -10
  173. package/dist/props/registry.js +493 -9
  174. package/dist/props/vocabulary/data.prop.d.ts +179 -1
  175. package/dist/props/vocabulary/index.d.ts +4 -4
  176. package/dist/props/vocabulary/interaction.prop.d.ts +51 -2
  177. package/dist/props/vocabulary/navigation.prop.d.ts +40 -0
  178. package/dist/props/vocabulary/shared.prop.d.ts +33 -0
  179. package/dist/styles/badge-layout.css +2 -1
  180. package/dist/styles/card-layout.css +26 -4
  181. package/dist/styles/chart-layout.css +15 -0
  182. package/dist/styles/control.css +515 -14
  183. package/dist/styles/data-display-layout.css +241 -6
  184. package/dist/styles/data-entry-layout.css +13 -0
  185. package/dist/styles/layout.css +221 -4
  186. package/dist/styles/navigation-layout.css +227 -0
  187. package/dist/styles/shell-layout.css +229 -5
  188. package/dist/styles/table-layout.css +95 -6
  189. package/dist/styles/text-layout.css +5 -0
  190. package/dist/tokens/base.css +1 -0
  191. package/dist/tokens/components/badge.css +1 -0
  192. package/dist/tokens/components/chart.css +6 -0
  193. package/dist/tokens/components/control.css +79 -2
  194. package/dist/tokens/components/data-display.css +9 -0
  195. package/dist/tokens/components/descriptions.css +11 -0
  196. package/dist/tokens/components/flex.css +8 -0
  197. package/dist/tokens/components/navigation.css +55 -0
  198. package/dist/tokens/components/shell.css +50 -2
  199. package/dist/tokens/components/table.css +14 -0
  200. package/dist/tokens/semantic/layout.css +9 -0
  201. package/docs/CONSUMER-RULES.md +13 -0
  202. package/docs/DESIGN-AUTHORITY.md +43 -6
  203. package/docs/DEVELOPMENT.md +4 -3
  204. package/docs/FORMS.md +151 -6
  205. package/docs/FRAME-COVERAGE-REPORT.md +29 -16
  206. package/docs/README.md +1 -1
  207. package/docs/STANDARDS-vocabulary-tokens.md +1 -1
  208. package/docs/TESTING.md +15 -6
  209. package/docs/charts/cjk-category-axis.tsx +81 -0
  210. package/docs/data-display/card/index.tsx +22 -0
  211. package/docs/data-display/data-table/examples/antd-parity.tsx +257 -0
  212. package/docs/data-display/data-table/index.tsx +23 -0
  213. package/docs/data-display/descriptions.tsx +41 -0
  214. package/docs/data-display/scroll-area.tsx +31 -25
  215. package/docs/data-display/table.tsx +104 -45
  216. package/docs/data-display/timeline.tsx +41 -0
  217. package/docs/data-entry/date-picker.tsx +85 -0
  218. package/docs/data-entry/date-range-picker.tsx +26 -0
  219. package/docs/data-entry/form-dynamic-fields.tsx +199 -0
  220. package/docs/data-entry/form.tsx +74 -4
  221. package/docs/data-entry/input-otp.tsx +24 -0
  222. package/docs/data-entry/input.tsx +46 -1
  223. package/docs/data-entry/month-range-picker.tsx +1 -1
  224. package/docs/data-entry/select.tsx +27 -0
  225. package/docs/data-entry/switch.tsx +41 -0
  226. package/docs/data-entry/textarea.tsx +38 -0
  227. package/docs/data-entry/time-picker.tsx +85 -1
  228. package/docs/data-entry/time-range-picker.tsx +55 -0
  229. package/docs/data-entry/transfer.tsx +17 -0
  230. package/docs/data-entry/upload.tsx +56 -12
  231. package/docs/feedback/tooltip.tsx +1 -1
  232. package/docs/general/activity.tsx +2 -2
  233. package/docs/general/button/index.tsx +14 -1
  234. package/docs/general/typography.tsx +14 -1
  235. package/docs/layout/app-launcher.tsx +151 -0
  236. package/docs/layout/app-shell.tsx +11 -0
  237. package/docs/layout/flex.tsx +50 -0
  238. package/docs/layout/responsive-grid.tsx +21 -1
  239. package/docs/layout/topbar.tsx +5 -9
  240. package/docs/navigation/app-setting-picker.tsx +11 -0
  241. package/docs/navigation/breadcrumb.tsx +48 -0
  242. package/docs/navigation/dropdown-menu.tsx +21 -0
  243. package/docs/navigation/pagination.tsx +52 -0
  244. package/docs/navigation/steps.tsx +37 -0
  245. package/docs/navigation/tabs.tsx +97 -1
  246. package/docs/query/button-refetch.tsx +1 -0
  247. package/package.json +19 -2
  248. package/scripts/_agent-setup.mjs +19 -2
  249. package/scripts/init-guinea-pig.mjs +26 -4
  250. package/scripts/ui-audit.mjs +243 -30
@@ -1,8 +1,8 @@
1
1
  /** Form module prop types — react-hook-form + Zod 4 only. */
2
2
  import type * as React from "react";
3
- import type { FieldPath, FieldValues, UseFormProps, UseFormReturn } from "react-hook-form";
3
+ import type { FieldArray, FieldArrayPath, FieldErrors, FieldPath, FieldValues, UseFormProps, UseFormReturn } from "react-hook-form";
4
4
  import type { z } from "zod";
5
- import type { ErrorProp, HelperProp, IdProp, LabelProp, RequiredProp } from "../vocabulary/index.js";
5
+ import type { BreakpointProp, DensityProp, DisabledProp, ErrorBagProp, ErrorProp, FormLayoutProp, HelperProp, IdProp, LabelProp, RequiredProp, WidthProp } from "../vocabulary/index.js";
6
6
  /** Schema passed to useZodForm — must be Zod 4 object schema. */
7
7
  export type ZodSchemaProp<T extends z.ZodType = z.ZodType> = T;
8
8
  /** Options for useZodForm (resolver injected automatically). */
@@ -27,6 +27,11 @@ export interface FormStateAdapter {
27
27
  /** Optional blur handler (e.g. touch-tracking); called with the field name. */
28
28
  onBlur?(name: string): void;
29
29
  getValues?(): unknown;
30
+ /**
31
+ * Restore the store's initial values (e.g. Inertia's `form.reset()`). `FormRoot` calls it for a
32
+ * native `<Button type="reset">`, so the reset button behaves identically on both paths.
33
+ */
34
+ reset?(): void;
30
35
  }
31
36
  /** @see FormRoot */
32
37
  export type FormRootProp<TFieldValues extends FieldValues> = {
@@ -39,26 +44,159 @@ export type FormRootProp<TFieldValues extends FieldValues> = {
39
44
  * Framework-agnostic form-state adapter (e.g. `inertiaAdapter(form)` from `@godxjp/ui/inertia`).
40
45
  */
41
46
  adapter?: FormStateAdapter;
42
- /** Submit handler. */
47
+ /** Submit handler — runs only after validation passes (antd `onFinish`). */
43
48
  onSubmit: (values: TFieldValues) => void | Promise<void>;
49
+ /**
50
+ * Validation FAILED (antd `onFinishFailed`) — receives react-hook-form's error tree. Use it to
51
+ * announce a summary; the first invalid field is focused (and scrolled to) regardless.
52
+ * react-hook-form path only: on the adapter path the server owns validation.
53
+ */
54
+ onSubmitFailed?: (errors: FieldErrors<TFieldValues>) => void;
55
+ /**
56
+ * `onSubmit` REJECTED (the network call failed). Without this the rejection escapes as an
57
+ * unhandled promise rejection, which is what an async `onSubmit` does today — pass a handler to
58
+ * render a form-level error instead.
59
+ */
60
+ onSubmitError?: (error: unknown) => void;
61
+ /**
62
+ * A native `<Button type="reset">` inside the form restores `defaultValues` (adapter path:
63
+ * `adapter.reset()`); this runs afterwards for any extra app state (a status banner, a step).
64
+ */
65
+ onReset?: () => void;
66
+ /**
67
+ * Scroll the first invalid field into view after a failed submit (antd `scrollToFirstError`).
68
+ * Honours `prefers-reduced-motion`. Default `true`.
69
+ */
70
+ scrollToFirstError?: boolean;
71
+ /**
72
+ * Disable EVERY field under this form (antd Form `disabled`) — read by `FormFieldControl`
73
+ * (which hands `disabled` to its render prop) and by `useFormDisabled()` for the action buttons.
74
+ * Values are NOT dropped from the submitted payload.
75
+ */
76
+ disabled?: DisabledProp;
77
+ /**
78
+ * Field layout for every `FormFieldControl` below (antd `layout`). Setting ANY layout prop makes
79
+ * `FormRoot` render the `Form` layout shell, whose `--form-block-gap` spacing replaces the plain
80
+ * `ui-stack-md` stack used by a bare `FormRoot`.
81
+ */
82
+ layout?: FormLayoutProp;
83
+ /** Label column width in the `horizontal` layout (antd `labelCol`). */
84
+ labelWidth?: WidthProp;
85
+ /** Control column width (antd `wrapperCol`). */
86
+ controlWidth?: WidthProp;
87
+ /** Label text alignment in the `horizontal` layout (antd `labelAlign`). */
88
+ labelAlign?: "start" | "end";
89
+ /** Viewport below which a `horizontal`/`inline` layout stacks; `false` never stacks. */
90
+ collapseBelow?: BreakpointProp | false;
91
+ /** Control density for the fields below (antd Form `size`). */
92
+ density?: DensityProp;
93
+ columns?: import("./data-entry.prop.js").FormProp["columns"];
94
+ /** How required/optional fields are marked in their labels (antd `requiredMark`). */
95
+ requiredMark?: boolean | "optional";
96
+ /**
97
+ * Server validation error bag. Fields claim their own key and `<FormErrors />` renders the
98
+ * unclaimed remainder — the same mechanism as `Form errors`, without a second `Form` wrapper.
99
+ */
100
+ errors?: ErrorBagProp;
44
101
  children: React.ReactNode;
45
102
  className?: string;
46
103
  id?: IdProp;
47
104
  };
48
105
  /** @see FormFieldControl */
49
- export type FormFieldControlProp<TFieldValues extends FieldValues> = {
106
+ export type FormFieldControlProp<TFieldValues extends FieldValues> = Pick<import("./data-entry.prop.js").FormFieldProp, "id" | "field" | "labelAddon" | "layout" | "labelWidth" | "controlWidth" | "colSpan"> & {
50
107
  name: FieldPath<TFieldValues>;
51
108
  label: LabelProp;
52
109
  required?: RequiredProp;
53
110
  helper?: HelperProp;
111
+ /**
112
+ * Disable this field only. Defaults to the surrounding `FormRoot disabled`. The resolved state
113
+ * reaches the control through the render prop's `disabled`; the field's value is still submitted
114
+ * (antd semantics), unlike react-hook-form's own `disabled`.
115
+ */
116
+ disabled?: DisabledProp;
117
+ /**
118
+ * Re-validate this field whenever one of these fields changes (antd `dependencies`) — the
119
+ * confirm-password / date-range case, where the schema's cross-field `.superRefine()` reports on
120
+ * THIS field but only re-runs when the OTHER one is edited. Runs only once the form has been
121
+ * submitted, so a dependency edit never flags a field the user has not reached yet.
122
+ */
123
+ dependencies?: FieldPath<TFieldValues>[];
124
+ /**
125
+ * Read the value out of the control's change payload (antd `getValueFromEvent`). Replaces the
126
+ * built-in DOM-event/raw-value detection — needed by a control that reports `(value, option)`.
127
+ */
128
+ getValueFromEvent?: (...args: unknown[]) => unknown;
129
+ /**
130
+ * Transform the extracted value before it is stored (antd `normalize`) — trim, upper-case,
131
+ * digits-only. Receives the previous value so a normaliser can reject a change.
132
+ */
133
+ normalize?: (value: unknown, previousValue: unknown) => unknown;
134
+ /**
135
+ * Message shown in the error slot INSTEAD of the resolved validation error (antd `help`) — for a
136
+ * server error the schema cannot know about.
137
+ */
138
+ help?: ErrorProp;
139
+ /**
140
+ * Force the validation state shown by the field (antd `validateStatus`) — `"validating"` for a
141
+ * remote check in flight, `"success"` for a confirmed-unique value. A real validation error
142
+ * always wins; mirrors `FormField validateStatus`.
143
+ */
144
+ validateStatus?: "success" | "warning" | "error" | "validating";
145
+ /** Render the status icon + localized status text for `validateStatus` (antd `hasFeedback`). */
146
+ hasFeedback?: boolean;
147
+ /** Replace the default feedback text next to the `hasFeedback` icon. */
148
+ feedback?: React.ReactNode;
149
+ /**
150
+ * Keep the value in the form state after the field unmounts (antd `preserve`, default `true`).
151
+ * `false` unregisters it — a conditional branch that must not submit a stale value.
152
+ */
153
+ preserve?: boolean;
54
154
  className?: string;
55
155
  children: (field: {
56
156
  id: string;
57
157
  name: string;
58
158
  value: unknown;
59
159
  onChange: (...args: unknown[]) => void;
160
+ onValueChange: (...args: unknown[]) => void;
60
161
  onBlur: () => void;
61
162
  ref: React.Ref<HTMLInputElement>;
163
+ /** Present (and `true`) only when the field is disabled, so `{...field}` never re-enables a control. */
164
+ disabled?: DisabledProp;
165
+ }) => React.ReactNode;
166
+ };
167
+ /**
168
+ * @see FormFieldArray — dynamic repeating fields (antd `Form.List`) on react-hook-form's
169
+ * `useFieldArray`. `name` is the array field; each row hands back the dotted path prefix to build
170
+ * the child `FormFieldControl name`.
171
+ */
172
+ export type FormFieldArrayProp<TFieldValues extends FieldValues, TName extends FieldArrayPath<TFieldValues> = FieldArrayPath<TFieldValues>> = {
173
+ /** Path of the array in the schema (`"contacts"`, `"invoice.lines"`). */
174
+ name: TName;
175
+ children: (list: {
176
+ /** One entry per row, in order. `key` is react-hook-form's stable row id — use it as the React key. */
177
+ fields: Array<{
178
+ key: string;
179
+ name: `${TName}.${number}`;
180
+ index: number;
181
+ }>;
182
+ /** Append one row (or several) at the end. */
183
+ append: (value: FieldArray<TFieldValues, TName> | FieldArray<TFieldValues, TName>[]) => void;
184
+ /** Insert one row (or several) at the front. */
185
+ prepend: (value: FieldArray<TFieldValues, TName> | FieldArray<TFieldValues, TName>[]) => void;
186
+ /** Insert at `index`. */
187
+ insert: (index: number, value: FieldArray<TFieldValues, TName> | FieldArray<TFieldValues, TName>[]) => void;
188
+ /** Remove `index` (or several); omit to clear every row. */
189
+ remove: (index?: number | number[]) => void;
190
+ /** Move a row, keeping its state (drag-reorder). */
191
+ move: (from: number, to: number) => void;
192
+ /** Exchange two rows. */
193
+ swap: (indexA: number, indexB: number) => void;
194
+ /** Replace every row at once. */
195
+ replace: (values: FieldArray<TFieldValues, TName>[]) => void;
196
+ /** Array-LEVEL validation message (a `.min(1)` on the array itself), not a row's. */
197
+ error?: string;
198
+ /** Resolved `FormRoot disabled` — gate the add/remove buttons on it. */
199
+ disabled: DisabledProp;
62
200
  }) => React.ReactNode;
63
201
  };
64
202
  /** Mapped field error from RHF — displayed via FormField error slot. */
@@ -1,6 +1,6 @@
1
1
  /** Foundation component prop types — @see docs/COMPONENTS.md#foundation */
2
2
  import type * as React from "react";
3
- import type { ActivityAnnounceProp, ActivityVariantProp, AsChildProp, ButtonSizeProp, ButtonVariantProp, ChildrenProp, ClassNameProp, DisabledProp, FontWeightProp, HeadingLevelProp, LabelProp, OnClickProp, PendingProp, RevealDelayProp, ShapeProp, SizeProp, TextAlignProp, TextSizeProp, TextToneProp } from "../vocabulary/index.js";
3
+ import type { ActivityAnnounceProp, ActivityVariantProp, AsChildProp, ButtonSizeProp, ButtonVariantProp, ChildrenProp, ClassNameProp, DisabledProp, FontWeightProp, HeadingLevelProp, LabelProp, OnClickProp, PendingProp, RevealDelayProp, ShapeProp, SizeProp, TextAlignProp, TextSizeProp, TextToneProp, TextWhitespaceProp } from "../vocabulary/index.js";
4
4
  /** @see Text — typographic primitive; replaces hand-rolled `<span className="text-[13px] …">`. */
5
5
  export type TextProp = Omit<React.HTMLAttributes<HTMLElement>, "color"> & {
6
6
  /** Render element. Default `span`. */
@@ -37,8 +37,24 @@ export type TextProp = Omit<React.HTMLAttributes<HTMLElement>, "color"> & {
37
37
  * line-clamp styling (never write the `line-clamp-N` utility page-side).
38
38
  */
39
39
  clamp?: number;
40
+ /**
41
+ * Whitespace handling. Default `normal` (CSS's own: newlines and space runs collapse).
42
+ *
43
+ * `pre-wrap` is for text a PERSON typed — a plain-text note, an issue description, a pasted log
44
+ * — where the line breaks and the indentation are CONTENT, not formatting. It preserves both and
45
+ * still wraps long lines at the container edge, and it breaks an over-long unbroken token (a URL,
46
+ * an id) rather than letting it overflow.
47
+ *
48
+ * Precedence is explicit and resolved in the component, not by CSS ordering: `truncate` is a
49
+ * single-line contract and WINS (dev builds warn, and `data-whitespace` is not emitted), while
50
+ * `clamp` composes with it — a clamped pre-wrap block shows its first N real lines.
51
+ */
52
+ whitespace?: TextWhitespaceProp;
40
53
  /** Tabular figures for aligned numbers. */
41
54
  tabular?: boolean;
55
+ decoration?: "none" | "underline" | "line-through";
56
+ /** Inline code chip; use with as="code". */
57
+ chip?: boolean;
42
58
  /** Monospace family (codes, ids). */
43
59
  mono?: boolean;
44
60
  htmlFor?: string;
@@ -1,10 +1,10 @@
1
- export type { AppShellProp, AuthFooterProp, AuthIdentityProp, OrgSwitcherLabels, OrgSwitcherOrganization, OrgSwitcherProp, PageContainerProp, PageInsetProp, SidebarItemProp, SidebarProductProp, SidebarProp, SidebarSectionProp, TopbarProp, } from "./layout.prop.js";
1
+ export type { AppLauncherApp, AppLauncherGroup, AppLauncherLabels, AppLauncherProp, AppShellProp, AuthFooterProp, AuthIdentityProp, OrgSwitcherLabels, OrgSwitcherOrganization, OrgSwitcherProp, PageContainerProp, PageInsetProp, SidebarItemProp, SidebarProductProp, SidebarProp, SidebarSectionProp, TopbarProp, } from "./layout.prop.js";
2
2
  export type { ButtonProp } from "./general.prop.js";
3
3
  export type { InputProp, TextareaProp, FormFieldProp, SearchInputProp, CheckboxProp, CheckboxGroupProp, ChoiceOptionProp, RadioProp, RadioGroupProp, SwitchProp, SliderProp, CalendarProp, DatePickerProp, DateRangePickerProp, TimePickerProp, ColorPickerProp, UploadProp, UploadFileItemProp, UploadVariantProp, TreeOptionProp, TreeFieldNamesProp, CascaderProp, TreeSelectProp, ShowCheckedStrategyProp, TransferProp, TransferItemProp, } from "./data-entry.prop.js";
4
4
  export type { AvatarProp, EmptyStateProp, DescriptionsProp, DescriptionsItemProp, BadgeProp, DataTableProp, QrCodeProp, } from "./data-display.prop.js";
5
5
  export type { ChartDatum, ChartSeriesProp, LineChartProp, BarChartProp, AreaChartProp, PieChartProp, } from "./charts.prop.js";
6
6
  export type { AlertQueryErrorProp, AlertProp, AlertTitleProp, AlertContentProp, AlertDescriptionProp, AlertActionsProp, SheetResponsiveProp, SkeletonRowsProp, } from "./feedback.prop.js";
7
7
  export type { DataStateProp, InfiniteQueryStateProp, InfiniteQueryHelpers, PrefetchLinkProp, } from "./query.prop.js";
8
- export type { PaginationProp, StepsProp, StepItemProp, StepStatusProp, TabsProp, TabItemProp, } from "./navigation.prop.js";
8
+ export type { DropdownMenuPlacementProp, PaginationProp, PaginationSizeProp, PaginationAlignProp, StepsProp, StepItemProp, StepStatusProp, StepsTypeProp, TabsProp, TabItemProp, TabsVariantProp, TabsPlacementProp, TabsExtraProp, TabsOnEditProp, } from "./navigation.prop.js";
9
9
  export type { AppProviderProp, AppContextValue, AppSettingKind, AppSettingPickerProp, AppSettingToggleKind, AppSettingToggleProp, } from "./app.prop.js";
10
10
  export type { ZodSchemaProp, UseZodFormOptionsProp, UseZodFormReturnProp, FormRootProp, FormFieldControlProp, FieldErrorMessageProp, } from "./form.prop.js";
@@ -24,6 +24,8 @@ export type PageContainerMeasureProp = "default" | "narrow" | "medium";
24
24
  export type PageContainerHeaderScaleProp = "document" | "chrome";
25
25
  /** @see PageContainer */
26
26
  export type PageContainerProp = {
27
+ toolbarPad?: PadProp;
28
+ footerPad?: PadProp;
27
29
  title: TitleProp;
28
30
  subtitle?: SubtitleProp;
29
31
  /**
@@ -101,7 +103,7 @@ export type FlexDirectionProp = "row" | "col";
101
103
  export type FlexAlignProp = "start" | "center" | "end" | "stretch" | "baseline";
102
104
  export type FlexJustifyProp = "start" | "center" | "end" | "between" | "around" | "evenly";
103
105
  /** @see Flex */
104
- export type FlexProp = React.HTMLAttributes<HTMLDivElement> & {
106
+ export type FlexProp = React.HTMLAttributes<HTMLElement> & {
105
107
  /**
106
108
  * Render element — `div` (default) or `span` when the Flex sits in a PHRASING context and a
107
109
  * `<div>` would be invalid HTML: inside a `TabsTrigger`/`PopoverTrigger`/`Button` (all of which
@@ -109,8 +111,16 @@ export type FlexProp = React.HTMLAttributes<HTMLDivElement> & {
109
111
  * inside a `<p>`. Same closed shape as `ListRow`'s `as` — it swaps the TAG, nothing else: the
110
112
  * `.ui-flex` rules carry `display: flex`, so the box is identical either way.
111
113
  */
112
- as?: "div" | "span";
113
- direction?: FlexDirectionProp;
114
+ as?: "div" | "span" | "ul" | "ol" | "li";
115
+ /** Lightweight surfaces for rows and notices; no Card elevation by default. */
116
+ surface?: "muted" | "popover" | "warning";
117
+ /** Negative inline inset, using the same spacing scale as pad. */
118
+ bleed?: GapProp;
119
+ /** Floating row actions: show on parent hover, focus-within, and touch. */
120
+ reveal?: "hover";
121
+ direction?: FlexDirectionProp | Partial<Record<"base" | BreakpointProp, FlexDirectionProp>>;
122
+ grow?: boolean;
123
+ shrink?: boolean;
114
124
  gap?: GapProp;
115
125
  /**
116
126
  * CỬA THOÁT: một khoảng cách tính bằng pixel, ngoài mọi bậc của thang.
@@ -213,8 +223,9 @@ export type ResponsiveGridColumnsProp = number | {
213
223
  * `pricing-plans` — the canonical billing/pricing-plan collection: 1 column until the `lg` step
214
224
  * (container ≥ 64rem), then 3 columns from `lg` upward.
215
225
  */
226
+ export type ResponsiveGridFlowProp = "rows" | "columns";
216
227
  export type ResponsiveGridPresetProp = "pricing-plans";
217
- export type MasterDetailRailWidthProp = "compact" | "standard";
228
+ export type MasterDetailRailWidthProp = "narrow" | "compact" | "standard" | "wide";
218
229
  export type MasterDetailRailProp = "master" | "detail";
219
230
  /**
220
231
  * Bounded viewport preset for the master collection. `auto` (default) never bounds it — the region
@@ -262,7 +273,8 @@ export type PageInsetProp = React.HTMLAttributes<HTMLDivElement> & {
262
273
  };
263
274
  /** @see AppShell */
264
275
  export type AppShellProp = {
265
- sidebar: ReactNode;
276
+ /** Omit or pass null/false for a shell without the sidebar landmark or grid track. */
277
+ sidebar?: ReactNode;
266
278
  children: ReactNode;
267
279
  topbar?: ReactNode;
268
280
  topbarLeft?: ReactNode;
@@ -467,6 +479,10 @@ export type MobileShellProp = {
467
479
  * so a service retunes a day divider or an unread watermark from its theme and never forks CSS.
468
480
  */
469
481
  export type SeparatorProp = Omit<React.HTMLAttributes<HTMLDivElement>, "children"> & {
482
+ labelSize?: "2xs" | "xs" | "sm" | "md";
483
+ space?: GapProp;
484
+ hideBelow?: BreakpointProp;
485
+ hideFrom?: BreakpointProp;
470
486
  /** Rule axis. Default `"horizontal"`. */
471
487
  orientation?: OrientationProp;
472
488
  /**
@@ -869,12 +885,132 @@ export type OrgSwitcherProp = {
869
885
  error?: ReactNode;
870
886
  onRetry?: () => void;
871
887
  labels: OrgSwitcherLabels;
888
+ /**
889
+ * WHICH SURFACE the panel opens on.
890
+ *
891
+ * - `"auto"` (default) — popover above `--sheet-responsive-breakpoint-width`, focus-trapped
892
+ * bottom Sheet at or below it.
893
+ * - `"dialog"` — a centred modal above that breakpoint, the same bottom Sheet below it. Reach for
894
+ * this once the panel carries more than a name per row — a role, a plan, a member count, a
895
+ * "create organization" action. A popover is anchored to its trigger, clipped by the viewport
896
+ * and sized by `--org-switcher-menu-width`; a dialog has a real title, a scrolling body and a
897
+ * footer, and takes the reader's full attention, which is the right trade when switching
898
+ * organization re-scopes everything on screen.
899
+ * - `"popover"` / `"sheet"` — pinned to one surface at every width. Useful for a deterministic
900
+ * embedded surface or a component test, rarely in a product.
901
+ *
902
+ * `auto` and `dialog` are the two RESPONSIVE pairs and differ only in their desktop half; the
903
+ * mobile half is the same Sheet, because a centred modal on a phone is a Sheet with worse
904
+ * ergonomics. All four resolve the breakpoint through the shared `useSheetResponsiveMode()`
905
+ * hook, so a service moves the line once for every overlay.
906
+ */
907
+ responsive?: "auto" | "popover" | "sheet" | "dialog";
908
+ open?: boolean;
909
+ onOpenChange?: (open: boolean) => void;
910
+ className?: ClassNameProp;
911
+ };
912
+ /**
913
+ * One app tile in the public {@link AppLauncher} contract.
914
+ *
915
+ * A tile is a REAL LINK, always. There is no `onClick`-only entry and no `disabled` entry: an app
916
+ * the viewer may not open is an app the consumer does not pass. A launcher that renders inert tiles
917
+ * is a launcher that teaches its users to stop trusting the grid.
918
+ */
919
+ export type AppLauncherApp = {
920
+ /** Stable app identifier — the React key, and the `data-app` hook an end-to-end test holds. */
921
+ id: string;
922
+ /** Visible app name. It is also the tile's accessible name — the mark is presentational. */
923
+ name: string;
924
+ /** The destination. Required, because the tile IS an `<a href>` (WCAG 2.2 / APG: link, not button). */
925
+ href: string;
926
+ /**
927
+ * Owned mark — a Lucide icon, a `<Logo>`, an `<img>`, an `<Avatar>`. Rendered `aria-hidden`;
928
+ * when omitted the launcher falls back to the first character of `name`, exactly as
929
+ * `OrgSwitcher` does for an organization with no avatar.
930
+ */
931
+ icon?: ReactNode;
932
+ /** The app the viewer is currently inside. That tile carries `aria-current="page"`. */
933
+ current?: boolean;
934
+ /**
935
+ * The destination leaves this SPA. Such a tile renders a plain `<a target="_blank" rel="noreferrer
936
+ * noopener">` and DELIBERATELY bypasses `linkComponent`: a client-side router link to another
937
+ * origin is a router asked to route somewhere it does not own, which is how a launcher entry
938
+ * turns into a blank screen. Pair it with `labels.externalHint` (WCAG 3.2.5).
939
+ */
940
+ external?: boolean;
941
+ };
942
+ /** A labelled section of the launcher grid — the "more from …" band of the Google-style panel. */
943
+ export type AppLauncherGroup = {
944
+ /** Section heading. Rendered as a real heading and used to name the section's own grid. */
945
+ label: string;
946
+ apps: readonly AppLauncherApp[];
947
+ };
948
+ /** Localized copy owned by the consuming product, never hard-coded by the component. */
949
+ export type AppLauncherLabels = {
950
+ /**
951
+ * Accessible name of the nine-dot trigger ("Apps" / "アプリ"). A plain string, NOT a function of
952
+ * the current app the way `OrgSwitcherLabels.trigger` is a function of the organization: the
953
+ * launcher's trigger shows no current value, so naming one in the trigger would announce a
954
+ * destination the button does not go to.
955
+ */
956
+ trigger: string;
957
+ /** Panel name — the popover's accessible name and the bottom Sheet's header title. */
958
+ title: string;
959
+ empty: string;
960
+ loading: string;
961
+ retry?: string;
962
+ /** Screen-reader suffix for an `external` tile, e.g. "(opens in a new tab)" (WCAG 3.2.5). */
963
+ externalHint?: string;
964
+ };
965
+ /**
966
+ * @see AppLauncher — the PLATFORM-scope app switcher that lives in the topbar.
967
+ *
968
+ * Related, and repeatedly confused with it:
969
+ *
970
+ * - `ServiceLauncherCard` (data-display) is also a launcher tile, but a PAGE-SIZED one: status,
971
+ * hostname, plan, an action button, a reason it is locked. It belongs on a service-catalogue
972
+ * page, where choosing is a considered act. `AppLauncher`'s tile is bar-sized — mark plus name,
973
+ * the whole tile a link — because switching app is a reflex, not a decision. Neither is built
974
+ * out of the other; a grid of `ServiceLauncherCard`s inside a popover is the wrong component.
975
+ * - `AppShellProp.navRail` expresses the SAME platform scope as a docked column. These are the two
976
+ * ways to say it, and a product picks ONE: the launcher suits a platform with MANY apps where
977
+ * switching is occasional (the Google Workspace shape), the rail suits a single product where
978
+ * switching workspace is a constant action worth permanent screen width (the Slack shape).
979
+ * Shipping both puts one scope in two places and makes neither authoritative.
980
+ */
981
+ export type AppLauncherProp = {
982
+ /** Ungrouped apps, rendered first, with no heading above them. */
983
+ apps: readonly AppLauncherApp[];
984
+ /** Labelled sections rendered after `apps`, in order. */
985
+ groups?: readonly AppLauncherGroup[];
986
+ labels: AppLauncherLabels;
987
+ /**
988
+ * Grid column count. Omit it and the panel keeps the stylesheet's own `--app-launcher-columns`
989
+ * (3, the Google-launcher shape, declared on `.ui-app-launcher-panel`): the default is where a
990
+ * theme can reach it, and this prop is the per-instance override written inline on top.
991
+ */
992
+ columns?: number;
993
+ /**
994
+ * THE framework-router contract, reusing `SidebarLinkComponentProp` VERBATIM — the same type
995
+ * `Sidebar` and `NavList` take, so a service that already wrote `inertiaSidebarLink(Link)` or
996
+ * `createSidebarLink(Link, "to")` for its rail hands the same value here. The launcher still
997
+ * composes the tile (mark, name, `aria-current`, the external hint); the consumer supplies only
998
+ * the element type. `external` apps bypass it — see {@link AppLauncherApp.external}.
999
+ */
1000
+ linkComponent?: SidebarLinkComponentProp;
1001
+ loading?: boolean;
1002
+ /** Error content replaces the grid while preserving the trigger and the retry affordance. */
1003
+ error?: ReactNode;
1004
+ onRetry?: () => void;
872
1005
  /**
873
1006
  * `"auto"` (default) uses the desktop popover above `--sheet-responsive-breakpoint-width` and a
874
1007
  * focus-trapped bottom Sheet at/below it — the SAME token that drives `SheetContent
875
1008
  * responsive="auto"`, resolved through the shared `useSheetResponsiveMode()` hook, so a service
876
1009
  * moves the drawer line once for every overlay instead of per component.
877
- * Explicit modes are useful for deterministic embedded surfaces and component tests.
1010
+ *
1011
+ * No `"dialog"` here, unlike `OrgSwitcher`: a launcher grid is a jump table, and a modal that
1012
+ * takes over the screen to offer nine links is heavier than the errand. Switching ORGANIZATION
1013
+ * re-scopes everything on screen and earns the interruption; opening an app does not.
878
1014
  */
879
1015
  responsive?: "auto" | "popover" | "sheet";
880
1016
  open?: boolean;
@@ -939,6 +1075,8 @@ export type SidebarProp = {
939
1075
  * configured via THEIR own props and dropped into a slot.
940
1076
  */
941
1077
  export type TopbarProp = Omit<React.HTMLAttributes<HTMLDivElement>, "children"> & {
1078
+ height?: "bar" | "auto";
1079
+ pad?: PadProp;
942
1080
  /** Inline-start cluster — typically the sidebar toggle + a brand mark (`Avatar`) + primary nav. */
943
1081
  start?: ReactNode;
944
1082
  /** Center cluster — optional (e.g. a search trigger or a page/entity switcher). */
@@ -964,6 +1102,25 @@ export type TopbarItemProp = Omit<React.ButtonHTMLAttributes<HTMLButtonElement>,
964
1102
  * Render the bar-cell shape ONTO the child instead of emitting a `<button>` — for a router link,
965
1103
  * or for a menu/popover trigger that needs to own the element itself.
966
1104
  */
1105
+ /** Hide below a shared responsive breakpoint, without changing cell height. */
1106
+ hideBelow?: BreakpointProp;
1107
+ /**
1108
+ * Unread count OVERLAID on the cell's glyph — the notification-bell affordance the cell's own use
1109
+ * cases name (gh#398). Pass the CONTENT ONLY, exactly like `SidebarItemProp.badge`: a number, a
1110
+ * string, `"99+"`. Position, size and colour come from `--topbar-item-badge-*`, so the count does
1111
+ * NOT widen the cell (an inline chip pushes the end cluster's shrink budget around every time the
1112
+ * count crosses a digit boundary) and a theme can retune the overlay once.
1113
+ *
1114
+ * The count is not an accessible name: give the cell an `aria-label` that says what the number
1115
+ * means (`aria-label={t("topbar.notifications.unread", { count })}`).
1116
+ */
1117
+ badge?: ReactNode;
1118
+ /**
1119
+ * Emphasis of `badge`. Vocabulary shared VERBATIM with `SidebarItemProp.badgeTone` so one count
1120
+ * pill reads the same in the rail and in the bar: `destructive` when the count is addressed to
1121
+ * the user rather than merely unread.
1122
+ */
1123
+ badgeTone?: SidebarBadgeToneProp;
967
1124
  asChild?: boolean;
968
1125
  children?: ReactNode;
969
1126
  className?: ClassNameProp;
@@ -130,10 +130,48 @@ export type PaginationProp = {
130
130
  */
131
131
  hideOnSinglePage?: boolean;
132
132
  simple?: boolean;
133
+ /**
134
+ * Ant Design `showQuickJumper`. Adds a "go to page" number field at the inline end of the bar;
135
+ * committing it (Enter, or the optional Go button) clamps into `[1, pageCount]` and fires
136
+ * `onValueChange`. Pass an object to supply the confirm button's content.
137
+ */
138
+ showQuickJumper?: boolean | {
139
+ goButton?: React.ReactNode;
140
+ };
141
+ /**
142
+ * Control tier of every button in the bar. `md` (default) is the library's standard control
143
+ * height; `sm` is Ant Design's `size="small"` pager for a dense table footer.
144
+ */
145
+ size?: PaginationSizeProp;
146
+ /**
147
+ * Ant Design `align`. Where the pager sits on its own inline axis — `end` (default) keeps the
148
+ * long-standing table-footer alignment.
149
+ */
150
+ align?: PaginationAlignProp;
151
+ /**
152
+ * Ant Design `responsive`. `true` (the default) collapses the bar to its `simple` form below the
153
+ * library's single mobile breakpoint (`useIsMobile`, max-width 767px) instead of leaving a number
154
+ * strip wider than the phone to scroll — measured at 390px: 224px wide, zero page buttons, no
155
+ * horizontal overflow. `simple` always wins; `responsive={false}` pins the full pager at every
156
+ * width.
157
+ */
158
+ responsive?: boolean;
133
159
  disabled?: DisabledProp;
134
160
  className?: ClassNameProp;
135
161
  onValueChange?: (page: number, pageSize: number) => void;
136
162
  };
163
+ /** @see Pagination — control tier (Ant Design `size`: `small` → `sm`, `middle` → `md`). */
164
+ export type PaginationSizeProp = "sm" | "md";
165
+ /** @see Pagination — inline-axis alignment of the bar (Ant Design `align`, RTL-logical). */
166
+ export type PaginationAlignProp = "start" | "center" | "end";
167
+ /**
168
+ * @see DropdownMenuContent — Ant Design `placement`, spelled on the LOGICAL inline axis.
169
+ * antd's names are physical (`bottomLeft`, `topRight`); the same six anchors are `bottomStart`,
170
+ * `topEnd` and so on here, so an Arabic or Hebrew app anchors on the correct edge with no second
171
+ * value. Only the block-axis set is offered — see the note on the `placement` prop for why the
172
+ * inline-side ones (antd `left*` / `right*`) stay on Radix's own physical `side`.
173
+ */
174
+ export type DropdownMenuPlacementProp = "top" | "topStart" | "topEnd" | "bottom" | "bottomStart" | "bottomEnd";
137
175
  export type StepStatusProp = "wait" | "process" | "finish" | "error";
138
176
  /** @see StepItem */
139
177
  export type StepItemProp = {
@@ -144,6 +182,13 @@ export type StepItemProp = {
144
182
  status?: StepStatusProp;
145
183
  disabled?: boolean;
146
184
  };
185
+ /**
186
+ * @see Steps — marker/rail appearance.
187
+ * `dot` IS Ant Design's `progressDot` (antd 6.6.2 deprecates that prop in favour of exactly this
188
+ * value). `inline` is the compact numbered auth/device progress row. `navigation` is antd's
189
+ * chevron-sectioned bar: each step becomes a full-width slab pointing at the next one.
190
+ */
191
+ export type StepsTypeProp = "default" | "dot" | "inline" | "navigation";
147
192
  /** @see Steps */
148
193
  export type StepsProp = {
149
194
  items?: StepItemProp[];
@@ -153,11 +198,18 @@ export type StepsProp = {
153
198
  orientation?: "horizontal" | "vertical";
154
199
  /**
155
200
  * Marker appearance. `inline` renders the compact numbered auth/device progress row without the
156
- * icon rail while preserving the same status and current-step semantics.
201
+ * icon rail while preserving the same status and current-step semantics; `navigation` renders
202
+ * Ant Design's chevron-sectioned bar.
157
203
  */
158
- type?: "default" | "dot" | "inline";
204
+ type?: StepsTypeProp;
159
205
  size?: "md" | "sm";
160
206
  titlePlacement?: "horizontal" | "vertical";
207
+ /**
208
+ * Ant Design `percent` — completion of the CURRENT (`process`) step only, 0–100. Draws a
209
+ * determinate arc around that step's marker and exposes it to assistive tech as a
210
+ * `progressbar`. Ignored by `inline`, which has no marker to draw into.
211
+ */
212
+ percent?: number;
161
213
  /**
162
214
  * The glyph between inline steps (`type="inline"` only). `chevron` (default, `›`) is the
163
215
  * breadcrumb-flavoured original.
@@ -174,14 +226,72 @@ export type TabItemProp = {
174
226
  label: React.ReactNode;
175
227
  content: React.ReactNode;
176
228
  disabled?: boolean;
229
+ /** Leading glyph inside the trigger (Ant Design `Tab.icon`). */
230
+ icon?: React.ReactNode;
231
+ /**
232
+ * Ant Design `Tab.closable`. Honoured only by `variant="editable-card"`, where it puts a remove
233
+ * button in the trigger that calls `onEdit(value, "remove")`. Defaults to `true` there.
234
+ */
235
+ closable?: boolean;
236
+ /** Ant Design `Tab.closeIcon` — replaces the default × on this item's remove button. */
237
+ closeIcon?: React.ReactNode;
238
+ };
239
+ /**
240
+ * @see Tabs — trigger-strip appearance. This is Ant Design's `type` spelled in the library's own
241
+ * `variant` vocabulary: `line`, `card` and `editable-card` are antd's values, `default` is the
242
+ * library's pill strip (antd has no equivalent).
243
+ */
244
+ export type TabsVariantProp = "default" | "line" | "card" | "editable-card";
245
+ /**
246
+ * @see Tabs — which edge the trigger strip parks on. This is Ant Design 6.6.2's `tabPlacement`
247
+ * (its `tabPosition` is deprecated there), so the inline values are already RTL-logical —
248
+ * `start`/`end`, never `left`/`right`. Both inline values also flip the tablist to vertical
249
+ * roving focus (WAI-ARIA APG), which is what `orientation="vertical"` did on its own before.
250
+ */
251
+ export type TabsPlacementProp = "top" | "bottom" | "start" | "end";
252
+ /**
253
+ * @see Tabs — Ant Design `tabBarExtraContent`, held to the library's `extra` slot name and to its
254
+ * logical inline axis: antd's `left`/`right` keys are `start`/`end` here, so an Arabic or Hebrew
255
+ * app gets the slot on the correct edge with no second code path.
256
+ */
257
+ export type TabsExtraProp = React.ReactNode | {
258
+ start?: React.ReactNode;
259
+ end?: React.ReactNode;
177
260
  };
261
+ /**
262
+ * @see Tabs — Ant Design `onEdit`. It is a NAMED alias rather than an inline signature so the
263
+ * field reads as one prop everywhere: the catalog-sync guard splits an object type on top-level
264
+ * commas, and an inline `(target, action) => void` leaks its second PARAMETER as a phantom prop.
265
+ */
266
+ export type TabsOnEditProp = (target: string | React.MouseEvent<HTMLButtonElement>, action: "add" | "remove") => void;
178
267
  /** @see Tabs — high-level tabs with optional `items` array. */
179
268
  export type TabsProp = {
180
269
  items?: TabItemProp[];
181
270
  value?: string;
182
271
  defaultValue?: string;
183
272
  onValueChange?: (value: string) => void;
184
- variant?: "default" | "line" | "card";
273
+ variant?: TabsVariantProp;
274
+ /** Ant Design `tabPlacement`. Default `top`. */
275
+ tabPlacement?: TabsPlacementProp;
276
+ /** Control tier of the triggers. Default `md`. Ant Design `size` (`small`/`middle`/`large`). */
277
+ size?: "sm" | "md" | "lg";
278
+ /** Ant Design `centered` — centre the trigger strip on its own inline axis. */
279
+ centered?: boolean;
280
+ /** Ant Design `tabBarExtraContent`, renamed and made logical. @see TabsExtraProp */
281
+ extra?: TabsExtraProp;
282
+ /**
283
+ * Ant Design `destroyOnHidden`. `true` (the default here, and Radix's own behaviour) unmounts a
284
+ * panel the moment it stops being selected. `false` keeps EVERY panel mounted and only hides the
285
+ * inactive ones, so a live chart, a scroll position or an unsent form draft survives a tab
286
+ * switch. The default is deliberately the opposite of antd's, which keeps panels mounted.
287
+ */
288
+ destroyOnHidden?: boolean;
289
+ /** Ant Design `onEdit`. `remove` passes the item's `value`; `add` passes the click event. */
290
+ onEdit?: TabsOnEditProp;
291
+ /** Ant Design `addIcon` — replaces the default + on the `editable-card` add button. */
292
+ addIcon?: React.ReactNode;
293
+ /** Ant Design `hideAdd` — keep `editable-card`'s remove buttons but drop the add button. */
294
+ hideAdd?: boolean;
185
295
  className?: ClassNameProp;
186
296
  listClassName?: ClassNameProp;
187
297
  contentClassName?: ClassNameProp;