@stapel/search-react 0.4.0 → 0.7.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 (139) hide show
  1. package/CHANGELOG.md +151 -0
  2. package/README.md +1 -1
  3. package/dist/default/DegradationNotice.d.ts +7 -0
  4. package/dist/default/DegradationNotice.d.ts.map +1 -1
  5. package/dist/default/DegradationNotice.js +17 -6
  6. package/dist/default/DegradationNotice.js.map +1 -1
  7. package/dist/default/FacetPanelPane.d.ts +54 -3
  8. package/dist/default/FacetPanelPane.d.ts.map +1 -1
  9. package/dist/default/FacetPanelPane.js +119 -19
  10. package/dist/default/FacetPanelPane.js.map +1 -1
  11. package/dist/default/LanguageSelect.d.ts +9 -0
  12. package/dist/default/LanguageSelect.d.ts.map +1 -0
  13. package/dist/default/LanguageSelect.js +72 -0
  14. package/dist/default/LanguageSelect.js.map +1 -0
  15. package/dist/default/PageSizeSelect.d.ts +29 -0
  16. package/dist/default/PageSizeSelect.d.ts.map +1 -0
  17. package/dist/default/PageSizeSelect.js +25 -0
  18. package/dist/default/PageSizeSelect.js.map +1 -0
  19. package/dist/default/RangeFilterRow.d.ts +12 -0
  20. package/dist/default/RangeFilterRow.d.ts.map +1 -0
  21. package/dist/default/RangeFilterRow.js +75 -0
  22. package/dist/default/RangeFilterRow.js.map +1 -0
  23. package/dist/default/RankingDisclosurePane.d.ts +5 -0
  24. package/dist/default/RankingDisclosurePane.d.ts.map +1 -1
  25. package/dist/default/RankingDisclosurePane.js +15 -15
  26. package/dist/default/RankingDisclosurePane.js.map +1 -1
  27. package/dist/default/SearchBox.d.ts +13 -0
  28. package/dist/default/SearchBox.d.ts.map +1 -0
  29. package/dist/default/SearchBox.js +67 -0
  30. package/dist/default/SearchBox.js.map +1 -0
  31. package/dist/default/SearchPage.d.ts +54 -16
  32. package/dist/default/SearchPage.d.ts.map +1 -1
  33. package/dist/default/SearchPage.js +155 -8
  34. package/dist/default/SearchPage.js.map +1 -1
  35. package/dist/default/SearchResultCard.d.ts +19 -18
  36. package/dist/default/SearchResultCard.d.ts.map +1 -1
  37. package/dist/default/SearchResultCard.js +178 -5
  38. package/dist/default/SearchResultCard.js.map +1 -1
  39. package/dist/default/SearchResultsPane.d.ts +42 -3
  40. package/dist/default/SearchResultsPane.d.ts.map +1 -1
  41. package/dist/default/SearchResultsPane.js +38 -21
  42. package/dist/default/SearchResultsPane.js.map +1 -1
  43. package/dist/default/SortSelect.d.ts +10 -2
  44. package/dist/default/SortSelect.d.ts.map +1 -1
  45. package/dist/default/SortSelect.js +27 -24
  46. package/dist/default/SortSelect.js.map +1 -1
  47. package/dist/default/UrlIssueNotice.d.ts.map +1 -1
  48. package/dist/default/UrlIssueNotice.js +19 -1
  49. package/dist/default/UrlIssueNotice.js.map +1 -1
  50. package/dist/default/index.d.ts +32 -15
  51. package/dist/default/index.d.ts.map +1 -1
  52. package/dist/default/index.js +26 -12
  53. package/dist/default/index.js.map +1 -1
  54. package/dist/default/sortLabels.d.ts +5 -0
  55. package/dist/default/sortLabels.d.ts.map +1 -0
  56. package/dist/default/sortLabels.js +32 -0
  57. package/dist/default/sortLabels.js.map +1 -0
  58. package/dist/headless/FacetPanel.d.ts +17 -0
  59. package/dist/headless/FacetPanel.d.ts.map +1 -1
  60. package/dist/headless/FacetPanel.js +23 -2
  61. package/dist/headless/FacetPanel.js.map +1 -1
  62. package/dist/headless/useAppliedCount.d.ts +8 -0
  63. package/dist/headless/useAppliedCount.d.ts.map +1 -0
  64. package/dist/headless/useAppliedCount.js +30 -0
  65. package/dist/headless/useAppliedCount.js.map +1 -0
  66. package/dist/headless/useScorerNames.d.ts +4 -0
  67. package/dist/headless/useScorerNames.d.ts.map +1 -0
  68. package/dist/headless/useScorerNames.js +34 -0
  69. package/dist/headless/useScorerNames.js.map +1 -0
  70. package/dist/headless/useSearchBox.d.ts +44 -0
  71. package/dist/headless/useSearchBox.d.ts.map +1 -0
  72. package/dist/headless/useSearchBox.js +116 -0
  73. package/dist/headless/useSearchBox.js.map +1 -0
  74. package/dist/i18n/es.d.ts.map +1 -1
  75. package/dist/i18n/es.js +30 -4
  76. package/dist/i18n/es.js.map +1 -1
  77. package/dist/i18n/keys.d.ts +35 -0
  78. package/dist/i18n/keys.d.ts.map +1 -1
  79. package/dist/i18n/keys.js +72 -4
  80. package/dist/i18n/keys.js.map +1 -1
  81. package/dist/i18n/ru.d.ts.map +1 -1
  82. package/dist/i18n/ru.js +34 -4
  83. package/dist/i18n/ru.js.map +1 -1
  84. package/dist/index.d.ts +7 -2
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/index.js +5 -2
  87. package/dist/index.js.map +1 -1
  88. package/dist/model/queries.d.ts +26 -2
  89. package/dist/model/queries.d.ts.map +1 -1
  90. package/dist/model/queries.js +38 -1
  91. package/dist/model/queries.js.map +1 -1
  92. package/dist/state/limits.d.ts +44 -0
  93. package/dist/state/limits.d.ts.map +1 -0
  94. package/dist/state/limits.js +44 -0
  95. package/dist/state/limits.js.map +1 -0
  96. package/dist/state/ranges.d.ts +52 -0
  97. package/dist/state/ranges.d.ts.map +1 -0
  98. package/dist/state/ranges.js +108 -0
  99. package/dist/state/ranges.js.map +1 -0
  100. package/llms.txt +15 -4
  101. package/manifest.json +238 -21
  102. package/nav-manifest.json +1 -1
  103. package/package.json +15 -10
  104. package/src/analytics/generated/events.json +1 -1
  105. package/src/default/DegradationNotice.tsx +34 -12
  106. package/src/default/FacetPanelPane.tsx +343 -64
  107. package/src/default/LanguageSelect.tsx +93 -0
  108. package/src/default/PageSizeSelect.tsx +80 -0
  109. package/src/default/RangeFilterRow.tsx +148 -0
  110. package/src/default/RankingDisclosurePane.tsx +67 -35
  111. package/src/default/SearchBox.tsx +130 -0
  112. package/src/default/SearchPage.tsx +351 -44
  113. package/src/default/SearchResultCard.tsx +231 -24
  114. package/src/default/SearchResultsPane.tsx +120 -70
  115. package/src/default/SortSelect.tsx +50 -37
  116. package/src/default/UrlIssueNotice.tsx +21 -3
  117. package/src/default/index.ts +38 -15
  118. package/src/default/sortLabels.ts +34 -0
  119. package/src/headless/FacetPanel.tsx +30 -2
  120. package/src/headless/useAppliedCount.ts +41 -0
  121. package/src/headless/useScorerNames.ts +36 -0
  122. package/src/headless/useSearchBox.ts +189 -0
  123. package/src/i18n/es.ts +37 -4
  124. package/src/i18n/keys.ts +83 -4
  125. package/src/i18n/ru.ts +41 -4
  126. package/src/index.ts +22 -2
  127. package/src/model/queries.ts +51 -1
  128. package/src/state/limits.ts +50 -0
  129. package/src/state/ranges.ts +144 -0
  130. package/dist/default/ErrorAlert.d.ts +0 -9
  131. package/dist/default/ErrorAlert.d.ts.map +0 -1
  132. package/dist/default/ErrorAlert.js +0 -27
  133. package/dist/default/ErrorAlert.js.map +0 -1
  134. package/dist/default/theme.d.ts +0 -24
  135. package/dist/default/theme.d.ts.map +0 -1
  136. package/dist/default/theme.js +0 -39
  137. package/dist/default/theme.js.map +0 -1
  138. package/src/default/ErrorAlert.tsx +0 -46
  139. package/src/default/theme.tsx +0 -66
