@godxjp/ui 19.6.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 (326) 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 +14 -3
  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/collapsible.d.ts +23 -4
  20. package/dist/components/data-display/collapsible.js +119 -4
  21. package/dist/components/data-display/data-table.d.ts +39 -4
  22. package/dist/components/data-display/data-table.js +802 -270
  23. package/dist/components/data-display/descriptions.d.ts +27 -6
  24. package/dist/components/data-display/descriptions.js +58 -17
  25. package/dist/components/data-display/index.d.ts +5 -1
  26. package/dist/components/data-display/index.js +4 -0
  27. package/dist/components/data-display/legend.d.ts +15 -0
  28. package/dist/components/data-display/legend.js +11 -0
  29. package/dist/components/data-display/list-row.d.ts +10 -1
  30. package/dist/components/data-display/list-row.js +8 -2
  31. package/dist/components/data-display/popover.d.ts +60 -7
  32. package/dist/components/data-display/popover.js +268 -39
  33. package/dist/components/data-display/progress.d.ts +50 -2
  34. package/dist/components/data-display/progress.js +57 -9
  35. package/dist/components/data-display/range-timeline.d.ts +38 -0
  36. package/dist/components/data-display/range-timeline.js +161 -0
  37. package/dist/components/data-display/scroll-area.js +13 -2
  38. package/dist/components/data-display/service-launcher-card.js +10 -10
  39. package/dist/components/data-display/table.d.ts +11 -3
  40. package/dist/components/data-display/table.js +48 -18
  41. package/dist/components/data-display/tree-list.js +4 -9
  42. package/dist/components/data-entry/calendar.d.ts +2 -2
  43. package/dist/components/data-entry/calendar.js +79 -33
  44. package/dist/components/data-entry/cascader.d.ts +1 -1
  45. package/dist/components/data-entry/cascader.js +188 -24
  46. package/dist/components/data-entry/checkbox.d.ts +19 -6
  47. package/dist/components/data-entry/checkbox.js +55 -16
  48. package/dist/components/data-entry/choice-option.d.ts +1 -1
  49. package/dist/components/data-entry/color-picker.d.ts +1 -1
  50. package/dist/components/data-entry/color-picker.js +17 -5
  51. package/dist/components/data-entry/control-appearance.d.ts +64 -0
  52. package/dist/components/data-entry/control-appearance.js +39 -0
  53. package/dist/components/data-entry/control-surface.d.ts +61 -0
  54. package/dist/components/data-entry/control-surface.js +39 -0
  55. package/dist/components/data-entry/date-picker.d.ts +1 -1
  56. package/dist/components/data-entry/date-picker.js +344 -113
  57. package/dist/components/data-entry/date-range-picker.d.ts +2 -2
  58. package/dist/components/data-entry/date-range-picker.js +278 -140
  59. package/dist/components/data-entry/field.js +0 -1
  60. package/dist/components/data-entry/form-field.d.ts +1 -1
  61. package/dist/components/data-entry/form-field.js +39 -4
  62. package/dist/components/data-entry/form.d.ts +4 -0
  63. package/dist/components/data-entry/form.js +5 -3
  64. package/dist/components/data-entry/index.d.ts +7 -3
  65. package/dist/components/data-entry/index.js +10 -1
  66. package/dist/components/data-entry/input-otp.d.ts +1 -1
  67. package/dist/components/data-entry/input.d.ts +12 -34
  68. package/dist/components/data-entry/input.js +92 -24
  69. package/dist/components/data-entry/label.d.ts +3 -2
  70. package/dist/components/data-entry/label.js +23 -10
  71. package/dist/components/data-entry/month-picker.d.ts +2 -2
  72. package/dist/components/data-entry/month-picker.js +47 -10
  73. package/dist/components/data-entry/month-range-picker.d.ts +2 -2
  74. package/dist/components/data-entry/month-range-picker.js +51 -11
  75. package/dist/components/data-entry/number-input.d.ts +7 -0
  76. package/dist/components/data-entry/number-input.js +147 -98
  77. package/dist/components/data-entry/password-input.d.ts +1 -1
  78. package/dist/components/data-entry/radio.d.ts +1 -1
  79. package/dist/components/data-entry/radio.js +61 -13
  80. package/dist/components/data-entry/search-input.d.ts +1 -1
  81. package/dist/components/data-entry/search-input.js +16 -2
  82. package/dist/components/data-entry/search-select.d.ts +2 -2
  83. package/dist/components/data-entry/search-select.js +209 -78
  84. package/dist/components/data-entry/select.d.ts +22 -4
  85. package/dist/components/data-entry/select.js +215 -163
  86. package/dist/components/data-entry/slider.d.ts +9 -1
  87. package/dist/components/data-entry/slider.js +87 -9
  88. package/dist/components/data-entry/switch.d.ts +3 -0
  89. package/dist/components/data-entry/switch.js +29 -3
  90. package/dist/components/data-entry/textarea.d.ts +14 -56
  91. package/dist/components/data-entry/textarea.js +80 -33
  92. package/dist/components/data-entry/time-picker.d.ts +2 -2
  93. package/dist/components/data-entry/time-picker.js +333 -109
  94. package/dist/components/data-entry/time-range-picker.d.ts +5 -0
  95. package/dist/components/data-entry/time-range-picker.js +89 -0
  96. package/dist/components/data-entry/transfer.d.ts +1 -1
  97. package/dist/components/data-entry/transfer.js +99 -31
  98. package/dist/components/data-entry/tree-select-strategy.d.ts +1 -1
  99. package/dist/components/data-entry/tree-select.d.ts +1 -1
  100. package/dist/components/data-entry/tree-select.js +197 -92
  101. package/dist/components/data-entry/tree-utils.d.ts +1 -1
  102. package/dist/components/data-entry/tree-utils.js +7 -14
  103. package/dist/components/data-entry/upload-files.d.ts +2 -0
  104. package/dist/components/data-entry/upload-files.js +31 -0
  105. package/dist/components/data-entry/upload-request.d.ts +4 -0
  106. package/dist/components/data-entry/upload-request.js +53 -0
  107. package/dist/components/data-entry/upload-types.d.ts +28 -0
  108. package/dist/components/data-entry/upload-types.js +2 -0
  109. package/dist/components/data-entry/upload.d.ts +2 -2
  110. package/dist/components/data-entry/upload.js +482 -117
  111. package/dist/components/feedback/dialog.d.ts +105 -38
  112. package/dist/components/feedback/dialog.js +268 -193
  113. package/dist/components/feedback/overlay-close-focus.d.ts +31 -0
  114. package/dist/components/feedback/overlay-close-focus.js +31 -0
  115. package/dist/components/feedback/overlay-header-tone.d.ts +1 -1
  116. package/dist/components/feedback/sheet.d.ts +53 -11
  117. package/dist/components/feedback/sheet.js +150 -81
  118. package/dist/components/feedback/tooltip.d.ts +51 -7
  119. package/dist/components/feedback/tooltip.js +107 -25
  120. package/dist/components/general/button.d.ts +1 -1
  121. package/dist/components/general/button.js +7 -3
  122. package/dist/components/general/index.d.ts +1 -0
  123. package/dist/components/general/index.js +2 -0
  124. package/dist/components/general/logo.d.ts +17 -0
  125. package/dist/components/general/logo.js +22 -16
  126. package/dist/components/general/typography.d.ts +3 -0
  127. package/dist/components/general/typography.js +15 -1
  128. package/dist/components/general/visually-hidden.d.ts +3 -0
  129. package/dist/components/general/visually-hidden.js +9 -0
  130. package/dist/components/layout/app-launcher.d.ts +34 -0
  131. package/dist/components/layout/app-launcher.js +228 -0
  132. package/dist/components/layout/app-shell.d.ts +3 -1
  133. package/dist/components/layout/app-shell.js +69 -12
  134. package/dist/components/layout/aspect-ratio.js +0 -1
  135. package/dist/components/layout/auth-divider.js +0 -1
  136. package/dist/components/layout/breadcrumb.d.ts +14 -2
  137. package/dist/components/layout/breadcrumb.js +46 -4
  138. package/dist/components/layout/flex.d.ts +1 -1
  139. package/dist/components/layout/flex.js +41 -3
  140. package/dist/components/layout/index.d.ts +3 -0
  141. package/dist/components/layout/index.js +5 -1
  142. package/dist/components/layout/nav-surface.d.ts +26 -0
  143. package/dist/components/layout/nav-surface.js +17 -0
  144. package/dist/components/layout/org-switcher.d.ts +5 -1
  145. package/dist/components/layout/org-switcher.js +25 -4
  146. package/dist/components/layout/page-container.d.ts +1 -1
  147. package/dist/components/layout/page-container.js +5 -3
  148. package/dist/components/layout/responsive-grid.d.ts +16 -2
  149. package/dist/components/layout/responsive-grid.js +29 -2
  150. package/dist/components/layout/separator.js +0 -1
  151. package/dist/components/layout/sidebar.js +4 -1
  152. package/dist/components/layout/split-pane.d.ts +14 -1
  153. package/dist/components/layout/split-pane.js +26 -13
  154. package/dist/components/layout/topbar-item.d.ts +3 -0
  155. package/dist/components/layout/topbar-item.js +19 -5
  156. package/dist/components/layout/topbar.d.ts +1 -1
  157. package/dist/components/layout/topbar.js +27 -6
  158. package/dist/components/navigation/app-setting-picker.js +21 -2
  159. package/dist/components/navigation/app-setting-toggle.d.ts +16 -0
  160. package/dist/components/navigation/app-setting-toggle.js +96 -0
  161. package/dist/components/navigation/dropdown-menu.d.ts +227 -18
  162. package/dist/components/navigation/dropdown-menu.js +402 -118
  163. package/dist/components/navigation/index.d.ts +2 -0
  164. package/dist/components/navigation/index.js +2 -0
  165. package/dist/components/navigation/pagination-utils.d.ts +2 -1
  166. package/dist/components/navigation/pagination.d.ts +2 -2
  167. package/dist/components/navigation/pagination.js +155 -83
  168. package/dist/components/navigation/steps.d.ts +2 -2
  169. package/dist/components/navigation/steps.js +29 -4
  170. package/dist/components/navigation/tabs.d.ts +29 -16
  171. package/dist/components/navigation/tabs.js +374 -144
  172. package/dist/components/ui/accordion.d.ts +50 -5
  173. package/dist/components/ui/accordion.js +239 -33
  174. package/dist/components/ui/aspect-ratio.d.ts +23 -2
  175. package/dist/components/ui/aspect-ratio.js +15 -13
  176. package/dist/components/ui/avatar.d.ts +29 -4
  177. package/dist/components/ui/avatar.js +111 -25
  178. package/dist/components/ui/hover-card.d.ts +42 -4
  179. package/dist/components/ui/hover-card.js +183 -27
  180. package/dist/components/ui/input-otp.d.ts +26 -28
  181. package/dist/components/ui/input-otp.js +50 -7
  182. package/dist/components/ui/label.js +0 -1
  183. package/dist/components/ui/password-input.d.ts +36 -2
  184. package/dist/components/ui/password-input.js +27 -7
  185. package/dist/components/ui/rating.d.ts +25 -0
  186. package/dist/components/ui/rating.js +67 -27
  187. package/dist/components/ui/segmented.d.ts +12 -3
  188. package/dist/components/ui/segmented.js +17 -2
  189. package/dist/components/ui/separator.d.ts +12 -2
  190. package/dist/components/ui/separator.js +30 -9
  191. package/dist/components/ui/tag-input.d.ts +45 -0
  192. package/dist/components/ui/tag-input.js +109 -27
  193. package/dist/components/ui/toggle-group.d.ts +50 -5
  194. package/dist/components/ui/toggle-group.js +79 -20
  195. package/dist/components/ui/toggle.d.ts +31 -5
  196. package/dist/components/ui/toggle.js +42 -3
  197. package/dist/form/form-context.d.ts +29 -0
  198. package/dist/form/form-context.js +44 -4
  199. package/dist/form/form-field-array.d.ts +22 -0
  200. package/dist/form/form-field-array.js +50 -0
  201. package/dist/form/form-field-control.d.ts +2 -1
  202. package/dist/form/form-field-control.js +116 -40
  203. package/dist/form/form-root.d.ts +2 -1
  204. package/dist/form/form-root.js +142 -23
  205. package/dist/form/index.d.ts +3 -1
  206. package/dist/form/index.js +12 -1
  207. package/dist/i18n/messages/en.json +64 -5
  208. package/dist/i18n/messages/ja.json +64 -5
  209. package/dist/i18n/messages/vi.json +64 -5
  210. package/dist/inertia/index.d.ts +20 -0
  211. package/dist/inertia/index.js +60 -1
  212. package/dist/lib/control-styles.d.ts +25 -3
  213. package/dist/lib/control-styles.js +9 -3
  214. package/dist/lib/datetime/picker-format.d.ts +8 -0
  215. package/dist/lib/datetime/picker-format.js +54 -0
  216. package/dist/lib/slot.d.ts +32 -0
  217. package/dist/lib/slot.js +22 -0
  218. package/dist/lib/variants.d.ts +22 -3
  219. package/dist/lib/variants.js +56 -1
  220. package/dist/props/components/app.prop.d.ts +25 -1
  221. package/dist/props/components/charts.prop.d.ts +21 -0
  222. package/dist/props/components/data-display.prop.d.ts +72 -4
  223. package/dist/props/components/data-entry.prop.d.ts +718 -46
  224. package/dist/props/components/form.prop.d.ts +142 -4
  225. package/dist/props/components/general.prop.d.ts +17 -1
  226. package/dist/props/components/index.d.ts +3 -3
  227. package/dist/props/components/layout.prop.d.ts +281 -11
  228. package/dist/props/components/navigation.prop.d.ts +114 -4
  229. package/dist/props/registry.d.ts +397 -11
  230. package/dist/props/registry.js +526 -11
  231. package/dist/props/vocabulary/content.prop.d.ts +1 -1
  232. package/dist/props/vocabulary/data.prop.d.ts +179 -1
  233. package/dist/props/vocabulary/index.d.ts +5 -5
  234. package/dist/props/vocabulary/interaction.prop.d.ts +68 -3
  235. package/dist/props/vocabulary/layout.prop.d.ts +57 -1
  236. package/dist/props/vocabulary/navigation.prop.d.ts +40 -0
  237. package/dist/props/vocabulary/shared.prop.d.ts +33 -0
  238. package/dist/styles/badge-layout.css +2 -1
  239. package/dist/styles/card-layout.css +26 -4
  240. package/dist/styles/chart-layout.css +15 -0
  241. package/dist/styles/control.css +657 -15
  242. package/dist/styles/core.css +5 -2
  243. package/dist/styles/data-display-layout.css +313 -6
  244. package/dist/styles/data-entry-layout.css +13 -0
  245. package/dist/styles/focus-ring.css +4 -0
  246. package/dist/styles/index.css +5 -2
  247. package/dist/styles/layout.css +327 -4
  248. package/dist/styles/navigation-layout.css +227 -0
  249. package/dist/styles/shell-layout.css +369 -13
  250. package/dist/styles/table-layout.css +95 -6
  251. package/dist/styles/text-layout.css +10 -4
  252. package/dist/tokens/base.css +2 -1
  253. package/dist/tokens/components/badge.css +1 -0
  254. package/dist/tokens/components/chart.css +6 -0
  255. package/dist/tokens/components/control.css +79 -2
  256. package/dist/tokens/components/data-display.css +20 -0
  257. package/dist/tokens/components/descriptions.css +11 -0
  258. package/dist/tokens/components/flex.css +8 -0
  259. package/dist/tokens/components/navigation.css +55 -0
  260. package/dist/tokens/components/shell.css +53 -3
  261. package/dist/tokens/components/table.css +14 -0
  262. package/dist/tokens/foundation.css +2 -0
  263. package/dist/tokens/semantic/layout.css +9 -0
  264. package/docs/COMPONENTS.md +9 -3
  265. package/docs/CONSUMER-RULES.md +13 -0
  266. package/docs/DESIGN-AUTHORITY.md +145 -83
  267. package/docs/DEVELOPMENT.md +4 -3
  268. package/docs/FORMS.md +151 -6
  269. package/docs/FRAME-COVERAGE-REPORT.md +32 -17
  270. package/docs/README.md +15 -15
  271. package/docs/STANDARDS-vocabulary-tokens.md +1 -1
  272. package/docs/TESTING.md +15 -6
  273. package/docs/WHAT-BELONGS-HERE.md +179 -0
  274. package/docs/charts/cjk-category-axis.tsx +81 -0
  275. package/docs/data-display/card/index.tsx +22 -0
  276. package/docs/data-display/data-table/examples/antd-parity.tsx +257 -0
  277. package/docs/data-display/data-table/index.tsx +23 -0
  278. package/docs/data-display/descriptions.tsx +41 -0
  279. package/docs/data-display/legend.tsx +145 -0
  280. package/docs/data-display/progress.tsx +32 -0
  281. package/docs/data-display/scroll-area.tsx +31 -25
  282. package/docs/data-display/table.tsx +104 -45
  283. package/docs/data-display/timeline.tsx +41 -0
  284. package/docs/data-entry/date-picker.tsx +85 -0
  285. package/docs/data-entry/date-range-picker.tsx +26 -0
  286. package/docs/data-entry/form-dynamic-fields.tsx +199 -0
  287. package/docs/data-entry/form.tsx +74 -4
  288. package/docs/data-entry/input-otp.tsx +24 -0
  289. package/docs/data-entry/input.tsx +46 -1
  290. package/docs/data-entry/month-range-picker.tsx +1 -1
  291. package/docs/data-entry/segmented.tsx +1 -1
  292. package/docs/data-entry/select.tsx +29 -2
  293. package/docs/data-entry/switch.tsx +41 -0
  294. package/docs/data-entry/textarea.tsx +38 -0
  295. package/docs/data-entry/time-picker.tsx +85 -1
  296. package/docs/data-entry/time-range-picker.tsx +55 -0
  297. package/docs/data-entry/transfer.tsx +17 -0
  298. package/docs/data-entry/upload.tsx +56 -12
  299. package/docs/feedback/sheet.tsx +1 -1
  300. package/docs/feedback/tooltip.tsx +1 -1
  301. package/docs/general/activity.tsx +2 -2
  302. package/docs/general/button/index.tsx +14 -1
  303. package/docs/general/typography.tsx +14 -1
  304. package/docs/layout/app-launcher.tsx +151 -0
  305. package/docs/layout/app-shell-arrangements.tsx +225 -0
  306. package/docs/layout/app-shell.tsx +11 -0
  307. package/docs/layout/aspect-ratio.tsx +1 -1
  308. package/docs/layout/flex.tsx +50 -0
  309. package/docs/layout/responsive-grid.tsx +21 -1
  310. package/docs/layout/topbar.tsx +5 -9
  311. package/docs/navigation/app-setting-picker.tsx +37 -1
  312. package/docs/navigation/app-setting-toggle.tsx +111 -0
  313. package/docs/navigation/breadcrumb.tsx +48 -0
  314. package/docs/navigation/dropdown-menu.tsx +21 -0
  315. package/docs/navigation/pagination.tsx +52 -0
  316. package/docs/navigation/steps.tsx +37 -0
  317. package/docs/navigation/tabs.tsx +97 -1
  318. package/docs/query/button-refetch.tsx +1 -0
  319. package/package.json +28 -8
  320. package/scripts/_agent-setup.mjs +182 -3
  321. package/scripts/consumer-rule.md +98 -0
  322. package/scripts/guinea-pig-skill.md +322 -0
  323. package/scripts/init-guinea-pig.mjs +84 -0
  324. package/scripts/postinstall.mjs +13 -2
  325. package/scripts/ui-audit.mjs +351 -37
  326. /package/dist/tokens/{antd.generated.css → derived.css} +0 -0
