@stapel/search-react 0.10.0 → 0.12.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 (130) hide show
  1. package/CHANGELOG.md +160 -0
  2. package/MODULE.md +111 -0
  3. package/README.md +42 -0
  4. package/dist/api/generated/schema.d.ts +76 -6
  5. package/dist/api/generated/schema.d.ts.map +1 -1
  6. package/dist/api/searchApi.d.ts +13 -6
  7. package/dist/api/searchApi.d.ts.map +1 -1
  8. package/dist/api/searchApi.js.map +1 -1
  9. package/dist/api/types.d.ts +107 -1
  10. package/dist/api/types.d.ts.map +1 -1
  11. package/dist/api/types.js +29 -0
  12. package/dist/api/types.js.map +1 -1
  13. package/dist/default/DegradationNotice.d.ts +22 -13
  14. package/dist/default/DegradationNotice.d.ts.map +1 -1
  15. package/dist/default/DegradationNotice.js +7 -8
  16. package/dist/default/DegradationNotice.js.map +1 -1
  17. package/dist/default/FacetPanelPane.d.ts +13 -2
  18. package/dist/default/FacetPanelPane.d.ts.map +1 -1
  19. package/dist/default/FacetPanelPane.js +29 -16
  20. package/dist/default/FacetPanelPane.js.map +1 -1
  21. package/dist/default/FilterChips.d.ts +88 -3
  22. package/dist/default/FilterChips.d.ts.map +1 -1
  23. package/dist/default/FilterChips.js +166 -13
  24. package/dist/default/FilterChips.js.map +1 -1
  25. package/dist/default/LocationSummaryLine.d.ts.map +1 -1
  26. package/dist/default/LocationSummaryLine.js +1 -1
  27. package/dist/default/LocationSummaryLine.js.map +1 -1
  28. package/dist/default/RangeFilterRow.d.ts.map +1 -1
  29. package/dist/default/RangeFilterRow.js +49 -5
  30. package/dist/default/RangeFilterRow.js.map +1 -1
  31. package/dist/default/SearchBox.d.ts.map +1 -1
  32. package/dist/default/SearchBox.js +74 -4
  33. package/dist/default/SearchBox.js.map +1 -1
  34. package/dist/default/SearchPage.d.ts +29 -1
  35. package/dist/default/SearchPage.d.ts.map +1 -1
  36. package/dist/default/SearchPage.js +25 -10
  37. package/dist/default/SearchPage.js.map +1 -1
  38. package/dist/default/SearchResultsPane.d.ts +22 -0
  39. package/dist/default/SearchResultsPane.d.ts.map +1 -1
  40. package/dist/default/SearchResultsPane.js +2 -2
  41. package/dist/default/SearchResultsPane.js.map +1 -1
  42. package/dist/default/SortSelect.d.ts +23 -0
  43. package/dist/default/SortSelect.d.ts.map +1 -1
  44. package/dist/default/SortSelect.js +29 -9
  45. package/dist/default/SortSelect.js.map +1 -1
  46. package/dist/default/index.d.ts +2 -2
  47. package/dist/default/index.d.ts.map +1 -1
  48. package/dist/default/index.js +1 -1
  49. package/dist/default/index.js.map +1 -1
  50. package/dist/headless/FacetPanel.d.ts +26 -0
  51. package/dist/headless/FacetPanel.d.ts.map +1 -1
  52. package/dist/headless/FacetPanel.js +16 -1
  53. package/dist/headless/FacetPanel.js.map +1 -1
  54. package/dist/headless/useFacetLabels.d.ts +39 -0
  55. package/dist/headless/useFacetLabels.d.ts.map +1 -0
  56. package/dist/headless/useFacetLabels.js +129 -0
  57. package/dist/headless/useFacetLabels.js.map +1 -0
  58. package/dist/headless/useSearchBox.d.ts +71 -0
  59. package/dist/headless/useSearchBox.d.ts.map +1 -1
  60. package/dist/headless/useSearchBox.js +67 -2
  61. package/dist/headless/useSearchBox.js.map +1 -1
  62. package/dist/i18n/es.d.ts.map +1 -1
  63. package/dist/i18n/es.js +8 -0
  64. package/dist/i18n/es.js.map +1 -1
  65. package/dist/i18n/keys.d.ts +48 -0
  66. package/dist/i18n/keys.d.ts.map +1 -1
  67. package/dist/i18n/keys.js +58 -0
  68. package/dist/i18n/keys.js.map +1 -1
  69. package/dist/i18n/ru.d.ts.map +1 -1
  70. package/dist/i18n/ru.js +10 -0
  71. package/dist/i18n/ru.js.map +1 -1
  72. package/dist/index.d.ts +9 -7
  73. package/dist/index.d.ts.map +1 -1
  74. package/dist/index.js +6 -5
  75. package/dist/index.js.map +1 -1
  76. package/dist/model/queries.d.ts +6 -5
  77. package/dist/model/queries.d.ts.map +1 -1
  78. package/dist/model/queries.js +4 -3
  79. package/dist/model/queries.js.map +1 -1
  80. package/dist/model/queryKeys.d.ts +12 -0
  81. package/dist/model/queryKeys.d.ts.map +1 -1
  82. package/dist/model/queryKeys.js +7 -0
  83. package/dist/model/queryKeys.js.map +1 -1
  84. package/dist/nav/manifest.d.ts +21 -0
  85. package/dist/nav/manifest.d.ts.map +1 -1
  86. package/dist/nav/manifest.js +3 -2
  87. package/dist/nav/manifest.js.map +1 -1
  88. package/dist/state/degradations.d.ts +32 -0
  89. package/dist/state/degradations.d.ts.map +1 -1
  90. package/dist/state/degradations.js +33 -0
  91. package/dist/state/degradations.js.map +1 -1
  92. package/dist/state/facets.d.ts +64 -0
  93. package/dist/state/facets.d.ts.map +1 -1
  94. package/dist/state/facets.js +134 -9
  95. package/dist/state/facets.js.map +1 -1
  96. package/dist/state/ranges.d.ts +45 -3
  97. package/dist/state/ranges.d.ts.map +1 -1
  98. package/dist/state/ranges.js +55 -14
  99. package/dist/state/ranges.js.map +1 -1
  100. package/llms.txt +2 -2
  101. package/manifest.json +27 -2
  102. package/nav-manifest.json +4 -3
  103. package/package.json +10 -10
  104. package/src/analytics/generated/events.json +1 -1
  105. package/src/api/generated/schema.ts +76 -6
  106. package/src/api/searchApi.ts +13 -6
  107. package/src/api/types.ts +115 -1
  108. package/src/default/DegradationNotice.tsx +30 -20
  109. package/src/default/FacetPanelPane.tsx +55 -25
  110. package/src/default/FilterChips.tsx +290 -38
  111. package/src/default/LocationSummaryLine.tsx +6 -1
  112. package/src/default/RangeFilterRow.tsx +61 -3
  113. package/src/default/SearchBox.tsx +134 -6
  114. package/src/default/SearchPage.tsx +79 -5
  115. package/src/default/SearchResultsPane.tsx +48 -11
  116. package/src/default/SortSelect.tsx +70 -9
  117. package/src/default/index.ts +10 -2
  118. package/src/headless/FacetPanel.tsx +44 -1
  119. package/src/headless/useFacetLabels.ts +172 -0
  120. package/src/headless/useSearchBox.ts +132 -5
  121. package/src/i18n/es.ts +9 -0
  122. package/src/i18n/keys.ts +60 -0
  123. package/src/i18n/ru.ts +11 -0
  124. package/src/index.ts +28 -4
  125. package/src/model/queries.ts +6 -5
  126. package/src/model/queryKeys.ts +23 -0
  127. package/src/nav/manifest.ts +24 -2
  128. package/src/state/degradations.ts +56 -0
  129. package/src/state/facets.ts +181 -9
  130. package/src/state/ranges.ts +85 -15