@@ -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
@@ -50,20 +50,25 @@ export { countIsEstimate, countKind, degradationMessageKey, isCountNuanceOnly, p
50
50
  export type { SearchCountKind } from "./state/degradations.js";
51
51
  export { buildFacetGroups, facetOptionLabel } from "./state/facets.js";
52
52
  export type { BuildFacetGroupsInput, FacetGroup, FacetOption, } from "./state/facets.js";
53
+ export { RANGE_FEATURE_TYPES, buildRangeGroups, isRangeFeature, isRangeUsable, } from "./state/ranges.js";
54
+ export type { BuildRangeGroupsInput, RangeGroup } from "./state/ranges.js";
55
+ export { SEARCH_BOX_DEBOUNCE_MS, SEARCH_BOX_SUGGEST_DEBOUNCE_MS, SEARCH_DEFAULT_PAGE_SIZE, SEARCH_MAX_PAGE_SIZE, SEARCH_QUERY_MAX_CHARS, SUGGEST_MAX_LIMIT, SUGGEST_MIN_CHARS, } from "./state/limits.js";
53
56
  export { createSearchRuntime } from "./model/runtime.js";
54
57
  export type { SearchRuntime, CreateSearchRuntimeOptions, } from "./model/runtime.js";
55
58
  export { SearchRuntimeContext, useSearchRuntime, useSearchApi, useSearchAnalytics, } from "./model/context.js";
56
59
  export { searchQueryKeys } from "./model/queryKeys.js";
57
60
  export type { SearchQueryKeyParams } from "./model/queryKeys.js";
58
- export { useRankingDisclosure, useSearchQuery } from "./model/queries.js";
61
+ export { useRankingDisclosure, useSearchQuery, useSuggest } from "./model/queries.js";
59
62
  export { SearchProvider } from "./headless/SearchProvider.js";
60
63
  export { SearchStateProvider, useSearchState } from "./headless/SearchStateProvider.js";
61
64
  export type { SearchParamsAdapter, SearchStateBag, SearchStateProviderProps, } from "./headless/SearchStateProvider.js";
62
65
  export { SearchResults } from "./headless/SearchResults.js";
63
66
  export type { SearchPageInfo, SearchResultsBag } from "./headless/SearchResults.js";
64
- export { FacetPanel } from "./headless/FacetPanel.js";
67
+ export { FacetPanel, useFacetPanel } from "./headless/FacetPanel.js";
65
68
  export type { FacetPanelBag } from "./headless/FacetPanel.js";
66
69
  export { useAppliedSort } from "./headless/useAppliedSort.js";
70
+ export { useSearchBox } from "./headless/useSearchBox.js";
71
+ export type { SearchBoxBag, UseSearchBoxOptions } from "./headless/useSearchBox.js";
67
72
  export { RankingDisclosure } from "./headless/RankingDisclosure.js";
68
73
  export type { RankingDisclosureBag } from "./headless/RankingDisclosure.js";
69
74
  export { navEntries } from "./nav/manifest.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -46,17 +46,20 @@ export { SEARCH_SORTS } from "./api/types.js";
46
46
  export { FILTER_PREFIX, RANGE_PREFIX, SEARCH_PARAM, activeFilterCount, clearFilters, ownsParam, parseSearchState, patchSearchState, setFilterValues, setRangeValue, toggleFilterValue, writeSearchState, } from "./state/urlState.js";
47
47
  export { countIsEstimate, countKind, degradationMessageKey, isCountNuanceOnly, parseDegradations, } from "./state/degradations.js";
48
48
  export { buildFacetGroups, facetOptionLabel } from "./state/facets.js";
49
+ export { RANGE_FEATURE_TYPES, buildRangeGroups, isRangeFeature, isRangeUsable, } from "./state/ranges.js";
50
+ export { SEARCH_BOX_DEBOUNCE_MS, SEARCH_BOX_SUGGEST_DEBOUNCE_MS, SEARCH_DEFAULT_PAGE_SIZE, SEARCH_MAX_PAGE_SIZE, SEARCH_QUERY_MAX_CHARS, SUGGEST_MAX_LIMIT, SUGGEST_MIN_CHARS, } from "./state/limits.js";
49
51
  // ── model (runtime wiring, query keys, context, hooks) ───────────────────────
50
52
  export { createSearchRuntime } from "./model/runtime.js";
51
53
  export { SearchRuntimeContext, useSearchRuntime, useSearchApi, useSearchAnalytics, } from "./model/context.js";
52
54
  export { searchQueryKeys } from "./model/queryKeys.js";
53
- export { useRankingDisclosure, useSearchQuery } from "./model/queries.js";
55
+ export { useRankingDisclosure, useSearchQuery, useSuggest } from "./model/queries.js";
54
56
  // ── headless (renderless components) ─────────────────────────────────────────
55
57
  export { SearchProvider } from "./headless/SearchProvider.js";
56
58
  export { SearchStateProvider, useSearchState } from "./headless/SearchStateProvider.js";
57
59
  export { SearchResults } from "./headless/SearchResults.js";
58
- export { FacetPanel } from "./headless/FacetPanel.js";
60
+ export { FacetPanel, useFacetPanel } from "./headless/FacetPanel.js";
59
61
  export { useAppliedSort } from "./headless/useAppliedSort.js";
62
+ export { useSearchBox } from "./headless/useSearchBox.js";
60
63
  export { RankingDisclosure } from "./headless/RankingDisclosure.js";
61
64
  // ── nav manifest (the pair's public surface declaration) ─────────────────────
62
65
  export { navEntries } from "./nav/manifest.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,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"}
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,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,aAAa,GACd,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,sBAAsB,EACtB,8BAA8B,EAC9B,wBAAwB,EACxB,oBAAoB,EACpB,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAE3B,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,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEtF,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,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAErE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D,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"}
@@ -1,6 +1,6 @@
1
1
  import type { UseQueryResult } from "@tanstack/react-query";
