@charcuterie/ui 2.12.0 → 2.13.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.
- package/dist/QueryBuilder/QueryBuilder.d.ts +64 -0
- package/dist/QueryBuilder/QueryBuilder.d.ts.map +1 -0
- package/dist/QueryBuilder/QueryBuilder.js +37 -0
- package/dist/QueryBuilder/QueryBuilder.js.map +1 -0
- package/dist/QueryBuilder/QueryBuilderGroup.d.ts +37 -0
- package/dist/QueryBuilder/QueryBuilderGroup.d.ts.map +1 -0
- package/dist/QueryBuilder/QueryBuilderGroup.js +57 -0
- package/dist/QueryBuilder/QueryBuilderGroup.js.map +1 -0
- package/dist/QueryBuilder/QueryBuilderRow.d.ts +28 -0
- package/dist/QueryBuilder/QueryBuilderRow.d.ts.map +1 -0
- package/dist/QueryBuilder/QueryBuilderRow.js +16 -0
- package/dist/QueryBuilder/QueryBuilderRow.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/QueryBuilder/QueryBuilder.mdx +63 -0
- package/src/QueryBuilder/QueryBuilder.stories.tsx +243 -0
- package/src/QueryBuilder/QueryBuilder.test.tsx +132 -0
- package/src/QueryBuilder/QueryBuilder.tsx +102 -0
- package/src/QueryBuilder/QueryBuilderGroup.tsx +185 -0
- package/src/QueryBuilder/QueryBuilderRow.tsx +54 -0
- package/src/index.ts +5 -0
- package/src/sourceRules.test.ts +21 -1
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Tree } from "@charcuterie/logic";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
export type QueryBuilderLabels = {
|
|
4
|
+
addGroup?: string;
|
|
5
|
+
addLeaf?: string;
|
|
6
|
+
removeGroup?: string;
|
|
7
|
+
removeLeaf?: string;
|
|
8
|
+
};
|
|
9
|
+
export type QueryBuilderProps<Combinator, Leaf> = {
|
|
10
|
+
/**
|
|
11
|
+
* The combinator choices offered in every group's "Match" select.
|
|
12
|
+
* The `value` is opaque — `and`/`or` for a mail rule, `any`/`all`/
|
|
13
|
+
* `none` for a DSL — and the `label` is what a user reads.
|
|
14
|
+
*/
|
|
15
|
+
combinatorOptions: readonly {
|
|
16
|
+
label: string;
|
|
17
|
+
value: Combinator;
|
|
18
|
+
}[];
|
|
19
|
+
/** The value a fresh leaf is born with when "+ Condition" is pressed. */
|
|
20
|
+
createLeafValue: () => Leaf;
|
|
21
|
+
labels?: QueryBuilderLabels;
|
|
22
|
+
/**
|
|
23
|
+
* The leaf UI, owned by the app. `QueryBuilder` knows nothing about
|
|
24
|
+
* what a condition *is* — a field/operator/value triple, a
|
|
25
|
+
* non-uniform per-kind shape — only that it can be rendered and
|
|
26
|
+
* patched. The delete control around each leaf is the builder's.
|
|
27
|
+
*/
|
|
28
|
+
renderLeaf: (args: {
|
|
29
|
+
nodeId: string;
|
|
30
|
+
onChange: (value: Leaf) => void;
|
|
31
|
+
value: Leaf;
|
|
32
|
+
}) => ReactNode;
|
|
33
|
+
/**
|
|
34
|
+
* The `Tree` core from `useTree`, owned by the consumer — the same
|
|
35
|
+
* arrangement as a `Listbox`'s parent owning `useVisibility`.
|
|
36
|
+
* `QueryBuilder` subscribes to it and drives it; it never creates
|
|
37
|
+
* one, so a consumer keeps `serialize()` and the initial tree.
|
|
38
|
+
*/
|
|
39
|
+
tree: Tree<Combinator, Leaf>;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* The generic, nestable AND/OR — and any-combinator — group editor.
|
|
43
|
+
*
|
|
44
|
+
* Two apps in the fleet grow the same widget: Mail Sifter's nested
|
|
45
|
+
* mail rules (leaf = field/operator/value, combinators AND/OR) and
|
|
46
|
+
* mux-magic's job DSL (non-uniform leaves, combinators any/all/none).
|
|
47
|
+
* Both are a recursive group of conditions with a combinator, so the
|
|
48
|
+
* value **and** the combinator are opaque here — `Combinator` and
|
|
49
|
+
* `Leaf` never appear except passed through to the consumer's
|
|
50
|
+
* `renderLeaf` and its `combinatorOptions`.
|
|
51
|
+
*
|
|
52
|
+
* State lives entirely in the `Tree` core from `@charcuterie/logic`;
|
|
53
|
+
* this component holds none of its own. It subscribes with
|
|
54
|
+
* `useStoreValue`, so a `patchLeaf` deep in the tree re-renders only
|
|
55
|
+
* the rows whose node identity changed — the same identity discipline
|
|
56
|
+
* the state layer is built on.
|
|
57
|
+
*
|
|
58
|
+
* The recursion and the per-leaf row each live in their own file
|
|
59
|
+
* (`QueryBuilderGroup`, `QueryBuilderRow`), not exported: a group
|
|
60
|
+
* renders groups, and both are rendered inside a `.map`, which is
|
|
61
|
+
* exactly the shape the member-file rule is for.
|
|
62
|
+
*/
|
|
63
|
+
export declare const QueryBuilder: <Combinator, Leaf>({ combinatorOptions, createLeafValue, labels, renderLeaf, tree, }: QueryBuilderProps<Combinator, Leaf>) => ReactNode;
|
|
64
|
+
//# sourceMappingURL=QueryBuilder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueryBuilder.d.ts","sourceRoot":"","sources":["../../src/QueryBuilder/QueryBuilder.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AAK9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItC,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,iBAAiB,CAAC,UAAU,EAAE,IAAI,IAAI;IAChD;;;;OAIG;IACH,iBAAiB,EAAE,SAAS;QAC1B,KAAK,EAAE,MAAM,CAAA;QACb,KAAK,EAAE,UAAU,CAAA;KAClB,EAAE,CAAA;IACH,yEAAyE;IACzE,eAAe,EAAE,MAAM,IAAI,CAAA;IAC3B,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B;;;;;OAKG;IACH,UAAU,EAAE,CAAC,IAAI,EAAE;QACjB,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,EAAE,CAAC,KAAK,EAAE,IAAI,KAAK,IAAI,CAAA;QAC/B,KAAK,EAAE,IAAI,CAAA;KACZ,KAAK,SAAS,CAAA;IACf;;;;;OAKG;IACH,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;CAC7B,CAAA;AASD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,YAAY,GAAI,UAAU,EAAE,IAAI,EAAE,mEAM5C,iBAAiB,CAAC,UAAU,EAAE,IAAI,CAAC,KAAG,SAiBxC,CAAA"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { selectRootGroup, useStoreValue, } from "@charcuterie/logic";
|
|
3
|
+
import { QueryBuilderGroup } from "./QueryBuilderGroup.js";
|
|
4
|
+
const DEFAULT_LABELS = {
|
|
5
|
+
addGroup: "Add group",
|
|
6
|
+
addLeaf: "Add condition",
|
|
7
|
+
removeGroup: "Remove group",
|
|
8
|
+
removeLeaf: "Remove condition",
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* The generic, nestable AND/OR — and any-combinator — group editor.
|
|
12
|
+
*
|
|
13
|
+
* Two apps in the fleet grow the same widget: Mail Sifter's nested
|
|
14
|
+
* mail rules (leaf = field/operator/value, combinators AND/OR) and
|
|
15
|
+
* mux-magic's job DSL (non-uniform leaves, combinators any/all/none).
|
|
16
|
+
* Both are a recursive group of conditions with a combinator, so the
|
|
17
|
+
* value **and** the combinator are opaque here — `Combinator` and
|
|
18
|
+
* `Leaf` never appear except passed through to the consumer's
|
|
19
|
+
* `renderLeaf` and its `combinatorOptions`.
|
|
20
|
+
*
|
|
21
|
+
* State lives entirely in the `Tree` core from `@charcuterie/logic`;
|
|
22
|
+
* this component holds none of its own. It subscribes with
|
|
23
|
+
* `useStoreValue`, so a `patchLeaf` deep in the tree re-renders only
|
|
24
|
+
* the rows whose node identity changed — the same identity discipline
|
|
25
|
+
* the state layer is built on.
|
|
26
|
+
*
|
|
27
|
+
* The recursion and the per-leaf row each live in their own file
|
|
28
|
+
* (`QueryBuilderGroup`, `QueryBuilderRow`), not exported: a group
|
|
29
|
+
* renders groups, and both are rendered inside a `.map`, which is
|
|
30
|
+
* exactly the shape the member-file rule is for.
|
|
31
|
+
*/
|
|
32
|
+
export const QueryBuilder = ({ combinatorOptions, createLeafValue, labels, renderLeaf, tree, }) => {
|
|
33
|
+
const state = useStoreValue(tree);
|
|
34
|
+
const resolvedLabels = { ...DEFAULT_LABELS, ...labels };
|
|
35
|
+
return (_jsx(QueryBuilderGroup, { combinatorOptions: combinatorOptions, createLeafValue: createLeafValue, depth: 0, labels: resolvedLabels, node: selectRootGroup(state), renderLeaf: renderLeaf, state: state, tree: tree }));
|
|
36
|
+
};
|
|
37
|
+
//# sourceMappingURL=QueryBuilder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueryBuilder.js","sourceRoot":"","sources":["../../src/QueryBuilder/QueryBuilder.tsx"],"names":[],"mappings":";AACA,OAAO,EACL,eAAe,EACf,aAAa,GACd,MAAM,oBAAoB,CAAA;AAG3B,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAyB,CAAA;AA0C3D,MAAM,cAAc,GAAG;IACrB,QAAQ,EAAE,WAAW;IACrB,OAAO,EAAE,eAAe;IACxB,WAAW,EAAE,cAAc;IAC3B,UAAU,EAAE,kBAAkB;CACQ,CAAA;AAExC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAmB,EAC7C,iBAAiB,EACjB,eAAe,EACf,MAAM,EACN,UAAU,EACV,IAAI,GACgC,EAAa,EAAE;IACnD,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,CAAA;IAEjC,MAAM,cAAc,GAAG,EAAE,GAAG,cAAc,EAAE,GAAG,MAAM,EAAE,CAAA;IAEvD,OAAO,CACL,KAAC,iBAAiB,IAChB,iBAAiB,EAAE,iBAAiB,EACpC,eAAe,EAAE,eAAe,EAChC,KAAK,EAAE,CAAC,EACR,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,eAAe,CAAC,KAAK,CAAC,EAC5B,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,IAAI,GACV,CACH,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Tree, TreeGroupNode, TreeState } from "@charcuterie/logic";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
import type { QueryBuilderLabels } from "./QueryBuilder.tsx";
|
|
4
|
+
export type QueryBuilderGroupProps<Combinator, Leaf> = {
|
|
5
|
+
combinatorOptions: readonly {
|
|
6
|
+
label: string;
|
|
7
|
+
value: Combinator;
|
|
8
|
+
}[];
|
|
9
|
+
createLeafValue: () => Leaf;
|
|
10
|
+
/** Root is `0`; nested groups deepen and gain the accent rail. */
|
|
11
|
+
depth: number;
|
|
12
|
+
labels: Required<QueryBuilderLabels>;
|
|
13
|
+
node: TreeGroupNode<Combinator>;
|
|
14
|
+
renderLeaf: (args: {
|
|
15
|
+
nodeId: string;
|
|
16
|
+
onChange: (value: Leaf) => void;
|
|
17
|
+
value: Leaf;
|
|
18
|
+
}) => ReactNode;
|
|
19
|
+
state: TreeState<Combinator, Leaf>;
|
|
20
|
+
tree: Tree<Combinator, Leaf>;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* One match group: a "Match" combinator select, its children (leaf
|
|
24
|
+
* rows and nested groups), and a toolbar to add either. Its own file
|
|
25
|
+
* because it renders itself recursively for nested groups and is
|
|
26
|
+
* itself rendered inside the parent's `.map` — the member-file case.
|
|
27
|
+
*
|
|
28
|
+
* The combinator is opaque, so the native `Select` (which speaks
|
|
29
|
+
* strings) is bridged by `String(value)`: options carry the
|
|
30
|
+
* stringified combinator, and a change is mapped back to the real
|
|
31
|
+
* `Combinator` before it reaches `setCombinator`. That keeps
|
|
32
|
+
* `Combinator` fully generic while still using the platform control
|
|
33
|
+
* that brings type-ahead, the mobile wheel, and form semantics for
|
|
34
|
+
* free.
|
|
35
|
+
*/
|
|
36
|
+
export declare const QueryBuilderGroup: <Combinator, Leaf>({ combinatorOptions, createLeafValue, depth, labels, node, renderLeaf, state, tree, }: QueryBuilderGroupProps<Combinator, Leaf>) => ReactNode;
|
|
37
|
+
//# sourceMappingURL=QueryBuilderGroup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueryBuilderGroup.d.ts","sourceRoot":"","sources":["../../src/QueryBuilder/QueryBuilderGroup.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,IAAI,EACJ,aAAa,EACb,SAAS,EACV,MAAM,oBAAoB,CAAA;AAE3B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAQtC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAG5D,MAAM,MAAM,sBAAsB,CAAC,UAAU,EAAE,IAAI,IAAI;IACrD,iBAAiB,EAAE,SAAS;QAC1B,KAAK,EAAE,MAAM,CAAA;QACb,KAAK,EAAE,UAAU,CAAA;KAClB,EAAE,CAAA;IACH,eAAe,EAAE,MAAM,IAAI,CAAA;IAC3B,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAA;IACpC,IAAI,EAAE,aAAa,CAAC,UAAU,CAAC,CAAA;IAC/B,UAAU,EAAE,CAAC,IAAI,EAAE;QACjB,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,EAAE,CAAC,KAAK,EAAE,IAAI,KAAK,IAAI,CAAA;QAC/B,KAAK,EAAE,IAAI,CAAA;KACZ,KAAK,SAAS,CAAA;IACf,KAAK,EAAE,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;IAClC,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;CAC7B,CAAA;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,GAAI,UAAU,EAAE,IAAI,EAAE,uFASjD,sBAAsB,CAAC,UAAU,EAAE,IAAI,CAAC,KAAG,SA6H7C,CAAA"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { selectChildNodes } from "@charcuterie/logic";
|
|
3
|
+
import { Button } from "../Button/Button.js";
|
|
4
|
+
import { Card } from "../Card/Card.js";
|
|
5
|
+
import { Field } from "../Field/Field.js";
|
|
6
|
+
import { IconButton } from "../IconButton/IconButton.js";
|
|
7
|
+
import { Select } from "../Select/Select.js";
|
|
8
|
+
import { toClassName } from "../toClassName.js";
|
|
9
|
+
import { QueryBuilderRow } from "./QueryBuilderRow.js";
|
|
10
|
+
/**
|
|
11
|
+
* One match group: a "Match" combinator select, its children (leaf
|
|
12
|
+
* rows and nested groups), and a toolbar to add either. Its own file
|
|
13
|
+
* because it renders itself recursively for nested groups and is
|
|
14
|
+
* itself rendered inside the parent's `.map` — the member-file case.
|
|
15
|
+
*
|
|
16
|
+
* The combinator is opaque, so the native `Select` (which speaks
|
|
17
|
+
* strings) is bridged by `String(value)`: options carry the
|
|
18
|
+
* stringified combinator, and a change is mapped back to the real
|
|
19
|
+
* `Combinator` before it reaches `setCombinator`. That keeps
|
|
20
|
+
* `Combinator` fully generic while still using the platform control
|
|
21
|
+
* that brings type-ahead, the mobile wheel, and form semantics for
|
|
22
|
+
* free.
|
|
23
|
+
*/
|
|
24
|
+
export const QueryBuilderGroup = ({ combinatorOptions, createLeafValue, depth, labels, node, renderLeaf, state, tree, }) => {
|
|
25
|
+
const children = selectChildNodes(state, node.id);
|
|
26
|
+
const selectOptions = combinatorOptions.map((option) => ({
|
|
27
|
+
label: option.label,
|
|
28
|
+
value: String(option.value),
|
|
29
|
+
}));
|
|
30
|
+
const card = (_jsx(Card
|
|
31
|
+
// Nested groups sit on the sunken surface so the depth reads as
|
|
32
|
+
// recession, not another raised card floating at the same level.
|
|
33
|
+
, {
|
|
34
|
+
// Nested groups sit on the sunken surface so the depth reads as
|
|
35
|
+
// recession, not another raised card floating at the same level.
|
|
36
|
+
surface: depth === 0 ? "raised" : "sunken", children: _jsxs("div", { className: "flex flex-col gap-3", children: [_jsxs("div", { className: "flex items-start justify-between gap-2", children: [_jsx("div", { className: "min-w-52", children: _jsx(Field, { label: "Match", children: _jsx(Select, { onChange: (nextValue) => {
|
|
37
|
+
const match = combinatorOptions.find((option) => String(option.value) === nextValue);
|
|
38
|
+
if (match) {
|
|
39
|
+
tree.setCombinator(node.id, match.value);
|
|
40
|
+
}
|
|
41
|
+
}, options: selectOptions, value: String(node.combinator) }) }) }), depth === 0 ? null : (_jsx(IconButton, { appearance: "ghost", intent: "danger", label: labels.removeGroup, onClick: () => {
|
|
42
|
+
tree.removeNode(node.id);
|
|
43
|
+
}, size: "sm", children: "\u2715" }))] }), children.length === 0 ? null : (_jsx("div", { className: "flex flex-col gap-2", children: children.map((child) => child.kind === "group" ? (_jsx(QueryBuilderGroup, { combinatorOptions: combinatorOptions, createLeafValue: createLeafValue, depth: depth + 1, labels: labels, node: child, renderLeaf: renderLeaf, state: state, tree: tree }, child.id)) : (_jsx(QueryBuilderRow, { label: labels.removeLeaf, nodeId: child.id, onChange: (value) => {
|
|
44
|
+
tree.patchLeaf(child.id, value);
|
|
45
|
+
}, onRemove: () => {
|
|
46
|
+
tree.removeNode(child.id);
|
|
47
|
+
}, renderLeaf: renderLeaf, value: child.value }, child.id))) })), _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(Button, { appearance: "outline", intent: "neutral", onClick: () => {
|
|
48
|
+
tree.addLeaf(node.id, createLeafValue());
|
|
49
|
+
}, size: "sm", children: `+ ${labels.addLeaf}` }), _jsx(Button, { appearance: "outline", intent: "neutral", onClick: () => {
|
|
50
|
+
tree.addGroup(node.id);
|
|
51
|
+
}, size: "sm", children: `+ ${labels.addGroup}` })] })] }) }));
|
|
52
|
+
// Depth is shown with a semantic-token inline-start rail. The colour
|
|
53
|
+
// utility paints all four sides, but only the inline-start edge has
|
|
54
|
+
// a width, so only it renders — no raw palette colour anywhere.
|
|
55
|
+
return depth === 0 ? (card) : (_jsx("div", { className: toClassName("border-intent-accent-border border-s-2 ps-3"), children: card }));
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=QueryBuilderGroup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueryBuilderGroup.js","sourceRoot":"","sources":["../../src/QueryBuilder/QueryBuilderGroup.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export type QueryBuilderRowProps<Leaf> = {
|
|
3
|
+
/** The accessible name of the row's delete control. */
|
|
4
|
+
label: string;
|
|
5
|
+
nodeId: string;
|
|
6
|
+
onChange: (value: Leaf) => void;
|
|
7
|
+
onRemove: () => void;
|
|
8
|
+
renderLeaf: (args: {
|
|
9
|
+
nodeId: string;
|
|
10
|
+
onChange: (value: Leaf) => void;
|
|
11
|
+
value: Leaf;
|
|
12
|
+
}) => ReactNode;
|
|
13
|
+
value: Leaf;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* A single leaf row: the app's own leaf UI, plus the builder's delete
|
|
17
|
+
* control. Its own file for the same reason `ListboxOption` is —
|
|
18
|
+
* rendered inside the group's `.map`, so it cannot be an inline
|
|
19
|
+
* component — and it is a member file (`QueryBuilder*.tsx`, not
|
|
20
|
+
* `QueryBuilder/QueryBuilder.tsx`), so it stays out of the barrel and
|
|
21
|
+
* the component count by rule.
|
|
22
|
+
*
|
|
23
|
+
* The delete control is an `IconButton` because a bare glyph is not an
|
|
24
|
+
* accessible name; its required `label` is what makes each row's
|
|
25
|
+
* remove button findable and unique per condition.
|
|
26
|
+
*/
|
|
27
|
+
export declare const QueryBuilderRow: <Leaf>({ label, nodeId, onChange, onRemove, renderLeaf, value, }: QueryBuilderRowProps<Leaf>) => ReactNode;
|
|
28
|
+
//# sourceMappingURL=QueryBuilderRow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueryBuilderRow.d.ts","sourceRoot":"","sources":["../../src/QueryBuilder/QueryBuilderRow.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItC,MAAM,MAAM,oBAAoB,CAAC,IAAI,IAAI;IACvC,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,IAAI,KAAK,IAAI,CAAA;IAC/B,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,UAAU,EAAE,CAAC,IAAI,EAAE;QACjB,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,EAAE,CAAC,KAAK,EAAE,IAAI,KAAK,IAAI,CAAA;QAC/B,KAAK,EAAE,IAAI,CAAA;KACZ,KAAK,SAAS,CAAA;IACf,KAAK,EAAE,IAAI,CAAA;CACZ,CAAA;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,eAAe,GAAI,IAAI,EAAG,2DAOpC,oBAAoB,CAAC,IAAI,CAAC,KAAG,SAgB/B,CAAA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { IconButton } from "../IconButton/IconButton.js";
|
|
3
|
+
/**
|
|
4
|
+
* A single leaf row: the app's own leaf UI, plus the builder's delete
|
|
5
|
+
* control. Its own file for the same reason `ListboxOption` is —
|
|
6
|
+
* rendered inside the group's `.map`, so it cannot be an inline
|
|
7
|
+
* component — and it is a member file (`QueryBuilder*.tsx`, not
|
|
8
|
+
* `QueryBuilder/QueryBuilder.tsx`), so it stays out of the barrel and
|
|
9
|
+
* the component count by rule.
|
|
10
|
+
*
|
|
11
|
+
* The delete control is an `IconButton` because a bare glyph is not an
|
|
12
|
+
* accessible name; its required `label` is what makes each row's
|
|
13
|
+
* remove button findable and unique per condition.
|
|
14
|
+
*/
|
|
15
|
+
export const QueryBuilderRow = ({ label, nodeId, onChange, onRemove, renderLeaf, value, }) => (_jsxs("div", { className: "flex items-start gap-2", children: [_jsx("div", { className: "grow", children: renderLeaf({ nodeId, onChange, value }) }), _jsx(IconButton, { appearance: "ghost", intent: "danger", label: label, onClick: onRemove, size: "sm", children: "\u2715" })] }));
|
|
16
|
+
//# sourceMappingURL=QueryBuilderRow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueryBuilderRow.js","sourceRoot":"","sources":["../../src/QueryBuilder/QueryBuilderRow.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA8B,CAAA;AAgBzD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAQ,EACrC,KAAK,EACL,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,KAAK,GACsB,EAAa,EAAE,CAAC,CAC3C,eAAK,SAAS,EAAC,wBAAwB,aACrC,cAAK,SAAS,EAAC,MAAM,YAClB,UAAU,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,GACpC,EAEN,KAAC,UAAU,IACT,UAAU,EAAC,OAAO,EAClB,MAAM,EAAC,QAAQ,EACf,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,QAAQ,EACjB,IAAI,EAAC,IAAI,uBAGE,IACT,CACP,CAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -98,6 +98,8 @@ export type { ProgressBarProps, ProgressBarSize, } from "./ProgressBar/ProgressB
|
|
|
98
98
|
export { ProgressBar } from "./ProgressBar/ProgressBar.tsx";
|
|
99
99
|
export type { ProgressThreshold } from "./ProgressBar/progressValue.ts";
|
|
100
100
|
export { getProgressIntent, toProgressPercent, toProgressValue, } from "./ProgressBar/progressValue.ts";
|
|
101
|
+
export type { QueryBuilderLabels, QueryBuilderProps, } from "./QueryBuilder/QueryBuilder.tsx";
|
|
102
|
+
export { QueryBuilder } from "./QueryBuilder/QueryBuilder.tsx";
|
|
101
103
|
export type { RadioGroupProps, RadioItem, } from "./RadioGroup/RadioGroup.tsx";
|
|
102
104
|
export { RadioGroup } from "./RadioGroup/RadioGroup.tsx";
|
|
103
105
|
export type { RailLandmark, RailProps, RailSide, } from "./Rail/Rail.tsx";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -64,6 +64,7 @@ export { Modal } from "./Modal/Modal.js";
|
|
|
64
64
|
export { Popover } from "./Popover/Popover.js";
|
|
65
65
|
export { ProgressBar } from "./ProgressBar/ProgressBar.js";
|
|
66
66
|
export { getProgressIntent, toProgressPercent, toProgressValue, } from "./ProgressBar/progressValue.js";
|
|
67
|
+
export { QueryBuilder } from "./QueryBuilder/QueryBuilder.js";
|
|
67
68
|
export { RadioGroup } from "./RadioGroup/RadioGroup.js";
|
|
68
69
|
export { Rail } from "./Rail/Rail.js";
|
|
69
70
|
export { AnchorLink } from "./RouterLink/AnchorLink.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@charcuterie/ui",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.13.0",
|
|
4
4
|
"description": "The Charcuterie components. Tokens for look, @charcuterie/logic for state, ARIA that agents can actually drive.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"typecheck": "tsc --noEmit"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@charcuterie/logic": "1.
|
|
51
|
+
"@charcuterie/logic": "1.5.0",
|
|
52
52
|
"@charcuterie/tokens": "1.5.0",
|
|
53
53
|
"@floating-ui/react": "^0.27.20",
|
|
54
54
|
"@tanstack/react-virtual": "^3.13.12"
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Canvas, Controls, Meta } from "@storybook/addon-docs/blocks";
|
|
2
|
+
|
|
3
|
+
import * as QueryBuilderStories from "./QueryBuilder.stories";
|
|
4
|
+
|
|
5
|
+
<Meta of={QueryBuilderStories} />
|
|
6
|
+
|
|
7
|
+
# QueryBuilder
|
|
8
|
+
|
|
9
|
+
The generic, nestable **AND/OR — and any-combinator — group editor**. A recursive group of
|
|
10
|
+
conditions, each group carrying a combinator the app owns and each leaf carrying a value the
|
|
11
|
+
app owns. Two apps in the fleet grow the same widget from opposite ends: Mail Sifter's nested
|
|
12
|
+
mail rules (leaf = field/operator/value, combinators AND/OR) and mux-magic's job DSL
|
|
13
|
+
(non-uniform leaves, combinators any/all/none). So both the **leaf value** and the **group
|
|
14
|
+
combinator** are fully opaque here — `Combinator` and `Leaf` only ever pass through to the
|
|
15
|
+
consumer's `renderLeaf` and `combinatorOptions`.
|
|
16
|
+
|
|
17
|
+
<Canvas of={QueryBuilderStories.Default} />
|
|
18
|
+
|
|
19
|
+
## Props
|
|
20
|
+
|
|
21
|
+
<Controls />
|
|
22
|
+
|
|
23
|
+
## The state is a `Tree`, and the consumer owns it
|
|
24
|
+
|
|
25
|
+
`QueryBuilder` holds no state of its own. It takes a `Tree` core from
|
|
26
|
+
[`useTree`](?path=/docs/state-usetree--docs) and subscribes to it, the same way a `Listbox`'s
|
|
27
|
+
parent owns `useVisibility` and hands it down. That is what leaves `serialize()` — the
|
|
28
|
+
YAML/DB round-trip — and the initial tree in the consumer's hands.
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
const tree = useTree<Combinator, Leaf>({
|
|
32
|
+
defaultCombinator: "and",
|
|
33
|
+
initialTree,
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
<QueryBuilder
|
|
37
|
+
combinatorOptions={COMBINATOR_OPTIONS}
|
|
38
|
+
createLeafValue={() => ({ field: "subject", operator: "contains", value: "" })}
|
|
39
|
+
renderLeaf={({ value, onChange }) => <ConditionFields value={value} onChange={onChange} />}
|
|
40
|
+
tree={tree}
|
|
41
|
+
/>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Because the tree is normalized and addressed by id, a `patchLeaf` deep in the tree re-renders
|
|
45
|
+
only the rows whose node identity changed — the same `useSyncExternalStore` identity
|
|
46
|
+
discipline the whole state layer rests on.
|
|
47
|
+
|
|
48
|
+
## Nesting, and depth
|
|
49
|
+
|
|
50
|
+
A group renders leaf rows and nested groups, recursively. The nested group wears a
|
|
51
|
+
semantic-token inline-start rail so depth reads without a raw palette colour, and it moves to
|
|
52
|
+
the sunken surface so it recedes rather than floating at the same level as its parent.
|
|
53
|
+
|
|
54
|
+
<Canvas of={QueryBuilderStories.AllStates} />
|
|
55
|
+
|
|
56
|
+
## Driving it
|
|
57
|
+
|
|
58
|
+
Every control is nameable, not a `data-testid`: the combinator select is named `Match` by the
|
|
59
|
+
field label, the leaf controls by their own labels, and each delete is an `IconButton` whose
|
|
60
|
+
required `label` makes it findable. Add a condition, nest a group, flip a combinator, delete a
|
|
61
|
+
row — all reachable by role and name.
|
|
62
|
+
|
|
63
|
+
<Canvas of={QueryBuilderStories.Interactive} />
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import type { SerializedTree } from "@charcuterie/logic"
|
|
2
|
+
import { createTree, useTree } from "@charcuterie/logic"
|
|
3
|
+
import type { Meta, StoryObj } from "@storybook/react"
|
|
4
|
+
import type { ReactNode } from "react"
|
|
5
|
+
import { StorySection } from "../board.storyHelpers.tsx"
|
|
6
|
+
import { Select } from "../Select/Select.tsx"
|
|
7
|
+
import { QueryBuilder } from "./QueryBuilder.tsx"
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The concrete demo leaf — a field/operator/value triple, Mail
|
|
11
|
+
* Sifter's shape. `QueryBuilder` never sees this type; it flows
|
|
12
|
+
* through `renderLeaf` and `createLeafValue` untouched, which is what
|
|
13
|
+
* lets mux-magic pass a non-uniform per-kind shape instead.
|
|
14
|
+
*/
|
|
15
|
+
type DemoLeaf = {
|
|
16
|
+
field: string
|
|
17
|
+
operator: string
|
|
18
|
+
value: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type Combinator = "and" | "or"
|
|
22
|
+
|
|
23
|
+
const COMBINATOR_OPTIONS: readonly {
|
|
24
|
+
label: string
|
|
25
|
+
value: Combinator
|
|
26
|
+
}[] = [
|
|
27
|
+
{ label: "ALL — every condition", value: "and" },
|
|
28
|
+
{ label: "ANY — one condition", value: "or" },
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
const FIELD_OPTIONS = [
|
|
32
|
+
{ label: "Subject", value: "subject" },
|
|
33
|
+
{ label: "From", value: "from" },
|
|
34
|
+
{ label: "Body", value: "body" },
|
|
35
|
+
] as const
|
|
36
|
+
|
|
37
|
+
const OPERATOR_OPTIONS = [
|
|
38
|
+
{ label: "contains", value: "contains" },
|
|
39
|
+
{ label: "is", value: "is" },
|
|
40
|
+
{ label: "starts with", value: "startsWith" },
|
|
41
|
+
] as const
|
|
42
|
+
|
|
43
|
+
const createLeafValue = (): DemoLeaf => ({
|
|
44
|
+
field: "subject",
|
|
45
|
+
operator: "contains",
|
|
46
|
+
value: "",
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
const renderLeaf = ({
|
|
50
|
+
onChange,
|
|
51
|
+
value,
|
|
52
|
+
}: {
|
|
53
|
+
nodeId: string
|
|
54
|
+
onChange: (value: DemoLeaf) => void
|
|
55
|
+
value: DemoLeaf
|
|
56
|
+
}): ReactNode => (
|
|
57
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
58
|
+
<Select
|
|
59
|
+
label="Field"
|
|
60
|
+
onChange={(field) => {
|
|
61
|
+
onChange({ ...value, field })
|
|
62
|
+
}}
|
|
63
|
+
options={FIELD_OPTIONS}
|
|
64
|
+
size="sm"
|
|
65
|
+
value={value.field}
|
|
66
|
+
/>
|
|
67
|
+
|
|
68
|
+
<Select
|
|
69
|
+
label="Operator"
|
|
70
|
+
onChange={(operator) => {
|
|
71
|
+
onChange({ ...value, operator })
|
|
72
|
+
}}
|
|
73
|
+
options={OPERATOR_OPTIONS}
|
|
74
|
+
size="sm"
|
|
75
|
+
value={value.operator}
|
|
76
|
+
/>
|
|
77
|
+
|
|
78
|
+
<input
|
|
79
|
+
aria-label="Value"
|
|
80
|
+
className="min-w-40 grow rounded-md border border-border-default bg-surface-raised px-3 py-1.5 text-content-primary text-sm"
|
|
81
|
+
onChange={(changeEvent) => {
|
|
82
|
+
onChange({
|
|
83
|
+
...value,
|
|
84
|
+
value: changeEvent.currentTarget.value,
|
|
85
|
+
})
|
|
86
|
+
}}
|
|
87
|
+
value={value.value}
|
|
88
|
+
/>
|
|
89
|
+
</div>
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
const FLAT_TREE: SerializedTree<Combinator, DemoLeaf> = {
|
|
93
|
+
children: [
|
|
94
|
+
{
|
|
95
|
+
kind: "leaf",
|
|
96
|
+
value: {
|
|
97
|
+
field: "from",
|
|
98
|
+
operator: "contains",
|
|
99
|
+
value: "@newsletter",
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
kind: "leaf",
|
|
104
|
+
value: {
|
|
105
|
+
field: "subject",
|
|
106
|
+
operator: "contains",
|
|
107
|
+
value: "sale",
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
combinator: "and",
|
|
112
|
+
kind: "group",
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const NESTED_TREE: SerializedTree<Combinator, DemoLeaf> = {
|
|
116
|
+
children: [
|
|
117
|
+
{
|
|
118
|
+
kind: "leaf",
|
|
119
|
+
value: {
|
|
120
|
+
field: "from",
|
|
121
|
+
operator: "is",
|
|
122
|
+
value: "billing@acme.test",
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
children: [
|
|
127
|
+
{
|
|
128
|
+
kind: "leaf",
|
|
129
|
+
value: {
|
|
130
|
+
field: "subject",
|
|
131
|
+
operator: "contains",
|
|
132
|
+
value: "invoice",
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
kind: "leaf",
|
|
137
|
+
value: {
|
|
138
|
+
field: "subject",
|
|
139
|
+
operator: "contains",
|
|
140
|
+
value: "receipt",
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
combinator: "or",
|
|
145
|
+
kind: "group",
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
combinator: "and",
|
|
149
|
+
kind: "group",
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const QueryBuilderHarness = ({
|
|
153
|
+
initialTree,
|
|
154
|
+
}: {
|
|
155
|
+
initialTree?: SerializedTree<Combinator, DemoLeaf>
|
|
156
|
+
}): ReactNode => {
|
|
157
|
+
const tree = useTree<Combinator, DemoLeaf>({
|
|
158
|
+
defaultCombinator: "and",
|
|
159
|
+
initialTree,
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
return (
|
|
163
|
+
<QueryBuilder
|
|
164
|
+
combinatorOptions={COMBINATOR_OPTIONS}
|
|
165
|
+
createLeafValue={createLeafValue}
|
|
166
|
+
renderLeaf={renderLeaf}
|
|
167
|
+
tree={tree}
|
|
168
|
+
/>
|
|
169
|
+
)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const meta = {
|
|
173
|
+
title: "Components/QueryBuilder",
|
|
174
|
+
component: QueryBuilder,
|
|
175
|
+
parameters: { layout: "padded" },
|
|
176
|
+
args: {
|
|
177
|
+
combinatorOptions: COMBINATOR_OPTIONS,
|
|
178
|
+
createLeafValue,
|
|
179
|
+
renderLeaf,
|
|
180
|
+
tree: createTree<Combinator, DemoLeaf>({
|
|
181
|
+
defaultCombinator: "and",
|
|
182
|
+
}),
|
|
183
|
+
},
|
|
184
|
+
} satisfies Meta<typeof QueryBuilder<Combinator, DemoLeaf>>
|
|
185
|
+
|
|
186
|
+
export default meta
|
|
187
|
+
|
|
188
|
+
type Story = StoryObj<typeof meta>
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* A flat group of two conditions joined by ALL. Change the combinator,
|
|
192
|
+
* edit a condition, or add another with "+ Add condition".
|
|
193
|
+
*/
|
|
194
|
+
export const Default: Story = {
|
|
195
|
+
render: () => (
|
|
196
|
+
<QueryBuilderHarness initialTree={FLAT_TREE} />
|
|
197
|
+
),
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Two shapes side by side: a flat rule, and a nested one where a
|
|
202
|
+
* sub-group joined by ANY sits inside a group joined by ALL. The
|
|
203
|
+
* nested group wears the inline-start accent rail that marks depth.
|
|
204
|
+
*/
|
|
205
|
+
export const AllStates: Story = {
|
|
206
|
+
render: () => (
|
|
207
|
+
<div className="flex flex-col gap-6">
|
|
208
|
+
<StorySection title="Flat — ALL of two conditions">
|
|
209
|
+
<QueryBuilderHarness initialTree={FLAT_TREE} />
|
|
210
|
+
</StorySection>
|
|
211
|
+
|
|
212
|
+
<StorySection title="Nested — ALL, with an ANY sub-group">
|
|
213
|
+
<QueryBuilderHarness initialTree={NESTED_TREE} />
|
|
214
|
+
</StorySection>
|
|
215
|
+
</div>
|
|
216
|
+
),
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Drive it: add a condition, add a nested group, flip a combinator,
|
|
221
|
+
* delete a row. Starts from a single condition so every control is
|
|
222
|
+
* unique and nameable.
|
|
223
|
+
*/
|
|
224
|
+
export const Interactive: Story = {
|
|
225
|
+
render: () => (
|
|
226
|
+
<QueryBuilderHarness
|
|
227
|
+
initialTree={{
|
|
228
|
+
children: [
|
|
229
|
+
{
|
|
230
|
+
kind: "leaf",
|
|
231
|
+
value: {
|
|
232
|
+
field: "subject",
|
|
233
|
+
operator: "contains",
|
|
234
|
+
value: "urgent",
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
],
|
|
238
|
+
combinator: "and",
|
|
239
|
+
kind: "group",
|
|
240
|
+
}}
|
|
241
|
+
/>
|
|
242
|
+
),
|
|
243
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { composeStories } from "@storybook/react"
|
|
2
|
+
import { expect, userEvent, waitFor } from "storybook/test"
|
|
3
|
+
import { test } from "vitest"
|
|
4
|
+
|
|
5
|
+
import { expectNoAxeViolations } from "../expectNoAxeViolations.testHelpers.ts"
|
|
6
|
+
import { mountStory } from "../mountStory.testHelpers.ts"
|
|
7
|
+
import { expectAgentDrivable } from "../testing/index.ts"
|
|
8
|
+
import * as stories from "./QueryBuilder.stories.tsx"
|
|
9
|
+
|
|
10
|
+
const { AllStates, Default, Interactive } =
|
|
11
|
+
composeStories(stories)
|
|
12
|
+
|
|
13
|
+
test("the root group exposes its combinator as a named 'Match' control", async () => {
|
|
14
|
+
const { canvas, canvasElement } =
|
|
15
|
+
await mountStory(Default)
|
|
16
|
+
|
|
17
|
+
// One root group, so exactly one combinator select — findable by
|
|
18
|
+
// the label `Field` wires, not a testid.
|
|
19
|
+
expectAgentDrivable(canvas, {
|
|
20
|
+
name: "Match",
|
|
21
|
+
role: "combobox",
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
await expectNoAxeViolations(canvasElement)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
test("'+ Add condition' appends a new leaf row", async () => {
|
|
28
|
+
const { canvas, canvasElement } =
|
|
29
|
+
await mountStory(Interactive)
|
|
30
|
+
|
|
31
|
+
// Interactive starts from a single condition, so every control is
|
|
32
|
+
// unique and nameable.
|
|
33
|
+
await expect(
|
|
34
|
+
canvas.getAllByRole("textbox", { name: "Value" }),
|
|
35
|
+
).toHaveLength(1)
|
|
36
|
+
|
|
37
|
+
await userEvent.click(
|
|
38
|
+
expectAgentDrivable(canvas, {
|
|
39
|
+
name: "+ Add condition",
|
|
40
|
+
role: "button",
|
|
41
|
+
}),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
await waitFor(() => {
|
|
45
|
+
expect(
|
|
46
|
+
canvas.getAllByRole("textbox", { name: "Value" }),
|
|
47
|
+
).toHaveLength(2)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
await expectNoAxeViolations(canvasElement)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
test("'+ Add group' nests a second group with its own combinator", async () => {
|
|
54
|
+
const { canvas, canvasElement } =
|
|
55
|
+
await mountStory(Interactive)
|
|
56
|
+
|
|
57
|
+
await expect(
|
|
58
|
+
canvas.getAllByRole("combobox", { name: "Match" }),
|
|
59
|
+
).toHaveLength(1)
|
|
60
|
+
|
|
61
|
+
await userEvent.click(
|
|
62
|
+
expectAgentDrivable(canvas, {
|
|
63
|
+
name: "+ Add group",
|
|
64
|
+
role: "button",
|
|
65
|
+
}),
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
await waitFor(() => {
|
|
69
|
+
expect(
|
|
70
|
+
canvas.getAllByRole("combobox", { name: "Match" }),
|
|
71
|
+
).toHaveLength(2)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// Only the nested group carries a remove control, so it is unique.
|
|
75
|
+
expectAgentDrivable(canvas, {
|
|
76
|
+
name: "Remove group",
|
|
77
|
+
role: "button",
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
await expectNoAxeViolations(canvasElement)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
test("changing the combinator select updates its value", async () => {
|
|
84
|
+
const { canvas } = await mountStory(Interactive)
|
|
85
|
+
|
|
86
|
+
const combinator = expectAgentDrivable(canvas, {
|
|
87
|
+
name: "Match",
|
|
88
|
+
role: "combobox",
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
await expect(combinator).toHaveValue("and")
|
|
92
|
+
|
|
93
|
+
await userEvent.selectOptions(
|
|
94
|
+
combinator,
|
|
95
|
+
"ANY — one condition",
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
await waitFor(() => {
|
|
99
|
+
expect(combinator).toHaveValue("or")
|
|
100
|
+
})
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
test("removing a condition takes its row away", async () => {
|
|
104
|
+
const { canvas } = await mountStory(Interactive)
|
|
105
|
+
|
|
106
|
+
await userEvent.click(
|
|
107
|
+
expectAgentDrivable(canvas, {
|
|
108
|
+
name: "Remove condition",
|
|
109
|
+
role: "button",
|
|
110
|
+
}),
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
await waitFor(() => {
|
|
114
|
+
expect(
|
|
115
|
+
canvas.queryAllByRole("textbox", { name: "Value" }),
|
|
116
|
+
).toHaveLength(0)
|
|
117
|
+
})
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
test("a nested tree renders every group's combinator and passes axe", async () => {
|
|
121
|
+
const { canvas, canvasElement } =
|
|
122
|
+
await mountStory(AllStates)
|
|
123
|
+
|
|
124
|
+
// Flat harness (1 group) + nested harness (root + one sub-group) =
|
|
125
|
+
// three combinator selects, which is the nesting rendering.
|
|
126
|
+
await expect(
|
|
127
|
+
canvas.getAllByRole("combobox", { name: "Match" })
|
|
128
|
+
.length,
|
|
129
|
+
).toBeGreaterThanOrEqual(3)
|
|
130
|
+
|
|
131
|
+
await expectNoAxeViolations(canvasElement)
|
|
132
|
+
})
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { Tree } from "@charcuterie/logic"
|
|
2
|
+
import {
|
|
3
|
+
selectRootGroup,
|
|
4
|
+
useStoreValue,
|
|
5
|
+
} from "@charcuterie/logic"
|
|
6
|
+
import type { ReactNode } from "react"
|
|
7
|
+
|
|
8
|
+
import { QueryBuilderGroup } from "./QueryBuilderGroup.tsx"
|
|
9
|
+
|
|
10
|
+
export type QueryBuilderLabels = {
|
|
11
|
+
addGroup?: string
|
|
12
|
+
addLeaf?: string
|
|
13
|
+
removeGroup?: string
|
|
14
|
+
removeLeaf?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type QueryBuilderProps<Combinator, Leaf> = {
|
|
18
|
+
/**
|
|
19
|
+
* The combinator choices offered in every group's "Match" select.
|
|
20
|
+
* The `value` is opaque — `and`/`or` for a mail rule, `any`/`all`/
|
|
21
|
+
* `none` for a DSL — and the `label` is what a user reads.
|
|
22
|
+
*/
|
|
23
|
+
combinatorOptions: readonly {
|
|
24
|
+
label: string
|
|
25
|
+
value: Combinator
|
|
26
|
+
}[]
|
|
27
|
+
/** The value a fresh leaf is born with when "+ Condition" is pressed. */
|
|
28
|
+
createLeafValue: () => Leaf
|
|
29
|
+
labels?: QueryBuilderLabels
|
|
30
|
+
/**
|
|
31
|
+
* The leaf UI, owned by the app. `QueryBuilder` knows nothing about
|
|
32
|
+
* what a condition *is* — a field/operator/value triple, a
|
|
33
|
+
* non-uniform per-kind shape — only that it can be rendered and
|
|
34
|
+
* patched. The delete control around each leaf is the builder's.
|
|
35
|
+
*/
|
|
36
|
+
renderLeaf: (args: {
|
|
37
|
+
nodeId: string
|
|
38
|
+
onChange: (value: Leaf) => void
|
|
39
|
+
value: Leaf
|
|
40
|
+
}) => ReactNode
|
|
41
|
+
/**
|
|
42
|
+
* The `Tree` core from `useTree`, owned by the consumer — the same
|
|
43
|
+
* arrangement as a `Listbox`'s parent owning `useVisibility`.
|
|
44
|
+
* `QueryBuilder` subscribes to it and drives it; it never creates
|
|
45
|
+
* one, so a consumer keeps `serialize()` and the initial tree.
|
|
46
|
+
*/
|
|
47
|
+
tree: Tree<Combinator, Leaf>
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const DEFAULT_LABELS = {
|
|
51
|
+
addGroup: "Add group",
|
|
52
|
+
addLeaf: "Add condition",
|
|
53
|
+
removeGroup: "Remove group",
|
|
54
|
+
removeLeaf: "Remove condition",
|
|
55
|
+
} satisfies Required<QueryBuilderLabels>
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The generic, nestable AND/OR — and any-combinator — group editor.
|
|
59
|
+
*
|
|
60
|
+
* Two apps in the fleet grow the same widget: Mail Sifter's nested
|
|
61
|
+
* mail rules (leaf = field/operator/value, combinators AND/OR) and
|
|
62
|
+
* mux-magic's job DSL (non-uniform leaves, combinators any/all/none).
|
|
63
|
+
* Both are a recursive group of conditions with a combinator, so the
|
|
64
|
+
* value **and** the combinator are opaque here — `Combinator` and
|
|
65
|
+
* `Leaf` never appear except passed through to the consumer's
|
|
66
|
+
* `renderLeaf` and its `combinatorOptions`.
|
|
67
|
+
*
|
|
68
|
+
* State lives entirely in the `Tree` core from `@charcuterie/logic`;
|
|
69
|
+
* this component holds none of its own. It subscribes with
|
|
70
|
+
* `useStoreValue`, so a `patchLeaf` deep in the tree re-renders only
|
|
71
|
+
* the rows whose node identity changed — the same identity discipline
|
|
72
|
+
* the state layer is built on.
|
|
73
|
+
*
|
|
74
|
+
* The recursion and the per-leaf row each live in their own file
|
|
75
|
+
* (`QueryBuilderGroup`, `QueryBuilderRow`), not exported: a group
|
|
76
|
+
* renders groups, and both are rendered inside a `.map`, which is
|
|
77
|
+
* exactly the shape the member-file rule is for.
|
|
78
|
+
*/
|
|
79
|
+
export const QueryBuilder = <Combinator, Leaf>({
|
|
80
|
+
combinatorOptions,
|
|
81
|
+
createLeafValue,
|
|
82
|
+
labels,
|
|
83
|
+
renderLeaf,
|
|
84
|
+
tree,
|
|
85
|
+
}: QueryBuilderProps<Combinator, Leaf>): ReactNode => {
|
|
86
|
+
const state = useStoreValue(tree)
|
|
87
|
+
|
|
88
|
+
const resolvedLabels = { ...DEFAULT_LABELS, ...labels }
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<QueryBuilderGroup
|
|
92
|
+
combinatorOptions={combinatorOptions}
|
|
93
|
+
createLeafValue={createLeafValue}
|
|
94
|
+
depth={0}
|
|
95
|
+
labels={resolvedLabels}
|
|
96
|
+
node={selectRootGroup(state)}
|
|
97
|
+
renderLeaf={renderLeaf}
|
|
98
|
+
state={state}
|
|
99
|
+
tree={tree}
|
|
100
|
+
/>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Tree,
|
|
3
|
+
TreeGroupNode,
|
|
4
|
+
TreeState,
|
|
5
|
+
} from "@charcuterie/logic"
|
|
6
|
+
import { selectChildNodes } from "@charcuterie/logic"
|
|
7
|
+
import type { ReactNode } from "react"
|
|
8
|
+
|
|
9
|
+
import { Button } from "../Button/Button.tsx"
|
|
10
|
+
import { Card } from "../Card/Card.tsx"
|
|
11
|
+
import { Field } from "../Field/Field.tsx"
|
|
12
|
+
import { IconButton } from "../IconButton/IconButton.tsx"
|
|
13
|
+
import { Select } from "../Select/Select.tsx"
|
|
14
|
+
import { toClassName } from "../toClassName.ts"
|
|
15
|
+
import type { QueryBuilderLabels } from "./QueryBuilder.tsx"
|
|
16
|
+
import { QueryBuilderRow } from "./QueryBuilderRow.tsx"
|
|
17
|
+
|
|
18
|
+
export type QueryBuilderGroupProps<Combinator, Leaf> = {
|
|
19
|
+
combinatorOptions: readonly {
|
|
20
|
+
label: string
|
|
21
|
+
value: Combinator
|
|
22
|
+
}[]
|
|
23
|
+
createLeafValue: () => Leaf
|
|
24
|
+
/** Root is `0`; nested groups deepen and gain the accent rail. */
|
|
25
|
+
depth: number
|
|
26
|
+
labels: Required<QueryBuilderLabels>
|
|
27
|
+
node: TreeGroupNode<Combinator>
|
|
28
|
+
renderLeaf: (args: {
|
|
29
|
+
nodeId: string
|
|
30
|
+
onChange: (value: Leaf) => void
|
|
31
|
+
value: Leaf
|
|
32
|
+
}) => ReactNode
|
|
33
|
+
state: TreeState<Combinator, Leaf>
|
|
34
|
+
tree: Tree<Combinator, Leaf>
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* One match group: a "Match" combinator select, its children (leaf
|
|
39
|
+
* rows and nested groups), and a toolbar to add either. Its own file
|
|
40
|
+
* because it renders itself recursively for nested groups and is
|
|
41
|
+
* itself rendered inside the parent's `.map` — the member-file case.
|
|
42
|
+
*
|
|
43
|
+
* The combinator is opaque, so the native `Select` (which speaks
|
|
44
|
+
* strings) is bridged by `String(value)`: options carry the
|
|
45
|
+
* stringified combinator, and a change is mapped back to the real
|
|
46
|
+
* `Combinator` before it reaches `setCombinator`. That keeps
|
|
47
|
+
* `Combinator` fully generic while still using the platform control
|
|
48
|
+
* that brings type-ahead, the mobile wheel, and form semantics for
|
|
49
|
+
* free.
|
|
50
|
+
*/
|
|
51
|
+
export const QueryBuilderGroup = <Combinator, Leaf>({
|
|
52
|
+
combinatorOptions,
|
|
53
|
+
createLeafValue,
|
|
54
|
+
depth,
|
|
55
|
+
labels,
|
|
56
|
+
node,
|
|
57
|
+
renderLeaf,
|
|
58
|
+
state,
|
|
59
|
+
tree,
|
|
60
|
+
}: QueryBuilderGroupProps<Combinator, Leaf>): ReactNode => {
|
|
61
|
+
const children = selectChildNodes(state, node.id)
|
|
62
|
+
|
|
63
|
+
const selectOptions = combinatorOptions.map((option) => ({
|
|
64
|
+
label: option.label,
|
|
65
|
+
value: String(option.value),
|
|
66
|
+
}))
|
|
67
|
+
|
|
68
|
+
const card = (
|
|
69
|
+
<Card
|
|
70
|
+
// Nested groups sit on the sunken surface so the depth reads as
|
|
71
|
+
// recession, not another raised card floating at the same level.
|
|
72
|
+
surface={depth === 0 ? "raised" : "sunken"}
|
|
73
|
+
>
|
|
74
|
+
<div className="flex flex-col gap-3">
|
|
75
|
+
<div className="flex items-start justify-between gap-2">
|
|
76
|
+
<div className="min-w-52">
|
|
77
|
+
<Field label="Match">
|
|
78
|
+
<Select
|
|
79
|
+
onChange={(nextValue) => {
|
|
80
|
+
const match = combinatorOptions.find(
|
|
81
|
+
(option) =>
|
|
82
|
+
String(option.value) === nextValue,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
if (match) {
|
|
86
|
+
tree.setCombinator(node.id, match.value)
|
|
87
|
+
}
|
|
88
|
+
}}
|
|
89
|
+
options={selectOptions}
|
|
90
|
+
value={String(node.combinator)}
|
|
91
|
+
/>
|
|
92
|
+
</Field>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
{depth === 0 ? null : (
|
|
96
|
+
<IconButton
|
|
97
|
+
appearance="ghost"
|
|
98
|
+
intent="danger"
|
|
99
|
+
label={labels.removeGroup}
|
|
100
|
+
onClick={() => {
|
|
101
|
+
tree.removeNode(node.id)
|
|
102
|
+
}}
|
|
103
|
+
size="sm"
|
|
104
|
+
>
|
|
105
|
+
✕
|
|
106
|
+
</IconButton>
|
|
107
|
+
)}
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
{children.length === 0 ? null : (
|
|
111
|
+
<div className="flex flex-col gap-2">
|
|
112
|
+
{children.map((child) =>
|
|
113
|
+
child.kind === "group" ? (
|
|
114
|
+
<QueryBuilderGroup
|
|
115
|
+
combinatorOptions={combinatorOptions}
|
|
116
|
+
createLeafValue={createLeafValue}
|
|
117
|
+
depth={depth + 1}
|
|
118
|
+
key={child.id}
|
|
119
|
+
labels={labels}
|
|
120
|
+
node={child}
|
|
121
|
+
renderLeaf={renderLeaf}
|
|
122
|
+
state={state}
|
|
123
|
+
tree={tree}
|
|
124
|
+
/>
|
|
125
|
+
) : (
|
|
126
|
+
<QueryBuilderRow
|
|
127
|
+
key={child.id}
|
|
128
|
+
label={labels.removeLeaf}
|
|
129
|
+
nodeId={child.id}
|
|
130
|
+
onChange={(value) => {
|
|
131
|
+
tree.patchLeaf(child.id, value)
|
|
132
|
+
}}
|
|
133
|
+
onRemove={() => {
|
|
134
|
+
tree.removeNode(child.id)
|
|
135
|
+
}}
|
|
136
|
+
renderLeaf={renderLeaf}
|
|
137
|
+
value={child.value}
|
|
138
|
+
/>
|
|
139
|
+
),
|
|
140
|
+
)}
|
|
141
|
+
</div>
|
|
142
|
+
)}
|
|
143
|
+
|
|
144
|
+
<div className="flex flex-wrap gap-2">
|
|
145
|
+
<Button
|
|
146
|
+
appearance="outline"
|
|
147
|
+
intent="neutral"
|
|
148
|
+
onClick={() => {
|
|
149
|
+
tree.addLeaf(node.id, createLeafValue())
|
|
150
|
+
}}
|
|
151
|
+
size="sm"
|
|
152
|
+
>
|
|
153
|
+
{`+ ${labels.addLeaf}`}
|
|
154
|
+
</Button>
|
|
155
|
+
|
|
156
|
+
<Button
|
|
157
|
+
appearance="outline"
|
|
158
|
+
intent="neutral"
|
|
159
|
+
onClick={() => {
|
|
160
|
+
tree.addGroup(node.id)
|
|
161
|
+
}}
|
|
162
|
+
size="sm"
|
|
163
|
+
>
|
|
164
|
+
{`+ ${labels.addGroup}`}
|
|
165
|
+
</Button>
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
</Card>
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
// Depth is shown with a semantic-token inline-start rail. The colour
|
|
172
|
+
// utility paints all four sides, but only the inline-start edge has
|
|
173
|
+
// a width, so only it renders — no raw palette colour anywhere.
|
|
174
|
+
return depth === 0 ? (
|
|
175
|
+
card
|
|
176
|
+
) : (
|
|
177
|
+
<div
|
|
178
|
+
className={toClassName(
|
|
179
|
+
"border-intent-accent-border border-s-2 ps-3",
|
|
180
|
+
)}
|
|
181
|
+
>
|
|
182
|
+
{card}
|
|
183
|
+
</div>
|
|
184
|
+
)
|
|
185
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { ReactNode } from "react"
|
|
2
|
+
|
|
3
|
+
import { IconButton } from "../IconButton/IconButton.tsx"
|
|
4
|
+
|
|
5
|
+
export type QueryBuilderRowProps<Leaf> = {
|
|
6
|
+
/** The accessible name of the row's delete control. */
|
|
7
|
+
label: string
|
|
8
|
+
nodeId: string
|
|
9
|
+
onChange: (value: Leaf) => void
|
|
10
|
+
onRemove: () => void
|
|
11
|
+
renderLeaf: (args: {
|
|
12
|
+
nodeId: string
|
|
13
|
+
onChange: (value: Leaf) => void
|
|
14
|
+
value: Leaf
|
|
15
|
+
}) => ReactNode
|
|
16
|
+
value: Leaf
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A single leaf row: the app's own leaf UI, plus the builder's delete
|
|
21
|
+
* control. Its own file for the same reason `ListboxOption` is —
|
|
22
|
+
* rendered inside the group's `.map`, so it cannot be an inline
|
|
23
|
+
* component — and it is a member file (`QueryBuilder*.tsx`, not
|
|
24
|
+
* `QueryBuilder/QueryBuilder.tsx`), so it stays out of the barrel and
|
|
25
|
+
* the component count by rule.
|
|
26
|
+
*
|
|
27
|
+
* The delete control is an `IconButton` because a bare glyph is not an
|
|
28
|
+
* accessible name; its required `label` is what makes each row's
|
|
29
|
+
* remove button findable and unique per condition.
|
|
30
|
+
*/
|
|
31
|
+
export const QueryBuilderRow = <Leaf,>({
|
|
32
|
+
label,
|
|
33
|
+
nodeId,
|
|
34
|
+
onChange,
|
|
35
|
+
onRemove,
|
|
36
|
+
renderLeaf,
|
|
37
|
+
value,
|
|
38
|
+
}: QueryBuilderRowProps<Leaf>): ReactNode => (
|
|
39
|
+
<div className="flex items-start gap-2">
|
|
40
|
+
<div className="grow">
|
|
41
|
+
{renderLeaf({ nodeId, onChange, value })}
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<IconButton
|
|
45
|
+
appearance="ghost"
|
|
46
|
+
intent="danger"
|
|
47
|
+
label={label}
|
|
48
|
+
onClick={onRemove}
|
|
49
|
+
size="sm"
|
|
50
|
+
>
|
|
51
|
+
✕
|
|
52
|
+
</IconButton>
|
|
53
|
+
</div>
|
|
54
|
+
)
|
package/src/index.ts
CHANGED
|
@@ -173,6 +173,11 @@ export {
|
|
|
173
173
|
toProgressPercent,
|
|
174
174
|
toProgressValue,
|
|
175
175
|
} from "./ProgressBar/progressValue.ts"
|
|
176
|
+
export type {
|
|
177
|
+
QueryBuilderLabels,
|
|
178
|
+
QueryBuilderProps,
|
|
179
|
+
} from "./QueryBuilder/QueryBuilder.tsx"
|
|
180
|
+
export { QueryBuilder } from "./QueryBuilder/QueryBuilder.tsx"
|
|
176
181
|
export type {
|
|
177
182
|
RadioGroupProps,
|
|
178
183
|
RadioItem,
|
package/src/sourceRules.test.ts
CHANGED
|
@@ -364,7 +364,16 @@ test("the barrel is the only place components are re-exported", async () => {
|
|
|
364
364
|
// `useToolbarOverflow.ts` and `chooseVisibleCount.ts` are its
|
|
365
365
|
// members and stay out of this count by the `<Name>/<Name>.tsx`
|
|
366
366
|
// rule.
|
|
367
|
-
|
|
367
|
+
//
|
|
368
|
+
// `QueryBuilder` — the generic nestable AND/OR (any-combinator) group
|
|
369
|
+
// editor Mail Sifter's nested rules and mux-magic's job DSL both need
|
|
370
|
+
// — is the library's first recursive component and its first with a
|
|
371
|
+
// fully opaque value *and* combinator: +1 -> 44. `QueryBuilderGroup`
|
|
372
|
+
// and `QueryBuilderRow` are its members — a group renders groups, and
|
|
373
|
+
// both are rendered inside a `.map` — and stay out of this count and
|
|
374
|
+
// the barrel by the `<Name>/<Name>.tsx` rule, exactly as
|
|
375
|
+
// `SegmentedOption` and `ListboxOption` do.
|
|
376
|
+
expect(componentNames.length).toBe(44)
|
|
368
377
|
|
|
369
378
|
for (const name of componentNames) {
|
|
370
379
|
expect(barrel).toContain(`export { ${name} }`)
|
|
@@ -448,6 +457,17 @@ const ENTRY_POINT_RUNTIMES: Record<
|
|
|
448
457
|
"./core": [],
|
|
449
458
|
"./jotai": ["jotai"],
|
|
450
459
|
"./preact": ["preact", "preact/hooks"],
|
|
460
|
+
// The request/response data layer. It reaches react-query, the
|
|
461
|
+
// two openapi-* primitives it re-exports, and `react` (the
|
|
462
|
+
// provider's `useState`) — all optional peers, so an app that
|
|
463
|
+
// never imports `./query` resolves none of them. `react/jsx-runtime`
|
|
464
|
+
// is added only at emit, so it is not a source specifier here.
|
|
465
|
+
"./query": [
|
|
466
|
+
"@tanstack/react-query",
|
|
467
|
+
"openapi-fetch",
|
|
468
|
+
"openapi-react-query",
|
|
469
|
+
"react",
|
|
470
|
+
],
|
|
451
471
|
"./signals": ["@preact/signals-core"],
|
|
452
472
|
},
|
|
453
473
|
tokens: {
|