@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
@@ -0,0 +1,50 @@
1
+ "use client";
2
+ import { Fragment, jsx } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import {
5
+ get,
6
+ useFieldArray,
7
+ useFormContext,
8
+ useFormState
9
+ } from "react-hook-form";
10
+ import { getFallbackFormControl, useFormDisabled } from "./form-context.js";
11
+ function arrayErrorMessage(errors, name) {
12
+ const entry = get(errors, name);
13
+ const message = entry?.root?.message ?? entry?.message;
14
+ return typeof message === "string" && message ? message : void 0;
15
+ }
16
+ function FormFieldArray({ name, children }) {
17
+ const rhf = useFormContext();
18
+ const control = rhf?.control ?? getFallbackFormControl();
19
+ const { fields, append, prepend, insert, remove, move, swap, replace } = useFieldArray({ control, name });
20
+ const { errors } = useFormState({ control, name });
21
+ const disabled = useFormDisabled();
22
+ const rows = React.useMemo(
23
+ () => fields.map((row, index) => ({
24
+ key: row.id,
25
+ name: `${String(name)}.${index}`,
26
+ index
27
+ })),
28
+ [fields, name]
29
+ );
30
+ if (!rhf) {
31
+ throw new Error(
32
+ "FormFieldArray must be rendered inside <FormRoot form={\u2026}> (react-hook-form path)."
33
+ );
34
+ }
35
+ return /* @__PURE__ */ jsx(Fragment, { children: children({
36
+ fields: rows,
37
+ append,
38
+ prepend,
39
+ insert,
40
+ remove,
41
+ move,
42
+ swap,
43
+ replace,
44
+ error: arrayErrorMessage(errors, String(name)),
45
+ disabled
46
+ }) });
47
+ }
48
+ export {
49
+ FormFieldArray
50
+ };
@@ -1,4 +1,5 @@
1
+ import * as React from "react";
1
2
  import { type FieldValues } from "react-hook-form";
2
3
  import type { FormFieldControlProp } from "../props/components/form.prop.js";
3
4
  export type { FormFieldControlProp } from "../props/components/form.prop.js";
4
- export declare function FormFieldControl<TFieldValues extends FieldValues>({ name, label, required, helper, className, children, }: FormFieldControlProp<TFieldValues>): import("react").JSX.Element;
5
+ export declare function FormFieldControl<TFieldValues extends FieldValues>({ name, id, field: fieldKey, labelAddon, layout, labelWidth, controlWidth, colSpan, label, required, helper, disabled, dependencies, getValueFromEvent, normalize, help, validateStatus, hasFeedback, feedback, preserve, className, children, }: FormFieldControlProp<TFieldValues>): React.JSX.Element;
@@ -1,70 +1,146 @@
1
1
  "use client";
2
- import { jsx } from "react/jsx-runtime";
3
- import { Controller, useFormContext } from "react-hook-form";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
4
+ import {
5
+ Controller,
6
+ useFormContext,
7
+ useFormState,
8
+ useWatch
9
+ } from "react-hook-form";
4
10
  import { FormField } from "../components/data-entry/form-field.js";
5
- import { extractControlValue, useFormAdapter } from "./form-context.js";
11
+ import { extractControlValue, useFormAdapter, useFormDisabled } from "./form-context.js";
6
12
  const noopRef = () => {
7
13
  };
