@stapel/search-react 0.1.0 → 0.3.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 +94 -0
- package/LICENSE +21 -0
- package/dist/default/SearchPage.d.ts.map +1 -1
- package/dist/default/SearchPage.js +2 -5
- package/dist/default/SearchPage.js.map +1 -1
- package/dist/default/SearchResultsPane.d.ts +20 -0
- package/dist/default/SearchResultsPane.d.ts.map +1 -1
- package/dist/default/SearchResultsPane.js +26 -7
- package/dist/default/SearchResultsPane.js.map +1 -1
- package/dist/default/SortSelect.d.ts +2 -1
- package/dist/default/SortSelect.d.ts.map +1 -1
- package/dist/default/SortSelect.js +12 -3
- package/dist/default/SortSelect.js.map +1 -1
- package/dist/default/index.d.ts +3 -1
- package/dist/default/index.d.ts.map +1 -1
- package/dist/default/index.js +2 -0
- package/dist/default/index.js.map +1 -1
- package/dist/headless/useAppliedSort.d.ts +2 -0
- package/dist/headless/useAppliedSort.d.ts.map +1 -0
- package/dist/headless/useAppliedSort.js +25 -0
- package/dist/headless/useAppliedSort.js.map +1 -0
- package/dist/i18n/es.d.ts.map +1 -1
- package/dist/i18n/es.js +4 -2
- package/dist/i18n/es.js.map +1 -1
- package/dist/i18n/keys.d.ts +19 -2
- package/dist/i18n/keys.d.ts.map +1 -1
- package/dist/i18n/keys.js +26 -4
- package/dist/i18n/keys.js.map +1 -1
- package/dist/i18n/ru.d.ts +1 -1
- package/dist/i18n/ru.d.ts.map +1 -1
- package/dist/i18n/ru.js +11 -3
- package/dist/i18n/ru.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/llms.txt +1 -1
- package/manifest.json +7 -1
- package/nav-manifest.json +1 -1
- package/package.json +15 -15
- package/src/analytics/generated/events.json +1 -1
- package/src/default/SearchPage.tsx +11 -16
- package/src/default/SearchResultsPane.tsx +68 -16
- package/src/default/SortSelect.tsx +14 -5
- package/src/default/index.ts +6 -1
- package/src/headless/useAppliedSort.ts +25 -0
- package/src/i18n/es.ts +4 -2
- package/src/i18n/keys.ts +27 -4
- package/src/i18n/ru.ts +10 -2
- package/src/index.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1 +1,95 @@
|
|
|
1
1
|
# @stapel/search-react
|
|
2
|
+
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 5246040: A result page that reads like one: plural counts, a grid, and one of each label
|
|
8
|
+
|
|
9
|
+
Three findings from a walk over the live storefront, all of them in the pane a
|
|
10
|
+
visitor spends the whole session looking at.
|
|
11
|
+
|
|
12
|
+
**The count is counted copy.** `"Примерно {count} объявлений"` was one Russian
|
|
13
|
+
string for every number — right for 5–20, wrong for 1, 2, 3, 4 and 21, which is
|
|
14
|
+
most of the pages a catalogue actually serves. Both count families are now
|
|
15
|
+
CLDR plural families (`.one` / `.other` in en and es, `.one` / `.few` / `.many`
|
|
16
|
+
/ `.other` in ru) rendered through core's `tPlural`, and the parity test asks
|
|
17
|
+
`Intl.PluralRules` which forms each locale can land on instead of checking a
|
|
18
|
+
hand-written list. `SEARCH_I18N_PLURAL_KEYS` names the families for a host
|
|
19
|
+
overriding the copy: **a host bundle that overrides
|
|
20
|
+
`search.results.count_exact` / `…count_approximate` should move to per-category
|
|
21
|
+
keys** — the flat key still renders (core falls back to it) but with one ending
|
|
22
|
+
for every number, which is the defect.
|
|
23
|
+
|
|
24
|
+
**The results are a grid.** `<Flex vertical>` made every page a one-column
|
|
25
|
+
full-bleed stack; a 1400px catalogue drew two enormous cards and a screenful of
|
|
26
|
+
white. The default is now `repeat(auto-fill, minmax(280px, 1fr))` — as many
|
|
27
|
+
columns as fit, each at least a readable card, one column on a phone, no
|
|
28
|
+
breakpoints to maintain. `renderResults(items)` is the new layout slot above
|
|
29
|
+
`renderCard`: a container that wants a table, a masonry wall or a list beside a
|
|
30
|
+
map replaces the grid entirely, and the pane keeps its four load arms, so
|
|
31
|
+
"nothing matches this search" is never the slot's problem.
|
|
32
|
+
|
|
33
|
+
**One heading and one sort control.** `<SearchPage>` captioned its toolbar
|
|
34
|
+
"Results" and then mounted a pane whose own heading says "Results"; the sort
|
|
35
|
+
control printed its label and then repeated it as the select's placeholder,
|
|
36
|
+
with no value showing. The pane now owns the heading row and takes a `toolbar`
|
|
37
|
+
slot beside the count (that is where `<SortSelect/>` goes), the placeholder is
|
|
38
|
+
gone, and `useAppliedSort()` — a new headless hook — reads the sort the SERVER
|
|
39
|
+
reported for the page already in cache, so a URL with no `sort` shows what the
|
|
40
|
+
results are actually ordered by. It subscribes with `enabled: false`: the same
|
|
41
|
+
query key the pane fills, never a request of its own.
|
|
42
|
+
|
|
43
|
+
## 0.2.0
|
|
44
|
+
|
|
45
|
+
### Minor Changes
|
|
46
|
+
|
|
47
|
+
- 6356af8: New package: `@stapel/search-react` — the frontend pair for stapel-search, and
|
|
48
|
+
the one surface a storefront's catalogue, category and search pages all come
|
|
49
|
+
from.
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
const runtime = createSearchRuntime({ baseUrl: "/search/api/v1/" });
|
|
53
|
+
<SearchProvider runtime={runtime}>
|
|
54
|
+
<SearchPage adapter={useRouterSearchParams()} defaultType="listing" />
|
|
55
|
+
</SearchProvider>;
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
No session, no workspace id, no auth client: every endpoint it calls is
|
|
59
|
+
`AllowAny`, so a catalogue renders for a visitor who will never sign in.
|
|
60
|
+
|
|
61
|
+
**The URL is the state.** Text, category, facet filters, ranges, geo, sort, page
|
|
62
|
+
size and the keyset cursor all live in the query string, under the backend's own
|
|
63
|
+
parameter names, and no component keeps a second copy. Copying the address into
|
|
64
|
+
another tab reproduces the page, Back removes exactly the last filter, and a
|
|
65
|
+
reload loses nothing — by construction rather than by discipline. Changing any
|
|
66
|
+
of them drops the keyset cursor, because `anchor` is a position inside one
|
|
67
|
+
ordered candidate set and carrying it across a filter change answers page 4 of
|
|
68
|
+
a different search. The router is a two-member seam (`SearchParamsAdapter`);
|
|
69
|
+
`./router` binds react-router's `useSearchParams`, and a Next.js app or a plain
|
|
70
|
+
`URLSearchParams` satisfies the same shape.
|
|
71
|
+
|
|
72
|
+
**Facets are drill-down, and the panel shows it.** Each is counted with its own
|
|
73
|
+
filter removed, so picking a value leaves its siblings with the counts you would
|
|
74
|
+
get by switching to them; closed sets keep their authored order, zeros included.
|
|
75
|
+
The server sends no option labels — they are keys in the category's feature
|
|
76
|
+
schema — so `categoryFeatures` is an explicit input and the captions resolve
|
|
77
|
+
through `@stapel/attributes-react`'s `formatFeatureValue`, the same formatter a
|
|
78
|
+
card uses.
|
|
79
|
+
|
|
80
|
+
**What the server admits, the screen repeats.** `exact_total: false` renders as
|
|
81
|
+
"about N", `facet_meta.approximate` says the counts are a sample, a skipped slug
|
|
82
|
+
shows "not counted" rather than `0`, and every `degraded[]` literal becomes a
|
|
83
|
+
line in a banner — including one this build has no wording for, which arrives
|
|
84
|
+
with its raw text. A failed search says "we could not run this search" with a
|
|
85
|
+
retry, and `error.400.search_window_exceeded` says "narrow the search"; neither
|
|
86
|
+
is ever spelled "nothing found".
|
|
87
|
+
|
|
88
|
+
`promoted` (DSA Art. 26) rides every item under every sort and reaches the card
|
|
89
|
+
slot whole, so a storefront's own `<ListingCard>` can still mark it; the P2B
|
|
90
|
+
Art. 5 ranking disclosure ships as a headless bag and a page, listing even the
|
|
91
|
+
parameters the configured engine cannot evaluate.
|
|
92
|
+
|
|
93
|
+
`./default` is the antd skin (`SearchPage`, `SearchResultsPane`,
|
|
94
|
+
`FacetPanelPane`, `RankingDisclosurePane`); the main entry carries no antd and
|
|
95
|
+
no router.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Stapel contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchPage.d.ts","sourceRoot":"","sources":["../../src/default/SearchPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"SearchPage.d.ts","sourceRoot":"","sources":["../../src/default/SearchPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAErD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAC9E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAIpE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAGhE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,WAAW,eAAgB,SAAQ,aAAa,EAAE,uBAAuB;IAC7E;2BACuB;IACvB,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,kBAAkB,CAAC;IACzC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAClD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;CAC7B;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,YAAY,CAwC/D"}
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Col, Flex, Row
|
|
3
|
-
import { useT } from "@stapel/core";
|
|
2
|
+
import { Col, Flex, Row } from "antd";
|
|
4
3
|
import { SearchStateProvider } from "../headless/SearchStateProvider.js";
|
|
5
|
-
import { SEARCH_I18N_KEYS } from "../i18n/keys.js";
|
|
6
4
|
import { FacetPanelPane } from "./FacetPanelPane.js";
|
|
7
5
|
import { SearchResultsPane } from "./SearchResultsPane.js";
|
|
8
6
|
import { SortSelect } from "./SortSelect.js";
|
|
9
7
|
import { SearchSkinTheme } from "./theme.js";
|
|
10
8
|
import { UrlIssueNotice } from "./UrlIssueNotice.js";
|
|
11
9
|
export function SearchPage(props) {
|
|
12
|
-
const t = useT();
|
|
13
10
|
const { adapter, renderCard, categoryFeatures, locale, footer, mode, ...parseOptions } = props;
|
|
14
|
-
return (_jsx(SearchSkinTheme, { ...(mode !== undefined ? { mode } : {}), children: _jsx(SearchStateProvider, { adapter: adapter, ...parseOptions, children: _jsxs(Flex, { vertical: true, gap: 16, "data-testid": "search-page", children: [_jsx(UrlIssueNotice, {}), _jsxs(Row, { gutter: [16, 16], children: [_jsx(Col, { xs: 24, md: 7, children: _jsx(FacetPanelPane, { ...(categoryFeatures !== undefined ? { categoryFeatures } : {}), ...(locale !== undefined ? { locale } : {}) }) }), _jsx(Col, { xs: 24, md: 17, children:
|
|
11
|
+
return (_jsx(SearchSkinTheme, { ...(mode !== undefined ? { mode } : {}), children: _jsx(SearchStateProvider, { adapter: adapter, ...parseOptions, children: _jsxs(Flex, { vertical: true, gap: 16, "data-testid": "search-page", children: [_jsx(UrlIssueNotice, {}), _jsxs(Row, { gutter: [16, 16], children: [_jsx(Col, { xs: 24, md: 7, children: _jsx(FacetPanelPane, { ...(categoryFeatures !== undefined ? { categoryFeatures } : {}), ...(locale !== undefined ? { locale } : {}) }) }), _jsx(Col, { xs: 24, md: 17, children: _jsx(SearchResultsPane, { toolbar: _jsx(SortSelect, {}), ...(renderCard !== undefined ? { renderCard } : {}), ...(footer !== undefined ? { footer } : {}) }) })] })] }) }) }));
|
|
15
12
|
}
|
|
16
13
|
//# sourceMappingURL=SearchPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchPage.js","sourceRoot":"","sources":["../../src/default/SearchPage.tsx"],"names":[],"mappings":";AAiBA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,
|
|
1
|
+
{"version":3,"file":"SearchPage.js","sourceRoot":"","sources":["../../src/default/SearchPage.tsx"],"names":[],"mappings":";AAiBA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAEtC,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAGzE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAcrD,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC/C,MAAM,EACJ,OAAO,EACP,UAAU,EACV,gBAAgB,EAChB,MAAM,EACN,MAAM,EACN,IAAI,EACJ,GAAG,YAAY,EAChB,GAAG,KAAK,CAAC;IAEV,OAAO,CACL,KAAC,eAAe,OAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,YACvD,KAAC,mBAAmB,IAAC,OAAO,EAAE,OAAO,KAAM,YAAY,YACrD,MAAC,IAAI,IAAC,QAAQ,QAAC,GAAG,EAAE,EAAE,iBAAc,aAAa,aAC/C,KAAC,cAAc,KAAG,EAClB,MAAC,GAAG,IAAC,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,aACnB,KAAC,GAAG,IAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,YAChB,KAAC,cAAc,OACT,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAC5D,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC5C,GACE,EACN,KAAC,GAAG,IAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,YAMjB,KAAC,iBAAiB,IAChB,OAAO,EAAE,KAAC,UAAU,KAAG,KACnB,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAChD,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC5C,GACE,IACF,IACD,GACa,GACN,CACnB,CAAC;AACJ,CAAC"}
|
|
@@ -14,8 +14,17 @@
|
|
|
14
14
|
* empty page.
|
|
15
15
|
*/
|
|
16
16
|
import type { ReactElement, ReactNode } from "react";
|
|
17
|
+
import type { SearchItem } from "../api/types.js";
|
|
17
18
|
import type { SearchCardRenderer } from "./SearchResultCard.js";
|
|
18
19
|
import type { ThemeModeProp } from "./types.js";
|
|
20
|
+
/**
|
|
21
|
+
* The whole result LAYOUT, for a container that wants its own — a map beside
|
|
22
|
+
* the list, a masonry wall, a table. It receives the loaded rows; the pane
|
|
23
|
+
* still owns the four load arms around it, so "nothing found" and "we could
|
|
24
|
+
* not run this search" stay the pane's sentences rather than the slot's
|
|
25
|
+
* problem.
|
|
26
|
+
*/
|
|
27
|
+
export type SearchResultsRenderer = (items: readonly SearchItem[]) => ReactNode;
|
|
19
28
|
export interface SearchResultsPaneProps extends ThemeModeProp {
|
|
20
29
|
/**
|
|
21
30
|
* The card slot (spec §6.2 item 1). A storefront passes
|
|
@@ -24,6 +33,17 @@ export interface SearchResultsPaneProps extends ThemeModeProp {
|
|
|
24
33
|
* default honours it.
|
|
25
34
|
*/
|
|
26
35
|
readonly renderCard?: SearchCardRenderer;
|
|
36
|
+
/**
|
|
37
|
+
* The layout slot: replaces the grid entirely, `renderCard` and all. Use it
|
|
38
|
+
* when the container's arrangement is not "cards in a grid".
|
|
39
|
+
*/
|
|
40
|
+
readonly renderResults?: SearchResultsRenderer;
|
|
41
|
+
/**
|
|
42
|
+
* Rendered beside the count in the heading row — the sort control, a view
|
|
43
|
+
* switch. The pane owns the heading, so a screen that composes it hands its
|
|
44
|
+
* toolbar in here instead of printing a second caption above the pane.
|
|
45
|
+
*/
|
|
46
|
+
readonly toolbar?: ReactNode;
|
|
27
47
|
/** Rendered under the pager — where the container puts the ranking link. */
|
|
28
48
|
readonly footer?: ReactNode;
|
|
29
49
|
readonly enabled?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchResultsPane.d.ts","sourceRoot":"","sources":["../../src/default/SearchResultsPane.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"SearchResultsPane.d.ts","sourceRoot":"","sources":["../../src/default/SearchResultsPane.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAiB,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAUpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAQlD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;;;GAMG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAClC,KAAK,EAAE,SAAS,UAAU,EAAE,KACzB,SAAS,CAAC;AAiBf,MAAM,WAAW,sBAAuB,SAAQ,aAAa;IAC3D;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,kBAAkB,CAAC;IACzC;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,qBAAqB,CAAC;IAC/C;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;IAC7B,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAiDD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,YAAY,CA0F7E"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Button, Empty, Flex, Spin, Typography } from "antd";
|
|
3
|
-
import { errorCode, matchList, toFlowError, useDescribeFlowError, useT, } from "@stapel/core";
|
|
3
|
+
import { errorCode, matchList, toFlowError, useDescribeFlowError, useT, useTPlural, } from "@stapel/core";
|
|
4
4
|
import { SearchResults } from "../headless/SearchResults.js";
|
|
5
5
|
import { SEARCH_WINDOW_EXCEEDED } from "../i18n/errorsMap.js";
|
|
6
6
|
import { SEARCH_I18N_KEYS } from "../i18n/keys.js";
|
|
@@ -8,14 +8,33 @@ import { DegradationNotice } from "./DegradationNotice.js";
|
|
|
8
8
|
import { ErrorAlert } from "./ErrorAlert.js";
|
|
9
9
|
import { SearchResultCard } from "./SearchResultCard.js";
|
|
10
10
|
import { SearchSkinTheme } from "./theme.js";
|
|
11
|
+
/**
|
|
12
|
+
* The results grid. `auto-fill` + `minmax(280px, 1fr)`: as many columns as fit,
|
|
13
|
+
* each at least a readable card and never wider than its share — a catalogue
|
|
14
|
+
* on a 1400px desktop is four columns, not four full-bleed rows, and the same
|
|
15
|
+
* declaration collapses to one column on a phone with no breakpoint to
|
|
16
|
+
* maintain. 280px is the width below which the default card's title, price and
|
|
17
|
+
* location stop fitting on their own lines.
|
|
18
|
+
*/
|
|
19
|
+
const RESULTS_GRID = {
|
|
20
|
+
display: "grid",
|
|
21
|
+
gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))",
|
|
22
|
+
gap: 12,
|
|
23
|
+
alignItems: "stretch",
|
|
24
|
+
};
|
|
11
25
|
function Count(props) {
|
|
12
|
-
|
|
26
|
+
// A COUNTED sentence: `tPlural` asks Intl.PluralRules for the locale's
|
|
27
|
+
// category, so Russian gets three different endings for 1, 3 and 17 instead
|
|
28
|
+
// of the single one that was right for 5-20 and wrong everywhere else.
|
|
29
|
+
const tPlural = useTPlural();
|
|
13
30
|
const page = props.bag.page;
|
|
14
31
|
if (page === null)
|
|
15
32
|
return null;
|
|
16
33
|
return (_jsx(Typography.Text, { type: "secondary", "data-testid": "search-count", children: page.countIsEstimate
|
|
17
|
-
?
|
|
18
|
-
|
|
34
|
+
? tPlural(SEARCH_I18N_KEYS.resultsCountApproximate, {
|
|
35
|
+
count: page.count,
|
|
36
|
+
})
|
|
37
|
+
: tPlural(SEARCH_I18N_KEYS.resultsCountExact, { count: page.count }) }));
|
|
19
38
|
}
|
|
20
39
|
function Pager(props) {
|
|
21
40
|
const t = useT();
|
|
@@ -25,8 +44,8 @@ function Pager(props) {
|
|
|
25
44
|
export function SearchResultsPane(props) {
|
|
26
45
|
const t = useT();
|
|
27
46
|
const describe = useDescribeFlowError();
|
|
28
|
-
const renderCard = props
|
|
29
|
-
return (_jsx(SearchSkinTheme, { ...(props.mode !== undefined ? { mode: props.mode } : {}), children: _jsx(SearchResults, { ...(props.enabled !== undefined ? { enabled: props.enabled } : {}), children: (bag) => (_jsxs(Flex, { vertical: true, gap: 16, children: [_jsxs(Flex, { justify: "space-between", align: "center", wrap: true, gap: 8, children: [_jsx(Typography.Title, { level: 4, style: { margin: 0 }, children: t(SEARCH_I18N_KEYS.resultsTitle) }), _jsx(Count, { bag: bag })] }), _jsx(DegradationNotice, { degradations: bag.degradations }), matchList(bag.state, {
|
|
47
|
+
const { renderCard, renderResults } = props;
|
|
48
|
+
return (_jsx(SearchSkinTheme, { ...(props.mode !== undefined ? { mode: props.mode } : {}), children: _jsx(SearchResults, { ...(props.enabled !== undefined ? { enabled: props.enabled } : {}), children: (bag) => (_jsxs(Flex, { vertical: true, gap: 16, children: [_jsxs(Flex, { justify: "space-between", align: "center", wrap: true, gap: 8, children: [_jsx(Typography.Title, { level: 4, style: { margin: 0 }, children: t(SEARCH_I18N_KEYS.resultsTitle) }), _jsxs(Flex, { align: "center", wrap: true, gap: 12, children: [_jsx(Count, { bag: bag }), props.toolbar] })] }), _jsx(DegradationNotice, { degradations: bag.degradations }), matchList(bag.state, {
|
|
30
49
|
loading: () => (_jsx(Flex, { justify: "center", style: { padding: 24 }, children: _jsx(Spin, { "data-testid": "search-loading" }) })),
|
|
31
50
|
failed: (error) => {
|
|
32
51
|
// The window refusal is a DIFFERENT sentence from a failed
|
|
@@ -40,7 +59,7 @@ export function SearchResultsPane(props) {
|
|
|
40
59
|
}, action: _jsx(Button, { size: "small", onClick: bag.refetch, "data-analytics": "none", "data-analytics-reason": "retry of a failed read; no flow to step", children: t(SEARCH_I18N_KEYS.resultsRetry) }) }));
|
|
41
60
|
},
|
|
42
61
|
empty: () => (_jsx(Empty, { "data-testid": "search-empty", description: t(SEARCH_I18N_KEYS.resultsEmpty) })),
|
|
43
|
-
ready: (items) => (_jsx(
|
|
62
|
+
ready: (items) => (_jsx("div", { "data-testid": "search-results", children: renderResults !== undefined ? (renderResults(items)) : (_jsx("div", { style: RESULTS_GRID, "data-testid": "search-results-grid", children: items.map((item) => (_jsx("div", { children: renderCard !== undefined ? (renderCard(item)) : (_jsx(SearchResultCard, { item: item })) }, item.key))) })) })),
|
|
44
63
|
}), _jsx(Pager, { bag: bag }), props.footer] })) }) }));
|
|
45
64
|
}
|
|
46
65
|
//# sourceMappingURL=SearchResultsPane.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchResultsPane.js","sourceRoot":"","sources":["../../src/default/SearchResultsPane.tsx"],"names":[],"mappings":";AAgBA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAC7D,OAAO,EACL,SAAS,EACT,SAAS,EACT,WAAW,EACX,oBAAoB,EACpB,IAAI,
|
|
1
|
+
{"version":3,"file":"SearchResultsPane.js","sourceRoot":"","sources":["../../src/default/SearchResultsPane.tsx"],"names":[],"mappings":"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"}
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import type { ReactElement } from "react";
|
|
17
17
|
export interface SortSelectProps {
|
|
18
|
-
/** The sort the SERVER applied, shown when the URL names none.
|
|
18
|
+
/** The sort the SERVER applied, shown when the URL names none. Omitted, it
|
|
19
|
+
* is read from the page already in cache — see {@link useAppliedSort}. */
|
|
19
20
|
readonly appliedSort?: string | undefined;
|
|
20
21
|
}
|
|
21
22
|
export declare function SortSelect(props: SortSelectProps): ReactElement;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SortSelect.d.ts","sourceRoot":"","sources":["../../src/default/SortSelect.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"SortSelect.d.ts","sourceRoot":"","sources":["../../src/default/SortSelect.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAgB1C,MAAM,WAAW,eAAe;IAC9B;8EAC0E;IAC1E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,YAAY,CAgD/D"}
|
|
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Flex, Select, Typography } from "antd";
|
|
3
3
|
import { useT } from "@stapel/core";
|
|
4
4
|
import { SEARCH_SORTS } from "../api/types.js";
|
|
5
|
+
import { useAppliedSort } from "../headless/useAppliedSort.js";
|
|
5
6
|
import { useSearchState } from "../headless/SearchStateProvider.js";
|
|
6
7
|
import { SEARCH_I18N_KEYS } from "../i18n/keys.js";
|
|
7
8
|
const SORT_LABEL_KEY = {
|
|
@@ -14,12 +15,20 @@ const SORT_LABEL_KEY = {
|
|
|
14
15
|
export function SortSelect(props) {
|
|
15
16
|
const t = useT();
|
|
16
17
|
const { state, setSort } = useSearchState();
|
|
18
|
+
// What the control SAYS must be what the results are ordered by. With no
|
|
19
|
+
// `sort` in the URL the select used to fall through to its placeholder and
|
|
20
|
+
// show nothing at all, while the server had already sorted the page and
|
|
21
|
+
// said so in the envelope.
|
|
22
|
+
const applied = useAppliedSort();
|
|
23
|
+
// What the page is ACTUALLY ordered by: the URL's sort, else the one the
|
|
24
|
+
// container states, else the one the server reported for the page in cache.
|
|
25
|
+
const active = state.sort ?? props.appliedSort ?? applied;
|
|
17
26
|
const hasCentre = state.geo !== undefined;
|
|
18
27
|
const known = new Set(SEARCH_SORTS);
|
|
19
|
-
const values =
|
|
20
|
-
? [...SEARCH_SORTS,
|
|
28
|
+
const values = active !== undefined && !known.has(active)
|
|
29
|
+
? [...SEARCH_SORTS, active]
|
|
21
30
|
: SEARCH_SORTS;
|
|
22
|
-
return (_jsxs(Flex, { gap: 8, align: "center", children: [_jsx(Typography.Text, { type: "secondary", children: t(SEARCH_I18N_KEYS.sortLabel) }), _jsx(Select, { "data-testid": "search-sort", style: { minWidth: 180 }, value:
|
|
31
|
+
return (_jsxs(Flex, { gap: 8, align: "center", children: [_jsx(Typography.Text, { type: "secondary", children: t(SEARCH_I18N_KEYS.sortLabel) }), _jsx(Select, { "data-testid": "search-sort", style: { minWidth: 180 }, value: active ?? null, onChange: (next) => {
|
|
23
32
|
setSort(next);
|
|
24
33
|
}, options: values.map((value) => {
|
|
25
34
|
const key = SORT_LABEL_KEY[value];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SortSelect.js","sourceRoot":"","sources":["../../src/default/SortSelect.tsx"],"names":[],"mappings":";AAgBA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,MAAM,cAAc,GAAqC;IACvD,SAAS,EAAE,gBAAgB,CAAC,aAAa;IACzC,MAAM,EAAE,gBAAgB,CAAC,UAAU;IACnC,SAAS,EAAE,gBAAgB,CAAC,YAAY;IACxC,UAAU,EAAE,gBAAgB,CAAC,aAAa;IAC1C,QAAQ,EAAE,gBAAgB,CAAC,YAAY;CACxC,CAAC;
|
|
1
|
+
{"version":3,"file":"SortSelect.js","sourceRoot":"","sources":["../../src/default/SortSelect.tsx"],"names":[],"mappings":";AAgBA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,MAAM,cAAc,GAAqC;IACvD,SAAS,EAAE,gBAAgB,CAAC,aAAa;IACzC,MAAM,EAAE,gBAAgB,CAAC,UAAU;IACnC,SAAS,EAAE,gBAAgB,CAAC,YAAY;IACxC,UAAU,EAAE,gBAAgB,CAAC,aAAa;IAC1C,QAAQ,EAAE,gBAAgB,CAAC,YAAY;CACxC,CAAC;AAQF,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC/C,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;IACjB,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC5C,yEAAyE;IACzE,2EAA2E;IAC3E,wEAAwE;IACxE,2BAA2B;IAC3B,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;IAEjC,yEAAyE;IACzE,4EAA4E;IAC5E,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,WAAW,IAAI,OAAO,CAAC;IAC1D,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,KAAK,SAAS,CAAC;IAC1C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;IACpC,MAAM,MAAM,GACV,MAAM,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;QACxC,CAAC,CAAC,CAAC,GAAG,YAAY,EAAE,MAAM,CAAC;QAC3B,CAAC,CAAC,YAAY,CAAC;IAEnB,OAAO,CACL,MAAC,IAAI,IAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAC,QAAQ,aAC1B,KAAC,UAAU,CAAC,IAAI,IAAC,IAAI,EAAC,WAAW,YAC9B,CAAC,CAAC,gBAAgB,CAAC,SAAS,CAAC,GACd,EAClB,KAAC,MAAM,mBACO,aAAa,EACzB,KAAK,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,EACxB,KAAK,EAAE,MAAM,IAAI,IAAI,EACrB,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE;oBACjB,OAAO,CAAC,IAAI,CAAC,CAAC;gBAChB,CAAC,EACD,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;oBAC5B,MAAM,GAAG,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;oBAClC,MAAM,WAAW,GAAG,KAAK,KAAK,UAAU,IAAI,CAAC,SAAS,CAAC;oBACvD,OAAO;wBACL,KAAK;wBACL,KAAK,EAAE,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK;wBACzC,QAAQ,EAAE,WAAW;wBACrB,+DAA+D;wBAC/D,gCAAgC;wBAChC,GAAG,CAAC,WAAW;4BACb,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,oCAAoC,CAAC,EAAE;4BACpD,CAAC,CAAC,EAAE,CAAC;qBACR,CAAC;gBACJ,CAAC,CAAC,GACF,IACG,CACR,CAAC;AACJ,CAAC"}
|
package/dist/default/index.d.ts
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
* 1. **`renderCard`** — the card slot. A storefront passes
|
|
12
12
|
* `<ListingCard>` from `@stapel/listings-react/default`; the generic card
|
|
13
13
|
* here is the documented default, not the intended end state (spec §3.7).
|
|
14
|
+
* `renderResults` is the level above it: the whole layout, for a container
|
|
15
|
+
* whose arrangement is not "cards in a grid".
|
|
14
16
|
* 2. **`categoryFeatures`** — the facet-label slot. The server sends
|
|
15
17
|
* `{value: count}` and no labels; the schema that names them lives in
|
|
16
18
|
* categories, and the container hands it in (spec §6.2 item 2).
|
|
@@ -21,7 +23,7 @@
|
|
|
21
23
|
export { SearchPage } from "./SearchPage.js";
|
|
22
24
|
export type { SearchPageProps } from "./SearchPage.js";
|
|
23
25
|
export { SearchResultsPane } from "./SearchResultsPane.js";
|
|
24
|
-
export type { SearchResultsPaneProps } from "./SearchResultsPane.js";
|
|
26
|
+
export type { SearchResultsPaneProps, SearchResultsRenderer, } from "./SearchResultsPane.js";
|
|
25
27
|
export { FacetPanelPane } from "./FacetPanelPane.js";
|
|
26
28
|
export type { FacetPanelPaneProps } from "./FacetPanelPane.js";
|
|
27
29
|
export { RankingDisclosurePane } from "./RankingDisclosurePane.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/default/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/default/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EACV,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,YAAY,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,YAAY,EAAE,0BAA0B,EAAE,MAAM,4BAA4B,CAAC;AAG7E,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC9E,YAAY,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG7C,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,YAAY,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACvD,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/default/index.js
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
* 1. **`renderCard`** — the card slot. A storefront passes
|
|
12
12
|
* `<ListingCard>` from `@stapel/listings-react/default`; the generic card
|
|
13
13
|
* here is the documented default, not the intended end state (spec §3.7).
|
|
14
|
+
* `renderResults` is the level above it: the whole layout, for a container
|
|
15
|
+
* whose arrangement is not "cards in a grid".
|
|
14
16
|
* 2. **`categoryFeatures`** — the facet-label slot. The server sends
|
|
15
17
|
* `{value: count}` and no labels; the schema that names them lives in
|
|
16
18
|
* categories, and the container hands it in (spec §6.2 item 2).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/default/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/default/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,+EAA+E;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAM3D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAGrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAGnE,+EAA+E;AAC/E,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,+EAA+E;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAppliedSort.d.ts","sourceRoot":"","sources":["../../src/headless/useAppliedSort.ts"],"names":[],"mappings":"AAoBA,wBAAgB,cAAc,IAAI,MAAM,GAAG,SAAS,CAInD"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sort the SERVER applied to the page currently in cache.
|
|
3
|
+
*
|
|
4
|
+
* A search with no `sort` in its URL is still sorted — the backend picks
|
|
5
|
+
* relevance when there is text and newest when there is not, and says so in
|
|
6
|
+
* the envelope's `sort`. A control that showed nothing in that case was not
|
|
7
|
+
* being cautious: it was hiding the answer the response already carried, and
|
|
8
|
+
* the live /s page rendered a sort box with no value while the results were
|
|
9
|
+
* plainly in an order.
|
|
10
|
+
*
|
|
11
|
+
* `enabled: false` is the whole trick. The key is the one `<SearchResults>`
|
|
12
|
+
* populates, so this subscribes to the SAME cache entry and re-renders when
|
|
13
|
+
* the page lands — but it never issues a request of its own, which is what
|
|
14
|
+
* keeps a control from turning into a second search (including on a pane
|
|
15
|
+
* mounted with `enabled={false}`, where a request would be exactly the thing
|
|
16
|
+
* the host switched off).
|
|
17
|
+
*/
|
|
18
|
+
import { useSearchQuery } from "../model/queries.js";
|
|
19
|
+
import { useSearchState } from "./SearchStateProvider.js";
|
|
20
|
+
export function useAppliedSort() {
|
|
21
|
+
const { state } = useSearchState();
|
|
22
|
+
const query = useSearchQuery(state, { enabled: false });
|
|
23
|
+
return query.data?.sort;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=useAppliedSort.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAppliedSort.js","sourceRoot":"","sources":["../../src/headless/useAppliedSort.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,MAAM,UAAU,cAAc;IAC5B,MAAM,EAAE,KAAK,EAAE,GAAG,cAAc,EAAE,CAAC;IACnC,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IACxD,OAAO,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC;AAC1B,CAAC"}
|
package/dist/i18n/es.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"es.d.ts","sourceRoot":"","sources":["../../src/i18n/es.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,EAAE,
|
|
1
|
+
{"version":3,"file":"es.d.ts","sourceRoot":"","sources":["../../src/i18n/es.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,EAAE,cA8FhC,CAAC;AAEF,+DAA+D;AAC/D,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAE7D"}
|
package/dist/i18n/es.js
CHANGED
|
@@ -15,8 +15,10 @@ export const searchI18nBundleEs = {
|
|
|
15
15
|
"search.results.load_failed": "No pudimos ejecutar esta búsqueda.",
|
|
16
16
|
"search.results.empty": "No hay nada que coincida con esta búsqueda.",
|
|
17
17
|
"search.results.retry": "Reintentar",
|
|
18
|
-
"search.results.count_approximate": "
|
|
19
|
-
"search.results.
|
|
18
|
+
"search.results.count_approximate.one": "Aproximadamente {count} resultado",
|
|
19
|
+
"search.results.count_approximate.other": "Unos {count} resultados",
|
|
20
|
+
"search.results.count_exact.one": "{count} resultado",
|
|
21
|
+
"search.results.count_exact.other": "{count} resultados",
|
|
20
22
|
"search.results.took_ms": "{ms} ms",
|
|
21
23
|
"search.results.next": "Página siguiente",
|
|
22
24
|
"search.results.prev": "Página anterior",
|
package/dist/i18n/es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"es.js","sourceRoot":"","sources":["../../src/i18n/es.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAmB;IAChD,GAAG,mBAAmB;IAEtB,sBAAsB,EAAE,4BAA4B;IAEpD,sBAAsB,EAAE,YAAY;IACpC,wBAAwB,EAAE,WAAW;IACrC,4BAA4B,EAAE,oCAAoC;IAClE,sBAAsB,EAAE,6CAA6C;IACrE,sBAAsB,EAAE,YAAY;IACpC,
|
|
1
|
+
{"version":3,"file":"es.js","sourceRoot":"","sources":["../../src/i18n/es.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAmB;IAChD,GAAG,mBAAmB;IAEtB,sBAAsB,EAAE,4BAA4B;IAEpD,sBAAsB,EAAE,YAAY;IACpC,wBAAwB,EAAE,WAAW;IACrC,4BAA4B,EAAE,oCAAoC;IAClE,sBAAsB,EAAE,6CAA6C;IACrE,sBAAsB,EAAE,YAAY;IACpC,sCAAsC,EAAE,mCAAmC;IAC3E,wCAAwC,EAAE,yBAAyB;IACnE,gCAAgC,EAAE,mBAAmB;IACrD,kCAAkC,EAAE,oBAAoB;IACxD,wBAAwB,EAAE,SAAS;IACnC,qBAAqB,EAAE,kBAAkB;IACzC,qBAAqB,EAAE,iBAAiB;IACxC,+BAA+B,EAAE,0BAA0B;IAC3D,iCAAiC,EAAE,2BAA2B;IAC9D,gCAAgC,EAC9B,iHAAiH;IACnH,yBAAyB,EAAE,cAAc;IACzC,8BAA8B,EAC5B,yGAAyG;IAC3G,4BAA4B,EAAE,WAAW;IACzC,yBAAyB,EAAE,YAAY;IACvC,qBAAqB,EAAE,OAAO;IAE9B,mBAAmB,EAAE,OAAO;IAC5B,uBAAuB,EAAE,gBAAgB;IACzC,oBAAoB,EAAE,eAAe;IACrC,uBAAuB,EAAE,0BAA0B;IACnD,wBAAwB,EAAE,0BAA0B;IACpD,sBAAsB,EAAE,cAAc;IACtC,0BAA0B,EAAE,qBAAqB;IAEjD,qBAAqB,EAAE,SAAS;IAChC,uBAAuB,EAAE,mBAAmB;IAC5C,2BAA2B,EAAE,gCAAgC;IAC7D,qBAAqB,EAAE,kCAAkC;IACzD,qBAAqB,EAAE,QAAQ;IAC/B,yBAAyB,EAAE,oCAAoC;IAC/D,2BAA2B,EACzB,kFAAkF;IACpF,uBAAuB,EACrB,0DAA0D;IAC5D,2BAA2B,EAAE,YAAY;IACzC,+BAA+B,EAC7B,6EAA6E;IAC/E,0BAA0B,EAAE,OAAO;IACnC,wBAAwB,EAAE,OAAO;IACjC,2BAA2B,EAAE,SAAS;IAEtC,kBAAkB,EAAE,WAAW;IAC/B,sBAAsB,EAAE,oBAAoB;IAC5C,kBAAkB,EAAE,oBAAoB;IACxC,gBAAgB,EAAE,0BAA0B;IAC5C,mBAAmB,EAAE,uBAAuB;IAE5C,yBAAyB,EAAE,sCAAsC;IACjE,+BAA+B,EAAE,qCAAqC;IACtE,iCAAiC,EAC/B,oDAAoD;IACtD,iCAAiC,EAC/B,2EAA2E;IAC7E,kCAAkC,EAChC,6CAA6C;IAE/C,uBAAuB,EAAE,oCAAoC;IAC7D,gCAAgC,EAC9B,+EAA+E;IACjF,iCAAiC,EAC/B,+EAA+E;IACjF,6BAA6B,EAAE,4CAA4C;IAC3E,oCAAoC,EAAE,2CAA2C;IACjF,iCAAiC,EAC/B,0FAA0F;IAC5F,wBAAwB,EACtB,2FAA2F;IAC7F,yBAAyB,EACvB,qFAAqF;IAEvF,sBAAsB,EAAE,kCAAkC;IAC1D,sBAAsB,EACpB,2FAA2F;IAC7F,wBAAwB,EAAE,qCAAqC;IAC/D,4BAA4B,EAAE,8CAA8C;IAC5E,sBAAsB,EAAE,oDAAoD;IAC5E,0BAA0B,EAAE,WAAW;IACvC,uBAAuB,EAAE,MAAM;IAC/B,2BAA2B,EAAE,aAAa;IAC1C,yBAAyB,EAAE,uBAAuB;IAClD,sBAAsB,EAAE,OAAO;IAC/B,qBAAqB,EAAE,kCAAkC;CAC1D,CAAC;AAEF,+DAA+D;AAC/D,MAAM,UAAU,oBAAoB,CAAC,MAAkB;IACrD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;AAClD,CAAC"}
|
package/dist/i18n/keys.d.ts
CHANGED
|
@@ -24,9 +24,10 @@ export declare const SEARCH_I18N_KEYS: {
|
|
|
24
24
|
readonly resultsLoadFailed: "search.results.load_failed";
|
|
25
25
|
readonly resultsEmpty: "search.results.empty";
|
|
26
26
|
readonly resultsRetry: "search.results.retry";
|
|
27
|
-
/** "About N results" — the sentence for an ESTIMATED count.
|
|
27
|
+
/** "About N results" — the sentence for an ESTIMATED count. A PLURAL
|
|
28
|
+
* FAMILY: render with `tPlural`, never `t` (see SEARCH_I18N_PLURAL_KEYS). */
|
|
28
29
|
readonly resultsCountApproximate: "search.results.count_approximate";
|
|
29
|
-
/** "N results" — only when `exact_total` is true. */
|
|
30
|
+
/** "N results" — only when `exact_total` is true. A PLURAL FAMILY. */
|
|
30
31
|
readonly resultsCountExact: "search.results.count_exact";
|
|
31
32
|
readonly resultsTookMs: "search.results.took_ms";
|
|
32
33
|
readonly resultsNext: "search.results.next";
|
|
@@ -92,6 +93,22 @@ export declare const SEARCH_I18N_KEYS: {
|
|
|
92
93
|
readonly rankingLink: "search.ranking.link";
|
|
93
94
|
};
|
|
94
95
|
export type SearchI18nKey = (typeof SEARCH_I18N_KEYS)[keyof typeof SEARCH_I18N_KEYS];
|
|
96
|
+
/**
|
|
97
|
+
* The keys above that are PLURAL FAMILIES rather than single messages.
|
|
98
|
+
*
|
|
99
|
+
* A family is catalogued as one flat key per CLDR category
|
|
100
|
+
* (`<family>.one`, `…few`, `…many`, `…other`) and rendered with core's
|
|
101
|
+
* `tPlural(family, { count })`, which asks `Intl.PluralRules` for the current
|
|
102
|
+
* locale's category. Which categories a bundle carries is a fact about the
|
|
103
|
+
* language — `en` needs two, `ru` needs four — so the pair's parity test asks
|
|
104
|
+
* `Intl.PluralRules` which forms each locale can select and demands exactly
|
|
105
|
+
* those, rather than checking a list somebody typed.
|
|
106
|
+
*
|
|
107
|
+
* The live defect this closes: the Russian estimate sentence was ONE string
|
|
108
|
+
* doing the work of four, correct only for 5-20 and wrong for every 1, 2, 3
|
|
109
|
+
* and 4 a result page actually shows.
|
|
110
|
+
*/
|
|
111
|
+
export declare const SEARCH_I18N_PLURAL_KEYS: readonly SearchI18nKey[];
|
|
95
112
|
/**
|
|
96
113
|
* English fallback bundle for search-react UI keys + backend error codes.
|
|
97
114
|
* The generated backend texts are spread FIRST so coverage of the error
|
package/dist/i18n/keys.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/i18n/keys.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/D;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,gBAAgB;;;;;;;IAS3B
|
|
1
|
+
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/i18n/keys.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/D;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,gBAAgB;;;;;;;IAS3B;iFAC6E;;IAE7E,sEAAsE;;;;;;;IAOtE,yDAAyD;;;;;;;;;;;;;;;;;;;;;;IA0BzD,oEAAoE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2C5D,CAAC;AAEX,MAAM,MAAM,aAAa,GACvB,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,OAAO,gBAAgB,CAAC,CAAC;AAE3D;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,uBAAuB,EAAE,SAAS,aAAa,EAG3D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA8FrD,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAEzD"}
|
package/dist/i18n/keys.js
CHANGED
|
@@ -25,9 +25,10 @@ export const SEARCH_I18N_KEYS = {
|
|
|
25
25
|
resultsLoadFailed: "search.results.load_failed",
|
|
26
26
|
resultsEmpty: "search.results.empty",
|
|
27
27
|
resultsRetry: "search.results.retry",
|
|
28
|
-
/** "About N results" — the sentence for an ESTIMATED count.
|
|
28
|
+
/** "About N results" — the sentence for an ESTIMATED count. A PLURAL
|
|
29
|
+
* FAMILY: render with `tPlural`, never `t` (see SEARCH_I18N_PLURAL_KEYS). */
|
|
29
30
|
resultsCountApproximate: "search.results.count_approximate",
|
|
30
|
-
/** "N results" — only when `exact_total` is true. */
|
|
31
|
+
/** "N results" — only when `exact_total` is true. A PLURAL FAMILY. */
|
|
31
32
|
resultsCountExact: "search.results.count_exact",
|
|
32
33
|
resultsTookMs: "search.results.took_ms",
|
|
33
34
|
resultsNext: "search.results.next",
|
|
@@ -98,6 +99,25 @@ export const SEARCH_I18N_KEYS = {
|
|
|
98
99
|
rankingNotes: "search.ranking.notes",
|
|
99
100
|
rankingLink: "search.ranking.link",
|
|
100
101
|
};
|
|
102
|
+
/**
|
|
103
|
+
* The keys above that are PLURAL FAMILIES rather than single messages.
|
|
104
|
+
*
|
|
105
|
+
* A family is catalogued as one flat key per CLDR category
|
|
106
|
+
* (`<family>.one`, `…few`, `…many`, `…other`) and rendered with core's
|
|
107
|
+
* `tPlural(family, { count })`, which asks `Intl.PluralRules` for the current
|
|
108
|
+
* locale's category. Which categories a bundle carries is a fact about the
|
|
109
|
+
* language — `en` needs two, `ru` needs four — so the pair's parity test asks
|
|
110
|
+
* `Intl.PluralRules` which forms each locale can select and demands exactly
|
|
111
|
+
* those, rather than checking a list somebody typed.
|
|
112
|
+
*
|
|
113
|
+
* The live defect this closes: the Russian estimate sentence was ONE string
|
|
114
|
+
* doing the work of four, correct only for 5-20 and wrong for every 1, 2, 3
|
|
115
|
+
* and 4 a result page actually shows.
|
|
116
|
+
*/
|
|
117
|
+
export const SEARCH_I18N_PLURAL_KEYS = [
|
|
118
|
+
SEARCH_I18N_KEYS.resultsCountApproximate,
|
|
119
|
+
SEARCH_I18N_KEYS.resultsCountExact,
|
|
120
|
+
];
|
|
101
121
|
/**
|
|
102
122
|
* English fallback bundle for search-react UI keys + backend error codes.
|
|
103
123
|
* The generated backend texts are spread FIRST so coverage of the error
|
|
@@ -111,8 +131,10 @@ export const searchI18nBundleEn = {
|
|
|
111
131
|
"search.results.load_failed": "We could not run this search",
|
|
112
132
|
"search.results.empty": "Nothing matches this search",
|
|
113
133
|
"search.results.retry": "Try again",
|
|
114
|
-
"search.results.count_approximate": "About {count}
|
|
115
|
-
"search.results.
|
|
134
|
+
"search.results.count_approximate.one": "About {count} result",
|
|
135
|
+
"search.results.count_approximate.other": "About {count} results",
|
|
136
|
+
"search.results.count_exact.one": "{count} result",
|
|
137
|
+
"search.results.count_exact.other": "{count} results",
|
|
116
138
|
"search.results.took_ms": "{ms} ms",
|
|
117
139
|
"search.results.next": "Next page",
|
|
118
140
|
"search.results.prev": "Previous page",
|
package/dist/i18n/keys.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/i18n/keys.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAEhE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,YAAY,EAAE,sBAAsB;IAEpC,4EAA4E;IAC5E,YAAY,EAAE,sBAAsB;IACpC,cAAc,EAAE,wBAAwB;IACxC,iBAAiB,EAAE,4BAA4B;IAC/C,YAAY,EAAE,sBAAsB;IACpC,YAAY,EAAE,sBAAsB;IACpC
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/i18n/keys.ts"],"names":[],"mappings":"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"}
|
package/dist/i18n/ru.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export { searchErrorBundleRu } from "./generated/errors.ru.gen.js";
|
|
|
7
7
|
* entry does not import this module — gated by size-limit + the bundle-purity
|
|
8
8
|
* test).
|
|
9
9
|
*
|
|
10
|
-
* This is the storefront's DEFAULT language (
|
|
10
|
+
* This is the storefront's DEFAULT language (storefront spec verdict F1:
|
|
11
11
|
* ru-first), which is why it is the fullest of the three bundles and why the
|
|
12
12
|
* wording is checked against what a marketplace visitor is actually being
|
|
13
13
|
* told — "counts are approximate" has to sound like an explanation, not an
|
package/dist/i18n/ru.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ru.d.ts","sourceRoot":"","sources":["../../src/i18n/ru.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,kBAAkB,EAAE,
|
|
1
|
+
{"version":3,"file":"ru.d.ts","sourceRoot":"","sources":["../../src/i18n/ru.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,kBAAkB,EAAE,cAoGhC,CAAC;AAEF;yDACyD;AACzD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAE7D"}
|