Release v2.1.0
Extracts the filter UI from PivotViewer into a generic, standalone FilterPanel component that can be used independently of any data viewer.
Added
Source/Filter/module: standaloneFilterPanel,FilterEditor,RangeHistogramFilter,useFilterStatehook, and full TypeScript type definitions (FilterDefinition,FilterEditorProps,FilterEditorSlotProps,FilterValues,RangeValues,CustomFilterValues) (#102)FilterEditorslot component — declares a custom editor for a specific filter group as a declarative child of<FilterPanel>; value tracked separately incustomValues(#102)type: 'custom'filter type as an explicit opt-in for fully custom filter editors (#102)- 5 Storybook stories for
FilterPanel: single-select, multi-select, numeric range/histogram, custom editor, and mixed filter types (#102) ./Filtersubpath export inpackage.jsonfor direct imports via@cratis/components/Filter(#102)Documentation/Filter/index.md— full API reference covering all exported types,FilterPanelprops,FilterEditorprops,useFilterStatehook, and usage examples for every filter type (#102)- BDD specs in
Source/Filter/for_useFilterState/coveringbuildFilterValuesandbuildRangeValues— 9 tests across 4 spec files (#102) Source/Filter/utils.tsexportingbuildFilterValuesandbuildRangeValuesas pure, testable utility functions (#102)
Changed
FilterPanelacceptschildren?: ReactNode— usesReact.Children+isValidElementto discover<FilterEditor>slots and render them in the matching filter group (#102)PivotViewer/components/FilterPanel.tsxis now a thin adapter: convertsPivotFilter<TItem>[]+ computed options intoFilterDefinition[], generates<FilterEditor>children from anyPivotFilter.renderEditor, and delegates all rendering to the new standalone component — no breaking changes to the public API (#102)PivotFilter<TItem>retainsrenderEditor?andtype: 'custom'so PivotViewer consumers can inject custom filter editors without any workarounds (#102)Source/Filter/useFilterState.tsnow importsbuildFilterValuesandbuildRangeValuesfrom./utils(#102)Documentation/toc.ymlupdated with Filter entries in both the Storybook section and Common Components section (#102)eslint.config.mjs— addedargsIgnorePattern: '^_'to the@typescript-eslint/no-unused-varsrule to honour the_-prefix convention for intentionally unused parameters (#102)
Fixed
- Storybook static build (
storybook build) now completes successfully — fixed a pre-existing[lightningcss minify] Invalid empty selectorcrash by addingcssMinify: falseto theviteFinalconfig inSource/.storybook/main.ts(#102) - CI build failure caused by ESLint flagging
_propsinFilterEditor.tsxas unused — resolved by addingargsIgnorePattern: '^_'to the ESLint rule config (#102)
Usage — custom editor in standalone context:
import { FilterPanel, FilterEditor, useFilterState } from '@cratis/components/Filter';
const filters: FilterDefinition[] = [
{ key: 'score', label: 'Score', type: 'custom' },
];
function MyView() {
const state = useFilterState(filters);
const buttonRef = useRef<HTMLButtonElement>(null);
return (
<>
<button ref={buttonRef}>Filters</button>
<FilterPanel
isOpen={open}
filters={filters}
anchorRef={buttonRef}
customValues={state.customValues}
onCustomValueChange={state.handleCustomValueChange}
onFilterToggle={state.handleToggleFilter}
onFilterClear={state.handleClearFilter}
onRangeChange={state.handleRangeChange}
onExpandedFilterChange={state.setExpandedFilterKey}
onClose={() => setOpen(false)}
{...state}
>
<FilterEditor filterKey="score">
{({ value, onChange }) => (
<MySlider value={value as number} onChange={onChange} />
)}
</FilterEditor>
</FilterPanel>
</>
);
}