2
2
  import type { StapelApiError } from "@stapel/core";
3
- import type { RankingResponse, SearchQueryState, SearchResponse } from "../api/types.js";
3
+ import type { RankingResponse, SearchQueryState, SearchResponse, SuggestResponse } from "../api/types.js";
4
4
  /**
5
5
  * Read hooks over the search API (frontend-standard §2). Keys are namespaced
6
6
  * (see `searchQueryKeys`).
@@ -38,11 +38,35 @@ import type { RankingResponse, SearchQueryState, SearchResponse } from "../api/t
38
38
  export declare function useSearchQuery(state: SearchQueryState, options?: {
39
39
  readonly enabled?: boolean;
40
40
  }): UseQueryResult<SearchResponse, StapelApiError>;
41
+ /**
42
+ * Title prefixes from the index, for the search box's typeahead.
43
+ *
44
+ * Not from a query log: stapel-search keeps none, which is a privacy decision
45
+ * before it is a product one (`services.suggest`). So the list is what exists
46
+ * in the catalogue, and choosing one is always a search that has results.
47
+ *
48
+ * `enabled` is the debounce's partner, not its replacement: the CALLER holds a
49
+ * debounced prefix (see `useSearchBox`) and this hook refuses to ask about a
50
+ * prefix too short to mean anything. `placeholderData: keepPreviousData` keeps
51
+ * the previous list under the cursor while the next one is in flight — a menu
52
+ * that empties and refills on every keystroke is a menu nobody can click.
53
+ *
54
+ * `staleTime` is a minute: the index changes when something is published, not
55
+ * between two letters of one word.
56
+ */
57
+ export declare function useSuggest(params: {
58
+ readonly type: string;
59
+ readonly q: string;
60
+ readonly limit?: number;
61
+ readonly enabled?: boolean;
62
+ }): UseQueryResult<SuggestResponse, StapelApiError>;
41
63
  /**
42
64
  * The P2B Art. 5 ranking disclosure.
43
65
  *
44
66
  * `staleTime: Infinity`: the scorer registry changes when somebody deploys,
45
67
  * not while a person reads the page it explains.
46
68
  */