@@ -1,11 +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
- import { Check, ChevronRight, ChevronsUpDown, Minus, X } from "lucide-react";
4
+ import { Check, ChevronRight, ChevronsUpDown, Loader2, Minus, X } from "lucide-react";
5
5
  import { useTranslation } from "../../i18n/use-translation.js";
6
6
  import { cn } from "../../lib/utils.js";
7
7
  import { pickFieldA11y, useFieldIdentity } from "../../lib/field-a11y.js";
8
- import { controlTriggerClass } from "../../lib/control-styles.js";
8
+ import { controlSurfaceTriggerClass } from "../../lib/control-styles.js";
9
+ import {
10
+ applyMaxTagCount,
11
+ controlSurfaceAttrs,
12
+ resolveAllowClear,
13
+ resolveAriaInvalid
14
+ } from "./control-surface.js";
9
15
  import { Popover, PopoverContent, PopoverTrigger } from "../data-display/popover.js";
10
16
  import { ScrollArea, ScrollBar } from "../data-display/scroll-area.js";
11
17
  import { Command, CommandInput } from "./command.js";
@@ -15,7 +21,8 @@ import {
15
21
  getNodeByPath,
16
22
  normalizeTreeOptions,
17
23
  pathKey,
18
- pathsEqual
24
+ pathsEqual,
25
+ reactNodeText
19
26
  } from "./tree-utils.js";
