@godxjp/ui 20.0.0 → 20.2.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 (273) hide show
  1. package/README.md +8 -2
  2. package/dist/app/app-provider.js +37 -21
  3. package/dist/app/index.d.ts +2 -0
  4. package/dist/app/index.js +2 -0
  5. package/dist/app/storage.d.ts +17 -0
  6. package/dist/app/storage.js +28 -0
  7. package/dist/app/theme-axes.d.ts +2 -0
  8. package/dist/app/theme-axes.js +45 -0
  9. package/dist/components/charts/chart-cartesian.d.ts +2 -1
  10. package/dist/components/charts/chart-cartesian.js +52 -3
  11. package/dist/components/charts/chart-category-axis.d.ts +55 -0
  12. package/dist/components/charts/chart-category-axis.js +93 -0
  13. package/dist/components/charts/chart-frame.d.ts +10 -1
  14. package/dist/components/charts/chart-frame.js +19 -3
  15. package/dist/components/charts/compact-bar-trend.d.ts +1 -1
  16. package/dist/components/charts/compact-bar-trend.js +2 -0
  17. package/dist/components/charts/pie-chart.d.ts +1 -1
  18. package/dist/components/charts/pie-chart.js +12 -1
  19. package/dist/components/charts/recharts-peer.d.ts +49 -0
  20. package/dist/components/charts/recharts-peer.js +45 -0
  21. package/dist/components/data-display/card.d.ts +12 -1
  22. package/dist/components/data-display/card.js +22 -4
  23. package/dist/components/data-display/code-block.js +6 -2
  24. package/dist/components/data-display/data-table.d.ts +39 -4
  25. package/dist/components/data-display/data-table.js +802 -270
  26. package/dist/components/data-display/descriptions.d.ts +27 -6
  27. package/dist/components/data-display/descriptions.js +58 -17
  28. package/dist/components/data-display/index.d.ts +2 -0
  29. package/dist/components/data-display/index.js +2 -0
  30. package/dist/components/data-display/list-row.d.ts +10 -1
  31. package/dist/components/data-display/list-row.js +7 -1
  32. package/dist/components/data-display/popover.d.ts +9 -3
  33. package/dist/components/data-display/popover.js +65 -11
  34. package/dist/components/data-display/range-timeline.d.ts +38 -0
  35. package/dist/components/data-display/range-timeline.js +161 -0
  36. package/dist/components/data-display/scroll-area.js +13 -2
  37. package/dist/components/data-display/service-launcher-card.js +14 -12
  38. package/dist/components/data-display/table.d.ts +71 -3
  39. package/dist/components/data-display/table.js +56 -18
  40. package/dist/components/data-display/tree-list.js +4 -9
  41. package/dist/components/data-entry/calendar.d.ts +2 -2
  42. package/dist/components/data-entry/calendar.js +23 -3
  43. package/dist/components/data-entry/cascader.d.ts +1 -1
  44. package/dist/components/data-entry/cascader.js +188 -24
  45. package/dist/components/data-entry/color-picker.d.ts +1 -1
  46. package/dist/components/data-entry/color-picker.js +17 -5
  47. package/dist/components/data-entry/control-appearance.d.ts +64 -0
  48. package/dist/components/data-entry/control-appearance.js +39 -0
  49. package/dist/components/data-entry/control-surface.d.ts +61 -0
  50. package/dist/components/data-entry/control-surface.js +39 -0
  51. package/dist/components/data-entry/date-picker.d.ts +1 -1
  52. package/dist/components/data-entry/date-picker.js +344 -113
  53. package/dist/components/data-entry/date-range-picker.d.ts +1 -1
  54. package/dist/components/data-entry/date-range-picker.js +278 -140
  55. package/dist/components/data-entry/form-field.d.ts +1 -1
  56. package/dist/components/data-entry/form-field.js +39 -4
  57. package/dist/components/data-entry/form.d.ts +4 -0
  58. package/dist/components/data-entry/form.js +4 -2
  59. package/dist/components/data-entry/index.d.ts +7 -3
  60. package/dist/components/data-entry/index.js +10 -1
  61. package/dist/components/data-entry/input-otp.d.ts +1 -1
  62. package/dist/components/data-entry/input.d.ts +12 -34
  63. package/dist/components/data-entry/input.js +92 -24
  64. package/dist/components/data-entry/month-picker.d.ts +1 -1
  65. package/dist/components/data-entry/month-picker.js +47 -10
  66. package/dist/components/data-entry/month-range-picker.d.ts +1 -1
  67. package/dist/components/data-entry/month-range-picker.js +51 -11
  68. package/dist/components/data-entry/number-input.d.ts +7 -0
  69. package/dist/components/data-entry/number-input.js +147 -98
  70. package/dist/components/data-entry/password-input.d.ts +1 -1
  71. package/dist/components/data-entry/radio.d.ts +1 -1
  72. package/dist/components/data-entry/radio.js +61 -13
  73. package/dist/components/data-entry/search-input.d.ts +1 -1
  74. package/dist/components/data-entry/search-input.js +16 -2
  75. package/dist/components/data-entry/search-select.d.ts +2 -2
  76. package/dist/components/data-entry/search-select.js +209 -78
  77. package/dist/components/data-entry/select.d.ts +22 -4
  78. package/dist/components/data-entry/select.js +215 -163
  79. package/dist/components/data-entry/slider.d.ts +9 -1
  80. package/dist/components/data-entry/slider.js +87 -9
  81. package/dist/components/data-entry/switch.d.ts +3 -0
  82. package/dist/components/data-entry/switch.js +29 -3
  83. package/dist/components/data-entry/textarea.d.ts +14 -56
  84. package/dist/components/data-entry/textarea.js +80 -33
  85. package/dist/components/data-entry/time-picker.d.ts +2 -2
  86. package/dist/components/data-entry/time-picker.js +333 -109
  87. package/dist/components/data-entry/time-range-picker.d.ts +5 -0
  88. package/dist/components/data-entry/time-range-picker.js +89 -0
  89. package/dist/components/data-entry/transfer.d.ts +1 -1
  90. package/dist/components/data-entry/transfer.js +86 -28
  91. package/dist/components/data-entry/tree-select.d.ts +1 -1
  92. package/dist/components/data-entry/tree-select.js +201 -113
  93. package/dist/components/data-entry/tree-utils.js +7 -14
  94. package/dist/components/data-entry/upload-files.d.ts +2 -0
  95. package/dist/components/data-entry/upload-files.js +31 -0
  96. package/dist/components/data-entry/upload-request.d.ts +4 -0
  97. package/dist/components/data-entry/upload-request.js +53 -0
  98. package/dist/components/data-entry/upload-types.d.ts +28 -0
  99. package/dist/components/data-entry/upload-types.js +2 -0
  100. package/dist/components/data-entry/upload.d.ts +2 -2
  101. package/dist/components/data-entry/upload.js +475 -115
  102. package/dist/components/feedback/dialog.js +19 -19
  103. package/dist/components/feedback/sheet.js +3 -0
  104. package/dist/components/feedback/tooltip.js +3 -0
  105. package/dist/components/general/button.d.ts +2 -1
  106. package/dist/components/general/button.js +7 -1
  107. package/dist/components/general/index.d.ts +1 -0
  108. package/dist/components/general/index.js +2 -0
  109. package/dist/components/general/typography.d.ts +3 -0
  110. package/dist/components/general/typography.js +15 -1
  111. package/dist/components/general/visually-hidden.d.ts +3 -0
  112. package/dist/components/general/visually-hidden.js +9 -0
  113. package/dist/components/layout/app-launcher.d.ts +34 -0
  114. package/dist/components/layout/app-launcher.js +261 -0
  115. package/dist/components/layout/app-shell.d.ts +3 -1
  116. package/dist/components/layout/app-shell.js +34 -14
  117. package/dist/components/layout/auth-shell.d.ts +1 -1
  118. package/dist/components/layout/auth-shell.js +2 -0
  119. package/dist/components/layout/breadcrumb.d.ts +14 -2
  120. package/dist/components/layout/breadcrumb.js +46 -4
  121. package/dist/components/layout/flex.d.ts +1 -1
  122. package/dist/components/layout/flex.js +23 -2
  123. package/dist/components/layout/index.d.ts +3 -0
  124. package/dist/components/layout/index.js +5 -1
  125. package/dist/components/layout/org-switcher.js +20 -1
  126. package/dist/components/layout/page-container.d.ts +1 -1
  127. package/dist/components/layout/page-container.js +5 -3
  128. package/dist/components/layout/responsive-grid.d.ts +16 -2
  129. package/dist/components/layout/responsive-grid.js +29 -2
  130. package/dist/components/layout/sidebar.js +2 -1
  131. package/dist/components/layout/topbar-item.d.ts +3 -0
  132. package/dist/components/layout/topbar-item.js +18 -3
  133. package/dist/components/layout/topbar.d.ts +1 -1
  134. package/dist/components/layout/topbar.js +27 -6
  135. package/dist/components/navigation/dropdown-menu.d.ts +30 -2
  136. package/dist/components/navigation/dropdown-menu.js +73 -11
  137. package/dist/components/navigation/pagination.d.ts +2 -2
  138. package/dist/components/navigation/pagination.js +155 -83
  139. package/dist/components/navigation/steps.d.ts +2 -2
  140. package/dist/components/navigation/steps.js +29 -4
  141. package/dist/components/navigation/tabs.d.ts +5 -33
  142. package/dist/components/navigation/tabs.js +232 -64
  143. package/dist/components/ui/hover-card.js +3 -0
  144. package/dist/components/ui/input-otp.d.ts +26 -28
  145. package/dist/components/ui/input-otp.js +50 -7
  146. package/dist/components/ui/password-input.d.ts +36 -2
  147. package/dist/components/ui/password-input.js +27 -7
  148. package/dist/components/ui/rating.d.ts +25 -0
  149. package/dist/components/ui/rating.js +67 -27
  150. package/dist/components/ui/segmented.d.ts +9 -0
  151. package/dist/components/ui/segmented.js +17 -2
  152. package/dist/components/ui/separator.d.ts +4 -0
  153. package/dist/components/ui/separator.js +13 -0
  154. package/dist/components/ui/tag-input.d.ts +45 -0
  155. package/dist/components/ui/tag-input.js +109 -27
  156. package/dist/form/form-context.d.ts +29 -0
  157. package/dist/form/form-context.js +44 -4
  158. package/dist/form/form-field-array.d.ts +22 -0
  159. package/dist/form/form-field-array.js +50 -0
  160. package/dist/form/form-field-control.d.ts +2 -1
  161. package/dist/form/form-field-control.js +116 -40
  162. package/dist/form/form-root.d.ts +2 -1
  163. package/dist/form/form-root.js +142 -23
  164. package/dist/form/index.d.ts +3 -1
  165. package/dist/form/index.js +12 -1
  166. package/dist/i18n/index.d.ts +1 -1
  167. package/dist/i18n/index.js +3 -1
  168. package/dist/i18n/messages/en.json +59 -6
  169. package/dist/i18n/messages/ja.json +59 -6
  170. package/dist/i18n/messages/vi.json +59 -6
  171. package/dist/i18n/translate.d.ts +19 -0
  172. package/dist/i18n/translate.js +24 -0
  173. package/dist/inertia/index.d.ts +20 -0
  174. package/dist/inertia/index.js +60 -1
  175. package/dist/lib/control-styles.d.ts +25 -3
  176. package/dist/lib/control-styles.js +9 -3
  177. package/dist/lib/datetime/picker-format.d.ts +8 -0
  178. package/dist/lib/datetime/picker-format.js +54 -0
  179. package/dist/lib/overlay-portal.d.ts +18 -0
  180. package/dist/lib/overlay-portal.js +17 -0
  181. package/dist/props/components/app.prop.d.ts +13 -2
  182. package/dist/props/components/charts.prop.d.ts +21 -0
  183. package/dist/props/components/data-display.prop.d.ts +55 -4
  184. package/dist/props/components/data-entry.prop.d.ts +687 -43
  185. package/dist/props/components/form.prop.d.ts +142 -4
  186. package/dist/props/components/general.prop.d.ts +30 -1
  187. package/dist/props/components/index.d.ts +2 -2
  188. package/dist/props/components/layout.prop.d.ts +255 -8
  189. package/dist/props/components/navigation.prop.d.ts +113 -3
  190. package/dist/props/registry.d.ts +376 -10
  191. package/dist/props/registry.js +493 -9
  192. package/dist/props/vocabulary/data.prop.d.ts +179 -1
  193. package/dist/props/vocabulary/index.d.ts +4 -4
  194. package/dist/props/vocabulary/interaction.prop.d.ts +51 -2
  195. package/dist/props/vocabulary/navigation.prop.d.ts +40 -0
  196. package/dist/props/vocabulary/shared.prop.d.ts +33 -0
  197. package/dist/styles/badge-layout.css +2 -1
  198. package/dist/styles/card-layout.css +36 -5
  199. package/dist/styles/chart-layout.css +17 -1
  200. package/dist/styles/control.css +520 -14
  201. package/dist/styles/data-display-layout.css +248 -7
  202. package/dist/styles/data-entry-layout.css +13 -0
  203. package/dist/styles/layout.css +221 -4
  204. package/dist/styles/navigation-layout.css +230 -1
  205. package/dist/styles/shell-layout.css +690 -21
  206. package/dist/styles/table-layout.css +95 -6
  207. package/dist/styles/text-layout.css +5 -0
  208. package/dist/tokens/base.css +1 -0
  209. package/dist/tokens/components/badge.css +1 -0
  210. package/dist/tokens/components/chart.css +6 -0
  211. package/dist/tokens/components/control.css +81 -3
  212. package/dist/tokens/components/data-display.css +9 -0
  213. package/dist/tokens/components/descriptions.css +11 -0
  214. package/dist/tokens/components/flex.css +8 -0
  215. package/dist/tokens/components/navigation.css +55 -0
  216. package/dist/tokens/components/shell.css +100 -5
  217. package/dist/tokens/components/table.css +14 -0
  218. package/dist/tokens/foundation.css +2 -0
  219. package/dist/tokens/semantic/layout.css +9 -0
  220. package/docs/CONSUMER-RULES.md +13 -0
  221. package/docs/DESIGN-AUTHORITY.md +43 -6
  222. package/docs/DEVELOPMENT.md +4 -3
  223. package/docs/FORMS.md +151 -6
  224. package/docs/FRAME-COVERAGE-REPORT.md +29 -16
  225. package/docs/README.md +1 -1
  226. package/docs/STANDARDS-vocabulary-tokens.md +1 -1
  227. package/docs/TESTING.md +15 -6
  228. package/docs/charts/cjk-category-axis.tsx +81 -0
  229. package/docs/data-display/card/index.tsx +22 -0
  230. package/docs/data-display/data-table/examples/antd-parity.tsx +257 -0
  231. package/docs/data-display/data-table/index.tsx +23 -0
  232. package/docs/data-display/descriptions.tsx +41 -0
  233. package/docs/data-display/list-row.tsx +6 -6
  234. package/docs/data-display/scroll-area.tsx +31 -25
  235. package/docs/data-display/table.tsx +104 -45
  236. package/docs/data-display/timeline.tsx +41 -0
  237. package/docs/data-entry/date-picker.tsx +85 -0
  238. package/docs/data-entry/date-range-picker.tsx +26 -0
  239. package/docs/data-entry/form-dynamic-fields.tsx +199 -0
  240. package/docs/data-entry/form.tsx +74 -4
  241. package/docs/data-entry/input-otp.tsx +24 -0
  242. package/docs/data-entry/input.tsx +46 -1
  243. package/docs/data-entry/month-range-picker.tsx +1 -1
  244. package/docs/data-entry/select.tsx +27 -0
  245. package/docs/data-entry/switch.tsx +41 -0
  246. package/docs/data-entry/textarea.tsx +38 -0
  247. package/docs/data-entry/time-picker.tsx +85 -1
  248. package/docs/data-entry/time-range-picker.tsx +55 -0
  249. package/docs/data-entry/transfer.tsx +17 -0
  250. package/docs/data-entry/upload.tsx +56 -12
  251. package/docs/feedback/tooltip.tsx +1 -1
  252. package/docs/general/activity.tsx +2 -2
  253. package/docs/general/button/index.tsx +14 -1
  254. package/docs/general/typography.tsx +14 -1
  255. package/docs/layout/app-launcher.tsx +195 -0
  256. package/docs/layout/app-shell-arrangements.tsx +5 -5
  257. package/docs/layout/app-shell.tsx +11 -0
  258. package/docs/layout/flex.tsx +50 -0
  259. package/docs/layout/responsive-grid.tsx +21 -1
  260. package/docs/layout/topbar.tsx +5 -9
  261. package/docs/navigation/app-setting-picker.tsx +11 -0
  262. package/docs/navigation/breadcrumb.tsx +48 -0
  263. package/docs/navigation/dropdown-menu.tsx +21 -0
  264. package/docs/navigation/pagination.tsx +52 -0
  265. package/docs/navigation/steps.tsx +37 -0
  266. package/docs/navigation/tabs.tsx +97 -1
  267. package/docs/query/button-refetch.tsx +1 -0
  268. package/docs/showcase/settings-security-mfa.tsx +3 -3
  269. package/package.json +24 -4
  270. package/scripts/_agent-setup.mjs +76 -9
  271. package/scripts/init-guinea-pig.mjs +26 -4
  272. package/scripts/ui-audit.mjs +243 -30
  273. package/scripts/visual-audit.mjs +45 -7