14
+ function bindField(field) {
15
+ return { ...field, onValueChange: field.onChange };
16
+ }
17
+ function FieldDependencies({
18
+ control,
19
+ name,
20
+ dependencies,
21
+ trigger
22
+ }) {
23
+ const values = useWatch({ control, name: dependencies });
24
+ const { isSubmitted } = useFormState({ control });
25
+ const signature = JSON.stringify(values ?? null);
26
+ React.useEffect(() => {
27
+ if (!isSubmitted) return;
28
+ void trigger(name);
29
+ }, [signature, isSubmitted, name, trigger]);
30
+ return null;
31
+ }
8
32
  function FormFieldControl({
9
33
  name,
34
+ id,
35
+ field: fieldKey,
36
+ labelAddon,
37
+ layout,
38
+ labelWidth,
39
+ controlWidth,
40
+ colSpan,
10
41
  label,
11
42
  required,
12
43
  helper,
44
+ disabled,
45
+ dependencies,
46
+ getValueFromEvent,
47
+ normalize,
48
+ help,
49
+ validateStatus,
50
+ hasFeedback,
51
+ feedback,
52
+ preserve,
13
53
  className,
14
54
  children
15
55
  }) {
56
+ const autoId = React.useId();
57
+ const resolvedId = id ?? `${autoId}-${String(name)}`;
58
+ const presentation = { field: fieldKey, labelAddon, layout, labelWidth, controlWidth, colSpan };
16
59
  const adapter = useFormAdapter();
17
60
  const rhf = useFormContext();
61
+ const formDisabled = useFormDisabled();
62
+ const isDisabled = disabled ?? formDisabled;
63
+ const disabledProp = isDisabled ? { disabled: true } : disabled === false ? { disabled: false } : void 0;
64
+ const readValue = (args, previousValue) => {
65
+ const raw = getValueFromEvent ? getValueFromEvent(...args) : extractControlValue(args[0]);
66
+ return normalize ? normalize(raw, previousValue) : raw;
67
+ };
18
68
  if (adapter) {
19
69
  const fieldName = String(name);
20
70
  return /* @__PURE__ */ jsx(
21
71
  FormField,
22
72
  {
23
- id: fieldName,
73
+ ...presentation,
74
+ id: resolvedId,
24
75
  name: fieldName,
25
76
  label,
26
77
  required,
27
78
  helper,
28
- error: adapter.getError(fieldName),
79
+ error: help ?? adapter.getError(fieldName),
80
+ validateStatus,
81
+ hasFeedback,
82
+ feedback,
29
83
  className,
30
- children: children({
31
- id: fieldName,
32
- name: fieldName,
33
- value: adapter.getValue(fieldName),
34
- onChange: (...args) => adapter.setValue(fieldName, extractControlValue(args[0])),
35
- onBlur: () => adapter.onBlur?.(fieldName),
36
- ref: noopRef
37
- })
84
+ children: children(
85
+ bindField({
86
+ id: resolvedId,
87
+ name: fieldName,
88
+ value: adapter.getValue(fieldName),
89
+ onChange: (...args) => adapter.setValue(fieldName, readValue(args, adapter.getValue(fieldName))),
90
+ onBlur: () => adapter.onBlur?.(fieldName),
91
+ ref: noopRef,
92
+ ...disabledProp
93
+ })
94
+ )
38
95
  }
39
96
  );
40
97
  }
41
- return /* @__PURE__ */ jsx(
42
- Controller,
43
- {
44
- name,
45
- control: rhf.control,
46
- render: ({ field, fieldState }) => /* @__PURE__ */ jsx(
47
- FormField,
48
- {
49
- id: String(name),
50
- name: String(name),
51
- label,
52
- required,
53
- helper,
54
- error: fieldState.error?.message,
55
- className,
56
- children: children({
57
- id: String(name),
58
- name: field.name,
59
- value: field.value,
60
- onChange: field.onChange,
61
- onBlur: field.onBlur,
62
- ref: field.ref
63
- })
64
- }
65
- )
66
- }
67
- );
98
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
99
+ dependencies?.length ? /* @__PURE__ */ jsx(
100
+ FieldDependencies,
101
+ {
102
+ control: rhf.control,
103
+ name,
104
+ dependencies,
105
+ trigger: rhf.trigger
106
+ }
107
+ ) : null,
108
+ /* @__PURE__ */ jsx(
109
+ Controller,
110
+ {
111
+ name,
112
+ control: rhf.control,
113
+ shouldUnregister: preserve === false,
114
+ render: ({ field, fieldState }) => /* @__PURE__ */ jsx(
115
+ FormField,
116
+ {
117
+ ...presentation,
118
+ id: resolvedId,
119
+ name: String(name),
120
+ label,
121
+ required,
122
+ helper,
123
+ error: help ?? fieldState.error?.message,
124
+ validateStatus,
125
+ hasFeedback,
126
+ feedback,
127
+ className,
128
+ children: children(
129
+ bindField({
130
+ id: resolvedId,
131
+ name: field.name,
132
+ value: field.value,
133
+ onChange: (...args) => field.onChange(readValue(args, field.value)),
134
+ onBlur: field.onBlur,
135
+ ref: field.ref,
136
+ ...disabledProp
137
+ })
138
+ )
139
+ }
140
+ )
141
+ }
142
+ )
143
+ ] });
68
144
  }
