import { Textfield, ValidationMessage } from "@digdir/designsystemet-react"; import { type FilterTree, getLocalizedString, toFilterTree } from "@olenbetong/appframe-core"; import { useFilterConversion } from "@olenbetong/appframe-react"; import { useEffect, useState } from "react"; import type { FilterEditorSize } from "./types.js"; export type FilterStringFieldProps = { filter: FilterTree; onChange: (filter: FilterTree) => void; viewName?: string; readOnly?: boolean; "data-size"?: FilterEditorSize; }; /** * Two-way filter string editor. The tree is the source of truth: it is * converted to a string whenever it changes. Editing the string and leaving the * field parses it back into a tree. */ export function FilterStringField({ filter, onChange, viewName, readOnly, "data-size": size = "sm", }: FilterStringFieldProps) { let { filterString, isConverting, error, warning, parseFilterString } = useFilterConversion(filter, { viewName }); let [draft, setDraft] = useState(null); let [parseError, setParseError] = useState(null); // The tree changed underneath us, so any half-typed string is stale. useEffect(() => { setDraft(null); setParseError(null); }, [filter]); async function commit() { if (draft === null || draft === filterString) { setDraft(null); return; } let parsed = await parseFilterString(draft); if (parsed) { setDraft(null); setParseError(null); onChange(toFilterTree(parsed)); } else { setParseError(getLocalizedString("The filter could not be parsed")); } } let message = parseError ?? error?.message ?? warning; return (
{getLocalizedString("Filter string")} {isConverting && {getLocalizedString("Converting…")}} } value={draft ?? filterString} onChange={(event) => setDraft(event.target.value)} onBlur={commit} /> {message && {message}}
); }