20
27
  function pathInValues(path, values) {
21
28
  return values.some((v) => pathsEqual(v, path));
@@ -66,6 +73,41 @@ function aggregateCheckState(node, path, values) {
66
73
  if (total === 0 || selected === 0) return "none";
67
74
  return selected === total ? "checked" : "indeterminate";
68
75
  }
76
+ function leafPathsUnder(node, path) {
77
+ const out = [];
78
+ const walk = (current, prefix) => {
79
+ const isLeaf = (current.children?.length ?? 0) === 0 || current.isLeaf === true;
80
+ if (isLeaf) {
81
+ out.push(prefix);
82
+ return;
83
+ }
84
+ for (const child of current.children) walk(child, [...prefix, child.value]);
85
+ };
86
+ walk(node, path);
87
+ return out;
88
+ }
89
+ function collapseToParents(values, options) {
90
+ const representative = /* @__PURE__ */ new Map();
91
+ const walk = (nodes, prefix) => {
92
+ for (const node of nodes) {
93
+ const path = [...prefix, node.value];
94
+ const hasChildren = (node.children?.length ?? 0) > 0 && node.isLeaf !== true;
95
+ if (!hasChildren) continue;
96
+ if (aggregateCheckState(node, path, values) === "checked") {
97
+ for (const leaf of leafPathsUnder(node, path)) representative.set(pathKey(leaf), path);
98
+ continue;
99
+ }
100
+ walk(node.children, path);
101
+ }
102
+ };
103
+ walk(options, []);
104
+ const out = [];
105
+ for (const value of values) {
106
+ const shown = representative.get(pathKey(value)) ?? value;
107
+ if (!out.some((existing) => pathsEqual(existing, shown))) out.push(shown);
108
+ }
109
+ return out;
110
+ }
69
111
  function Cascader({
70
112
  options: optionsProp,
71
113
  value,
@@ -76,25 +118,76 @@ function Cascader({
76
118
  showSearch,
77
119
  placeholder,
78
120
  disabled,
121
+ readOnly,
122
+ name,
79
123
  className,
80
124
  id,
81
125
  expandTrigger = "click",
82
126
  fieldNames,
83
- allowClear = true,
127
+ allowClear,
128
+ size,
129
+ status,
130
+ variant,
131
+ loading = false,
132
+ open: openProp,
133
+ defaultOpen = false,
134
+ onOpenChange,
135
+ showCheckedStrategy = "SHOW_CHILD",
136
+ loadData,
137
+ displayRender,
138
+ optionRender,
139
+ maxTagCount,
140
+ maxTagPlaceholder,
141
+ notFoundContent,
142
+ autoClearSearchValue = true,
143
+ search: searchProp,
144
+ onSearchChange,
84
145
  ...ariaProps
85
146
  }) {
86
147
  const { t } = useTranslation();
87
148
  const fieldA11y = pickFieldA11y(ariaProps);
88
- const identity = useFieldIdentity({ id, "data-field": fieldA11y["data-field"] });
149
+ const identity = useFieldIdentity({ id, name, "data-field": fieldA11y["data-field"] });
150
+ const resolvedName = name ?? identity.name;
89
151
  const reactId = React.useId();
90
152
  const panelId = `${id ?? reactId}-panel`;
91
153
  const options = React.useMemo(
92
154
  () => normalizeTreeOptions(optionsProp, fieldNames),
93
155
  [optionsProp, fieldNames]
94
156
  );
95
- const [open, setOpen] = React.useState(false);
157
+ const [internalOpen, setInternalOpen] = React.useState(defaultOpen);
158
+ const isOpenControlled = openProp !== void 0;
159
+ const open = isOpenControlled ? openProp : internalOpen;
160
+ const setOpen = React.useCallback(
161
+ (next) => {
162
+ if (!isOpenControlled) setInternalOpen(next);
163
+ onOpenChange?.(next);
164
+ },
165
+ [isOpenControlled, onOpenChange]
166
+ );
96
167
  const [activePath, setActivePath] = React.useState([]);
97
- const [search, setSearch] = React.useState("");
168
+ const [internalSearch, setInternalSearch] = React.useState("");
169
+ const isSearchControlled = searchProp !== void 0;
170
+ const search = isSearchControlled ? searchProp : internalSearch;
171
+ const setSearch = React.useCallback(
172
+ (next) => {
173
+ if (!isSearchControlled) setInternalSearch(next);
174
+ onSearchChange?.(next);
175
+ },
176
+ [isSearchControlled, onSearchChange]
177
+ );
178
+ const requestedLoads = React.useRef(/* @__PURE__ */ new Set());
179
+ const requestLoad = React.useCallback(
180
+ (path, chain) => {
181
+ if (!loadData) return;
182
+ const node = chain.at(-1);
183
+ if (!node || node.isLeaf === true || (node.children?.length ?? 0) > 0) return;
184
+ const key = pathKey(path);
185
+ if (requestedLoads.current.has(key)) return;
186
+ requestedLoads.current.add(key);
187
+ void loadData(chain);
188
+ },
189
+ [loadData]
190
+ );
98
191
  const isControlledSingle = !multiple && value !== void 0;
99
192
  const isControlledMulti = multiple && value !== void 0;
100
193
  const [internalSingle, setInternalSingle] = React.useState(
@@ -106,14 +199,52 @@ function Cascader({
106
199
  const singleValue = isControlledSingle ? value : internalSingle;
107
200
  const multiValue = isControlledMulti ? value : internalMulti;
108
201
  const resolvedPlaceholder = placeholder ?? t("dataEntry.cascader.placeholder");
202
+ const hasValue = multiple ? multiValue.length > 0 : singleValue.length > 0;
109
203
  const displayLabel = React.useMemo(() => {
110
204
  if (multiple) {
111
205
  if (!multiValue.length) return null;
112
- return multiValue.map((path) => formatPathLabels(getNodeByPath(options, path))).join(", ");
206
+ const shown = showCheckedStrategy === "SHOW_PARENT" ? collapseToParents(multiValue, options) : multiValue;
207
+ const items = shown.map((path) => {
208
+ const chain2 = getNodeByPath(options, path);
209
+ const labels = chain2.map((node) => reactNodeText(node.label));
210
+ return {
211
+ value: pathKey(path),
212
+ label: displayRender ? displayRender(labels, chain2) : formatPathLabels(chain2)
213
+ };
214
+ });
215
+ const { visible, omitted, overflow } = applyMaxTagCount(
216
+ items,
217
+ maxTagCount,
218
+ maxTagPlaceholder
219
+ );
220
+ const body = visible.map((item, index) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
221
+ index > 0 ? ", " : null,
222
+ item.label
223
+ ] }, item.value));
224
+ if (omitted.length === 0) return body;
225
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
226
+ body,
227
+ ", ",
228
+ /* @__PURE__ */ jsx("span", { "data-slot": "cascader-overflow", children: overflow ?? t("dataEntry.selection.overflow", { count: omitted.length }) })
229
+ ] });
113
230
  }
114
231
  if (!singleValue.length) return null;
115
- return formatPathLabels(getNodeByPath(options, singleValue));
116
- }, [multiple, multiValue, singleValue, options]);
232
+ const chain = getNodeByPath(options, singleValue);
233
+ return displayRender ? displayRender(
234
+ chain.map((node) => reactNodeText(node.label)),
235
+ chain
236
+ ) : formatPathLabels(chain);
237
+ }, [
238
+ multiple,
239
+ multiValue,
240
+ singleValue,
241
+ options,
242
+ showCheckedStrategy,
243
+ displayRender,
244
+ maxTagCount,
245
+ maxTagPlaceholder,
246
+ t
247
+ ]);
117
248
  const setSingleValue = (path) => {
118
249
  if (!isControlledSingle) setInternalSingle(path);
119
250
  onValueChange?.(path, getNodeByPath(options, path));
@@ -122,7 +253,7 @@ function Cascader({
122
253
  setSingleValue(path);
123
254
  setOpen(false);
124
255
  setActivePath([]);
125
- setSearch("");
256
+ if (autoClearSearchValue) setSearch("");
126
257
  };
127
258
  const commitMulti = (paths) => {
128
259
  if (!isControlledMulti) setInternalMulti(paths);
@@ -143,6 +274,11 @@ function Cascader({
143
274
  }, [options, activePath]);
144
275
  const handleSelectNode = (node, path) => {
145
276
  const hasChildren = (node.children?.length ?? 0) > 0 && node.isLeaf !== true;
277
+ requestLoad(path, getNodeByPath(options, path));
278
+ if (loadData && node.isLeaf === false && !(node.children?.length ?? 0)) {
279
+ setActivePath(path);
280
+ return;
281
+ }
146
282
  if (multiple) {
147
283
  if (hasChildren && !changeOnSelect) setActivePath(path);
148
284
  else if (!node.disableCheckbox) commitMulti(togglePath(multiValue, path));
@@ -161,11 +297,12 @@ function Cascader({
161
297
  [options, search, isSearching]
162
298
  );
163
299
  const handleOpenChange = (next) => {
300
+ if (readOnly && next) return;
164
301
  setOpen(next);
165
302
  if (next) {
166
303
  setActivePath(multiple ? [] : singleValue);
167
304
  } else {
168
- setSearch("");
305
+ if (autoClearSearchValue) setSearch("");
169
306
  setActivePath([]);
170
307
  }
171
308
  };
@@ -208,7 +345,11 @@ function Cascader({
208
345
  // deeper column but keeps its own. Never collapse on the column's mouseleave
209
346
  // — moving the pointer toward the next column would strand the deeper levels
210
347
  // and make a depth-3 leaf unreachable.
211
- expandTrigger === "hover" && !node.disabled ? () => setActivePath(hasChildren ? path : path.slice(0, -1)) : void 0
348
+ expandTrigger === "hover" && !node.disabled ? () => {
349
+ const loadable = node.isLeaf === false && !(node.children?.length ?? 0);
350
+ requestLoad(path, getNodeByPath(options, path));
351
+ setActivePath(hasChildren || loadable ? path : path.slice(0, -1));
352
+ } : void 0
212
353
  ),
213
354
  onClick: () => !node.disabled && handleSelectNode(node, path),
214
355
  children: [
@@ -222,8 +363,8 @@ function Cascader({
222
363
  }
223
364
  ),
224
365
  !multiple && selected && /* @__PURE__ */ jsx(Check, { className: "ui-cascader-option-icon", "aria-hidden": "true" }),
225
- /* @__PURE__ */ jsx("span", { className: "flex-1 truncate text-start", children: node.label }),
226
- hasChildren && /* @__PURE__ */ jsx(ChevronRight, { className: "ui-cascader-option-chevron", "aria-hidden": "true" })
366
+ /* @__PURE__ */ jsx("span", { className: "flex-1 truncate text-start", children: optionRender ? optionRender(node) : node.label }),
367
+ (hasChildren || loadData && node.isLeaf === false) && /* @__PURE__ */ jsx(ChevronRight, { className: "ui-cascader-option-chevron", "aria-hidden": "true" })
227
368
  ]
228
369
  }
229
370
  ) }, node.value);
@@ -233,7 +374,9 @@ function Cascader({
233
374
  )) }),
234
375
  /* @__PURE__ */ jsx(ScrollBar, { orientation: "horizontal" })
235
376
  ] });