69
145
  export {
70
146
  FormFieldControl
@@ -1,3 +1,4 @@
1
+ import * as React from "react";
1
2
  import { type FieldValues } from "react-hook-form";
2
3
  import type { FormRootProp } from "../props/components/form.prop.js";
3
4
  export type { FormRootProp } from "../props/components/form.prop.js";
@@ -6,4 +7,4 @@ export type { FormRootProp } from "../props/components/form.prop.js";
6
7
  * validation) OR `adapter` (a framework-agnostic {@link FormStateAdapter} for a server-driven form
7
8
  * library — Inertia's `useForm` via `@godxjp/ui/inertia`, formik, TanStack Form).
8
9
  */
9
- export declare function FormRoot<TFieldValues extends FieldValues>({ form, adapter, onSubmit, children, className, id, }: FormRootProp<TFieldValues>): import("react").JSX.Element;
10
+ export declare function FormRoot<TFieldValues extends FieldValues>({ form, adapter, onSubmit, onSubmitFailed, onSubmitError, onReset, scrollToFirstError, disabled, layout, labelWidth, controlWidth, labelAlign, collapseBelow, density, columns, requiredMark, errors, children, className, id, }: FormRootProp<TFieldValues>): React.JSX.Element;
@@ -1,46 +1,165 @@
1
1
  "use client";
2
- import { jsx } from "react/jsx-runtime";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React from "react";
3
4
  import { FormProvider } from "react-hook-form";
5
+ import { Alert, AlertDescription } from "../components/feedback/alert.js";
6
+ import { ResponsiveGrid } from "../components/layout/responsive-grid.js";
7
+ import { useTranslation } from "../i18n/use-translation.js";
4
8
  import { cn } from "../lib/utils.js";
5
- import { FormAdapterContext } from "./form-context.js";
9
+ import { Form } from "../components/data-entry/form.js";
10
+ import { FormAdapterContext, FormOptionsContext } from "./form-context.js";
11
+ function collectErrorNames(errors, prefix = "", out = []) {
12
+ if (!errors || typeof errors !== "object") return out;
13
+ for (const [key, value] of Object.entries(errors)) {
14
+ if (!value || typeof value !== "object") continue;
15
+ const path = prefix ? `${prefix}.${key}` : key;
16
+ if ("message" in value || "type" in value) out.push(path);
17
+ else collectErrorNames(value, path, out);
18
+ }
19
+ return out;
20
+ }
21
+ function scrollFirstErrorIntoView(formEl, errors) {
22
+ if (!formEl) return;
23
+ const names = new Set(collectErrorNames(errors));
24
+ if (names.size === 0) return;
25
+ const control = Array.from(formEl.querySelectorAll("[data-field]")).find(
26
+ (el) => names.has(el.dataset.field ?? "")
27
+ );
28
+ if (!control) return;
29
+ const focusTarget = control.matches("input, select, textarea, button, [tabindex]") ? control : control.querySelector("input, select, textarea, button, [tabindex]");
30
+ focusTarget?.focus({ preventScroll: true });
31
+ const target = control.closest('[data-slot="form-field"]') ?? control;
32
+ if (typeof target.scrollIntoView !== "function") return;
33
+ const reduceMotion = typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
34
+ target.scrollIntoView({ block: "center", behavior: reduceMotion ? "auto" : "smooth" });
35
+ }
36
+ function afterPaint(run) {
37
+ if (typeof requestAnimationFrame === "function") requestAnimationFrame(() => run());
38
+ else setTimeout(run, 0);
39
+ }
6
40
  function FormRoot({
7
41
  form,
8
42
  adapter,
9
43
  onSubmit,
44
+ onSubmitFailed,
45
+ onSubmitError,
46
+ onReset,
47
+ scrollToFirstError = true,
48
+ disabled = false,
49
+ layout,
50
+ labelWidth,
51
+ controlWidth,
52
+ labelAlign,
53
+ collapseBelow,
54
+ density,
55
+ columns,
56
+ requiredMark,
57
+ errors,
10
58
  children,
11
59
  className,
12
60
  id
13
61
  }) {
62
+ const formRef = React.useRef(null);
63
+ const { t } = useTranslation();
64
+ const pending = React.useRef(false);
65
+ const [submitting, setSubmitting] = React.useState(false);
66
+ const [submitFailed, setSubmitFailed] = React.useState(false);
67
+ const options = React.useMemo(() => ({ disabled, submitting }), [disabled, submitting]);
68
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [
69
+ submitFailed && /* @__PURE__ */ jsx(Alert, { tone: "destructive", children: /* @__PURE__ */ jsx(AlertDescription, { children: t("dataEntry.form.submitFailed") }) }),
70
+ columns ? /* @__PURE__ */ jsx(ResponsiveGrid, { columns, children }) : children
71
+ ] });
72
+ const submit = async (work) => {
73
+ if (disabled || pending.current || adapter?.isSubmitting) return;
74
+ pending.current = true;
75
+ setSubmitting(true);
76
+ setSubmitFailed(false);
77
+ try {
78
+ await work();
79
+ } catch (error) {
80
+ setSubmitFailed(true);
81
+ onSubmitError?.(error);
82
+ } finally {
83
+ pending.current = false;
84
+ setSubmitting(false);
85
+ }
86
+ };
87
+ const layoutShell = layout !== void 0 || labelWidth !== void 0 || controlWidth !== void 0 || labelAlign !== void 0 || collapseBelow !== void 0 || density !== void 0 || requiredMark !== void 0 || errors !== void 0;
88
+ const formClassName = layoutShell ? className : cn("ui-stack-md", className);
89
+ const withLayout = (node) => layoutShell ? /* @__PURE__ */ jsx(
90
+ Form,
91
+ {
92
+ asChild: true,
93
+ layout,
94
+ labelWidth,
95
+ controlWidth,
96
+ labelAlign,
97
+ collapseBelow,
98
+ density,
99
+ requiredMark,
100
+ disabled,
101
+ errors,
102
+ children: node
103
+ }
104
+ ) : node;
14
105
  if (adapter) {
15
- return /* @__PURE__ */ jsx(FormAdapterContext.Provider, { value: adapter, children: /* @__PURE__ */ jsx(
106
+ return /* @__PURE__ */ jsx(FormAdapterContext.Provider, { value: adapter, children: /* @__PURE__ */ jsx(FormOptionsContext.Provider, { value: options, children: withLayout(
107
+ /* @__PURE__ */ jsx(
108
+ "form",
109
+ {
110
+ ref: formRef,
111
+ id,
112
+ className: formClassName,
113
+ onSubmit: (event) => {
114
+ event.preventDefault();
115
+ void submit(() => onSubmit(adapter.getValues?.() ?? {}));
116
+ },
117
+ onReset: (event) => {
118
+ event.preventDefault();
119
+ if (pending.current) return;
120
+ setSubmitFailed(false);
121
+ adapter.reset?.();
122
+ onReset?.();
123
+ },
124
+ noValidate: true,
125
+ children: content
126
+ }
127
+ )
128
+ ) }) });
129
+ }
130
+ if (!form) {
131
+ throw new Error("FormRoot requires either a `form` (react-hook-form) or an `adapter` prop.");
132
+ }
133
+ const handleInvalid = (fieldErrors) => {
134
+ onSubmitFailed?.(fieldErrors);
135
+ if (scrollToFirstError)
136
+ afterPaint(() => scrollFirstErrorIntoView(formRef.current, fieldErrors));
137
+ };
138
+ return /* @__PURE__ */ jsx(FormProvider, { ...form, children: /* @__PURE__ */ jsx(FormOptionsContext.Provider, { value: options, children: withLayout(
139
+ /* @__PURE__ */ jsx(
16
140
  "form",
17
141
  {
142
+ ref: formRef,
18
143
  id,
19
- className: cn("ui-stack-md", className),
144
+ className: formClassName,
20
145
  onSubmit: (event) => {
21
146
  event.preventDefault();
22
- void onSubmit(adapter.getValues?.() ?? {});
147
+ void submit(
148
+ () => form.handleSubmit((values) => onSubmit(values), handleInvalid)(event)
149
+ );
150
+ },
151
+ onReset: (event) => {
152
+ event.preventDefault();
153
+ if (pending.current) return;
154
+ setSubmitFailed(false);
155
+ form.reset();
156
+ onReset?.();
23
157
  },
24
158
  noValidate: true,
25
- children
159
+ children: content
26
160
  }
27
- ) });
28
- }
29
- if (!form) {
30
- throw new Error("FormRoot requires either a `form` (react-hook-form) or an `adapter` prop.");
31
- }
32
- return /* @__PURE__ */ jsx(FormProvider, { ...form, children: /* @__PURE__ */ jsx(
33
- "form",
34
- {
35
- id,
36
- className: cn("ui-stack-md", className),
37
- onSubmit: (event) => {
38
- void form.handleSubmit((values) => onSubmit(values))(event);
39
- },
40
- noValidate: true,
41
- children
42
- }
43
- ) });
161
+ )
162
+ ) }) });
44
163
  }
