@stapel/search-react 0.11.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.
- package/CHANGELOG.md +120 -0
- package/MODULE.md +111 -0
- package/README.md +42 -0
- package/dist/api/generated/schema.d.ts +60 -6
- package/dist/api/generated/schema.d.ts.map +1 -1
- package/dist/api/searchApi.d.ts +13 -6
- package/dist/api/searchApi.d.ts.map +1 -1
- package/dist/api/searchApi.js.map +1 -1
- package/dist/api/types.d.ts +107 -1
- package/dist/api/types.d.ts.map +1 -1
- package/dist/api/types.js +29 -0
- package/dist/api/types.js.map +1 -1
- package/dist/default/FacetPanelPane.d.ts +13 -2
- package/dist/default/FacetPanelPane.d.ts.map +1 -1
- package/dist/default/FacetPanelPane.js +3 -1
- package/dist/default/FacetPanelPane.js.map +1 -1
- package/dist/default/FilterChips.d.ts +88 -3
- package/dist/default/FilterChips.d.ts.map +1 -1
- package/dist/default/FilterChips.js +161 -13
- package/dist/default/FilterChips.js.map +1 -1
- package/dist/default/LocationSummaryLine.d.ts.map +1 -1
- package/dist/default/LocationSummaryLine.js +1 -1
- package/dist/default/LocationSummaryLine.js.map +1 -1
- package/dist/default/SearchBox.d.ts.map +1 -1
- package/dist/default/SearchBox.js +74 -4
- package/dist/default/SearchBox.js.map +1 -1
- package/dist/default/SearchPage.d.ts +29 -1
- package/dist/default/SearchPage.d.ts.map +1 -1
- package/dist/default/SearchPage.js +25 -10
- package/dist/default/SearchPage.js.map +1 -1
- package/dist/default/SearchResultsPane.d.ts +22 -0
- package/dist/default/SearchResultsPane.d.ts.map +1 -1
- package/dist/default/SearchResultsPane.js +2 -2
- package/dist/default/SearchResultsPane.js.map +1 -1
- package/dist/default/SortSelect.d.ts +23 -0
- package/dist/default/SortSelect.d.ts.map +1 -1
- package/dist/default/SortSelect.js +29 -9
- package/dist/default/SortSelect.js.map +1 -1
- package/dist/default/index.d.ts +2 -2
- package/dist/default/index.d.ts.map +1 -1
- package/dist/default/index.js +1 -1
- package/dist/default/index.js.map +1 -1
- package/dist/headless/FacetPanel.d.ts +10 -0
- package/dist/headless/FacetPanel.d.ts.map +1 -1
- package/dist/headless/FacetPanel.js +9 -1
- package/dist/headless/FacetPanel.js.map +1 -1
- package/dist/headless/useFacetLabels.d.ts +39 -0
- package/dist/headless/useFacetLabels.d.ts.map +1 -0
- package/dist/headless/useFacetLabels.js +129 -0
- package/dist/headless/useFacetLabels.js.map +1 -0
- package/dist/headless/useSearchBox.d.ts +71 -0
- package/dist/headless/useSearchBox.d.ts.map +1 -1
- package/dist/headless/useSearchBox.js +67 -2
- package/dist/headless/useSearchBox.js.map +1 -1
- package/dist/i18n/es.d.ts.map +1 -1
- package/dist/i18n/es.js +7 -0
- package/dist/i18n/es.js.map +1 -1
- package/dist/i18n/keys.d.ts +45 -0
- package/dist/i18n/keys.d.ts.map +1 -1
- package/dist/i18n/keys.js +54 -0
- package/dist/i18n/keys.js.map +1 -1
- package/dist/i18n/ru.d.ts.map +1 -1
- package/dist/i18n/ru.js +9 -0
- package/dist/i18n/ru.js.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/model/queries.d.ts +6 -5
- package/dist/model/queries.d.ts.map +1 -1
- package/dist/model/queries.js +4 -3
- package/dist/model/queries.js.map +1 -1
- package/dist/model/queryKeys.d.ts +12 -0
- package/dist/model/queryKeys.d.ts.map +1 -1
- package/dist/model/queryKeys.js +7 -0
- package/dist/model/queryKeys.js.map +1 -1
- package/dist/nav/manifest.d.ts +21 -0
- package/dist/nav/manifest.d.ts.map +1 -1
- package/dist/nav/manifest.js +3 -2
- package/dist/nav/manifest.js.map +1 -1
- package/dist/state/facets.d.ts +56 -15
- package/dist/state/facets.d.ts.map +1 -1
- package/dist/state/facets.js +101 -27
- package/dist/state/facets.js.map +1 -1
- package/llms.txt +2 -2
- package/manifest.json +22 -2
- package/nav-manifest.json +4 -3
- package/package.json +11 -11
- package/src/analytics/generated/events.json +1 -1
- package/src/api/generated/schema.ts +60 -6
- package/src/api/searchApi.ts +13 -6
- package/src/api/types.ts +115 -1
- package/src/default/FacetPanelPane.tsx +16 -2
- package/src/default/FilterChips.tsx +285 -38
- package/src/default/LocationSummaryLine.tsx +6 -1
- package/src/default/SearchBox.tsx +134 -6
- package/src/default/SearchPage.tsx +79 -5
- package/src/default/SearchResultsPane.tsx +48 -11
- package/src/default/SortSelect.tsx +70 -9
- package/src/default/index.ts +10 -2
- package/src/headless/FacetPanel.tsx +20 -1
- package/src/headless/useFacetLabels.ts +172 -0
- package/src/headless/useSearchBox.ts +132 -5
- package/src/i18n/es.ts +8 -0
- package/src/i18n/keys.ts +56 -0
- package/src/i18n/ru.ts +10 -0
- package/src/index.ts +21 -3
- package/src/model/queries.ts +6 -5
- package/src/model/queryKeys.ts +23 -0
- package/src/nav/manifest.ts +24 -2
- package/src/state/facets.ts +123 -39
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FacetPanel.d.ts","sourceRoot":"","sources":["../../src/headless/FacetPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAa,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"FacetPanel.d.ts","sourceRoot":"","sources":["../../src/headless/FacetPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAa,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAG9D,oDAAoD;AACpD,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,SAAS,UAAU,EAAE,CAAC,CAAC;IACjD;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,+BAA+B;IAC/B,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC;;;;;;;OAOG;IACH,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,2EAA2E;IAC3E,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,qDAAqD;IACrD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAE/B,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAAC;IACxD,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,IAAI,IAAI,CAAC;CAClB;AAUD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE;IAChC,kEAAkE;IAClE,gBAAgB,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACzC,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,qEAAqE;IACrE,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,QAAQ,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,SAAS,CAAC;CAC7C,GAAG,SAAS,CAaZ;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,KAAK,GAAE;IACnC,gBAAgB,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;CACpC,GAAG,aAAa,CAmDrB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { loadStateFromQuery, mapLoad, useT } from "@stapel/core";
|
|
2
2
|
import { useSearchQuery } from "../model/queries.js";
|
|
3
3
|
import { buildFacetGroups } from "../state/facets.js";
|
|
4
|
+
import { useHostFacetLabels } from "./useFacetLabels.js";
|
|
4
5
|
import { useSearchState } from "./SearchStateProvider.js";
|
|
5
6
|
const EMPTY_META = {
|
|
6
7
|
approximate: false,
|
|
@@ -31,6 +32,9 @@ export function FacetPanel(props) {
|
|
|
31
32
|
: {}),
|
|
32
33
|
...(props.locale !== undefined ? { locale: props.locale } : {}),
|
|
33
34
|
...(props.enabled !== undefined ? { enabled: props.enabled } : {}),
|
|
35
|
+
...(props.resolveFacetLabels !== undefined
|
|
36
|
+
? { resolveFacetLabels: props.resolveFacetLabels }
|
|
37
|
+
: {}),
|
|
34
38
|
}));
|
|
35
39
|
}
|
|
36
40
|
/**
|
|
@@ -62,8 +66,12 @@ export function useFacetPanel(props = {}) {
|
|
|
62
66
|
t,
|
|
63
67
|
...(props.locale !== undefined ? { locale: props.locale } : {}),
|
|
64
68
|
}));
|
|
69
|
+
// The host seam runs AFTER `buildFacetGroups`, on what it could not name:
|
|
70
|
+
// the precedence is server captions, then the schema's own option table,
|
|
71
|
+
// then this. See `useFacetLabels.ts`.
|
|
72
|
+
const labelled = useHostFacetLabels(groups, props.resolveFacetLabels, props.locale);
|
|
65
73
|
return {
|
|
66
|
-
state:
|
|
74
|
+
state: labelled,
|
|
67
75
|
approximate: meta.approximate,
|
|
68
76
|
skipped: meta.skipped,
|
|
69
77
|
counted: meta.counted,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FacetPanel.js","sourceRoot":"","sources":["../../src/headless/FacetPanel.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAIjE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAoD1D,MAAM,UAAU,GAAc;IAC5B,WAAW,EAAE,KAAK;IAClB,UAAU,EAAE,CAAC;IACb,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,EAAE;IACX,WAAW,EAAE,EAAE;CAChB,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"FacetPanel.js","sourceRoot":"","sources":["../../src/headless/FacetPanel.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { LoadState } from "@stapel/core";
|
|
2
|
+
import type { FeatureDef } from "@stapel/attributes-react";
|
|
3
|
+
import type { FacetGroup } from "../state/facets.js";
|
|
4
|
+
/** What the host is asked to name. */
|
|
5
|
+
export interface FacetLabelRequest {
|
|
6
|
+
/** The facet slug — `vendor`, `color_ref_select`. */
|
|
7
|
+
readonly slug: string;
|
|
8
|
+
/**
|
|
9
|
+
* The category's own def for the slug, when the host supplied a schema.
|
|
10
|
+
* It carries the `optionsRef` pointer (vocabulary + level) a resolver needs
|
|
11
|
+
* to know WHICH vocabulary these codes belong to, so a host does not have to
|
|
12
|
+
* keep a second copy of the schema to answer.
|
|
13
|
+
*/
|
|
14
|
+
readonly feature: FeatureDef | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* The values nobody has named yet, sorted. Only the unresolved ones: a
|
|
17
|
+
* resolver is never asked about a value the server or the schema captioned.
|
|
18
|
+
*/
|
|
19
|
+
readonly values: readonly string[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A host's answer: `{value: caption}`.
|
|
23
|
+
*
|
|
24
|
+
* Partial answers are the expected case, not an error — a code the vocabulary
|
|
25
|
+
* no longer holds simply is not in the map, and its chip keeps printing the
|
|
26
|
+
* raw value. Returning `{}` is a legitimate "I cannot name any of these".
|
|
27
|
+
*/
|
|
28
|
+
export type FacetLabelResolver = (request: FacetLabelRequest, options: {
|
|
29
|
+
readonly signal: AbortSignal;
|
|
30
|
+
}) => Promise<Readonly<Record<string, string>>>;
|
|
31
|
+
/**
|
|
32
|
+
* Fill in what the server and the schema could not name, through the host.
|
|
33
|
+
*
|
|
34
|
+
* Returns the groups UNCHANGED — same object identity — when there is no
|
|
35
|
+
* resolver or nothing came back, so a page with the seam unwired pays neither
|
|
36
|
+
* a request nor a re-render.
|
|
37
|
+
*/
|
|
38
|
+
export declare function useHostFacetLabels(groups: LoadState<readonly FacetGroup[]>, resolve: FacetLabelResolver | undefined, locale: string | undefined): LoadState<readonly FacetGroup[]>;
|
|
39
|
+
//# sourceMappingURL=useFacetLabels.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFacetLabels.d.ts","sourceRoot":"","sources":["../../src/headless/useFacetLabels.ts"],"names":[],"mappings":"AA2DA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,sCAAsC;AACtC,MAAM,WAAW,iBAAiB;IAChC,qDAAqD;IACrD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,SAAS,CAAC;IACzC;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAC/B,OAAO,EAAE,iBAAiB,EAC1B,OAAO,EAAE;IAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;CAAE,KACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;AAiB/C;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,CAAC,SAAS,UAAU,EAAE,CAAC,EACxC,OAAO,EAAE,kBAAkB,GAAG,SAAS,EACvC,MAAM,EAAE,MAAM,GAAG,SAAS,GACzB,SAAS,CAAC,SAAS,UAAU,EAAE,CAAC,CAmDlC"}
|
|
@@ -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":"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"}
|
|
@@ -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":"
|
|
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),
|
|
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":"AAAA
|
|
1
|
+
{"version":3,"file":"useSearchBox.js","sourceRoot":"","sources":["../../src/headless/useSearchBox.ts"],"names":[],"mappings":"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"}
|
package/dist/i18n/es.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"es.d.ts","sourceRoot":"","sources":["../../src/i18n/es.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,EAAE,
|
|
1
|
+
{"version":3,"file":"es.d.ts","sourceRoot":"","sources":["../../src/i18n/es.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,EAAE,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",
|
|
@@ -77,6 +80,7 @@ export const searchI18nBundleEs = {
|
|
|
77
80
|
"search.filters.dismiss": "Cerrar los filtros",
|
|
78
81
|
"search.filters.chips_label": "Filtros",
|
|
79
82
|
"search.filters.all": "Todos los filtros",
|
|
83
|
+
"search.filters.short": "Filtros",
|
|
80
84
|
"search.filters.chip_more": ", +{count}",
|
|
81
85
|
"search.category.title": "Categoría",
|
|
82
86
|
"search.category.clear": "Buscar en todo el catálogo",
|
|
@@ -117,6 +121,9 @@ export const searchI18nBundleEs = {
|
|
|
117
121
|
"search.ranking.inactive": "No aplicado: {reason}",
|
|
118
122
|
"search.ranking.notes": "Notas",
|
|
119
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",
|
|
120
127
|
};
|
|
121
128
|
/** Register the es bundle. Call AFTER `registerSearchI18n`. */
|
|
122
129
|
export function registerSearchI18nEs(engine) {
|
package/dist/i18n/es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"es.js","sourceRoot":"","sources":["../../src/i18n/es.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAmB;IAChD,GAAG,mBAAmB;IAEtB,sBAAsB,EAAE,4BAA4B;IAEpD,sBAAsB,EAAE,YAAY;IACpC,wBAAwB,EAAE,WAAW;IACrC,4BAA4B,EAAE,oCAAoC;IAClE,sBAAsB,EAAE,6CAA6C;IACrE,sBAAsB,EAAE,YAAY;IACpC,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;
|
|
1
|
+
{"version":3,"file":"es.js","sourceRoot":"","sources":["../../src/i18n/es.ts"],"names":[],"mappings":"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"}
|
package/dist/i18n/keys.d.ts
CHANGED
|
@@ -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";
|
|
@@ -115,6 +131,9 @@ export declare const SEARCH_I18N_KEYS: {
|
|
|
115
131
|
/** The leading, icon-only chip: the whole panel. Icon-only means the name
|
|
116
132
|
* exists ONLY here, so this key is the control's entire accessibility. */
|
|
117
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";
|
|
118
137
|
/** A chip filtering on more than one value: "Bosch, +2". Not a plural
|
|
119
138
|
* family — nothing is being counted in words. */
|
|
120
139
|
readonly filtersChipMore: "search.filters.chip_more";
|
|
@@ -179,6 +198,32 @@ export declare const SEARCH_I18N_KEYS: {
|
|
|
179
198
|
readonly rankingInactive: "search.ranking.inactive";
|
|
180
199
|
readonly rankingNotes: "search.ranking.notes";
|
|
181
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";
|
|
182
227
|
};
|
|
183
228
|
export type SearchI18nKey = (typeof SEARCH_I18N_KEYS)[keyof typeof SEARCH_I18N_KEYS];
|
|
184
229
|
/**
|
package/dist/i18n/keys.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../src/i18n/keys.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/D;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,gBAAgB;;;;;;;IAS3B;;;;;;;OAOG;;IAEH;kEAC8D;;IAE9D,sEAAsE;;;;;;;IAOtE,yDAAyD;;;;;;;IAOzD,yEAAyE;;;;;;IAQzE,4DAA4D;;;;;;;;;
|
|
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"}
|