@stapel/search-react 0.2.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.
Files changed (48) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/default/SearchPage.d.ts.map +1 -1
  3. package/dist/default/SearchPage.js +2 -5
  4. package/dist/default/SearchPage.js.map +1 -1
  5. package/dist/default/SearchResultsPane.d.ts +20 -0
  6. package/dist/default/SearchResultsPane.d.ts.map +1 -1
  7. package/dist/default/SearchResultsPane.js +26 -7
  8. package/dist/default/SearchResultsPane.js.map +1 -1
  9. package/dist/default/SortSelect.d.ts +2 -1
  10. package/dist/default/SortSelect.d.ts.map +1 -1
  11. package/dist/default/SortSelect.js +12 -3
  12. package/dist/default/SortSelect.js.map +1 -1
  13. package/dist/default/index.d.ts +3 -1
  14. package/dist/default/index.d.ts.map +1 -1
  15. package/dist/default/index.js +2 -0
  16. package/dist/default/index.js.map +1 -1
  17. package/dist/headless/useAppliedSort.d.ts +2 -0
  18. package/dist/headless/useAppliedSort.d.ts.map +1 -0
  19. package/dist/headless/useAppliedSort.js +25 -0
  20. package/dist/headless/useAppliedSort.js.map +1 -0
  21. package/dist/i18n/es.d.ts.map +1 -1
  22. package/dist/i18n/es.js +4 -2
  23. package/dist/i18n/es.js.map +1 -1
  24. package/dist/i18n/keys.d.ts +19 -2
  25. package/dist/i18n/keys.d.ts.map +1 -1
  26. package/dist/i18n/keys.js +26 -4
  27. package/dist/i18n/keys.js.map +1 -1
  28. package/dist/i18n/ru.d.ts.map +1 -1
  29. package/dist/i18n/ru.js +10 -2
  30. package/dist/i18n/ru.js.map +1 -1
  31. package/dist/index.d.ts +2 -1
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +2 -1
  34. package/dist/index.js.map +1 -1
  35. package/llms.txt +1 -1
  36. package/manifest.json +7 -1
  37. package/nav-manifest.json +1 -1
  38. package/package.json +2 -2
  39. package/src/analytics/generated/events.json +1 -1
  40. package/src/default/SearchPage.tsx +11 -16
  41. package/src/default/SearchResultsPane.tsx +68 -16
  42. package/src/default/SortSelect.tsx +14 -5
  43. package/src/default/index.ts +6 -1
  44. package/src/headless/useAppliedSort.ts +25 -0
  45. package/src/i18n/es.ts +4 -2
  46. package/src/i18n/keys.ts +27 -4
  47. package/src/i18n/ru.ts +10 -2
  48. package/src/index.ts +2 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,45 @@
1
1
  # @stapel/search-react
2
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
+
3
43
  ## 0.2.0
4
44
 
5
45
  ### Minor Changes
