Customizing Data Input
This guide demonstrates how to customize the data input view in your Filter Sphere components using a custom theme.
Overriding the Default Data Input View
In this example, we will create a custom boolean input view and override the default boolean input view.
import { type DataInputViewSpec, useFilterSphere, FilterSphereProvider, FilterBuilder, createFilterTheme,} from "@fn-sphere/filter";import { z } from "zod";
const schema = z.object({ active: z.boolean(), id: z.number(),});
// Define a custom input componentconst booleanInput: DataInputViewSpec = { name: "boolean", // The data type that this input component can handle match: [z.boolean()], view: ({ rule, updateInput }) => { return ( <input type="checkbox" value={!!rule.args?.[0]} onChange={(e) => { const value = e.target.checked; updateInput(value); }} /> ); },};
const customTheme = createFilterTheme({ // Add the custom input component to the list of data input views dataInputViews: [booleanInput],});
export default function CustomDataInput() { const { filterRule, predicate, context } = useFilterSphere({ schema }); return ( <FilterSphereProvider context={context} theme={customTheme}> <FilterBuilder /> </FilterSphereProvider> );}
Creating a Custom Data Input View
Sometimes you may want to create a custom input view for a specific data type. You can create a custom input view by defining a custom input component and adding it to the list of data input views in the theme.
X:Y:
import { type DataInputViewSpec, useFilterSphere, FilterSphereProvider, FilterBuilder, createFilterTheme, presetFilter, defineTypedFn,} from "@fn-sphere/filter";import { z } from "zod";
const pointSchema = z.object({ x: z.number(), y: z.number(),});
const schema = z.object({ point: pointSchema,});
// Define a custom input componentconst pointInput: DataInputViewSpec = { name: "point", // The data type that this input component can handle match: [pointSchema], view: ({ rule, updateInput }) => { const point = rule.args[0] ?? { x: 0, y: 0 }; return ( <> <span>X:</span> <input onChange={(e) => { const value = e.target.value; updateInput({ x: value, y: point.y, }); }} style={{ width: "50px" }} /> <span>Y:</span> <input onChange={(e) => { const value = e.target.value; updateInput({ x: point.x, y: value, }); }} style={{ width: "50px" }} /> </> ); },};
// Define a custom filter function for the point data typeconst pointFilter = defineTypedFn({ name: "equals", define: z.function().args(pointSchema, pointSchema).returns(z.boolean()), implement: (value, userInput) => { return value.x === userInput.x && value.y === userInput.y; },});
const customTheme = createFilterTheme({ // Add the custom input component to the list of data input views dataInputViews: [pointInput],});
export default function CustomDataInput() { const { filterRule, predicate, context } = useFilterSphere({ schema, filterFnList: [pointFilter, ...presetFilter], }); return ( <FilterSphereProvider context={context} theme={customTheme}> <FilterBuilder /> </FilterSphereProvider> );}
Type Definition
type DataInputViewProps = { rule: SingleFilter; requiredDataSchema: [] | [z.ZodTypeAny, ...z.ZodTypeAny[]]; updateInput: (...input: unknown[]) => void;};
type DataInputViewSpec = { name: string; match: | [] | [z.ZodTypeAny, ...z.ZodTypeAny[]] | (( parameterSchemas: [] | [z.ZodTypeAny, ...z.ZodTypeAny[]], fieldSchema?: z.ZodTypeAny, ) => boolean); view: ComponentType<DataInputViewProps>; meta?: Record<string, unknown>;};