@stapel/search-react 0.3.1 → 0.4.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 +29 -0
- package/MODULE.md +43 -4
- package/dist/api/generated/schema.d.ts +5 -1
- package/dist/api/generated/schema.d.ts.map +1 -1
- package/dist/default/DegradationNotice.d.ts +27 -0
- package/dist/default/DegradationNotice.d.ts.map +1 -1
- package/dist/default/DegradationNotice.js +17 -6
- package/dist/default/DegradationNotice.js.map +1 -1
- package/dist/default/SearchPage.d.ts +4 -0
- package/dist/default/SearchPage.d.ts.map +1 -1
- package/dist/default/SearchPage.js +4 -2
- package/dist/default/SearchPage.js.map +1 -1
- package/dist/default/SearchResultsPane.d.ts +12 -0
- package/dist/default/SearchResultsPane.d.ts.map +1 -1
- package/dist/default/SearchResultsPane.js +8 -5
- package/dist/default/SearchResultsPane.js.map +1 -1
- package/dist/default/index.d.ts +1 -1
- package/dist/default/index.d.ts.map +1 -1
- package/dist/default/index.js.map +1 -1
- package/dist/headless/SearchResults.d.ts +20 -3
- package/dist/headless/SearchResults.d.ts.map +1 -1
- package/dist/headless/SearchResults.js +3 -1
- package/dist/headless/SearchResults.js.map +1 -1
- package/dist/i18n/es.d.ts.map +1 -1
- package/dist/i18n/es.js +2 -0
- package/dist/i18n/es.js.map +1 -1
- package/dist/i18n/keys.d.ts +11 -2
- package/dist/i18n/keys.d.ts.map +1 -1
- package/dist/i18n/keys.js +14 -2
- package/dist/i18n/keys.js.map +1 -1
- package/dist/i18n/ru.d.ts.map +1 -1
- package/dist/i18n/ru.js +4 -0
- package/dist/i18n/ru.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/state/degradations.d.ts +41 -0
- package/dist/state/degradations.d.ts.map +1 -1
- package/dist/state/degradations.js +41 -0
- package/dist/state/degradations.js.map +1 -1
- package/llms.txt +2 -2
- package/manifest.json +8 -2
- package/nav-manifest.json +1 -1
- package/package.json +3 -3
- package/src/analytics/generated/events.json +1 -1
- package/src/api/generated/schema.ts +5 -1
- package/src/default/DegradationNotice.tsx +61 -13
- package/src/default/SearchPage.tsx +8 -0
- package/src/default/SearchResultsPane.tsx +27 -6
- package/src/default/index.ts +4 -1
- package/src/headless/SearchResults.tsx +32 -4
- package/src/i18n/es.ts +2 -0
- package/src/i18n/keys.ts +14 -2
- package/src/i18n/ru.ts +4 -0
- package/src/index.ts +8 -1
- package/src/state/degradations.ts +60 -0
package/dist/i18n/keys.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/i18n/keys.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAEhE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,YAAY,EAAE,sBAAsB;IAEpC,4EAA4E;IAC5E,YAAY,EAAE,sBAAsB;IACpC,cAAc,EAAE,wBAAwB;IACxC,iBAAiB,EAAE,4BAA4B;IAC/C,YAAY,EAAE,sBAAsB;IACpC,YAAY,EAAE,sBAAsB;IACpC;
|
|
1
|
+
{"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/i18n/keys.ts"],"names":[],"mappings":"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"}
|
package/dist/i18n/ru.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ru.d.ts","sourceRoot":"","sources":["../../src/i18n/ru.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,kBAAkB,EAAE,
|
|
1
|
+
{"version":3,"file":"ru.d.ts","sourceRoot":"","sources":["../../src/i18n/ru.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,kBAAkB,EAAE,cAwGhC,CAAC;AAEF;yDACyD;AACzD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAE7D"}
|
package/dist/i18n/ru.js
CHANGED
|
@@ -36,6 +36,10 @@ export const searchI18nBundleRu = {
|
|
|
36
36
|
"search.results.count_approximate.few": "Примерно {count} объявления",
|
|
37
37
|
"search.results.count_approximate.many": "Примерно {count} объявлений",
|
|
38
38
|
"search.results.count_approximate.other": "Примерно {count} объявления",
|
|
39
|
+
"search.results.count_at_least.one": "{count}+ объявление",
|
|
40
|
+
"search.results.count_at_least.few": "{count}+ объявления",
|
|
41
|
+
"search.results.count_at_least.many": "{count}+ объявлений",
|
|
42
|
+
"search.results.count_at_least.other": "{count}+ объявления",
|
|
39
43
|
"search.results.count_exact.one": "{count} объявление",
|
|
40
44
|
"search.results.count_exact.few": "{count} объявления",
|
|
41
45
|
"search.results.count_exact.many": "{count} объявлений",
|
package/dist/i18n/ru.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ru.js","sourceRoot":"","sources":["../../src/i18n/ru.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ru.js","sourceRoot":"","sources":["../../src/i18n/ru.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -46,7 +46,8 @@ export { SEARCH_SORTS } from "./api/types.js";
|
|
|
46
46
|
export type { FacetMeta, FacetSelection, RankingResponse, Scorer, SearchDegradation, SearchDegradationKind, SearchGeo, SearchGeoBox, SearchGeoCenter, SearchItem, SearchQueryState, SearchRange, SearchResponse, SuggestParams, SuggestResponse, } from "./api/types.js";
|
|
47
47
|
export { FILTER_PREFIX, RANGE_PREFIX, SEARCH_PARAM, activeFilterCount, clearFilters, ownsParam, parseSearchState, patchSearchState, setFilterValues, setRangeValue, toggleFilterValue, writeSearchState, } from "./state/urlState.js";
|
|
48
48
|
export type { ParseSearchStateOptions, ParsedSearchState, SearchStateIssue, SearchStateIssueCode, SearchStatePatch, } from "./state/urlState.js";
|
|
49
|
-
export { countIsEstimate, degradationMessageKey, parseDegradations } from "./state/degradations.js";
|
|
49
|
+
export { countIsEstimate, countKind, degradationMessageKey, isCountNuanceOnly, parseDegradations, } from "./state/degradations.js";
|
|
50
|
+
export type { SearchCountKind } from "./state/degradations.js";
|
|
50
51
|
export { buildFacetGroups, facetOptionLabel } from "./state/facets.js";
|
|
51
52
|
export type { BuildFacetGroupsInput, FacetGroup, FacetOption, } from "./state/facets.js";
|
|
52
53
|
export { createSearchRuntime } from "./model/runtime.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -44,7 +44,7 @@ export { createSearchApi, searchQueryParams } from "./api/searchApi.js";
|
|
|
44
44
|
export { SEARCH_SORTS } from "./api/types.js";
|
|
45
45
|
// ── state (pure: no React, no router) ────────────────────────────────────────
|
|
46
46
|
export { FILTER_PREFIX, RANGE_PREFIX, SEARCH_PARAM, activeFilterCount, clearFilters, ownsParam, parseSearchState, patchSearchState, setFilterValues, setRangeValue, toggleFilterValue, writeSearchState, } from "./state/urlState.js";
|
|
47
|
-
export { countIsEstimate, degradationMessageKey, parseDegradations } from "./state/degradations.js";
|
|
47
|
+
export { countIsEstimate, countKind, degradationMessageKey, isCountNuanceOnly, parseDegradations, } from "./state/degradations.js";
|
|
48
48
|
export { buildFacetGroups, facetOptionLabel } from "./state/facets.js";
|
|
49
49
|
// ── model (runtime wiring, query keys, context, hooks) ───────────────────────
|
|
50
50
|
export { createSearchRuntime } from "./model/runtime.js";
|
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,
|
|
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,EACL,eAAe,EACf,SAAS,EACT,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,yBAAyB,CAAC;AAGjC,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"}
|
|
@@ -25,6 +25,47 @@ export declare function parseDegradations(degraded: readonly string[] | undefine
|
|
|
25
25
|
* the envelope's own `exact_total: false`, and the `"exact_total"`
|
|
26
26
|
* degradation. They agree in practice; treating either as decisive is what
|
|
27
27
|
* keeps "≈1 200" from ever being rendered as "1 200".
|
|
28
|
+
*
|
|
29
|
+
* @deprecated Since stapel-search 0.2.0 the envelope answers this directly
|
|
30
|
+
* with `count_is_lower_bound`, and "not exact" now means a FLOOR rather than
|
|
31
|
+
* a fuzzy number. Use {@link countKind}, which reads the wire field and also
|
|
32
|
+
* handles `count: null`.
|
|
28
33
|
*/
|
|
29
34
|
export declare function countIsEstimate(exactTotal: boolean, degradations: readonly SearchDegradation[]): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* How a count may be spoken: as a number, as a floor, or not at all.
|
|
37
|
+
*
|
|
38
|
+
* The three states stapel-search 0.2.0 made explicit, because the version
|
|
39
|
+
* before it had only two and used `0` for both "none match" and "we do not
|
|
40
|
+
* know" — which is how a storefront came to print "About 0 listings" over
|
|
41
|
+
* four visible cards.
|
|
42
|
+
*/
|
|
43
|
+
export type SearchCountKind = "exact" | "at_least" | "unknown";
|
|
44
|
+
/**
|
|
45
|
+
* Read the envelope's three count fields as one decision.
|
|
46
|
+
*
|
|
47
|
+
* `null` is UNKNOWN and renders as no count line — never as `0`, and never
|
|
48
|
+
* as "about 0". Anything the server declines to call exact is rendered as a
|
|
49
|
+
* floor ("N+"), including the defensive case of an `exact_total: false` from
|
|
50
|
+
* a server that predates `count_is_lower_bound`: claiming "at least N" over
|
|
51
|
+
* a page that shows N rows is the one reading that cannot be contradicted by
|
|
52
|
+
* what the reader can see.
|
|
53
|
+
*/
|
|
54
|
+
export declare function countKind(count: number | null | undefined, isLowerBound: boolean | undefined, exactTotal: boolean, degradations: readonly SearchDegradation[]): SearchCountKind;
|
|
55
|
+
/**
|
|
56
|
+
* Is `exact_total` the ONLY thing the engine could not do?
|
|
57
|
+
*
|
|
58
|
+
* It is a count NUANCE, not a failed search: the answer is complete, the
|
|
59
|
+
* rows are the right rows, and the single consequence — that the total is a
|
|
60
|
+
* floor — is already spoken by the count itself as "N+". Raising a warning
|
|
61
|
+
* banner over it teaches a reader that a perfectly good result page is
|
|
62
|
+
* broken, and a banner that cries wolf on every landing page is a banner
|
|
63
|
+
* nobody reads on the day `category_rollup` shows up in it.
|
|
64
|
+
*
|
|
65
|
+
* Every other degradation changes what the page MEANS ("typos were not
|
|
66
|
+
* corrected", "subcategories may be missing", "counts are approximate") and
|
|
67
|
+
* still renders. So does `exact_total` when it arrives BESIDE one of them —
|
|
68
|
+
* the list is then a description of a genuinely degraded answer.
|
|
69
|
+
*/
|
|
70
|
+
export declare function isCountNuanceOnly(degradations: readonly SearchDegradation[]): boolean;
|
|
30
71
|
//# sourceMappingURL=degradations.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"degradations.d.ts","sourceRoot":"","sources":["../../src/state/degradations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAYhF,+CAA+C;AAC/C,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,qBAAqB,GAAG,MAAM,CAEzE;AAED,0DAA0D;AAC1D,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GACtC,SAAS,iBAAiB,EAAE,CAwB9B;AAED
|
|
1
|
+
{"version":3,"file":"degradations.d.ts","sourceRoot":"","sources":["../../src/state/degradations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAYhF,+CAA+C;AAC/C,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,qBAAqB,GAAG,MAAM,CAEzE;AAED,0DAA0D;AAC1D,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GACtC,SAAS,iBAAiB,EAAE,CAwB9B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,OAAO,EACnB,YAAY,EAAE,SAAS,iBAAiB,EAAE,GACzC,OAAO,CAET;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC;AAE/D;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAChC,YAAY,EAAE,OAAO,GAAG,SAAS,EACjC,UAAU,EAAE,OAAO,EACnB,YAAY,EAAE,SAAS,iBAAiB,EAAE,GACzC,eAAe,CAIjB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,SAAS,iBAAiB,EAAE,GACzC,OAAO,CAKT"}
|
|
@@ -45,8 +45,49 @@ export function parseDegradations(degraded) {
|
|
|
45
45
|
* the envelope's own `exact_total: false`, and the `"exact_total"`
|
|
46
46
|
* degradation. They agree in practice; treating either as decisive is what
|
|
47
47
|
* keeps "≈1 200" from ever being rendered as "1 200".
|
|
48
|
+
*
|
|
49
|
+
* @deprecated Since stapel-search 0.2.0 the envelope answers this directly
|
|
50
|
+
* with `count_is_lower_bound`, and "not exact" now means a FLOOR rather than
|
|
51
|
+
* a fuzzy number. Use {@link countKind}, which reads the wire field and also
|
|
52
|
+
* handles `count: null`.
|
|
48
53
|
*/
|
|
49
54
|
export function countIsEstimate(exactTotal, degradations) {
|
|
50
55
|
return !exactTotal || degradations.some((d) => d.kind === "exact_total");
|
|
51
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Read the envelope's three count fields as one decision.
|
|
59
|
+
*
|
|
60
|
+
* `null` is UNKNOWN and renders as no count line — never as `0`, and never
|
|
61
|
+
* as "about 0". Anything the server declines to call exact is rendered as a
|
|
62
|
+
* floor ("N+"), including the defensive case of an `exact_total: false` from
|
|
63
|
+
* a server that predates `count_is_lower_bound`: claiming "at least N" over
|
|
64
|
+
* a page that shows N rows is the one reading that cannot be contradicted by
|
|
65
|
+
* what the reader can see.
|
|
66
|
+
*/
|
|
67
|
+
export function countKind(count, isLowerBound, exactTotal, degradations) {
|
|
68
|
+
if (count === null || count === undefined)
|
|
69
|
+
return "unknown";
|
|
70
|
+
if (isLowerBound === true)
|
|
71
|
+
return "at_least";
|
|
72
|
+
return countIsEstimate(exactTotal, degradations) ? "at_least" : "exact";
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Is `exact_total` the ONLY thing the engine could not do?
|
|
76
|
+
*
|
|
77
|
+
* It is a count NUANCE, not a failed search: the answer is complete, the
|
|
78
|
+
* rows are the right rows, and the single consequence — that the total is a
|
|
79
|
+
* floor — is already spoken by the count itself as "N+". Raising a warning
|
|
80
|
+
* banner over it teaches a reader that a perfectly good result page is
|
|
81
|
+
* broken, and a banner that cries wolf on every landing page is a banner
|
|
82
|
+
* nobody reads on the day `category_rollup` shows up in it.
|
|
83
|
+
*
|
|
84
|
+
* Every other degradation changes what the page MEANS ("typos were not
|
|
85
|
+
* corrected", "subcategories may be missing", "counts are approximate") and
|
|
86
|
+
* still renders. So does `exact_total` when it arrives BESIDE one of them —
|
|
87
|
+
* the list is then a description of a genuinely degraded answer.
|
|
88
|
+
*/
|
|
89
|
+
export function isCountNuanceOnly(degradations) {
|
|
90
|
+
return (degradations.length > 0 &&
|
|
91
|
+
degradations.every((degradation) => degradation.kind === "exact_total"));
|
|
92
|
+
}
|
|
52
93
|
//# sourceMappingURL=degradations.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"degradations.js","sourceRoot":"","sources":["../../src/state/degradations.ts"],"names":[],"mappings":"AAiBA,MAAM,aAAa,GAAG,SAAS,CAAC;AAEhC,MAAM,KAAK,GAAoD;IAC7D,cAAc,EAAE,gBAAgB;IAChC,eAAe,EAAE,iBAAiB;IAClC,WAAW,EAAE,aAAa;IAC1B,kBAAkB,EAAE,oBAAoB;IACxC,eAAe,EAAE,iBAAiB;CACnC,CAAC;AAEF,+CAA+C;AAC/C,MAAM,UAAU,qBAAqB,CAAC,IAA2B;IAC/D,OAAO,mBAAmB,IAAI,EAAE,CAAC;AACnC,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,iBAAiB,CAC/B,QAAuC;IAEvC,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACtC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,GAAG,GAAwB,EAAE,CAAC;IACpC,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,IAAI,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;YAClC,GAAG,CAAC,IAAI,CAAC;gBACP,IAAI,EAAE,QAAQ;gBACd,GAAG;gBACH,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC;gBACvC,UAAU,EAAE,qBAAqB,CAAC,QAAQ,CAAC;aAC5C,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QACxB,GAAG,CAAC,IAAI,CAAC;YACP,IAAI,EAAE,IAAI,IAAI,SAAS;YACvB,GAAG;YACH,UAAU,EAAE,qBAAqB,CAAC,IAAI,IAAI,SAAS,CAAC;SACrD,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"degradations.js","sourceRoot":"","sources":["../../src/state/degradations.ts"],"names":[],"mappings":"AAiBA,MAAM,aAAa,GAAG,SAAS,CAAC;AAEhC,MAAM,KAAK,GAAoD;IAC7D,cAAc,EAAE,gBAAgB;IAChC,eAAe,EAAE,iBAAiB;IAClC,WAAW,EAAE,aAAa;IAC1B,kBAAkB,EAAE,oBAAoB;IACxC,eAAe,EAAE,iBAAiB;CACnC,CAAC;AAEF,+CAA+C;AAC/C,MAAM,UAAU,qBAAqB,CAAC,IAA2B;IAC/D,OAAO,mBAAmB,IAAI,EAAE,CAAC;AACnC,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,iBAAiB,CAC/B,QAAuC;IAEvC,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACtC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,GAAG,GAAwB,EAAE,CAAC;IACpC,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,IAAI,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;YAClC,GAAG,CAAC,IAAI,CAAC;gBACP,IAAI,EAAE,QAAQ;gBACd,GAAG;gBACH,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC;gBACvC,UAAU,EAAE,qBAAqB,CAAC,QAAQ,CAAC;aAC5C,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QACxB,GAAG,CAAC,IAAI,CAAC;YACP,IAAI,EAAE,IAAI,IAAI,SAAS;YACvB,GAAG;YACH,UAAU,EAAE,qBAAqB,CAAC,IAAI,IAAI,SAAS,CAAC;SACrD,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAC7B,UAAmB,EACnB,YAA0C;IAE1C,OAAO,CAAC,UAAU,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC,CAAC;AAC3E,CAAC;AAYD;;;;;;;;;GASG;AACH,MAAM,UAAU,SAAS,CACvB,KAAgC,EAChC,YAAiC,EACjC,UAAmB,EACnB,YAA0C;IAE1C,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC5D,IAAI,YAAY,KAAK,IAAI;QAAE,OAAO,UAAU,CAAC;IAC7C,OAAO,eAAe,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC;AAC1E,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,iBAAiB,CAC/B,YAA0C;IAE1C,OAAO,CACL,YAAY,CAAC,MAAM,GAAG,CAAC;QACvB,YAAY,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,KAAK,aAAa,CAAC,CACxE,CAAC;AACJ,CAAC"}
|
package/llms.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# @stapel/search-react 0.
|
|
1
|
+
# @stapel/search-react 0.4.0
|
|
2
2
|
|
|
3
|
-
Headless React flow pair for stapel-search (contract >=0.
|
|
3
|
+
Headless React flow pair for stapel-search (contract >=0.2 <0.3) — business + state, zero visual opinion.
|
|
4
4
|
Built on @stapel/core: typed client + StapelApiError envelope, auth token refresh,
|
|
5
5
|
verification-403 interception, i18n engine, analytics facade, TanStack Query layer.
|
|
6
6
|
|
package/manifest.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
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.
|
|
4
|
+
"version": "0.4.0",
|
|
5
5
|
"backend": {
|
|
6
6
|
"module": "stapel-search",
|
|
7
|
-
"contract": ">=0.
|
|
7
|
+
"contract": ">=0.2 <0.3"
|
|
8
8
|
},
|
|
9
9
|
"layers": [
|
|
10
10
|
"api",
|
|
@@ -534,6 +534,9 @@
|
|
|
534
534
|
"search.results.count_approximate",
|
|
535
535
|
"search.results.count_approximate.one",
|
|
536
536
|
"search.results.count_approximate.other",
|
|
537
|
+
"search.results.count_at_least",
|
|
538
|
+
"search.results.count_at_least.one",
|
|
539
|
+
"search.results.count_at_least.other",
|
|
537
540
|
"search.results.count_exact",
|
|
538
541
|
"search.results.count_exact.one",
|
|
539
542
|
"search.results.count_exact.other",
|
|
@@ -586,11 +589,13 @@
|
|
|
586
589
|
"buildFacetGroups",
|
|
587
590
|
"clearFilters",
|
|
588
591
|
"countIsEstimate",
|
|
592
|
+
"countKind",
|
|
589
593
|
"createSearchApi",
|
|
590
594
|
"createSearchRuntime",
|
|
591
595
|
"degradationMessageKey",
|
|
592
596
|
"explainSearchError",
|
|
593
597
|
"facetOptionLabel",
|
|
598
|
+
"isCountNuanceOnly",
|
|
594
599
|
"navEntries",
|
|
595
600
|
"ownsParam",
|
|
596
601
|
"parseDegradations",
|
|
@@ -629,6 +634,7 @@
|
|
|
629
634
|
"Schemas",
|
|
630
635
|
"Scorer",
|
|
631
636
|
"SearchApi",
|
|
637
|
+
"SearchCountKind",
|
|
632
638
|
"SearchDegradation",
|
|
633
639
|
"SearchDegradationKind",
|
|
634
640
|
"SearchErrorCode",
|
package/nav-manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stapel/search-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.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,10 +112,10 @@
|
|
|
112
112
|
"typescript": "^5.8.3",
|
|
113
113
|
"vitest": "^3.2.4",
|
|
114
114
|
"@stapel/attributes-react": "^0.2.0",
|
|
115
|
-
"@stapel/core": "^0.17.0",
|
|
116
115
|
"@stapel/showcase": "^0.2.0",
|
|
117
116
|
"@stapel/tokens": "^0.5.0",
|
|
118
|
-
"@stapel/tokens-antd": "^0.5.0"
|
|
117
|
+
"@stapel/tokens-antd": "^0.5.0",
|
|
118
|
+
"@stapel/core": "^0.17.0"
|
|
119
119
|
},
|
|
120
120
|
"engines": {
|
|
121
121
|
"node": ">=22"
|
|
@@ -213,7 +213,11 @@ export interface components {
|
|
|
213
213
|
prev_anchor: string | null;
|
|
214
214
|
has_next: boolean;
|
|
215
215
|
has_prev: boolean;
|
|
216
|
-
count
|
|
216
|
+
/** @description How many documents match. NEVER 0 beside a non-empty items[] — the answer may not claim fewer matches than the page shows. `null` means the engine cannot say, and is rendered as no count at all. */
|
|
217
|
+
count: number | null;
|
|
218
|
+
/** @description True when `count` is a floor: at least this many match, possibly more (a capped count, a window-truncated engine answer). Render 'N+', never 'N'. */
|
|
219
|
+
count_is_lower_bound: boolean;
|
|
220
|
+
/** @description True when `count` is exact for THIS answer — equivalent to `count is not null and not count_is_lower_bound`. Per answer, not per engine: an engine without a guaranteed exact total still counts a small candidate set exactly. */
|
|
217
221
|
exact_total: boolean;
|
|
218
222
|
/** @description What the configured engine could not do for this query. */
|
|
219
223
|
degraded: string[];
|
|
@@ -9,41 +9,89 @@
|
|
|
9
9
|
* An `unknown` degradation still renders — with the raw literal, because a
|
|
10
10
|
* build that predates a new limitation should say "the engine reported
|
|
11
11
|
* something we have no wording for: X", not nothing at all.
|
|
12
|
+
*
|
|
13
|
+
* ── Two deliberate ways NOT to shout ───────────────────────────────────────
|
|
14
|
+
*
|
|
15
|
+
* 1. **`exact_total` alone never raises a banner.** It is a count NUANCE, not
|
|
16
|
+
* a failed search: the rows are right, and the single consequence — that
|
|
17
|
+
* the total is a floor — is already spoken by the count as "N+". A warning
|
|
18
|
+
* box over a perfectly good result page teaches the reader that the page
|
|
19
|
+
* is broken, and a banner that cries wolf on every landing page is a
|
|
20
|
+
* banner nobody reads on the day `category_rollup` appears in it. Beside
|
|
21
|
+
* any other degradation it renders normally, because the list is then
|
|
22
|
+
* describing an answer that really is degraded. See
|
|
23
|
+
* {@link isCountNuanceOnly}.
|
|
24
|
+
* 2. **`variant`.** A catalogue page wants the banner; a landing page that
|
|
25
|
+
* shows six cards under a hero has no room for a warning box and passes
|
|
26
|
+
* `"inline"` (one quiet line) or `"off"`. `"off"` is a decision the
|
|
27
|
+
* CONTAINER makes about ITS surface — the notice stays the default, and
|
|
28
|
+
* nothing here silences a degradation for everyone.
|
|
12
29
|
*/
|
|
13
30
|
import type { ReactElement } from "react";
|
|
14
|
-
import { Alert, Typography } from "antd";
|
|
31
|
+
import { Alert, Flex, Typography } from "antd";
|
|
15
32
|
import { useT } from "@stapel/core";
|
|
16
33
|
import type { SearchDegradation } from "../api/types.js";
|
|
34
|
+
import { isCountNuanceOnly } from "../state/degradations.js";
|
|
17
35
|
import { SEARCH_I18N_KEYS } from "../i18n/keys.js";
|
|
18
36
|
|
|
37
|
+
/**
|
|
38
|
+
* How loudly a surface says what the engine could not do.
|
|
39
|
+
*
|
|
40
|
+
* - `"banner"` (default) — an antd warning `Alert` with one line per item.
|
|
41
|
+
* - `"inline"` — the same sentences as quiet secondary text, no box.
|
|
42
|
+
* - `"off"` — nothing. For a surface where the notice does not belong at all;
|
|
43
|
+
* the container that turns it off owns saying so somewhere else.
|
|
44
|
+
*/
|
|
45
|
+
export type DegradationNoticeVariant = "banner" | "inline" | "off";
|
|
46
|
+
|
|
19
47
|
export interface DegradationNoticeProps {
|
|
20
48
|
readonly degradations: readonly SearchDegradation[];
|
|
49
|
+
readonly variant?: DegradationNoticeVariant;
|
|
21
50
|
}
|
|
22
51
|
|
|
23
52
|
export function DegradationNotice(
|
|
24
53
|
props: DegradationNoticeProps
|
|
25
54
|
): ReactElement | null {
|
|
26
55
|
const t = useT();
|
|
56
|
+
const variant: DegradationNoticeVariant = props.variant ?? "banner";
|
|
57
|
+
if (variant === "off") return null;
|
|
27
58
|
if (props.degradations.length === 0) return null;
|
|
59
|
+
// A count nuance is not a degraded search — the count already says "N+".
|
|
60
|
+
if (isCountNuanceOnly(props.degradations)) return null;
|
|
61
|
+
|
|
62
|
+
const lines = props.degradations.map((degradation) => (
|
|
63
|
+
<li key={degradation.raw} data-degradation={degradation.raw}>
|
|
64
|
+
<Typography.Text type="secondary">
|
|
65
|
+
{t(degradation.messageKey, {
|
|
66
|
+
scorer: degradation.scorer ?? "",
|
|
67
|
+
raw: degradation.raw,
|
|
68
|
+
})}
|
|
69
|
+
</Typography.Text>
|
|
70
|
+
</li>
|
|
71
|
+
));
|
|
72
|
+
|
|
73
|
+
if (variant === "inline") {
|
|
74
|
+
return (
|
|
75
|
+
<Flex vertical gap={2} data-testid="search-degraded" data-variant="inline">
|
|
76
|
+
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
|
|
77
|
+
{t(SEARCH_I18N_KEYS.degradedTitle)}
|
|
78
|
+
</Typography.Text>
|
|
79
|
+
<ul style={{ margin: 0, paddingInlineStart: 20, fontSize: 12 }}>
|
|
80
|
+
{lines}
|
|
81
|
+
</ul>
|
|
82
|
+
</Flex>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
28
86
|
return (
|
|
29
87
|
<Alert
|
|
30
88
|
type="warning"
|
|
31
89
|
showIcon
|
|
32
90
|
data-testid="search-degraded"
|
|
91
|
+
data-variant="banner"
|
|
33
92
|
message={t(SEARCH_I18N_KEYS.degradedTitle)}
|
|
34
93
|
description={
|
|
35
|
-
<ul style={{ margin: 0, paddingInlineStart: 20 }}>
|
|
36
|
-
{props.degradations.map((degradation) => (
|
|
37
|
-
<li key={degradation.raw} data-degradation={degradation.raw}>
|
|
38
|
-
<Typography.Text type="secondary">
|
|
39
|
-
{t(degradation.messageKey, {
|
|
40
|
-
scorer: degradation.scorer ?? "",
|
|
41
|
-
raw: degradation.raw,
|
|
42
|
-
})}
|
|
43
|
-
</Typography.Text>
|
|
44
|
-
</li>
|
|
45
|
-
))}
|
|
46
|
-
</ul>
|
|
94
|
+
<ul style={{ margin: 0, paddingInlineStart: 20 }}>{lines}</ul>
|
|
47
95
|
}
|
|
48
96
|
/>
|
|
49
97
|
);
|
|
@@ -23,6 +23,7 @@ import type { ParseSearchStateOptions } from "../state/urlState.js";
|
|
|
23
23
|
import { FacetPanelPane } from "./FacetPanelPane.js";
|
|
24
24
|
import { SearchResultsPane } from "./SearchResultsPane.js";
|
|
25
25
|
import { SortSelect } from "./SortSelect.js";
|
|
26
|
+
import type { DegradationNoticeVariant } from "./DegradationNotice.js";
|
|
26
27
|
import type { SearchCardRenderer } from "./SearchResultCard.js";
|
|
27
28
|
import { SearchSkinTheme } from "./theme.js";
|
|
28
29
|
import { UrlIssueNotice } from "./UrlIssueNotice.js";
|
|
@@ -37,6 +38,9 @@ export interface SearchPageProps extends ThemeModeProp, ParseSearchStateOptions
|
|
|
37
38
|
readonly locale?: string;
|
|
38
39
|
/** Container chrome under the results — e.g. the ranking-disclosure link. */
|
|
39
40
|
readonly footer?: ReactNode;
|
|
41
|
+
/** How the results surface says what the engine could not do (default
|
|
42
|
+
* `"banner"`). Handed straight to `<SearchResultsPane>`. */
|
|
43
|
+
readonly degradationNotice?: DegradationNoticeVariant;
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
export function SearchPage(props: SearchPageProps): ReactElement {
|
|
@@ -46,6 +50,7 @@ export function SearchPage(props: SearchPageProps): ReactElement {
|
|
|
46
50
|
categoryFeatures,
|
|
47
51
|
locale,
|
|
48
52
|
footer,
|
|
53
|
+
degradationNotice,
|
|
49
54
|
mode,
|
|
50
55
|
...parseOptions
|
|
51
56
|
} = props;
|
|
@@ -72,6 +77,9 @@ export function SearchPage(props: SearchPageProps): ReactElement {
|
|
|
72
77
|
toolbar={<SortSelect />}
|
|
73
78
|
{...(renderCard !== undefined ? { renderCard } : {})}
|
|
74
79
|
{...(footer !== undefined ? { footer } : {})}
|
|
80
|
+
{...(degradationNotice !== undefined
|
|
81
|
+
? { degradationNotice }
|
|
82
|
+
: {})}
|
|
75
83
|
/>
|
|
76
84
|
</Col>
|
|
77
85
|
</Row>
|
|
@@ -29,6 +29,7 @@ import type { SearchResultsBag } from "../headless/SearchResults.js";
|
|
|
29
29
|
import { SEARCH_WINDOW_EXCEEDED } from "../i18n/errorsMap.js";
|
|
30
30
|
import { SEARCH_I18N_KEYS } from "../i18n/keys.js";
|
|
31
31
|
import { DegradationNotice } from "./DegradationNotice.js";
|
|
32
|
+
import type { DegradationNoticeVariant } from "./DegradationNotice.js";
|
|
32
33
|
import { ErrorAlert } from "./ErrorAlert.js";
|
|
33
34
|
import { SearchResultCard } from "./SearchResultCard.js";
|
|
34
35
|
import type { SearchCardRenderer } from "./SearchResultCard.js";
|
|
@@ -82,6 +83,17 @@ export interface SearchResultsPaneProps extends ThemeModeProp {
|
|
|
82
83
|
readonly toolbar?: ReactNode;
|
|
83
84
|
/** Rendered under the pager — where the container puts the ranking link. */
|
|
84
85
|
readonly footer?: ReactNode;
|
|
86
|
+
/**
|
|
87
|
+
* How this surface says what the engine could not do (default `"banner"`).
|
|
88
|
+
*
|
|
89
|
+
* A catalogue page wants the warning box. A landing page showing six cards
|
|
90
|
+
* under a hero has no room for one and passes `"inline"` or `"off"` — a
|
|
91
|
+
* decision about THIS surface, not about whether the degradation matters.
|
|
92
|
+
* Note that an `exact_total`-only degradation never raises a banner under
|
|
93
|
+
* any variant: it is a count nuance the count itself already speaks as
|
|
94
|
+
* "N+", not a failed search.
|
|
95
|
+
*/
|
|
96
|
+
readonly degradationNotice?: DegradationNoticeVariant;
|
|
85
97
|
readonly enabled?: boolean;
|
|
86
98
|
}
|
|
87
99
|
|
|
@@ -92,12 +104,18 @@ function Count(props: { bag: SearchResultsBag }): ReactElement | null {
|
|
|
92
104
|
const tPlural = useTPlural();
|
|
93
105
|
const page = props.bag.page;
|
|
94
106
|
if (page === null) return null;
|
|
107
|
+
// No count line at all when the server cannot say. The alternative — some
|
|
108
|
+
// number — is how "About 0 listings" ended up printed over four visible
|
|
109
|
+
// cards: an unknown total rendered as a claim about the catalogue.
|
|
110
|
+
if (page.countKind === "unknown" || page.count === null) return null;
|
|
95
111
|
return (
|
|
96
|
-
<Typography.Text
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
112
|
+
<Typography.Text
|
|
113
|
+
type="secondary"
|
|
114
|
+
data-testid="search-count"
|
|
115
|
+
data-count-kind={page.countKind}
|
|
116
|
+
>
|
|
117
|
+
{page.countKind === "at_least"
|
|
118
|
+
? tPlural(SEARCH_I18N_KEYS.resultsCountAtLeast, { count: page.count })
|
|
101
119
|
: tPlural(SEARCH_I18N_KEYS.resultsCountExact, { count: page.count })}
|
|
102
120
|
</Typography.Text>
|
|
103
121
|
);
|
|
@@ -152,7 +170,10 @@ export function SearchResultsPane(props: SearchResultsPaneProps): ReactElement {
|
|
|
152
170
|
</Flex>
|
|
153
171
|
</Flex>
|
|
154
172
|
|
|
155
|
-
<DegradationNotice
|
|
173
|
+
<DegradationNotice
|
|
174
|
+
degradations={bag.degradations}
|
|
175
|
+
variant={props.degradationNotice ?? "banner"}
|
|
176
|
+
/>
|
|
156
177
|
|
|
157
178
|
{matchList(bag.state, {
|
|
158
179
|
loading: () => (
|
package/src/default/index.ts
CHANGED
|
@@ -41,7 +41,10 @@ export type { RankingDisclosurePaneProps } from "./RankingDisclosurePane.js";
|
|
|
41
41
|
export { SearchResultCard, GENERIC_CARD_FIELDS } from "./SearchResultCard.js";
|
|
42
42
|
export type { SearchCardProps, SearchCardRenderer } from "./SearchResultCard.js";
|
|
43
43
|
export { DegradationNotice } from "./DegradationNotice.js";
|
|
44
|
-
export type {
|
|
44
|
+
export type {
|
|
45
|
+
DegradationNoticeProps,
|
|
46
|
+
DegradationNoticeVariant,
|
|
47
|
+
} from "./DegradationNotice.js";
|
|
45
48
|
export { UrlIssueNotice } from "./UrlIssueNotice.js";
|
|
46
49
|
export { SortSelect } from "./SortSelect.js";
|
|
47
50
|
export type { SortSelectProps } from "./SortSelect.js";
|
|
@@ -15,15 +15,36 @@ import type {
|
|
|
15
15
|
} from "../api/types.js";
|
|
16
16
|
import { SEARCH_I18N_KEYS } from "../i18n/keys.js";
|
|
17
17
|
import { useSearchQuery } from "../model/queries.js";
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
countIsEstimate,
|
|
20
|
+
countKind,
|
|
21
|
+
parseDegradations,
|
|
22
|
+
} from "../state/degradations.js";
|
|
23
|
+
import type { SearchCountKind } from "../state/degradations.js";
|
|
19
24
|
import { useSearchState } from "./SearchStateProvider.js";
|
|
20
25
|
|
|
21
26
|
/** What the envelope says about this page, beside the rows. */
|
|
22
27
|
export interface SearchPageInfo {
|
|
23
|
-
/**
|
|
24
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Total matches, or `null` when the engine cannot say — which is a real
|
|
30
|
+
* state and NOT zero. Read it together with {@link SearchPageInfo.countKind}:
|
|
31
|
+
* a `count` under `"at_least"` is a floor, not a total.
|
|
32
|
+
*/
|
|
33
|
+
readonly count: number | null;
|
|
25
34
|
readonly exactTotal: boolean;
|
|
26
|
-
/**
|
|
35
|
+
/** The server's own word: `count` is a floor ("at least N"), not a total. */
|
|
36
|
+
readonly countIsLowerBound: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* The one value a skin needs to choose a sentence: `"exact"` → "N",
|
|
39
|
+
* `"at_least"` → "N+", `"unknown"` → no count at all.
|
|
40
|
+
*/
|
|
41
|
+
readonly countKind: SearchCountKind;
|
|
42
|
+
/**
|
|
43
|
+
* `true` when `count` must not be rendered as a plain number.
|
|
44
|
+
*
|
|
45
|
+
* @deprecated Equivalent to `countKind !== "exact"` and blind to
|
|
46
|
+
* `count: null`. Use {@link SearchPageInfo.countKind}.
|
|
47
|
+
*/
|
|
27
48
|
readonly countIsEstimate: boolean;
|
|
28
49
|
readonly hasNext: boolean;
|
|
29
50
|
readonly hasPrev: boolean;
|
|
@@ -102,6 +123,13 @@ export function SearchResults(props: {
|
|
|
102
123
|
: {
|
|
103
124
|
count: data.count,
|
|
104
125
|
exactTotal: data.exact_total,
|
|
126
|
+
countIsLowerBound: data.count_is_lower_bound === true,
|
|
127
|
+
countKind: countKind(
|
|
128
|
+
data.count,
|
|
129
|
+
data.count_is_lower_bound,
|
|
130
|
+
data.exact_total,
|
|
131
|
+
degradations
|
|
132
|
+
),
|
|
105
133
|
countIsEstimate: countIsEstimate(data.exact_total, degradations),
|
|
106
134
|
hasNext: data.has_next,
|
|
107
135
|
hasPrev: data.has_prev,
|
package/src/i18n/es.ts
CHANGED
|
@@ -22,6 +22,8 @@ export const searchI18nBundleEs: I18nDictionary = {
|
|
|
22
22
|
"search.results.retry": "Reintentar",
|
|
23
23
|
"search.results.count_approximate.one": "Aproximadamente {count} resultado",
|
|
24
24
|
"search.results.count_approximate.other": "Unos {count} resultados",
|
|
25
|
+
"search.results.count_at_least.one": "{count}+ resultado",
|
|
26
|
+
"search.results.count_at_least.other": "{count}+ resultados",
|
|
25
27
|
"search.results.count_exact.one": "{count} resultado",
|
|
26
28
|
"search.results.count_exact.other": "{count} resultados",
|
|
27
29
|
"search.results.took_ms": "{ms} ms",
|