Skip to content

Commit 44b7cbf

Browse files
committed
rename emptyText to empty, remove defaultValue
1 parent 359493d commit 44b7cbf

File tree

4 files changed

+51
-99
lines changed

4 files changed

+51
-99
lines changed

docs/RecordField.md

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -77,19 +77,18 @@ The `source`, `field`, `children`, and `render` props are mutually exclusive.
7777

7878
## Props
7979

80-
| Prop | Required | Type | Default | Description |
81-
| ----------- | -------- | ------------------ | ------- | -------------------------------------------------------------------------------- |
82-
| `children` | Optional | ReactNode | '' | Elements rendering the actual field. |
83-
| `className` | Optional | string | '' | CSS class name to apply to the field. |
84-
| `defaultValue` | Optional | any | undefined | Default value to display when the field is empty. |
85-
| `emptyText` | Optional | string | '-' | Text to display when the field is empty. |
86-
| `field` | Optional | ReactElement | `TextField` | Field component used to render the field. Ignored if `children` or `render` are set. |
87-
| `label` | Optional | string | '' | Label to render. Can be a translation key. |
88-
| `render` | Optional | record => JSX | | Function to render the field value. Ignored if `children` is set. |
89-
| `source` | Optional | string | '' | Name of the record field to render. |
90-
| `sx` | Optional | object | {} | Styles to apply to the field. |
91-
| `TypographyProps` | Optional | object | {} | Props to pass to label wrapper |
92-
| `variant` | Optional | `'default' || 'inline'` | 'default' | When `inline`, the label is displayed inline with the field value. |
80+
| Prop | Required | Type | Default | Description |
81+
| ----------- | -------- | ----------------------- | ------- | -------------------------------------------------------------------------------- |
82+
| `children` | Optional | ReactNode | '' | Elements rendering the actual field. |
83+
| `className` | Optional | string | '' | CSS class name to apply to the field. |
84+
| `empty` | Optional | ReactNode | '' | Text to display when the field is empty. |
85+
| `field` | Optional | ReactElement | `TextField` | Field component used to render the field. Ignored if `children` or `render` are set. |
86+
| `label` | Optional | string | '' | Label to render. Can be a translation key. |
87+
| `render` | Optional | record => JSX | | Function to render the field value. Ignored if `children` is set. |
88+
| `source` | Optional | string | '' | Name of the record field to render. |
89+
| `sx` | Optional | object | {} | Styles to apply to the field. |
90+
| `TypographyProps` | Optional | object | {} | Props to pass to label wrapper |
91+
| `variant` | Optional | `'default' || 'inline'` | 'default' | When `inline`, the label is displayed inline with the field value. |
9392

9493
## `children`
9594