236
- const showClear = allowClear && displayLabel && !disabled;
377
+ const clearControl = resolveAllowClear(allowClear, true, t("dataEntry.cascader.clear"));
378
+ const showClear = clearControl.enabled && hasValue && !disabled && !readOnly && !loading;
379
+ const surface = controlSurfaceAttrs({ variant, status, size });
237
380
  return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), children: [
238
381
  /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: handleOpenChange, children: [
239
382
  /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
@@ -247,17 +390,31 @@ function Cascader({
247
390
  "aria-haspopup": "listbox",
248
391
  "aria-controls": open ? panelId : void 0,
249
392
  ...fieldA11y,
393
+ ...surface,
394
+ "aria-invalid": resolveAriaInvalid(fieldA11y["aria-invalid"], status),
395
+ "aria-busy": loading || void 0,
396
+ "aria-readonly": readOnly || void 0,
250
397
  disabled,
251
398
  className: cn(
252
- controlTriggerClass,
399
+ controlSurfaceTriggerClass,
253
400
  "w-full justify-start",
254
401
  // Reserve trailing room for the single clear-or-chevron overlay rendered below.
255
402
  "ui-control-trigger-affixed",
256
- !displayLabel && "text-muted-foreground"
403
+ !hasValue && "text-muted-foreground"
257
404
  ),
258
- children: /* @__PURE__ */ jsx("span", { className: "truncate", children: displayLabel ?? resolvedPlaceholder })
405
+ children: /* @__PURE__ */ jsx("span", { className: "truncate", children: hasValue ? displayLabel : resolvedPlaceholder })
259
406
  }
260
407
  ) }),