45
164
  export {
46
165
  FormRoot
@@ -4,5 +4,7 @@ export { FormRoot } from "./form-root.js";
4
4
  export type { FormRootProp } from "./form-root.js";
5
5
  export { FormFieldControl } from "./form-field-control.js";
6
6
  export type { FormFieldControlProp } from "./form-field-control.js";
7
- export { useFormSubmitting, useFormAdapter } from "./form-context.js";
7
+ export { FormFieldArray } from "./form-field-array.js";
8
+ export type { FormFieldArrayProp } from "./form-field-array.js";
9
+ export { useFormSubmitting, useFormAdapter, useFormDisabled, useFormInstance, useFormWatch, } from "./form-context.js";
8
10
  export type { ZodSchemaProp, FieldErrorMessageProp, FormStateAdapter, } from "../props/components/form.prop.js";
@@ -1,11 +1,22 @@
1
1
  import { useZodForm } from "./use-zod-form.js";
2
2
  import { FormRoot } from "./form-root.js";
3
3
  import { FormFieldControl } from "./form-field-control.js";
4
- import { useFormSubmitting, useFormAdapter } from "./form-context.js";
4
+ import { FormFieldArray } from "./form-field-array.js";
5
+ import {
6
+ useFormSubmitting,
7
+ useFormAdapter,
8
+ useFormDisabled,
9
+ useFormInstance,
10
+ useFormWatch
11
+ } from "./form-context.js";
5
12
  export {
13
+ FormFieldArray,
6
14
  FormFieldControl,
7
15
  FormRoot,
8
16
  useFormAdapter,
17
+ useFormDisabled,
18
+ useFormInstance,
9
19
  useFormSubmitting,
20
+ useFormWatch,
10
21
  useZodForm
11
22
  };
@@ -23,7 +23,8 @@
23
23
  },
