Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/dataviews/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
- DataForm: Reduce panel's dialog min-width. [#76345](https://github.com/WordPress/gutenberg/pull/76345)
- DataViews: Add border to sticky table headers. [#76396](https://github.com/WordPress/gutenberg/pull/76396)

- DataViews: Update scrolling so the scrollbar appears on the active layout when DataViews is rendered in a constrained-height container. This may slightly change the UI depending on the container height. [#76453](https://github.com/WordPress/gutenberg/pull/76453)

### Bug Fixes

- DataViews: Fix last column classname in table layout. [#76133](https://github.com/WordPress/gutenberg/pull/76133)
Expand Down
39 changes: 21 additions & 18 deletions packages/dataviews/src/components/dataviews-layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export default function DataViewsLayout( { className }: DataViewsLayoutProps ) {
isItemClickable,
renderItemLink,
defaultLayouts,
containerRef,
empty = <p>{ __( 'No results' ) }</p>,
} = useContext( DataViewsContext );

Expand Down Expand Up @@ -69,23 +70,25 @@ export default function DataViewsLayout( { className }: DataViewsLayoutProps ) {
)?.component as ComponentType< ViewBaseProps< any > >;

return (
<ViewComponent
className={ className }
actions={ actions }
data={ data }
fields={ fields }
getItemId={ getItemId }
getItemLevel={ getItemLevel }
isLoading={ isLoading }
onChangeView={ onChangeView }
onChangeSelection={ onChangeSelection }
selection={ selection }
setOpenedFilter={ setOpenedFilter }
onClickItem={ onClickItem }
renderItemLink={ renderItemLink }
isItemClickable={ isItemClickable }
view={ view }
empty={ empty }
/>
<div className="dataviews-layout__container" ref={ containerRef }>
<ViewComponent
className={ className }
actions={ actions }
data={ data }
fields={ fields }
getItemId={ getItemId }
getItemLevel={ getItemLevel }
isLoading={ isLoading }
onChangeView={ onChangeView }
onChangeSelection={ onChangeSelection }
selection={ selection }
setOpenedFilter={ setOpenedFilter }
onClickItem={ onClickItem }
renderItemLink={ renderItemLink }
isItemClickable={ isItemClickable }
view={ view }
empty={ empty }
/>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.dataviews-layout__container {
flex: 1;
min-height: 0;
overflow: auto;
display: flex;
flex-direction: column;
background-color: inherit;
}
2 changes: 1 addition & 1 deletion packages/dataviews/src/dataviews-picker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ function DataViewsPicker< Item >( {
hasInfiniteScrollHandler: !! infiniteScrollHandler,
} }
>
<div className="dataviews-picker-wrapper" ref={ containerRef }>
<div className="dataviews-picker-wrapper">
{ children ?? (
<DefaultUI search={ search } searchLabel={ searchLabel } />
) }
Expand Down
26 changes: 17 additions & 9 deletions packages/dataviews/src/dataviews/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,19 @@ function DataViews< Item >( {
}
}, [ hasPrimaryOrLockedFilters, isShowingFilter ] );

const {
data: displayData,
paginationInfo: displayPaginationInfo,
hasInitiallyLoaded,
} = useData( data, isLoading, paginationInfo );

// Attach scroll event listener for infinite scroll
useEffect( () => {
if ( ! view.infiniteScrollEnabled || ! containerRef.current ) {
if (
! hasInitiallyLoaded ||
! view.infiniteScrollEnabled ||
! containerRef.current
) {
return;
}

Expand All @@ -220,7 +230,11 @@ function DataViews< Item >( {
container.removeEventListener( 'scroll', handleScroll );
handleScroll.cancel(); // Cancel any pending throttled calls
};
}, [ infiniteScrollHandler, view.infiniteScrollEnabled ] );
}, [
hasInitiallyLoaded,
infiniteScrollHandler,
view.infiniteScrollEnabled,
] );

// Filter out DataViewsPicker layouts.
const defaultLayouts = useMemo(
Expand All @@ -237,12 +251,6 @@ function DataViews< Item >( {
[ defaultLayoutsProperty ]
);

const {
data: displayData,
paginationInfo: displayPaginationInfo,
hasInitiallyLoaded,
} = useData( data, isLoading, paginationInfo );

if ( ! defaultLayouts[ view.type ] ) {
return null;
}
Expand Down Expand Up @@ -280,7 +288,7 @@ function DataViews< Item >( {
onReset,
} }
>
<div className="dataviews-wrapper" ref={ containerRef }>
<div className="dataviews-wrapper">
{ children ?? (
<DefaultUI
header={ header }
Expand Down
4 changes: 1 addition & 3 deletions packages/dataviews/src/dataviews/stories/empty.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,9 @@ const CustomEmptyComponent = () => (

const EmptyComponent = ( {
customEmpty,
containerHeight,
isLoading,
}: {
customEmpty?: boolean;
containerHeight?: 'auto' | '50vh' | '100vh';
isLoading?: boolean;
} ) => {
const [ view, setView ] = useState< View >( {
Expand All @@ -69,7 +67,7 @@ const EmptyComponent = ( {
style={ {
display: 'flex',
flexDirection: 'column',
height: containerHeight,
height: '100%',
} }
>
<DataViews
Expand Down
66 changes: 32 additions & 34 deletions packages/dataviews/src/dataviews/stories/free-composition.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ function PlanetOverview( { planets }: { planets: SpaceObject[] } ) {
</Stack>
</CardBody>
</Card>
<DataViews.Layout className="free-composition-dataviews-layout" />
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that this was a mistake. Before Layout was a child of the free-composition-header div.

</Stack>
</div>
<DataViews.Layout className="free-composition-dataviews-layout" />
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this story, moving <DataViews.Layout /> outside of the header wrapper changes which element is actually scrolling (now the internal .dataviews-layout__container). The story CSS still offsets the table header with .free-composition-dataviews-layout thead { inset-block-start: 67px; }, which was likely compensating for a sticky header inside the same scroll container. With the header now outside the scroll area, this offset will leave an unnecessary gap when the thead becomes sticky. Consider updating/removing that offset so the sticky thead aligns to the top of the layout scroll container.

Suggested change
<DataViews.Layout className="free-composition-dataviews-layout" />
<DataViews.Layout />

Copilot uses AI. Check for mistakes.
</>
);
}
Expand Down Expand Up @@ -132,7 +132,7 @@ export const FreeCompositionComponent = () => {
type: LAYOUT_TABLE,
search: '',
page: 1,
perPage: 10,
perPage: 20,
layout: {
enableMoving: false,
},
Expand All @@ -152,38 +152,36 @@ export const FreeCompositionComponent = () => {
);

return (
<div className="free-composition">
<DataViews
getItemId={ ( item ) => item.id.toString() }
paginationInfo={ paginationInfo }
data={ processedData }
view={ view }
fields={ fields }
actions={ actions }
onChangeView={ setView }
defaultLayouts={ {
table: {},
grid: {},
} }
empty={
<Stack
direction="column"
gap="sm"
justify="space-around"
align="center"
className="free-composition-dataviews-empty"
>
<Text size={ 18 } as="p">
No planets
</Text>
<Text variant="muted">{ `Try a different search because “${ view.search }” returned no results.` }</Text>
<Button variant="secondary">Create new planet</Button>
</Stack>
}
>
<PlanetOverview planets={ planets } />
</DataViews>
</div>
<DataViews
getItemId={ ( item ) => item.id.toString() }
paginationInfo={ paginationInfo }
data={ processedData }
view={ view }
fields={ fields }
actions={ actions }
onChangeView={ setView }
defaultLayouts={ {
table: {},
grid: {},
} }
empty={
<Stack
direction="column"
gap="sm"
justify="space-around"
align="center"
className="free-composition-dataviews-empty"
>
<Text size={ 18 } as="p">
No planets
</Text>
<Text variant="muted">{ `Try a different search because “${ view.search }” returned no results.` }</Text>
<Button variant="secondary">Create new planet</Button>
</Stack>
}
>
<PlanetOverview planets={ planets } />
</DataViews>
);
};

Expand Down
22 changes: 14 additions & 8 deletions packages/dataviews/src/dataviews/stories/index.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ import './style.css';
const meta = {
title: 'DataViews/DataViews',
component: DataViews,
args: {
containerHeight: 'auto',
},
argTypes: {
containerHeight: {
control: 'select',
options: [ 'auto', '600px', '80vh' ],
description: 'Height of the container',
},
},
// Use fullscreen layout and a wrapper div with padding to resolve conflicts
// between Ariakit's Dialog (usePreventBodyScroll) and Storybook's body padding
// (sb-main-padding class). This ensures consistent layout in DataViews stories
Expand All @@ -31,9 +41,11 @@ const meta = {
layout: 'fullscreen',
},
decorators: [
( Story ) => (
( Story, { args }: { args: any } ) => (
<div style={ { padding: '1rem' } }>
<Story />
<div style={ { height: args.containerHeight, minHeight: 0 } }>
<Story containerHeight={ args.containerHeight } />
</div>
</div>
),
],
Expand Down Expand Up @@ -212,19 +224,13 @@ export const Empty = {
render: EmptyComponent,
args: {
customEmpty: false,
containerHeight: '50vh',
isLoading: false,
},
argTypes: {
customEmpty: {
control: 'boolean',
description: 'Use custom empty state with planet illustration',
},
containerHeight: {
control: 'select',
options: [ 'auto', '50vh', '100vh' ],
description: 'Height of the container',
},
isLoading: {
control: 'boolean',
description: 'Show loading state',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,6 @@ const InfiniteScroll = () => {

return (
<>
<style>{ `
.dataviews-wrapper {
height: 600px;
overflow: auto;
}
` }</style>
<Text
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code was in place to ensure that infinite scroll was triggered on this story at any window size. Removing it has broken infinite scrolling in the story.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch! I fixed it with #76566

style={ {
marginBottom: '16px',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,7 @@ const LayoutActivityComponent = ( {
<div
style={
{
height: '100%',
maxWidth: fullWidth ? undefined : '400px',
'--wp-dataviews-color-background': backgroundColor,
} as React.CSSProperties
Expand Down
10 changes: 7 additions & 3 deletions packages/dataviews/src/dataviews/stories/layout-custom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,11 @@ function PosterGrid( { items }: { items: typeof data } ) {
* - Render a completely custom layout (poster grid) instead of `<DataViews.Layout />`
* - Still leverage DataViews sub-components for search and pagination
*/
export const LayoutCustomComponent = () => {
export const LayoutCustomComponent = ( {
containerHeight,
}: {
containerHeight: string;
} ) => {
const [ view, setView ] = useState< View >( {
type: LAYOUT_TABLE,
search: '',
Expand All @@ -128,11 +132,11 @@ export const LayoutCustomComponent = () => {
onChangeView={ setView }
defaultLayouts={ { table: {} } }
>
<div style={ { padding: '2px' } }>
<div style={ { padding: '2px', height: containerHeight } }>
<DataViews.Search />
<PosterGrid items={ processedData } />
<DataViews.Pagination />
</div>
<DataViews.Pagination />
</DataViews>
);
};
Expand Down
1 change: 1 addition & 0 deletions packages/dataviews/src/dataviews/stories/layout-grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export const LayoutTableComponent = ( {
<div
style={
{
height: '100%',
'--wp-dataviews-color-background': backgroundColor,
} as React.CSSProperties
}
Expand Down
1 change: 1 addition & 0 deletions packages/dataviews/src/dataviews/stories/layout-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export const LayoutTableComponent = ( {
<div
style={
{
height: '100%',
maxWidth: fullWidth ? undefined : '400px',
'--wp-dataviews-color-background': backgroundColor,
} as React.CSSProperties
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export const LayoutTableComponent = ( {
<div
style={
{
height: '100%',
'--wp-dataviews-color-background': backgroundColor,
} as React.CSSProperties
}
Expand Down
5 changes: 0 additions & 5 deletions packages/dataviews/src/dataviews/stories/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@
text-wrap: pretty;
}

.free-composition {
height: 600px;
overflow: auto;
}

.free-composition-heading,
.free-composition-header {
padding: 16px 48px;
Expand Down
Loading
Loading