@stapel/search-react 0.3.1 → 0.7.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 +180 -0
- package/MODULE.md +43 -4
- package/README.md +1 -1
- package/dist/api/generated/schema.d.ts +5 -1
- package/dist/api/generated/schema.d.ts.map +1 -1
- package/dist/default/DegradationNotice.d.ts +34 -0
- package/dist/default/DegradationNotice.d.ts.map +1 -1
- package/dist/default/DegradationNotice.js +28 -6
- package/dist/default/DegradationNotice.js.map +1 -1
- package/dist/default/FacetPanelPane.d.ts +54 -3
- package/dist/default/FacetPanelPane.d.ts.map +1 -1
- package/dist/default/FacetPanelPane.js +119 -19
- package/dist/default/FacetPanelPane.js.map +1 -1
- package/dist/default/LanguageSelect.d.ts +9 -0
- package/dist/default/LanguageSelect.d.ts.map +1 -0
- package/dist/default/LanguageSelect.js +72 -0
- package/dist/default/LanguageSelect.js.map +1 -0
- package/dist/default/PageSizeSelect.d.ts +29 -0
- package/dist/default/PageSizeSelect.d.ts.map +1 -0
- package/dist/default/PageSizeSelect.js +25 -0
- package/dist/default/PageSizeSelect.js.map +1 -0
- package/dist/default/RangeFilterRow.d.ts +12 -0
- package/dist/default/RangeFilterRow.d.ts.map +1 -0
- package/dist/default/RangeFilterRow.js +75 -0
- package/dist/default/RangeFilterRow.js.map +1 -0
- package/dist/default/RankingDisclosurePane.d.ts +5 -0
- package/dist/default/RankingDisclosurePane.d.ts.map +1 -1
- package/dist/default/RankingDisclosurePane.js +15 -15
- package/dist/default/RankingDisclosurePane.js.map +1 -1
- package/dist/default/SearchBox.d.ts +13 -0
- package/dist/default/SearchBox.d.ts.map +1 -0
- package/dist/default/SearchBox.js +67 -0
- package/dist/default/SearchBox.js.map +1 -0
- package/dist/default/SearchPage.d.ts +58 -16
- package/dist/default/SearchPage.d.ts.map +1 -1
- package/dist/default/SearchPage.js +155 -6
- package/dist/default/SearchPage.js.map +1 -1
- package/dist/default/SearchResultCard.d.ts +19 -18
- package/dist/default/SearchResultCard.d.ts.map +1 -1
- package/dist/default/SearchResultCard.js +178 -5
- package/dist/default/SearchResultCard.js.map +1 -1
- package/dist/default/SearchResultsPane.d.ts +54 -3
- package/dist/default/SearchResultsPane.d.ts.map +1 -1
- package/dist/default/SearchResultsPane.js +45 -25
- package/dist/default/SearchResultsPane.js.map +1 -1
- package/dist/default/SortSelect.d.ts +10 -2
- package/dist/default/SortSelect.d.ts.map +1 -1
- package/dist/default/SortSelect.js +27 -24
- package/dist/default/SortSelect.js.map +1 -1
- package/dist/default/UrlIssueNotice.d.ts.map +1 -1
- package/dist/default/UrlIssueNotice.js +19 -1
- package/dist/default/UrlIssueNotice.js.map +1 -1
- package/dist/default/index.d.ts +33 -16
- package/dist/default/index.d.ts.map +1 -1
- package/dist/default/index.js +26 -12
- package/dist/default/index.js.map +1 -1
- package/dist/default/sortLabels.d.ts +5 -0
- package/dist/default/sortLabels.d.ts.map +1 -0
- package/dist/default/sortLabels.js +32 -0
- package/dist/default/sortLabels.js.map +1 -0
- package/dist/headless/FacetPanel.d.ts +17 -0
- package/dist/headless/FacetPanel.d.ts.map +1 -1
- package/dist/headless/FacetPanel.js +23 -2
- package/dist/headless/FacetPanel.js.map +1 -1
- package/dist/headless/SearchResults.d.ts +20 -3
- package/dist/headless/SearchResults.d.ts.map +1 -1
- package/dist/headless/SearchResults.js +3 -1
- package/dist/headless/SearchResults.js.map +1 -1
- package/dist/headless/useAppliedCount.d.ts +8 -0
- package/dist/headless/useAppliedCount.d.ts.map +1 -0
- package/dist/headless/useAppliedCount.js +30 -0
- package/dist/headless/useAppliedCount.js.map +1 -0
- package/dist/headless/useScorerNames.d.ts +4 -0
- package/dist/headless/useScorerNames.d.ts.map +1 -0
- package/dist/headless/useScorerNames.js +34 -0
- package/dist/headless/useScorerNames.js.map +1 -0
- package/dist/headless/useSearchBox.d.ts +44 -0
- package/dist/headless/useSearchBox.d.ts.map +1 -0
- package/dist/headless/useSearchBox.js +116 -0
- package/dist/headless/useSearchBox.js.map +1 -0
- package/dist/i18n/es.d.ts.map +1 -1
- package/dist/i18n/es.js +32 -4
- package/dist/i18n/es.js.map +1 -1
- package/dist/i18n/keys.d.ts +46 -2
- package/dist/i18n/keys.d.ts.map +1 -1
- package/dist/i18n/keys.js +86 -6
- package/dist/i18n/keys.js.map +1 -1
- package/dist/i18n/ru.d.ts.map +1 -1
- package/dist/i18n/ru.js +38 -4
- package/dist/i18n/ru.js.map +1 -1
- package/dist/index.d.ts +9 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/model/queries.d.ts +26 -2
- package/dist/model/queries.d.ts.map +1 -1
- package/dist/model/queries.js +38 -1
- package/dist/model/queries.js.map +1 -1
- package/dist/state/degradations.d.ts +41 -0
- package/dist/state/degradations.d.ts.map +1 -1
- package/dist/state/degradations.js +41 -0
- package/dist/state/degradations.js.map +1 -1
- package/dist/state/limits.d.ts +44 -0
- package/dist/state/limits.d.ts.map +1 -0
- package/dist/state/limits.js +44 -0
- package/dist/state/limits.js.map +1 -0
- package/dist/state/ranges.d.ts +52 -0
- package/dist/state/ranges.d.ts.map +1 -0
- package/dist/state/ranges.js +108 -0
- package/dist/state/ranges.js.map +1 -0
- package/llms.txt +16 -5
- package/manifest.json +245 -22
- package/nav-manifest.json +1 -1
- package/package.json +15 -10
- package/src/analytics/generated/events.json +1 -1
- package/src/api/generated/schema.ts +5 -1
- package/src/default/DegradationNotice.tsx +84 -14
- package/src/default/FacetPanelPane.tsx +343 -64
- package/src/default/LanguageSelect.tsx +93 -0
- package/src/default/PageSizeSelect.tsx +80 -0
- package/src/default/RangeFilterRow.tsx +148 -0
- package/src/default/RankingDisclosurePane.tsx +67 -35
- package/src/default/SearchBox.tsx +130 -0
- package/src/default/SearchPage.tsx +356 -41
- package/src/default/SearchResultCard.tsx +231 -24
- package/src/default/SearchResultsPane.tsx +147 -76
- package/src/default/SortSelect.tsx +50 -37
- package/src/default/UrlIssueNotice.tsx +21 -3
- package/src/default/index.ts +42 -16
- package/src/default/sortLabels.ts +34 -0
- package/src/headless/FacetPanel.tsx +30 -2
- package/src/headless/SearchResults.tsx +32 -4
- package/src/headless/useAppliedCount.ts +41 -0
- package/src/headless/useScorerNames.ts +36 -0
- package/src/headless/useSearchBox.ts +189 -0
- package/src/i18n/es.ts +39 -4
- package/src/i18n/keys.ts +97 -6
- package/src/i18n/ru.ts +45 -4
- package/src/index.ts +30 -3
- package/src/model/queries.ts +51 -1
- package/src/state/degradations.ts +60 -0
- package/src/state/limits.ts +50 -0
- package/src/state/ranges.ts +144 -0
- package/dist/default/ErrorAlert.d.ts +0 -9
- package/dist/default/ErrorAlert.d.ts.map +0 -1
- package/dist/default/ErrorAlert.js +0 -27
- package/dist/default/ErrorAlert.js.map +0 -1
- package/dist/default/theme.d.ts +0 -24
- package/dist/default/theme.d.ts.map +0 -1
- package/dist/default/theme.js +0 -39
- package/dist/default/theme.js.map +0 -1
- package/src/default/ErrorAlert.tsx +0 -46
- package/src/default/theme.tsx +0 -66
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,185 @@
|
|
|
1
1
|
# @stapel/search-react
|
|
2
2
|
|
|
3
|
+
## 0.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 9545a2f: Search: the five blank stories, the phone filter path, money, and the dark scope
|
|
8
|
+
|
|
9
|
+
**Five stories rendered nothing.** `results-pane--*` and `filter-panel--*` crashed on
|
|
10
|
+
`data.items.filter` / `data.facet_meta.skipped` — 15 blank shots, including the designed
|
|
11
|
+
empty state. The seeded demos wrote the answer into the query cache and `useSearchQuery`
|
|
12
|
+
sets no `staleTime` (drill-down facets must never serve a stale page), so TanStack
|
|
13
|
+
refetched on mount and the demo `fetch`, which had no handler for a variant that seeded
|
|
14
|
+
instead of mocking, replaced the page with `{}`. A seed now mounts as a handler too, and
|
|
15
|
+
an UNMOCKED path answers 503 rather than an empty 200, so a forgotten handler renders the
|
|
16
|
+
pane's "we could not run this search" arm instead of a white screen.
|
|
17
|
+
|
|
18
|
+
**The phone filter sheet had no visual evidence at all** — the only filter path a phone
|
|
19
|
+
has, reachable only by a tap. `<SearchPage defaultFiltersOpen>` opens it on mount (for a
|
|
20
|
+
container that deep-links into the filters), and `search.filter-sheet` photographs it.
|
|
21
|
+
Its commit button now says **"Show 25+ results"** (`useAppliedCount`, cache-only — no
|
|
22
|
+
second request), the sheet no longer prints "Filters" twice (`FacetPanelPane heading`),
|
|
23
|
+
and the opener drops the "(0)" until something is applied.
|
|
24
|
+
|
|
25
|
+
**Money.** `3200 RUB` → `₽3,200`, through core's `useFormat().number` with
|
|
26
|
+
`style: "currency"` — the same `Intl` path `@stapel/currencies-react`'s `formatMoney`
|
|
27
|
+
takes. Non-numeric prices pass through; an unusable code falls back to a grouped number.
|
|
28
|
+
|
|
29
|
+
**Contrast, touch targets, orphans.** The DSA "Promoted" tag was `warning-on` (white)
|
|
30
|
+
over `warning-bg` (cream) — the one legally mandated string in the package, at ~1.2:1;
|
|
31
|
+
it is `warning` now, in both themes. Degradation banner lines drop `type="secondary"`
|
|
32
|
+
(grey on the warning tint failed AA). `size="small"` is gone from the range Apply/Clear,
|
|
33
|
+
the category/geo/clear-all buttons, so the shared skin's 44px phone control height
|
|
34
|
+
applies. The range Apply is primary when there is something to apply, not before. An
|
|
35
|
+
unfilled `renderGeoFilter` no longer leaves a "Location" heading over empty space in a
|
|
36
|
+
production build, and a facet group with no options draws no heading.
|
|
37
|
+
|
|
38
|
+
**Copy.** Scorer slugs are named from the ranking disclosure the pair already fetches
|
|
39
|
+
(`geo_decay` → "Distance"); skipped facet slugs from the category schema (`power_w` →
|
|
40
|
+
"Power"); `applies_to_sorts` through the sort control's own labels; the weight tag is
|
|
41
|
+
labelled; the unreadable-link notice says "price", not `r.price`, and no longer explains
|
|
42
|
+
`from..to` or `lat`/`lon`. New keys `search.filters.show_count{,_at_least}` (plural
|
|
43
|
+
families) and `search.limit.from_link`, in en/ru/es.
|
|
44
|
+
|
|
45
|
+
**Layout.** The desktop filter rail is a fixed 280px instead of `Col md={7}` (measured at
|
|
46
|
+
45% of a 1280px page). Result cards carry the photo well filled (`fit` needs a box when
|
|
47
|
+
the snapshot has no aspect) and the whole row is one link when the doc type stores
|
|
48
|
+
`card.url`. The three superseded headless debug-dump demos are gone; their components are
|
|
49
|
+
covered by the skin demos that supersede them.
|
|
50
|
+
|
|
51
|
+
## 0.6.0
|
|
52
|
+
|
|
53
|
+
### Minor Changes
|
|
54
|
+
|
|
55
|
+
- 80617e9: The search page can start a search.
|
|
56
|
+
|
|
57
|
+
`setText` had zero callers in the entire repository: the codec carried `q`, the state
|
|
58
|
+
machine could set it, the request sent it, and no screen could type one. Six of the nine
|
|
59
|
+
state setters had no control at all. This release is the missing half of the pair.
|
|
60
|
+
|
|
61
|
+
- **`<SearchBox>`** — the query box, debounced (350ms, `replace: true`, so ten letters are
|
|
62
|
+
one history entry), capped at the server's own `MAX_QUERY_CHARS`, with a typeahead over
|
|
63
|
+
`GET /suggest` — an endpoint that had been typed and unreachable since 0.1. `useSearchBox`
|
|
64
|
+
is the headless half; `useSuggest` the hook. Exported, so a container's header can mount
|
|
65
|
+
the same box the page does (`searchBox={false}` then keeps exactly one on screen).
|
|
66
|
+
- **Range filters** — `r.<slug>=from..to` finally has a control. `state/ranges.ts` decides
|
|
67
|
+
which rows exist (numeric features of the category schema, plus any slug the URL already
|
|
68
|
+
constrains); `<RangeFilterRow>` commits on Apply and refuses a backwards range with the
|
|
69
|
+
reason beside the button instead of returning an empty page.
|
|
70
|
+
- **Category, location, language and page size** — `renderCategoryFilter` and
|
|
71
|
+
`renderGeoFilter` are named slots the categories/geo pairs fill, with `SlotPlaceholder`
|
|
72
|
+
where they are not; either way a constraint that arrived in a shared link now has a control
|
|
73
|
+
that widens it again (clear the category, adjust or clear the radius). `<LanguageSelect>`
|
|
74
|
+
and `<PageSizeSelect>` bind `setLanguage` and `setLimit`.
|
|
75
|
+
- **No reason lives in a hover any more.** The pager, the distance sort and the DSA Art. 26
|
|
76
|
+
`promoted` explanation were all `title=`/`<Tooltip>` — invisible on every phone and on
|
|
77
|
+
every disabled button. They are visible text now (`GatedButton`/`GatedControl`, and plain
|
|
78
|
+
copy under the marking). The pager is absent, not dead, when there is nothing to page.
|
|
79
|
+
- **The generic card draws `image_url`** through `@stapel/image` (new optional peer), in an
|
|
80
|
+
aspect box, with the promoted tag on a `--stapel-*` role instead of antd's `gold` preset.
|
|
81
|
+
- **On a phone the filters are a bottom sheet** behind a "Filters (N)" button, through the
|
|
82
|
+
shared `SkinDialog`, instead of a full-width panel stacked above the first result.
|
|
83
|
+
- **The pair's `theme.tsx` and `ErrorAlert.tsx` are deleted** in favour of
|
|
84
|
+
`@stapel/tokens-antd/skin`'s `SkinTheme` / `ErrorAlert` / `EmptyState` / `LoadList`.
|
|
85
|
+
`SearchSkinTheme` is no longer exported (pre-1.0 breaking = minor): import `SkinTheme`
|
|
86
|
+
from the substrate — same props, and a runtime `data-theme` flip repaints it.
|
|
87
|
+
|
|
88
|
+
Peers: `@stapel/core >=0.18.0`, `@stapel/tokens-antd >=0.6.0`, `@stapel/image >=0.3.0`
|
|
89
|
+
(optional — only the `/default` skin needs it). The `/default` size budget moves 13 KB → 16 KB.
|
|
90
|
+
|
|
91
|
+
### Patch Changes
|
|
92
|
+
|
|
93
|
+
- 308e3d6: Every `/default` surface is drawn, seeded and photographed.
|
|
94
|
+
|
|
95
|
+
The skin shipped in the last release with one demo out of twelve names: the pair could
|
|
96
|
+
be read in source and not LOOKED at, which is the state §54's gate exists to end. All
|
|
97
|
+
twelve are covered now, and covered in the state each one is named for.
|
|
98
|
+
|
|
99
|
+
- **Eleven new skin demos** — the results pane (found / phone / a search that ran and
|
|
100
|
+
matched nothing), the filter panel (open, and narrowed by a shared link so every
|
|
101
|
+
constraint's door-out is visible), the ranking disclosure, the result card (promoted
|
|
102
|
+
with a photo, and plain), the query box, the sort gate (blocked and open), the page-size
|
|
103
|
+
ladder, the language filter, the numeric range row, the degradation notice (banner and
|
|
104
|
+
inline) and the unreadable-link notice. Each imports from `src/default`, each has a
|
|
105
|
+
`viewport: "phone"` variant, each variant declares the `step` it is seeded at.
|
|
106
|
+
- **Demos are SEEDED, not fetched** (`DemoSeed` in the demo harness): the answer is written
|
|
107
|
+
into the query cache under the key the pair's own codec derives, so a variant opens in its
|
|
108
|
+
state on the first frame instead of photographing the same skeleton under three names.
|
|
109
|
+
`assertVariantsRenderDistinctly` is wired into the demo suite and enforces it.
|
|
110
|
+
- **Dedicated suites** for `useSearchBox` (debounce, one history entry per word, the URL
|
|
111
|
+
winning whenever it moves on its own, the `MAX_QUERY_CHARS` cap), `useSuggest` (the
|
|
112
|
+
three-character floor, the clamped limit, a refusal that leaves the box typeable, a menu
|
|
113
|
+
that stays shut on an empty answer) and the range model (which slugs get a row, what the
|
|
114
|
+
row refuses, and that the reason stands beside the button).
|
|
115
|
+
- **A render matrix per surface** — each of the four surfaces in phone and desktop, light
|
|
116
|
+
and dark, asserting the mode is the DOCUMENT's rather than a default baked into the skin,
|
|
117
|
+
plus the filter surface following the viewport. `setViewport` / `setDocumentTheme` are the
|
|
118
|
+
test harness helpers the setup file has been pointing at.
|
|
119
|
+
|
|
120
|
+
No public API change: `src/` is untouched. The demo registry, manifest and `llms.txt` are
|
|
121
|
+
regenerated.
|
|
122
|
+
|
|
123
|
+
## 0.5.0
|
|
124
|
+
|
|
125
|
+
### Minor Changes
|
|
126
|
+
|
|
127
|
+
- d778c54: `<SearchPage>` stops laying out a column for filters that do not exist, and
|
|
128
|
+
stops printing a second heading over the list.
|
|
129
|
+
|
|
130
|
+
- The filter column was unconditional. On a deployment whose search plan
|
|
131
|
+
declares no facets that spent a quarter of `/s`, of every category page and
|
|
132
|
+
of every seller page on an illustration saying "no filters for this search" —
|
|
133
|
+
three screens with a hole in them. The page now asks the facet bag what it
|
|
134
|
+
has and gives the results the whole width when the answer is a LOADED zero.
|
|
135
|
+
`loading` and `failed` keep the column: a panel that has not answered yet is
|
|
136
|
+
not a panel with nothing in it, and a layout that reflowed mid-load would be
|
|
137
|
+
worse than the hole. An active filter keeps it too.
|
|
138
|
+
- `resultsHeading` / `<SearchResultsPane heading>`: what this surface calls its
|
|
139
|
+
list. "Results" is only right when the person performed a search — a
|
|
140
|
+
landing's newest-first strip, a seller's page and a category page each wrote
|
|
141
|
+
their own caption above the pane and got "Results" underneath it a moment
|
|
142
|
+
later. The name now goes INTO the heading row that already exists.
|
|
143
|
+
- `filtersHeader`: a slot at the top of the filter column, for a filter this
|
|
144
|
+
pair cannot ship. `SearchQueryState` has carried `geo` since 0.2 and
|
|
145
|
+
`<SortSelect>` already disables "by distance" with the reason "no centre
|
|
146
|
+
set", but nothing here could ever SET one — turning an address into a
|
|
147
|
+
coordinate needs a geocoder, and a geocoder is the deployment's. Whatever a
|
|
148
|
+
host renders here reads and writes the same URL state as the facets beside
|
|
149
|
+
it.
|
|
150
|
+
- `useFacetPanel()` is exported: the same bag as `<FacetPanel>`, for a caller
|
|
151
|
+
that must know what the panel will render before it renders it. A render prop
|
|
152
|
+
cannot answer a question asked one level up.
|
|
153
|
+
|
|
154
|
+
## 0.4.0
|
|
155
|
+
|
|
156
|
+
### Minor Changes
|
|
157
|
+
|
|
158
|
+
- 2d93b52: The count stops lying, and the banner stops crying wolf.
|
|
159
|
+
|
|
160
|
+
The pair now reads stapel-search 0.2.0's count contract (pin `v0.2.0`): `count`
|
|
161
|
+
is nullable, `count_is_lower_bound` marks a floor, and `exact_total` describes
|
|
162
|
+
the answer rather than the engine. `page.countKind` turns the three wire fields
|
|
163
|
+
into one decision — `"exact"` renders «25 объявлений», `"at_least"` renders
|
|
164
|
+
«1200+ объявлений» through `tPlural` (a new `search.results.count_at_least`
|
|
165
|
+
family in en/ru/es), and `"unknown"` renders **no count line at all**. The
|
|
166
|
+
state this replaces printed «Примерно 0 объявлений» over four visible cards on
|
|
167
|
+
the live storefront: 0.1.0 had no way to say "we do not know" except `0`.
|
|
168
|
+
|
|
169
|
+
`<DegradationNotice>` no longer raises a warning banner for a `degraded[]` that
|
|
170
|
+
contains ONLY `exact_total`. It is a count nuance, not a failed search — the
|
|
171
|
+
rows are right and the consequence is already spoken by the count as "N+" —
|
|
172
|
+
and a banner that cries wolf on every landing page is one nobody reads on the
|
|
173
|
+
day `category_rollup` shows up in it. Beside any other degradation it renders
|
|
174
|
+
as before. Volume is now the container's call: `<SearchResultsPane>` and
|
|
175
|
+
`<SearchPage>` take `degradationNotice?: "banner" | "inline" | "off"`
|
|
176
|
+
(default `"banner"`), so a landing page can pass `"inline"` or `"off"`.
|
|
177
|
+
|
|
178
|
+
New exports: `countKind`, `isCountNuanceOnly`, `SearchCountKind`,
|
|
179
|
+
`DegradationNoticeVariant`. `SearchPageInfo.count` is now `number | null` and
|
|
180
|
+
gains `countIsLowerBound` / `countKind`; `countIsEstimate` (both the helper and
|
|
181
|
+
the bag field) is deprecated — it cannot see `count: null`.
|
|
182
|
+
|
|
3
183
|
## 0.3.1
|
|
4
184
|
|
|
5
185
|
### Patch Changes
|
package/MODULE.md
CHANGED
|
@@ -132,7 +132,7 @@ Four independent signals, all surfaced:
|
|
|
132
132
|
|
|
133
133
|
| Signal | Where it comes from | What must not happen |
|
|
134
134
|
|---|---|---|
|
|
135
|
-
| `exact_total` | envelope | rendering an
|
|
135
|
+
| `count` / `count_is_lower_bound` / `exact_total` | envelope | rendering a floor, or an unknown, as a total |
|
|
136
136
|
| `facet_meta.approximate` | candidate set over `FACET_CANDIDATE_CAP` | a precise-looking number |
|
|
137
137
|
| `facet_meta.skipped` | plan slugs dropped at `MAX_FACET_FIELDS` | a `0` where nothing was counted |
|
|
138
138
|
| `degraded[]` | `_degradations` + backend + facet counter | silence |
|
|
@@ -142,6 +142,44 @@ contributions without de-duplicating them (`services.py`) and the same literal
|
|
|
142
142
|
can arrive twice. An unrecognised literal is kept with `kind: "unknown"` and
|
|
143
143
|
shown with its raw text — a build that predates a new limitation should say so.
|
|
144
144
|
|
|
145
|
+
### The count has three states, and one of them prints nothing
|
|
146
|
+
|
|
147
|
+
stapel-search 0.2.0 replaced "a number, possibly approximate" with three
|
|
148
|
+
distinct answers, because the two-state version had to spell "we do not know"
|
|
149
|
+
as `0` — and the live storefront printed «Примерно 0 объявлений» over four
|
|
150
|
+
visible cards.
|
|
151
|
+
|
|
152
|
+
| envelope | `page.countKind` | rendered |
|
|
153
|
+
|---|---|---|
|
|
154
|
+
| `count: 25`, `count_is_lower_bound: false` | `"exact"` | «25 объявлений» |
|
|
155
|
+
| `count: 1200`, `count_is_lower_bound: true` | `"at_least"` | «1200+ объявлений» |
|
|
156
|
+
| `count: null` | `"unknown"` | nothing at all |
|
|
157
|
+
|
|
158
|
+
`countKind()` is the whole decision in one call, and it is deliberately
|
|
159
|
+
conservative: a bare `exact_total: false` (a server that predates
|
|
160
|
+
`count_is_lower_bound`) reads as a floor, never as a total, because "at least
|
|
161
|
+
N" is the one claim the visible page cannot contradict. `page.countIsEstimate`
|
|
162
|
+
survives as a deprecated alias; it cannot see `count: null`.
|
|
163
|
+
|
|
164
|
+
### An `exact_total`-only degradation raises no banner
|
|
165
|
+
|
|
166
|
+
The rule, and the reasoning, live in `isCountNuanceOnly()` and
|
|
167
|
+
`<DegradationNotice>`: `exact_total` is a count NUANCE, not a failed search.
|
|
168
|
+
The rows are the right rows, and its single consequence — the total is a floor
|
|
169
|
+
— is already spoken by the count as "N+". A warning box over an otherwise
|
|
170
|
+
perfect page teaches the reader that the page is broken, and a banner that
|
|
171
|
+
cries wolf on every landing page is a banner nobody reads on the day
|
|
172
|
+
`category_rollup` appears in it. Beside ANY other degradation it renders
|
|
173
|
+
normally, because the list is then describing an answer that really is
|
|
174
|
+
degraded.
|
|
175
|
+
|
|
176
|
+
Volume is the container's choice, not the library's: `<SearchResultsPane>` (and
|
|
177
|
+
`<SearchPage>`) take `degradationNotice?: "banner" | "inline" | "off"`,
|
|
178
|
+
defaulting to `"banner"`. A catalogue keeps the box; a landing page with six
|
|
179
|
+
cards under a hero passes `"inline"` (the same sentences, quiet secondary text)
|
|
180
|
+
or `"off"`. Nothing about `"off"` silences a degradation for other surfaces —
|
|
181
|
+
it is one surface saying "not here".
|
|
182
|
+
|
|
145
183
|
## Where the refusals go
|
|
146
184
|
|
|
147
185
|
`error.400.search_window_exceeded` gets its own branch in the results pane.
|
|
@@ -189,12 +227,13 @@ nothing here".
|
|
|
189
227
|
their declared order, a skipped slug says "not counted", labels resolve
|
|
190
228
|
through the category schema.
|
|
191
229
|
- `results.test.tsx` — the four load outcomes, the window refusal as its own
|
|
192
|
-
sentence, the
|
|
193
|
-
five sorts.
|
|
230
|
+
sentence, the three count states (`N`, `N+`, and no line at all), and
|
|
231
|
+
`promoted` under every one of the five sorts.
|
|
194
232
|
- `pagination.test.tsx` — cursor forward and back with `direction`, both
|
|
195
233
|
controls blocked WITH a reason, and the panel not blanking between clicks.
|
|
196
234
|
- `degraded.test.tsx` — every literal parsed, duplicates collapsed, unknown
|
|
197
|
-
kept
|
|
235
|
+
kept, an `exact_total`-only degradation raising no banner (and raising one
|
|
236
|
+
again beside a real degradation), and the `off`/`inline` variants.
|
|
198
237
|
- `contract.test.ts` — every operation lands on a path the backend declares,
|
|
199
238
|
every query parameter is one it declares, and `f.<slug>` is repeated rather
|
|
200
239
|
than comma-joined.
|
package/README.md
CHANGED
|
@@ -152,7 +152,7 @@ the configured engine cannot evaluate.
|
|
|
152
152
|
| state (pure) | `parseSearchState`, `writeSearchState`, `patchSearchState`, `toggleFilterValue`, `setFilterValues`, `setRangeValue`, `clearFilters`, `activeFilterCount`, `parseDegradations`, `countIsEstimate`, `buildFacetGroups`, `facetOptionLabel` |
|
|
153
153
|
| model | `createSearchRuntime`, `searchQueryKeys`, `useSearchQuery`, `useRankingDisclosure` |
|
|
154
154
|
| headless | `SearchProvider`, `SearchStateProvider`/`useSearchState`, `SearchResults`, `FacetPanel`, `RankingDisclosure` |
|
|
155
|
-
| `./default` | `SearchPage`, `SearchResultsPane`, `FacetPanelPane`, `RankingDisclosurePane`, `SearchResultCard`, `DegradationNotice`, `UrlIssueNotice
|
|
155
|
+
| `./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) |
|
|
156
156
|
| `./router` | `useRouterSearchParams` |
|
|
157
157
|
| i18n | `registerSearchI18n` (+ `./i18n/ru`, `./i18n/es`) |
|
|
158
158
|
| errors | `SEARCH_ERRORS`, `explainSearchError`, `SEARCH_WINDOW_EXCEEDED`, `SEARCH_BACKEND_UNAVAILABLE` |
|
|
@@ -210,7 +210,11 @@ export interface components {
|
|
|
210
210
|
prev_anchor: string | null;
|
|
211
211
|
has_next: boolean;
|
|
212
212
|
has_prev: boolean;
|
|
213
|
-
count
|
|
213
|
+
/** @description How many documents match. NEVER 0 beside a non-empty items[] — the answer may not claim fewer matches than the page shows. `null` means the engine cannot say, and is rendered as no count at all. */
|
|
214
|
+
count: number | null;
|
|
215
|
+
/** @description True when `count` is a floor: at least this many match, possibly more (a capped count, a window-truncated engine answer). Render 'N+', never 'N'. */
|
|
216
|
+
count_is_lower_bound: boolean;
|
|
217
|
+
/** @description True when `count` is exact for THIS answer — equivalent to `count is not null and not count_is_lower_bound`. Per answer, not per engine: an engine without a guaranteed exact total still counts a small candidate set exactly. */
|
|
214
218
|
exact_total: boolean;
|
|
215
219
|
/** @description What the configured engine could not do for this query. */
|
|
216
220
|
degraded: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/api/generated/schema.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/api/generated/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,11 +9,45 @@
|
|
|
9
9
|
* An `unknown` degradation still renders — with the raw literal, because a
|
|
10
10
|
* build that predates a new limitation should say "the engine reported
|
|
11
11
|
* something we have no wording for: X", not nothing at all.
|
|
12
|
+
*
|
|
13
|
+
* ── Two deliberate ways NOT to shout ───────────────────────────────────────
|
|
14
|
+
*
|
|
15
|
+
* 1. **`exact_total` alone never raises a banner.** It is a count NUANCE, not
|
|
16
|
+
* a failed search: the rows are right, and the single consequence — that
|
|
17
|
+
* the total is a floor — is already spoken by the count as "N+". A warning
|
|
18
|
+
* box over a perfectly good result page teaches the reader that the page
|
|
19
|
+
* is broken, and a banner that cries wolf on every landing page is a
|
|
20
|
+
* banner nobody reads on the day `category_rollup` appears in it. Beside
|
|
21
|
+
* any other degradation it renders normally, because the list is then
|
|
22
|
+
* describing an answer that really is degraded. See
|
|
23
|
+
* {@link isCountNuanceOnly}.
|
|
24
|
+
* 2. **`variant`.** A catalogue page wants the banner; a landing page that
|
|
25
|
+
* shows six cards under a hero has no room for a warning box and passes
|
|
26
|
+
* `"inline"` (one quiet line) or `"off"`. `"off"` is a decision the
|
|
27
|
+
* CONTAINER makes about ITS surface — the notice stays the default, and
|
|
28
|
+
* nothing here silences a degradation for everyone.
|
|
12
29
|
*/
|
|
13
30
|
import type { ReactElement } from "react";
|
|
14
31
|
import type { SearchDegradation } from "../api/types.js";
|
|
32
|
+
/**
|
|
33
|
+
* How loudly a surface says what the engine could not do.
|
|
34
|
+
*
|
|
35
|
+
* - `"banner"` (default) — an antd warning `Alert` with one line per item.
|
|
36
|
+
* - `"inline"` — the same sentences as quiet secondary text, no box.
|
|
37
|
+
* - `"off"` — nothing. For a surface where the notice does not belong at all;
|
|
38
|
+
* the container that turns it off owns saying so somewhere else.
|
|
39
|
+
*/
|
|
40
|
+
export type DegradationNoticeVariant = "banner" | "inline" | "off";
|
|
15
41
|
export interface DegradationNoticeProps {
|
|
16
42
|
readonly degradations: readonly SearchDegradation[];
|
|
43
|
+
readonly variant?: DegradationNoticeVariant;
|
|
44
|
+
/**
|
|
45
|
+
* Names a `scorer:` degradation's slug, when something on the page knows
|
|
46
|
+
* one. `<SearchResultsPane>` passes the ranking disclosure's own names
|
|
47
|
+
* (`useScorerNames`); with no answer the slug is printed, which is what a
|
|
48
|
+
* registry identifier is worth on its own.
|
|
49
|
+
*/
|
|
50
|
+
readonly scorerName?: (slug: string) => string | undefined;
|
|
17
51
|
}
|
|
18
52
|
export declare function DegradationNotice(props: DegradationNoticeProps): ReactElement | null;
|
|
19
53
|
//# sourceMappingURL=DegradationNotice.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DegradationNotice.d.ts","sourceRoot":"","sources":["../../src/default/DegradationNotice.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"DegradationNotice.d.ts","sourceRoot":"","sources":["../../src/default/DegradationNotice.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAI1C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAIzD;;;;;;;GAOG;AACH,MAAM,MAAM,wBAAwB,GAAG,QAAQ,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEnE,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,YAAY,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACpD,QAAQ,CAAC,OAAO,CAAC,EAAE,wBAAwB,CAAC;IAC5C;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;CAC5D;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,sBAAsB,GAC5B,YAAY,GAAG,IAAI,CA0DrB"}
|
|
@@ -1,14 +1,36 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { Alert, Typography } from "antd";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Alert, Flex, Typography } from "antd";
|
|
3
|
+
import { fontSize, spacing } from "@stapel/tokens";
|
|
3
4
|
import { useT } from "@stapel/core";
|
|
5
|
+
import { isCountNuanceOnly } from "../state/degradations.js";
|
|
4
6
|
import { SEARCH_I18N_KEYS } from "../i18n/keys.js";
|
|
5
7
|
export function DegradationNotice(props) {
|
|
6
8
|
const t = useT();
|
|
9
|
+
const variant = props.variant ?? "banner";
|
|
10
|
+
if (variant === "off")
|
|
11
|
+
return null;
|
|
7
12
|
if (props.degradations.length === 0)
|
|
8
13
|
return null;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
// A count nuance is not a degraded search — the count already says "N+".
|
|
15
|
+
if (isCountNuanceOnly(props.degradations))
|
|
16
|
+
return null;
|
|
17
|
+
const say = (degradation) => {
|
|
18
|
+
const slug = degradation.scorer;
|
|
19
|
+
return t(degradation.messageKey, {
|
|
20
|
+
scorer: slug === undefined
|
|
21
|
+
? ""
|
|
22
|
+
: (props.scorerName?.(slug) ?? slug),
|
|
23
|
+
raw: degradation.raw,
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
// NOT `type="secondary"` in the banner: antd paints a warning Alert in the
|
|
27
|
+
// theme's warning tint, and grey body text on it measured under 3:1 in the
|
|
28
|
+
// visual pass. Inside a coloured box the readable colour is the box's own
|
|
29
|
+
// text colour, which is what a plain `<Typography.Text>` inherits.
|
|
30
|
+
const lines = props.degradations.map((degradation) => (_jsx("li", { "data-degradation": degradation.raw, children: _jsx(Typography.Text, { children: say(degradation) }) }, degradation.raw)));
|
|
31
|
+
if (variant === "inline") {
|
|
32
|
+
return (_jsxs(Flex, { vertical: true, gap: spacing[1], "data-testid": "search-degraded", "data-variant": "inline", children: [_jsx(Typography.Text, { type: "secondary", style: { fontSize: fontSize.xs.fontSize }, children: t(SEARCH_I18N_KEYS.degradedTitle) }), _jsx("ul", { style: { margin: 0, paddingInlineStart: spacing[5], fontSize: fontSize.xs.fontSize }, children: props.degradations.map((degradation) => (_jsx("li", { "data-degradation": degradation.raw, children: _jsx(Typography.Text, { type: "secondary", children: say(degradation) }) }, degradation.raw))) })] }));
|
|
33
|
+
}
|
|
34
|
+
return (_jsx(Alert, { type: "warning", showIcon: true, "data-testid": "search-degraded", "data-variant": "banner", title: t(SEARCH_I18N_KEYS.degradedTitle), description: _jsx("ul", { style: { margin: 0, paddingInlineStart: spacing[5] }, children: lines }) }));
|
|
13
35
|
}
|
|
14
36
|
//# sourceMappingURL=DegradationNotice.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DegradationNotice.js","sourceRoot":"","sources":["../../src/default/DegradationNotice.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"DegradationNotice.js","sourceRoot":"","sources":["../../src/default/DegradationNotice.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `<FacetPanelPane>` — the antd
|
|
2
|
+
* `<FacetPanelPane>` — the antd FILTER panel: everything that narrows a
|
|
3
|
+
* search, in the order a person narrows it.
|
|
4
|
+
*
|
|
5
|
+
* Category → language → location → numeric ranges → facet checkboxes. The last
|
|
6
|
+
* of those was, for three releases, the only one that existed: six of the nine
|
|
7
|
+
* state setters had no control at all, so a price range or a location could
|
|
8
|
+
* only be applied by editing the address bar (audit S-2, S-7).
|
|
3
9
|
*
|
|
4
10
|
* Three things it is obliged to render, all of which a naive panel drops:
|
|
5
11
|
*
|
|
@@ -12,15 +18,60 @@
|
|
|
12
18
|
* - `skipped` — the slugs the server did not count at all. Their options show
|
|
13
19
|
* "not counted", never `0`. A silent zero there is the same defect class as
|
|
14
20
|
* `data ?? []`: a number that looks like an answer and is not one.
|
|
21
|
+
*
|
|
22
|
+
* ── Two slots, and why they are slots ─────────────────────────────────────
|
|
23
|
+
*
|
|
24
|
+
* `renderCategoryFilter` and `renderGeoFilter` are filled by OTHER pairs:
|
|
25
|
+
* choosing a category means walking the catalogue tree (`categories-react`),
|
|
26
|
+
* and turning an address into a coordinate needs a geocoder and a map
|
|
27
|
+
* (`geo-react`). Neither belongs in a search package, and importing either
|
|
28
|
+
* would tie a storefront's search to a catalogue it might not have.
|
|
29
|
+
*
|
|
30
|
+
* What this panel does NOT do is pretend the slot is optional. An unfilled
|
|
31
|
+
* slot renders `SlotPlaceholder` in development — a named, visible hole rather
|
|
32
|
+
* than a silent absence — and, in every build, any constraint the URL already
|
|
33
|
+
* carries gets a control that REMOVES it. A shared link that narrows to a
|
|
34
|
+
* category or a point must never leave a person with no way to widen it again.
|
|
15
35
|
*/
|
|
16
|
-
import type { ReactElement } from "react";
|
|
36
|
+
import type { ReactElement, ReactNode } from "react";
|
|
17
37
|
import type { FeatureDef } from "@stapel/attributes-react";
|
|
38
|
+
import type { SearchGeo } from "../api/types.js";
|
|
18
39
|
import type { ThemeModeProp } from "./types.js";
|
|
40
|
+
/** What a host's category control is handed. */
|
|
41
|
+
export interface CategoryFilterSlotProps {
|
|
42
|
+
/** The `root/leaf` path the search is narrowed to, if any. */
|
|
43
|
+
readonly value: string | undefined;
|
|
44
|
+
/** `null` widens the search back to the whole catalogue. */
|
|
45
|
+
readonly onChange: (path: string | null) => void;
|
|
46
|
+
}
|
|
47
|
+
/** What a host's location control is handed. */
|
|
48
|
+
export interface GeoFilterSlotProps {
|
|
49
|
+
readonly value: SearchGeo | undefined;
|
|
50
|
+
/** `null` clears the location constraint. */
|
|
51
|
+
readonly onChange: (geo: SearchGeo | null) => void;
|
|
52
|
+
}
|
|
19
53
|
export interface FacetPanelPaneProps extends ThemeModeProp {
|
|
20
|
-
/** The category's feature schema — the source of option LABELS
|
|
54
|
+
/** The category's feature schema — the source of option LABELS and of which
|
|
55
|
+
* slugs get a numeric range row. */
|
|
21
56
|
readonly categoryFeatures?: readonly FeatureDef[];
|
|
22
57
|
readonly locale?: string;
|
|
23
58
|
readonly enabled?: boolean;
|
|
59
|
+
/** The catalogue picker (`categories-react`'s `CategoryPickerField`, bound
|
|
60
|
+
* to a path). Unfilled, an active category still gets a "clear" control. */
|
|
61
|
+
readonly renderCategoryFilter?: (slot: CategoryFilterSlotProps) => ReactNode;
|
|
62
|
+
/** The location control (`geo-react`). Unfilled, a location that arrived in
|
|
63
|
+
* the URL still gets its radius and a "clear" control. */
|
|
64
|
+
readonly renderGeoFilter?: (slot: GeoFilterSlotProps) => ReactNode;
|
|
65
|
+
/** BCP-47 tags this deployment indexes — see {@link LanguageSelect}. */
|
|
66
|
+
readonly languages?: readonly string[];
|
|
67
|
+
/**
|
|
68
|
+
* What the panel calls itself. `null` draws no title at all — for a surface
|
|
69
|
+
* that has ALREADY named it, which the phone sheet has: its dialog title and
|
|
70
|
+
* the panel's own heading both said "Filters", one under the other, in every
|
|
71
|
+
* shot of the open sheet. The row itself stays either way, because the
|
|
72
|
+
* "Clear all" control lives in it.
|
|
73
|
+
*/
|
|
74
|
+
readonly heading?: ReactNode;
|
|
24
75
|
}
|
|
25
76
|
export declare function FacetPanelPane(props: FacetPanelPaneProps): ReactElement;
|
|
26
77
|
//# sourceMappingURL=FacetPanelPane.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FacetPanelPane.d.ts","sourceRoot":"","sources":["../../src/default/FacetPanelPane.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"FacetPanelPane.d.ts","sourceRoot":"","sources":["../../src/default/FacetPanelPane.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAmBrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAQjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,gDAAgD;AAChD,MAAM,WAAW,uBAAuB;IACtC,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CAClD;AAED,gDAAgD;AAChD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CAAC;IACtC,6CAA6C;IAC7C,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI,KAAK,IAAI,CAAC;CACpD;AAED,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACxD;wCACoC;IACpC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAClD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B;gFAC4E;IAC5E,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,uBAAuB,KAAK,SAAS,CAAC;IAC7E;8DAC0D;IAC1D,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,SAAS,CAAC;IACnE,wEAAwE;IACxE,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;CAC9B;AA4MD,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,YAAY,CAkJvE"}
|