24
24
  "datePicker": {
25
25
  "placeholder": "Select date",
26
- "openCalendar": "Open calendar"
26
+ "openCalendar": "Open calendar",
27
+ "quarter": "Q{quarter}"
27
28
  },
28
29
  "dateRangePicker": {
29
30
  "placeholder": "Select date range",
@@ -39,7 +40,10 @@
39
40
  "openPicker": "Open time picker",
40
41
  "meridiem": "AM/PM",
41
42
  "am": "AM",
42
- "pm": "PM"
43
+ "pm": "PM",
44
+ "now": "Now",
45
+ "confirm": "OK",
46
+ "second": "Second"
43
47
  },
44
48
  "searchInput": {
45
49
  "placeholder": "Search…"
@@ -55,7 +59,7 @@
55
59
  "upload": {
56
60
  "dropzoneLabel": "Upload files",
57
61
  "dropzoneHint": "Drag and drop files here, or click to browse",
58
- "dropzoneMeta": "Uploads go to temp storage — promote on form save",
62
+ "dropzoneMeta": "Selected files appear here.",
59
63
  "buttonLabel": "Choose file",
60
64
  "addImage": "Add image",
61
65
  "uploading": "Uploading…",
@@ -75,7 +79,17 @@
75
79
  "statusFailed": "{count} upload(s) failed",
76
80
  "removeImage": "Remove image",
77
81
  "removeFile": "Remove {name}",
78
- "cropDescription": "Drag the zoom slider, then save to crop your photo to a square."
82
+ "cropDescription": "Drag the zoom slider, then save to crop your photo to a square.",
83
+ "preview": "Preview",
84
+ "download": "Download",
85
+ "retry": "Retry",
86
+ "start": "Upload",
87
+ "cancel": "Cancel",
88
+ "rejectAccept": "{name}: file type is not allowed.",
89
+ "rejectSize": "{name}: file is too large.",
90
+ "rejectCount": "{name}: file limit reached.",
91
+ "rejectBeforeUpload": "{name}: file validation failed.",
92
+ "readFailed": "Could not read the selected folder."
79
93
  },
80
94
  "cascader": {
81
95
  "placeholder": "Select…",
@@ -109,6 +123,9 @@
109
123
  "empty": "No results",
110
124
  "error": "Couldn’t load options"
111
125
  },
126
+ "selection": {
127
+ "overflow": "+{count}"
128
+ },
112
129
  "monthPicker": {
113
130
  "openGrid": "Open month grid",
114
131
  "previousYear": "Previous year",
@@ -135,6 +152,14 @@
135
152
  },
136
153
  "formErrors": {
137
154
  "title": "Please review the following errors"
155
+ },
156
+ "form": {
157
+ "optional": "(optional)",
158
+ "success": "Valid",
159
+ "warning": "Please review",
160
+ "error": "Invalid",
161
+ "validating": "Validating",
162
+ "submitFailed": "Could not submit the form. Please try again."
138
163
  }
139
164
  },