@@ -0,0 +1,129 @@
1
+ /**
2
+ * The HOST LABEL SEAM — the third source of a facet option's caption, and the
3
+ * only one that can reach a vocabulary.
4
+ *
5
+ * ── The defect ────────────────────────────────────────────────────────────
6
+ *
7
+ * A live classified deployment's category schema types `vendor`, `model`,
8
+ * `memory_size` and `color_ref_select` as `ref_select`: their config carries
9
+ * no `options` table at all, only a POINTER —
10
+ * `{"optionsRef": {"level": "Vendor", "vocabulary": "avito-phone-catalog"}}`.
11
+ * The words live in the vocabulary the pointer names, which is a different
12
+ * service with a different client. So the two label sources this pair already
13
+ * has both come up empty: the answer's `facet_labels` because the deployed
14
+ * server predates stapel-search 0.4.0 and sends no such key, and the schema
15
+ * because a pointer is not a table. The chips printed `apple`, `128-gb`,
16
+ * `chernyy` — storage slugs, at buyers.
17
+ *
18
+ * This pair must not grow a vocabulary client to fix that: it would tie every
19
+ * storefront's search to a service it may not run, and the host ALREADY has
20
+ * that client (`@stapel/attributes-react`'s `VocabularyClientProvider` is
21
+ * mounted for the composer). So the fetch is the host's and the discipline is
22
+ * this module's — the same division as `renderGeoFilter` and
23
+ * `renderCategoryFilter`, one seam lower because what crosses it is data
24
+ * rather than a control.
25
+ *
26
+ * ── Precedence, stated once ───────────────────────────────────────────────
27
+ *
28
+ * 1. the answer's `facet_labels` — the server saw the write-time snapshot;
29
+ * 2. the feature def's inline `options` table — for the plain `select`
30
+ * family, which carries its words with it;
31
+ * 3. this resolver;
32
+ * 4. the raw value.
33
+ *
34
+ * `buildFacetGroups` has already applied 1 and 2 by the time this hook runs,
35
+ * and it leaves an option it could not name with `label === value` — which is
36
+ * what makes "did anyone name this?" answerable without a second lookup. Only
37
+ * those values are asked about, so the host is never called for a value the
38
+ * server or the schema already captioned, and a resolver that returns nothing
39
+ * for a value leaves the raw value on screen. A chip that silently dropped an
40
+ * option would be worse than one showing a slug: the option is real, it has a
41
+ * count, and it is the only way to reach those documents.
42
+ *
43
+ * ── The fetch discipline ──────────────────────────────────────────────────
44
+ *
45
+ * TanStack Query, exactly like the pair's other three reads, and for the four
46
+ * reasons that made it right there:
47
+ *
48
+ * - **batched per group.** One call per facet slug carrying every unresolved
49
+ * value of it, not one call per chip.
50
+ * - **cached.** `staleTime: Infinity` — a vocabulary term's caption changes
51
+ * when somebody edits the catalogue, not between two clicks on a filter.
52
+ * - **deduplicated.** The chip row, the filter panel and the page's layout
53
+ * probe each call `useFacetPanel`, so three components ask for the same
54
+ * group's captions in one render pass; one query key means one request.
55
+ * - **aborted on supersession.** The `signal` is the query's own, so a
56
+ * resolver that honours it stops a request whose answer nobody will read.
57
+ */
58
+ import { useQueries } from "@tanstack/react-query";
59
+ import { mapLoad } from "@stapel/core";
60
+ import { searchQueryKeys } from "../model/queryKeys.js";
61
+ /** One frozen empty list, so a render with no unresolved values is stable. */
62
+ const NO_REQUESTS = [];
63
+ /** The values of one group nobody has named — see the precedence note above. */
64
+ function unresolvedValues(group) {
65
+ return group.options
66
+ .filter((option) => option.label === option.value)
67
+ .map((option) => option.value)
68
+ .sort((a, b) => a.localeCompare(b));
69
+ }
70
+ function isCaptionMap(value) {
71
+ return typeof value === "object" && value !== null && !Array.isArray(value);
72
+ }
73
+ /**
74
+ * Fill in what the server and the schema could not name, through the host.
75
+ *
76
+ * Returns the groups UNCHANGED — same object identity — when there is no
77
+ * resolver or nothing came back, so a page with the seam unwired pays neither
78
+ * a request nor a re-render.
79
+ */
80
+ export function useHostFacetLabels(groups, resolve, locale) {
81
+ const requests = resolve === undefined || groups.status !== "ready"
82
+ ? NO_REQUESTS
83
+ : groups.data
84
+ .map((group) => ({
85
+ slug: group.slug,
86
+ feature: group.feature,
87
+ values: unresolvedValues(group),
88
+ }))
89
+ .filter((request) => request.values.length > 0);
90
+ const answers = useQueries({
91
+ queries: requests.map((request) => ({
92
+ queryKey: searchQueryKeys.facetLabels(request.slug, request.values, locale),
93
+ queryFn: async ({ signal }) => resolve === undefined ? {} : await resolve(request, { signal }),
94
+ staleTime: Number.POSITIVE_INFINITY,
95
+ // A vocabulary that answered 500 answers 500 again a millisecond later,
96
+ // and three retries only delay the chip's raw value by three round
97
+ // trips — the same discipline the pair's other reads keep.
98
+ retry: false,
99
+ })),
100
+ });
101
+ const captions = new Map();
102
+ requests.forEach((request, index) => {
103
+ const data = answers[index]?.data;
104
+ if (isCaptionMap(data))
105
+ captions.set(request.slug, data);
106
+ });
107
+ if (captions.size === 0)
108
+ return groups;
109
+ return mapLoad(groups, (list) => list.map((group) => {
110
+ const named = captions.get(group.slug);
111
+ if (named === undefined)
112
+ return group;
113
+ return {
114
+ ...group,
115
+ options: group.options.map((option) => {
116
+ // Precedence again, enforced rather than assumed: an option whose
117
+ // label already differs from its value was named by the server or
118
+ // the schema, and the host does not get to overwrite either.
119
+ if (option.label !== option.value)
120
+ return option;
121
+ const caption = named[option.value];
122
+ return caption === undefined || caption.length === 0
123
+ ? option
124
+ : { ...option, label: caption };
125
+ }),
126
+ };
127
+ }));
128
+ }
129
+ //# sourceMappingURL=useFacetLabels.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFacetLabels.js","sourceRoot":"","sources":["../../src/headless/useFacetLabels.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAiCxD,8EAA8E;AAC9E,MAAM,WAAW,GAAiC,EAAE,CAAC;AAErD,gFAAgF;AAChF,SAAS,gBAAgB,CAAC,KAAiB;IACzC,OAAO,KAAK,CAAC,OAAO;SACjB,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,CAAC;SACjD,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC;SAC7B,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;AACxC,CAAC;AAED,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAAwC,EACxC,OAAuC,EACvC,MAA0B;IAE1B,MAAM,QAAQ,GACZ,OAAO,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,OAAO;QAChD,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,MAAM,CAAC,IAAI;aACR,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACf,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,MAAM,EAAE,gBAAgB,CAAC,KAAK,CAAC;SAChC,CAAC,CAAC;aACF,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAExD,MAAM,OAAO,GAAG,UAAU,CAAC;QACzB,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAClC,QAAQ,EAAE,eAAe,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC;YAC3E,OAAO,EAAE,KAAK,EAAE,EAAE,MAAM,EAA2B,EAAoB,EAAE,CACvE,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC;YACjE,SAAS,EAAE,MAAM,CAAC,iBAAiB;YACnC,wEAAwE;YACxE,mEAAmE;YACnE,2DAA2D;YAC3D,KAAK,EAAE,KAAK;SACb,CAAC,CAAC;KACJ,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA4C,CAAC;IACrE,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;QAClC,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC;QAClC,IAAI,YAAY,CAAC,IAAI,CAAC;YAAE,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IACH,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IAEvC,OAAO,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAC9B,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACjB,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QACtC,OAAO;YACL,GAAG,KAAK;YACR,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;gBACpC,kEAAkE;gBAClE,kEAAkE;gBAClE,6DAA6D;gBAC7D,IAAI,MAAM,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK;oBAAE,OAAO,MAAM,CAAC;gBACjD,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACpC,OAAO,OAAO,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;oBAClD,CAAC,CAAC,MAAM;oBACR,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;YACpC,CAAC,CAAC;SACH,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;AACJ,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import type { LoadState } from "@stapel/core";
2
+ import type { SuggestAnswer, SuggestCategory } from "../api/types.js";
2
3
  /** What a query box needs to read and move the search text. */
