diff --git a/apps/client/src/features/base/components/formula/formula-editor.tsx b/apps/client/src/features/base/components/formula/formula-editor.tsx new file mode 100644 index 000000000..b786e35b6 --- /dev/null +++ b/apps/client/src/features/base/components/formula/formula-editor.tsx @@ -0,0 +1,84 @@ +import { useState } from "react"; +import { Button, Divider, Group, Paper, Stack, Text } from "@mantine/core"; +import { registry } from "@docmost/base-formula/client"; +import { FormulaInput } from "./formula-input"; +import { PropertyChipRow } from "./property-chip-row"; +import { FunctionPalette } from "./function-palette"; +import { useFormulaParser } from "@/features/base/hooks/use-formula-parser"; +import type { IBaseProperty } from "@/features/base/types/base.types"; + +type Props = { + properties: IBaseProperty[]; + editingPropertyId: string | null; + initialSource?: string; + onSave: ( + source: string, + ast: unknown, + resultType: string, + dependencies: string[], + ) => void; + onCancel: () => void; +}; + +export function FormulaEditor({ + properties, + editingPropertyId, + initialSource = "", + onSave, + onCancel, +}: Props) { + const [source, setSource] = useState(initialSource); + const parseState = useFormulaParser( + source, + properties, + editingPropertyId, + registry, + ); + const canSave = parseState.state === "ok"; + + const insertAtEnd = (snippet: string) => + setSource((s) => `${s}${s ? " " : ""}${snippet}`); + + return ( + + + Formula + + + Properties + p.id !== editingPropertyId)} + onInsert={(name) => insertAtEnd(`prop("${name}")`)} + /> + + Functions + insertAtEnd(`${name}()`)} + /> + + + + + + + ); +} diff --git a/apps/client/src/features/base/components/formula/formula-input.tsx b/apps/client/src/features/base/components/formula/formula-input.tsx new file mode 100644 index 000000000..e165c8f17 --- /dev/null +++ b/apps/client/src/features/base/components/formula/formula-input.tsx @@ -0,0 +1,35 @@ +import { Textarea, Text } from "@mantine/core"; + +type Props = { + value: string; + onChange: (v: string) => void; + error?: { message: string; span?: { start: number; end: number } }; + resultType?: string; +}; + +export function FormulaInput({ value, onChange, error, resultType }: Props) { + return ( +
+