ding-react-admin 2.4.0 → 2.5.1

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 (78) hide show
  1. package/dist/index.js +278 -232
  2. package/dist/src/crud/HiddenSources.d.ts +9 -0
  3. package/dist/src/crud/HiddenSources.d.ts.map +1 -0
  4. package/dist/src/crud/InlineFormSet.d.ts.map +1 -1
  5. package/dist/src/crud/columns/BooleanColumn.d.ts.map +1 -1
  6. package/dist/src/crud/columns/DateColumn.d.ts.map +1 -1
  7. package/dist/src/crud/columns/ImageColumn.d.ts.map +1 -1
  8. package/dist/src/crud/columns/NumberColumn.d.ts.map +1 -1
  9. package/dist/src/crud/columns/ReferenceColumn.d.ts.map +1 -1
  10. package/dist/src/crud/columns/ReferenceManyColumn.d.ts.map +1 -1
  11. package/dist/src/crud/columns/TextColumn.d.ts.map +1 -1
  12. package/dist/src/crud/fields/BooleanField.d.ts +3 -3
  13. package/dist/src/crud/fields/BooleanField.d.ts.map +1 -1
  14. package/dist/src/crud/fields/DateField.d.ts +3 -3
  15. package/dist/src/crud/fields/DateField.d.ts.map +1 -1
  16. package/dist/src/crud/fields/FieldWrapper.d.ts +3 -1
  17. package/dist/src/crud/fields/FieldWrapper.d.ts.map +1 -1
  18. package/dist/src/crud/fields/FileField.d.ts +3 -3
  19. package/dist/src/crud/fields/FileField.d.ts.map +1 -1
  20. package/dist/src/crud/fields/ImageField.d.ts +3 -3
  21. package/dist/src/crud/fields/ImageField.d.ts.map +1 -1
  22. package/dist/src/crud/fields/NumberField.d.ts +3 -3
  23. package/dist/src/crud/fields/NumberField.d.ts.map +1 -1
  24. package/dist/src/crud/fields/PasswordField.d.ts +3 -3
  25. package/dist/src/crud/fields/PasswordField.d.ts.map +1 -1
  26. package/dist/src/crud/fields/ReferenceField.d.ts +3 -3
  27. package/dist/src/crud/fields/ReferenceField.d.ts.map +1 -1
  28. package/dist/src/crud/fields/ReferenceManyField.d.ts +3 -3
  29. package/dist/src/crud/fields/ReferenceManyField.d.ts.map +1 -1
  30. package/dist/src/crud/fields/SelectField.d.ts +3 -3
  31. package/dist/src/crud/fields/SelectField.d.ts.map +1 -1
  32. package/dist/src/crud/fields/TextAreaField.d.ts +3 -3
  33. package/dist/src/crud/fields/TextAreaField.d.ts.map +1 -1
  34. package/dist/src/crud/fields/TextField.d.ts +3 -3
  35. package/dist/src/crud/fields/TextField.d.ts.map +1 -1
  36. package/dist/src/crud/fields/TimeField.d.ts +3 -3
  37. package/dist/src/crud/fields/TimeField.d.ts.map +1 -1
  38. package/dist/src/crud/index.d.ts +3 -1
  39. package/dist/src/crud/index.d.ts.map +1 -1
  40. package/dist/src/crud/types.d.ts +5 -0
  41. package/dist/src/crud/types.d.ts.map +1 -1
  42. package/dist/src/crud/utils/buildInlineRowsPayload.d.ts.map +1 -1
  43. package/dist/src/crud/utils/columnDataIndex.d.ts +5 -0
  44. package/dist/src/crud/utils/columnDataIndex.d.ts.map +1 -0
  45. package/dist/src/crud/utils/shouldRegisterSourceInPayload.d.ts +6 -0
  46. package/dist/src/crud/utils/shouldRegisterSourceInPayload.d.ts.map +1 -0
  47. package/dist/src/index.d.ts +2 -2
  48. package/dist/src/index.d.ts.map +1 -1
  49. package/package.json +1 -1
  50. package/src/crud/HiddenSources.tsx +37 -0
  51. package/src/crud/InlineFormSet.tsx +4 -1
  52. package/src/crud/columns/BooleanColumn.tsx +2 -1
  53. package/src/crud/columns/DateColumn.tsx +2 -1
  54. package/src/crud/columns/ImageColumn.tsx +2 -1
  55. package/src/crud/columns/NumberColumn.tsx +2 -1
  56. package/src/crud/columns/ReferenceColumn.tsx +2 -1
  57. package/src/crud/columns/ReferenceManyColumn.tsx +2 -1
  58. package/src/crud/columns/TextColumn.tsx +3 -2
  59. package/src/crud/fields/BooleanField.tsx +4 -2
  60. package/src/crud/fields/DateField.tsx +4 -2
  61. package/src/crud/fields/FieldWrapper.tsx +20 -7
  62. package/src/crud/fields/FileField.tsx +4 -2
  63. package/src/crud/fields/ImageField.tsx +4 -2
  64. package/src/crud/fields/NumberField.tsx +4 -2
  65. package/src/crud/fields/PasswordField.tsx +8 -2
  66. package/src/crud/fields/ReferenceField.tsx +8 -4
  67. package/src/crud/fields/ReferenceManyField.tsx +5 -3
  68. package/src/crud/fields/SelectField.tsx +5 -3
  69. package/src/crud/fields/TextAreaField.tsx +4 -2
  70. package/src/crud/fields/TextField.tsx +4 -2
  71. package/src/crud/fields/TimeField.tsx +4 -2
  72. package/src/crud/index.ts +3 -0
  73. package/src/crud/types.ts +6 -0
  74. package/src/crud/utils/buildInlineRowsPayload.ts +5 -2
  75. package/src/crud/utils/columnDataIndex.ts +6 -0
  76. package/src/crud/utils/shouldRegisterSourceInPayload.ts +10 -0
  77. package/src/data/dataUtils.test.ts +52 -1
  78. package/src/index.ts +3 -0