@@ -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;AAGrD,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;AAKpE,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,CA2C/D"}
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, Typography } from "antd";
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: _jsxs(Flex, { vertical: true, gap: 12, children: [_jsxs(Flex, { justify: "space-between", align: "center", wrap: true, gap: 8, children: [_jsx(Typography.Text, { type: "secondary", children: t(SEARCH_I18N_KEYS.resultsTitle) }), _jsx(SortSelect, {})] }), _jsx(SearchResultsPane, { ...(renderCard !== undefined ? { renderCard } : {}), ...(footer !== undefined ? { footer } : {}) })] }) })] })] }) }) }));
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,UAAU,EAAE,MAAM,MAAM,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAGzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,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,CAAC,GAAG,IAAI,EAAE,CAAC;IACjB,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,YACjB,MAAC,IAAI,IAAC,QAAQ,QAAC,GAAG,EAAE,EAAE,aACpB,MAAC,IAAI,IAAC,OAAO,EAAC,eAAe,EAAC,KAAK,EAAC,QAAQ,EAAC,IAAI,QAAC,GAAG,EAAE,CAAC,aACtD,KAAC,UAAU,CAAC,IAAI,IAAC,IAAI,EAAC,WAAW,YAC9B,CAAC,CAAC,gBAAgB,CAAC,YAAY,CAAC,GACjB,EAClB,KAAC,UAAU,KAAG,IACT,EACP,KAAC,iBAAiB,OACZ,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,IACG,GACH,IACF,IACD,GACa,GACN,CACnB,CAAC;AACJ,CAAC"}
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,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAiBrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,WAAW,sBAAuB,SAAQ,aAAa;IAC3D;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,kBAAkB,CAAC;IACzC,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AA4CD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,YAAY,CAiF7E"}
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
- const t = useT();
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
- ? t(SEARCH_I18N_KEYS.resultsCountApproximate, { count: page.count })
18
- : t(SEARCH_I18N_KEYS.resultsCountExact, { count: page.count }) }));
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.renderCard;
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(Flex, { vertical: true, gap: 12, "data-testid": "search-results", children: items.map((item) => (_jsx("div", { children: renderCard !== undefined ? (renderCard(item)) : (_jsx(SearchResultCard, { item: item })) }, item.key))) })),
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":"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"}
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,EACJ,UAAU,GACX,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAc7C;;;;;;;GAOG;AACH,MAAM,YAAY,GAAkB;IAClC,OAAO,EAAE,MAAM;IACf,mBAAmB,EAAE,uCAAuC;IAC5D,GAAG,EAAE,EAAE;IACP,UAAU,EAAE,SAAS;CACtB,CAAC;AA0BF,SAAS,KAAK,CAAC,KAAgC;IAC7C,uEAAuE;IACvE,4EAA4E;IAC5E,uEAAuE;IACvE,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;IAC5B,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/B,OAAO,CACL,KAAC,UAAU,CAAC,IAAI,IAAC,IAAI,EAAC,WAAW,iBAAa,cAAc,YACzD,IAAI,CAAC,eAAe;YACnB,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,uBAAuB,EAAE;gBAChD,KAAK,EAAE,IAAI,CAAC,KAAK;aAClB,CAAC;YACJ,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,iBAAiB,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,GACtD,CACnB,CAAC;AACJ,CAAC;AAED,SAAS,KAAK,CAAC,KAAgC;IAC7C,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;IACjB,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC;IACjD,OAAO,CACL,MAAC,IAAI,IAAC,GAAG,EAAE,CAAC,EAAE,OAAO,EAAC,QAAQ,iBAAa,cAAc,aACvD,KAAC,MAAM,IACL,QAAQ,EAAE,CAAC,IAAI,CAAC,SAAS,EACzB,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EACzE,OAAO,EAAE,MAAM,oBACA,MAAM,2BACC,0CAA0C,iBACpD,aAAa,YAExB,CAAC,CAAC,gBAAgB,CAAC,WAAW,CAAC,GACzB,EACT,KAAC,MAAM,IACL,QAAQ,EAAE,CAAC,IAAI,CAAC,SAAS,EACzB,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EACzE,OAAO,EAAE,MAAM,oBACA,MAAM,2BACC,0CAA0C,iBACpD,aAAa,YAExB,CAAC,CAAC,gBAAgB,CAAC,WAAW,CAAC,GACzB,IACJ,CACR,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAA6B;IAC7D,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;IACjB,MAAM,QAAQ,GAAG,oBAAoB,EAAE,CAAC;IACxC,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,GAAG,KAAK,CAAC;IAE5C,OAAO,CACL,KAAC,eAAe,OAAK,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,YACzE,KAAC,aAAa,OAAK,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,YAC/E,CAAC,GAAG,EAAE,EAAE,CAAC,CACR,MAAC,IAAI,IAAC,QAAQ,QAAC,GAAG,EAAE,EAAE,aACpB,MAAC,IAAI,IAAC,OAAO,EAAC,eAAe,EAAC,KAAK,EAAC,QAAQ,EAAC,IAAI,QAAC,GAAG,EAAE,CAAC,aACtD,KAAC,UAAU,CAAC,KAAK,IAAC,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,YAC7C,CAAC,CAAC,gBAAgB,CAAC,YAAY,CAAC,GAChB,EACnB,MAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,EAAC,IAAI,QAAC,GAAG,EAAE,EAAE,aAC/B,KAAC,KAAK,IAAC,GAAG,EAAE,GAAG,GAAI,EAClB,KAAK,CAAC,OAAO,IACT,IACF,EAEP,KAAC,iBAAiB,IAAC,YAAY,EAAE,GAAG,CAAC,YAAY,GAAI,EAEpD,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE;wBACpB,OAAO,EAAE,GAAG,EAAE,CAAC,CACb,KAAC,IAAI,IAAC,OAAO,EAAC,QAAQ,EAAC,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,YAC3C,KAAC,IAAI,mBAAa,gBAAgB,GAAG,GAChC,CACR;wBACD,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;4BAChB,2DAA2D;4BAC3D,uDAAuD;4BACvD,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,sBAAsB,CAAC;4BAC7D,OAAO,CACL,KAAC,UAAU,IACT,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,eAAe,EAC7D,KAAK,EAAE;oCACL,GAAG,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;oCAC/B,OAAO,EAAE,CAAC,CACR,QAAQ;wCACN,CAAC,CAAC,gBAAgB,CAAC,qBAAqB;wCACxC,CAAC,CAAC,gBAAgB,CAAC,iBAAiB,CACvC;iCACF,EACD,MAAM,EACJ,KAAC,MAAM,IACL,IAAI,EAAC,OAAO,EACZ,OAAO,EAAE,GAAG,CAAC,OAAO,oBACL,MAAM,2BACC,yCAAyC,YAE9D,CAAC,CAAC,gBAAgB,CAAC,YAAY,CAAC,GAC1B,GAEX,CACH,CAAC;wBACJ,CAAC;wBACD,KAAK,EAAE,GAAG,EAAE,CAAC,CACX,KAAC,KAAK,mBACQ,cAAc,EAC1B,WAAW,EAAE,CAAC,CAAC,gBAAgB,CAAC,YAAY,CAAC,GAC7C,CACH;wBACD,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAChB,6BAAiB,gBAAgB,YAC9B,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,CAC7B,aAAa,CAAC,KAAK,CAAC,CACrB,CAAC,CAAC,CAAC,CACF,cAAK,KAAK,EAAE,YAAY,iBAAc,qBAAqB,YACxD,KAAK,CAAC,GAAG,CAAC,CAAC,IAAgB,EAAE,EAAE,CAAC,CAC/B,wBACG,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,CAC1B,UAAU,CAAC,IAAI,CAAC,CACjB,CAAC,CAAC,CAAC,CACF,KAAC,gBAAgB,IAAC,IAAI,EAAE,IAAI,GAAI,CACjC,IALO,IAAI,CAAC,GAAG,CAMZ,CACP,CAAC,GACE,CACP,GACG,CACP;qBACF,CAAC,EAEF,KAAC,KAAK,IAAC,GAAG,EAAE,GAAG,GAAI,EAClB,KAAK,CAAC,MAAM,IACR,CACR,GACa,GACA,CACnB,CAAC;AACJ,CAAC"}
@@ -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;AAe1C,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,YAAY,CAyC/D"}
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 = state.sort !== undefined && !known.has(state.sort)
20
- ? [...SEARCH_SORTS, state.sort]
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: state.sort ?? props.appliedSort ?? null, placeholder: t(SEARCH_I18N_KEYS.sortLabel), onChange: (next) => {
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;AAOF,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC/C,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;IACjB,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAE5C,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,KAAK,SAAS,CAAC;IAC1C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;IACpC,MAAM,MAAM,GACV,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;QAChD,CAAC,CAAC,CAAC,GAAG,YAAY,EAAE,KAAK,CAAC,IAAI,CAAC;QAC/B,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,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,WAAW,IAAI,IAAI,EAC9C,WAAW,EAAE,CAAC,CAAC,gBAAgB,CAAC,SAAS,CAAC,EAC1C,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"}
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"}
@@ -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;;;;;;;;;;;;;;;;;;;GAmBG;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,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAErE,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"}
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"}
@@ -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;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,+EAA+E;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAG3D,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"}
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,2 @@
1
+ export declare function useAppliedSort(): string | undefined;
2
+ //# sourceMappingURL=useAppliedSort.d.ts.map
@@ -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"}
@@ -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,cA4FhC,CAAC;AAEF,+DAA+D;AAC/D,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAE7D"}
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": "Unos {count} resultados",
19
- "search.results.count_exact": "{count} resultados",
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",
@@ -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,kCAAkC,EAAE,yBAAyB;IAC7D,4BAA4B,EAAE,oBAAoB;IAClD,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"}
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"}
@@ -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
@@ -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,+DAA+D;;IAE/D,qDAAqD;;;;;;;IAOrD,yDAAyD;;;;;;;;;;;;;;;;;;;;;;IA0BzD,oEAAoE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2C5D,CAAC;AAEX,MAAM,MAAM,aAAa,GACvB,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,OAAO,gBAAgB,CAAC,CAAC;AAE3D;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA4FrD,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAEzD"}
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} results",
115
- "search.results.count_exact": "{count} 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",
@@ -1 +1 @@
1
- {"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/i18n/keys.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/i18n/keys.ts"],"names":[],"mappings":"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"}
@@ -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,cA4FhC,CAAC;AAEF;yDACyD;AACzD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAE7D"}
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"}
package/dist/i18n/ru.js CHANGED
@@ -30,8 +30,16 @@ export const searchI18nBundleRu = {
30
30
  "search.results.load_failed": "Не удалось выполнить поиск.",
31
31
  "search.results.empty": "По этому запросу ничего не нашлось.",
32
32
  "search.results.retry": "Повторить",
33
- "search.results.count_approximate": "Примерно {count} объявлений",
34
- "search.results.count_exact": "{count} объявлений",
33
+ // Four forms, because Russian has four (1 / 2-4 / 5-20 / fractions). One
34
+ // string here is wrong on most pages the storefront serves.
35
+ "search.results.count_approximate.one": "Примерно {count} объявление",
36
+ "search.results.count_approximate.few": "Примерно {count} объявления",
37
+ "search.results.count_approximate.many": "Примерно {count} объявлений",
38
+ "search.results.count_approximate.other": "Примерно {count} объявления",
39
+ "search.results.count_exact.one": "{count} объявление",
40
+ "search.results.count_exact.few": "{count} объявления",
41
+ "search.results.count_exact.many": "{count} объявлений",
42
+ "search.results.count_exact.other": "{count} объявления",
35
43
  "search.results.took_ms": "{ms} мс",
36
44
  "search.results.next": "Следующая страница",
37
45
  "search.results.prev": "Предыдущая страница",
@@ -1 +1 @@
1
- {"version":3,"file":"ru.js","sourceRoot":"","sources":["../../src/i18n/ru.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAmB;IAChD,GAAG,mBAAmB;IAEtB,sBAAsB,EAAE,iCAAiC;IAEzD,sBAAsB,EAAE,YAAY;IACpC,wBAAwB,EAAE,OAAO;IACjC,4BAA4B,EAAE,6BAA6B;IAC3D,sBAAsB,EAAE,qCAAqC;IAC7D,sBAAsB,EAAE,WAAW;IACnC,kCAAkC,EAAE,6BAA6B;IACjE,4BAA4B,EAAE,oBAAoB;IAClD,wBAAwB,EAAE,SAAS;IACnC,qBAAqB,EAAE,oBAAoB;IAC3C,qBAAqB,EAAE,qBAAqB;IAC5C,+BAA+B,EAAE,wBAAwB;IACzD,iCAAiC,EAAE,qBAAqB;IACxD,gCAAgC,EAC9B,uFAAuF;IACzF,yBAAyB,EAAE,cAAc;IACzC,8BAA8B,EAC5B,+GAA+G;IACjH,4BAA4B,EAAE,gBAAgB;IAC9C,yBAAyB,EAAE,cAAc;IACzC,qBAAqB,EAAE,SAAS;IAEhC,mBAAmB,EAAE,YAAY;IACjC,uBAAuB,EAAE,kBAAkB;IAC3C,oBAAoB,EAAE,eAAe;IACrC,uBAAuB,EAAE,iBAAiB;IAC1C,wBAAwB,EAAE,gBAAgB;IAC1C,sBAAsB,EAAE,iBAAiB;IACzC,0BAA0B,EAAE,uBAAuB;IAEnD,qBAAqB,EAAE,SAAS;IAChC,uBAAuB,EAAE,oBAAoB;IAC7C,2BAA2B,EAAE,+BAA+B;IAC5D,qBAAqB,EAAE,gCAAgC;IACvD,qBAAqB,EAAE,UAAU;IACjC,yBAAyB,EAAE,gCAAgC;IAC3D,2BAA2B,EACzB,wFAAwF;IAC1F,uBAAuB,EACrB,uDAAuD;IACzD,2BAA2B,EAAE,cAAc;IAC3C,+BAA+B,EAC7B,6EAA6E;IAC/E,0BAA0B,EAAE,IAAI;IAChC,wBAAwB,EAAE,IAAI;IAC9B,2BAA2B,EAAE,WAAW;IAExC,kBAAkB,EAAE,YAAY;IAChC,sBAAsB,EAAE,mBAAmB;IAC3C,kBAAkB,EAAE,OAAO;IAC3B,gBAAgB,EAAE,sBAAsB;IACxC,mBAAmB,EAAE,sBAAsB;IAE3C,yBAAyB,EAAE,wCAAwC;IACnE,+BAA+B,EAAE,uCAAuC;IACxE,iCAAiC,EAC/B,kDAAkD;IACpD,iCAAiC,EAC/B,kFAAkF;IACpF,kCAAkC,EAChC,wDAAwD;IAE1D,uBAAuB,EAAE,gCAAgC;IACzD,gCAAgC,EAC9B,0EAA0E;IAC5E,iCAAiC,EAC/B,2EAA2E;IAC7E,6BAA6B,EAAE,+CAA+C;IAC9E,oCAAoC,EAAE,oCAAoC;IAC1E,iCAAiC,EAC/B,0EAA0E;IAC5E,wBAAwB,EACtB,4FAA4F;IAC9F,yBAAyB,EACvB,oFAAoF;IAEtF,sBAAsB,EAAE,4BAA4B;IACpD,sBAAsB,EACpB,8EAA8E;IAChF,wBAAwB,EAAE,mCAAmC;IAC7D,4BAA4B,EAAE,8CAA8C;IAC5E,sBAAsB,EAAE,uDAAuD;IAC/E,0BAA0B,EAAE,UAAU;IACtC,uBAAuB,EAAE,KAAK;IAC9B,2BAA2B,EAAE,eAAe;IAC5C,yBAAyB,EAAE,0BAA0B;IACrD,sBAAsB,EAAE,YAAY;IACpC,qBAAqB,EAAE,4BAA4B;CACpD,CAAC;AAEF;yDACyD;AACzD,MAAM,UAAU,oBAAoB,CAAC,MAAkB;IACrD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;AAClD,CAAC"}
1
+ {"version":3,"file":"ru.js","sourceRoot":"","sources":["../../src/i18n/ru.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -62,10 +62,11 @@ export { SearchResults } from "./headless/SearchResults.js";
62
62
  export type { SearchPageInfo, SearchResultsBag } from "./headless/SearchResults.js";
63
63
  export { FacetPanel } from "./headless/FacetPanel.js";
64
64
  export type { FacetPanelBag } from "./headless/FacetPanel.js";
65
+ export { useAppliedSort } from "./headless/useAppliedSort.js";
65
66
  export { RankingDisclosure } from "./headless/RankingDisclosure.js";
66
67
  export type { RankingDisclosureBag } from "./headless/RankingDisclosure.js";
67
68
  export { navEntries } from "./nav/manifest.js";
68
- export { SEARCH_I18N_KEYS, searchI18nBundleEn, registerSearchI18n, } from "./i18n/keys.js";
69
+ export { SEARCH_I18N_KEYS, SEARCH_I18N_PLURAL_KEYS, searchI18nBundleEn, registerSearchI18n, } from "./i18n/keys.js";
69
70
  export type { SearchI18nKey } from "./i18n/keys.js";
70
71
  export { SEARCH_ERRORS, SEARCH_ERROR_CODES, SEARCH_BACKEND_UNAVAILABLE, SEARCH_WINDOW_EXCEEDED, searchErrorBundleEn, explainSearchError, } from "./i18n/errorsMap.js";
71
72
  export type { SearchErrorCode, SearchErrorSpec, Remediation, } from "./i18n/errorsMap.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAGH,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACxE,YAAY,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,YAAY,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EACV,SAAS,EACT,cAAc,EACd,eAAe,EACf,MAAM,EACN,iBAAiB,EACjB,qBAAqB,EACrB,SAAS,EACT,YAAY,EACZ,eAAe,EACf,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,aAAa,EACb,eAAe,GAChB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,SAAS,EACT,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,uBAAuB,EACvB,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEpG,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACvE,YAAY,EACV,qBAAqB,EACrB,UAAU,EACV,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,YAAY,EACV,aAAa,EACb,0BAA0B,GAC3B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAG1E,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACxF,YAAY,EACV,mBAAmB,EACnB,cAAc,EACd,wBAAwB,GACzB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AACpF,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,YAAY,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAG5E,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAG/C,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGpD,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,0BAA0B,EAC1B,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,eAAe,EACf,eAAe,EACf,WAAW,GACZ,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -56,11 +56,12 @@ export { SearchProvider } from "./headless/SearchProvider.js";
56
56
  export { SearchStateProvider, useSearchState } from "./headless/SearchStateProvider.js";
57
57
  export { SearchResults } from "./headless/SearchResults.js";
58
58
  export { FacetPanel } from "./headless/FacetPanel.js";
59
+ export { useAppliedSort } from "./headless/useAppliedSort.js";
59
60
  export { RankingDisclosure } from "./headless/RankingDisclosure.js";
60
61
  // ── nav manifest (the pair's public surface declaration) ─────────────────────
61
62
  export { navEntries } from "./nav/manifest.js";
62
63
  // ── i18n ─────────────────────────────────────────────────────────────────────
63
- export { SEARCH_I18N_KEYS, searchI18nBundleEn, registerSearchI18n, } from "./i18n/keys.js";
64
+ export { SEARCH_I18N_KEYS, SEARCH_I18N_PLURAL_KEYS, searchI18nBundleEn, registerSearchI18n, } from "./i18n/keys.js";
64
65
  // ── errors map (code → status/params/remediation/en; generated) ──────────────
65
66
  export { SEARCH_ERRORS, SEARCH_ERROR_CODES, SEARCH_BACKEND_UNAVAILABLE, SEARCH_WINDOW_EXCEEDED, searchErrorBundleEn, explainSearchError, } from "./i18n/errorsMap.js";
66
67
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,gFAAgF;AAChF,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAGxE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAmB9C,gFAAgF;AAChF,OAAO,EACL,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,SAAS,EACT,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAS7B,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEpG,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAOvE,gFAAgF;AAChF,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAKzD,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGvD,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAE1E,gFAAgF;AAChF,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAMxF,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAGpE,gFAAgF;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,gFAAgF;AAChF,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AAGxB,gFAAgF;AAChF,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,0BAA0B,EAC1B,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,gFAAgF;AAChF,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAGxE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAmB9C,gFAAgF;AAChF,OAAO,EACL,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,SAAS,EACT,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAS7B,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEpG,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAOvE,gFAAgF;AAChF,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAKzD,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGvD,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAE1E,gFAAgF;AAChF,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAMxF,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAGpE,gFAAgF;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,gFAAgF;AAChF,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AAGxB,gFAAgF;AAChF,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,0BAA0B,EAC1B,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,qBAAqB,CAAC"}
package/llms.txt CHANGED
@@ -1,4 +1,4 @@
1
- # @stapel/search-react 0.2.0
1
+ # @stapel/search-react 0.3.0
2
2
 
3
3
  Headless React flow pair for stapel-search (contract >=0.1 <0.2) — business + state, zero visual opinion.
4
4
  Built on @stapel/core: typed client + StapelApiError envelope, auth token refresh,
package/manifest.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$generated": "by scripts/gen-manifest.mjs — do not edit; drift-gated (pnpm gen:manifest:check)",
3
3
  "package": "@stapel/search-react",
4
- "version": "0.2.0",
4
+ "version": "0.3.0",
5
5
  "backend": {
6
6
  "module": "stapel-search",
7
7
  "contract": ">=0.1 <0.2"
@@ -532,7 +532,11 @@
532
532
  "search.results.blocked.at_end",
533
533
  "search.results.blocked.at_start",
534
534
  "search.results.count_approximate",
535
+ "search.results.count_approximate.one",
536
+ "search.results.count_approximate.other",
535
537
  "search.results.count_exact",
538
+ "search.results.count_exact.one",
539
+ "search.results.count_exact.other",
536
540
  "search.results.distance_km",
537
541
  "search.results.empty",
538
542
  "search.results.load_failed",
@@ -570,6 +574,7 @@
570
574
  "SEARCH_ERRORS",
571
575
  "SEARCH_ERROR_CODES",
572
576
  "SEARCH_I18N_KEYS",
577
+ "SEARCH_I18N_PLURAL_KEYS",
573
578
  "SEARCH_PARAM",
574
579
  "SEARCH_SORTS",
575
580
  "SEARCH_WINDOW_EXCEEDED",
@@ -599,6 +604,7 @@
599
604
  "setFilterValues",
600
605
  "setRangeValue",
601
606
  "toggleFilterValue",
607
+ "useAppliedSort",
602
608
  "useRankingDisclosure",
603
609
  "useSearchAnalytics",
604
610
  "useSearchApi",
package/nav-manifest.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "package": "@stapel/search-react",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "entries": [
5
5
  {
6
6
  "id": "search.results",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stapel/search-react",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Headless React pair for stapel-search: a typed query client, TanStack Query hooks, and a URL-first state codec that makes a search shareable by construction (filters, ranges, geo, sort and the keyset cursor all live in the query string). Drill-down facets rendered with their remaining counts and with the server's own honesty flags — approximate, skipped, degraded — never swallowed; keyset pagination with the window refusal named; DSA Art. 26 `promoted` marking carried into every card slot and the P2B Art. 5 ranking disclosure exposed as data. Zero visual opinion in the main entry; an opt-in /default subpath ships the antd skin, and /router binds the codec to react-router's useSearchParams.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -112,7 +112,7 @@
112
112
  "typescript": "^5.8.3",
113
113
  "vitest": "^3.2.4",
114
114
  "@stapel/attributes-react": "^0.2.0",
115
- "@stapel/core": "^0.15.0",
115
+ "@stapel/core": "^0.17.0",
116
116
  "@stapel/showcase": "^0.2.0",
117
117
  "@stapel/tokens": "^0.5.0",
118
118
  "@stapel/tokens-antd": "^0.5.0"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$generated": "by scripts/gen-events.mjs — do not edit; drift-gated (pnpm gen:events:check)",
3
3
  "package": "@stapel/search-react",
4
- "version": "0.2.0",
4
+ "version": "0.3.0",
5
5
  "defined": [],
6
6
  "flows": []
7
7
  }
@@ -15,13 +15,11 @@
15
15
  * optional behaviour in disguise — every one has a working default.
16
16
  */
17
17
  import type { ReactElement, ReactNode } from "react";
18
- import { Col, Flex, Row, Typography } from "antd";
19
- import { useT } from "@stapel/core";
18
+ import { Col, Flex, Row } from "antd";
20
19
  import type { FeatureDef } from "@stapel/attributes-react";
21
20
  import { SearchStateProvider } from "../headless/SearchStateProvider.js";
22
21
  import type { SearchParamsAdapter } from "../headless/SearchStateProvider.js";
23
22
  import type { ParseSearchStateOptions } from "../state/urlState.js";
24
- import { SEARCH_I18N_KEYS } from "../i18n/keys.js";
25
23
  import { FacetPanelPane } from "./FacetPanelPane.js";
26
24
  import { SearchResultsPane } from "./SearchResultsPane.js";
27
25
  import { SortSelect } from "./SortSelect.js";
@@ -42,7 +40,6 @@ export interface SearchPageProps extends ThemeModeProp, ParseSearchStateOptions
42
40
  }
43
41
 
44
42
  export function SearchPage(props: SearchPageProps): ReactElement {
45
- const t = useT();
46
43
  const {
47
44
  adapter,
48
45
  renderCard,
@@ -66,18 +63,16 @@ export function SearchPage(props: SearchPageProps): ReactElement {
66
63
  />
67
64
  </Col>
68
65
  <Col xs={24} md={17}>
69
- <Flex vertical gap={12}>
70
- <Flex justify="space-between" align="center" wrap gap={8}>
71
- <Typography.Text type="secondary">
72
- {t(SEARCH_I18N_KEYS.resultsTitle)}
73
- </Typography.Text>
74
- <SortSelect />
75
- </Flex>
76
- <SearchResultsPane
77
- {...(renderCard !== undefined ? { renderCard } : {})}
78
- {...(footer !== undefined ? { footer } : {})}
79
- />
80
- </Flex>
66
+ {/* ONE heading and ONE sort control. The page used to caption
67
+ the toolbar "Results" and then mount a pane whose own heading
68
+ says "Results" again — the live /s page printed both, one
69
+ above the other. The pane owns the heading row; the page puts
70
+ the sort control INTO it. */}
71
+ <SearchResultsPane
72
+ toolbar={<SortSelect />}
73
+ {...(renderCard !== undefined ? { renderCard } : {})}
74
+ {...(footer !== undefined ? { footer } : {})}
75
+ />
81
76
  </Col>
82
77
  </Row>
83
78
  </Flex>
@@ -13,7 +13,7 @@
13
13
  * with an empty body, which is precisely how it would otherwise render as an
14
14
  * empty page.
15
15
  */
16
- import type { ReactElement, ReactNode } from "react";
16
+ import type { CSSProperties, ReactElement, ReactNode } from "react";
17
17
  import { Button, Empty, Flex, Spin, Typography } from "antd";
18
18
  import {
19
19
  errorCode,
@@ -21,6 +21,7 @@ import {
21
21
  toFlowError,
22
22
  useDescribeFlowError,
23
23
  useT,
24
+ useTPlural,
24
25
  } from "@stapel/core";
25
26
  import type { SearchItem } from "../api/types.js";
26
27
  import { SearchResults } from "../headless/SearchResults.js";
@@ -34,6 +35,32 @@ import type { SearchCardRenderer } from "./SearchResultCard.js";
34
35
  import { SearchSkinTheme } from "./theme.js";
35
36
  import type { ThemeModeProp } from "./types.js";
36
37
 
38
+ /**
39
+ * The whole result LAYOUT, for a container that wants its own — a map beside
40
+ * the list, a masonry wall, a table. It receives the loaded rows; the pane
41
+ * still owns the four load arms around it, so "nothing found" and "we could
42
+ * not run this search" stay the pane's sentences rather than the slot's
43
+ * problem.
44
+ */
45
+ export type SearchResultsRenderer = (
46
+ items: readonly SearchItem[]
47
+ ) => ReactNode;
48
+
49
+ /**
50
+ * The results grid. `auto-fill` + `minmax(280px, 1fr)`: as many columns as fit,
51
+ * each at least a readable card and never wider than its share — a catalogue
52
+ * on a 1400px desktop is four columns, not four full-bleed rows, and the same
53
+ * declaration collapses to one column on a phone with no breakpoint to
54
+ * maintain. 280px is the width below which the default card's title, price and
55
+ * location stop fitting on their own lines.
56
+ */
57
+ const RESULTS_GRID: CSSProperties = {
58
+ display: "grid",
59
+ gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))",
60
+ gap: 12,
61
+ alignItems: "stretch",
62
+ };
63
+
37
64
  export interface SearchResultsPaneProps extends ThemeModeProp {
38
65
  /**
39
66
  * The card slot (spec §6.2 item 1). A storefront passes
@@ -42,20 +69,36 @@ export interface SearchResultsPaneProps extends ThemeModeProp {
42
69
  * default honours it.
43
70
  */
44
71
  readonly renderCard?: SearchCardRenderer;
72
+ /**
73
+ * The layout slot: replaces the grid entirely, `renderCard` and all. Use it
74
+ * when the container's arrangement is not "cards in a grid".
75
+ */
76
+ readonly renderResults?: SearchResultsRenderer;
77
+ /**
78
+ * Rendered beside the count in the heading row — the sort control, a view
79
+ * switch. The pane owns the heading, so a screen that composes it hands its
80
+ * toolbar in here instead of printing a second caption above the pane.
81
+ */
82
+ readonly toolbar?: ReactNode;
45
83
  /** Rendered under the pager — where the container puts the ranking link. */
46
84
  readonly footer?: ReactNode;
47
85
  readonly enabled?: boolean;
48
86
  }
49
87
 
50
88
  function Count(props: { bag: SearchResultsBag }): ReactElement | null {
51
- const t = useT();
89
+ // A COUNTED sentence: `tPlural` asks Intl.PluralRules for the locale's
90
+ // category, so Russian gets three different endings for 1, 3 and 17 instead
91
+ // of the single one that was right for 5-20 and wrong everywhere else.
92
+ const tPlural = useTPlural();
52
93
  const page = props.bag.page;
53
94
  if (page === null) return null;
54
95
  return (
55
96
  <Typography.Text type="secondary" data-testid="search-count">
56
97
  {page.countIsEstimate
57
- ? t(SEARCH_I18N_KEYS.resultsCountApproximate, { count: page.count })
58
- : t(SEARCH_I18N_KEYS.resultsCountExact, { count: page.count })}
98
+ ? tPlural(SEARCH_I18N_KEYS.resultsCountApproximate, {
99
+ count: page.count,
100
+ })
101
+ : tPlural(SEARCH_I18N_KEYS.resultsCountExact, { count: page.count })}
59
102
  </Typography.Text>
60
103
  );
61
104
  }
@@ -92,7 +135,7 @@ function Pager(props: { bag: SearchResultsBag }): ReactElement {
92
135
  export function SearchResultsPane(props: SearchResultsPaneProps): ReactElement {
93
136
  const t = useT();
94
137
  const describe = useDescribeFlowError();
95
- const renderCard = props.renderCard;
138
+ const { renderCard, renderResults } = props;
96
139
 
97
140
  return (
98
141
  <SearchSkinTheme {...(props.mode !== undefined ? { mode: props.mode } : {})}>
@@ -103,7 +146,10 @@ export function SearchResultsPane(props: SearchResultsPaneProps): ReactElement {
103
146
  <Typography.Title level={4} style={{ margin: 0 }}>
104
147
  {t(SEARCH_I18N_KEYS.resultsTitle)}
105
148
  </Typography.Title>
106
- <Count bag={bag} />
149
+ <Flex align="center" wrap gap={12}>
150
+ <Count bag={bag} />
151
+ {props.toolbar}
152
+ </Flex>
107
153
  </Flex>
108
154
 
109
155
  <DegradationNotice degradations={bag.degradations} />
@@ -149,17 +195,23 @@ export function SearchResultsPane(props: SearchResultsPaneProps): ReactElement {
149
195
  />
150
196
  ),
151
197
  ready: (items) => (
152
- <Flex vertical gap={12} data-testid="search-results">
153
- {items.map((item: SearchItem) => (
154
- <div key={item.key}>
155
- {renderCard !== undefined ? (
156
- renderCard(item)
157
- ) : (
158
- <SearchResultCard item={item} />
159
- )}
198
+ <div data-testid="search-results">
199
+ {renderResults !== undefined ? (
200
+ renderResults(items)
201
+ ) : (
202
+ <div style={RESULTS_GRID} data-testid="search-results-grid">
203
+ {items.map((item: SearchItem) => (
204
+ <div key={item.key}>
205
+ {renderCard !== undefined ? (
206
+ renderCard(item)
207
+ ) : (
208
+ <SearchResultCard item={item} />
209
+ )}
210
+ </div>
211
+ ))}
160
212
  </div>
161
- ))}
162
- </Flex>
213
+ )}
214
+ </div>
163
215
  ),
164
216
  })}
165
217
 
@@ -17,6 +17,7 @@ import type { ReactElement } from "react";
17
17
  import { Flex, Select, Typography } from "antd";
18
18
  import { useT } from "@stapel/core";
19
19
  import { SEARCH_SORTS } from "../api/types.js";
20
+ import { useAppliedSort } from "../headless/useAppliedSort.js";
20
21
  import { useSearchState } from "../headless/SearchStateProvider.js";
21
22
  import { SEARCH_I18N_KEYS } from "../i18n/keys.js";
22
23
 
@@ -29,19 +30,28 @@ const SORT_LABEL_KEY: Readonly<Record<string, string>> = {
29
30
  };
30
31
 
31
32
  export interface SortSelectProps {
32
- /** The sort the SERVER applied, shown when the URL names none. */
33
+ /** The sort the SERVER applied, shown when the URL names none. Omitted, it
34
+ * is read from the page already in cache — see {@link useAppliedSort}. */
33
35
  readonly appliedSort?: string | undefined;
34
36
  }
35
37
 
36
38
  export function SortSelect(props: SortSelectProps): ReactElement {
37
39
  const t = useT();
38
40
  const { state, setSort } = useSearchState();
41
+ // What the control SAYS must be what the results are ordered by. With no
42
+ // `sort` in the URL the select used to fall through to its placeholder and
43
+ // show nothing at all, while the server had already sorted the page and
44
+ // said so in the envelope.
45
+ const applied = useAppliedSort();
39
46
 
47
+ // What the page is ACTUALLY ordered by: the URL's sort, else the one the
48
+ // container states, else the one the server reported for the page in cache.
49
+ const active = state.sort ?? props.appliedSort ?? applied;
40
50
  const hasCentre = state.geo !== undefined;
41
51
  const known = new Set(SEARCH_SORTS);
42
52
  const values =
43
- state.sort !== undefined && !known.has(state.sort)
44
- ? [...SEARCH_SORTS, state.sort]
53
+ active !== undefined && !known.has(active)
54
+ ? [...SEARCH_SORTS, active]
45
55
  : SEARCH_SORTS;
46
56
 
47
57
  return (
@@ -52,8 +62,7 @@ export function SortSelect(props: SortSelectProps): ReactElement {
52
62
  <Select<string>
53
63
  data-testid="search-sort"
54
64
  style={{ minWidth: 180 }}
55
- value={state.sort ?? props.appliedSort ?? null}
56
- placeholder={t(SEARCH_I18N_KEYS.sortLabel)}
65
+ value={active ?? null}
57
66
  onChange={(next) => {
58
67
  setSort(next);
59
68
  }}
@@ -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).
@@ -24,7 +26,10 @@ export { SearchPage } from "./SearchPage.js";
24
26
  export type { SearchPageProps } from "./SearchPage.js";
25
27
 
26
28
  export { SearchResultsPane } from "./SearchResultsPane.js";
27
- export type { SearchResultsPaneProps } from "./SearchResultsPane.js";
29
+ export type {
30
+ SearchResultsPaneProps,
31
+ SearchResultsRenderer,
32
+ } from "./SearchResultsPane.js";
28
33
 
29
34
  export { FacetPanelPane } from "./FacetPanelPane.js";
30
35
  export type { FacetPanelPaneProps } from "./FacetPanelPane.js";
@@ -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
+
21
+ export function useAppliedSort(): string | undefined {
22
+ const { state } = useSearchState();
23
+ const query = useSearchQuery(state, { enabled: false });
24
+ return query.data?.sort;
25
+ }
package/src/i18n/es.ts CHANGED
@@ -20,8 +20,10 @@ export const searchI18nBundleEs: I18nDictionary = {
20
20
  "search.results.load_failed": "No pudimos ejecutar esta búsqueda.",
21
21
  "search.results.empty": "No hay nada que coincida con esta búsqueda.",
22
22
  "search.results.retry": "Reintentar",
23
- "search.results.count_approximate": "Unos {count} resultados",
24
- "search.results.count_exact": "{count} resultados",
23
+ "search.results.count_approximate.one": "Aproximadamente {count} resultado",
24
+ "search.results.count_approximate.other": "Unos {count} resultados",
25
+ "search.results.count_exact.one": "{count} resultado",
26
+ "search.results.count_exact.other": "{count} resultados",
25
27
  "search.results.took_ms": "{ms} ms",
26
28
  "search.results.next": "Página siguiente",
27
29
  "search.results.prev": "Página anterior",
package/src/i18n/keys.ts CHANGED
@@ -28,9 +28,10 @@ export const SEARCH_I18N_KEYS = {
28
28
  resultsLoadFailed: "search.results.load_failed",
29
29
  resultsEmpty: "search.results.empty",
30
30
  resultsRetry: "search.results.retry",
31
- /** "About N results" — the sentence for an ESTIMATED count. */
31
+ /** "About N results" — the sentence for an ESTIMATED count. A PLURAL
32
+ * FAMILY: render with `tPlural`, never `t` (see SEARCH_I18N_PLURAL_KEYS). */
32
33
  resultsCountApproximate: "search.results.count_approximate",
33
- /** "N results" — only when `exact_total` is true. */
34
+ /** "N results" — only when `exact_total` is true. A PLURAL FAMILY. */
34
35
  resultsCountExact: "search.results.count_exact",
35
36
  resultsTookMs: "search.results.took_ms",
36
37
  resultsNext: "search.results.next",
@@ -111,6 +112,26 @@ export const SEARCH_I18N_KEYS = {
111
112
  export type SearchI18nKey =
112
113
  (typeof SEARCH_I18N_KEYS)[keyof typeof SEARCH_I18N_KEYS];
113
114
 
115
+ /**
116
+ * The keys above that are PLURAL FAMILIES rather than single messages.
117
+ *
118
+ * A family is catalogued as one flat key per CLDR category
119
+ * (`<family>.one`, `…few`, `…many`, `…other`) and rendered with core's
120
+ * `tPlural(family, { count })`, which asks `Intl.PluralRules` for the current
121
+ * locale's category. Which categories a bundle carries is a fact about the
122
+ * language — `en` needs two, `ru` needs four — so the pair's parity test asks
123
+ * `Intl.PluralRules` which forms each locale can select and demands exactly
124
+ * those, rather than checking a list somebody typed.
125
+ *
126
+ * The live defect this closes: the Russian estimate sentence was ONE string
127
+ * doing the work of four, correct only for 5-20 and wrong for every 1, 2, 3
128
+ * and 4 a result page actually shows.
129
+ */
130
+ export const SEARCH_I18N_PLURAL_KEYS: readonly SearchI18nKey[] = [
131
+ SEARCH_I18N_KEYS.resultsCountApproximate,
132
+ SEARCH_I18N_KEYS.resultsCountExact,
133
+ ];
134
+
114
135
  /**
115
136
  * English fallback bundle for search-react UI keys + backend error codes.
116
137
  * The generated backend texts are spread FIRST so coverage of the error
@@ -126,8 +147,10 @@ export const searchI18nBundleEn: Record<string, string> = {
126
147
  "search.results.load_failed": "We could not run this search",
127
148
  "search.results.empty": "Nothing matches this search",
128
149
  "search.results.retry": "Try again",
129
- "search.results.count_approximate": "About {count} results",
130
- "search.results.count_exact": "{count} results",
150
+ "search.results.count_approximate.one": "About {count} result",
151
+ "search.results.count_approximate.other": "About {count} results",
152
+ "search.results.count_exact.one": "{count} result",
153
+ "search.results.count_exact.other": "{count} results",
131
154
  "search.results.took_ms": "{ms} ms",
132
155
  "search.results.next": "Next page",
133
156
  "search.results.prev": "Previous page",
package/src/i18n/ru.ts CHANGED
@@ -35,8 +35,16 @@ export const searchI18nBundleRu: I18nDictionary = {
35
35
  "search.results.load_failed": "Не удалось выполнить поиск.",
36
36
  "search.results.empty": "По этому запросу ничего не нашлось.",
37
37
  "search.results.retry": "Повторить",
38
- "search.results.count_approximate": "Примерно {count} объявлений",
39
- "search.results.count_exact": "{count} объявлений",
38
+ // Four forms, because Russian has four (1 / 2-4 / 5-20 / fractions). One
39
+ // string here is wrong on most pages the storefront serves.
40
+ "search.results.count_approximate.one": "Примерно {count} объявление",
41
+ "search.results.count_approximate.few": "Примерно {count} объявления",
42
+ "search.results.count_approximate.many": "Примерно {count} объявлений",
43
+ "search.results.count_approximate.other": "Примерно {count} объявления",
44
+ "search.results.count_exact.one": "{count} объявление",
45
+ "search.results.count_exact.few": "{count} объявления",
46
+ "search.results.count_exact.many": "{count} объявлений",
47
+ "search.results.count_exact.other": "{count} объявления",
40
48
  "search.results.took_ms": "{ms} мс",
41
49
  "search.results.next": "Следующая страница",
42
50
  "search.results.prev": "Предыдущая страница",
package/src/index.ts CHANGED
@@ -124,6 +124,7 @@ export { SearchResults } from "./headless/SearchResults.js";
124
124
  export type { SearchPageInfo, SearchResultsBag } from "./headless/SearchResults.js";
125
125
  export { FacetPanel } from "./headless/FacetPanel.js";
126
126
  export type { FacetPanelBag } from "./headless/FacetPanel.js";
127
+ export { useAppliedSort } from "./headless/useAppliedSort.js";
127
128
  export { RankingDisclosure } from "./headless/RankingDisclosure.js";
128
129
  export type { RankingDisclosureBag } from "./headless/RankingDisclosure.js";
129
130
 
@@ -133,6 +134,7 @@ export { navEntries } from "./nav/manifest.js";
133
134
  // ── i18n ─────────────────────────────────────────────────────────────────────
134
135
  export {
135
136
  SEARCH_I18N_KEYS,
137
+ SEARCH_I18N_PLURAL_KEYS,
136
138
  searchI18nBundleEn,
137
139
  registerSearchI18n,
138
140
  } from "./i18n/keys.js";