3
4
  export interface SearchBoxBag {
4
5
  /** What is in the input right now. */
@@ -20,6 +21,42 @@ export interface SearchBoxBag {
20
21
  readonly suggestState: LoadState<readonly string[]>;
21
22
  /** A suggestion request is in flight for a prefix nothing is shown for yet. */
22
23
  readonly suggestLoading: boolean;
24
+ /**
25
+ * CATEGORY destinations for the typed prefix, server-ranked by live listing
26
+ * count — the primary half of the answer (stapel-search 0.7.0).
27
+ *
28
+ * Empty on a server that sends no `categories` key, and empty when the
29
+ * server could not reach a category provider: see
30
+ * {@link SearchBoxBag.categoriesUnavailable} for why a surface must tell
31
+ * those two apart from "nothing matched".
32
+ *
33
+ * A category with a count of `0` is already filtered out — see
34
+ * {@link SearchBoxBag.categoryCountsUnknown}.
35
+ */
36
+ readonly categories: readonly SuggestCategory[];
37
+ /**
38
+ * The server HAS no category provider for this answer
39
+ * (`degraded: ["category_suggestions"]`), so `categories` being empty says
40
+ * nothing about the catalogue.
41
+ *
42
+ * A surface must render no group at all rather than an empty one: a heading
43
+ * over nothing is the box telling a person the catalogue has no section by
44
+ * that name, which is a claim this answer did not make. It is deliberately
45
+ * NOT a banner either — the reader is mid-word, the terms half still
46
+ * answers, and a provider being down is the operator's business, the same
47
+ * ruling `degradationAudience` already applies to an engine shortfall.
48
+ */
49
+ readonly categoriesUnavailable: boolean;
50
+ /**
51
+ * The counts on {@link SearchBoxBag.categories} are not answers
52
+ * (`degraded: ["category_rollup"]`): with no ancestry every stored path is
53
+ * one segment long, so every count would read `0` for a mechanical reason.
54
+ *
55
+ * The rows are still real destinations and are still offered; a surface
56
+ * prints the path and omits the number, because a catalogue of zeros is
57
+ * worse than a list with no counts.
58
+ */
59
+ readonly categoryCountsUnknown: boolean;
23
60
  /** Characters a prefix needs before the index is asked. */
24
61
  readonly minSuggestChars: number;
25
62
  readonly maxLength: number;
@@ -29,6 +66,25 @@ export interface SearchBoxBag {
29
66
  submit(value?: string): void;
30
67
  /** Empty the box AND the search (an empty `q` is a valid browse). */
31
68
  clear(): void;
69
+ /**
70
+ * Follow a category suggestion: narrow the SERP to that section.
71
+ *
72
+ * Two decisions, both load-bearing.
73
+ *
74
+ * The `category` parameter is set to the server's own
75
+ * {@link SuggestCategory.category} string, VERBATIM. The server joins the
76
+ * ancestry itself precisely so a client cannot invent a different join and
77
+ * silently miss, so nothing here rebuilds it from the path or the slug.
78
+ *
79
+ * The typed text is CLEARED in the same write. The row promised a count —
80
+ * "Menswear / Shorts, 1 240 listings" — and that number is the
81
+ * section's, not the section's intersected with a title search for the word
82
+ * that found it. Keeping `q` would land a person on strictly fewer results
83
+ * than the row they tapped had just quoted, which is the row lying about
84
+ * where it goes. One `patch` call, so it is also one history entry: Back
85
+ * returns to the search the person typed.
86
+ */
87
+ chooseCategory(category: SuggestCategory): void;
32
88
  }
33
89
  export interface UseSearchBoxOptions {
34
90
  readonly debounceMs?: number;
@@ -40,5 +96,20 @@ export interface UseSearchBoxOptions {
40
96
  /** How many suggestions to ask for (backend clamps to 25). Default 8. */
41
97
  readonly suggestLimit?: number;
42
98
  }
99
+ /**
100
+ * The destinations worth offering out of one answer.
101
+ *
102
+ * A category with a count of `0` is a section with nothing in it: following it
103
+ * lands the buyer on an empty SERP, which is a dead end dressed as a
104
+ * destination — and the server does return those (it reads the count with a
105
+ * `0` default and ranks them last), so somebody has to drop them.
106
+ *
107
+ * The one exception is `category_rollup`, where EVERY count is `0` because the
108
+ * ancestry never arrived rather than because the sections are empty. Filtering
109
+ * on the count there would delete the whole group for a reason that has
110
+ * nothing to do with what is in the catalogue, so the rows are kept and the
111
+ * numbers are what the surface omits.
112
+ */
113
+ export declare function offerableCategories(answer: SuggestAnswer | undefined): readonly SuggestCategory[];
43
114
  export declare function useSearchBox(options?: UseSearchBoxOptions): SearchBoxBag;
44
115
  //# sourceMappingURL=useSearchBox.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useSearchBox.d.ts","sourceRoot":"","sources":["../../src/headless/useSearchBox.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAU9C,+DAA+D;AAC/D,MAAM,WAAW,YAAY;IAC3B,sCAAsC;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,wEAAwE;IACxE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B;;;;;;;OAOG;IACH,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,gDAAgD;IAChD,QAAQ,CAAC,YAAY,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;IACpD,+EAA+E;IAC/E,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,2DAA2D;IAC3D,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,sEAAsE;IACtE,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,qEAAqE;IACrE,KAAK,IAAI,IAAI,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,kDAAkD;IAClD,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B;kDAC8C;IAC9C,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,yEAAyE;IACzE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAKD,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,YAAY,CAyG5E"}
1
+ {"version":3,"file":"useSearchBox.d.ts","sourceRoot":"","sources":["../../src/headless/useSearchBox.ts"],"names":[],"mappings":"AA8CA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAM9C,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAUtE,+DAA+D;AAC/D,MAAM,WAAW,YAAY;IAC3B,sCAAsC;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,wEAAwE;IACxE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B;;;;;;;OAOG;IACH,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,gDAAgD;IAChD,QAAQ,CAAC,YAAY,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;IACpD,+EAA+E;IAC/E,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,UAAU,EAAE,SAAS,eAAe,EAAE,CAAC;IAChD;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,qBAAqB,EAAE,OAAO,CAAC;IACxC;;;;;;;;OAQG;IACH,QAAQ,CAAC,qBAAqB,EAAE,OAAO,CAAC;IACxC,2DAA2D;IAC3D,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,sEAAsE;IACtE,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,qEAAqE;IACrE,KAAK,IAAI,IAAI,CAAC;IACd;;;;;;;;;;;;;;;;;OAiBG;IACH,cAAc,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;CACjD;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,kDAAkD;IAClD,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B;kDAC8C;IAC9C,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,yEAAyE;IACzE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAaD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,aAAa,GAAG,SAAS,GAChC,SAAS,eAAe,EAAE,CAK5B;AAED,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,GAAG,YAAY,CAwH5E"}
@@ -21,16 +21,65 @@
21
21
  *
22
22
  * The suggestion list is asked for the DEBOUNCED prefix, not the draft — one
23
23
  * request per pause, not per keystroke, on an endpoint the backend throttles.
24
+ *
25
+ * ── The box reaches the CATALOGUE, not only the titles ────────────────────
26
+ *
27
+ * stapel-search 0.7.0 answers `/suggest` with two halves. Until it did, typing
28
+ * a word that names a section of the catalogue answered listing titles and
29
+ * nothing else: on a live classified deployment the search field could not
30
+ * reach a category at all, and the owner's own navigation canon rules out both
31
+ * of the usual workarounds — a picker, and a client-side typeahead over the
32
+ * whole tree.
33
+ *
34
+ * The server's answer is neither, and it carries the one thing a client-side
35
+ * matcher can never have: the number of LIVE listings behind each destination,
36
+ * computed as one aggregate over the index and equal to what `/query` reports
37
+ * for the same category. That number is what tells "Menswear / Shorts" from
38
+ * "Childrenswear / Shorts".
39
+ *
40
+ * Everything here is absent-safe. A server that predates 0.7.0 sends no
41
+ * `categories` key, `suggestCategories` is empty, and the box behaves exactly
42
+ * as it did — which is not a hypothetical: the key appeared mid-session on a
43
+ * stand that was redeployed underneath a running client.
24
44
  */
25
45
  import { useCallback, useEffect, useRef, useState } from "react";
26
46
  import { loadStateFromQuery, mapLoad } from "@stapel/core";
47
+ import { SUGGEST_DEGRADED_CATEGORIES, SUGGEST_DEGRADED_ROLLUP, suggestTerms, } from "../api/types.js";
27
48
  import { useSearchState } from "./SearchStateProvider.js";
28
49
  import { useSuggest } from "../model/queries.js";
29
50
  import { SEARCH_BOX_DEBOUNCE_MS, SEARCH_BOX_SUGGEST_DEBOUNCE_MS, SEARCH_QUERY_MAX_CHARS, SUGGEST_MIN_CHARS, } from "../state/limits.js";
30
51
  /** One frozen empty list, so a render with no suggestions is a stable value. */
31
52
  const NO_SUGGESTIONS = [];
53
+ /** The same, for the categories half. */
54
+ const NO_CATEGORIES = [];
55
+ /** Does this answer name a shortfall? Absent-safe on every older server. */
56
+ function degradedWith(answer, literal) {
57
+ return answer?.degraded?.includes(literal) === true;
58
+ }
59
+ /**
60
+ * The destinations worth offering out of one answer.
61
+ *
62
+ * A category with a count of `0` is a section with nothing in it: following it
63
+ * lands the buyer on an empty SERP, which is a dead end dressed as a
64
+ * destination — and the server does return those (it reads the count with a
65
+ * `0` default and ranks them last), so somebody has to drop them.
66
+ *
67
+ * The one exception is `category_rollup`, where EVERY count is `0` because the
68
+ * ancestry never arrived rather than because the sections are empty. Filtering
69
+ * on the count there would delete the whole group for a reason that has
70
+ * nothing to do with what is in the catalogue, so the rows are kept and the
71
+ * numbers are what the surface omits.
72
+ */
73
+ export function offerableCategories(answer) {
74
+ const categories = answer?.categories;
75
+ if (categories === undefined || categories.length === 0)
76
+ return NO_CATEGORIES;
77
+ if (degradedWith(answer, SUGGEST_DEGRADED_ROLLUP))
78
+ return categories;
79
+ return categories.filter((category) => category.count > 0);
80
+ }
32
81
  export function useSearchBox(options = {}) {
33
- const { state, setText } = useSearchState();
82
+ const { state, setText, patch } = useSearchState();
34
83
  const committed = state.q;
35
84
  const debounceMs = options.debounceMs ?? SEARCH_BOX_DEBOUNCE_MS;
36
85
  const [draft, setDraftState] = useState(committed);
@@ -98,7 +147,19 @@ export function useSearchBox(options = {}) {
98
147
  ...(options.suggestLimit !== undefined ? { limit: options.suggestLimit } : {}),
99
148
  enabled: options.suggest !== false,
100
149
  });
101
- const suggestState = mapLoad(loadStateFromQuery(suggest), (data) => data.items);
150
+ const suggestState = mapLoad(loadStateFromQuery(suggest), suggestTerms);
151
+ // The READY answer only. A category row is a navigation control, and one
152
+ // rendered out of a stale answer would send a person somewhere the current
153
+ // prefix never named.
154
+ const answer = suggest.data;
155
+ const categories = offerableCategories(answer);
156
+ const chooseCategory = (category) => {
157
+ setDraftState("");
158
+ cancel();
159
+ // One write, so one history entry — see `SearchBoxBag.chooseCategory` for
160
+ // why the text goes with it.
161
+ patch({ q: "", category: category.category });
162
+ };
102
163
  return {
103
164
  draft,
104
165
  committed,
@@ -106,11 +167,15 @@ export function useSearchBox(options = {}) {
106
167
  suggestions: suggestState.status === "ready" ? suggestState.data : NO_SUGGESTIONS,
107
168
  suggestState,
108
169
  suggestLoading: suggest.isLoading && suggest.fetchStatus === "fetching",
170
+ categories,
171
+ categoriesUnavailable: degradedWith(answer, SUGGEST_DEGRADED_CATEGORIES),
172
+ categoryCountsUnknown: degradedWith(answer, SUGGEST_DEGRADED_ROLLUP),
109
173
  minSuggestChars: SUGGEST_MIN_CHARS,
110
174
  maxLength: SEARCH_QUERY_MAX_CHARS,
111
175
  setDraft,
112
176
  submit,
113
177
  clear,
178
+ chooseCategory,
114
179
  };
115
180
  }
116
181
  //# sourceMappingURL=useSearchBox.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useSearchBox.js","sourceRoot":"","sources":["../../src/headless/useSearchBox.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useSearchBox.js","sourceRoot":"","sources":["../../src/headless/useSearchBox.ts"],"names":[],"mappings":"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"}
@@ -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,cA2IhC,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,cAoJhC,CAAC;AAEF,+DAA+D;AAC/D,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAE7D"}
package/dist/i18n/es.js CHANGED
@@ -38,6 +38,9 @@ export const searchI18nBundleEs = {
38
38
  "search.box.submit": "Buscar",
39
39
  "search.box.clear": "Borrar la búsqueda",
40
40
  "search.box.suggestions": "Sugerencias",
41
+ "search.box.categories": "Secciones",
42
+ "search.box.category_count.one": "{count} anuncio",
43
+ "search.box.category_count.other": "{count} anuncios",
41
44
  "search.sort.label": "Orden",
42
45
  "search.sort.relevance": "Más relevantes",
43
46
  "search.sort.newest": "Más recientes",
@@ -58,6 +61,7 @@ export const searchI18nBundleEs = {
58
61
  "search.facets.skipped": "Estos filtros no se contaron para esta búsqueda: {slugs}",
59
62
  "search.facets.not_counted": "sin contar",
60
63
  "search.facets.drill_down_hint": "Cada recuento es lo que obtendrías eligiendo ese valor en lugar del actual.",
64
+ "search.range.price": "Precio",
61
65
  "search.facets.range_from": "Desde",
62
66
  "search.facets.range_to": "Hasta",
63
67
  "search.facets.range_apply": "Aplicar",
@@ -76,6 +80,7 @@ export const searchI18nBundleEs = {
76
80
  "search.filters.dismiss": "Cerrar los filtros",
77
81
  "search.filters.chips_label": "Filtros",
78
82
  "search.filters.all": "Todos los filtros",
83
+ "search.filters.short": "Filtros",
79
84
  "search.filters.chip_more": ", +{count}",
80
85
  "search.category.title": "Categoría",
81
86
  "search.category.clear": "Buscar en todo el catálogo",
@@ -116,6 +121,9 @@ export const searchI18nBundleEs = {
116
121
  "search.ranking.inactive": "No aplicado: {reason}",
117
122
  "search.ranking.notes": "Notas",
118
123
  "search.ranking.link": "Cómo se ordenan estos resultados",
124
+ "search.nav.results": "Buscar",
125
+ "search.nav.ranking": "Orden de resultados",
126
+ "search.nav.ranking.short": "Orden",
119
127
  };
120
128
  /** Register the es bundle. Call AFTER `registerSearchI18n`. */
121
129
  export function registerSearchI18nEs(engine) {
@@ -1 +1 @@
1
- {"version":3,"file":"es.js","sourceRoot":"","sources":["../../src/i18n/es.ts"],"names":[],"mappings":"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"}
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,mCAAmC,EAAE,oBAAoB;IACzD,qCAAqC,EAAE,qBAAqB;IAC5D,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;IAC9B,0BAA0B,EAAE,iBAAiB;IAE7C,kBAAkB,EAAE,QAAQ;IAC5B,wBAAwB,EAAE,sBAAsB;IAChD,mBAAmB,EAAE,QAAQ;IAC7B,kBAAkB,EAAE,oBAAoB;IACxC,wBAAwB,EAAE,aAAa;IACvC,uBAAuB,EAAE,WAAW;IACpC,+BAA+B,EAAE,iBAAiB;IAClD,iCAAiC,EAAE,kBAAkB;IAErD,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,mBAAmB,EAAE,OAAO;IAC5B,kBAAkB,EAAE,OAAO;IAC3B,kBAAkB,EAAE,YAAY;IAEhC,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,oBAAoB,EAAE,QAAQ;IAC9B,0BAA0B,EAAE,OAAO;IACnC,wBAAwB,EAAE,OAAO;IACjC,2BAA2B,EAAE,SAAS;IACtC,2BAA2B,EAAE,QAAQ;IACrC,+BAA+B,EAAE,kBAAkB;IACnD,6BAA6B,EAAE,kBAAkB;IACjD,wBAAwB,EAAE,qBAAqB;IAC/C,yBAAyB,EAAE,WAAW;IACtC,6BAA6B,EAC3B,oGAAoG;IAEtG,qBAAqB,EAAE,mBAAmB;IAC1C,sBAAsB,EAAE,gBAAgB;IACxC,+BAA+B,EAAE,uBAAuB;IACxD,iCAAiC,EAAE,wBAAwB;IAC3D,wCAAwC,EAAE,wBAAwB;IAClE,0CAA0C,EAAE,yBAAyB;IACrE,wBAAwB,EAAE,oBAAoB;IAC9C,4BAA4B,EAAE,SAAS;IACvC,oBAAoB,EAAE,mBAAmB;IACzC,sBAAsB,EAAE,SAAS;IACjC,0BAA0B,EAAE,YAAY;IAExC,uBAAuB,EAAE,WAAW;IACpC,uBAAuB,EAAE,4BAA4B;IACrD,yBAAyB,EAAE,2BAA2B;IAEtD,uBAAuB,EAAE,uBAAuB;IAChD,qBAAqB,EAAE,kBAAkB;IAEzC,oBAAoB,EAAE,YAAY;IAClC,qBAAqB,EAAE,oBAAoB;IAC3C,wBAAwB,EAAE,8CAA8C;IAExE,kBAAkB,EAAE,WAAW;IAC/B,sBAAsB,EAAE,oBAAoB;IAC5C,yBAAyB,EAAE,WAAW;IACtC,kBAAkB,EAAE,oBAAoB;IACxC,uBAAuB,EAAE,0BAA0B;IACnD,gBAAgB,EAAE,0BAA0B;IAC5C,yBAAyB,EAAE,6BAA6B;IAExD,yBAAyB,EAAE,sCAAsC;IACjE,+BAA+B,EAC7B,6DAA6D;IAC/D,iCAAiC,EAC/B,gEAAgE;IAClE,iCAAiC,EAC/B,oEAAoE;IACtE,kCAAkC,EAChC,wEAAwE;IAE1E,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;IAEzD,oBAAoB,EAAE,QAAQ;IAC9B,oBAAoB,EAAE,qBAAqB;IAC3C,0BAA0B,EAAE,OAAO;CACpC,CAAC;AAEF,+DAA+D;AAC/D,MAAM,UAAU,oBAAoB,CAAC,MAAkB;IACrD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC;AAClD,CAAC"}
@@ -58,6 +58,22 @@ export declare const SEARCH_I18N_KEYS: {
58
58
  readonly boxClear: "search.box.clear";
59
59
  /** Accessible name of the suggestion list under the box. */
60
60
  readonly boxSuggestions: "search.box.suggestions";
61
+ /**
62
+ * The heading over the CATEGORY half of the type-ahead (stapel-search
63
+ * 0.7.0). The rows under it are DESTINATIONS — a section of the catalogue —
64
+ * and not, like everything else in the menu, another set of words to search
65
+ * for; a group with no heading would read as more of the same.
66
+ */
67
+ readonly boxCategories: "search.box.categories";
68
+ /**
69
+ * "1 240 listings" beside a category row — how many LIVE listings a buyer
70
+ * would see there, the same number the SERP reports for it.
71
+ *
72
+ * A PLURAL FAMILY: render with `tPlural`, never `t`. It counts a noun in
73
+ * words, so Russian needs its four endings and a single string would be
74
+ * right only for 5-20 — the exact defect the results count already fixed.
75
+ */
76
+ readonly boxCategoryCount: "search.box.category_count";
61
77
  readonly sortLabel: "search.sort.label";
62
78
  readonly sortRelevance: "search.sort.relevance";
63
79
  readonly sortNewest: "search.sort.newest";
@@ -91,6 +107,9 @@ export declare const SEARCH_I18N_KEYS: {
91
107
  readonly facetsRangeToAria: "search.facets.range_to_aria";
92
108
  /** The reason "Apply" is off: the range reads backwards. */
93
109
  readonly facetsRangeInvalid: "search.facets.range_invalid";
110
+ /** A CORE range axis has no FeatureDef and so no `name` to translate.
111
+ * `search.range.<slug>`; `price` is the one stapel-search ships. */
112
+ readonly rangePrice: "search.range.price";
94
113
  /** The fold on a long facet group: "Show all (46)". The number is in
95
114
  * brackets and not a counted noun, so this is one message and not a plural
96
115
  * family — "(1)" never renders, because a group is only folded when the
@@ -112,6 +131,9 @@ export declare const SEARCH_I18N_KEYS: {
112
131
  /** The leading, icon-only chip: the whole panel. Icon-only means the name
113
132
  * exists ONLY here, so this key is the control's entire accessibility. */
114
133
  readonly filtersAll: "search.filters.all";
134
+ /** The same door, named for a 390px row: the location line's trailing link
135
+ * sits beside a place name and cannot spend six characters on "All". */
136
+ readonly filtersShort: "search.filters.short";
115
137
  /** A chip filtering on more than one value: "Bosch, +2". Not a plural
116
138
  * family — nothing is being counted in words. */
117
139
  readonly filtersChipMore: "search.filters.chip_more";
@@ -176,6 +198,32 @@ export declare const SEARCH_I18N_KEYS: {
176
198
  readonly rankingInactive: "search.ranking.inactive";
177
199
  readonly rankingNotes: "search.ranking.notes";
178
200
  readonly rankingLink: "search.ranking.link";
201
+ /**
202
+ * What the MENU calls the results screen.
203
+ *
204
+ * Separate from `search.results.title` on purpose. That key captions the
205
+ * list of matches — a heading over rows, which is why it reads "Results" —
206
+ * and a menu entry pointing at `/s` labelled "Results" tells a visitor
207
+ * nothing about where they would be going: results of what? The destination
208
+ * is the search itself. One key, one job; a translator asked to make
209
+ * "Results" work as both a page heading and a menu label has to pick which
210
+ * one to get wrong.
211
+ */
212
+ readonly navResults: "search.nav.results";
213
+ /** The menu name of the P2B disclosure PAGE — see {@link navResults} for
214
+ * why it is not `search.ranking.title`, which is the page's own heading and
215
+ * a whole sentence. */
216
+ readonly navRanking: "search.nav.ranking";
217
+ /**
218
+ * The compact form for a phone dock — see `NavEntry.shortLabelKey`. A
219
+ * five-cell dock at 390px gives a destination roughly ten characters, and
220
+ * "Ranking disclosure" ellipsizes to a fragment there.
221
+ *
222
+ * `search.nav.results` needs no short form: it is already one word in every
223
+ * locale this pair ships, and declaring a short key identical to the long
224
+ * one only gives a translator two strings to keep in sync.
225
+ */
226
+ readonly navRankingShort: "search.nav.ranking.short";
179
227
  };
180
228
  export type SearchI18nKey = (typeof SEARCH_I18N_KEYS)[keyof typeof SEARCH_I18N_KEYS];
181
229
  /**
@@ -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;;;;;;;OAOG;;IAEH;kEAC8D;;IAE9D,sEAAsE;;;;;;;IAOtE,yDAAyD;;;;;;;IAOzD,yEAAyE;;;;;;IAQzE,4DAA4D;;;;;;;;;IAa5D;2CACuC;;;;;;;;;;;;IAcvC,oEAAoE;;;;;;;IAOpE;kEAC8D;;;IAG9D,4DAA4D;;IAE5D;;;sCAGkC;;;;IAMlC,2DAA2D;;IAE3D;0BACsB;;IAEtB,uEAAuE;;;IAGvE;mEAC+D;;IAE/D;8EAC0E;;IAE1E;qDACiD;;;;;;;;;IAejD;iFAC6E;;;;;;IAQ7E;;;;;;;;OAQG;;;IAGH;;;;;;;;;;OAUG;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCK,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,EAM3D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA0IrD,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;;;;;;;OAOG;;IAEH;kEAC8D;;IAE9D,sEAAsE;;;;;;;IAOtE,yDAAyD;;;;;;;IAOzD,yEAAyE;;;;;;IAQzE,4DAA4D;;IAE5D;;;;;OAKG;;IAEH;;;;;;;OAOG;;;;;;;;;IAaH;2CACuC;;;;;;;;;;;;IAcvC,oEAAoE;;;;;;;IAOpE;kEAC8D;;;IAG9D,4DAA4D;;IAE5D;wEACoE;;IAEpE;;;sCAGkC;;;;IAMlC,2DAA2D;;IAE3D;0BACsB;;IAEtB,uEAAuE;;;IAGvE;mEAC+D;;IAE/D;8EAC0E;;IAE1E;4EACwE;;IAExE;qDACiD;;;;;;;;;IAejD;iFAC6E;;;;;;IAQ7E;;;;;;;;OAQG;;;IAGH;;;;;;;;;;OAUG;;;;;;;;;;;;;;;;;;;;;;;;;;IAkCH;;;;;;;;;;OAUG;;IAEH;;2BAEuB;;IAEvB;;;;;;;;OAQG;;CAEK,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,EAO3D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAmJrD,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAEzD"}
package/dist/i18n/keys.js CHANGED
@@ -60,6 +60,22 @@ export const SEARCH_I18N_KEYS = {
60
60
  boxClear: "search.box.clear",
61
61
  /** Accessible name of the suggestion list under the box. */
62
62
  boxSuggestions: "search.box.suggestions",
63
+ /**
64
+ * The heading over the CATEGORY half of the type-ahead (stapel-search
65
+ * 0.7.0). The rows under it are DESTINATIONS — a section of the catalogue —
66
+ * and not, like everything else in the menu, another set of words to search
67
+ * for; a group with no heading would read as more of the same.
68
+ */
69
+ boxCategories: "search.box.categories",
70
+ /**
71
+ * "1 240 listings" beside a category row — how many LIVE listings a buyer
72
+ * would see there, the same number the SERP reports for it.
73
+ *
74
+ * A PLURAL FAMILY: render with `tPlural`, never `t`. It counts a noun in
75
+ * words, so Russian needs its four endings and a single string would be
76
+ * right only for 5-20 — the exact defect the results count already fixed.
77
+ */
78
+ boxCategoryCount: "search.box.category_count",
63
79
  // ── sort ─────────────────────────────────────────────────────────────────
64
80
  sortLabel: "search.sort.label",
65
81
  sortRelevance: "search.sort.relevance",
@@ -96,6 +112,9 @@ export const SEARCH_I18N_KEYS = {
96
112
  facetsRangeToAria: "search.facets.range_to_aria",
97
113
  /** The reason "Apply" is off: the range reads backwards. */
98
114
  facetsRangeInvalid: "search.facets.range_invalid",
115
+ /** A CORE range axis has no FeatureDef and so no `name` to translate.
116
+ * `search.range.<slug>`; `price` is the one stapel-search ships. */
117
+ rangePrice: "search.range.price",
99
118
  /** The fold on a long facet group: "Show all (46)". The number is in
100
119
  * brackets and not a counted noun, so this is one message and not a plural
101
120
  * family — "(1)" never renders, because a group is only folded when the
@@ -118,6 +137,9 @@ export const SEARCH_I18N_KEYS = {
118
137
  /** The leading, icon-only chip: the whole panel. Icon-only means the name
119
138
  * exists ONLY here, so this key is the control's entire accessibility. */
120
139
  filtersAll: "search.filters.all",
140
+ /** The same door, named for a 390px row: the location line's trailing link
141
+ * sits beside a place name and cannot spend six characters on "All". */
142
+ filtersShort: "search.filters.short",
121
143
  /** A chip filtering on more than one value: "Bosch, +2". Not a plural
122
144
  * family — nothing is being counted in words. */
123
145
  filtersChipMore: "search.filters.chip_more",
@@ -189,6 +211,33 @@ export const SEARCH_I18N_KEYS = {
189
211
  rankingInactive: "search.ranking.inactive",
190
212
  rankingNotes: "search.ranking.notes",
191
213
  rankingLink: "search.ranking.link",
214
+ // ── nav (the destination's own name, not the page's heading) ─────────────
215
+ /**
216
+ * What the MENU calls the results screen.
217
+ *
218
+ * Separate from `search.results.title` on purpose. That key captions the
219
+ * list of matches — a heading over rows, which is why it reads "Results" —
220
+ * and a menu entry pointing at `/s` labelled "Results" tells a visitor
221
+ * nothing about where they would be going: results of what? The destination
222
+ * is the search itself. One key, one job; a translator asked to make
223
+ * "Results" work as both a page heading and a menu label has to pick which
224
+ * one to get wrong.
225
+ */
226
+ navResults: "search.nav.results",
227
+ /** The menu name of the P2B disclosure PAGE — see {@link navResults} for
228
+ * why it is not `search.ranking.title`, which is the page's own heading and
229
+ * a whole sentence. */
230
+ navRanking: "search.nav.ranking",
231
+ /**
232
+ * The compact form for a phone dock — see `NavEntry.shortLabelKey`. A
233
+ * five-cell dock at 390px gives a destination roughly ten characters, and
234
+ * "Ranking disclosure" ellipsizes to a fragment there.
235
+ *
236
+ * `search.nav.results` needs no short form: it is already one word in every
237
+ * locale this pair ships, and declaring a short key identical to the long
238
+ * one only gives a translator two strings to keep in sync.
239
+ */
240
+ navRankingShort: "search.nav.ranking.short",
192
241
  };
193
242
  /**
194
243
  * The keys above that are PLURAL FAMILIES rather than single messages.
@@ -211,6 +260,7 @@ export const SEARCH_I18N_PLURAL_KEYS = [
211
260
  SEARCH_I18N_KEYS.resultsCountExact,
212
261
  SEARCH_I18N_KEYS.filtersShowCount,
213
262
  SEARCH_I18N_KEYS.filtersShowCountAtLeast,
263
+ SEARCH_I18N_KEYS.boxCategoryCount,
214
264
  ];
215
265
  /**
216
266
  * English fallback bundle for search-react UI keys + backend error codes.
@@ -248,6 +298,9 @@ export const searchI18nBundleEn = {
248
298
  "search.box.submit": "Search",
249
299
  "search.box.clear": "Clear the search",
250
300
  "search.box.suggestions": "Suggestions",
301
+ "search.box.categories": "Sections",
302
+ "search.box.category_count.one": "{count} listing",
303
+ "search.box.category_count.other": "{count} listings",
251
304
  "search.sort.label": "Sort",
252
305
  "search.sort.relevance": "Most relevant",
253
306
  "search.sort.newest": "Newest first",
@@ -268,6 +321,7 @@ export const searchI18nBundleEn = {
268
321
  "search.facets.skipped": "These filters were not counted for this search: {slugs}",
269
322
  "search.facets.not_counted": "not counted",
270
323
  "search.facets.drill_down_hint": "Each count is what you would get by choosing that value instead of the one you have.",
324
+ "search.range.price": "Price",
271
325
  "search.facets.range_from": "From",
272
326
  "search.facets.range_to": "To",
273
327
  "search.facets.range_apply": "Apply",
@@ -286,6 +340,7 @@ export const searchI18nBundleEn = {
286
340
  "search.filters.dismiss": "Close the filters",
287
341
  "search.filters.chips_label": "Filters",
288
342
  "search.filters.all": "All filters",
343
+ "search.filters.short": "Filters",
289
344
  "search.filters.chip_more": ", +{count}",
290
345
  "search.category.title": "Category",
291
346
  "search.category.clear": "Search the whole catalogue",
@@ -326,6 +381,9 @@ export const searchI18nBundleEn = {
326
381
  "search.ranking.inactive": "Not applied: {reason}",
327
382
  "search.ranking.notes": "Notes",
328
383
  "search.ranking.link": "How these results are ordered",
384
+ "search.nav.results": "Search",
385
+ "search.nav.ranking": "Ranking disclosure",
386
+ "search.nav.ranking.short": "Ranking",
329
387
  };
330
388
  /**
331
389
  * Register the English bundle into a core i18n engine. Locale bundles ship as