feat(filter-builder): the group header is the ALL/ANY switch
The group header ("MATCH"/"GROUP") was a dead label while the engine
honored group modes all along — buildGroupClause parenthesizes nested
groups and joins each by its own mode, and validation accepted
all/any from day one. The only thing missing was the UI: + Group
birthed ALL groups and no control anywhere could flip one, so the
user's target structures (GROUP(GROUP(... or ...) ...) — 3-level
mixed-mode nesting) were constructible only through the invisible
row-level chips, and standalone ANY-groups not at all (2026-11-01
user report: "MATCH cannot be clicked").
- The header is now the control: MATCH ALL ⇄ MATCH ANY (root — a
synthetic header row, since the root was never projected and its
mode was invisible too), GROUP ALL ⇄ GROUP ANY (nested). ANY is
accented; aria-pressed carries the state. Labels are path-based
(root reads Match, explicit groups read Group) instead of
depth-based, which previously mislabeled top-level groups.
- The row-level chips are untouched — they mix AND/OR inside a group
(A AND (B OR C)), which a global mode toggle cannot express; the
header is the discoverable entry point, the chips the refinement.
- Dropdown audit (the "would it bug out" check): suggestTree is
mode-generic — root-ANY drops group siblings, sibling ANY-groups
survive into the constraint with their mode intact, empty groups
never emit (no 400s) — now pinned. Deep-nesting Go pin: a 3-level
mixed-mode tree evaluated through composed search + the suggestion
endpoint (200, never the empty-group 400). 192 web tests green.
This commit is contained in:
1 parent
5fb80f82ed
commit
2344f5686a
7 files changed
+254
-5
No files matched your search
@@ -2018,6 +2018,34 @@
|
||||
padding: 0.2rem 0.25rem;
|
||||
outline: none;
|
||||
}
|
||||
/* group header = the ALL/ANY switch (2026-11-01): the header was a
|
||||
dead label while the engine honored group modes — now it's the
|
||||
control. ANY is accented: it's the mode that changes semantics. */
|
||||
.fb-group-mode {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
font-size: 0.65rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
padding: 0.15rem 0.5rem;
|
||||
border-radius: 0.4rem;
|
||||
border: 1px solid var(--border);
|
||||
background-color: var(--bg-primary);
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.fb-group-mode:hover {
|
||||
border-color: color-mix(in srgb, var(--accent) 45%, var(--border));
|
||||
color: var(--text-primary);
|
||||
}
|
||||
.fb-group-mode.fb-group-any {
|
||||
border-color: color-mix(in srgb, var(--accent) 45%, var(--border));
|
||||
background-color: var(--accent-muted);
|
||||
color: var(--accent);
|
||||
}
|
||||
.fb-menu {
|
||||
position: absolute;
|
||||
z-index: 60;
|
||||
|
||||
Reference in new issue
Block a user