140
165
  "feedback": {
@@ -290,8 +315,13 @@
290
315
  }
291
316
  },
292
317
  "navigation": {
318
+ "tabs": {
319
+ "addTab": "Add tab",
320
+ "removeTab": "Close tab"
321
+ },
293
322
  "steps": {
294
323
  "ariaLabel": "Progress",
324
+ "percentLabel": "Current step progress",
295
325
  "status": {
296
326
  "wait": "Waiting",
297
327
  "process": "Current step",
@@ -332,6 +362,7 @@
332
362
  "page": "Page {page}",
333
363
  "pageSize": "Page size",
334
364
  "pageSizeTrigger": "{size} / page",
365
+ "jumpTo": "Go to page",
335
366
  "pageSizeOption": "{size} / page",
336
367
  "total": {
337
368
  "one": "Total {total} item",
@@ -410,7 +441,19 @@
410
441
  "error": "Couldn't load this list",
411
442
  "errorDescription": "The data could not be retrieved. Try again in a moment.",
412
443
  "denied": "You don't have access to this list",
413
- "deniedDescription": "Ask an administrator to grant you permission to view these records."
444
+ "deniedDescription": "Ask an administrator to grant you permission to view these records.",
445
+ "selectInvert": "Invert selection",
446
+ "selectNone": "Clear selection",
447
+ "selectionMenu": "Selection options",
448
+ "filterColumn": "Filter",
449
+ "filterReset": "Reset filter",
450
+ "expandColumn": "Expand",
451
+ "expandRow": "Expand row",
452
+ "collapseRow": "Collapse row",
453
+ "sortAscending": "Sort ascending",
454
+ "sortDescending": "Sort descending",
455
+ "sortCancel": "Cancel sort",
456
+ "selectColumn": "Select"
414
457
  },
415
458
  "dataGrid": {
416
459
  "search": "Search",
@@ -478,5 +521,13 @@
478
521
  "summaryPie": "Pie chart with {slices} slices",
479
522
  "summaryTrend": "Bar trend with {points} data points",
480
523
  "trendCurrent": "current"
524
+ },
525
+ "rangeTimeline": {
526
+ "outsideRange": "Outside the visible range",
527
+ "schedule": "Schedule"
528
+ },
529
+ "textExamples": {
530
+ "preservedText": "Plain text",
531
+ "sampleText": "First line\n Indented line\n\nLast line"
481
532
  }
482
533
  }