Skip to content

Commit 2d15362

Browse files
committed
DataViews now accepts a empty ReactNode for free customization
1 parent e55e11a commit 2d15362

File tree

14 files changed

+40
-211
lines changed

14 files changed

+40
-211
lines changed

packages/dataviews/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
### Features
1010

11-
- Add `empty` prop to `DataViews` to customize the empty state message.
11+
- `DataViews` empty state can be customized using the new `empty` prop.
1212

1313
### Bug Fixes
1414

packages/dataviews/README.md

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -421,27 +421,9 @@ A list of numbers used to control the available item counts per page.
421421
422422
It's optional. Defaults to `[10, 20, 50, 100]`.
423423
424-
#### `empty`: `Object`
424+
#### `empty`: React node
425425
426-
The empty object configures what should be shown when the `data` is empty.
427-
428-
Example:
429-
430-
```js
431-
const empty = {
432-
heading: 'No pages found',
433-
description: 'Your search did not match any pages.',
434-
illustration: 'https://example.com/illustration.svg',
435-
actions: <Button>Create a new page</Button>,
436-
};
437-
```
438-
439-
Properties:
440-
441-
- `heading`: short message describing the empty state. If this is the only property provided then the empty state will render as plain text without any additional styling.
442-
- `description`: a longer description of the empty state, providing more context or instructions.
443-
- `illustration`: either a URL to an image or a React component that renders an illustration. This should be purely illustrative as it does not render with any alt text.
444-
- `actions`: a `<Button>` (or list of `<Button>`s rendered in a fragment) which provide the user with next steps.
426+
A message or element to be displayed instead of the dataview's default empty message.
445427
446428
### Composition modes
447429
@@ -473,7 +455,6 @@ The following components are available directly under `DataViews`:
473455
- `DataViews.Pagination`
474456
- `DataViews.BulkActionToolbar`
475457
- `DataViews.ViewConfig`
476-
- `DataViews.Empty`
477458
478459
#### example
479460

packages/dataviews/src/components/dataviews-context/index.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
/**
22
* External dependencies
33
*/
4-
import type { ComponentProps, ReactElement } from 'react';
4+
import type { ComponentProps, ReactElement, ReactNode } from 'react';
55

66
/**
77
* WordPress dependencies
88
*/
99
import { createContext, createRef } from '@wordpress/element';
10-
import { __ } from '@wordpress/i18n';
1110

1211
/**
1312
* Internal dependencies
@@ -18,7 +17,6 @@ import type {
1817
NormalizedField,
1918
SupportedLayouts,
2019
NormalizedFilter,
21-
EmptyViewProps,
2220
} from '../../types';
2321
import type { SetSelection } from '../../private-types';
2422
import { LAYOUT_TABLE } from '../../constants';
@@ -57,11 +55,7 @@ type DataViewsContextType< Item > = {
5755
isShowingFilter: boolean;
5856
setIsShowingFilter: ( value: boolean ) => void;
5957
perPageSizes?: [ number, number, number, number ];
60-
empty: EmptyViewProps;
61-
};
62-
63-
export const DEFAULT_VIEW_EMPTY = {
64-
heading: __( 'No results' ),
58+
empty?: ReactNode;
6559
};
6660

6761
const DataViewsContext = createContext< DataViewsContextType< any > >( {
@@ -87,7 +81,6 @@ const DataViewsContext = createContext< DataViewsContextType< any > >( {
8781
filters: [],
8882
isShowingFilter: false,
8983
setIsShowingFilter: () => {},
90-
empty: DEFAULT_VIEW_EMPTY,
9184
} );
9285

9386
export default DataViewsContext;

packages/dataviews/src/components/dataviews-empty/index.tsx

Lines changed: 0 additions & 60 deletions
This file was deleted.

packages/dataviews/src/components/dataviews-empty/style.scss

Lines changed: 0 additions & 23 deletions
This file was deleted.

packages/dataviews/src/components/dataviews-layout/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type { ComponentType } from 'react';
77
* WordPress dependencies
88
*/
99
import { useContext } from '@wordpress/element';
10+
import { __ } from '@wordpress/i18n';
1011