@@ -7,6 +7,8 @@ import type {
7
7
  InlineRowContext,
8
8
  } from "./types";
9
9
  import { nestedFieldPath } from "./utils/nestedFieldPath";
10
+ import { getFormValue } from "./utils/getFormValue";
11
+ import { setFormValue } from "./utils/setFormValue";
10
12
  import { useRegisterInlineField } from "./context/InlineFieldsRegistry";
11
13
  import { useRegisterPayloadField } from "./context/PayloadFieldsContext";
12
14
 
@@ -29,7 +31,8 @@ export type InlineFormSetStackedProps = InlineFormSetBaseProps & {
29
31
  function emptyRow(sources: string[], defaults?: Record<string, unknown>) {
30
32
  const row: Record<string, unknown> = {};
31
33
  for (const source of sources) {
32
- row[source] = defaults?.[source] ?? undefined;
34
+ const value = defaults ? getFormValue(defaults, source) : undefined;
35
+ setFormValue(row, source, value);
33
36
  }
34
37
  return row;
35
38
  }
@@ -1,5 +1,6 @@
1
1
  import { useMemo } from "react";
2
2
  import type { BaseSourceProps } from "../types";
3
+ import { columnDataIndex } from "../utils/columnDataIndex";
3
4
  import { useRegisterColumn } from "../context/ListContext";
4
5
 
5
6
  export type BooleanColumnProps = BaseSourceProps & {
@@ -19,7 +20,7 @@ export function BooleanColumn({
19
20
  sortable,
20
21
  buildColumn: () => ({
21
22
  title: label ?? source,
22
- dataIndex: source,
23
+ dataIndex: columnDataIndex(source),
23
24
  key: source,
24
25
  sorter: sortable ? true : undefined,
25
26
  render: (v: boolean) => (v ? "Yes" : "No"),
@@ -1,5 +1,6 @@
1
1
  import { useMemo } from "react";
2
2
  import type { BaseSourceProps } from "../types";
3
+ import { columnDataIndex } from "../utils/columnDataIndex";
3
4
  import { useRegisterColumn } from "../context/ListContext";
4
5
 
5
6
  export type DateColumnProps = BaseSourceProps & {
@@ -15,7 +16,7 @@ export function DateColumn({ source, label, sortable = true }: DateColumnProps)
15
16
  sortable,
16
17
  buildColumn: () => ({
17
18
  title: label ?? source,
18
- dataIndex: source,
19
+ dataIndex: columnDataIndex(source),
19
20
  key: source,
20
21
  sorter: sortable ? true : undefined,
21
22
  render: (v: string) => (v ? String(v).slice(0, 10) : "—"),
@@ -1,5 +1,6 @@
1
1
  import { useMemo, type CSSProperties } from "react";
2
2
  import type { BaseSourceProps } from "../types";
3
+ import { columnDataIndex } from "../utils/columnDataIndex";
3
4
  import { useRegisterColumn } from "../context/ListContext";
4
5
 
5
6
  export type ImageColumnProps = BaseSourceProps & {
@@ -31,7 +32,7 @@ export function ImageColumn({
31
32
  sortable,
32
33
  buildColumn: () => ({
33
34
  title: label ?? source,
34
- dataIndex: source,
35
+ dataIndex: columnDataIndex(source),
35
36
  key: source,
36
37
  sorter: sortable ? true : undefined,
37
38
  render: (value: unknown) => {
@@ -1,5 +1,6 @@
1
1
  import { useMemo } from "react";
2
2
  import type { BaseSourceProps } from "../types";
3
+ import { columnDataIndex } from "../utils/columnDataIndex";
3
4
  import { useRegisterColumn } from "../context/ListContext";
4
5
 
5
6
  export type NumberColumnProps = BaseSourceProps & {
@@ -19,7 +20,7 @@ export function NumberColumn({
19
20
  sortable,
20
21
  buildColumn: () => ({
21
22
  title: label ?? source,
22
- dataIndex: source,
23
+ dataIndex: columnDataIndex(source),
23
24
  key: source,
24
25
  sorter: sortable ? true : undefined,
25
26
  }),
@@ -1,6 +1,7 @@
1
1
  import { useMemo } from "react";
2
2
  import type { BaseSourceProps, DisplayProps, ReferenceProps } from "../types";
3
3
  import { useRegisterColumn } from "../context/ListContext";
4
+ import { getFormValue } from "../utils/getFormValue";
4
5
  import { useChoices } from "../utils/useChoices";
5
6
  import { renderDisplayValue } from "./TextColumn";
6
7
 
@@ -25,7 +26,7 @@ function ReferenceColumnCell({
25
26
  optionLabel,
26
27
  optionValue,
27
28
  );
28
- const raw = record[source];
29
+ const raw = getFormValue(record, source);
29
30
  if (typeof display === "function") return <>{display(record)}</>;
30
31
  if (display && display !== source) {
31
32
  const nested = renderDisplayValue(record, source, display);
@@ -1,6 +1,7 @@
1
1
  import { useMemo } from "react";
2
2
  import type { BaseSourceProps, DisplayProps, ReferenceProps } from "../types";
3
3
  import { useRegisterColumn } from "../context/ListContext";
4
+ import { getFormValue } from "../utils/getFormValue";
4
5
  import { useChoices } from "../utils/useChoices";
5
6
 
6
7
  export type ReferenceManyColumnProps = BaseSourceProps &
@@ -23,7 +24,7 @@ function ReferenceManyColumnCell({
23
24
  optionLabel,
24
25
  optionValue,
25
26
  );
26
- const raw = record[source];
27
+ const raw = getFormValue(record, source);
27
28
  const values = Array.isArray(raw) ? raw : [];
28
29
  return <>{labelsForValues(values)}</>;
29
30
  }
@@ -1,5 +1,6 @@
1
1
  import { useMemo } from "react";
2
2
  import type { BaseSourceProps } from "../types";
3
+ import { columnDataIndex } from "../utils/columnDataIndex";
3
4
  import { getFormValue } from "../utils/getFormValue";
4
5
  import { useRegisterColumn } from "../context/ListContext";
5
6
 
@@ -16,7 +17,7 @@ export function TextColumn({ source, label, sortable = true }: TextColumnProps)
16
17
  sortable,
17
18
  buildColumn: () => ({
18
19
  title: label ?? source,
19
- dataIndex: source,
20
+ dataIndex: columnDataIndex(source),
20
21
  key: source,
21
22
  sorter: sortable ? true : undefined,
22
23
  }),
@@ -34,5 +35,5 @@ export function renderDisplayValue(
34
35
  ): unknown {
35
36
  if (typeof display === "function") return display(record);
36
37
  if (display) return getFormValue(record, display);
37
- return record[source];
38
+ return getFormValue(record, source);
38
39
  }
@@ -1,8 +1,8 @@
1
1
  import { Switch } from "antd";
2
- import type { BaseSourceProps, FieldRules } from "../types";
2
+ import type { FieldSourceProps, FieldRules } from "../types";
3
3
  import { FieldWrapper } from "./FieldWrapper";
4
4
 
5
- export type BooleanFieldProps = BaseSourceProps & {
5
+ export type BooleanFieldProps = FieldSourceProps & {
6
6
  name?: string;
7
7
  required?: boolean;
8
8
  rules?: FieldRules;
@@ -17,6 +17,7 @@ export function BooleanField({
17
17
  required,
18
18
  rules,
19
19
  hideLabel,
20
+ hidden,
20
21
  disabled: disabledProp,
21
22
  }: BooleanFieldProps) {
22
23
  return (
@@ -27,6 +28,7 @@ export function BooleanField({
27
28
  required={required}
28
29
  rules={rules}
29
30
  hideLabel={hideLabel}
31
+ hidden={hidden}
30
32
  >
31
33
  {({ value, onChange, disabled }) => (
32
34
  <Switch
@@ -1,5 +1,5 @@
1
1
  import { DatePicker } from "antd";
2
- import type { BaseSourceProps, FieldRules } from "../types";
2
+ import type { FieldSourceProps, FieldRules } from "../types";
3
3
  import { parseDayjsValue } from "../utils/parseDayjsValue";
4
4
  import { FieldWrapper } from "./FieldWrapper";
5
5
 
@@ -7,7 +7,7 @@ const DATE_FORMAT = "YYYY-MM-DD";
7
7
  const DATE_TIME_FORMAT = `${DATE_FORMAT} HH:mm:ss`;
8
8
  const PARSE_FORMATS = [DATE_FORMAT, DATE_TIME_FORMAT, "YYYY-MM-DDTHH:mm:ss", "YYYY-MM-DDTHH:mm:ssZ"];
9
9
 
10
- export type DateFieldProps = BaseSourceProps & {
10
+ export type DateFieldProps = FieldSourceProps & {
11
11
  name?: string;
12
12
  required?: boolean;
13
13
  rules?: FieldRules;
@@ -23,6 +23,7 @@ export function DateField({
23
23
  rules,
24
24
  showTime,
25
25
  hideLabel,
26
+ hidden,
26
27
  }: DateFieldProps) {
27
28
  return (
28
29
  <FieldWrapper
@@ -32,6 +33,7 @@ export function DateField({
32
33
  required={required}
33
34
  rules={rules}
34
35
  hideLabel={hideLabel}
36
+ hidden={hidden}
35
37
  >
36
38
  {({ value, onChange, onBlur, disabled }) => (
37
39
  <DatePicker
@@ -7,6 +7,8 @@ import {
7
7
  useRegisterPayloadField,
8
8
  useRegisterSectionField,
9
9
  } from "../context/PayloadFieldsContext";
10
+ import { shouldRegisterSourceInPayload } from "../utils/shouldRegisterSourceInPayload";
11
+ import { isSourceHidden, useHiddenSources } from "../HiddenSources";
10
12
 
11
13
  export type FieldWrapperProps = {
12
14
  /** Logical field name — used for submit payload tracking on top-level fields. */
@@ -18,6 +20,8 @@ export type FieldWrapperProps = {
18
20
  rules?: FieldRules;
19
21
  /** Tabular inline cells: column header replaces the label. */
20
22
  hideLabel?: boolean;
23
+ /** Hide the control but keep the value in the form and save payload. */
24
+ hidden?: boolean;
21
25
  children: (props: {
22
26
  value: unknown;
23
27
  onChange: (value: unknown) => void;
@@ -34,10 +38,12 @@ export function FieldWrapper({
34
38
  required,
35
39
  rules,
36
40
  hideLabel,
41
+ hidden,
37
42
  children,
38
43
  }: FieldWrapperProps) {
39
44
  const fieldName = name ?? source;
40
- const isTopLevel = !fieldName.includes(".");
45
+ const registerSource = shouldRegisterSourceInPayload(source, name);
46
+ const isHidden = isSourceHidden(source, hidden, useHiddenSources());
41
47
 
42
48
  // react-hook-form: connect this field to the form from <ResourceForm>'s FormProvider.
43
49
  // `control` is passed to <Controller> below so value, onChange, and validation work.
@@ -49,13 +55,20 @@ export function FieldWrapper({
49
55
  const fieldLabel = hideLabel ? undefined : (label ?? source);
50
56
  const requiredMessage = label ?? source;
51
57
 
52
- // Add this field's `source` to the Save payload (ResourceForm → buildFormPayload).
53
- // `isTopLevel` is false when `name` contains "." (e.g. inline cell `__inline_lines.0.label`) —
54
- // those values live in the inline array and are saved by saveInlineRows, not the parent PATCH.
55
- useRegisterPayloadField(source, isTopLevel);
58
+ // Nested parent fields (`source="address.city"`) register; inline cells
59
+ // (`name="lines.0.label"`, `source="label"`) do not those go through the inline array.
60
+ useRegisterPayloadField(source, registerSource);
61
+ useRegisterSectionField(source, registerSource);
56
62
 
57
- // Same top-level check: attach this field to the current FormTab / FormStep for error highlighting.
58
- useRegisterSectionField(source, isTopLevel);
63
+ if (isHidden) {
64
+ return (
65
+ <Controller
66
+ name={fieldName}
67
+ control={control}
68
+ render={() => <></>}
69
+ />
70
+ );
71
+ }
59
72
 
60
73
  return (
61
74
  <Controller
@@ -1,7 +1,7 @@
1
1
  import { DeleteOutlined, PaperClipOutlined, UploadOutlined } from "@ant-design/icons";
2
2
  import { Button, Space, Typography } from "antd";
3
3
  import { useRef } from "react";
4
- import type { BaseSourceProps, FieldRules } from "../types";
4
+ import type { FieldSourceProps, FieldRules } from "../types";
5
5
  import { FieldWrapper } from "./FieldWrapper";
6
6
  import {
7
7
  getUploadFileName,
@@ -9,7 +9,7 @@ import {
9
9
  type UploadFieldValue,
10
10
  } from "./uploadFieldUtils";
11
11
 
12
- export type FileFieldProps = BaseSourceProps & {
12
+ export type FileFieldProps = FieldSourceProps & {
13
13
  name?: string;
14
14
  required?: boolean;
15
15
  rules?: FieldRules;
@@ -97,6 +97,7 @@ export function FileField({
97
97
  required,
98
98
  rules,
99
99
  hideLabel,
100
+ hidden,
100
101
  clearable,
101
102
  accept,
102
103
  }: FileFieldProps) {
@@ -108,6 +109,7 @@ export function FileField({
108
109
  required={required}
109
110
  rules={rules}
110
111
  hideLabel={hideLabel}
112
+ hidden={hidden}
111
113
  >
112
114
  {({ value, onChange, disabled }) => (
113
115
  <FileFieldInput
@@ -1,12 +1,12 @@
1
1
  import { DeleteOutlined, UploadOutlined } from "@ant-design/icons";
2
2
  import { Button, Image, Space } from "antd";
3
3
  import { useRef } from "react";
4
- import type { BaseSourceProps, FieldRules } from "../types";
4
+ import type { FieldSourceProps, FieldRules } from "../types";
5
5
  import { FieldWrapper } from "./FieldWrapper";
6
6
  import { hasUploadValue, type UploadFieldValue } from "./uploadFieldUtils";
7
7
  import { useUploadPreviewUrl } from "./useUploadPreviewUrl";
8
8
 
9
- export type ImageFieldProps = BaseSourceProps & {
9
+ export type ImageFieldProps = FieldSourceProps & {
10
10
  name?: string;
11
11
  required?: boolean;
12
12
  rules?: FieldRules;
@@ -92,6 +92,7 @@ export function ImageField({
92
92
  required,
93
93
  rules,
94
94
  hideLabel,
95
+ hidden,
95
96
  clearable,
96
97
  accept,
97
98
  previewWidth,
@@ -104,6 +105,7 @@ export function ImageField({
104
105
  required={required}
105
106
  rules={rules}
106
107
  hideLabel={hideLabel}
108
+ hidden={hidden}
107
109
  >
108
110
  {({ value, onChange, disabled }) => (
109
111
  <ImageFieldInput
@@ -1,9 +1,9 @@
1
1
  import { InputNumber } from "antd";
2
2
  import type { CSSProperties } from "react";
3
- import type { BaseSourceProps, FieldRules } from "../types";
3
+ import type { FieldSourceProps, FieldRules } from "../types";
4
4
  import { FieldWrapper } from "./FieldWrapper";
5
5
 
6
- export type NumberFieldProps = BaseSourceProps & {
6
+ export type NumberFieldProps = FieldSourceProps & {
7
7
  name?: string;
8
8
  required?: boolean;
9
9
  rules?: FieldRules;
@@ -25,6 +25,7 @@ export function NumberField({
25
25
  step,
26
26
  inputStyle,
27
27
  hideLabel,
28
+ hidden,
28
29
  }: NumberFieldProps) {
29
30
  return (
30
31
  <FieldWrapper
@@ -34,6 +35,7 @@ export function NumberField({
34
35
  required={required}
35
36
  rules={rules}
36
37
  hideLabel={hideLabel}
38
+ hidden={hidden}
37
39
  >
38
40
  {({ value, onChange, onBlur, disabled }) => (
39
41
  <InputNumber
@@ -1,9 +1,9 @@
1
1
  import { Input } from "antd";
2
2
  import { useWatch } from "react-hook-form";
3
- import type { BaseSourceProps, FieldRules } from "../types";
3
+ import type { FieldSourceProps, FieldRules } from "../types";
4
4
  import { FieldWrapper } from "./FieldWrapper";
5
5
 
6
- export type PasswordFieldProps = BaseSourceProps & {
6
+ export type PasswordFieldProps = FieldSourceProps & {
7
7
  name?: string;
8
8
  required?: boolean;
9
9
  rules?: FieldRules;
@@ -22,6 +22,7 @@ function PasswordInputField({
22
22
  rules,
23
23
  autoComplete,
24
24
  hideLabel,
25
+ hidden,
25
26
  }: PasswordFieldProps) {
26
27
  return (
27
28
  <FieldWrapper
@@ -31,6 +32,7 @@ function PasswordInputField({
31
32
  required={required}
32
33
  rules={rules}
33
34
  hideLabel={hideLabel}
35
+ hidden={hidden}
34
36
  >
35
37
  {({ value, onChange, onBlur, disabled }) => (
36
38
  <Input.Password
@@ -55,6 +57,7 @@ export function PasswordField({
55
57
  confirmLabel = "Confirm password",
56
58
  autoComplete = "new-password",
57
59
  hideLabel,
60
+ hidden,
58
61
  }: PasswordFieldProps) {
59
62
  const password = useWatch({ name: name ?? source, disabled: !confirmSource });
60
63
 
@@ -68,6 +71,7 @@ export function PasswordField({
68
71
  rules={rules}
69
72
  autoComplete={autoComplete}
70
73
  hideLabel={hideLabel}
74
+ hidden={hidden}
71
75
  />
72
76
  );
73
77
  }
@@ -82,6 +86,7 @@ export function PasswordField({
82
86
  rules={rules}
83
87
  autoComplete={autoComplete}
84
88
  hideLabel={hideLabel}
89
+ hidden={hidden}
85
90
  />
86
91
  <PasswordInputField
87
92
  source={confirmSource}
@@ -93,6 +98,7 @@ export function PasswordField({
93
98
  validate: (value: string) =>
94
99
  !password || value === password || "Passwords do not match",
95
100
  }}
101
+ hidden={hidden}
96
102
  />
97
103
  </>
98
104
  );
@@ -3,7 +3,7 @@ import type { CSSProperties } from "react";
3
3
  import { useMemo, useState } from "react";
4
4
  import { useWatch } from "react-hook-form";
5
5
  import type {
6
- BaseSourceProps,
6
+ FieldSourceProps,
7
7
  ChoiceOption,
8
8
  FieldRules,
9
9
  ReferenceProps,
@@ -21,7 +21,7 @@ import { ReferenceInputActions } from "./ReferenceInputActions";
21
21
  import type { ResourcePermissions } from "../../permissions/resourcePermissions";
22
22
  import type { ReactNode } from "react";
23
23
 
24
- export type ReferenceFieldProps = BaseSourceProps &
24
+ export type ReferenceFieldProps = FieldSourceProps &
25
25
  ReferenceProps & {
26
26
  name?: string;
27
27
  required?: boolean;
@@ -142,8 +142,10 @@ function ReferenceFieldSelect({
142
142
  {...referenceSelectDropdownProps({ popupMatchSelectWidth, popupMinWidth })}
143
143
  value={referenceSelectDisplayValue(selectedLoading, selectValue, undefined)}
144
144
  onChange={(next) => {
145
- onChange(next);
146
- onValueChange?.(next, optionForValue(next), { name: fieldName });
145
+ // Ant Design clear emits undefined; RHF Controller ignores that.
146
+ const value = next ?? null;
147
+ onChange(value);
148
+ onValueChange?.(value, optionForValue(next), { name: fieldName });
147
149
  }}
148
150
  options={selectOptions}
149
151
  loading={selectState.loading}
@@ -197,6 +199,7 @@ export function ReferenceField({
197
199
  allowClear,
198
200
  disabled: disabledProp,
199
201
  hideLabel,
202
+ hidden,
200
203
  inputStyle,
201
204
  onValueChange,
202
205
  lazy = true,
@@ -224,6 +227,7 @@ export function ReferenceField({
224
227
  required={required}
225
228
  rules={rules}
226
229
  hideLabel={hideLabel}
230
+ hidden={hidden}
227
231
  >
228
232
  {({ value, onChange, disabled, name: fieldName }) => (
229
233
  <ReferenceFieldSelect
@@ -1,7 +1,7 @@
1
1
  import { Select } from "antd";
2
2
  import { useMemo, useState } from "react";
3
3
  import { useWatch } from "react-hook-form";
4
- import type { BaseSourceProps, FieldRules, ReferenceProps } from "../types";
4
+ import type { FieldSourceProps, FieldRules, ReferenceProps } from "../types";
5
5
  import { valuesAsIds } from "../utils/choiceSelectionUtils";
6
6
  import { referenceSelectDropdownProps } from "../utils/referenceSelectDropdownProps";
7
7
  import { referenceSelectNotFoundContent } from "../utils/referenceSelectNotFoundContent";
@@ -15,7 +15,7 @@ import { ReferenceInputActions } from "./ReferenceInputActions";
15
15
  import type { ResourcePermissions } from "../../permissions/resourcePermissions";
16
16
  import type { ReactNode } from "react";
17
17
 
18
- export type ReferenceManyFieldProps = BaseSourceProps &
18
+ export type ReferenceManyFieldProps = FieldSourceProps &
19
19
  ReferenceProps & {
20
20
  name?: string;
21
21
  required?: boolean;
@@ -106,7 +106,7 @@ function ReferenceManyFieldSelect({
106
106
  {...referenceSelectDropdownProps({ popupMatchSelectWidth, popupMinWidth })}
107
107
  mode="multiple"
108
108
  value={referenceSelectDisplayValue(selectedLoading, selectValue, [])}
109
- onChange={onChange}
109
+ onChange={(next) => onChange(next ?? [])}
110
110
  options={selectOptions}
111
111
  loading={selectState.loading}
112
112
  notFoundContent={referenceSelectNotFoundContent(selectState.loading)}
@@ -165,6 +165,7 @@ export function ReferenceManyField({
165
165
  search,
166
166
  allowClear = true,
167
167
  hideLabel,
168
+ hidden,
168
169
  disabled: disabledProp,
169
170
  lazy = true,
170
171
  recordSource,
@@ -191,6 +192,7 @@ export function ReferenceManyField({
191
192
  required={required}
192
193
  rules={rules}
193
194
  hideLabel={hideLabel}
195
+ hidden={hidden}
194
196
  >
195
197
  {({ value, onChange, disabled }) => (
196
198
  <ReferenceManyFieldSelect
@@ -1,8 +1,8 @@
1
1
  import { Select } from "antd";
2
- import type { BaseSourceProps, ChoiceOption, FieldRules } from "../types";
2
+ import type { FieldSourceProps, ChoiceOption, FieldRules } from "../types";
3
3
  import { FieldWrapper } from "./FieldWrapper";
4
4
 
5
- export type SelectFieldProps = BaseSourceProps & {
5
+ export type SelectFieldProps = FieldSourceProps & {
6
6
  name?: string;
7
7
  required?: boolean;
8
8
  rules?: FieldRules;
@@ -22,6 +22,7 @@ export function SelectField({
22
22
  mode,
23
23
  allowClear,
24
24
  hideLabel,
25
+ hidden,
25
26
  }: SelectFieldProps) {
26
27
  return (
27
28
  <FieldWrapper
@@ -31,11 +32,12 @@ export function SelectField({
31
32
  required={required}
32
33
  rules={rules}
33
34
  hideLabel={hideLabel}
35
+ hidden={hidden}
34
36
  >
35
37
  {({ value, onChange, disabled }) => (
36
38
  <Select
37
39
  value={value as string | number | (string | number)[] | undefined}
38
- onChange={onChange}
40
+ onChange={(next) => onChange(next ?? null)}
39
41
  options={choices}
40
42
  mode={mode}
41
43
  allowClear={allowClear}
@@ -1,9 +1,9 @@
1
1
  import { Input } from "antd";
2
2
  import type { CSSProperties } from "react";
3
- import type { BaseSourceProps, FieldRules } from "../types";
3
+ import type { FieldSourceProps, FieldRules } from "../types";
4
4
  import { FieldWrapper } from "./FieldWrapper";
5
5
 
6
- export type TextAreaFieldProps = BaseSourceProps & {
6
+ export type TextAreaFieldProps = FieldSourceProps & {
7
7
  name?: string;
8
8
  required?: boolean;
9
9
  rules?: FieldRules;
@@ -25,6 +25,7 @@ export function TextAreaField({
25
25
  placeholder,
26
26
  inputStyle,
27
27
  hideLabel,
28
+ hidden,
28
29
  rows = 4,
29
30
  maxLength,
30
31
  showCount,
@@ -38,6 +39,7 @@ export function TextAreaField({
38
39
  required={required}
39
40
  rules={rules}
40
41
  hideLabel={hideLabel}
42
+ hidden={hidden}
41
43
  >
42
44
  {({ value, onChange, onBlur, disabled }) => (
43
45
  <Input.TextArea
@@ -1,9 +1,9 @@
1
1
  import { Input } from "antd";
2
2
  import type { CSSProperties } from "react";
3
- import type { BaseSourceProps, FieldRules } from "../types";
3
+ import type { FieldSourceProps, FieldRules } from "../types";
4
4
  import { FieldWrapper } from "./FieldWrapper";
5
5
 
6
- export type TextFieldProps = BaseSourceProps & {
6
+ export type TextFieldProps = FieldSourceProps & {
7
7
  name?: string;
8
8
  required?: boolean;
9
9
  rules?: FieldRules;
@@ -21,6 +21,7 @@ export function TextField({
21
21
  placeholder,
22
22
  inputStyle,
23
23
  hideLabel,
24
+ hidden,
24
25
  }: TextFieldProps) {
25
26
  return (
26
27
  <FieldWrapper
@@ -30,6 +31,7 @@ export function TextField({
30
31
  required={required}
31
32
  rules={rules}
32
33
  hideLabel={hideLabel}
34
+ hidden={hidden}
33
35
  >
34
36
  {({ value, onChange, onBlur, disabled }) => (
35
37
  <Input
@@ -1,12 +1,12 @@
1
1
  import { TimePicker } from "antd";
2
- import type { BaseSourceProps, FieldRules } from "../types";
2
+ import type { FieldSourceProps, FieldRules } from "../types";
3
3
  import { parseDayjsValue } from "../utils/parseDayjsValue";
4
4
  import { FieldWrapper } from "./FieldWrapper";
5
5
 
6
6
  const DEFAULT_TIME_FORMAT = "HH:mm:ss";
7
7
  const PARSE_FORMATS = [DEFAULT_TIME_FORMAT, "HH:mm", "H:mm:ss", "H:mm"];
8
8
 
9
- export type TimeFieldProps = BaseSourceProps & {
9
+ export type TimeFieldProps = FieldSourceProps & {
10
10
  name?: string;
11
11
  required?: boolean;
12
12
  rules?: FieldRules;
@@ -22,6 +22,7 @@ export function TimeField({
22
22
  required,
23
23
  rules,
24
24
  hideLabel,
25
+ hidden,
25
26
  format = DEFAULT_TIME_FORMAT,
26
27
  }: TimeFieldProps) {
27
28
  return (
@@ -32,6 +33,7 @@ export function TimeField({
32
33
  required={required}
33
34
  rules={rules}
34
35
  hideLabel={hideLabel}
36
+ hidden={hidden}
35
37
  >
36
38
  {({ value, onChange, onBlur, disabled }) => (
37
39
  <TimePicker
package/src/crud/index.ts CHANGED
@@ -5,6 +5,7 @@ export { ResourceForm } from "./ResourceForm";
5
5
  export type { ResourceFormProps } from "./ResourceForm";
6
6
  export { ResourceFormModal } from "./ResourceFormModal";
7
7
  export type { ResourceFormModalProps } from "./ResourceFormModal";
8
+ export { HiddenSources } from "./HiddenSources";
8
9
  export { InlineFormSet, InlineFormSetStacked } from "./InlineFormSet";
9
10
  export type {
10
11
  InlineFormSetProps,
@@ -75,6 +76,7 @@ export { getFormValue } from "./utils/getFormValue";
75
76
  export { setFormValue } from "./utils/setFormValue";
76
77
  export { buildFormPayload } from "./utils/buildFormPayload";
77
78
  export { buildInlineRowsPayload } from "./utils/buildInlineRowsPayload";
79
+ export { columnDataIndex } from "./utils/columnDataIndex";
78
80
  export { buildResourceFormSubmitBody } from "./utils/buildResourceFormSubmitBody";
79
81
  export { prepareFormSubmitBody } from "./utils/prepareFormSubmitBody";
80
82
  export { toFormData } from "./utils/toFormData";
@@ -90,6 +92,7 @@ export type { InlineFieldRegistration } from "./context/InlineFieldsRegistry";
90
92
 
91
93
  export type {
92
94
  BaseSourceProps,
95
+ FieldSourceProps,
93
96
  ChoiceOption,
94
97
  ChoicesLoader,
95
98
  ReferenceProps,
package/src/crud/types.ts CHANGED
@@ -8,6 +8,12 @@ export type BaseSourceProps = {
8
8
  label?: string;
9
9
  };
10
10
 
11
+ /** Form fields only — columns and filters do not hide-and-keep a value. */
12
+ export type FieldSourceProps = BaseSourceProps & {
13
+ /** Hide the control but keep the value in the form and save payload. */
14
+ hidden?: boolean;
15
+ };
16
+
11
17
  export type ChoiceOption = {
12
18
  label: string;
13
19
  value: unknown;