-
+
+ {Object.values(filterState).map((filter) => (
+
+ ))}
+ {Object.keys(filterState).length > 0 ? (
+
+ ) : null}
)
}
diff --git a/packages/design-system/ui/src/blocks/data-table/components/data-table-filter-menu.tsx b/packages/design-system/ui/src/blocks/data-table/components/data-table-filter-menu.tsx
index 07e02019796c3..6ed6d19e16f96 100644
--- a/packages/design-system/ui/src/blocks/data-table/components/data-table-filter-menu.tsx
+++ b/packages/design-system/ui/src/blocks/data-table/components/data-table-filter-menu.tsx
@@ -13,20 +13,33 @@ export interface DataTableFilterMenuProps {
const DataTableFilterMenu = ({ tooltip }: DataTableFilterMenuProps) => {
const { instance } = useDataTableContext()
+ const enabledFilters = Object.keys(instance.getFiltering())
+
+ const filterOptions = instance
+ .getFilterOptions()
+ .filter((filter) => !enabledFilters.includes(filter.id))
+
const Wrapper = tooltip ? Tooltip : React.Fragment
return (
-
-
+
+
- {instance.getFilterOptions().map((filter) => (
- {filter.label}
+ {filterOptions.map((filter) => (
+ {
+ instance.addFilter({ id: filter.id, value: undefined })
+ }}
+ >
+ {filter.label}
+
))}
diff --git a/packages/design-system/ui/src/blocks/data-table/components/data-table-filter.tsx b/packages/design-system/ui/src/blocks/data-table/components/data-table-filter.tsx
index 93bc2cd4c0e4a..931334a173330 100644
--- a/packages/design-system/ui/src/blocks/data-table/components/data-table-filter.tsx
+++ b/packages/design-system/ui/src/blocks/data-table/components/data-table-filter.tsx
@@ -1,9 +1,34 @@
import { XMark } from "@medusajs/icons"
+import { ColumnFilter } from "@tanstack/react-table"
import * as React from "react"
import { DropdownMenu } from "../../../components/dropdown-menu"
import { clx } from "../../../utils/clx"
+import { useDataTableContext } from "../context/use-data-table-context"
+
+interface DataTableFilterProps {
+ filter: ColumnFilter
+ label: string
+}
+
+const DataTableFilter = ({ filter, label }: DataTableFilterProps) => {
+ const { instance } = useDataTableContext()
+ const [open, setOpen] = React.useState(filter.value === undefined)
+
+ const onOpenChange = React.useCallback(
+ (open: boolean) => {
+ if (!open && !filter.value) {
+ instance.removeFilter(filter.id)
+ }
+
+ setOpen(open)
+ },
+ [instance, filter.id, filter.value]
+ )
+
+ const removeFilter = React.useCallback(() => {
+ instance.removeFilter(filter.id)
+ }, [instance, filter.id])
-const DataTableFilter = () => {
return (
{
"[&>*]:txt-compact-small-plus [&>*]:flex [&>*]:items-center [&>*]:justify-center"
)}
>
-
Filter
-
+
{label}
+
@@ -25,11 +55,17 @@ const DataTableFilter = () => {
interface DataTableFilterMenuProps {
label: string
+ open: boolean
+ onOpenChange: (open: boolean) => void
}
-const DataTableFilterMenu = ({ label }: DataTableFilterMenuProps) => {
+const DataTableFilterMenu = ({
+ label,
+ open,
+ onOpenChange,
+}: DataTableFilterMenuProps) => {
return (
-
+
{label}
diff --git a/packages/design-system/ui/src/blocks/data-table/data-table.stories.tsx b/packages/design-system/ui/src/blocks/data-table/data-table.stories.tsx
index 1f2740c9e9c3a..35403efaab5f4 100644
--- a/packages/design-system/ui/src/blocks/data-table/data-table.stories.tsx
+++ b/packages/design-system/ui/src/blocks/data-table/data-table.stories.tsx
@@ -3,7 +3,7 @@ import * as React from "react"
import { Container } from "@/components/container"
import { PencilSquare, Trash } from "@medusajs/icons"
-import { RowSelectionState } from "@tanstack/react-table"
+import { ColumnFilter, RowSelectionState } from "@tanstack/react-table"
import { Button } from "../../components/button"
import { Heading } from "../../components/heading"
import { TooltipProvider } from "../../components/tooltip"
@@ -23,6 +23,7 @@ export default meta
type Story = StoryObj
type Person = {
+ id: string
name: string
email: string
age: number
@@ -32,6 +33,7 @@ type Person = {
const data: Person[] = [
{
+ id: "1",
name: "John Doe",
email: "john.doe@example.com",
age: 20,
@@ -39,6 +41,7 @@ const data: Person[] = [
relationshipStatus: "single",
},
{
+ id: "2",
name: "Jane Doe",
email: "jane.doe@example.com",
age: 25,
@@ -46,6 +49,7 @@ const data: Person[] = [
relationshipStatus: "married",
},
{
+ id: "3",
name: "John Smith",
email: "john.smith@example.com",
age: 30,
@@ -53,6 +57,7 @@ const data: Person[] = [
relationshipStatus: "divorced",
},
{
+ id: "4",
name: "Jane Smith",
email: "jane.smith@example.com",
age: 35,
@@ -60,6 +65,7 @@ const data: Person[] = [
relationshipStatus: "widowed",
},
{
+ id: "5",
name: "Mike Doe",
email: "mike.doe@example.com",
age: 40,
@@ -67,6 +73,7 @@ const data: Person[] = [
relationshipStatus: "single",
},
{
+ id: "6",
name: "Emily Smith",
email: "emily.smith@example.com",
age: 45,
@@ -74,6 +81,7 @@ const data: Person[] = [
relationshipStatus: "married",
},
{
+ id: "7",
name: "Sam Doe",
email: "sam.doe@example.com",
age: 50,
@@ -236,6 +244,9 @@ const BasicDemo = () => {
const [sorting, setSorting] = React.useState(
null
)
+ const [filtering, setFiltering] = React.useState<
+ Record
+ >({})
const { data, count } = usePeople({ q: debouncedSearch, order: sorting })
@@ -243,7 +254,12 @@ const BasicDemo = () => {
data,
columns,
count,
+ getRowId: (row) => row.id,
filters,
+ filtering: {
+ state: filtering,
+ onFilteringChange: setFiltering,
+ },
rowSelection: {
state: rowSelection,
onRowSelectionChange: setRowSelection,
diff --git a/packages/design-system/ui/src/blocks/data-table/use-data-table.tsx b/packages/design-system/ui/src/blocks/data-table/use-data-table.tsx
index 4b97d3dc60f56..8ce24fda89d80 100644
--- a/packages/design-system/ui/src/blocks/data-table/use-data-table.tsx
+++ b/packages/design-system/ui/src/blocks/data-table/use-data-table.tsx
@@ -1,4 +1,5 @@
import {
+ ColumnFilter,
ColumnFiltersState,
type ColumnSort,
getCoreRowModel,
@@ -16,8 +17,8 @@ interface DataTableOptions
extends Pick, "data" | "columns" | "getRowId"> {
filters?: DataTableFilter[]
filtering?: {
- state: ColumnFiltersState
- onFilteringChange: (state: ColumnFiltersState) => void
+ state: Record
+ onFilteringChange: (state: Record) => void
}
rowSelection?: {
state: RowSelectionState
@@ -53,7 +54,11 @@ interface UseDataTableReturn
| ((prev: DataTableSortingState | null) => DataTableSortingState)
) => void
getFilterOptions: () => DataTableFilter[]
- getFiltering: () => ColumnFiltersState
+ getFiltering: () => Record
+ addFilter: (filter: ColumnFilter) => void
+ removeFilter: (id: string) => void
+ clearFilters: () => void
+ updateFilter: (filter: ColumnFilter) => void
}
const useDataTable = ({
@@ -99,7 +104,7 @@ const useDataTable = ({
state: {
rowSelection: rowSelection?.state,
sorting: sorting?.state ? [sorting.state] : undefined,
- columnFilters: filtering?.state,
+ columnFilters: Object.values(filtering?.state ?? {}),
},
onColumnFiltersChange: filteringStateHandler(),
onRowSelectionChange: rowSelectionStateHandler(),
@@ -134,9 +139,37 @@ const useDataTable = ({
}, [options.filters])
const getFiltering = React.useCallback(() => {
- return instance.getState().columnFilters ?? []
+ const state = instance.getState().columnFilters ?? []
+ return Object.fromEntries(state.map((filter) => [filter.id, filter]))
}, [instance])
+ const addFilter = React.useCallback(
+ (filter: ColumnFilter) => {
+ filtering?.onFilteringChange?.({ ...getFiltering(), [filter.id]: filter })
+ },
+ [filtering?.onFilteringChange, getFiltering]
+ )
+
+ const removeFilter = React.useCallback(
+ (id: string) => {
+ const currentFilters = getFiltering()
+ delete currentFilters[id]
+ filtering?.onFilteringChange?.(currentFilters)
+ },
+ [filtering?.onFilteringChange, getFiltering]
+ )
+
+ const clearFilters = React.useCallback(() => {
+ filtering?.onFilteringChange?.({})
+ }, [filtering?.onFilteringChange])
+
+ const updateFilter = React.useCallback(
+ (filter: ColumnFilter) => {
+ addFilter(filter)
+ },
+ [addFilter]
+ )
+
return {
// Table
getHeaderGroups: instance.getHeaderGroups,
@@ -157,6 +190,10 @@ const useDataTable = ({
// Filtering
getFilterOptions,
getFiltering,
+ addFilter,
+ removeFilter,
+ clearFilters,
+ updateFilter,
}
}
@@ -190,16 +227,20 @@ function onRowSelectionChangeTransformer(
}
function onFilteringChangeTransformer(
- onFilteringChange: (state: ColumnFiltersState) => void,
- state?: ColumnFiltersState
+ onFilteringChange: (state: Record