1112
/**
1213
* Internal dependencies
@@ -35,6 +36,7 @@ export default function DataViewsLayout( { className }: DataViewsLayoutProps ) {
3536
onClickItem,
3637
isItemClickable,
3738
renderItemLink,
39+
empty = __( 'No results' ),
3840
} = useContext( DataViewsContext );
3941

4042
const ViewComponent = VIEW_LAYOUTS.find( ( v ) => v.type === view.type )
@@ -57,6 +59,7 @@ export default function DataViewsLayout( { className }: DataViewsLayoutProps ) {
5759
renderItemLink={ renderItemLink }
5860
isItemClickable={ isItemClickable }
5961
view={ view }
62+
empty={ empty }
6063
/>
6164
);
6265
}

packages/dataviews/src/components/dataviews/index.tsx

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { useResizeObserver } from '@wordpress/compose';
1313
/**
1414
* Internal dependencies
1515
*/
16-
import DataViewsContext, { DEFAULT_VIEW_EMPTY } from '../dataviews-context';
16+
import DataViewsContext from '../dataviews-context';
1717
import {
1818
default as DataViewsFilters,
1919
useFilters,
@@ -23,20 +23,13 @@ import DataViewsLayout from '../dataviews-layout';
2323
import DataViewsFooter from '../dataviews-footer';
2424
import DataViewsSearch from '../dataviews-search';
2525
import { BulkActionsFooter } from '../dataviews-bulk-actions';
26-
import { DataViewsEmpty } from '../dataviews-empty';
2726
import { DataViewsPagination } from '../dataviews-pagination';
2827
import DataViewsViewConfig, {
2928
DataviewsViewConfigDropdown,
3029
ViewTypeMenu,
3130
} from '../dataviews-view-config';
3231
import { normalizeFields } from '../../normalize-fields';
33-
import type {
34-
Action,
35-
Field,
36-
View,
37-
SupportedLayouts,
38-
EmptyViewProps,
39-
} from '../../types';
32+
import type { Action, Field, View, SupportedLayouts } from '../../types';
4033
import type { SelectionOrUpdater } from '../../private-types';
4134
type ItemWithId = { id: string };
4235

@@ -67,7 +60,7 @@ type DataViewsProps< Item > = {
6760
getItemLevel?: ( item: Item ) => number;
6861
children?: ReactNode;
6962
perPageSizes?: [ number, number, number, number ];
70-
empty?: EmptyViewProps;
63+
empty?: ReactNode;
7164
} & ( Item extends ItemWithId
7265
? { getItemId?: ( item: Item ) => string }
7366
: { getItemId: ( item: Item ) => string } );
@@ -208,7 +201,7 @@ function DataViews< Item >( {
208201
isShowingFilter,
209202
setIsShowingFilter,
210203
perPageSizes,
211-
empty: empty ?? DEFAULT_VIEW_EMPTY,
204+
empty,
212205
} }
213206
>
214207
<div className="dataviews-wrapper" ref={ containerRef }>
@@ -234,7 +227,6 @@ const DataViewsSubComponents = DataViews as typeof DataViews & {
234227
Pagination: typeof DataViewsPagination;
235228
Search: typeof DataViewsSearch;
236229
ViewConfig: typeof DataviewsViewConfigDropdown;
237-
Empty: typeof DataViewsEmpty;
238230
};
239231

240232
DataViewsSubComponents.BulkActionToolbar = BulkActionsFooter;
@@ -245,6 +237,5 @@ DataViewsSubComponents.LayoutSwitcher = ViewTypeMenu;
245237
DataViewsSubComponents.Pagination = DataViewsPagination;
246238
DataViewsSubComponents.Search = DataViewsSearch;
247239
DataViewsSubComponents.ViewConfig = DataviewsViewConfigDropdown;
248-
DataViewsSubComponents.Empty = DataViewsEmpty;
249240

250241
export default DataViewsSubComponents;

packages/dataviews/src/components/dataviews/stories/index.story.tsx

Lines changed: 14 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -127,32 +127,7 @@ export const CustomEmpty = () => {
127127
onChangeView={ setView }
128128
actions={ actions }
129129
defaultLayouts={ defaultLayouts }
130-
empty={ {
131-
heading: view.search ? 'No sites found' : 'No sites',
132-
description: view.search
133-
? `Your search for “${ view.search }” did not match any sites. Try searching by the site title or domain name.`
134-
: 'Get started by creating a new site.',
135-
illustration:
136-
'https://pd.w.org/2025/05/9376819135a616da1.38400720-768x432.jpeg',
137-
actions: (
138-
<>
139-
{ view.search && (
140-
<Button
141-
variant="secondary"
142-
onClick={ () => {
143-
setView( ( oldView ) => ( {
144-
...oldView,
145-
search: '',
146-
} ) );
147-
} }
148-
>
149-
Clear search
150-
</Button>
151-
) }
152-
<Button variant="primary">Add new site</Button>
153-
</>
154-
),
155-
} }
130+
empty={ view.search ? 'No sites found' : 'No sites' }
156131
/>
157132
);
158133
};
@@ -258,16 +233,7 @@ function PlanetOverview( { planets }: { planets: SpaceObject[] } ) {
258233
</VStack>
259234
</Grid>
260235

261-
{ planets.length > 0 ? (
262-
<DataViews.Layout className="free-composition-dataviews-layout" />
263-
) : (
264-
<HStack
265-
justify="space-around"
266-
className="free-composition-dataviews-empty"
267-
>
268-
<DataViews.Empty />
269-
</HStack>
270-
) }
236+
<DataViews.Layout className="free-composition-dataviews-layout" />
271237
</>
272238
);
273239
}
@@ -317,13 +283,19 @@ export const FreeComposition = () => {
317283
table: {},
318284
grid: {},
319285
} }
320-
empty={ {
321-
heading: 'No plants',
322-
description: `Try a different search because “${ view.search }” returned no results.`,
323-
actions: (
286+
empty={
287+
<VStack
288+
justify="space-around"
289+
alignment="center"
290+
className="free-composition-dataviews-empty"
291+
>
292+
<Text size={ 18 } as="p">
293+
No planets
294+
</Text>
295+
<Text variant="muted">{ `Try a different search because “${ view.search }” returned no results.` }</Text>
324296
<Button variant="secondary">Create new planet</Button>
325-
),
326-
} }
297+
</VStack>
298+
}
327299
>
328300
<PlanetOverview planets={ planets } />
329301
</DataViews>

