Skip to content

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 component
const 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 component
const 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 type
const 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>;
};