@@ -127,38 +126,38 @@ import { RecordField, NumberField } from 'react-admin';
127126
</RecordField>
128127
```
129128

130-
## `defaultValue`
129+
## `empty`
131130

132-
When the record contains no value for the `source` prop, `RecordField` renders an empty string. You can use the `defaultValue` prop to specify a default value to display instead.
131+
When the record contains no value for the `source` prop, `RecordField` renders an empty string. If you need to render a custom string in this case, you can use the `empty` prop :
133132

134133
```jsx
135-
<RecordField source="rating" defaultValue={0} />
134+
<RecordField source="title" empty="Missing title" />
136135
```
137136

138-
If you're using the `render` prop, the `defaultValue` will be passed to the `render` function as the second argument:
137+
`empty` also accepts a translation key, so you can have a localized string when the field is empty:
139138

140139
```jsx
141-
<RecordField
142-
label="Rating"
143-
defaultValue={0}
144-
render={(record, defaultValue) =>
145-
record.rating ? `${record.rating} stars` : defaultValue
146-
}
147-
/>
140+
<RecordField source="title" empty="resources.books.fields.title.missing" />
148141
```
149142

150-
**Tip**: If you need the default value to be translated, use the `emptyText` prop instead.
143+
If you use the `render` prop, you can even use a React element as `empty` value.
151144

152-
## `emptyText`
145+
```jsx
146+
<RecordField
147+
source="title"
148+
empty={<span style={{ color: 'red' }}>Missing title</span>}
149+
render={record => record.title}
150+
/>
151+
```
153152

154-
When the record contains no value for the `source` prop, `RecordField` renders an empty string. If you need to render a locale-specific string in this case, you can use the `emptyText` prop to specify a translation key:
153+
Note that `empty` is ignored when you pass a custom field component as child. In this case, it's the child's responsibility to handle the empty value.
155154

156155
```jsx
157-
<RecordField source="title" emptyText="resources.books.fields.title.missing" />
156+
<RecordField label="title">
157+
<TextField source="title" emptyText="Missing title" />
158+
</RecordField>
158159
```
159160

160-
**Tip**: If you don't need the default value to be translated, use the `defaultValue` prop instead.
161-
162161
## `field`
163162

164163
By default, `<RecordField>` uses the [`<TextField>`](./TextField.md) component to render the field value.

packages/ra-ui-materialui/src/field/RecordField.spec.tsx

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ import {
66
Basic,
77
Source,
88
Label,
9-
DefaultValue,
10-
EmptyText,
9+
Empty,
1110
Render,
1211
Field,
1312
Children,
@@ -45,31 +44,17 @@ describe('<RecordField />', () => {
4544
expect(screen.queryByText('Summary')).toBeNull();
4645
});
4746
});
48-
describe('defaultValue', () => {
49-
it('should render the defaultValue when the record is undefined', () => {
50-
render(<DefaultValue />);
51-
expect(screen.queryByText('N/A')).not.toBeNull();
52-
});
53-
it('should render the defaultValue when using a render prop', () => {
54-
render(<DefaultValue />);
55-
expect(screen.queryByText('Unknown')).not.toBeNull();
56-
});
57-
it('should render the defaultValue when using a field prop', () => {
58-
render(<DefaultValue />);
59-
expect(screen.queryByText('0')).not.toBeNull();
60-
});
61-
});
62-
describe('emptyText', () => {
63-
it('should render the translated emptyText when the record is undefined', () => {
64-
render(<EmptyText />);
47+
describe('empty', () => {
48+
it('should render the translated empty when the record is undefined', () => {
49+
render(<Empty />);
6550
expect(screen.queryByText('No title')).not.toBeNull();
6651
});
67-
it('should render the translated emptyText when using a render prop', () => {
68-
render(<EmptyText />);
52+
it('should render the translated empty when using a render prop', () => {
53+
render(<Empty />);
6954
expect(screen.queryByText('Unknown author')).not.toBeNull();
7055
});
71-
it('should render the translated emptyText when using a field prop', () => {
72-
render(<EmptyText />);
56+
it('should render the translated empty when using a field prop', () => {
57+
render(<Empty />);
7358
expect(screen.queryByText('0')).not.toBeNull();
7459
});
7560
});

packages/ra-ui-materialui/src/field/RecordField.stories.tsx

Lines changed: 5 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -59,35 +59,12 @@ export const Field = () => (
5959
</ResourceContext.Provider>
6060
);
6161

62-
export const DefaultValue = () => (
63-
<ResourceContext.Provider value="books">
64-
<RecordContextProvider value={{}}>
65-
<Stack>
66-
<RecordField source="title" defaultValue="N/A" />
67-
<RecordField
68-
source="author"
69-
defaultValue="Unknown"
70-
render={(record, defaultValue) =>
71-
record.author || defaultValue
72-
}
73-
/>
74-
<RecordField
75-
source="year"
76-
field={NumberField}
77-
defaultValue={0}
78-
/>
79-
</Stack>
80-
</RecordContextProvider>
81-
</ResourceContext.Provider>
82-
);
83-
8462
const translations = {
8563
'books.title.missing': 'No title',
86-
'books.author.missing': 'Unknown author',
8764
'books.year.missing': '0',
8865
};
8966

90-
export const EmptyText = () => (
67+
export const Empty = () => (
9168
<I18nContextProvider
9269
value={{
9370
getLocale: () => 'en',
@@ -98,21 +75,16 @@ export const EmptyText = () => (
9875
<ResourceContext.Provider value="books">
9976
<RecordContextProvider value={{}}>
10077
<Stack>
101-
<RecordField
102-
source="title"
103-
emptyText="books.title.missing"
104-
/>
78+
<RecordField source="title" empty="books.title.missing" />
10579
<RecordField
10680
source="author"
107-
emptyText="books.author.missing"
108-
render={(record, defaultValue) =>
109-
record.author || defaultValue
110-
}
81+
empty={<>Unknown author</>}
82+
render={record => record.author}
11183
/>
11284
<RecordField
11385
source="year"
11486
field={NumberField}
115-
emptyText="books.year.missing"
87+
empty="books.year.missing"
11688
/>
11789
</Stack>
11890
</RecordContextProvider>

packages/ra-ui-materialui/src/field/RecordField.tsx

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ export const RecordField = <
2626
>({
2727
children,
2828
className,
29-
defaultValue,
30-
emptyText,
29+
empty,
3130
field,
3231
label,
3332
render,
@@ -71,24 +70,22 @@ export const RecordField = <
7170
variant="body2"
7271
className={RecordFieldClasses.value}
7372
>
74-
{render(record, defaultValue) ||
75-
(emptyText
76-
? translate(emptyText, { _: emptyText })
77-
: null)}
73+
{render(record) ||
74+
(typeof empty === 'string'
75+
? translate(empty, { _: empty })
76+
: empty)}
7877
</Typography>
7978
)
8079
) : field ? (
8180
React.createElement(field, {
8281
source,
83-
defaultValue,
84-
emptyText,
82+
emptyText: empty as string,
8583
className: RecordFieldClasses.value,
8684
})
8785
) : source ? (
8886
<TextField
8987
source={source}
90-
defaultValue={defaultValue}
91-
emptyText={emptyText}
88+
emptyText={empty as string}
9289
resource={resource}
9390
className={RecordFieldClasses.value}
9491
/>
@@ -105,11 +102,10 @@ export interface RecordFieldProps<
105102
> extends StackProps {
106103
children?: ReactNode;
107104
className?: string;
108-
defaultValue?: any;
109-
emptyText?: string;
105+
empty?: ReactNode;
110106
field?: ElementType;
111107
label?: ReactNode;
112-
render?: (record: RecordType, defaultValue?: any) => React.ReactNode;
108+
render?: (record: RecordType) => React.ReactNode;
113109
source?: NoInfer<HintedString<ExtractRecordPaths<RecordType>>>;
114110
record?: RaRecord;
115111
sx?: SxProps;

0 commit comments

Comments
 (0)