@stapel/search-react 0.21.0 → 0.23.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/CHANGELOG.md +141 -0
- package/MODULE.md +12 -0
- package/README.md +143 -2
- package/dist/api/types.d.ts +37 -3
- package/dist/api/types.d.ts.map +1 -1
- package/dist/api/types.js.map +1 -1
- package/dist/default/FacetGroupControl.d.ts +53 -5
- package/dist/default/FacetGroupControl.d.ts.map +1 -1
- package/dist/default/FacetGroupControl.js +189 -8
- package/dist/default/FacetGroupControl.js.map +1 -1
- package/dist/default/FacetPanelPane.d.ts +41 -0
- package/dist/default/FacetPanelPane.d.ts.map +1 -1
- package/dist/default/FacetPanelPane.js +72 -18
- package/dist/default/FacetPanelPane.js.map +1 -1
- package/dist/default/FilterChips.d.ts.map +1 -1
- package/dist/default/FilterChips.js +2 -2
- package/dist/default/FilterChips.js.map +1 -1
- package/dist/default/PartitionChips.d.ts +37 -0
- package/dist/default/PartitionChips.d.ts.map +1 -0
- package/dist/default/PartitionChips.js +120 -0
- package/dist/default/PartitionChips.js.map +1 -0
- package/dist/default/PopularValues.d.ts +58 -0
- package/dist/default/PopularValues.d.ts.map +1 -0
- package/dist/default/PopularValues.js +46 -0
- package/dist/default/PopularValues.js.map +1 -0
- package/dist/default/RangeFilterRow.d.ts.map +1 -1
- package/dist/default/RangeFilterRow.js +65 -11
- package/dist/default/RangeFilterRow.js.map +1 -1
- package/dist/default/SearchPage.d.ts +49 -0
- package/dist/default/SearchPage.d.ts.map +1 -1
- package/dist/default/SearchPage.js +43 -2
- package/dist/default/SearchPage.js.map +1 -1
- package/dist/default/index.d.ts +7 -3
- package/dist/default/index.d.ts.map +1 -1
- package/dist/default/index.js +8 -3
- package/dist/default/index.js.map +1 -1
- package/dist/headless/useFacetLabels.js +7 -7
- package/dist/headless/useFacetLabels.js.map +1 -1
- package/dist/i18n/es.d.ts.map +1 -1
- package/dist/i18n/es.js +9 -0
- package/dist/i18n/es.js.map +1 -1
- package/dist/i18n/keys.d.ts +52 -0
- package/dist/i18n/keys.d.ts.map +1 -1
- package/dist/i18n/keys.js +62 -0
- package/dist/i18n/keys.js.map +1 -1
- package/dist/i18n/ru.d.ts.map +1 -1
- package/dist/i18n/ru.js +9 -0
- package/dist/i18n/ru.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/state/facets.d.ts +90 -6
- package/dist/state/facets.d.ts.map +1 -1
- package/dist/state/facets.js +216 -15
- package/dist/state/facets.js.map +1 -1
- package/dist/state/ranges.d.ts +22 -0
- package/dist/state/ranges.d.ts.map +1 -1
- package/dist/state/ranges.js +30 -0
- package/dist/state/ranges.js.map +1 -1
- package/dist/state/translit.d.ts +58 -0
- package/dist/state/translit.d.ts.map +1 -0
- package/dist/state/translit.js +115 -0
- package/dist/state/translit.js.map +1 -0
- package/llms.txt +3 -1
- package/manifest.json +45 -1
- package/nav-manifest.json +1 -1
- package/package.json +8 -8
- package/src/analytics/generated/events.json +1 -1
- package/src/api/types.ts +42 -3
- package/src/default/FacetGroupControl.tsx +339 -9
- package/src/default/FacetPanelPane.tsx +131 -19
- package/src/default/FilterChips.tsx +5 -2
- package/src/default/PartitionChips.tsx +204 -0
- package/src/default/PopularValues.tsx +151 -0
- package/src/default/RangeFilterRow.tsx +116 -1
- package/src/default/SearchPage.tsx +61 -2
- package/src/default/index.ts +27 -2
- package/src/headless/useFacetLabels.ts +7 -7
- package/src/i18n/es.ts +9 -0
- package/src/i18n/keys.ts +63 -0
- package/src/i18n/ru.ts +9 -0
- package/src/index.ts +13 -0
- package/src/state/facets.ts +259 -27
- package/src/state/ranges.ts +44 -0
- package/src/state/translit.ts +113 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,146 @@
|
|
|
1
1
|
# @stapel/search-react
|
|
2
2
|
|
|
3
|
+
## 0.23.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e8d7744: search: the rail is the category's own form, and the axes a seller had to fill are the ones a buyer sees first
|
|
8
|
+
|
|
9
|
+
A walk of a live classified's desktop cars page reported three things in one
|
|
10
|
+
breath, and they turned out to be four faults with one shape: the panel was
|
|
11
|
+
answering questions the _answer_ had asked, not the ones the _category_ asks.
|
|
12
|
+
|
|
13
|
+
**The rail is in SCHEMA order, required first.** It ranked by evidence — the
|
|
14
|
+
sum of an axis's counts — which is the right question for a phone chip row
|
|
15
|
+
with room for four and the wrong one for the column a person narrows a
|
|
16
|
+
catalogue in. On three listings the busiest axis is whichever three values
|
|
17
|
+
happen to be counted, so the rail opened on condition and colour while the
|
|
18
|
+
make, the model and the year — the three fields the category marks `mandatory`,
|
|
19
|
+
i.e. the three every seller had to fill — sat below them. `orderFacetGroupsBySchema`
|
|
20
|
+
puts pinned slugs first, then the required features in the schema's own order,
|
|
21
|
+
then the rest in schema order, then what the schema does not name at all in
|
|
22
|
+
evidence order, because with no schema there is no other order to have. Stable
|
|
23
|
+
under a click, which a rail that reshuffles as you tick is not. Past
|
|
24
|
+
`visibleGroups` (default 8) the tail folds under one **All filters (K)**
|
|
25
|
+
control — never a group you have already chosen a value in, because the control
|
|
26
|
+
that removes a filter is the one you came back for. `<SearchPage>` gains
|
|
27
|
+
`partition` (drawn above the price: which half of one template a page is about
|
|
28
|
+
is not a filter among filters) and `pinnedFacets`.
|
|
29
|
+
|
|
30
|
+
**Why the make could vanish.** `facetGroupIsDrawable` is now the one predicate
|
|
31
|
+
the rail and the chip row share, and it says what the old duplicated
|
|
32
|
+
`options.length > 0` said without saying WHY: a group with nothing under it is
|
|
33
|
+
a heading over nothing. The catalogue's `make`, `model`, `generation` and
|
|
34
|
+
`body_type` are `ref_select` features whose config is a bare `optionsRef`
|
|
35
|
+
pointer — no option table in the schema and there never will be — so the moment
|
|
36
|
+
the server's plan does not count one, there is nothing on either side to
|
|
37
|
+
enumerate and the group leaves the page, while every `select`-typed comfort
|
|
38
|
+
option (steering side, power steering, heating) draws its own schema table and
|
|
39
|
+
stays. That is the exact set the walker saw and did not see. The drop is still
|
|
40
|
+
right — a dead heading helps nobody — and it is no longer SILENT: outside
|
|
41
|
+
production one `console.warn` names the axis, says which side is missing
|
|
42
|
+
(uncounted, or a schema that does not define it), and says when the schema
|
|
43
|
+
calls the axis **required**. Both owners of that wiring fault can now see it
|
|
44
|
+
from the page. The regression is pinned against the live answer itself, saved
|
|
45
|
+
as a fixture (`test/liveCars.ts`, captured 2026-09-04): an axis with evidence
|
|
46
|
+
buckets survives the parent node's EMPTY feature list and a def that names it
|
|
47
|
+
without typing it.
|
|
48
|
+
|
|
49
|
+
**A dictionary outranks the pills, and on desktop it is a FIELD.** The live
|
|
50
|
+
make axis is `maxSelected: 1` over a 418-value vocabulary, so "pick one" won
|
|
51
|
+
the shape contest and the control it produced was four hundred pills in a 280px
|
|
52
|
+
rail — a wall with a different border radius. `facetGroupShape` now asks
|
|
53
|
+
"dictionary?" before "single-choice?". And on the rail
|
|
54
|
+
(`dictionaryMode="field"`, which `<SearchPage>` sets for the column layout) a
|
|
55
|
+
dictionary closes into a select-style field reading its chosen values or _Any_,
|
|
56
|
+
which opens the searchable list you already had: a real `role="combobox"`
|
|
57
|
+
button, ArrowDown to open, Escape to close. The phone sheet keeps the list
|
|
58
|
+
inline — the sheet is already the disclosure.
|
|
59
|
+
|
|
60
|
+
**A bounded integer is a picker, not a bare number.** The year was two empty
|
|
61
|
+
number fields; it is `int` with `min: 1900, max: 2027`, which is 128 values and
|
|
62
|
+
therefore a list. `RangeGroup.picker` carries it (newest first — a year picker
|
|
63
|
+
that opens on 1900 is a picker nobody uses) for any `int` feature whose schema
|
|
64
|
+
declares both bounds and spans at most `RANGE_PICKER_MAX_VALUES` (300), and
|
|
65
|
+
`<RangeFilterRow>` draws two from/to selects. Typing still works and carries
|
|
66
|
+
the bounds: a valid in-range number narrows the list, anything else brings the
|
|
67
|
+
whole list back with the bounds said in words, because a year below the
|
|
68
|
+
catalogue's floor otherwise does nothing at all, silently. A mileage
|
|
69
|
+
(`1..1000000`) and the core price stay two typed fields.
|
|
70
|
+
|
|
71
|
+
**The rail's scrollbar is in the gutter, not on the filters.**
|
|
72
|
+
`scrollbar-width: thin` and `scrollbar-gutter: stable` are the standard half
|
|
73
|
+
and they are not enough: on every overlay-scrollbar platform — a Mac by
|
|
74
|
+
default, every iOS browser — the bar is painted OVER the content and the gutter
|
|
75
|
+
reserves nothing, which is why it lay across the checkbox labels. The rail now
|
|
76
|
+
also declares a classic bar through the WebKit pseudo-elements, with a real
|
|
77
|
+
width so it displaces rather than overlaps, and every colour a `--stapel-*`
|
|
78
|
+
custom property so it is the panel's own hairline in both themes rather than a
|
|
79
|
+
grey that glows in the dark one. `railScrollbarCss()` and `RAIL_CLASS` are
|
|
80
|
+
exported for a host that lays out its own column.
|
|
81
|
+
|
|
82
|
+
**`<PartitionChips variant="segmented">`** is the desktop rail's shape of the
|
|
83
|
+
same choice: one joined control under its own label instead of a wrapping pill
|
|
84
|
+
row, which in a 280px column is two ragged lines. The SEMANTICS do not vary
|
|
85
|
+
with the variant — the same `radiogroup`, the same roving tabindex, the same
|
|
86
|
+
arrow keys — because a segmented look is a border-radius decision, and swapping
|
|
87
|
+
in a component that draws joined cells by giving up "exactly one of these is
|
|
88
|
+
true" would trade the accessible half of the control for the visible half.
|
|
89
|
+
|
|
90
|
+
Also: `FacetLabels.label_translatable` is typed. The live answer sends it
|
|
91
|
+
beside every group label and the pinned `schema.json` does not describe it, so
|
|
92
|
+
a fixture captured from the wire was a type error.
|
|
93
|
+
|
|
94
|
+
## 0.22.0
|
|
95
|
+
|
|
96
|
+
### Minor Changes
|
|
97
|
+
|
|
98
|
+
- 65e0c9f: search: headings come from the server, a vocabulary becomes a dictionary, and two browse surfaces for a category page
|
|
99
|
+
|
|
100
|
+
**A heading is named, or it is marked.** Group headings and option captions now
|
|
101
|
+
resolve in one stated order — `facet_labels` from the answer, then the category
|
|
102
|
+
feature definition, then the raw slug. The slug arm is not a fallback anyone may
|
|
103
|
+
ship: it renders, because a heading a person cannot read still beats options
|
|
104
|
+
with no heading at all, and it renders MARKED — `labelSource: "none"` on the
|
|
105
|
+
group and the option, `data-label-source` on the drawn control, and one
|
|
106
|
+
`console.warn` per slug outside production, so a storefront's own test fails on
|
|
107
|
+
it. Measured on a live classified's cars branch the page passed an empty feature
|
|
108
|
+
list and the whole rail was raw index slugs: the make group was on screen,
|
|
109
|
+
unlabelled, and the complaint that came back was "I cannot pick a make".
|
|
110
|
+
`FacetGroup` and `FacetOption` both carry `labelSource`
|
|
111
|
+
(`"server" | "schema" | "host" | "none"`) — "did anybody actually name this?" is
|
|
112
|
+
a question two surfaces have to answer and neither can answer by reading the
|
|
113
|
+
string.
|
|
114
|
+
|
|
115
|
+
**A vocabulary level is a DICTIONARY.** Past eight counted buckets a
|
|
116
|
+
`ref_select` group — or an untyped group that long, which is the live case where
|
|
117
|
+
no schema was threaded through — stops being eight checkboxes plus a
|
|
118
|
+
`Show all (418)` and becomes the busiest values, a search box over the rest, and
|
|
119
|
+
the chosen values pinned above it where a filter cannot go invisible. The box
|
|
120
|
+
matches ACROSS ALPHABETS: `тойота` finds `Toyota`, `тимберленд` finds
|
|
121
|
+
`Timberland`, `ровер` finds `Land Rover`. That is a prefix rule over two keys
|
|
122
|
+
per word — a transliteration, and its consonant skeleton, because the two
|
|
123
|
+
scripts disagree exactly on the vowels of a borrowed name (`timberlend` vs
|
|
124
|
+
`timberland`, both `tmbrlnd`). Table-driven and dependency-free, and local: the
|
|
125
|
+
buckets are already in the answer, so nothing is requested per keystroke.
|
|
126
|
+
`facetGroupShape` gains a `"dictionary"` arm beside `segmented`/`nested`/
|
|
127
|
+
`checkbox`, and the threshold counts EVIDENCE buckets — a zero-filled option
|
|
128
|
+
table or a schema-only tail is still a list a person can read.
|
|
129
|
+
|
|
130
|
+
**`<PopularValues>`** prints the busiest values of one group as a multi-column
|
|
131
|
+
`Toyota 802` block that applies the filter on click — a table of contents for a
|
|
132
|
+
category, drawn from the same drill-down counts the panel shows, so a value
|
|
133
|
+
cannot read `802` in one place and `93` in the other. `hidden` is a PROP rather
|
|
134
|
+
than a media query inside: whether a 390px screen has room for forty links is a
|
|
135
|
+
fact about the page, and the page is the storefront's.
|
|
136
|
+
|
|
137
|
+
**`<PartitionChips>`** is the single-select row a `chips` category draws instead
|
|
138
|
+
of a tile grid: `Все | child…` from `{id, path, name}`, controlled — the choice
|
|
139
|
+
is a `category` in the URL, not state in a chip row. It is a real `radiogroup`
|
|
140
|
+
with roving tabindex and arrow keys, because exactly one of them is true at a
|
|
141
|
+
time and a row of `aria-pressed` toggles announces the opposite: independent
|
|
142
|
+
switches, with no reason why pressing one released another.
|
|
143
|
+
|
|
3
144
|
## 0.21.0
|
|
4
145
|
|
|
5
146
|
### Minor Changes
|
package/MODULE.md
CHANGED
|
@@ -207,6 +207,18 @@ Set on `<SearchPage>`, it reaches both filter surfaces: the desktop panel and
|
|
|
207
207
|
the phone chip row read one `useFacetPanel`, so they cannot print two words for
|
|
208
208
|
one value.
|
|
209
209
|
|
|
210
|
+
**The gap the seam does not close: EXISTENCE.** `resolveFacetLabels` names
|
|
211
|
+
values; it does not enumerate them. A `ref_select` group the server did not
|
|
212
|
+
count therefore has no options from either side — the answer counted nothing,
|
|
213
|
+
the schema holds a pointer — and `facetGroupIsDrawable` refuses to draw a
|
|
214
|
+
heading over nothing. Measured on a live cars leaf, that is exactly the set a
|
|
215
|
+
buyer misses (make, model, generation, body type) while every `select`-typed
|
|
216
|
+
option keeps its schema table. The client cannot invent the values, so the fix
|
|
217
|
+
is on the other side — the facet plan must count a required vocabulary axis —
|
|
218
|
+
and until it does, the disappearance is reported: one `console.warn` per slug
|
|
219
|
+
outside production, naming the axis, the missing side, and whether the schema
|
|
220
|
+
marks it required.
|
|
221
|
+
|
|
210
222
|
## The chip row's order is the row's product
|
|
211
223
|
|
|
212
224
|
At 390px about four chips fit before the fold. On a live phone category the
|
package/README.md
CHANGED
|
@@ -141,6 +141,147 @@ the raw value; a value nobody names keeps printing itself. `renderCategoryFilter
|
|
|
141
141
|
also becomes the leading chip of the phone filter row, which is where the
|
|
142
142
|
catalogue's deeper levels are chosen on a result list.
|
|
143
143
|
|
|
144
|
+
## A heading is named by the server, or it is marked
|
|
145
|
+
|
|
146
|
+
Group headings and option captions resolve in one order and one only:
|
|
147
|
+
`facet_labels` from the answer → the category feature definition → the raw
|
|
148
|
+
slug. The last arm is not a fallback anyone ships: it renders (a heading a
|
|
149
|
+
person cannot read still beats options with no heading), and it renders
|
|
150
|
+
**marked** — `labelSource: "none"` on the group, `data-label-source="none"` on
|
|
151
|
+
the drawn control, and one `console.warn` per slug outside production. A
|
|
152
|
+
storefront's own test asserts on that attribute; measured on a live cars branch
|
|
153
|
+
the whole rail was raw slugs and the complaint that came back was "I cannot
|
|
154
|
+
pick a make".
|
|
155
|
+
|
|
156
|
+
Every `FacetGroup` and every `FacetOption` carries `labelSource:
|
|
157
|
+
"server" | "schema" | "host" | "none"`, so "did anybody actually name this?" is
|
|
158
|
+
answerable without looking at the string.
|
|
159
|
+
|
|
160
|
+
## The rail is in schema order, required first
|
|
161
|
+
|
|
162
|
+
The panel used to rank its groups by **evidence** — the sum of an axis's
|
|
163
|
+
counts. That is the right question for a phone chip row with room for four and
|
|
164
|
+
the wrong one for the column a person narrows a catalogue in: on a live cars
|
|
165
|
+
page it opened on *condition* and *colour*, because with three listings the
|
|
166
|
+
busiest axis is whichever three values happen to be counted, while *make*,
|
|
167
|
+
*model* and *year* — the three fields the category marks `mandatory`, i.e. the
|
|
168
|
+
three every seller had to fill — sat below them.
|
|
169
|
+
|
|
170
|
+
The rail now follows the **category's own order**, in four bands: pinned slugs,
|
|
171
|
+
then `mandatory` features in schema order, then the rest in schema order, then
|
|
172
|
+
whatever the schema does not name at all (evidence order among themselves —
|
|
173
|
+
with no schema there is no other order to have). Stable under a click, which a
|
|
174
|
+
rail that reshuffles as you tick is not.
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
<SearchPage
|
|
178
|
+
partition={<PartitionChips variant="segmented" items={children} … />}
|
|
179
|
+
pinnedFacets={["body_type_ref_select"]}
|
|
180
|
+
/>
|
|
181
|
+
orderFacetGroupsBySchema({ groups, categoryFeatures, pinned })
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Past `visibleGroups` (default `FACET_VISIBLE_GROUPS`, 8) the tail folds under
|
|
185
|
+
one **All filters (K)** control — except a group you have already chosen a
|
|
186
|
+
value in, which is never folded away: the control that removes a filter is the
|
|
187
|
+
one you came back for. The phone sheet passes `visibleGroups={null}`; a surface
|
|
188
|
+
devoted to filtering has the room.
|
|
189
|
+
|
|
190
|
+
`facetGroupIsDrawable(group)` is the one rule the rail and the chip row share
|
|
191
|
+
for "is there anything to draw here". A group with no options is a heading over
|
|
192
|
+
nothing — after `buildFacetGroups` learned to read the schema, what is left in
|
|
193
|
+
that state is a `ref_select` whose config is a bare `optionsRef` pointer and
|
|
194
|
+
which the server did not count, so there is nothing to enumerate from either
|
|
195
|
+
side. It is not drawn, and outside production it is **named**: a
|
|
196
|
+
`console.warn` says which axis went, why, and whether the schema calls it
|
|
197
|
+
required. That is the fault that took *make* off a live cars rail while every
|
|
198
|
+
`select`-typed comfort option drew its own table and stayed.
|
|
199
|
+
|
|
200
|
+
## A vocabulary is a dictionary, not a checkbox list
|
|
201
|
+
|
|
202
|
+
Past eight **evidence buckets** a `ref_select` group (or an untyped group that
|
|
203
|
+
long — the live case, where no schema was threaded through) stops being a list
|
|
204
|
+
and becomes a dictionary: the busiest values, a search box that filters them
|
|
205
|
+
locally, and the chosen values pinned above the box so a filter is never
|
|
206
|
+
invisible. The box matches **across alphabets** — `тойота` finds `Toyota`,
|
|
207
|
+
`тимберленд` finds `Timberland`, `ровер` finds `Land Rover` — by a prefix rule
|
|
208
|
+
over two keys per word, a transliteration and its consonant skeleton
|
|
209
|
+
(`translitPrefixMatch`, `translitKey`, `consonantKey`; table-driven, no
|
|
210
|
+
dependency). No request per keystroke: the whole bucket list is already in the
|
|
211
|
+
answer — stapel-search caps a vocabulary-backed group at
|
|
212
|
+
`MAX_FACET_VALUES_VOCABULARY` (1000, raised from the shared 200 for exactly
|
|
213
|
+
this), so a 418-term make dictionary arrives whole and the box has everything
|
|
214
|
+
it filters.
|
|
215
|
+
|
|
216
|
+
A dictionary outranks the pills, too: the live `make` axis is `maxSelected: 1`
|
|
217
|
+
over a 418-value vocabulary, so "pick one" used to win and the control it drew
|
|
218
|
+
was four hundred pills in a 280px rail.
|
|
219
|
+
|
|
220
|
+
On the **desktop rail** a dictionary is a select-style FIELD
|
|
221
|
+
(`dictionaryMode="field"`, which `<SearchPage>` sets for the column layout):
|
|
222
|
+
closed it reads the chosen values or *Any*, and it opens the searchable list —
|
|
223
|
+
a real `role="combobox"` button, Enter/Space to open, ArrowDown to open,
|
|
224
|
+
Escape to close. The phone sheet keeps the list inline, because the sheet is
|
|
225
|
+
already the disclosure.
|
|
226
|
+
|
|
227
|
+
```tsx
|
|
228
|
+
facetGroupShape(group) // "segmented" | "nested" | "checkbox" | "dictionary"
|
|
229
|
+
isDictionaryFacet(group) // > FACET_DICTIONARY_THRESHOLD counted buckets
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## A bounded integer is a picker, not a bare number
|
|
233
|
+
|
|
234
|
+
A year is not a quantity a person computes, it is one of a hundred-odd values,
|
|
235
|
+
and on a live cars page it was two empty number fields. An `int` feature whose
|
|
236
|
+
schema declares both bounds and spans at most `RANGE_PICKER_MAX_VALUES` (300)
|
|
237
|
+
gets `RangeGroup.picker` — the value list, newest first — and
|
|
238
|
+
`<RangeFilterRow>` draws two from/to selects over it. Typing still works and
|
|
239
|
+
carries the bounds: a valid in-range number narrows the list, anything else
|
|
240
|
+
brings the whole list back **with the bounds said in words** ("from 1900 to
|
|
241
|
+
2027"), because a year below the catalogue's floor otherwise does nothing at
|
|
242
|
+
all, silently. A mileage (`1..1000000`) and the core price stay two typed
|
|
243
|
+
fields.
|
|
244
|
+
|
|
245
|
+
## The rail's scrollbar is in the gutter, not on the filters
|
|
246
|
+
|
|
247
|
+
The rail scrolls on its own when it outgrows the window. `scrollbar-width:
|
|
248
|
+
thin` plus `scrollbar-gutter: stable` is the standard half and it is not
|
|
249
|
+
enough: on every overlay-scrollbar platform (a Mac by default, every iOS
|
|
250
|
+
browser) the bar is drawn OVER the content and the gutter reserves nothing. So
|
|
251
|
+
the rail also declares a classic bar through the WebKit pseudo-elements, with a
|
|
252
|
+
real width and every colour a `--stapel-*` custom property, so it is the
|
|
253
|
+
panel's own hairline in both themes. `railScrollbarCss()` and `RAIL_CLASS` are
|
|
254
|
+
exported for a host that lays out its own column.
|
|
255
|
+
|
|
256
|
+
## Two browse surfaces the page places
|
|
257
|
+
|
|
258
|
+
Both are exported from `./default` and neither lays itself out — where they
|
|
259
|
+
belong on a category page is the storefront's decision.
|
|
260
|
+
|
|
261
|
+
`<PopularValues>` prints the busiest values of one group as a multi-column
|
|
262
|
+
`Toyota 802` list that applies the filter on click — a table of contents for a
|
|
263
|
+
category, from the same drill-down counts the panel shows. `hidden` is a prop,
|
|
264
|
+
not a media query: whether a 390px screen has room is a fact about the page.
|
|
265
|
+
|
|
266
|
+
```tsx
|
|
267
|
+
<PopularValues group={firstRefSelect} onApply={toggle} hidden={isPhone}
|
|
268
|
+
onShowAll={openPanel} />
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
`<PartitionChips>` is the single-select row a `chips` category draws instead of
|
|
272
|
+
a tile grid: an "all" cell plus one per child, from `{id, path, name}`,
|
|
273
|
+
controlled (the choice is a `category` in the URL), a real `radiogroup` with
|
|
274
|
+
roving tabindex and arrow keys — because exactly one of them is true at a time,
|
|
275
|
+
and `aria-pressed` toggles say the opposite. `variant="segmented"` is the
|
|
276
|
+
desktop rail's shape (one joined control under its own label); the semantics do
|
|
277
|
+
not vary with it.
|
|
278
|
+
|
|
279
|
+
```tsx
|
|
280
|
+
<PartitionChips items={children} value={state.category ?? null}
|
|
281
|
+
variant={isPhone ? "chips" : "segmented"}
|
|
282
|
+
onChange={(path) => patch({ category: path })} />
|
|
283
|
+
```
|
|
284
|
+
|
|
144
285
|
## What the server admits, the screen repeats
|
|
145
286
|
|
|
146
287
|
| The envelope says | The page says |
|
|
@@ -191,10 +332,10 @@ the configured engine cannot evaluate.
|
|
|
191
332
|
| Layer | Exports |
|
|
192
333
|
|---|---|
|
|
193
334
|
| api | `createSearchApi`, `searchQueryParams`, `SEARCH_SORTS`, wire types |
|
|
194
|
-
| state (pure) | `parseSearchState`, `writeSearchState`, `patchSearchState`, `toggleFilterValue`, `setFilterValues`, `setRangeValue`, `clearFilters`, `activeFilterCount`, `parseDegradations`, `countIsEstimate`, `buildFacetGroups`, `facetOptionLabel` |
|
|
335
|
+
| state (pure) | `parseSearchState`, `writeSearchState`, `patchSearchState`, `toggleFilterValue`, `setFilterValues`, `setRangeValue`, `clearFilters`, `activeFilterCount`, `parseDegradations`, `countIsEstimate`, `buildFacetGroups`, `orderFacetGroupsBySchema`, `facetGroupIsDrawable`, `facetGroupHasEvidence`, `facetOptionLabel`, `translitPrefixMatch`, `translitKey`, `consonantKey` |
|
|
195
336
|
| model | `createSearchRuntime`, `searchQueryKeys`, `useSearchQuery`, `useRankingDisclosure` |
|
|
196
337
|
| headless | `SearchProvider`, `SearchStateProvider`/`useSearchState`, `SearchResults`, `FacetPanel`, `RankingDisclosure` |
|
|
197
|
-
| `./default` | `SearchPage`, `SearchResultsPane`, `FacetPanelPane`, `RankingDisclosurePane`, `SearchBox`, `SortSelect`, `PageSizeSelect`, `LanguageSelect`, `SearchResultCard`, `RangeFilterRow`, `DegradationNotice`, `UrlIssueNotice` (the skin themes itself through `SkinTheme` from `@stapel/tokens-antd/skin`; the pair's own `SearchSkinTheme` is gone as of 0.6.0) |
|
|
338
|
+
| `./default` | `SearchPage`, `SearchResultsPane`, `FacetPanelPane`, `RankingDisclosurePane`, `SearchBox`, `SortSelect`, `PageSizeSelect`, `LanguageSelect`, `SearchResultCard`, `RangeFilterRow`, `DegradationNotice`, `UrlIssueNotice`, `PopularValues`, `PartitionChips`, `facetGroupShape`, `isDictionaryFacet`, `railScrollbarCss`, `RAIL_CLASS`, `FACET_VISIBLE_GROUPS` (the skin themes itself through `SkinTheme` from `@stapel/tokens-antd/skin`; the pair's own `SearchSkinTheme` is gone as of 0.6.0) |
|
|
198
339
|
| `./router` | `useRouterSearchParams` |
|
|
199
340
|
| i18n | `registerSearchI18n` (+ `./i18n/ru`, `./i18n/es`) |
|
|
200
341
|
| errors | `SEARCH_ERRORS`, `explainSearchError`, `SEARCH_WINDOW_EXCEEDED`, `SEARCH_BACKEND_UNAVAILABLE` |
|
package/dist/api/types.d.ts
CHANGED
|
@@ -11,10 +11,44 @@
|
|
|
11
11
|
import type { components } from "./generated/schema.js";
|
|
12
12
|
/** The generated schema table — the one source of truth for wire shapes. */
|
|
13
13
|
export type Schemas = components["schemas"];
|
|
14
|
-
/**
|
|
15
|
-
*
|
|
16
|
-
|
|
14
|
+
/**
|
|
15
|
+
* One slug's captions: the GROUP's own name, and the words for its values.
|
|
16
|
+
*
|
|
17
|
+
* `label` is the group heading the server resolved from the category's
|
|
18
|
+
* feature definition, in the request's own language. It is the only source
|
|
19
|
+
* that always exists — `categoryFeatures` is an optional slot a live
|
|
20
|
+
* classified board never filled, and without it every heading in the panel
|
|
21
|
+
* was the raw index slug. `null` is the server saying it has no name for the
|
|
22
|
+
* slug either; ABSENT is a server too old to send one, and both read the same
|
|
23
|
+
* way here (fall through to the schema).
|
|
24
|
+
*
|
|
25
|
+
* WHAT THE GENERATOR LOST: the field is newer than this pair's pinned
|
|
26
|
+
* `schema.json`, so it is declared here as optional-and-nullable rather than
|
|
27
|
+
* regenerated into a shape a deployed older server does not send.
|
|
28
|
+
*/
|
|
29
|
+
export type FacetLabels = Schemas["FacetLabels"] & {
|
|
30
|
+
readonly label?: string | null;
|
|
31
|
+
/**
|
|
32
|
+
* Whether {@link label} is a translation KEY rather than a caption, the way
|
|
33
|
+
* `translatable` says it for the values.
|
|
34
|
+
*
|
|
35
|
+
* Measured on a live answer (`category=141/151`, 2026-09-04): the server
|
|
36
|
+
* sends it beside every label — a make caption with
|
|
37
|
+
* `label_translatable: false`, a condition caption with `true` — and the
|
|
38
|
+
* describe it. Declared, not consumed: this pair passes the group heading
|
|
39
|
+
* through its translator either way, and a caption that is not a key comes
|
|
40
|
+
* back unchanged (`translate()` keeps a key it cannot resolve). Typed so a
|
|
41
|
+
* fixture captured from the wire is not a type error.
|
|
42
|
+
*/
|
|
43
|
+
readonly label_translatable?: boolean;
|
|
44
|
+
};
|
|
45
|
+
/** `facet_labels` as a whole: `{slug: {label, translatable, values}}`. */
|
|
46
|
+
export type FacetLabelsMap = Readonly<Record<string, FacetLabels>>;
|
|
47
|
+
/** `GET /query` 200 — the whole envelope. Corrected in two places: see
|
|
48
|
+
* {@link FacetMeta} and {@link FacetLabels}. */
|
|
49
|
+
export type SearchResponse = Omit<Schemas["SearchResponse"], "facet_meta" | "facet_labels"> & {
|
|
17
50
|
readonly facet_meta: FacetMeta;
|
|
51
|
+
readonly facet_labels: FacetLabelsMap;
|
|
18
52
|
};
|
|
19
53
|
/** One result row. `promoted` is present on EVERY item under EVERY sort — a
|
|
20
54
|
* mandatory marking (DSA Art. 26), not an optional field, which is why the
|
package/dist/api/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/api/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,4EAA4E;AAC5E,MAAM,MAAM,OAAO,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;AAE5C;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/api/types.ts"],"names":[],"mappings":"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"}
|
package/dist/api/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/api/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/api/types.ts"],"names":[],"mappings":"AAiMA;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,sBAAsB,CAAC;AAElE;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,iBAAiB,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,MAAiC;IAC5D,OAAO,MAAM,EAAE,KAAK,IAAI,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC;AAC9C,CAAC;AAQD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,YAAY,GAAsB;IAC7C,WAAW;IACX,QAAQ;IACR,WAAW;IACX,YAAY;IACZ,UAAU;CACX,CAAC"}
|
|
@@ -9,8 +9,14 @@ import type { FacetGroup, FacetOption } from "../state/facets.js";
|
|
|
9
9
|
* leaves a group of seven whole rather than truncated by one row.
|
|
10
10
|
*/
|
|
11
11
|
export declare const FACET_VISIBLE_OPTIONS = 8;
|
|
12
|
-
/**
|
|
13
|
-
|
|
12
|
+
/**
|
|
13
|
+
* From how many values a group stops being a list and becomes a DICTIONARY —
|
|
14
|
+
* the same eight, because it is the same fold: past it the group is drawn as
|
|
15
|
+
* its busiest values plus a box that searches the rest.
|
|
16
|
+
*/
|
|
17
|
+
export declare const FACET_DICTIONARY_THRESHOLD: number;
|
|
18
|
+
/** The four shapes a facet group takes. */
|
|
19
|
+
export type FacetGroupShape = "segmented" | "nested" | "checkbox" | "dictionary";
|
|
14
20
|
/** The option rows of a group, already nested where the schema nests them. */
|
|
15
21
|
export interface FacetOptionNode {
|
|
16
22
|
readonly option: FacetOption;
|
|
@@ -18,10 +24,44 @@ export interface FacetOptionNode {
|
|
|
18
24
|
readonly depth: number;
|
|
19
25
|
}
|
|
20
26
|
/**
|
|
21
|
-
*
|
|
27
|
+
* Is this group a DICTIONARY — a vocabulary's level, too long to scroll?
|
|
28
|
+
*
|
|
29
|
+
* Two ways to be one, because the schema is an optional slot and the live
|
|
30
|
+
* case is the one where it is empty:
|
|
31
|
+
*
|
|
32
|
+
* - the def types the slug `ref_select`/`ref_hierarchical_select`, i.e. its
|
|
33
|
+
* config is a POINTER into a vocabulary and there was never an option
|
|
34
|
+
* table to draw;
|
|
35
|
+
* - there is NO def at all and the answer came back with more values than a
|
|
36
|
+
* fold. At a live classified's cars branch the storefront passed an empty
|
|
37
|
+
* feature list, so the 418 makes arrived as an unnamed, untyped group of
|
|
38
|
+
* 418 checkboxes behind "Show all (418)". A box is the only control that
|
|
39
|
+
* answers that, and refusing to draw one because the schema is missing
|
|
40
|
+
* punishes the buyer for the wiring.
|
|
41
|
+
*
|
|
42
|
+
* Either way it takes more than {@link FACET_DICTIONARY_THRESHOLD} EVIDENCE
|
|
43
|
+
* buckets — values the answer actually counted. A zero-filled option table or
|
|
44
|
+
* a schema-only tail is a list a person can already read, and a box over it
|
|
45
|
+
* would search for values no document carries.
|
|
46
|
+
*/
|
|
47
|
+
export declare function isDictionaryFacet(group: FacetGroup): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Which of the four shapes a group takes.
|
|
50
|
+
*
|
|
51
|
+
* Order matters, and it changed in one place after a live measurement:
|
|
22
52
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
53
|
+
* - a hierarchical facet is nested even when it is single-choice, because
|
|
54
|
+
* losing the tree costs more than losing the pills;
|
|
55
|
+
* - a DICTIONARY outranks the pills. The make axis on the live cars leaf
|
|
56
|
+
* `maxSelected: 1` over a 418-value vocabulary, so "pick one" won and the
|
|
57
|
+
* control it produced was four hundred pills in a 280px rail — a wall
|
|
58
|
+
* with a different border radius. Above the fold the shape a person needs
|
|
59
|
+
* is a search box, whether or not they may tick two; below it,
|
|
60
|
+
* single-choice still means pills, because `isDictionaryFacet` requires
|
|
61
|
+
* more than {@link FACET_DICTIONARY_THRESHOLD} counted buckets;
|
|
62
|
+
* - and a dictionary is a dictionary before it is a checkbox list, because
|
|
63
|
+
* the checkbox list is the shape it was drawn as when nobody could pick a
|
|
64
|
+
* make.
|
|
25
65
|
*/
|
|
26
66
|
export declare function facetGroupShape(group: FacetGroup): FacetGroupShape;
|
|
27
67
|
/** The group's options in render order, carrying the depth the schema gives. */
|
|
@@ -45,6 +85,14 @@ export interface FacetGroupControlProps {
|
|
|
45
85
|
/** Whether a `collapsible` group STARTS open. Default `true`. The initial
|
|
46
86
|
* value only — the person owns the state after the first click. */
|
|
47
87
|
readonly defaultOpen?: boolean;
|
|
88
|
+
/**
|
|
89
|
+
* How a `"dictionary"` group is drawn. `"field"` is the desktop shape — a
|
|
90
|
+
* select-style field reading its chosen values or "Any", which opens the
|
|
91
|
+
* searchable list; `"inline"` (the default) keeps the list open, the shape
|
|
92
|
+
* a phone sheet wants because the sheet is already the disclosure.
|
|
93
|
+
* Meaningless for the other three shapes.
|
|
94
|
+
*/
|
|
95
|
+
readonly dictionaryMode?: "field" | "inline";
|
|
48
96
|
}
|
|
49
97
|
export declare function FacetGroupControl(props: FacetGroupControlProps): ReactElement;
|
|
50
98
|
//# sourceMappingURL=FacetGroupControl.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FacetGroupControl.d.ts","sourceRoot":"","sources":["../../src/default/FacetGroupControl.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"FacetGroupControl.d.ts","sourceRoot":"","sources":["../../src/default/FacetGroupControl.tsx"],"names":[],"mappings":"AAiEA,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,OAAO,CAAC;AAUzD,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAIlE;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,EAAE,MAA8B,CAAC;AAExE,2CAA2C;AAC3C,MAAM,MAAM,eAAe,GACvB,WAAW,GACX,QAAQ,GACR,UAAU,GACV,YAAY,CAAC;AAEjB,8EAA8E;AAC9E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAwCD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAS5D;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,eAAe,CAOlE;AAWD,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,eAAe,EAAE,CAkC9E;AA2XD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACzD;2EACuE;IACvE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B;gFAC4E;IAC5E,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B;uEACmE;IACnE,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B;;;;;;OAMG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC9C;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,YAAY,CA2I7E"}
|