@@ -6,30 +6,50 @@ import { useTranslation } from "../../i18n/use-translation.js";
6
6
  import { cn } from "../../lib/utils.js";
7
7
  import { Input } from "../data-entry/input.js";
8
8
  const PasswordInput = React.forwardRef(
9
- ({ className, ...props }, ref) => {
9
+ ({ className, visibilityToggle = true, iconRender, suffix, trailingIcon, allowClear, ...props }, ref) => {
10
10
  const { t } = useTranslation();
11
- const [visible, setVisible] = React.useState(false);
11
+ const controlledVisible = typeof visibilityToggle === "object" ? visibilityToggle.visible : void 0;
12
+ const onVisibleChange = typeof visibilityToggle === "object" ? visibilityToggle.onVisibleChange : void 0;
13
+ const showToggle = visibilityToggle !== false;
14
+ const [internalVisible, setInternalVisible] = React.useState(false);
15
+ const isVisibleControlled = controlledVisible !== void 0;
16
+ const visible = showToggle ? isVisibleControlled ? controlledVisible : internalVisible : false;
17
+ const setVisible = (next) => {
18
+ if (!isVisibleControlled) setInternalVisible(next);
19
+ onVisibleChange?.(next);
20
+ };
21
+ const toggleOwnsTrailing = showToggle;
22
+ if (toggleOwnsTrailing && process.env?.NODE_ENV !== "production" && (suffix != null || trailingIcon != null || allowClear)) {
23
+ console.warn(
24
+ "[godxjp-ui] PasswordInput: the reveal toggle owns the trailing slot, so `suffix` / `trailingIcon` / `allowClear` are ignored. Use `leadingIcon` (or `prefix`), or pass `visibilityToggle={false}` to hand the slot back."
25
+ );
26
+ }
12
27
  return /* @__PURE__ */ jsxs("div", { className: "ui-password-input", "data-slot": "password-input", children: [
13
28
  /* @__PURE__ */ jsx(
14
29
  Input,
15
30
  {
16
31
  ref,
17
32
  type: visible ? "text" : "password",
18
- className: cn("ui-password-input-field", className),
33
+ className: cn(showToggle && "ui-password-input-field", className),
34
+ suffix: toggleOwnsTrailing ? void 0 : suffix,
35
+ trailingIcon: toggleOwnsTrailing ? void 0 : trailingIcon,
36
+ allowClear: toggleOwnsTrailing ? false : allowClear,
19
37
  ...props
20
38
  }
21
39
  ),
22
- /* @__PURE__ */ jsx(
40
+ showToggle ? /* @__PURE__ */ jsx(
23
41
  "button",
24
42
  {
25
43
  type: "button",
26
44
  className: "ui-password-input-toggle",
27
- onClick: () => setVisible((v) => !v),
45
+ disabled: props.disabled,
46
+ onMouseDown: (event) => event.preventDefault(),
47
+ onClick: () => setVisible(!visible),
28
48
  "aria-label": visible ? t("ui.passwordInput.hide") : t("ui.passwordInput.show"),
29
49
  "aria-pressed": visible,
30
- children: visible ? /* @__PURE__ */ jsx(EyeOff, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Eye, { "aria-hidden": "true" })
50
+ children: iconRender ? iconRender(visible) : visible ? /* @__PURE__ */ jsx(EyeOff, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Eye, { "aria-hidden": "true" })
31
51
  }
32
- )
52
+ ) : null
33
53
  ] });
34
54
  }
35
55
  );
@@ -3,7 +3,32 @@ export type RatingProps = {
3
3
  value?: number;
4
4
  defaultValue?: number;
5
5
  onValueChange?: (value: number) => void;
6
+ /** Number of symbols. This library's older name for antd's `count`; both are accepted. */
6
7
  max?: number;
8
+ /** antd `count` — number of symbols. Default 5. */
9
+ count?: number;
10
+ /**
11
+ * antd `allowHalf` — a symbol can be half-filled, so the scale is 0.5 … count in steps of 0.5.
12
+ * The keyboard steps by a half too, and each symbol becomes TWO hit areas (leading / trailing).
13
+ */
14
+ allowHalf?: boolean;
15
+ /**
16
+ * antd `allowClear` — choosing the value that is already chosen clears it back to 0. On by
17
+ * default in antd; off here, because a rating inside a form is usually required and a silent
18
+ * reset on a second click reads as a lost answer.
19
+ */
20
+ allowClear?: boolean;
21
+ /**
22
+ * antd `character` — what a symbol IS. A node for every symbol, or a function of the 1-based
23
+ * index for a scale whose symbols differ (A/B/C, 松竹梅, a heart for the top step).
24
+ */
25
+ character?: React.ReactNode | ((index: number) => React.ReactNode);
26
+ /**
27
+ * antd `tooltips` — a label per step, in order. It is folded into each symbol's ACCESSIBLE NAME
28
+ * rather than shown only on hover: a `title` attribute is invisible to a keyboard and to touch,
29
+ * and the whole point of the prop is to say what "3 of 5" means.
30
+ */
31
+ tooltips?: readonly string[];
7
32
  readOnly?: boolean;
8
33
  disabled?: boolean;
9
34
  name?: string;
@@ -9,7 +9,12 @@ const Rating = React.forwardRef(
9
9
  value,
10
10
  defaultValue = 0,
11
11
  onValueChange,
12
- max = 5,
12
+ max,
13
+ count,
14
+ allowHalf = false,
15
+ allowClear = false,
16
+ character,
17
+ tooltips,
13
18
  readOnly,
14
19
  disabled,
15
20
  name,
@@ -17,68 +22,103 @@ const Rating = React.forwardRef(
17
22
  ...rest
18
23
  }, ref) => {
19
24
  const { t } = useTranslation();
25
+ const symbols = count ?? max ?? 5;
20
26
  const [internal, setInternal] = React.useState(defaultValue);
21
27
  const current = value ?? internal;
22
28
  const [hover, setHover] = React.useState(null);
23
29
  const display = hover ?? current;
24
30
  const interactive = !readOnly && !disabled;
31
+ const stepSize = allowHalf ? 0.5 : 1;
25
32
  const select = (next) => {
26
33
  if (!interactive) return;
27
- if (value === void 0) setInternal(next);
28
- onValueChange?.(next);
34
+ const resolved = allowClear && next === current ? 0 : next;
35
+ if (value === void 0) setInternal(resolved);
36
+ onValueChange?.(resolved);
29
37
  };
30
- const focusableStar = current > 0 ? current : 1;
38
+ const focusableStar = current > 0 ? Math.ceil(current) : 1;
31
39
  const onKeyDown = (e, star) => {
32
40
  if (!interactive) return;
33
41
  let next;
34
42
  switch (e.key) {
35
43
  case "ArrowRight":
36
44
  case "ArrowUp":
37
- next = Math.min(max, star + 1);
45
+ next = Math.min(symbols, star + stepSize);
38
46
  break;
39
47
  case "ArrowLeft":
40
48
  case "ArrowDown":
41
- next = Math.max(1, star - 1);
49
+ next = Math.max(stepSize, star - stepSize);
42
50
  break;
43
51
  case "Home":
44
- next = 1;
52
+ next = stepSize;
45
53
  break;
46
54
  case "End":
47
- next = max;
55
+ next = symbols;
48
56
  break;
49
57
  default:
50
58
  return;
51
59
  }
52
60
  e.preventDefault();
53
- select(next);
61
+ if (value === void 0) setInternal(next);
62
+ onValueChange?.(next);
63
+ };
64
+ const stepLabel = (star) => {
65
+ const tooltip = tooltips?.[star - 1];
66
+ const base = t("ui.rating.starLabel", { star, max: symbols });
67
+ return tooltip ? `${base}, ${tooltip}` : base;
54
68
  };
69
+ const glyph = (star) => typeof character === "function" ? character(star) : character ?? /* @__PURE__ */ jsx(Star, { "aria-hidden": "true" });
55
70
  return /* @__PURE__ */ jsxs(
56
71
  "div",
57
72
  {
58
73
  ref,
59
74
  role: "radiogroup",
60
75
  "data-slot": "rating",
76
+ "data-allow-half": allowHalf ? "true" : void 0,
61
77
  className: cn("ui-rating", className),
62
78
  "aria-label": rest["aria-label"] ?? t("ui.rating.ariaLabel"),
63
79
  children: [
64
- Array.from({ length: max }, (_, i) => i + 1).map((star) => /* @__PURE__ */ jsx(
65
- "button",
66
- {
67
- type: "button",
68
- role: "radio",
69
- "aria-checked": current === star,
70
- "aria-label": t("ui.rating.starLabel", { star, max }),
71
- disabled: disabled || readOnly,
72
- tabIndex: interactive && star === focusableStar ? 0 : -1,
73
- className: cn("ui-rating-star", star <= display && "ui-rating-star-filled"),
74
- onMouseEnter: () => interactive && setHover(star),
75
- onMouseLeave: () => setHover(null),
76
- onClick: () => select(star),
77
- onKeyDown: (e) => onKeyDown(e, star),
78
- children: /* @__PURE__ */ jsx(Star, { "aria-hidden": "true" })
79
- },
80
- star
81
- )),
80
+ Array.from({ length: symbols }, (_, i) => i + 1).map((star) => {
81
+ const symbol = /* @__PURE__ */ jsx(
82
+ "button",
83
+ {
84
+ type: "button",
85
+ role: "radio",
86
+ "aria-checked": current === star,
87
+ "aria-label": stepLabel(star),
88
+ disabled: disabled || readOnly,
89
+ tabIndex: interactive && star === focusableStar ? 0 : -1,
90
+ className: cn(
91
+ "ui-rating-star",
92
+ star <= display && "ui-rating-star-filled",
93
+ allowHalf && star - 0.5 === display && "ui-rating-star-half-filled"
94
+ ),
95
+ onMouseEnter: () => interactive && setHover(star),
96
+ onMouseLeave: () => setHover(null),
97
+ onClick: () => select(star),
98
+ onKeyDown: (e) => onKeyDown(e, star),
99
+ children: glyph(star)
100
+ },
101
+ star
102
+ );
103
+ if (!allowHalf) return symbol;
104
+ return /* @__PURE__ */ jsxs("span", { "data-slot": "rating-symbol", className: "ui-rating-symbol", children: [
105
+ /* @__PURE__ */ jsx(
106
+ "button",
107
+ {
108
+ type: "button",
109
+ tabIndex: -1,
110
+ "aria-hidden": "true",
111
+ disabled: disabled || readOnly,
112
+ "data-slot": "rating-half",
113
+ className: "ui-rating-star-half",
114
+ onMouseEnter: () => interactive && setHover(star - 0.5),
115
+ onMouseLeave: () => setHover(null),
116
+ onClick: () => select(star - 0.5)
117
+ }
118
+ ),
119
+ symbol
120
+ ] }, star);
121
+ }),
82
122
  name ? /* @__PURE__ */ jsx("input", { type: "hidden", name, value: current }) : null
83
123
  ]
84
124
  }
@@ -18,6 +18,15 @@ export type SegmentedProp = {
18
18
  /** Uncontrolled initial selection. */
19
19
  defaultValue?: string;
20
20
  onValueChange?: (value: string) => void;
21
+ /**
22
+ * antd `block` — stretch the bar to its container and share the width EQUALLY between the
23
+ * choices, so the selected pill does not resize as the label changes length.
24
+ */
25
+ block?: boolean;
26
+ /** antd `vertical` — stack the choices in a column. Arrow keys follow the axis. */
27
+ vertical?: boolean;
28
+ /** Control height tier: `md` (default), `sm` or `lg` — the same tiers as every other control. */
29
+ size?: "sm" | "md" | "lg";
21
30
  /** Disable the whole group. */
22
31
  disabled?: boolean;
23
32
  /** Form field name — submits the selected value with the form. */
@@ -3,15 +3,30 @@ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
5
5
  import { cn } from "../../lib/utils.js";
6
- const Segmented = React.forwardRef(function Segmented2({ options, value, defaultValue, onValueChange, disabled, name, id, className, ...props }, ref) {
6
+ const Segmented = React.forwardRef(function Segmented2({
7
+ options,
8
+ value,
9
+ defaultValue,
10
+ onValueChange,
11
+ disabled,
12
+ block = false,
13
+ vertical = false,
14
+ size,
15
+ name,
16
+ id,
17
+ className,
18
+ ...props
19
+ }, ref) {
7
20
  return /* @__PURE__ */ jsx(
8
21
  RadioGroupPrimitive.Root,
9
22
  {
10
23
  ref,
11
24
  id,
12
25
  "data-slot": "segmented",
26
+ "data-block": block ? "true" : void 0,
27
+ "data-size": size,
13
28
  className: cn("ui-segmented", className),
14
- orientation: "horizontal",
29
+ orientation: vertical ? "vertical" : "horizontal",
15
30
  value,
16
31
  defaultValue,
17
32
  onValueChange,
@@ -12,6 +12,10 @@ export type { SeparatorProp, SeparatorProp as SeparatorProps, } from "../../prop
12
12
  * the ref, and we decide what element carries them.
13
13
  */
14
14
  export declare const Separator: React.ForwardRefExoticComponent<Omit<React.HTMLAttributes<HTMLDivElement>, "children"> & {
15
+ labelSize?: "2xs" | "xs" | "sm" | "md";
16
+ space?: import("../../props/index.js").GapProp;
17
+ hideBelow?: import("../../props/index.js").BreakpointProp;
18
+ hideFrom?: import("../../props/index.js").BreakpointProp;
15
19
  orientation?: import("../../props/index.js").OrientationProp;
16
20
  label?: string;
17
21
  labelAlign?: import("../../props/index.js").TextAlignProp;
@@ -1,10 +1,16 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import * as React from "react";
3
3
  import { Separator as AriaSeparator } from "react-aria-components";
4
+ import { padStepToken } from "../../lib/variants.js";
4
5
  import { cn } from "../../lib/utils.js";
5
6
  const Separator = React.forwardRef(
6
7
  ({
7
8
  className,
9
+ labelSize,
10
+ space,
11
+ hideBelow,
12
+ hideFrom,
13
+ style,
8
14
  orientation = "horizontal",
9
15
  decorative,
10
16
  label,
@@ -28,6 +34,13 @@ const Separator = React.forwardRef(
28
34
  ref,
29
35
  elementType: "div",
30
36
  "data-slot": "separator",
37
+ "data-label-size": labelSize,
38
+ "data-hide-below": hideBelow,
39
+ "data-hide-from": hideFrom,
40
+ style: {
41
+ ...style,
42
+ ...space === void 0 ? void 0 : { marginBlock: padStepToken(space) }
43
+ },
31
44
  "data-orientation": orientation,
32
45
  "data-tone": tone,
33
46
  "data-labelled": labelled ? "" : void 0,
@@ -1,13 +1,58 @@
1
1
  import * as React from "react";
2
+ import type { AllowClearProp, ControlStatusProp, ControlVariantProp, MaxTagCountProp, MaxTagPlaceholderProp, SizeProp } from "../../props/vocabulary/index.js";
3
+ /**
4
+ * TagInput is this library's answer to antd's `Select mode="tags"` — a free-text token field — so
5
+ * it takes the same token-level props antd puts on that mode.
6
+ */
2
7
  export type TagInputProps = {
3
8
  value?: string[];
4
9
  defaultValue?: string[];
5
10
  onValueChange?: (tags: string[]) => void;
6
11
  placeholder?: string;
7
12
  disabled?: boolean;
13
+ /**
14
+ * Read-only: the tags stay visible, selectable and submitted, but nothing can be added or
15
+ * removed — the draft field is read-only, the chip removers and the clear ✕ are withdrawn, and
16
+ * the container reports `aria-readonly`. Mirrors Select's readOnly contract (still focusable and
17
+ * still in the tab order, unlike `disabled`).
18
+ */
19
+ readOnly?: boolean;
8
20
  name?: string;
9
21
  className?: string;
10
22
  id?: string;
11
23
  "aria-label"?: string;
24
+ /** Control height tier (antd `size`) — the shared `--control-height` ladder. */
25
+ size?: SizeProp;
26
+ /** Validation status (antd `status`). `error` also sets `aria-invalid`; `warning` recolours only. */
27
+ status?: ControlStatusProp;
28
+ /** Control surface (antd `variant`). Default `outlined`. */
29
+ variant?: ControlVariantProp;
30
+ /** Hard ceiling on how many tags may be held (antd `maxCount`). Further input is refused. */
31
+ maxCount?: number;
32
+ /**
33
+ * antd `allowClear` — a single ✕ that drops EVERY tag at once. Off by default (antd's own
34
+ * default for a tags field). The object form replaces the icon and/or the accessible label.
35
+ */
36
+ allowClear?: AllowClearProp;
37
+ /** Fired after every tag is dropped through the ✕ (antd `onClear`). */
38
+ onClear?: () => void;
39
+ /** How many chips render before the rest collapse into the overflow node (antd `maxTagCount`). */
40
+ maxTagCount?: MaxTagCountProp;
41
+ /** The node standing in for what `maxTagCount` hid (antd `maxTagPlaceholder`). */
42
+ maxTagPlaceholder?: MaxTagPlaceholderProp;
43
+ /** Render one chip yourself (antd `tagRender`) — receives the value and an `onClose` remover. */
44
+ tagRender?: (props: {
45
+ value: string;
46
+ label: React.ReactNode;
47
+ onClose: () => void;
48
+ index: number;
49
+ disabled: boolean;
50
+ }) => React.ReactNode;
51
+ /**
52
+ * Characters that commit the draft into a tag (antd `tokenSeparators`). Default `[","]`; Enter
53
+ * always commits and is not a separator. Pasting a run containing a separator splits it into
54
+ * several tags, which is antd's behaviour and the reason the prop exists.
55
+ */
56
+ tokenSeparators?: string[];
12
57
  };
13
58
  export declare const TagInput: React.ForwardRefExoticComponent<TagInputProps & React.RefAttributes<HTMLInputElement>>;
@@ -1,9 +1,17 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { X } from "lucide-react";
5
5
  import { useTranslation } from "../../i18n/use-translation.js";
6
6
  import { cn } from "../../lib/utils.js";
7
+ import {
8
+ applyMaxTagCount,
9
+ controlSurfaceAttrs,
10
+ resolveAllowClear
11
+ } from "../data-entry/control-surface.js";
12
+ function escapeForCharClass(character) {
13
+ return character.replace(/[\\\]^-]/g, "\\$&");
14
+ }
7
15
  const TagInput = React.forwardRef(
8
16
  ({
9
17
  value,
@@ -11,10 +19,21 @@ const TagInput = React.forwardRef(
11
19
  onValueChange,
12
20
  placeholder,
13
21
  disabled,
22
+ readOnly,
14
23
  name,
15
24
  className,
16
25
  id,
17
- "aria-label": ariaLabel
26
+ "aria-label": ariaLabel,
27
+ size,
28
+ status,
29
+ variant,
30
+ maxCount,
31
+ allowClear,
32
+ onClear,
33
+ maxTagCount,
34
+ maxTagPlaceholder,
35
+ tagRender,
36
+ tokenSeparators = [","]
18
37
  }, ref) => {
19
38
  const { t } = useTranslation();
20
39
  const [internal, setInternal] = React.useState(defaultValue);
@@ -27,11 +46,25 @@ const TagInput = React.forwardRef(
27
46
  const add = (raw) => {
28
47
  const tag = raw.trim();
29
48
  if (!tag || tags.includes(tag)) return;
49
+ if (maxCount !== void 0 && tags.length >= maxCount) return;
30
50
  commit([...tags, tag]);
31
51
  };
52
+ const addAll = (raw) => {
53
+ let next = [...tags];
54
+ const pieces = tokenSeparators.length ? raw.split(new RegExp(`[${tokenSeparators.map(escapeForCharClass).join("")}]`)) : [raw];
55
+ for (const piece of pieces) {
56
+ const tag = piece.trim();
57
+ if (!tag || next.includes(tag)) continue;
58
+ if (maxCount !== void 0 && next.length >= maxCount) break;
59
+ next = [...next, tag];
60
+ }
61
+ if (next.length !== tags.length) commit(next);
62
+ };
32
63
  const removeAt = (i) => commit(tags.filter((_, idx) => idx !== i));
33
64
  const onKeyDown = (e) => {
34
- if (e.key === "Enter" || e.key === ",") {
65
+ if (readOnly) return;
66
+ if (e.nativeEvent.isComposing) return;
67
+ if (e.key === "Enter" || tokenSeparators.includes(e.key)) {
35
68
  e.preventDefault();
36
69
  add(draft);
37
70
  setDraft("");
@@ -39,35 +72,63 @@ const TagInput = React.forwardRef(
39
72
  removeAt(tags.length - 1);
40
73
  }
41
74
  };
75
+ const clearControl = resolveAllowClear(allowClear, false, t("common.clear"));
76
+ const showClear = clearControl.enabled && tags.length > 0 && !disabled && !readOnly;
77
+ const clearAll = () => {
78
+ commit([]);
79
+ onClear?.();
80
+ };
81
+ const chips = tags.map((tag, index) => ({ value: tag, label: tag, index }));
82
+ const {
83
+ visible: visibleChips,
84
+ omitted: omittedChips,
85
+ overflow
86
+ } = applyMaxTagCount(chips, maxTagCount, maxTagPlaceholder);
42
87
  return /* @__PURE__ */ jsxs(
43
88
  "div",
44
89
  {
45
90
  "data-slot": "tag-input",
46
91
  "aria-disabled": disabled || void 0,
47
- className: cn("ui-tag-input", disabled && "ui-tag-input-disabled", className),
92
+ "aria-readonly": readOnly || void 0,
93
+ ...controlSurfaceAttrs({ variant, status, size }),
94
+ "aria-invalid": status === "error" ? true : void 0,
95
+ className: cn(
96
+ "ui-tag-input ui-control-surface",
97
+ disabled && "ui-tag-input-disabled",
98
+ className
99
+ ),
48
100
  children: [
49
- tags.length > 0 ? /* @__PURE__ */ jsx("ul", { role: "list", className: "ui-tag-input-list", "data-slot": "tag-input-list", children: tags.map((tag, i) => /* @__PURE__ */ jsxs(
50
- "li",
51
- {
52
- role: "listitem",
53
- className: "ui-tag-input-chip",
54
- "data-slot": "tag-input-chip",
55
- children: [
56
- tag,
57
- !disabled ? /* @__PURE__ */ jsx(
58
- "button",
59
- {
60
- type: "button",
61
- className: "ui-tag-input-remove",
62
- "aria-label": t("ui.tagInput.removeTag", { tag }),
63
- onClick: () => removeAt(i),
64
- children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true" })
65
- }
66
- ) : null
67
- ]
68
- },
69
- tag
70
- )) }) : null,
101
+ tags.length > 0 ? /* @__PURE__ */ jsxs("ul", { role: "list", className: "ui-tag-input-list", "data-slot": "tag-input-list", children: [
102
+ visibleChips.map((chip) => /* @__PURE__ */ jsx(
103
+ "li",
104
+ {
105
+ role: "listitem",
106
+ className: "ui-tag-input-chip",
107
+ "data-slot": "tag-input-chip",
108
+ children: tagRender ? tagRender({
109
+ value: chip.value,
110
+ label: chip.label,
111
+ index: chip.index,
112
+ disabled: Boolean(disabled) || Boolean(readOnly),
113
+ onClose: () => removeAt(chip.index)
114
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [
115
+ chip.value,
116
+ !disabled && !readOnly ? /* @__PURE__ */ jsx(
117
+ "button",
118
+ {
119
+ type: "button",
120
+ className: "ui-tag-input-remove",
121
+ "aria-label": t("ui.tagInput.removeTag", { tag: chip.value }),
122
+ onClick: () => removeAt(chip.index),
123
+ children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true" })
124
+ }
125
+ ) : null
126
+ ] })
127
+ },
128
+ chip.value
129
+ )),
130
+ omittedChips.length > 0 ? /* @__PURE__ */ jsx("li", { role: "listitem", className: "ui-tag-input-chip", "data-slot": "tag-input-overflow", children: overflow ?? t("dataEntry.selection.overflow", { count: omittedChips.length }) }) : null
131
+ ] }) : null,
71
132
  /* @__PURE__ */ jsx(
72
133
  "input",
73
134
  {
@@ -76,12 +137,21 @@ const TagInput = React.forwardRef(
76
137
  type: "text",
77
138
  className: "ui-tag-input-field",
78
139
  value: draft,
79
- placeholder: tags.length === 0 ? placeholder : void 0,
140
+ placeholder: tags.length === 0 && !readOnly ? placeholder : void 0,
80
141
  disabled,
142
+ readOnly,
81
143
  "aria-label": ariaLabel ?? t("ui.tagInput.inputLabel"),
82
144
  onChange: (e) => setDraft(e.target.value),
83
145
  onKeyDown,
146
+ onPaste: (e) => {
147
+ const text = e.clipboardData.getData("text");
148
+ if (!tokenSeparators.some((separator) => text.includes(separator))) return;
149
+ e.preventDefault();
150
+ addAll(text);
151
+ setDraft("");
152
+ },
84
153
  onBlur: () => {
154
+ if (readOnly) return;
85
155
  if (draft.trim()) {
86
156
  add(draft);
87
157
  setDraft("");
@@ -89,6 +159,18 @@ const TagInput = React.forwardRef(
89
159
  }
90
160
  }
91
161
  ),
162
+ showClear ? /* @__PURE__ */ jsx(
163
+ "button",
164
+ {
165
+ type: "button",
166
+ tabIndex: -1,
167
+ "aria-label": clearControl.label,
168
+ "data-slot": "tag-input-clear",
169
+ className: "ui-control-inline-affix-action ui-tag-input-clear",
170
+ onClick: clearAll,
171
+ children: clearControl.clearIcon ?? /* @__PURE__ */ jsx(X, { className: "ui-control-inline-affix-icon", "aria-hidden": "true" })
172
+ }
173
+ ) : null,
92
174
  /* @__PURE__ */ jsx("span", { "aria-live": "polite", className: "sr-only", "data-slot": "tag-input-status", children: t("ui.tagInput.tagCount", { count: tags.length }) }),
93
175
  name ? /* @__PURE__ */ jsx("input", { type: "hidden", name, value: tags.join(",") }) : null
94
176
  ]
@@ -1,3 +1,4 @@
1
+ import { type Control, type FieldPath, type FieldValues, type UseFormReturn } from "react-hook-form";
1
2
  import type { FormStateAdapter } from "../props/components/form.prop.js";
2
3
  /**
3
4
  * Context carrying a framework-agnostic {@link FormStateAdapter}. `FormRoot` provides it on the
@@ -7,11 +8,39 @@ import type { FormStateAdapter } from "../props/components/form.prop.js";
7
8
  export declare const FormAdapterContext: import("react").Context<FormStateAdapter | null>;
8
9
  /** Read the active form-state adapter, or `null` when `FormRoot` runs the react-hook-form path. */
9
10
  export declare function useFormAdapter(): FormStateAdapter | null;
11
+ /** Form-wide options shared by BOTH paths — currently the antd-style form-level `disabled`. */
12
+ export interface FormOptionsContextValue {
13
+ disabled: boolean;
14
+ submitting?: boolean;
15
+ }
16
+ /** Defaults to enabled so a `FormField`/`FormFieldControl` outside a `FormRoot` keeps working. */
17
+ export declare const FormOptionsContext: import("react").Context<FormOptionsContextValue>;
18
+ /**
19
+ * Whether the surrounding `FormRoot` disables its fields (`FormRoot disabled`). Read it for the
20
+ * action buttons, which are NOT fields and so are never disabled automatically.
21
+ */
22
+ export declare function useFormDisabled(): boolean;
10
23
  /**
11
24
  * Whether the surrounding `FormRoot` is currently submitting — works for BOTH paths: the adapter's
12
25
  * `isSubmitting` (e.g. Inertia's `processing`) or react-hook-form's `formState.isSubmitting`.
13
26
  */
14
27
  export declare function useFormSubmitting(): boolean;
28
+ /**
29
+ * The react-hook-form instance of the surrounding `FormRoot` (antd `Form.useFormInstance`) — for
30
+ * `setValue`/`trigger`/`getValues` deep inside a form without prop-drilling `form`. Throws on the
31
+ * adapter path, which has no RHF instance; use {@link useFormAdapter} there.
32
+ */
33
+ export declare function useFormInstance<TFieldValues extends FieldValues = FieldValues>(): UseFormReturn<TFieldValues>;
34
+ export declare function getFallbackFormControl(): Control<FieldValues>;
35
+ /**
36
+ * Subscribe to a field's value (antd `Form.useWatch`) — the "show this section only when `plan`
37
+ * is `enterprise`" case, WITHOUT re-rendering the whole form. Omit `name` for every value.
38
+ * Works on both paths: react-hook-form's `useWatch`, or the adapter's `getValue`/`getValues`.
39
+ *
40
+ * Returns `unknown` — the same contract as `FormFieldControl`'s render-prop `value`. Narrow at the
41
+ * call site (`String(v ?? "")`, a Zod parse, a type guard).
42
+ */
43
+ export declare function useFormWatch<TFieldValues extends FieldValues = FieldValues>(name?: FieldPath<TFieldValues>): unknown;
15
44
  /**
16
45
  * Normalise a control's change payload to a bare value. The `FormFieldControl` render-prop spreads
17
46
  * `onChange` onto a control that may call it with a DOM `ChangeEvent` (native `<Input>`) OR a raw