From fdf96ad63f13df2e0eabca1cb38f0c5f0c4c0de6 Mon Sep 17 00:00:00 2001 From: Marco Schumacher Date: Tue, 15 Mar 2022 15:14:07 +0100 Subject: [PATCH] fix: Added some missing exports and props documentation. --- src/components/dateFilter.tsx | 3 +++ src/components/datePicker.tsx | 8 ++++++++ src/components/selectFilter.tsx | 4 ++++ src/components/textFilter.tsx | 5 ++++- src/hooks/useFilter.ts | 2 +- src/index.ts | 4 +++- src/types.ts | 35 +++++++++++++++++++++++---------- 7 files changed, 48 insertions(+), 13 deletions(-) diff --git a/src/components/dateFilter.tsx b/src/components/dateFilter.tsx index 9312ff1..598a7b2 100644 --- a/src/components/dateFilter.tsx +++ b/src/components/dateFilter.tsx @@ -32,8 +32,11 @@ export function DateFilter({ filterBy = convertDateOrArray, ...props }: { + /** Which locale to use to render the calendar. */ locale?: string; + /** Which day of the week should be in the first column. */ firstDayOfWeek?: DatePickerProps['firstDayOfWeek']; + /** If enabled, only single days can be selected. Ranges otherwise. */ singleSelect?: boolean; } & CommonFilterProps): JSX.Element { const { diff --git a/src/components/datePicker.tsx b/src/components/datePicker.tsx index 96902ad..4c5d299 100644 --- a/src/components/datePicker.tsx +++ b/src/components/datePicker.tsx @@ -7,20 +7,28 @@ import { useCssVariables } from '../theme/useCssVariables'; export type DateRange = { min: Date; max: Date }; export type DatePickerProps = { + /** Currently selected day or range of days. */ value: Date | DateRange | null; + /** Callback for when the day (range) changes. */ onChange: (value: Date | DateRange | null) => void; + /** If enabled, ranges can be selected. */ rangeSelect?: boolean; + /** Which locale to use to render the calendar. */ locale?: string; + /** Which day of the week should be in the first column. */ firstDayOfWeek?: 0 | 1 | 2 | 3 | 4 | 5 | 6; }; const weekDays = [0, 1, 2, 3, 4, 5, 6] as const; const months = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] as const; +/** Rounds a date down to the start of the day. */ export const startOfDay = (d: Date) => new Date(d.getFullYear(), d.getMonth(), d.getDate()); +/** Rounds a date up to the end of the day. */ export const endOfDay = (d: Date) => new Date(d.getFullYear(), d.getMonth(), d.getDate() + 1, 0, 0, 0, -1); +/** Returns whether two dates and/or date ranges intersect. Intersection is considered per day. */ export function dateIntersect(a: Date | null | DateRange, b: Date | null | DateRange) { if (a instanceof Date) { a = { min: a, max: a }; diff --git a/src/components/selectFilter.tsx b/src/components/selectFilter.tsx index 1848764..25d211b 100644 --- a/src/components/selectFilter.tsx +++ b/src/components/selectFilter.tsx @@ -24,9 +24,13 @@ export function SelectFilter({ singleSelect, ...props }: { + /** Which options are provided to select. By default all unique item values are used. */ options?: F[]; + /** String representation of a value. Used to filter options via the text field. */ stringValue?: (value: F) => string; + /** Render values. By default a string representation of the value is used. */ render?: (value: F) => ReactNode; + /** If enabled, only one option can be selected at a time. */ singleSelect?: boolean; } & CommonFilterProps>): JSX.Element { const { diff --git a/src/components/textFilter.tsx b/src/components/textFilter.tsx index a248ffd..478ceb5 100644 --- a/src/components/textFilter.tsx +++ b/src/components/textFilter.tsx @@ -11,7 +11,10 @@ export function TextFilter({ filterBy = asStringOrArray, ...props }: { - compare?: (a: string, b: string) => boolean; + /** Custom comparison function. Should return true if an item value matches the current filter value. + * By default a fuzzy text comparison is used. + */ + compare?: (itemValue: string, filterValue: string) => boolean; } & CommonFilterProps): JSX.Element { const { components: { IconButton }, diff --git a/src/hooks/useFilter.ts b/src/hooks/useFilter.ts index 471f879..dd3adb0 100644 --- a/src/hooks/useFilter.ts +++ b/src/hooks/useFilter.ts @@ -32,7 +32,7 @@ export function useFilter(impl: FilterImpl state.filters.delete(columnId); }); }; - }, [table, columnId, ...(impl.dependencies ?? [impl])]); + }, [table, columnId, impl]); // Track local value and update it globally after delay const value = table.useState((state) => state.filterValues.get(columnId) as S | undefined); diff --git a/src/index.ts b/src/index.ts index 7ab12dc..e23d76b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,7 @@ export { AutoFocusTextField } from './components/autoFocusTextField'; export { DateFilter } from './components/dateFilter'; +export { dateIntersect, DatePicker, endOfDay, startOfDay } from './components/datePicker'; +export type { DatePickerProps, DateRange } from './components/datePicker'; export { SelectFilter } from './components/selectFilter'; export { ColumnContext, Table, TableContext, useColumnContext, useTableContext } from './components/table'; export { TextFilter } from './components/textFilter'; @@ -8,4 +10,4 @@ export { useTheme } from './hooks/useTheme'; export type { TableStateStorage } from './internalState/tableStateStorage'; export { termMatch, textMatch } from './misc/textMatch'; export { configureTableTheme, mergeThemes, TableThemeContext, TableThemeProvider } from './theme/tableTheme'; -export type { Column, Id, InternalColumn, PartialTableTheme, Rows, Sort, SortDirection, TableProps } from './types'; +export type { Column, Id, InternalColumn, PartialTableTheme, Sort, SortDirection, TableProps } from './types'; diff --git a/src/types.ts b/src/types.ts index a42a059..a6dbbb9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,5 +1,5 @@ import { CSSInterpolation } from '@emotion/serialize'; -import React, { ComponentType, CSSProperties, ReactNode, Ref } from 'react'; +import React, { ComponentType, ReactNode, Ref } from 'react'; import { TableStateStorage } from './internalState/tableStateStorage'; import { CsvExportOptions } from './misc/csvExport'; @@ -232,22 +232,30 @@ export type InternalTableProps = Omit, 'id' | 'parentId' | 'col export type TableItem = T & { id: Id; parentId?: Id; children: TableItem[] }; export type Column = { + /** Column id. If not provided, the index in the column array will be used. + * An explicit id is better however for controlling column related states, persitance etc. + */ id?: string; + /** Render table header for this column. */ header?: ReactNode; + /** Extract value for this column */ value: (item: T) => V; + /** Render table cell. If not provided, a string representation of the value will be rendered. */ renderCell?: (value: V, item: T) => ReactNode; + /** Serialize column value for exports. If not provided, a string representation of the value will be used. */ exportCell?: (value: V, item: T) => string | number; + /** Customize sort criteria. By default it will be the value itself in case it's a number or Date, or a string representation of the value otherwise. */ sortBy?: ((value: V, item: T) => unknown) | ((value: V) => unknown)[]; - + /** Set filter component that will be displayed in the column header */ filter?: ReactNode; - + /** Prevent hiding the column. */ cannotHide?: boolean; - + /** Specify a css width. + * @default 'max-content' + */ width?: string; - justifyContent?: CSSProperties['justifyContent']; - + /** Provide css class names to override columns styles. */ classes?: TableTheme['classes']; - /** If the column definition changes, supply parameters that it depends on. If not set, the column will not update */ dependencies?: any[]; }; @@ -260,8 +268,6 @@ type Required = T & { [P in keyof T as P extends S ? P : never]-?: T[P]; }; -export type Rows = [{ value: V; item: T }, ...{ value: V; item: T }[]]; - export type InternalTableState = { // Basically the passed in props, but normalized props: InternalTableProps; @@ -289,17 +295,26 @@ export type InternalTableState = { }; export type CommonFilterProps = { + /** Filter by? By default the column value will be used. If filterBy returns an array, an items will be active if at least one entry matches the active filter. */ filterBy?: (value: V, item: T) => F | F[]; + /** Preselected filter value. */ defaultValue?: S; + /** Controlled filter value. */ value?: S; + /** Notifies on filter change. */ onChange?: (value?: S) => void; - dependencies?: any[]; + /** Whether to persist filter value (given that filter persitance is enabled for the table). + * @default true + */ persist?: boolean; }; export type FilterImplementation = CommonFilterProps & { + /** Unique filter id. Used to persist filter values. */ id: string; + /** Whether the filter is active currently. */ isActive: (filterValue: S) => boolean; + /** When the filter is active, this function is used to filter the items to be displayed. */ test: (filterValue: S, value: F) => boolean; };