408
+ resolvedName ? (multiple ? multiValue : singleValue.length ? [singleValue] : []).map((path, index) => /* @__PURE__ */ jsx(
409
+ "input",
410
+ {
411
+ type: "hidden",
412
+ name: resolvedName,
413
+ value: path.join("/"),
414
+ readOnly: true
415
+ },
416
+ `${pathKey(path)}-${index}`
417
+ )) : null,
261
418
  /* @__PURE__ */ jsxs(PopoverContent, { id: panelId, className: "ui-cascader-popover", align: "start", children: [
262
419
  showSearch && /* @__PURE__ */ jsx(Command, { shouldFilter: false, children: /* @__PURE__ */ jsx(
263
420
  CommandInput,
@@ -273,7 +430,7 @@ function Cascader({
273
430
  className: "ui-cascader-panel",
274
431
  role: "listbox",
275
432
  "aria-multiselectable": multiple ? true : void 0,
276
- children: searchResults.length === 0 ? /* @__PURE__ */ jsx("p", { className: "ui-cascader-empty", children: t("dataEntry.cascader.empty") }) : searchResults.map(({ path, labels }) => {
433
+ children: searchResults.length === 0 ? /* @__PURE__ */ jsx("p", { className: "ui-cascader-empty", children: notFoundContent ?? t("dataEntry.cascader.empty") }) : searchResults.map(({ path, labels }) => {
277
434
  const label = labels.join(" / ");
278
435
  const selected = multiple ? pathInValues(path, multiValue) : pathsEqual(path, singleValue);
279
436
  return /* @__PURE__ */ jsxs(
@@ -307,14 +464,21 @@ function Cascader({
307
464
  ) }) : renderCascadeColumns()
308
465
  ] })
309
466
  ] }),
310
- /* @__PURE__ */ jsx("div", { className: "ui-control-affix ui-cascader-affix", children: showClear ? /* @__PURE__ */ jsx(
467
+ /* @__PURE__ */ jsx("div", { className: "ui-control-affix ui-cascader-affix", children: loading ? /* @__PURE__ */ jsx(
468
+ Loader2,
469
+ {
470
+ "data-slot": "cascader-loading",
471
+ className: "ui-control-affix-icon ui-control-affix-indicator animate-spin",
472
+ "aria-hidden": "true"
473
+ }
474
+ ) : showClear ? /* @__PURE__ */ jsx(
311
475
  "button",
312
476
  {
313
477
  type: "button",
314
- "aria-label": t("dataEntry.cascader.clear"),
478
+ "aria-label": clearControl.label,
315
479
  className: "ui-control-affix-action",
316
480
  onClick: clearValue,
317
- children: /* @__PURE__ */ jsx(X, { className: "ui-control-affix-icon", "aria-hidden": "true" })
481
+ children: clearControl.clearIcon ?? /* @__PURE__ */ jsx(X, { className: "ui-control-affix-icon", "aria-hidden": "true" })
318
482
  }
319
483
  ) : /* @__PURE__ */ jsx(
320
484
  ChevronsUpDown,
@@ -1,11 +1,10 @@
1
1
  import * as React from "react";
2
- import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
3
2
  import { CheckboxGroup } from "./checkbox-group.js";
4
3
  /**
5
4
  * Decorative checkbox glyph — a non-interactive `<span>`, NOT the real {@link Checkbox} (which is a
6
- * `<button>`). Used where the row itself is the interactive element and a nested `<button>` would
7
- * be invalid HTML (Cascader's option rows). Shares {@link CheckboxGlyph} so "partial" can never
8
- * drift apart from the real control's rendering again.
5
+ * real `<input>` wrapped by react-aria-components). Used where the row itself is the interactive
6
+ * element and a nested control would be invalid HTML (Cascader's option rows). Shares
7
+ * {@link CheckboxGlyph} so "partial" can never drift apart from the real control's rendering again.
9
8
  */
10
9
  export declare function CheckboxVisual({ checked, indeterminate, disabled, className, }: {
11
10
  checked: boolean;
@@ -13,7 +12,21 @@ export declare function CheckboxVisual({ checked, indeterminate, disabled, class
13
12
  disabled?: boolean;
14
13
  className?: string;
15
14
  }): React.JSX.Element;
16
- /** Checkbox — dùng standalone hoặc `Checkbox.Group` với `options` (Ant Design style). */
17
- export declare const Checkbox: React.ForwardRefExoticComponent<Omit<CheckboxPrimitive.CheckboxProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>> & {
15
+ /**
16
+ * The PUBLIC prop shape, unchanged from the @radix-ui/react-checkbox era: `checked` /
17
+ * `defaultChecked` accept the tri-state `"indeterminate"`, `onCheckedChange` reports it back, and
18
+ * `disabled` / `required` keep their HTML spelling. react-aria-components spells the same four
19
+ * `isSelected` + `isIndeterminate` / `defaultSelected` / `onChange` / `isDisabled` / `isRequired`;
20
+ * that translation happens INSIDE this component and none of those names reach a consumer.
21
+ */
22
+ interface CheckboxRootProps extends Omit<React.ComponentPropsWithoutRef<"button">, "checked" | "defaultChecked" | "onChange"> {
23
+ checked?: boolean | "indeterminate";
24
+ defaultChecked?: boolean | "indeterminate";
25
+ onCheckedChange?: (checked: boolean | "indeterminate") => void;
26
+ required?: boolean;
27
+ }
28
+ /** Checkbox — dùng standalone hoặc `Checkbox.Group` với `options` (theo quy ước phổ biến). */
29
+ export declare const Checkbox: React.ForwardRefExoticComponent<CheckboxRootProps & React.RefAttributes<HTMLLabelElement>> & {
18
30
  Group: typeof CheckboxGroup;
19
31
  };
32
+ export {};
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
- import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
4
+ import { Checkbox as AriaCheckbox } from "react-aria-components";
5
5
  import { Check, Minus } from "lucide-react";
6
6
  import { cn } from "../../lib/utils.js";
7
7
  import { useFieldIdentity } from "../../lib/field-a11y.js";
@@ -28,44 +28,83 @@ function CheckboxVisual({
28
28
  }
29
29
  );
30
30
  }
31
- const CheckboxRoot = React.forwardRef(({ className, ...props }, ref) => {
31
+ const CheckboxRoot = React.forwardRef((props, ref) => {
32
+ const {
33
+ className,
34
+ checked,
35
+ defaultChecked,
36
+ onCheckedChange,
37
+ disabled,
38
+ required,
39
+ value,
40
+ tabIndex,
41
+ "data-field": ownField,
42
+ ...rest
43
+ } = props;
32
44
  const identity = useFieldIdentity({
33
45
  id: props.id,
34
46
  name: props.name,
35
- "data-field": props["data-field"]
47
+ "data-field": ownField
36
48
  });
49
+ const fieldKey = ownField ?? identity["data-field"];
50
+ const inputRef = React.useRef(null);
51
+ React.useLayoutEffect(() => {
52
+ const input = inputRef.current;
53
+ if (!input) return;
54
+ if (fieldKey === void 0) {
55
+ input.removeAttribute("data-field");
56
+ } else {
57
+ input.setAttribute("data-field", fieldKey);
58
+ }
59
+ }, [fieldKey]);
37
60
  const [uncontrolled, setUncontrolled] = React.useState(
38
- props.defaultChecked ?? false
61
+ defaultChecked ?? false
39
62
  );
40
- const state = props.checked ?? uncontrolled;
63
+ const state = checked ?? uncontrolled;
64
+ const invalid = props["aria-invalid"];
41
65
  return /* @__PURE__ */ jsx(
42
- CheckboxPrimitive.Root,
66
+ AriaCheckbox,
43
67
  {
68
+ ...rest,
44
69
  ref,
70
+ inputRef,
45
71
  "data-slot": "checkbox",
72
+ "data-state": state === "indeterminate" ? "indeterminate" : state ? "checked" : "unchecked",
73
+ name: identity.name ?? props.name,
74
+ value,
75
+ isSelected: state === true,
76
+ isIndeterminate: state === "indeterminate",
77
+ isDisabled: disabled,
78
+ isRequired: required,
79
+ isInvalid: invalid !== void 0 && invalid !== false && invalid !== "false",
80
+ excludeFromTabOrder: tabIndex !== void 0 && tabIndex < 0,
46
81
  className: cn(
47
82
  // `disabled:cursor-not-allowed disabled:opacity-50` and the checked fill are DELETED, not
48
83
  // moved: `.ui-checkbox:disabled, .ui-checkbox[data-disabled]` and
49
84
  // `.ui-checkbox[data-state="checked"]` in styles/control.css already declare both, reading
50
85
  // --disabled-opacity and --checkbox-checked-background. Utilities are layered AFTER
51
86
  // components in Tailwind v4, so these literals were silently OUTRANKING those knobs — a
52
- // service overriding --checkbox-checked-background got no fill change at all. Radix sets
53
- // `data-state`/`data-disabled` on the root, so the CSS rules match. Rendering is unchanged:
54
- // both knobs default to exactly the values these utilities hard-coded.
55
- "peer ui-checkbox aria-invalid:border-destructive data-[state=checked]:border-primary data-[state=checked]:text-primary-foreground shrink-0 shadow-xs transition-shadow outline-none",
87
+ // service overriding --checkbox-checked-background got no fill change at all. `data-state`
88
+ // above and react-aria's own `data-disabled` keep those CSS rules matching. Rendering is
89
+ // unchanged: both knobs default to exactly the values these utilities hard-coded.
90
+ //
91
+ // `inline-flex items-center justify-center` is NEW and load-bearing: the root used to be a
92
+ // `<button>` (inline-block, so `.ui-checkbox`'s width/height applied and the glyph centred
93
+ // itself). react-aria's root is a `<label>`, which is `display:inline` — without this the
94
+ // 16px box collapses to nothing. CheckboxVisual already carries the same three for the
95
+ // same reason.
96
+ "peer ui-checkbox data-[invalid]:border-destructive data-[state=checked]:border-primary data-[state=checked]:text-primary-foreground inline-flex shrink-0 items-center justify-center shadow-xs transition-shadow outline-none",
56
97
  className
57
98
  ),
58
- ...props,
59
- ...identity,
60
- onCheckedChange: (next) => {
99
+ onChange: (next) => {
61
100
  setUncontrolled(next);
62
- props.onCheckedChange?.(next);
101
+ onCheckedChange?.(next);
63
102
  },
64
- children: /* @__PURE__ */ jsx(CheckboxPrimitive.Indicator, { "data-slot": "checkbox-indicator", className: "ui-choice-indicator", children: /* @__PURE__ */ jsx(CheckboxGlyph, { state }) })
103
+ children: /* @__PURE__ */ jsx("span", { "data-slot": "checkbox-indicator", className: "ui-choice-indicator", children: state ? /* @__PURE__ */ jsx(CheckboxGlyph, { state }) : null })
65
104
  }
66
105
  );
67
106
  });
68
- CheckboxRoot.displayName = CheckboxPrimitive.Root.displayName;
107
+ CheckboxRoot.displayName = "Checkbox";
69
108
  const Checkbox = Object.assign(CheckboxRoot, {
70
109
  Group: CheckboxGroup
71
110
  });
@@ -1,5 +1,5 @@
1
1
  import type * as React from "react";
2
- /** Shared option shape — Ant Design `CheckboxOptionType` / `Radio` options. */
2
+ /** Shared option shape — the conventional `CheckboxOptionType` / `Radio` options entry. */
3
3
  export type ChoiceOption = {
4
4
  label: React.ReactNode;
5
5
  value: string;
@@ -1,4 +1,4 @@
1
1
  import * as React from "react";
2
2
  import type { ColorPickerProp } from "../../props/components/data-entry.prop.js";
3
3
  export type { ColorPickerProp, ColorPickerProp as ColorPickerProps, } from "../../props/components/data-entry.prop.js";
4
- export declare function ColorPicker({ value, onValueChange, disabled, className, id, showHexInput, ...ariaProps }: ColorPickerProp): React.JSX.Element;
4
+ export declare function ColorPicker({ value: valueProp, defaultValue, onValueChange, disabled, name, className, id, showHexInput, ...ariaProps }: ColorPickerProp): React.JSX.Element;
@@ -3,26 +3,35 @@ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { useTranslation } from "../../i18n/use-translation.js";
5
5
  import { cn } from "../../lib/utils.js";
6
- import { resolveFieldA11y } from "../../lib/field-a11y.js";
6
+ import { resolveFieldA11y, useFieldIdentity } from "../../lib/field-a11y.js";
7
7
  import { controlIconClass } from "../../lib/control-styles.js";
8
8
  import { Input } from "./input.js";
9
9
  const HEX_PATTERN = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
10
+ const NATIVE_COLOR_FALLBACK = "#000000";
10
11
  function normalizeHex(value) {
11
12
  if (!value.startsWith("#")) return `#${value}`;
12
13
  return value;
13
14
  }
14
15
  function ColorPicker({
15
- value = "#2563eb",
16
+ value: valueProp,
17
+ defaultValue,
16
18
  onValueChange,
17
19
  disabled,
20
+ name,
18
21
  className,
19
22
  id,
20
23
  showHexInput = true,
21
24
  ...ariaProps
22
25
  }) {
23
26
  const { t } = useTranslation();
27
+ const isControlled = valueProp !== void 0;
28
+ const [internalValue, setInternalValue] = React.useState(defaultValue ?? "");
29
+ const value = isControlled ? valueProp : internalValue;
24
30
  const [draft, setDraft] = React.useState(null);
25
31
  const display = draft ?? value;
32
+ const swatchValue = HEX_PATTERN.test(display) ? display : HEX_PATTERN.test(value) ? value : NATIVE_COLOR_FALLBACK;
33
+ const identity = useFieldIdentity({ id, name, "data-field": ariaProps["data-field"] });
34
+ const resolvedName = name ?? identity.name;
26
35
  const swatchA11y = resolveFieldA11y(ariaProps, t("dataEntry.colorPicker.ariaLabel"));
27
36
  const commit = (next) => {
28
37
  const normalized = normalizeHex(next);
@@ -31,6 +40,7 @@ function ColorPicker({
31
40
  return;
32
41
  }
33
42
  setDraft(null);
43
+ if (!isControlled) setInternalValue(normalized);
34
44
  onValueChange?.(normalized);
35
45
  };
36
46
  return /* @__PURE__ */ jsxs("div", { className: cn("ui-color-picker", className), children: [
@@ -39,7 +49,7 @@ function ColorPicker({
39
49
  "div",
40
50
  {
41
51
  className: "ui-color-picker-preview",
42
- style: { backgroundColor: HEX_PATTERN.test(display) ? display : value },
52
+ style: { backgroundColor: swatchValue },
43
53
  "aria-hidden": "true"
44
54
  }
45
55
  ),
@@ -48,10 +58,11 @@ function ColorPicker({
48
58
  {
49
59
  id,
50
60
  type: "color",
51
- value: HEX_PATTERN.test(display) ? display : value,
61
+ value: swatchValue,
52
62
  disabled,
53
63
  onChange: (event) => commit(event.target.value),
54
64
  className: "ui-color-picker-input",
65
+ "data-field": ariaProps["data-field"] ?? identity["data-field"],
55
66
  ...swatchA11y
56
67
  }
57
68
  )
@@ -71,7 +82,8 @@ function ColorPicker({
71
82
  className: "ui-color-picker-hex",
72
83
  spellCheck: false
73
84
  }
74
- )
85
+ ),
86
+ resolvedName ? /* @__PURE__ */ jsx("input", { type: "hidden", name: resolvedName, value, readOnly: true }) : null
75
87
  ] });
76
88
  }
77
89
  export {
@@ -0,0 +1,64 @@
1
+ import type * as React from "react";
2
+ import type { ControlStatusProp, ControlVariantProp } from "../../props/vocabulary/index.js";
3
+ import type { ControlCountProp } from "../../props/components/data-entry.prop.js";
4
+ /**
5
+ * The two appearance axes Ant Design puts on every text field — `status` and `variant` — resolved
6
+ * once, here, so Input / Textarea / NumberInput / PasswordInput / SearchInput cannot drift into
7
+ * three different spellings of "this field is wrong".
8
+ *
9
+ * WHY A HELPER AND NOT A CLASS PER COMPONENT. `status` has a SECOND half that is not paint:
10
+ * `error` must also report `aria-invalid`, or the red boundary is a lie to a screen reader. That
11
+ * pairing is the thing worth keeping in one place; the CSS is the easy half.
12
+ */
13
+ export type ControlAppearanceInput = {
14
+ status?: ControlStatusProp;
15
+ variant?: ControlVariantProp;
16
+ "aria-invalid"?: React.AriaAttributes["aria-invalid"];
17
+ };
18
+ export type ControlAppearanceAttributes = {
19
+ "data-status"?: ControlStatusProp;
20
+ "data-variant"?: ControlVariantProp;
21
+ "aria-invalid"?: React.AriaAttributes["aria-invalid"];
22
+ };
23
+ /**
24
+ * `status="error"` REPORTS `aria-invalid` — unless the caller (or FormField, which injects it)
25
+ * already said something, in which case the explicit value wins and nothing is overwritten.
26
+ * `status="warning"` deliberately reports nothing: a warning is not a validity failure, and
27
+ * antd does not announce one either (es/_util/statusUtils.js only reaches for the class name).
28
+ */
29
+ export declare function controlAppearanceAttributes({ status, variant, "aria-invalid": ariaInvalid, }: ControlAppearanceInput): ControlAppearanceAttributes;
30
+ /**
31
+ * The chrome utilities a variant carries, kept in the COMPONENT rather than in `control.css`.
32
+ *
33
+ * A Tailwind utility lives in `@layer utilities`, which outranks `@layer components` no matter
34
+ * how specific the component rule is — so `bg-background` baked unconditionally into the class
35
+ * list would silently defeat `filled` and `borderless` and no gate would notice. The outlined
36
+ * field therefore keeps exactly the utilities it always had, and the other two simply do not
37
+ * receive them; their surface comes from `.ui-control--filled` / `.ui-control--borderless`.
38
+ */
39
+ export declare const CONTROL_VARIANT_CHROME_CLASS: Record<ControlVariantProp, string>;
40
+ /**
41
+ * The status BOUNDARY, for the same cascade-layer reason — and this one was measured the hard way.
42
+ *
43
+ * `.ui-control[data-status="warning"] { border-color: … }` in `@layer components` renders exactly
44
+ * nothing: `border-input` is a utility, utilities are a later layer, and a later layer wins over
45
+ * any specificity. In Chromium the warned field measured `rgb(144 135 127)` — the resting border —
46
+ * with the component rule in place and no error anywhere. Painting it from a utility instead puts
47
+ * the two declarations in the SAME layer, where `data-[status=…]` (0,2,0) genuinely outranks
48
+ * `border-input` (0,1,0). It is also the mechanism the library already used for the invalid state
49
+ * (`aria-invalid:border-destructive`), so the two states now paint the same way.
50
+ *
51
+ * The `--focus-*` reassignments stay in `control.css`: those are custom properties, and no utility
52
+ * competes for them.
53
+ */
54
+ export declare const CONTROL_STATUS_CHROME_CLASS = "data-[status=error]:border-destructive data-[status=warning]:border-warning";
55
+ /** Default `count.strategy` — code points, so a surrogate pair counts once. */
56
+ export declare function countCodePoints(value: string): number;
57
+ export type ResolvedControlCount = {
58
+ count: number;
59
+ max?: number;
60
+ exceeded: boolean;
61
+ content: React.ReactNode;
62
+ };
63
+ /** `null` when the counter is switched off (no `count`, or `count.show === false`). */
64
+ export declare function resolveControlCount(config: ControlCountProp | undefined, value: string): ResolvedControlCount | null;