@wordpress/dataviews 12.1.1-next.v.202602241322.0 → 13.0.0
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.
- package/CHANGELOG.md +22 -1
- package/README.md +132 -14
- package/build/components/dataform-layouts/card/index.cjs +12 -7
- package/build/components/dataform-layouts/card/index.cjs.map +2 -2
- package/build/components/dataform-layouts/panel/utils/get-label-content.cjs +2 -2
- package/build/components/dataform-layouts/panel/utils/get-label-content.cjs.map +2 -2
- package/build/components/dataviews-context/index.cjs +1 -0
- package/build/components/dataviews-context/index.cjs.map +2 -2
- package/build/components/dataviews-filters/toggle.cjs +6 -2
- package/build/components/dataviews-filters/toggle.cjs.map +2 -2
- package/build/components/dataviews-footer/index.cjs +28 -12
- package/build/components/dataviews-footer/index.cjs.map +3 -3
- package/build/components/dataviews-item-actions/index.cjs +0 -1
- package/build/components/dataviews-item-actions/index.cjs.map +2 -2
- package/build/components/dataviews-layout/index.cjs +4 -0
- package/build/components/dataviews-layout/index.cjs.map +2 -2
- package/build/components/dataviews-layouts/activity/index.cjs +41 -26
- package/build/components/dataviews-layouts/activity/index.cjs.map +3 -3
- package/build/components/dataviews-layouts/grid/composite-grid.cjs +2 -0
- package/build/components/dataviews-layouts/grid/composite-grid.cjs.map +2 -2
- package/build/components/dataviews-layouts/grid/index.cjs +19 -14
- package/build/components/dataviews-layouts/grid/index.cjs.map +3 -3
- package/build/components/dataviews-layouts/list/index.cjs +25 -12
- package/build/components/dataviews-layouts/list/index.cjs.map +2 -2
- package/build/components/dataviews-layouts/table/index.cjs +40 -19
- package/build/components/dataviews-layouts/table/index.cjs.map +2 -2
- package/build/dataviews/index.cjs +9 -2
- package/build/dataviews/index.cjs.map +3 -3
- package/build/dataviews-picker/index.cjs +1 -0
- package/build/dataviews-picker/index.cjs.map +2 -2
- package/build/hooks/use-data.cjs +46 -0
- package/build/hooks/use-data.cjs.map +7 -0
- package/build/hooks/use-delayed-loading.cjs +47 -0
- package/build/hooks/use-delayed-loading.cjs.map +7 -0
- package/build-module/components/dataform-layouts/card/index.mjs +12 -7
- package/build-module/components/dataform-layouts/card/index.mjs.map +2 -2
- package/build-module/components/dataform-layouts/panel/utils/get-label-content.mjs +3 -3
- package/build-module/components/dataform-layouts/panel/utils/get-label-content.mjs.map +2 -2
- package/build-module/components/dataviews-context/index.mjs +1 -0
- package/build-module/components/dataviews-context/index.mjs.map +2 -2
- package/build-module/components/dataviews-filters/toggle.mjs +6 -2
- package/build-module/components/dataviews-filters/toggle.mjs.map +2 -2
- package/build-module/components/dataviews-footer/index.mjs +28 -12
- package/build-module/components/dataviews-footer/index.mjs.map +2 -2
- package/build-module/components/dataviews-item-actions/index.mjs +0 -1
- package/build-module/components/dataviews-item-actions/index.mjs.map +2 -2
- package/build-module/components/dataviews-layout/index.mjs +4 -0
- package/build-module/components/dataviews-layout/index.mjs.map +2 -2
- package/build-module/components/dataviews-layouts/activity/index.mjs +41 -26
- package/build-module/components/dataviews-layouts/activity/index.mjs.map +2 -2
- package/build-module/components/dataviews-layouts/grid/composite-grid.mjs +2 -0
- package/build-module/components/dataviews-layouts/grid/composite-grid.mjs.map +2 -2
- package/build-module/components/dataviews-layouts/grid/index.mjs +19 -14
- package/build-module/components/dataviews-layouts/grid/index.mjs.map +2 -2
- package/build-module/components/dataviews-layouts/list/index.mjs +25 -12
- package/build-module/components/dataviews-layouts/list/index.mjs.map +2 -2
- package/build-module/components/dataviews-layouts/table/index.mjs +40 -19
- package/build-module/components/dataviews-layouts/table/index.mjs.map +2 -2
- package/build-module/dataviews/index.mjs +9 -2
- package/build-module/dataviews/index.mjs.map +2 -2
- package/build-module/dataviews-picker/index.mjs +1 -0
- package/build-module/dataviews-picker/index.mjs.map +2 -2
- package/build-module/hooks/use-data.mjs +25 -0
- package/build-module/hooks/use-data.mjs.map +7 -0
- package/build-module/hooks/use-delayed-loading.mjs +22 -0
- package/build-module/hooks/use-delayed-loading.mjs.map +7 -0
- package/build-style/style-rtl.css +91 -19
- package/build-style/style.css +91 -19
- package/build-types/components/dataform-layouts/card/index.d.ts.map +1 -1
- package/build-types/components/dataform-layouts/panel/utils/get-label-content.d.ts +1 -1
- package/build-types/components/dataform-layouts/panel/utils/get-label-content.d.ts.map +1 -1
- package/build-types/components/dataviews-context/index.d.ts +1 -0
- package/build-types/components/dataviews-context/index.d.ts.map +1 -1
- package/build-types/components/dataviews-filters/toggle.d.ts.map +1 -1
- package/build-types/components/dataviews-footer/index.d.ts +1 -1
- package/build-types/components/dataviews-footer/index.d.ts.map +1 -1
- package/build-types/components/dataviews-item-actions/index.d.ts.map +1 -1
- package/build-types/components/dataviews-layout/index.d.ts +1 -1
- package/build-types/components/dataviews-layout/index.d.ts.map +1 -1
- package/build-types/components/dataviews-layouts/activity/index.d.ts.map +1 -1
- package/build-types/components/dataviews-layouts/grid/composite-grid.d.ts +2 -1
- package/build-types/components/dataviews-layouts/grid/composite-grid.d.ts.map +1 -1
- package/build-types/components/dataviews-layouts/grid/index.d.ts.map +1 -1
- package/build-types/components/dataviews-layouts/list/index.d.ts.map +1 -1
- package/build-types/components/dataviews-layouts/table/index.d.ts.map +1 -1
- package/build-types/dataform/stories/layout-panel.d.ts.map +1 -1
- package/build-types/dataviews/index.d.ts.map +1 -1
- package/build-types/dataviews/stories/empty.d.ts.map +1 -1
- package/build-types/dataviews/stories/free-composition.d.ts.map +1 -1
- package/build-types/dataviews/stories/layout-table.d.ts.map +1 -1
- package/build-types/dataviews/stories/minimal-ui.d.ts.map +1 -1
- package/build-types/dataviews/stories/with-card.d.ts.map +1 -1
- package/build-types/dataviews-picker/index.d.ts.map +1 -1
- package/build-types/hooks/use-data.d.ts +12 -0
- package/build-types/hooks/use-data.d.ts.map +1 -0
- package/build-types/hooks/use-delayed-loading.d.ts +4 -0
- package/build-types/hooks/use-delayed-loading.d.ts.map +1 -0
- package/build-wp/index.js +263 -135
- package/package.json +16 -19
- package/src/components/dataform-layouts/card/index.tsx +8 -9
- package/src/components/dataform-layouts/card/style.scss +1 -0
- package/src/components/dataform-layouts/panel/style.scss +2 -0
- package/src/components/dataform-layouts/panel/utils/get-label-content.tsx +3 -5
- package/src/components/dataform-layouts/regular/style.scss +3 -2
- package/src/components/dataviews-context/index.ts +2 -0
- package/src/components/dataviews-filters/toggle.tsx +9 -2
- package/src/components/dataviews-footer/index.tsx +39 -12
- package/src/components/dataviews-footer/style.scss +6 -1
- package/src/components/dataviews-item-actions/index.tsx +0 -3
- package/src/components/dataviews-item-actions/style.scss +7 -0
- package/src/components/dataviews-layout/index.tsx +5 -0
- package/src/components/dataviews-layouts/activity/index.tsx +29 -22
- package/src/components/dataviews-layouts/activity/style.scss +5 -0
- package/src/components/dataviews-layouts/grid/composite-grid.tsx +4 -0
- package/src/components/dataviews-layouts/grid/index.tsx +19 -22
- package/src/components/dataviews-layouts/grid/style.scss +5 -0
- package/src/components/dataviews-layouts/list/index.tsx +39 -21
- package/src/components/dataviews-layouts/list/style.scss +5 -9
- package/src/components/dataviews-layouts/table/index.tsx +48 -22
- package/src/components/dataviews-layouts/table/style.scss +6 -0
- package/src/dataform/stories/layout-card.tsx +2 -2
- package/src/dataform/stories/layout-panel.tsx +5 -1
- package/src/dataviews/index.tsx +10 -2
- package/src/dataviews/stories/empty.tsx +1 -7
- package/src/dataviews/stories/free-composition.tsx +0 -5
- package/src/dataviews/stories/layout-table.tsx +1 -7
- package/src/dataviews/stories/minimal-ui.tsx +0 -5
- package/src/dataviews/stories/with-card.tsx +1 -7
- package/src/dataviews/style.scss +25 -0
- package/src/dataviews-picker/index.tsx +1 -0
- package/src/hooks/use-data.ts +45 -0
- package/src/hooks/use-delayed-loading.ts +21 -0
|
@@ -33,6 +33,7 @@ import { Stack } from '@wordpress/ui';
|
|
|
33
33
|
import { unlock } from '../../../lock-unlock';
|
|
34
34
|
import { ActionsMenuGroup, ActionModal } from '../../dataviews-item-actions';
|
|
35
35
|
import DataViewsContext from '../../dataviews-context';
|
|
36
|
+
import { useDelayedLoading } from '../../../hooks/use-delayed-loading';
|
|
36
37
|
import type {
|
|
37
38
|
Action,
|
|
38
39
|
NormalizedField,
|
|
@@ -216,6 +217,10 @@ function ListItem< Item >( {
|
|
|
216
217
|
<titleField.render item={ item } field={ titleField } />
|
|
217
218
|
) : null;
|
|
218
219
|
|
|
220
|
+
const renderDescription = showDescription && descriptionField?.render;
|
|
221
|
+
// When we have only the media and title fields, we want to center them vertically in the list item.
|
|
222
|
+
const hasOnlyMediaAndTitle =
|
|
223
|
+
!! renderedMediaField && ! renderDescription && ! otherFields.length;
|
|
219
224
|
const usedActions = eligibleActions?.length > 0 && (
|
|
220
225
|
<Stack
|
|
221
226
|
direction="row"
|
|
@@ -314,7 +319,7 @@ function ListItem< Item >( {
|
|
|
314
319
|
direction="row"
|
|
315
320
|
gap="md"
|
|
316
321
|
justify="start"
|
|
317
|
-
align=
|
|
322
|
+
align={ hasOnlyMediaAndTitle ? 'center' : 'flex-start' }
|
|
318
323
|
style={ { flex: 1, minWidth: 0 } }
|
|
319
324
|
>
|
|
320
325
|
{ renderedMediaField }
|
|
@@ -332,7 +337,7 @@ function ListItem< Item >( {
|
|
|
332
337
|
</div>
|
|
333
338
|
{ usedActions }
|
|
334
339
|
</Stack>
|
|
335
|
-
{
|
|
340
|
+
{ renderDescription && (
|
|
336
341
|
<div className="dataviews-view-list__field">
|
|
337
342
|
<descriptionField.render
|
|
338
343
|
item={ item }
|
|
@@ -389,6 +394,7 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) {
|
|
|
389
394
|
empty,
|
|
390
395
|
} = props;
|
|
391
396
|
const baseId = useInstanceId( ViewList, 'view-list' );
|
|
397
|
+
const isDelayedLoading = useDelayedLoading( !! isLoading );
|
|
392
398
|
|
|
393
399
|
const selectedItem = data?.findLast( ( item ) =>
|
|
394
400
|
selection.includes( getItemId( item ) )
|
|
@@ -425,6 +431,8 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) {
|
|
|
425
431
|
string | null | undefined
|
|
426
432
|
>( undefined );
|
|
427
433
|
|
|
434
|
+
const compositeRef = useRef< HTMLDivElement >( null );
|
|
435
|
+
|
|
428
436
|
// Update the active composite item when the selected item changes.
|
|
429
437
|
useEffect( () => {
|
|
430
438
|
if ( selectedItem ) {
|
|
@@ -463,7 +471,17 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) {
|
|
|
463
471
|
const targetCompositeItemId = generateCompositeId( itemIdPrefix );
|
|
464
472
|
|
|
465
473
|
setActiveCompositeId( targetCompositeItemId );
|
|
466
|
-
|
|
474
|
+
// The active composite item is controlled state that
|
|
475
|
+
// can update without needing a focus move (e.g., searching
|
|
476
|
+
// can trigger an active ID update). Only move DOM focus
|
|
477
|
+
// when it's already within the list.
|
|
478
|
+
if (
|
|
479
|
+
compositeRef.current?.contains(
|
|
480
|
+
compositeRef.current.ownerDocument.activeElement
|
|
481
|
+
)
|
|
482
|
+
) {
|
|
483
|
+
document.getElementById( targetCompositeItemId )?.focus();
|
|
484
|
+
}
|
|
467
485
|
},
|
|
468
486
|
[ data, generateCompositeItemIdPrefix ]
|
|
469
487
|
);
|
|
@@ -511,36 +529,30 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) {
|
|
|
511
529
|
[ selectCompositeItem, activeItemIndex ]
|
|
512
530
|
);
|
|
513
531
|
|
|
514
|
-
const hasData = data?.length;
|
|
532
|
+
const hasData = !! data?.length;
|
|
533
|
+
const groupField = view.groupBy?.field
|
|
534
|
+
? fields.find( ( field ) => field.id === view.groupBy?.field )
|
|
535
|
+
: null;
|
|
536
|
+
const dataByGroup =
|
|
537
|
+
hasData && groupField ? getDataByGroup( data, groupField ) : null;
|
|
538
|
+
const isInfiniteScroll = view.infiniteScrollEnabled && ! dataByGroup;
|
|
515
539
|
if ( ! hasData ) {
|
|
516
540
|
return (
|
|
517
541
|
<div
|
|
518
|
-
className={ clsx( {
|
|
519
|
-
'
|
|
520
|
-
'dataviews-no-results': ! hasData && ! isLoading,
|
|
542
|
+
className={ clsx( 'dataviews-no-results', {
|
|
543
|
+
'is-refreshing': isDelayedLoading,
|
|
521
544
|
} ) }
|
|
522
545
|
>
|
|
523
|
-
{
|
|
524
|
-
( isLoading ? (
|
|
525
|
-
<p>
|
|
526
|
-
<Spinner />
|
|
527
|
-
</p>
|
|
528
|
-
) : (
|
|
529
|
-
empty
|
|
530
|
-
) ) }
|
|
546
|
+
{ empty }
|
|
531
547
|
</div>
|
|
532
548
|
);
|
|
533
549
|
}
|
|
534
550
|
|
|
535
|
-
const groupField = view.groupBy?.field
|
|
536
|
-
? fields.find( ( field ) => field.id === view.groupBy?.field )
|
|
537
|
-
: null;
|
|
538
|
-
const dataByGroup = groupField ? getDataByGroup( data, groupField ) : null;
|
|
539
|
-
|
|
540
551
|
// Render data grouped by field
|
|
541
552
|
if ( hasData && groupField && dataByGroup ) {
|
|
542
553
|
return (
|
|
543
554
|
<Composite
|
|
555
|
+
ref={ compositeRef }
|
|
544
556
|
id={ `${ baseId }` }
|
|
545
557
|
render={ <div /> }
|
|
546
558
|
className="dataviews-view-list__group"
|
|
@@ -606,6 +618,7 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) {
|
|
|
606
618
|
return (
|
|
607
619
|
<>
|
|
608
620
|
<Composite
|
|
621
|
+
ref={ compositeRef }
|
|
609
622
|
id={ baseId }
|
|
610
623
|
render={ <div /> }
|
|
611
624
|
className={ clsx( 'dataviews-view-list', className, {
|
|
@@ -614,10 +627,15 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) {
|
|
|
614
627
|
[ 'compact', 'comfortable' ].includes(
|
|
615
628
|
view.layout.density
|
|
616
629
|
),
|
|
630
|
+
'is-refreshing': ! isInfiniteScroll && isDelayedLoading,
|
|
617
631
|
} ) }
|
|
618
632
|
role={ view.infiniteScrollEnabled ? 'feed' : 'grid' }
|
|
619
633
|
activeId={ activeCompositeId }
|
|
620
634
|
setActiveId={ setActiveCompositeId }
|
|
635
|
+
// @ts-ignore
|
|
636
|
+
inert={
|
|
637
|
+
! isInfiniteScroll && !! isLoading ? 'true' : undefined
|
|
638
|
+
}
|
|
621
639
|
>
|
|
622
640
|
{ data.map( ( item, index ) => {
|
|
623
641
|
const id = generateCompositeItemIdPrefix( item );
|
|
@@ -646,7 +664,7 @@ export default function ViewList< Item >( props: ViewListProps< Item > ) {
|
|
|
646
664
|
);
|
|
647
665
|
} ) }
|
|
648
666
|
</Composite>
|
|
649
|
-
{
|
|
667
|
+
{ isInfiniteScroll && isLoading && (
|
|
650
668
|
<p className="dataviews-loading-more">
|
|
651
669
|
<Spinner />
|
|
652
670
|
</p>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
@use "@wordpress/base-styles/colors" as *;
|
|
2
2
|
@use "@wordpress/base-styles/variables" as *;
|
|
3
|
+
@use "../../../dataviews/style" as *;
|
|
3
4
|
|
|
4
5
|
div.dataviews-view-list {
|
|
5
6
|
list-style-type: none;
|
|
@@ -169,7 +170,6 @@ div.dataviews-view-list {
|
|
|
169
170
|
}
|
|
170
171
|
|
|
171
172
|
.dataviews-view-list__field-wrapper {
|
|
172
|
-
min-height: $grid-unit-05 * 13; // Ensures title is centrally aligned when all fields are hidden
|
|
173
173
|
flex-grow: 1;
|
|
174
174
|
min-width: 0;
|
|
175
175
|
}
|
|
@@ -224,10 +224,6 @@ div.dataviews-view-list {
|
|
|
224
224
|
height: $grid-unit-05 * 8;
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
.dataviews-view-list__field-wrapper {
|
|
228
|
-
min-height: $grid-unit-05 * 8;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
227
|
.dataviews-view-list__fields {
|
|
232
228
|
gap: $grid-unit-10;
|
|
233
229
|
row-gap: $grid-unit-05;
|
|
@@ -256,10 +252,6 @@ div.dataviews-view-list {
|
|
|
256
252
|
height: $grid-unit-05 * 16;
|
|
257
253
|
}
|
|
258
254
|
|
|
259
|
-
.dataviews-view-list__field-wrapper {
|
|
260
|
-
min-height: $grid-unit-05 * 16;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
255
|
.dataviews-view-list__fields {
|
|
264
256
|
gap: $grid-unit-20;
|
|
265
257
|
row-gap: $grid-unit-10;
|
|
@@ -271,6 +263,10 @@ div.dataviews-view-list {
|
|
|
271
263
|
}
|
|
272
264
|
}
|
|
273
265
|
}
|
|
266
|
+
|
|
267
|
+
&.is-refreshing {
|
|
268
|
+
@include dataviews-refreshing();
|
|
269
|
+
}
|
|
274
270
|
}
|
|
275
271
|
|
|
276
272
|
.dataviews-view-list__group-header {
|
|
@@ -42,6 +42,20 @@ import ColumnPrimary from './column-primary';
|
|
|
42
42
|
import { useIsHorizontalScrollEnd } from './use-is-horizontal-scroll-end';
|
|
43
43
|
import getDataByGroup from '../utils/get-data-by-group';
|
|
44
44
|
import { PropertiesSection } from '../../dataviews-view-config/properties-section';
|
|
45
|
+
import { useDelayedLoading } from '../../../hooks/use-delayed-loading';
|
|
46
|
+
|
|
47
|
+
function getEffectiveAlign(
|
|
48
|
+
explicitAlign: 'start' | 'center' | 'end' | undefined,
|
|
49
|
+
fieldType: string | undefined
|
|
50
|
+
): 'start' | 'center' | 'end' | undefined {
|
|
51
|
+
if ( explicitAlign ) {
|
|
52
|
+
return explicitAlign;
|
|
53
|
+
}
|
|
54
|
+
if ( fieldType === 'integer' || fieldType === 'number' ) {
|
|
55
|
+
return 'end';
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
45
59
|
|
|
46
60
|
interface TableColumnFieldProps< Item > {
|
|
47
61
|
fields: NormalizedField< Item >[];
|
|
@@ -225,6 +239,8 @@ function TableRow< Item >( {
|
|
|
225
239
|
// Explicit picks the supported styles.
|
|
226
240
|
const { width, maxWidth, minWidth, align } =
|
|
227
241
|
view.layout?.styles?.[ column ] ?? {};
|
|
242
|
+
const field = fields.find( ( f ) => f.id === column );
|
|
243
|
+
const effectiveAlign = getEffectiveAlign( align, field?.type );
|
|
228
244
|
|
|
229
245
|
return (
|
|
230
246
|
<td
|
|
@@ -239,7 +255,7 @@ function TableRow< Item >( {
|
|
|
239
255
|
fields={ fields }
|
|
240
256
|
item={ item }
|
|
241
257
|
column={ column }
|
|
242
|
-
align={
|
|
258
|
+
align={ effectiveAlign }
|
|
243
259
|
/>
|
|
244
260
|
</td>
|
|
245
261
|
);
|
|
@@ -287,13 +303,13 @@ function ViewTable< Item >( {
|
|
|
287
303
|
empty,
|
|
288
304
|
}: ViewTableProps< Item > ) {
|
|
289
305
|
const { containerRef } = useContext( DataViewsContext );
|
|
306
|
+
const isDelayedLoading = useDelayedLoading( isLoading );
|
|
290
307
|
const headerMenuRefs = useRef<
|
|
291
308
|
Map< string, { node: HTMLButtonElement; fallback: string } >
|
|
292
309
|
>( new Map() );
|
|
293
310
|
const headerMenuToFocusRef = useRef< HTMLButtonElement >( undefined );
|
|
294
311
|
const [ nextHeaderMenuToFocus, setNextHeaderMenuToFocus ] =
|
|
295
312
|
useState< HTMLButtonElement >();
|
|
296
|
-
const hasBulkActions = useSomeItemHasAPossibleBulkAction( actions, data );
|
|
297
313
|
const [ contextMenuAnchor, setContextMenuAnchor ] = useState< {
|
|
298
314
|
getBoundingClientRect: () => DOMRect;
|
|
299
315
|
} | null >( null );
|
|
@@ -312,6 +328,8 @@ function ViewTable< Item >( {
|
|
|
312
328
|
enabled: !! actions?.length,
|
|
313
329
|
} );
|
|
314
330
|
|
|
331
|
+
const hasBulkActions = useSomeItemHasAPossibleBulkAction( actions, data );
|
|
332
|
+
|
|
315
333
|
if ( nextHeaderMenuToFocus ) {
|
|
316
334
|
// If we need to force focus, we short-circuit rendering here
|
|
317
335
|
// to prevent any additional work while we handle that.
|
|
@@ -382,6 +400,18 @@ function ViewTable< Item >( {
|
|
|
382
400
|
};
|
|
383
401
|
const isInfiniteScroll = view.infiniteScrollEnabled && ! dataByGroup;
|
|
384
402
|
const isRtl = isRTL();
|
|
403
|
+
if ( ! hasData ) {
|
|
404
|
+
return (
|
|
405
|
+
<div
|
|
406
|
+
className={ clsx( 'dataviews-no-results', {
|
|
407
|
+
'is-refreshing': isDelayedLoading,
|
|
408
|
+
} ) }
|
|
409
|
+
id={ tableNoticeId }
|
|
410
|
+
>
|
|
411
|
+
{ empty }
|
|
412
|
+
</div>
|
|
413
|
+
);
|
|
414
|
+
}
|
|
385
415
|
|
|
386
416
|
return (
|
|
387
417
|
<>
|
|
@@ -393,10 +423,13 @@ function ViewTable< Item >( {
|
|
|
393
423
|
view.layout.density
|
|
394
424
|
),
|
|
395
425
|
'has-bulk-actions': hasBulkActions,
|
|
426
|
+
'is-refreshing': ! isInfiniteScroll && isDelayedLoading,
|
|
396
427
|
} ) }
|
|
397
428
|
aria-busy={ isLoading }
|
|
398
429
|
aria-describedby={ tableNoticeId }
|
|
399
430
|
role={ isInfiniteScroll ? 'feed' : undefined }
|
|
431
|
+
// @ts-ignore Reason: inert is a recent HTML attribute
|
|
432
|
+
inert={ ! isInfiniteScroll && isLoading ? 'true' : undefined }
|
|
400
433
|
>
|
|
401
434
|
<colgroup>
|
|
402
435
|
{ hasBulkActions && (
|
|
@@ -411,7 +444,7 @@ function ViewTable< Item >( {
|
|
|
411
444
|
className={ clsx(
|
|
412
445
|
`dataviews-view-table__col-${ column }`,
|
|
413
446
|
{
|
|
414
|
-
'dataviews-view-table__col-expand':
|
|
447
|
+
'dataviews-view-table__col-first-expand':
|
|
415
448
|
! hasPrimaryColumn &&
|
|
416
449
|
index === columns.length - 1,
|
|
417
450
|
}
|
|
@@ -483,6 +516,13 @@ function ViewTable< Item >( {
|
|
|
483
516
|
// Explicit picks the supported styles.
|
|
484
517
|
const { width, maxWidth, minWidth, align } =
|
|
485
518
|
view.layout?.styles?.[ column ] ?? {};
|
|
519
|
+
const field = fields.find(
|
|
520
|
+
( f ) => f.id === column
|
|
521
|
+
);
|
|
522
|
+
const effectiveAlign = getEffectiveAlign(
|
|
523
|
+
align,
|
|
524
|
+
field?.type
|
|
525
|
+
);
|
|
486
526
|
const canInsertOrMove =
|
|
487
527
|
view.layout?.enableMoving ?? true;
|
|
488
528
|
return (
|
|
@@ -492,7 +532,7 @@ function ViewTable< Item >( {
|
|
|
492
532
|
width,
|
|
493
533
|
maxWidth,
|
|
494
534
|
minWidth,
|
|
495
|
-
textAlign:
|
|
535
|
+
textAlign: effectiveAlign,
|
|
496
536
|
} }
|
|
497
537
|
aria-sort={
|
|
498
538
|
view.sort?.direction &&
|
|
@@ -634,27 +674,13 @@ function ViewTable< Item >( {
|
|
|
634
674
|
</tbody>
|
|
635
675
|
) }
|
|
636
676
|
</table>
|
|
637
|
-
|
|
638
|
-
className={
|
|
639
|
-
'dataviews-loading': isLoading,
|
|
640
|
-
'dataviews-no-results': ! hasData && ! isLoading,
|
|
641
|
-
} ) }
|
|
642
|
-
id={ tableNoticeId }
|
|
643
|
-
>
|
|
644
|
-
{ ! hasData &&
|
|
645
|
-
( isLoading ? (
|
|
646
|
-
<p>
|
|
647
|
-
<Spinner />
|
|
648
|
-
</p>
|
|
649
|
-
) : (
|
|
650
|
-
empty
|
|
651
|
-
) ) }
|
|
652
|
-
{ hasData && isLoading && (
|
|
677
|
+
{ isInfiniteScroll && isLoading && (
|
|
678
|
+
<div className="dataviews-loading" id={ tableNoticeId }>
|
|
653
679
|
<p className="dataviews-loading-more">
|
|
654
680
|
<Spinner />
|
|
655
681
|
</p>
|
|
656
|
-
|
|
657
|
-
|
|
682
|
+
</div>
|
|
683
|
+
) }
|
|
658
684
|
</>
|
|
659
685
|
);
|
|
660
686
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
@use "@wordpress/base-styles/mixins" as *;
|
|
3
3
|
@use "@wordpress/base-styles/variables" as *;
|
|
4
4
|
@use "@wordpress/base-styles/z-index" as *;
|
|
5
|
+
@use "../../../dataviews/style" as *;
|
|
5
6
|
|
|
6
7
|
.dataviews-view-table {
|
|
7
8
|
width: 100%;
|
|
@@ -176,6 +177,7 @@
|
|
|
176
177
|
|
|
177
178
|
&.dataviews-view-table__cell-align-end {
|
|
178
179
|
justify-content: flex-end;
|
|
180
|
+
font-variant-numeric: tabular-nums;
|
|
179
181
|
}
|
|
180
182
|
|
|
181
183
|
&.dataviews-view-table__cell-align-center {
|
|
@@ -309,3 +311,7 @@
|
|
|
309
311
|
.dataviews-view-table col[class^="dataviews-view-table__col-"]:not(.dataviews-view-table__col-first-data):not(.dataviews-view-table__col-expand) {
|
|
310
312
|
width: 1%;
|
|
311
313
|
}
|
|
314
|
+
|
|
315
|
+
.dataviews-view-table.is-refreshing {
|
|
316
|
+
@include dataviews-refreshing();
|
|
317
|
+
}
|
|
@@ -152,7 +152,7 @@ const LayoutCardComponent = ( {
|
|
|
152
152
|
isCollapsible: collapsible,
|
|
153
153
|
isOpened: opened,
|
|
154
154
|
}: {
|
|
155
|
-
summary?: string | { id: string; visibility: 'always' }[];
|
|
155
|
+
summary?: string | string[] | { id: string; visibility: 'always' }[];
|
|
156
156
|
withSummary?: boolean;
|
|
157
157
|
withHeader?: boolean;
|
|
158
158
|
isCollapsible?: boolean;
|
|
@@ -178,7 +178,7 @@ const LayoutCardComponent = ( {
|
|
|
178
178
|
{
|
|
179
179
|
id: 'customerCard',
|
|
180
180
|
layout: getCardLayoutFromStoryArgs( {
|
|
181
|
-
summary: 'plan-summary',
|
|
181
|
+
summary: [ 'name', 'plan-summary' ],
|
|
182
182
|
withHeader: withHeader ?? true,
|
|
183
183
|
withSummary,
|
|
184
184
|
isCollapsible,
|
|
@@ -75,6 +75,10 @@ const fields: Field< SamplePost >[] = [
|
|
|
75
75
|
{ value: 2, label: 'John' },
|
|
76
76
|
{ value: 3, label: 'Alice' },
|
|
77
77
|
{ value: 4, label: 'Bob' },
|
|
78
|
+
{
|
|
79
|
+
value: 5,
|
|
80
|
+
label: 'Superadministratoraccountwithalongunhyphenatedusername',
|
|
81
|
+
},
|
|
78
82
|
],
|
|
79
83
|
setValue: ( { value } ) => ( {
|
|
80
84
|
author: Number( value ),
|
|
@@ -310,7 +314,7 @@ const LayoutPanelComponent = ( {
|
|
|
310
314
|
const [ post, setPost ] = useState< SamplePost >( {
|
|
311
315
|
title: 'Hello, World!',
|
|
312
316
|
order: 2,
|
|
313
|
-
author:
|
|
317
|
+
author: 5,
|
|
314
318
|
status: 'draft',
|
|
315
319
|
reviewer: 'fulano',
|
|
316
320
|
date: '2021-01-01T12:00:00',
|
package/src/dataviews/index.tsx
CHANGED
|
@@ -31,6 +31,7 @@ import DataViewsViewConfig, {
|
|
|
31
31
|
ViewTypeMenu,
|
|
32
32
|
} from '../components/dataviews-view-config';
|
|
33
33
|
import normalizeFields from '../field-types';
|
|
34
|
+
import useData from '../hooks/use-data';
|
|
34
35
|
import type { Action, Field, View, SupportedLayouts } from '../types';
|
|
35
36
|
import type { SelectionOrUpdater } from '../types/private';
|
|
36
37
|
type ItemWithId = { id: string };
|
|
@@ -236,6 +237,12 @@ function DataViews< Item >( {
|
|
|
236
237
|
[ defaultLayoutsProperty ]
|
|
237
238
|
);
|
|
238
239
|
|
|
240
|
+
const {
|
|
241
|
+
data: displayData,
|
|
242
|
+
paginationInfo: displayPaginationInfo,
|
|
243
|
+
hasInitiallyLoaded,
|
|
244
|
+
} = useData( data, isLoading, paginationInfo );
|
|
245
|
+
|
|
239
246
|
if ( ! defaultLayouts[ view.type ] ) {
|
|
240
247
|
return null;
|
|
241
248
|
}
|
|
@@ -247,9 +254,9 @@ function DataViews< Item >( {
|
|
|
247
254
|
onChangeView,
|
|
248
255
|
fields: _fields,
|
|
249
256
|
actions,
|
|
250
|
-
data,
|
|
257
|
+
data: displayData,
|
|
251
258
|
isLoading,
|
|
252
|
-
paginationInfo,
|
|
259
|
+
paginationInfo: displayPaginationInfo,
|
|
253
260
|
selection: _selection,
|
|
254
261
|
onChangeSelection: setSelectionWithChange,
|
|
255
262
|
openedFilter,
|
|
@@ -268,6 +275,7 @@ function DataViews< Item >( {
|
|
|
268
275
|
setIsShowingFilter,
|
|
269
276
|
config,
|
|
270
277
|
empty,
|
|
278
|
+
hasInitiallyLoaded,
|
|
271
279
|
hasInfiniteScrollHandler: !! infiniteScrollHandler,
|
|
272
280
|
onReset,
|
|
273
281
|
} }
|
|
@@ -59,13 +59,7 @@ const EmptyComponent = ( {
|
|
|
59
59
|
search: '',
|
|
60
60
|
page: 1,
|
|
61
61
|
perPage: 10,
|
|
62
|
-
layout: {
|
|
63
|
-
styles: {
|
|
64
|
-
satellites: {
|
|
65
|
-
align: 'end' as const,
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
},
|
|
62
|
+
layout: {},
|
|
69
63
|
filters: [],
|
|
70
64
|
fields: [ 'title', 'description', 'categories' ],
|
|
71
65
|
} );
|
|
@@ -32,13 +32,7 @@ export const LayoutTableComponent = ( {
|
|
|
32
32
|
search: '',
|
|
33
33
|
page: 1,
|
|
34
34
|
perPage: 10,
|
|
35
|
-
layout: {
|
|
36
|
-
styles: {
|
|
37
|
-
satellites: {
|
|
38
|
-
align: 'end' as const,
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
},
|
|
35
|
+
layout: {},
|
|
42
36
|
filters: [],
|
|
43
37
|
fields: [ 'categories' ],
|
|
44
38
|
titleField: 'title',
|
|
@@ -24,13 +24,7 @@ const WithCardComponent = () => {
|
|
|
24
24
|
search: '',
|
|
25
25
|
page: 1,
|
|
26
26
|
perPage: 10,
|
|
27
|
-
layout: {
|
|
28
|
-
styles: {
|
|
29
|
-
satellites: {
|
|
30
|
-
align: 'end' as const,
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
},
|
|
27
|
+
layout: {},
|
|
34
28
|
filters: [],
|
|
35
29
|
fields: [ 'categories' ],
|
|
36
30
|
titleField: 'title',
|
package/src/dataviews/style.scss
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
@use "@wordpress/base-styles/variables" as *;
|
|
3
3
|
@use "@wordpress/base-styles/mixins" as *;
|
|
4
4
|
|
|
5
|
+
@mixin dataviews-refreshing {
|
|
6
|
+
opacity: 0.5;
|
|
7
|
+
pointer-events: none;
|
|
8
|
+
|
|
9
|
+
@media not (prefers-reduced-motion) {
|
|
10
|
+
opacity: 1;
|
|
11
|
+
animation: dataviews-pulse 1s ease-in-out infinite;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
5
15
|
.dataviews-wrapper,
|
|
6
16
|
.dataviews-picker-wrapper {
|
|
7
17
|
height: 100%;
|
|
@@ -44,6 +54,21 @@
|
|
|
44
54
|
}
|
|
45
55
|
}
|
|
46
56
|
|
|
57
|
+
.dataviews-no-results.is-refreshing {
|
|
58
|
+
@include dataviews-refreshing();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@keyframes dataviews-pulse {
|
|
62
|
+
0%,
|
|
63
|
+
100% {
|
|
64
|
+
opacity: 1;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
50% {
|
|
68
|
+
opacity: 0.5;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
47
72
|
.dataviews-loading-more {
|
|
48
73
|
text-align: center;
|
|
49
74
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useEffect, useRef, useState } from '@wordpress/element';
|
|
5
|
+
|
|
6
|
+
type PaginationInfo = {
|
|
7
|
+
totalItems: number;
|
|
8
|
+
totalPages: number;
|
|
9
|
+
infiniteScrollHandler?: () => void;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default function useData< Item >(
|
|
13
|
+
data: Item[],
|
|
14
|
+
isLoading: boolean | undefined,
|
|
15
|
+
paginationInfo: PaginationInfo
|
|
16
|
+
): {
|
|
17
|
+
data: Item[];
|
|
18
|
+
paginationInfo: PaginationInfo;
|
|
19
|
+
hasInitiallyLoaded: boolean;
|
|
20
|
+
} {
|
|
21
|
+
const previousDataRef = useRef< Item[] >( data );
|
|
22
|
+
const previousPaginationInfoRef =
|
|
23
|
+
useRef< PaginationInfo >( paginationInfo );
|
|
24
|
+
const [ hasInitiallyLoaded, setHasInitiallyLoaded ] = useState(
|
|
25
|
+
! isLoading
|
|
26
|
+
);
|
|
27
|
+
useEffect( () => {
|
|
28
|
+
if ( ! isLoading ) {
|
|
29
|
+
previousDataRef.current = data;
|
|
30
|
+
previousPaginationInfoRef.current = paginationInfo;
|
|
31
|
+
setHasInitiallyLoaded( true );
|
|
32
|
+
}
|
|
33
|
+
}, [ data, isLoading, paginationInfo ] );
|
|
34
|
+
return {
|
|
35
|
+
data:
|
|
36
|
+
isLoading && previousDataRef.current?.length
|
|
37
|
+
? previousDataRef.current
|
|
38
|
+
: data,
|
|
39
|
+
paginationInfo:
|
|
40
|
+
isLoading && previousDataRef.current?.length
|
|
41
|
+
? previousPaginationInfoRef.current
|
|
42
|
+
: paginationInfo,
|
|
43
|
+
hasInitiallyLoaded,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useEffect, useState } from '@wordpress/element';
|
|
2
|
+
|
|
3
|
+
export function useDelayedLoading(
|
|
4
|
+
isLoading: boolean,
|
|
5
|
+
options: { delay: number } = { delay: 400 }
|
|
6
|
+
): boolean {
|
|
7
|
+
const [ showLoader, setShowLoader ] = useState( false );
|
|
8
|
+
useEffect( () => {
|
|
9
|
+
if ( ! isLoading ) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const timeout = setTimeout( () => {
|
|
13
|
+
setShowLoader( true );
|
|
14
|
+
}, options.delay );
|
|
15
|
+
return () => {
|
|
16
|
+
clearTimeout( timeout );
|
|
17
|
+
setShowLoader( false );
|
|
18
|
+
};
|
|
19
|
+
}, [ isLoading, options.delay ] );
|
|
20
|
+
return showLoader;
|
|
21
|
+
}
|