@stll/workspace-ui 0.0.1-placeholder.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,447 @@
1
+ import { appendChild, asGroup, buildLeaf, isConditionOperator, isMultiValue, leafFromField, leafOperand, leafOperator, leafValueList, leafValueString, operandsEqual, operatorsFor, removeChild, replaceChild, valueEditorFor } from "./logic.js";
2
+ import { panic } from "better-result";
3
+ import { PlusIcon, XIcon } from "lucide-react";
4
+ import { Button } from "@stll/ui/button";
5
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
+ import { cn } from "@stll/ui/utils";
7
+ import { createContext, use } from "react";
8
+ import { DatePickerPopover } from "@stll/ui/date-picker-popover";
9
+ import { Input } from "@stll/ui/input";
10
+ import { Select, SelectItem, SelectPopup, SelectSeparator, SelectTrigger, SelectValue } from "@stll/ui/select";
11
+ //#region src/conditions/builder.tsx
12
+ const BuilderContext = createContext(null);
13
+ /**
14
+ * A context rather than a prop on every row because the builder is recursive:
15
+ * threading one object through six nested components would put it in every
16
+ * signature and still arrive at the same leaf.
17
+ */
18
+ const useBuilderContext = () => {
19
+ const context = use(BuilderContext);
20
+ if (!context) panic("ConditionBuilder rendered outside its own provider");
21
+ return context;
22
+ };
23
+ const useLabels = () => useBuilderContext().labels;
24
+ /** The formula leaf's left operand carries no field type, so its operators come
25
+ * from the numeric set and its value editor is the int input. */
26
+ const FORMULA_VALUE_TYPE = "int";
27
+ /** Sentinel select value that switches a leaf to a formula operand. Leads with a
28
+ * space so it never collides with a real field index. */
29
+ const FORMULA_OPTION = " formula";
30
+ const ConditionBuilder = ({ value, onChange, capabilities, labels, locale }) => /* @__PURE__ */ jsx(BuilderContext, {
31
+ value: {
32
+ labels,
33
+ locale
34
+ },
35
+ children: /* @__PURE__ */ jsx(ConditionBuilderTree, {
36
+ capabilities,
37
+ onChange,
38
+ value
39
+ })
40
+ });
41
+ const ConditionBuilderTree = ({ value, onChange, capabilities }) => {
42
+ const labels = useLabels();
43
+ const group = asGroup(value);
44
+ const { fields, allowNesting = false } = capabilities;
45
+ const firstField = fields.at(0);
46
+ return /* @__PURE__ */ jsxs("div", {
47
+ className: "flex flex-col gap-2",
48
+ children: [/* @__PURE__ */ jsx("div", {
49
+ className: "flex flex-col gap-2",
50
+ children: group.children.map((child, index) => {
51
+ if (child.type === "group" && allowNesting) return /* @__PURE__ */ jsx(NestedGroupRow, {
52
+ capabilities,
53
+ combinator: group.combinator,
54
+ index,
55
+ onChange: (next) => onChange(replaceChild(group, index, next)),
56
+ onRemove: () => onChange(removeChild(group, index)),
57
+ onSetCombinator: (combinator) => onChange({
58
+ ...group,
59
+ combinator
60
+ }),
61
+ value: child
62
+ }, index);
63
+ return /* @__PURE__ */ jsx(LeafRow, {
64
+ capabilities,
65
+ combinator: group.combinator,
66
+ index,
67
+ node: child,
68
+ onChange: (next) => onChange(replaceChild(group, index, next)),
69
+ onRemove: () => onChange(removeChild(group, index)),
70
+ onSetCombinator: (combinator) => onChange({
71
+ ...group,
72
+ combinator
73
+ })
74
+ }, index);
75
+ })
76
+ }), /* @__PURE__ */ jsxs("div", {
77
+ className: "ms-[5.375rem] flex flex-wrap gap-1",
78
+ children: [/* @__PURE__ */ jsxs(Button, {
79
+ className: "w-fit justify-start",
80
+ disabled: !firstField,
81
+ onClick: () => {
82
+ if (firstField) onChange(appendChild(group, leafFromField(firstField)));
83
+ },
84
+ size: "xs",
85
+ type: "button",
86
+ variant: "ghost",
87
+ children: [/* @__PURE__ */ jsx(PlusIcon, {}), labels.addCondition]
88
+ }), allowNesting && /* @__PURE__ */ jsxs(Button, {
89
+ className: "w-fit justify-start",
90
+ disabled: !firstField,
91
+ onClick: () => {
92
+ if (firstField) onChange(appendChild(group, {
93
+ type: "group",
94
+ combinator: "and",
95
+ children: [leafFromField(firstField)]
96
+ }));
97
+ },
98
+ size: "xs",
99
+ type: "button",
100
+ variant: "ghost",
101
+ children: [/* @__PURE__ */ jsx(PlusIcon, {}), labels.addGroup]
102
+ })]
103
+ })]
104
+ });
105
+ };
106
+ /** Left gutter: row 0 reads "When", row 1 carries the editable And/Or that sets
107
+ * the group's combinator, later rows echo it read-only. A single-child group
108
+ * shows no combinator word at all. */
109
+ const ConditionGutter = ({ index, combinator, onCombinator }) => {
110
+ const labels = useLabels();
111
+ const gutterClass = "w-20 shrink-0 text-muted-foreground text-xs";
112
+ if (index === 0) return /* @__PURE__ */ jsx("span", {
113
+ className: cn(gutterClass, "ps-1"),
114
+ children: labels.when
115
+ });
116
+ if (index === 1) return /* @__PURE__ */ jsxs(Select, {
117
+ onValueChange: (next) => onCombinator(next === "or" ? "or" : "and"),
118
+ value: combinator,
119
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
120
+ "aria-label": labels.match,
121
+ className: "h-7 min-h-0 w-20 min-w-0 shrink-0 text-xs",
122
+ size: "sm",
123
+ children: /* @__PURE__ */ jsx(SelectValue, {})
124
+ }), /* @__PURE__ */ jsxs(SelectPopup, { children: [/* @__PURE__ */ jsx(SelectItem, {
125
+ value: "and",
126
+ children: labels.and
127
+ }), /* @__PURE__ */ jsx(SelectItem, {
128
+ value: "or",
129
+ children: labels.or
130
+ })] })]
131
+ });
132
+ return /* @__PURE__ */ jsx("span", {
133
+ className: cn(gutterClass, "ps-1"),
134
+ children: combinator === "or" ? labels.or : labels.and
135
+ });
136
+ };
137
+ const NestedGroupRow = ({ value, capabilities, index, combinator, onChange, onRemove, onSetCombinator }) => {
138
+ const removeLabel = useLabels().remove;
139
+ return /* @__PURE__ */ jsxs("div", {
140
+ className: "flex items-start gap-2",
141
+ children: [/* @__PURE__ */ jsx(ConditionGutter, {
142
+ combinator,
143
+ index,
144
+ onCombinator: onSetCombinator
145
+ }), /* @__PURE__ */ jsxs("div", {
146
+ className: "border-border/70 bg-muted/20 flex flex-1 items-start gap-2 rounded-md border p-2",
147
+ children: [/* @__PURE__ */ jsx("div", {
148
+ className: "flex-1",
149
+ children: /* @__PURE__ */ jsx(ConditionBuilderTree, {
150
+ capabilities,
151
+ onChange,
152
+ value
153
+ })
154
+ }), /* @__PURE__ */ jsx(Button, {
155
+ "aria-label": removeLabel,
156
+ onClick: onRemove,
157
+ size: "icon-xs",
158
+ tooltip: removeLabel,
159
+ type: "button",
160
+ variant: "ghost",
161
+ children: /* @__PURE__ */ jsx(XIcon, {})
162
+ })]
163
+ })]
164
+ });
165
+ };
166
+ const LeafRow = ({ node, capabilities, index, combinator, onChange, onRemove, onSetCombinator }) => {
167
+ const labels = useLabels();
168
+ const { fields, allowFormula = false } = capabilities;
169
+ const operand = leafOperand(node);
170
+ if (operand?.type === "formula") return /* @__PURE__ */ jsx(FormulaLeafRow, {
171
+ capabilities,
172
+ combinator,
173
+ expr: operand.expr,
174
+ index,
175
+ node,
176
+ onChange,
177
+ onRemove,
178
+ onSetCombinator
179
+ });
180
+ const opsFor = capabilities.operatorsFor ?? operatorsFor;
181
+ const editorFor = capabilities.valueEditorFor ?? valueEditorFor;
182
+ const fieldIndex = operand ? fields.findIndex((f) => operandsEqual(f.operand, operand)) : -1;
183
+ const field = fields[fieldIndex];
184
+ if (!field) return null;
185
+ const operator = leafOperator(node) ?? opsFor(field.valueType).at(0);
186
+ if (!operator) return null;
187
+ const operators = opsFor(field.valueType);
188
+ const editorKind = editorFor(field.valueType, operator);
189
+ return /* @__PURE__ */ jsxs("div", {
190
+ className: "flex items-center gap-1.5",
191
+ children: [
192
+ /* @__PURE__ */ jsx(ConditionGutter, {
193
+ combinator,
194
+ index,
195
+ onCombinator: onSetCombinator
196
+ }),
197
+ /* @__PURE__ */ jsxs("div", {
198
+ className: "flex min-w-0 flex-1 items-center gap-1.5",
199
+ children: [
200
+ /* @__PURE__ */ jsxs(Select, {
201
+ onValueChange: (next) => {
202
+ if (next === null) return;
203
+ if (next === FORMULA_OPTION) {
204
+ onChange(buildLeaf({
205
+ operand: {
206
+ type: "formula",
207
+ expr: ""
208
+ },
209
+ operator: opsFor(FORMULA_VALUE_TYPE).at(0) ?? "eq",
210
+ value: ""
211
+ }));
212
+ return;
213
+ }
214
+ const nextField = fields[Number(next)];
215
+ if (nextField) onChange(leafFromField(nextField));
216
+ },
217
+ value: String(fieldIndex),
218
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
219
+ className: "h-7 min-h-0 w-auto max-w-56 text-xs",
220
+ size: "sm",
221
+ children: /* @__PURE__ */ jsx(SelectValue, {
222
+ placeholder: labels.fieldPlaceholder,
223
+ children: field.label
224
+ })
225
+ }), /* @__PURE__ */ jsxs(SelectPopup, {
226
+ alignItemWithTrigger: false,
227
+ children: [fields.map((option, optionIndex) => /* @__PURE__ */ jsx(SelectItem, {
228
+ value: String(optionIndex),
229
+ children: option.label
230
+ }, JSON.stringify(option.operand))), allowFormula && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SelectSeparator, {}), /* @__PURE__ */ jsx(SelectItem, {
231
+ value: FORMULA_OPTION,
232
+ children: labels.useFormula
233
+ })] })]
234
+ })]
235
+ }),
236
+ /* @__PURE__ */ jsx(OperatorSelect, {
237
+ field,
238
+ node,
239
+ onChange,
240
+ operator,
241
+ operators
242
+ }),
243
+ /* @__PURE__ */ jsx(LeafValueEditor, {
244
+ capabilities,
245
+ editorKind,
246
+ field,
247
+ node,
248
+ onChange,
249
+ operator
250
+ })
251
+ ]
252
+ }),
253
+ /* @__PURE__ */ jsx(RemoveButton, { onRemove })
254
+ ]
255
+ });
256
+ };
257
+ const FormulaLeafRow = ({ node, expr, capabilities, index, combinator, onChange, onRemove, onSetCombinator }) => {
258
+ const labels = useLabels();
259
+ const { fields, formulaNumberFields = [] } = capabilities;
260
+ const opsFor = capabilities.operatorsFor ?? operatorsFor;
261
+ const operator = leafOperator(node) ?? opsFor(FORMULA_VALUE_TYPE).at(0) ?? "eq";
262
+ const operators = opsFor(FORMULA_VALUE_TYPE);
263
+ const firstField = fields.at(0);
264
+ const formulaOperand = {
265
+ type: "formula",
266
+ expr
267
+ };
268
+ return /* @__PURE__ */ jsxs("div", {
269
+ className: "flex items-center gap-1.5",
270
+ children: [
271
+ /* @__PURE__ */ jsx(ConditionGutter, {
272
+ combinator,
273
+ index,
274
+ onCombinator: onSetCombinator
275
+ }),
276
+ /* @__PURE__ */ jsxs("div", {
277
+ className: "flex min-w-0 flex-1 items-center gap-1.5",
278
+ children: [
279
+ capabilities.renderFormulaCell?.({
280
+ expr,
281
+ numberFields: formulaNumberFields,
282
+ onChangeExpr: (nextExpr) => onChange(buildLeaf({
283
+ operand: {
284
+ type: "formula",
285
+ expr: nextExpr
286
+ },
287
+ operator,
288
+ value: leafValueString(node)
289
+ })),
290
+ onUseField: () => {
291
+ if (firstField) onChange(leafFromField(firstField));
292
+ }
293
+ }),
294
+ /* @__PURE__ */ jsx(OperatorSelectFormula, {
295
+ node,
296
+ onChange,
297
+ operand: formulaOperand,
298
+ operator,
299
+ operators
300
+ }),
301
+ /* @__PURE__ */ jsx(Input, {
302
+ "aria-label": labels.valuePlaceholder,
303
+ className: "h-7! w-24 text-xs",
304
+ onChange: (e) => onChange(buildLeaf({
305
+ operand: formulaOperand,
306
+ operator,
307
+ value: e.currentTarget.value
308
+ })),
309
+ placeholder: labels.valuePlaceholder,
310
+ size: "sm",
311
+ type: "number",
312
+ value: leafValueString(node)
313
+ })
314
+ ]
315
+ }),
316
+ /* @__PURE__ */ jsx(RemoveButton, { onRemove })
317
+ ]
318
+ });
319
+ };
320
+ const OperatorSelect = ({ field, node, operator, operators, onChange }) => {
321
+ const labels = useLabels();
322
+ return /* @__PURE__ */ jsxs(Select, {
323
+ onValueChange: (next) => {
324
+ if (next === null || !isConditionOperator(next)) return;
325
+ onChange(buildLeaf({
326
+ operand: field.operand,
327
+ operator: next,
328
+ value: isMultiValue(next) ? leafValueList(node) : leafValueString(node)
329
+ }));
330
+ },
331
+ value: operator,
332
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
333
+ className: "h-7 min-h-0 w-auto min-w-24 text-xs",
334
+ size: "sm",
335
+ children: /* @__PURE__ */ jsx(SelectValue, { children: () => labels.operator(field.valueType, operator) })
336
+ }), /* @__PURE__ */ jsx(SelectPopup, {
337
+ alignItemWithTrigger: false,
338
+ children: operators.map((op) => /* @__PURE__ */ jsx(SelectItem, {
339
+ value: op,
340
+ children: labels.operator(field.valueType, op)
341
+ }, op))
342
+ })]
343
+ });
344
+ };
345
+ const OperatorSelectFormula = ({ node, operand, operator, operators, onChange }) => {
346
+ const labels = useLabels();
347
+ return /* @__PURE__ */ jsxs(Select, {
348
+ onValueChange: (next) => {
349
+ if (next === null || !isConditionOperator(next)) return;
350
+ onChange(buildLeaf({
351
+ operand,
352
+ operator: next,
353
+ value: leafValueString(node)
354
+ }));
355
+ },
356
+ value: operator,
357
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
358
+ className: "h-7 min-h-0 w-auto min-w-24 text-xs",
359
+ size: "sm",
360
+ children: /* @__PURE__ */ jsx(SelectValue, { children: () => labels.operator(FORMULA_VALUE_TYPE, operator) })
361
+ }), /* @__PURE__ */ jsx(SelectPopup, {
362
+ alignItemWithTrigger: false,
363
+ children: operators.map((op) => /* @__PURE__ */ jsx(SelectItem, {
364
+ value: op,
365
+ children: labels.operator(FORMULA_VALUE_TYPE, op)
366
+ }, op))
367
+ })]
368
+ });
369
+ };
370
+ const RemoveButton = ({ onRemove }) => {
371
+ const labels = useLabels();
372
+ return /* @__PURE__ */ jsx(Button, {
373
+ "aria-label": labels.remove,
374
+ onClick: onRemove,
375
+ size: "icon-xs",
376
+ type: "button",
377
+ variant: "ghost",
378
+ children: /* @__PURE__ */ jsx(XIcon, {})
379
+ });
380
+ };
381
+ const LeafValueEditor = ({ capabilities, editorKind, field, node, operator, onChange }) => {
382
+ const { labels, locale } = useBuilderContext();
383
+ const emit = (value) => {
384
+ onChange(buildLeaf({
385
+ operand: field.operand,
386
+ operator,
387
+ value
388
+ }));
389
+ };
390
+ const injected = capabilities.renderValueEditor?.({
391
+ editorKind,
392
+ field,
393
+ node,
394
+ operator,
395
+ emit
396
+ });
397
+ if (injected !== null && injected !== void 0) return injected;
398
+ if (editorKind === "none") return null;
399
+ if (editorKind === "select") return /* @__PURE__ */ jsxs(Select, {
400
+ multiple: isMultiValue(operator),
401
+ onValueChange: (next) => {
402
+ if (next !== null) emit(next);
403
+ },
404
+ value: isMultiValue(operator) ? leafValueList(node) : leafValueString(node),
405
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
406
+ className: "h-7 min-h-0 w-auto min-w-28 text-xs",
407
+ size: "sm",
408
+ children: /* @__PURE__ */ jsx(SelectValue, { placeholder: labels.valuePlaceholder })
409
+ }), /* @__PURE__ */ jsx(SelectPopup, {
410
+ alignItemWithTrigger: false,
411
+ children: field.options?.map((option) => /* @__PURE__ */ jsx(SelectItem, {
412
+ value: option.value,
413
+ children: option.label
414
+ }, option.value))
415
+ })]
416
+ });
417
+ if (editorKind === "int") return /* @__PURE__ */ jsx(Input, {
418
+ "aria-label": labels.valuePlaceholder,
419
+ className: "h-7! w-24 text-xs",
420
+ onChange: (e) => emit(e.currentTarget.value),
421
+ placeholder: labels.valuePlaceholder,
422
+ size: "sm",
423
+ type: "number",
424
+ value: leafValueString(node)
425
+ });
426
+ if (editorKind === "date") return /* @__PURE__ */ jsx("div", {
427
+ className: "border-input bg-background min-w-28 rounded-md border px-1",
428
+ children: /* @__PURE__ */ jsx(DatePickerPopover, {
429
+ clearLabel: labels.clearDate,
430
+ locale,
431
+ onChange: (next) => emit(next ?? ""),
432
+ placeholderLabel: labels.selectDate,
433
+ todayLabel: labels.today,
434
+ value: leafValueString(node) || null
435
+ })
436
+ });
437
+ return /* @__PURE__ */ jsx(Input, {
438
+ "aria-label": labels.valuePlaceholder,
439
+ className: "h-7! w-32 text-xs",
440
+ onChange: (e) => emit(e.currentTarget.value),
441
+ placeholder: labels.valuePlaceholder,
442
+ size: "sm",
443
+ value: leafValueString(node)
444
+ });
445
+ };
446
+ //#endregion
447
+ export { ConditionBuilder };
@@ -0,0 +1,3 @@
1
+ import { CONDITION_OPERATORS, ConditionOperator, FieldOption, FieldOptionChoice, FieldValueType, ValueEditorKind, appendChild, asGroup, buildLeaf, fieldForNode, isConditionOperator, isMultiValue, leafFromField, leafOperand, leafOperator, leafValueList, leafValueString, operandsEqual, operatorsFor, removeChild, replaceChild, valueEditorFor } from "./logic.js";
2
+ import { ConditionBuilder, ConditionBuilderLabels, ConditionCapabilities, FormulaCellRenderCtx, ValueEditorRenderCtx } from "./builder.js";
3
+ export { CONDITION_OPERATORS, ConditionBuilder, type ConditionBuilderLabels, type ConditionCapabilities, type ConditionOperator, type FieldOption, type FieldOptionChoice, type FieldValueType, type FormulaCellRenderCtx, type ValueEditorKind, type ValueEditorRenderCtx, appendChild, asGroup, buildLeaf, fieldForNode, isConditionOperator, isMultiValue, leafFromField, leafOperand, leafOperator, leafValueList, leafValueString, operandsEqual, operatorsFor, removeChild, replaceChild, valueEditorFor };
@@ -0,0 +1,3 @@
1
+ import { CONDITION_OPERATORS, appendChild, asGroup, buildLeaf, fieldForNode, isConditionOperator, isMultiValue, leafFromField, leafOperand, leafOperator, leafValueList, leafValueString, operandsEqual, operatorsFor, removeChild, replaceChild, valueEditorFor } from "./logic.js";
2
+ import { ConditionBuilder } from "./builder.js";
3
+ export { CONDITION_OPERATORS, ConditionBuilder, appendChild, asGroup, buildLeaf, fieldForNode, isConditionOperator, isMultiValue, leafFromField, leafOperand, leafOperator, leafValueList, leafValueString, operandsEqual, operatorsFor, removeChild, replaceChild, valueEditorFor };
@@ -0,0 +1,70 @@
1
+ import { PropertyIconType } from "../property-icon.js";
2
+ import { ConditionNode, GroupNode, RefOperand } from "@stll/conditions";
3
+ //#region src/conditions/logic.d.ts
4
+ /**
5
+ * Context-agnostic description of one operand the builder may filter
6
+ * on. `valueType` drives both the operator set (`operatorsFor`) and
7
+ * the value editor; `options` supplies the choices for any select-like
8
+ * value type.
9
+ */
10
+ type FieldValueType = "text" | "single-select" | "multi-select" | "date" | "int" | "money" | "person" | "kind" | "status" | "priority";
11
+ type FieldOptionChoice = {
12
+ value: string;
13
+ label: string;
14
+ color?: string;
15
+ };
16
+ type FieldOption = {
17
+ operand: RefOperand;
18
+ label: string;
19
+ valueType: FieldValueType;
20
+ /** Drives the property-type icon shown in chips and the picker. */
21
+ type: PropertyIconType;
22
+ options?: FieldOptionChoice[];
23
+ };
24
+ /**
25
+ * The surface operators the builder exposes. A subset maps to
26
+ * `compare` nodes (binary comparisons against a literal); the rest map
27
+ * to `predicate` nodes. `operatorKind` is the single place that
28
+ * decides which AST node each operator builds.
29
+ */
30
+ declare const CONDITION_OPERATORS: readonly ["eq", "neq", "contains", "not_contains", "starts_with", "ends_with", "contains_all", "in", "gt", "lt", "gte", "lte", "is_empty", "is_not_empty"];
31
+ type ConditionOperator = (typeof CONDITION_OPERATORS)[number];
32
+ declare const isConditionOperator: (value: string) => value is ConditionOperator;
33
+ declare const operatorsFor: (valueType: FieldValueType) => readonly ConditionOperator[];
34
+ /** How a value type renders its value editor. */
35
+ type ValueEditorKind = "none" | "text" | "int" | "date" | "select";
36
+ declare const valueEditorFor: (valueType: FieldValueType, operator: ConditionOperator) => ValueEditorKind;
37
+ /** Whether the value editor accepts multiple selections. */
38
+ declare const isMultiValue: (operator: ConditionOperator) => boolean;
39
+ /** Compares two ref operands for the field-matching needed by the row. */
40
+ declare const operandsEqual: (a: RefOperand, b: RefOperand) => boolean;
41
+ /** Reads the ref operand a leaf node filters on, or null for a group. */
42
+ declare const leafOperand: (node: ConditionNode) => RefOperand | null;
43
+ /** Reads the surface operator a leaf node represents. */
44
+ declare const leafOperator: (node: ConditionNode) => ConditionOperator | null;
45
+ /** Reads a leaf's value as a string (scalar editors). */
46
+ declare const leafValueString: (node: ConditionNode) => string;
47
+ /** Reads a leaf's value as a string list (multi editors). */
48
+ declare const leafValueList: (node: ConditionNode) => string[];
49
+ type BuildLeafArgs = {
50
+ operand: RefOperand;
51
+ operator: ConditionOperator;
52
+ value: string | string[];
53
+ };
54
+ /**
55
+ * Rebuilds a leaf node from its editor state. `compare` operators
56
+ * produce a literal right operand; predicate operators carry their
57
+ * payload (or none, for `is_empty`).
58
+ */
59
+ declare const buildLeaf: ({ operand, operator, value }: BuildLeafArgs) => ConditionNode;
60
+ /** A fresh leaf for a newly added row, with the field's first operator. */
61
+ declare const leafFromField: (field: FieldOption) => ConditionNode;
62
+ /** Finds the field a leaf node targets, or null when none matches. */
63
+ declare const fieldForNode: (node: ConditionNode, fields: FieldOption[]) => FieldOption | null;
64
+ /** Normalizes the controlled `value` prop into a concrete group root. */
65
+ declare const asGroup: (value: ConditionNode | null) => GroupNode;
66
+ declare const replaceChild: (group: GroupNode, index: number, child: ConditionNode) => GroupNode;
67
+ declare const removeChild: (group: GroupNode, index: number) => GroupNode;
68
+ declare const appendChild: (group: GroupNode, child: ConditionNode) => GroupNode;
69
+ //#endregion
70
+ export { CONDITION_OPERATORS, ConditionOperator, FieldOption, FieldOptionChoice, FieldValueType, ValueEditorKind, appendChild, asGroup, buildLeaf, fieldForNode, isConditionOperator, isMultiValue, leafFromField, leafOperand, leafOperator, leafValueList, leafValueString, operandsEqual, operatorsFor, removeChild, replaceChild, valueEditorFor };