Skip to content

Commit c7a7ede

Browse files
committed
Improve DataViews filters, search debounce and styles
1 parent 6b2dc20 commit c7a7ede

2 files changed

Lines changed: 99 additions & 73 deletions

File tree

src/components/wordpress/dataviews.tsx

Lines changed: 69 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -236,12 +236,12 @@ const FilterItems = ({
236236
return null;
237237
}
238238
return (
239-
<div className="relative flex items-center gap-2" key={id}>
240-
<div className="[&>input]:pr-8 [&>select]:pr-8">{field.field}</div>
239+
<div className="relative flex items-center pe-2 border rounded-md border-border **:border-0 **:shadow-none" key={id}>
240+
{field.field}
241241
<span
242242
role="button"
243243
aria-label={removeFilter}
244-
className="absolute right-2 inline-flex items-center justify-center w-5 h-5 text-muted-foreground hover:text-primary z-10"
244+
className="inline-flex items-center justify-center w-5 h-5 text-muted-foreground hover:text-primary z-10"
245245
onClick={() => handleRemoveFilter(id)}>
246246
<X size="12" />
247247
</span>
@@ -591,42 +591,37 @@ export function DataViews<Item>(props: DataViewsProps<Item>) {
591591

592592
const hasFilters = (filter?.fields?.length ?? 0) > 0;
593593

594-
const tabsWithFilterButton = hasFilters
595-
? (() => {
596-
const existing = tabs?.headerContent || tabs?.headerSlot || [];
597-
const newButton = (
598-
<button
599-
type="button"
600-
ref={setButtonRef}
601-
title="Filter"
602-
className={cn(
603-
'relative inline-flex items-center gap-2 rounded-md bg-transparent! hover:bg-transparent! px-3 py-1.5 text-sm hover:text-primary',
604-
showFilters ? 'text-primary' : 'text-muted-foreground'
605-
)}
606-
onClick={() => {
607-
if (activeFilterCount > 0) {
608-
setShowFilters((prev) => !prev);
609-
} else {
610-
setOpenSelectorSignal((s) => s + 1);
611-
}
612-
}}>
613-
<Funnel size={20} />
614-
{activeFilterCount > 0 && (
615-
<span className="absolute -top-1.5 -right-1.5 flex h-5 w-5 items-center justify-center rounded-full bg-primary text-[10px] font-medium text-primary-foreground">
616-
{activeFilterCount}
617-
</span>
618-
)}
619-
</button>
620-
);
621-
622-
return {
623-
...tabs,
624-
headerContent: [...existing, newButton]
625-
};
626-
})()
627-
: tabs;
594+
const filterButton = hasFilters ? (
595+
<button
596+
type="button"
597+
ref={setButtonRef}
598+
title="Filter"
599+
className={cn(
600+
'relative inline-flex items-center gap-2 rounded-md bg-transparent! hover:bg-transparent! px-3 py-1.5 text-sm hover:text-primary',
601+
showFilters ? 'text-primary' : 'text-muted-foreground'
602+
)}
603+
onClick={() => {
604+
if (activeFilterCount > 0) {
605+
setShowFilters((prev) => !prev);
606+
} else {
607+
setOpenSelectorSignal((s) => s + 1);
608+
}
609+
}}>
610+
<Funnel size={20} />
611+
{activeFilterCount > 0 && (
612+
<span className="absolute -top-1.5 -right-1.5 flex h-5 w-5 items-center justify-center rounded-full bg-primary text-[10px] font-medium text-primary-foreground">
613+
{activeFilterCount}
614+
</span>
615+
)}
616+
</button>
617+
) : null;
628618

629-
const resolvedTabsConfig = tabsWithFilterButton || tabs;
619+
const resolvedTabsConfig = hasFilters
620+
? {
621+
...tabs,
622+
headerContent: [...(tabs?.headerContent || tabs?.headerSlot || []), filterButton]
623+
}
624+
: tabs;
630625

631626
// Backward compatibility: prefer modern keys and fallback to deprecated aliases.
632627
const tabItems = resolvedTabsConfig?.items ?? resolvedTabsConfig?.tabs ?? [];
@@ -656,6 +651,39 @@ export function DataViews<Item>(props: DataViewsProps<Item>) {
656651
const afterSlotId = `${filterId}-after`;
657652

658653
const searchTerm = (view as View & { search?: string }).search ?? '';
654+
const [localSearch, setLocalSearch] = useState(searchTerm);
655+
const debounceRef = useRef<ReturnType<typeof setTimeout>>(null);
656+
657+
// Sync local state when the external view search changes (e.g. tab reset)
658+
useEffect(() => {
659+
setLocalSearch(searchTerm);
660+
}, [searchTerm]);
661+
662+
const handleSearchChange = useCallback(
663+
(value: string) => {
664+
setLocalSearch(value);
665+
if (debounceRef.current) {
666+
clearTimeout(debounceRef.current);
667+
}
668+
debounceRef.current = setTimeout(() => {
669+
handleViewChange({
670+
...view,
671+
search: value,
672+
page: 1
673+
} as View);
674+
}, 500);
675+
},
676+
[handleViewChange, view]
677+
);
678+
679+
// Cleanup timeout on unmount
680+
useEffect(() => {
681+
return () => {
682+
if (debounceRef.current) {
683+
clearTimeout(debounceRef.current);
684+
}
685+
};
686+
}, []);
659687

660688
const searchInput = search ? (
661689
<InputGroup className="md:w-64 md:min-w-64">
@@ -665,14 +693,8 @@ export function DataViews<Item>(props: DataViewsProps<Item>) {
665693
<InputGroupInput
666694
className="border-none!"
667695
placeholder={searchPlaceholder}
668-
value={searchTerm}
669-
onChange={(event) =>
670-
handleViewChange({
671-
...view,
672-
search: event.target.value,
673-
page: 1
674-
} as View)
675-
}
696+
value={localSearch}
697+
onChange={(event) => handleSearchChange(event.target.value)}
676698
/>
677699
</InputGroup>
678700
) : null;
@@ -793,6 +815,7 @@ export function DataViews<Item>(props: DataViewsProps<Item>) {
793815
</Fragment>
794816
)}
795817
</DataViewsTable>
818+
796819
<Slot name={afterSlotId} fillProps={{ ...filteredProps }} />
797820

798821
{/* Destructive action confirmation AlertDialog */}

src/components/wordpress/style.css

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55

66
.pui-root-dataviews:not(.custom-layout) {
77
border-radius: 6px;
8-
border: 1px solid var(--border);
8+
border: 1px solid var(--border, #E7E7E7);
99
box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.1019607843);
10-
background-color: var(--background);
11-
color: var(--foreground);
10+
background-color: var(--background, #FFFFFF);
11+
color: var(--foreground, #1D1D1D);
12+
}
13+
.pui-root-dataviews .dataviews-no-results {
14+
border-top: 1px solid var(--border, #E7E7E7);
1215
}
1316
.pui-root-dataviews:not(.custom-layout) .dataviews-wrapper {
1417
border-radius: 6px;
@@ -17,32 +20,32 @@
1720
border-left: none;
1821
border-right: none;
1922
border-top: none;
20-
background-color: var(--background);
23+
background-color: var(--background, #FFFFFF);
2124
}
2225
.pui-root-dataviews .dataviews-wrapper .dataviews-view-table thead {
2326
z-index: 0;
24-
background-color: var(--muted);
27+
background-color: var(--muted, #F5F5F5);
2528
}
2629
.pui-root-dataviews .dataviews-wrapper .dataviews-view-table thead th {
27-
color: var(--foreground);
28-
background-color: var(--background) !important;
30+
color: var(--foreground, #1D1D1D);
31+
background-color: var(--background, #FFFFFF) !important;
2932
}
30-
33+
3134
.pui-root-dataviews .dataviews-view-table .dataviews-view-table-header-button:not(:hover) {
32-
color: var(--foreground);
35+
color: var(--foreground, #1D1D1D);
3336
box-shadow: none;
3437
}
3538
.pui-root-dataviews .dataviews-wrapper .dataviews-view-table tbody tr {
36-
background-color: var(--background);
39+
background-color: var(--background, #FFFFFF);
3740
}
3841
.pui-root-dataviews .dataviews-wrapper .dataviews-view-table tbody tr.is-selected td,
3942
.pui-root-dataviews .dataviews-wrapper .dataviews-view-table tbody tr:hover td {
40-
background-color: var(--accent);
43+
background-color: var(--accent, #F5F5F5);
4144
}
4245
.pui-root-dataviews .dataviews-wrapper .dataviews-view-table tbody td {
43-
color: var(--foreground);
44-
border-bottom-color: var(--border);
45-
background-color: var(--background);
46+
color: var(--foreground, #1D1D1D);
47+
border-bottom-color: var(--border, #E7E7E7);
48+
background-color: var(--background, #FFFFFF);
4649
}
4750
.pui-root-dataviews .dataviews-wrapper .dataviews-view-table td,
4851
.pui-root-dataviews .dataviews-wrapper .dataviews-view-table th {
@@ -51,11 +54,11 @@
5154
border-right: none;
5255
}
5356
.pui-root-dataviews .dataviews-wrapper .dataviews-view-table tr {
54-
border-color: var(--border);
57+
border-color: var(--border, #E7E7E7);
5558
}
5659
.pui-root-dataviews .dataviews-wrapper .dataviews-pagination .components-input-control__container {
57-
background-color: var(--background);
58-
color: var(--foreground);
60+
background-color: var(--background, #FFFFFF);
61+
color: var(--foreground, #1D1D1D);
5962
}
6063
.pui-root-dataviews .dataviews-wrapper .dataviews-pagination {
6164
width: 100%;
@@ -88,38 +91,38 @@
8891
width: 100%;
8992
justify-content: space-between;
9093
padding: 15px 20px;
91-
background-color: var(--background);
92-
color: var(--foreground);
94+
background-color: var(--background, #FFFFFF);
95+
color: var(--foreground, #1D1D1D);
9396
}
9497
.pui-root-dataviews .dataviews-wrapper .dataviews-bulk-actions-footer__action-buttons {
9598
gap: 10px;
9699
}
97100
.pui-root-dataviews .dataviews-wrapper .dataviews-bulk-actions-footer__action-buttons .components-button.is-compact:not(:last-child) {
98-
border: 1px solid var(--border);
101+
border: 1px solid var(--border, #E7E7E7);
99102
border-radius: 6px;
100103
line-height: 1;
101104
}
102105
/* DataViews list view theming */
103106
.pui-root-dataviews .dataviews-view-list {
104-
background-color: var(--background);
107+
background-color: var(--background, #FFFFFF);
105108
}
106109
.pui-root-dataviews .dataviews-view-list [role="row"],
107110
.pui-root-dataviews .dataviews-view-list [role="article"] {
108-
background-color: var(--background);
109-
border-color: var(--border);
111+
background-color: var(--background, #FFFFFF);
112+
border-color: var(--border, #E7E7E7);
110113
}
111114
.pui-root-dataviews .dataviews-loading {
112115
padding: 50px;
113116
}
114117
.pui-root-dataviews .dataviews-view-table.has-bulk-actions tr.is-selected td.dataviews-view-table__actions-column,
115118
.pui-root-dataviews .dataviews-view-table.has-bulk-actions tr:hover td.dataviews-view-table__actions-column {
116-
background-color: var(--accent);
119+
background-color: var(--accent, #F5F5F5);
117120
}
118-
.pui-root-dataviews .dataviews-wrapper .dataviews-pagination .components-button svg,
121+
.pui-root-dataviews .dataviews-wrapper .dataviews-pagination .components-button svg,
119122
.pui-root-dataviews .dataviews-view-table__actions-column .components-button svg {
120-
fill: var(--foreground);
123+
fill: var(--foreground, #1D1D1D);
121124
}
122125
.pui-root-dataviews .dataviews-wrapper .dataviews-bulk-actions-footer__container .components-button,
123126
.pui-root-dataviews .dataviews-wrapper .dataviews-bulk-actions-footer__item-count {
124-
color: var(--foreground);
127+
color: var(--foreground, #1D1D1D);
125128
}

0 commit comments

Comments
 (0)