Skip to content

Commit 1970995

Browse files
committed
introduce TextArrayField and use it in ShowGuesser
1 parent 8d1c6a8 commit 1970995

File tree

7 files changed

+152
-2
lines changed

7 files changed

+152
-2
lines changed

packages/ra-ui-materialui/src/detail/ShowGuesser.spec.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ describe('<ShowGuesser />', () => {
1111
await screen.findByText('john doe');
1212
expect(logSpy).toHaveBeenCalledWith(`Guessed Show:
1313
14-
import { ArrayField, BooleanField, DataTable, DateField, EmailField, NumberField, ReferenceArrayField, ReferenceField, RichTextField, Show, SimpleShowLayout, TextField, UrlField } from 'react-admin';
14+
import { ArrayField, BooleanField, DataTable, DateField, EmailField, NumberField, ReferenceArrayField, ReferenceField, RichTextField, Show, SimpleShowLayout, TextArrayField, TextField, UrlField } from 'react-admin';
1515
1616
export const BookShow = () => (
1717
<Show>
@@ -39,6 +39,7 @@ export const BookShow = () => (
3939
<UrlField source="url" />
4040
<EmailField source="email" />
4141
<BooleanField source="isAlreadyPublished" />
42+
<TextArrayField source="genres" />
4243
</SimpleShowLayout>
4344
</Show>
4445
);`);

packages/ra-ui-materialui/src/detail/ShowGuesser.stories.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ published serially, then in its entirety in 1869.</p>
2626
url: 'https://www.myshop.com/tags/top-seller',
2727
2828
isAlreadyPublished: true,
29+
genres: [
30+
'Fiction',
31+
'Historical Fiction',
32+
'Classic Literature',
33+
'Russian Literature',
34+
],
2935
},
3036
],
3137
tags: [

packages/ra-ui-materialui/src/detail/showFieldTypes.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import * as React from 'react';
22
import { ReactNode } from 'react';
3-
import type { InferredElement, InferredTypeMap, InputProps } from 'ra-core';
3+
import {
4+
type InferredElement,
5+
type InferredTypeMap,
6+
type InputProps,
7+
} from 'ra-core';
48
import {
59
ArrayField,
610
BooleanField,
@@ -15,6 +19,7 @@ import {
1519
TextField,
1620
UrlField,
1721
ChipField,
22+
TextArrayField,
1823
} from '../field';
1924
import { SimpleShowLayout, SimpleShowLayoutProps } from './SimpleShowLayout';
2025
import { DataTable, SingleFieldList } from '../list';
@@ -55,6 +60,11 @@ ${children.map(child => ` ${child.getRepresentation()}`).join('\n')}
5560
</DataTable>
5661
</ArrayField>`,
5762
},
63+
scalar_array: {
64+
component: TextArrayField,
65+
representation: (props: InputProps) =>
66+
`<TextArrayField source="${props.source}" />`,
67+
},
5868
boolean: {
5969
component: BooleanField,
6070
representation: (props: InputProps) =>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import * as React from 'react';
2+
import { render, screen } from '@testing-library/react';
3+
4+
import { Basic } from './TextArrayField.stories';
5+
6+
describe('<TextArrayField />', () => {
7+
it('should render the array values', async () => {
8+
render(<Basic />);
9+
await screen.findByText('Fiction');
10+
await screen.findByText('Historical Fiction');
11+
await screen.findByText('Classic Literature');
12+
await screen.findByText('Russian Literature');
13+
});
14+
});
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import * as React from 'react';
2+
import { TextArrayField } from './TextArrayField';
3+
4+
export default { title: 'ra-ui-materialui/fields/TextArrayField' };
5+
6+
const book = {
7+
id: 1,
8+
title: 'War and Peace',
9+
genres: [
10+
'Fiction',
11+
'Historical Fiction',
12+
'Classic Literature',
13+
'Russian Literature',
14+
],
15+
};
16+
17+
export const Basic = () => <TextArrayField record={book} source="genres" />;
18+
19+
export const EmptyText = () => (
20+
<TextArrayField
21+
record={{ genres: [] }}
22+
source="genres"
23+
emptyText="No genres available"
24+
/>
25+
);
26+
27+
export const Size = () => (
28+
<TextArrayField record={book} source="genres" size="medium" />
29+
);
30+
31+
export const Color = () => (
32+
<TextArrayField record={book} source="genres" color="secondary" />
33+
);
34+
35+
export const Variant = () => (
36+
<TextArrayField record={book} source="genres" variant="outlined" />
37+
);
38+
39+
export const Direction = () => (
40+
<TextArrayField
41+
record={book}
42+
source="genres"
43+
direction="column"
44+
alignItems="flex-start"
45+
/>
46+
);
47+
48+
export const Gap = () => (
49+
<TextArrayField record={book} source="genres" gap={2} />
50+
);
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { useFieldValue } from 'ra-core';
2+
import * as React from 'react';
3+
import { ReactNode } from 'react';
4+
5+
import { Chip, ChipProps, Stack, StackProps } from '@mui/material';
6+
import { FieldProps } from './types';
7+
8+
/**
9+
* Renders an array of scalar values using MUI Stack and Chips.
10+
*
11+
* @example
12+
* // const post = {
13+
* // id: 123
14+
* // genres: [
15+
* // 'Fiction',
16+
* // 'Historical Fiction',
17+
* // 'Classic Literature',
18+
* // 'Russian Literature',
19+
* // ]
20+
* // };
21+
* const PostShow = () => (
22+
* <Show>
23+
* <SimpleShowLayout>
24+
* <TextArrayField source="genres" />
25+
* </SimpleShowLayout>
26+
* </Show>
27+
* );
28+
*/
29+
export const TextArrayField = <
30+
RecordType extends Record<string, any> = Record<string, any>,
31+
>(
32+
props: TextArrayFieldProps<RecordType>
33+
) => {
34+
const {
35+
emptyText,
36+
source,
37+
record,
38+
resource,
39+
size = 'small',
40+
color,
41+
variant,
42+
...rest
43+
} = props;
44+
const data = useFieldValue(props) || emptyArray;
45+
return (
46+
<Stack direction="row" gap={1} {...rest}>
47+
{data.length === 0
48+
? emptyText
49+
: data.map((item: ReactNode, index: number) => (
50+
<Chip
51+
key={index}
52+
label={item}
53+
size={size}
54+
color={color}
55+
variant={variant}
56+
/>
57+
))}
58+
</Stack>
59+
);
60+
};
61+
62+
export interface TextArrayFieldProps<
63+
RecordType extends Record<string, any> = Record<string, any>,
64+
> extends FieldProps<RecordType>,
65+
Omit<StackProps, 'textAlign' | 'color'>,
66+
Pick<ChipProps, 'size' | 'color' | 'variant'> {}
67+
68+
const emptyArray = [];

packages/ra-ui-materialui/src/field/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export * from './ReferenceOneField';
1818
export * from './RichTextField';
1919
export * from './sanitizeFieldRestProps';
2020
export * from './SelectField';
21+
export * from './TextArrayField';
2122
export * from './TextField';
2223
export * from './TranslatableFields';
2324
export * from './TranslatableFieldsTab';

0 commit comments

Comments
 (0)