47
- export declare function useRankingDisclosure(type?: string): UseQueryResult<RankingResponse, StapelApiError>;
69
+ export declare function useRankingDisclosure(type?: string, options?: {
70
+ readonly enabled?: boolean;
71
+ }): UseQueryResult<RankingResponse, StapelApiError>;
48
72
  //# sourceMappingURL=queries.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/model/queries.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,cAAc,EACf,MAAM,iBAAiB,CAAC;AAIzB;;;;;;;;;;;GAWG;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,gBAAgB,EACvB,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GACvC,cAAc,CAAC,cAAc,EAAE,cAAc,CAAC,CAUhD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,CAAC,EAAE,MAAM,GACZ,cAAc,CAAC,eAAe,EAAE,cAAc,CAAC,CAQjD"}
1
+ {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../src/model/queries.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,eAAe,EAChB,MAAM,iBAAiB,CAAC;AAKzB;;;;;;;;;;;GAWG;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,gBAAgB,EACvB,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GACvC,cAAc,CAAC,cAAc,EAAE,cAAc,CAAC,CAUhD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B,GAAG,cAAc,CAAC,eAAe,EAAE,cAAc,CAAC,CAuBlD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,CAAC,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GACvC,cAAc,CAAC,eAAe,EAAE,cAAc,CAAC,CASjD"}
@@ -1,5 +1,6 @@
1
1
  import { keepPreviousData, useQuery } from "@tanstack/react-query";
2
2
  import { searchQueryParams } from "../api/searchApi.js";
3
+ import { SUGGEST_MAX_LIMIT, SUGGEST_MIN_CHARS } from "../state/limits.js";
3
4
  import { useSearchApi } from "./context.js";
4
5
  import { searchQueryKeys } from "./queryKeys.js";
5
6
  /**
@@ -47,17 +48,53 @@ export function useSearchQuery(state, options) {
47
48
  retry: false,
48
49
  });
49
50
  }
51
+ /**
52
+ * Title prefixes from the index, for the search box's typeahead.
53
+ *
54
+ * Not from a query log: stapel-search keeps none, which is a privacy decision
55
+ * before it is a product one (`services.suggest`). So the list is what exists
56
+ * in the catalogue, and choosing one is always a search that has results.
57
+ *
58
+ * `enabled` is the debounce's partner, not its replacement: the CALLER holds a
59
+ * debounced prefix (see `useSearchBox`) and this hook refuses to ask about a
60
+ * prefix too short to mean anything. `placeholderData: keepPreviousData` keeps
61
+ * the previous list under the cursor while the next one is in flight — a menu
62
+ * that empties and refills on every keystroke is a menu nobody can click.
63
+ *
64
+ * `staleTime` is a minute: the index changes when something is published, not
65
+ * between two letters of one word.
66
+ */
67
+ export function useSuggest(params) {
68
+ const api = useSearchApi();
69
+ const q = params.q.trim();
70
+ const limit = params.limit;
71
+ return useQuery({
72
+ queryKey: searchQueryKeys.suggest(params.type, q, limit),
73
+ queryFn: ({ signal }) => api.suggest({
74
+ type: params.type,
75
+ q,
76
+ ...(limit !== undefined ? { limit: Math.min(limit, SUGGEST_MAX_LIMIT) } : {}),
77
+ }, { signal }),
78
+ enabled: (params.enabled ?? true) &&
79
+ params.type.length > 0 &&
80
+ q.length >= SUGGEST_MIN_CHARS,
81
+ placeholderData: keepPreviousData,
82
+ staleTime: 60_000,
83
+ retry: false,
84
+ });
85
+ }
50
86
  /**
51
87
  * The P2B Art. 5 ranking disclosure.
52
88
  *
53
89
  * `staleTime: Infinity`: the scorer registry changes when somebody deploys,
54
90
  * not while a person reads the page it explains.
55
91
  */
56
- export function useRankingDisclosure(type) {
92
+ export function useRankingDisclosure(type, options) {
57
93
  const api = useSearchApi();
58
94
  return useQuery({
59
95
  queryKey: searchQueryKeys.ranking(type),
60
96
  queryFn: ({ signal }) => api.ranking(type, { signal }),
97
+ enabled: options?.enabled ?? true,
61
98
  staleTime: Number.POSITIVE_INFINITY,
62
99
  retry: false,
63
100
  });
@@ -1 +1 @@
1
- {"version":3,"file":"queries.js","sourceRoot":"","sources":["../../src/model/queries.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAMxD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD;;;;;;;;;;;GAWG;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAuB,EACvB,OAAwC;IAExC,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;IACxC,OAAO,QAAQ,CAAC;QACd,QAAQ,EAAE,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC;QACvC,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC;QACrD,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC;QAC5D,eAAe,EAAE,gBAAgB;QACjC,KAAK,EAAE,KAAK;KACb,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAAa;IAEb,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;IAC3B,OAAO,QAAQ,CAAC;QACd,QAAQ,EAAE,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC;QACvC,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC;QACtD,SAAS,EAAE,MAAM,CAAC,iBAAiB;QACnC,KAAK,EAAE,KAAK;KACb,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"queries.js","sourceRoot":"","sources":["../../src/model/queries.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAOxD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD;;;;;;;;;;;GAWG;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAuB,EACvB,OAAwC;IAExC,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;IACxC,OAAO,QAAQ,CAAC;QACd,QAAQ,EAAE,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC;QACvC,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC;QACrD,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC;QAC5D,eAAe,EAAE,gBAAgB;QACjC,KAAK,EAAE,KAAK;KACb,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,UAAU,CAAC,MAK1B;IACC,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;IAC3B,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IAC3B,OAAO,QAAQ,CAAC;QACd,QAAQ,EAAE,eAAe,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,CAAC;QACxD,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CACtB,GAAG,CAAC,OAAO,CACT;YACE,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,CAAC;YACD,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9E,EACD,EAAE,MAAM,EAAE,CACX;QACH,OAAO,EACL,CAAC,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC;YACxB,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC;YACtB,CAAC,CAAC,MAAM,IAAI,iBAAiB;QAC/B,eAAe,EAAE,gBAAgB;QACjC,SAAS,EAAE,MAAM;QACjB,KAAK,EAAE,KAAK;KACb,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAAa,EACb,OAAwC;IAExC,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;IAC3B,OAAO,QAAQ,CAAC;QACd,QAAQ,EAAE,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC;QACvC,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC;QACtD,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,IAAI;QACjC,SAAS,EAAE,MAAM,CAAC,iBAAiB;QACnC,KAAK,EAAE,KAAK;KACb,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The backend's own limits, in one place — and the two timings the client
3
+ * chooses so that it never provokes them.
4
+ *
5
+ * Every number here is a fact about stapel-search's `conf.py` (or, for the
6
+ * debounces, a decision taken because of one). They live in the state layer,
7
+ * beside the codec, because they are properties of the CONTRACT rather than of
8
+ * any component: a control that caps its input at `SEARCH_QUERY_MAX_CHARS`
9
+ * cannot produce `error.400.search_query_too_long`, and a typeahead that waits
10
+ * for `SEARCH_BOX_SUGGEST_DEBOUNCE_MS` does not earn a 429 from a throttled
11
+ * endpoint for typing quickly.
12
+ *
13
+ * They are DEFAULTS, not assertions: a deployment may raise `MAX_PAGE_SIZE` or
14
+ * lower `MAX_QUERY_CHARS`, and nothing here is sent to the server as a claim.
15
+ * The server remains the one entitled to refuse.
16
+ */
17
+ /** `MAX_QUERY_CHARS` — the longest `q` (and suggest prefix) the server reads. */
18
+ export declare const SEARCH_QUERY_MAX_CHARS = 200;
19
+ /** `DEFAULT_PAGE_SIZE` — what a request with no `limit` gets. */
20
+ export declare const SEARCH_DEFAULT_PAGE_SIZE = 24;
21
+ /** `MAX_PAGE_SIZE` — the server clamps anything above this. */
22
+ export declare const SEARCH_MAX_PAGE_SIZE = 100;
23
+ /** `services.suggest` clamps `limit` into `1..25`. */
24
+ export declare const SUGGEST_MAX_LIMIT = 25;
25
+ /**
26
+ * The shortest prefix worth asking the index about.
27
+ *
28
+ * One and two letters match nearly everything, so the answer is noise and the
29
+ * request is a keystroke tax on a throttled endpoint (`SuggestThrottle`,
30
+ * scope `search-suggest`). Three is where a prefix starts to mean something.
31
+ */
32
+ export declare const SUGGEST_MIN_CHARS = 3;
33
+ /** How long the typing has to stop before the SEARCH runs. */
34
+ export declare const SEARCH_BOX_DEBOUNCE_MS = 350;
35
+ /**
36
+ * How long it has to stop before the INDEX is asked for prefixes.
37
+ *
38
+ * Shorter than the commit: a suggestion is only worth having while you are
39
+ * still typing, and it costs a cheap read of one column. Longer than zero: the
40
+ * endpoint is throttled per client, and a request per keystroke is how a person
41
+ * gets 429s for typing quickly.
42
+ */
43
+ export declare const SEARCH_BOX_SUGGEST_DEBOUNCE_MS = 150;
44
+ //# sourceMappingURL=limits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../../src/state/limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,iFAAiF;AACjF,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C,iEAAiE;AACjE,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAE3C,+DAA+D;AAC/D,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC,sDAAsD;AACtD,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAEpC;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC,8DAA8D;AAC9D,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C;;;;;;;GAOG;AACH,eAAO,MAAM,8BAA8B,MAAM,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The backend's own limits, in one place — and the two timings the client
3
+ * chooses so that it never provokes them.
4
+ *
5
+ * Every number here is a fact about stapel-search's `conf.py` (or, for the
6
+ * debounces, a decision taken because of one). They live in the state layer,
7
+ * beside the codec, because they are properties of the CONTRACT rather than of
8
+ * any component: a control that caps its input at `SEARCH_QUERY_MAX_CHARS`
9
+ * cannot produce `error.400.search_query_too_long`, and a typeahead that waits
10
+ * for `SEARCH_BOX_SUGGEST_DEBOUNCE_MS` does not earn a 429 from a throttled
11
+ * endpoint for typing quickly.
12
+ *
13
+ * They are DEFAULTS, not assertions: a deployment may raise `MAX_PAGE_SIZE` or
14
+ * lower `MAX_QUERY_CHARS`, and nothing here is sent to the server as a claim.
15
+ * The server remains the one entitled to refuse.
16
+ */
17
+ /** `MAX_QUERY_CHARS` — the longest `q` (and suggest prefix) the server reads. */
18
+ export const SEARCH_QUERY_MAX_CHARS = 200;
19
+ /** `DEFAULT_PAGE_SIZE` — what a request with no `limit` gets. */
20
+ export const SEARCH_DEFAULT_PAGE_SIZE = 24;
21
+ /** `MAX_PAGE_SIZE` — the server clamps anything above this. */
22
+ export const SEARCH_MAX_PAGE_SIZE = 100;
23
+ /** `services.suggest` clamps `limit` into `1..25`. */
24
+ export const SUGGEST_MAX_LIMIT = 25;
25
+ /**
26
+ * The shortest prefix worth asking the index about.
27
+ *
28
+ * One and two letters match nearly everything, so the answer is noise and the
29
+ * request is a keystroke tax on a throttled endpoint (`SuggestThrottle`,
30
+ * scope `search-suggest`). Three is where a prefix starts to mean something.
31
+ */
32
+ export const SUGGEST_MIN_CHARS = 3;
33
+ /** How long the typing has to stop before the SEARCH runs. */
34
+ export const SEARCH_BOX_DEBOUNCE_MS = 350;
35
+ /**
36
+ * How long it has to stop before the INDEX is asked for prefixes.
37
+ *
38
+ * Shorter than the commit: a suggestion is only worth having while you are
39
+ * still typing, and it costs a cheap read of one column. Longer than zero: the
40
+ * endpoint is throttled per client, and a request per keystroke is how a person
41
+ * gets 429s for typing quickly.
42
+ */
43
+ export const SEARCH_BOX_SUGGEST_DEBOUNCE_MS = 150;
44
+ //# sourceMappingURL=limits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"limits.js","sourceRoot":"","sources":["../../src/state/limits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,iFAAiF;AACjF,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAE1C,iEAAiE;AACjE,MAAM,CAAC,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAE3C,+DAA+D;AAC/D,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAExC,sDAAsD;AACtD,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAEpC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAEnC,8DAA8D;AAC9D,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAE1C;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,GAAG,CAAC"}
@@ -0,0 +1,52 @@
1
+ import type { FeatureDef } from "@stapel/attributes-react";
2
+ import type { SearchQueryState, SearchRange } from "../api/types.js";
3
+ /**
4
+ * Value types a numeric range row is drawn for (`config.type`, the
5
+ * stapel-attributes value-type slug).
6
+ */
7
+ export declare const RANGE_FEATURE_TYPES: readonly string[];
8
+ /** One `r.<slug>` row of the filter panel. */
9
+ export interface RangeGroup {
10
+ readonly slug: string;
11
+ /** The feature's display name (translated when it is a key), else the slug. */
12
+ readonly label: string;
13
+ /** The schema entry behind the slug, when the host supplied one. */
14
+ readonly feature: FeatureDef | undefined;
15
+ /** The applied bounds, exactly as the URL carries them (strings — the wire
16
+ * never promised a number, and re-formatting one would rewrite the link). */
17
+ readonly from: string | undefined;
18
+ readonly to: string | undefined;
19
+ /** Bounds the schema declares, for the input's own limits. */
20
+ readonly min: number | undefined;
21
+ readonly max: number | undefined;
22
+ /** Unit suffix the schema declares (`postfix`, or a convertible unit). */
23
+ readonly unit: string | undefined;
24
+ /** `1` for an integer feature — a whole-number input for a whole number. */
25
+ readonly step: number | undefined;
26
+ /** Whether the URL currently constrains this slug. */
27
+ readonly active: boolean;
28
+ }
29
+ export interface BuildRangeGroupsInput {
30
+ readonly state: SearchQueryState;
31
+ readonly categoryFeatures?: readonly FeatureDef[];
32
+ /** Translator for label keys (the schema's `name` is often one). */
33
+ readonly t?: (key: string) => string;
34
+ }
35
+ /** Is this feature one a numeric range row is drawn for? */
36
+ export declare function isRangeFeature(feature: FeatureDef): boolean;
37
+ /**
38
+ * The range rows for the current search: every numeric feature of the
39
+ * category, in the schema's own order, plus any slug the URL constrains that
40
+ * the schema does not explain.
41
+ */
42
+ export declare function buildRangeGroups(input: BuildRangeGroupsInput): readonly RangeGroup[];
43
+ /**
44
+ * Is a from/to pair one the server could ever match?
45
+ *
46
+ * `100..50` is syntactically fine and semantically empty, and the backend does
47
+ * not refuse it — it answers zero results, which reads as "there is nothing
48
+ * like this" rather than "you typed it backwards". So the panel refuses to
49
+ * apply it and says why, beside the button (`search.facets.range_invalid`).
50
+ */
51
+ export declare function isRangeUsable(range: SearchRange): boolean;
52
+ //# sourceMappingURL=ranges.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ranges.d.ts","sourceRoot":"","sources":["../../src/state/ranges.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAErE;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAIhD,CAAC;AAEF,8CAA8C;AAC9C,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,SAAS,CAAC;IACzC;iFAC6E;IAC7E,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,8DAA8D;IAC9D,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,4EAA4E;IAC5E,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,sDAAsD;IACtD,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IACjC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAClD,oEAAoE;IACpE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;CACtC;AAgBD,4DAA4D;AAC5D,wBAAgB,cAAc,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAG3D;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,qBAAqB,GAC3B,SAAS,UAAU,EAAE,CA8BvB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAMzD"}
@@ -0,0 +1,108 @@
1
+ /**
2
+ * The RANGE half of the filter model — `r.<slug>=from..to`.
3
+ *
4
+ * The codec has carried ranges since 0.1 (`setRangeValue`, `RANGE_PREFIX`) and
5
+ * nothing ever drew one: a marketplace shipped without a price filter because
6
+ * the panel only knew how to draw checkboxes. This module is the missing half:
7
+ * which slugs a range row exists for, and what the row is called.
8
+ *
9
+ * ── Where a range row comes from, and why it is not the response ───────────
10
+ *
11
+ * A facet answer (`facets: {slug: {value: count}}`) enumerates DISCRETE values;
12
+ * a range is not enumerable and the server never sends one. So the rows come
13
+ * from the CATEGORY SCHEMA — the same `categoryFeatures` slot that gives the
14
+ * checkboxes their labels — filtered to the numeric value types, plus every
15
+ * slug the URL already carries a range for.
16
+ *
17
+ * That last clause is the same rule `buildFacetGroups` follows for a filtered
18
+ * slug that fell out of the plan: a constraint that is ACTIVE must always have
19
+ * a control that removes it, even when the schema no longer explains it.
20
+ * Otherwise a shared link narrows the search with nothing on screen to widen it
21
+ * again.
22
+ *
23
+ * `date` is range-capable on the wire and is deliberately NOT here: a date
24
+ * range needs a date editor, the editor lives in `@stapel/attributes-react`'s
25
+ * registry, and a numeric input over a Unix timestamp would be worse than no
26
+ * control at all. The codec still round-trips one a host sets.
27
+ */
28
+ import { featureConfig, featureName, featureType } from "@stapel/attributes-react";
29
+ /**
30
+ * Value types a numeric range row is drawn for (`config.type`, the
31
+ * stapel-attributes value-type slug).
32
+ */
33
+ export const RANGE_FEATURE_TYPES = [
34
+ "int",
35
+ "float",
36
+ "convertible_unit",
37
+ ];
38
+ function num(value) {
39
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
40
+ }
41
+ function str(value) {
42
+ return typeof value === "string" && value.length > 0 ? value : undefined;
43
+ }
44
+ function translate(t, key) {
45
+ if (t === undefined)
46
+ return key;
47
+ const resolved = t(key);
48
+ return resolved.length > 0 ? resolved : key;
49
+ }
50
+ /** Is this feature one a numeric range row is drawn for? */
51
+ export function isRangeFeature(feature) {
52
+ const type = featureType(feature);
53
+ return type !== undefined && RANGE_FEATURE_TYPES.includes(type);
54
+ }
55
+ /**
56
+ * The range rows for the current search: every numeric feature of the
57
+ * category, in the schema's own order, plus any slug the URL constrains that
58
+ * the schema does not explain.
59
+ */
60
+ export function buildRangeGroups(input) {
61
+ const bySlug = new Map();
62
+ for (const feature of input.categoryFeatures ?? [])
63
+ bySlug.set(feature.slug, feature);
64
+ const slugs = [];
65
+ for (const feature of input.categoryFeatures ?? []) {
66
+ if (isRangeFeature(feature))
67
+ slugs.push(feature.slug);
68
+ }
69
+ for (const slug of Object.keys(input.state.ranges)) {
70
+ if (!slugs.includes(slug))
71
+ slugs.push(slug);
72
+ }
73
+ return slugs.map((slug) => {
74
+ const feature = bySlug.get(slug);
75
+ const config = feature === undefined ? {} : featureConfig(feature);
76
+ const applied = input.state.ranges[slug];
77
+ return {
78
+ slug,
79
+ label: feature === undefined ? slug : translate(input.t, featureName(feature)),
80
+ feature,
81
+ from: applied?.from,
82
+ to: applied?.to,
83
+ min: num(config["min"]),
84
+ max: num(config["max"]),
85
+ unit: str(config["postfix"]) ?? str(config["unit_m"]) ?? str(config["unit_i"]),
86
+ step: feature !== undefined && featureType(feature) === "int" ? 1 : undefined,
87
+ active: applied !== undefined,
88
+ };
89
+ });
90
+ }
91
+ /**
92
+ * Is a from/to pair one the server could ever match?
93
+ *
94
+ * `100..50` is syntactically fine and semantically empty, and the backend does
95
+ * not refuse it — it answers zero results, which reads as "there is nothing
96
+ * like this" rather than "you typed it backwards". So the panel refuses to
97
+ * apply it and says why, beside the button (`search.facets.range_invalid`).
98
+ */
99
+ export function isRangeUsable(range) {
100
+ if (range.from === undefined || range.to === undefined)
101
+ return true;
102
+ const from = Number(range.from);
103
+ const to = Number(range.to);
104
+ if (!Number.isFinite(from) || !Number.isFinite(to))
105
+ return true;
106
+ return from <= to;
107
+ }
108
+ //# sourceMappingURL=ranges.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ranges.js","sourceRoot":"","sources":["../../src/state/ranges.ts"],"names":[],"mappings":"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"}
package/llms.txt CHANGED
@@ -1,4 +1,4 @@
1
- # @stapel/search-react 0.4.0
1
+ # @stapel/search-react 0.7.0
2
2
 
3
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,
@@ -30,6 +30,7 @@ Paths are relative to `/search/api/v1/`.
30
30
  ## Query hooks (server state; keys come only from the key factory)
31
31
  - useRankingDisclosure (query) → ranking
32
32
  - useSearchQuery (query) → query
33
+ - useSuggest (query) → suggest
33
34
 
34
35
  ## Errors (render t(code, params); UX from remediation)
35
36
  54 keys (full catalog: manifest.json §errors). By remediation: fix_input 26 · retry 15 · verify 5 · wait_and_retry 5 · contact_support 2 · reauthenticate 1.
@@ -74,9 +75,19 @@ const { tracked } = useTracked();
74
75
  ```
75
76
 
76
77
  ## Demos (defineDemo → manifest.demos; compiled, linted, rendered examples)
77
- - search.facets → <FacetPanel> [default] demo/FacetPanel.demo.tsx
78
- - search.ranking → <RankingDisclosure> [default] demo/RankingDisclosure.demo.tsx
79
- - search.results → <SearchResults> [default] demo/SearchResults.demo.tsx
78
+ - search.box → <SearchBox> [empty|typed] demo/SearchBox.demo.tsx
79
+ - search.degradation-notice → <DegradationNotice> [banner|inline] demo/DegradationNotice.demo.tsx
80
+ - search.facet-panel-pane → <FacetPanelPane> [open-search|narrowed] demo/FacetPanelPane.demo.tsx
81
+ - search.filter-sheet → <SearchPage> [open] demo/FilterSheet.demo.tsx
82
+ - search.language-select → <LanguageSelect> [offered|from-a-link] demo/LanguageSelect.demo.tsx
83
+ - search.page → <SearchPage> [desktop|phone|unreadable-link] demo/SearchPage.demo.tsx
84
+ - search.page-size-select → <PageSizeSelect> [ladder|off-ladder] demo/PageSizeSelect.demo.tsx
85
+ - search.range-filter-row → <RangeFilterRow> [untouched|applied] demo/RangeFilterRow.demo.tsx
86
+ - search.ranking-pane → <RankingDisclosurePane> [desktop|phone] demo/RankingDisclosurePane.demo.tsx
87
+ - search.result-card → <SearchResultCard> [promoted|plain] demo/SearchResultCard.demo.tsx
88
+ - search.results-pane → <SearchResultsPane> [desktop|phone|empty] demo/SearchResultsPane.demo.tsx
89
+ - search.sort-select → <SortSelect> [no-centre|with-centre] demo/SortSelect.demo.tsx
90
+ - search.url-issue-notice → <UrlIssueNotice> [two-issues|one-issue] demo/UrlIssueNotice.demo.tsx
80
91
  Each source file is the canonical usage snippet (open the default variant).
81
92
 
82
93
  ## Snippets