packages/dataviews/src/components/dataviews/stories/style.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
inset-block-start: 67px;
2525
}
2626

27-
.free-composition-dataviews-empty > * {
27+
.free-composition-dataviews-empty {
2828
border: 1px solid #000;
2929
border-radius: 8px;
3030
padding: 24px;

packages/dataviews/src/dataviews-layouts/grid/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ import type {
3939
} from '../../types';
4040
import type { SetSelection } from '../../private-types';
4141
import { ItemClickWrapper } from '../utils/item-click-wrapper';
42-
import { DataViewsEmpty } from '../../components/dataviews-empty';
4342
const { Badge } = unlock( componentsPrivateApis );
4443

4544
interface GridItemProps< Item > {
@@ -264,6 +263,7 @@ function ViewGrid< Item >( {
264263
selection,
265264
view,
266265
className,
266+
empty,
267267
}: ViewGridProps< Item > ) {
268268
const { resizeObserverRef } = useContext( DataViewsContext );
269269
const titleField = fields.find(
@@ -447,7 +447,7 @@ function ViewGrid< Item >( {
447447
'dataviews-no-results': ! isLoading,
448448
} ) }
449449
>
450-
<p>{ isLoading ? <Spinner /> : <DataViewsEmpty /> }</p>
450+
<p>{ isLoading ? <Spinner /> : empty }</p>
451451
</div>
452452
)
453453
}

0 commit comments

Comments
 (0)