diff --git a/src/components/TableFilters/TableFilters.md b/src/components/TableFilters/TableFilters.md index e1b95d3c..f1b26456 100644 --- a/src/components/TableFilters/TableFilters.md +++ b/src/components/TableFilters/TableFilters.md @@ -1,184 +1,91 @@ The TableFilters component is supposed to be used with `Table` to provide actions, search input and filter controllers for the table. It's not included in the Table component for flexibility in how to layout them in your pages. You could have one TableFilters control the filters and search for multiple tables for example. -Using it is pretty simple, the props `actions`, `search` and `filters` are responsible for handling what will be displayed, as seen below. +Using it is pretty simple, inside the `TableFilters` component, use one `TableFilters.Item` for each item, and inside the `Item` you can use a `Button`, `Input`, `Selector` or whatever you need. -### Props -#### actions - -The `actions` prop is where the actions shown are defined. It receives an array of objects in the format: - -```js static -{ - label: string - color?: string - variant?: string - disabled?: boolean - onClick: function -} -``` - -##### label - -- The text that will be shown on the button of the action - -##### color - -- The color of the button, defaults to `primary` - -##### variant - -- The button variant, defaults to `filled` - -##### disabled - -- True if the button is disabled, defaults to `false` - -##### onClick - -- The callback function to be called when the button is clicked - -#### filters and onFilterChange - -The `filters` prop is where the filters shown are defined. It receives an array of objects in the format: - -```js static -{ - key: string - label?: string - value?: string - options: Array<{ - label: string - value: string | number - }> -} -``` - -##### key - -- The key for this filter. When this filter changes it will be passed to the `onFilterChange` callback along with the new value -- Usually you want this to be the name of the property in your data that this filter will filter by (e.g. a filter select for the status of a patient would use `status` as the key, if that is the name of the property where the status is stored in the patient data object) +### TableFilters.Item Props ##### label -- The Select label - -##### value - -- The controlled value of the `Select` - -##### options - -- An array of objects for the options of the Select -- For more information see the `Selector` component - -##### onFilterChange - -- This is the callback that will be called when there's a change in any of the Select components -- It's called with the changed filter `key` and the new `value` - -#### search, hideSearch and onSearchChange - -The `search` prop is where the input props are defined. It receives an object in the format: - -```js static -{ - placeholder: string - value: string - minWidth?: number -} -``` - -##### placeholder - -- The input placeholder text - -##### value - -- The controlled value of the input +- The text that will be shown next to the item ##### minWidth -- The minimum width this input can shrink to. Defaults to `200` (px) -- The input tries to occupy all the remaining space in the line, but can only shrink up to this size, if necessary the filters will wrap into a new line to give space to the input - -##### hideSearch - -- A boolean used to hide the search input +- The minimum width the Item should have, in case it needs to shrink due to not enough space on screen. -##### onSearchChange +##### grows -- This is the callback that will be called when there's a change in the input -- It's called with the new `value` of the input +- A boolean signaling if the Item should grow to fill the screen or not. Defaults to false. ### Example ```jsx - alert("new study"), - }, - ]} - search={{ - placeholder: "Search studies by ID, patient or doctor", - }} - filters={[ - { - key: "status", - label: "Study status", - options: [ +import { Button, Selector, Input } from '../'; + + + + + + + + + + + + + + ]} + /> + + ``` Without a search input ```jsx - alert("new study"), - }, - ]} - hideSearch - filters={[ - { - key: "status", - label: "Study status", - options: [ +import { Button, Selector } from '../'; + + + + + + + + + + + + ]} + /> + + ``` diff --git a/src/components/TableFilters/TableFilters.stories.tsx b/src/components/TableFilters/TableFilters.stories.tsx index 27a81192..22fd8196 100644 --- a/src/components/TableFilters/TableFilters.stories.tsx +++ b/src/components/TableFilters/TableFilters.stories.tsx @@ -1,7 +1,10 @@ import React from "react" import TableFilters, { TableFiltersProps } from "./TableFilters" import { Meta, Story } from "@storybook/react/types-6-0" -import { action } from "@storybook/addon-actions" +// import { action } from "@storybook/addon-actions" +import Button from "../Button/Button" +import Selector from "../Selector/Selector" +import Input from "../Input/Input" export default { title: "Design System/TableFilters", @@ -15,66 +18,116 @@ const Template: Story = (props) => ( // Each story then reuses that template export const Example = Template.bind({}) Example.args = { - actions: [ - { - label: "New Study", - onClick: action("newStudy"), - }, - ], - search: { - placeholder: "Search studies by ID, patient or doctor", - }, - filters: [ - { - key: "status", - label: "Study status", - options: [ - { value: "all", label: "All" }, - { value: "active", label: "Active" }, - { value: "inactive", label: "Inactive" }, - { value: "pending", label: "Pending" }, - ], - }, - { - key: "type", - label: "Study type", - options: [ - { value: "all", label: "All" }, - { value: "inactive", label: "Inactive" }, - { value: "pending", label: "Pending" }, - ], - }, - ], + children: ( + + + + + + + + + + + + + + + ), } export const WithoutSearch = Template.bind({}) WithoutSearch.args = { - actions: [ - { - label: "New Study", - onClick: action("newStudy"), - }, - ], - hideSearch: true, - filters: [ - { - key: "status", - label: "Study status", - options: [ - { value: "all", label: "All" }, - { value: "active", label: "Active" }, - { value: "inactive", label: "Inactive" }, - { value: "pending", label: "Pending" }, - ], - }, - { - key: "type", - label: "Study type", - options: [ - { value: "all", label: "All" }, - { value: "inactive", label: "Inactive" }, - { value: "pending", label: "Pending" }, - ], - }, - ], + children: ( + + + + + + + + + + + + + ), +} + +export const CustomOrder = Template.bind({}) +CustomOrder.args = { + children: ( + + + + + + + + + + + + + + + + + + + + + ), } diff --git a/src/components/TableFilters/TableFilters.tsx b/src/components/TableFilters/TableFilters.tsx index f47203dc..6c65d7e0 100644 --- a/src/components/TableFilters/TableFilters.tsx +++ b/src/components/TableFilters/TableFilters.tsx @@ -1,67 +1,52 @@ /** @jsxRuntime classic / /** @jsx jsx */ -import React from "react" +import React, { HTMLAttributes } from "react" import { jsx } from "theme-ui" -import Selector, { SelectorProps } from "../Selector/Selector" -import Button, { ButtonProps } from "../Button/Button" -import Input, { InputProps } from "../Input/Input" -export interface TableFiltersProps { - /** Actions */ - actions?: Array<{ - /** Button label */ - label: string - /** Button color */ - color?: ButtonProps["color"] - /** Button variant */ - variant?: ButtonProps["variant"] - /** Button disabled */ - disabled?: boolean - /** Callback on action button click */ - onClick: () => void - // icon?: string - }> - - /** Search input options */ - search?: { - /** Search input placeholder */ - placeholder?: InputProps["placeholder"] - /** Search input value */ - value?: InputProps["value"] - /** Search input min width. Input grows to fill remaining width, but shrinks when there are multiple filters, this prop sets the minimum width it can shrink to. Defaults to 200px */ - minWidth?: number - } - hideSearch?: boolean - onSearchChange?: (value: string) => void +const Item = ({ + label, + children, + className, + minWidth, + grows = false, +}: { + label?: string + children?: React.ReactNode + className?: HTMLAttributes["className"] + minWidth?: number + grows?: boolean +}) => { + return ( +
+ {label && ( +
+ {label} +
+ )} + {children} +
+ ) +} - /** Filters */ - filters?: Array<{ - /** Filter key */ - key: string - /** Label for the filter Select component */ - label?: string - /** Value for the filter Select component */ - value?: string - /** Default value for the filter Select component */ - defaultValue?: string - /** Options for the filter Select component */ - options: SelectorProps["options"] - }> - onFilterChange?: ({ key, value }: { key: string; value?: string }) => void +export interface TableFiltersProps { + children: React.ReactNode } -const TableFilters = ({ - filters = [], - actions = [], - onFilterChange, - hideSearch = false, - search: { - placeholder = "", - value: searchValue, - minWidth: searchMinWidth = 200, - } = {}, - onSearchChange, -}: TableFiltersProps) => { +const TableFilters = ({ children }: TableFiltersProps) => { return (
- {actions && - actions.map( - ( - { - label, - color = "primary", - variant = "filled", - disabled = false, - onClick, - }, - index - ) => ( -
- -
- ) - )} - -
- {!hideSearch && ( - onSearchChange?.(event.target.value)} - /> - )} -
- - {filters && - filters.map(({ key, options, label, value, defaultValue }, index) => ( -
- - onFilterChange?.({ - key, - value: selectedItem?.toString() || undefined, - }) - } - /> -
- ))} + {children}
) } +TableFilters.Item = Item + export default TableFilters diff --git a/src/tests/__image_snapshots__/storyshots-test-ts-image-storyshots-design-system-table-filters-custom-order-1-snap.png b/src/tests/__image_snapshots__/storyshots-test-ts-image-storyshots-design-system-table-filters-custom-order-1-snap.png new file mode 100644 index 00000000..042dc2d5 Binary files /dev/null and b/src/tests/__image_snapshots__/storyshots-test-ts-image-storyshots-design-system-table-filters-custom-order-1-snap.png differ diff --git a/src/tests/__image_snapshots__/storyshots-test-ts-image-storyshots-design-system-table-filters-example-1-snap.png b/src/tests/__image_snapshots__/storyshots-test-ts-image-storyshots-design-system-table-filters-example-1-snap.png index cc26ba84..1b7de246 100644 Binary files a/src/tests/__image_snapshots__/storyshots-test-ts-image-storyshots-design-system-table-filters-example-1-snap.png and b/src/tests/__image_snapshots__/storyshots-test-ts-image-storyshots-design-system-table-filters-example-1-snap.png differ diff --git a/src/tests/__image_snapshots__/storyshots-test-ts-image-storyshots-design-system-table-filters-without-search-1-snap.png b/src/tests/__image_snapshots__/storyshots-test-ts-image-storyshots-design-system-table-filters-without-search-1-snap.png index 90eaa862..b068128f 100644 Binary files a/src/tests/__image_snapshots__/storyshots-test-ts-image-storyshots-design-system-table-filters-without-search-1-snap.png and b/src/tests/__image_snapshots__/storyshots-test-ts-image-storyshots-design-system-table-filters-without-search-1-snap.png differ