@stapel/search-react 0.1.0 → 0.2.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 CHANGED
@@ -1 +1,55 @@
1
1
  # @stapel/search-react
2
+
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 6356af8: New package: `@stapel/search-react` — the frontend pair for stapel-search, and
8
+ the one surface a storefront's catalogue, category and search pages all come
9
+ from.
10
+
11
+ ```tsx
12
+ const runtime = createSearchRuntime({ baseUrl: "/search/api/v1/" });
13
+ <SearchProvider runtime={runtime}>
14
+ <SearchPage adapter={useRouterSearchParams()} defaultType="listing" />
15
+ </SearchProvider>;
16
+ ```
17
+
18
+ No session, no workspace id, no auth client: every endpoint it calls is
19
+ `AllowAny`, so a catalogue renders for a visitor who will never sign in.
20
+
21
+ **The URL is the state.** Text, category, facet filters, ranges, geo, sort, page
22
+ size and the keyset cursor all live in the query string, under the backend's own
23
+ parameter names, and no component keeps a second copy. Copying the address into
24
+ another tab reproduces the page, Back removes exactly the last filter, and a
25
+ reload loses nothing — by construction rather than by discipline. Changing any
26
+ of them drops the keyset cursor, because `anchor` is a position inside one
27
+ ordered candidate set and carrying it across a filter change answers page 4 of
28
+ a different search. The router is a two-member seam (`SearchParamsAdapter`);
29
+ `./router` binds react-router's `useSearchParams`, and a Next.js app or a plain
30
+ `URLSearchParams` satisfies the same shape.
31
+
32
+ **Facets are drill-down, and the panel shows it.** Each is counted with its own
33
+ filter removed, so picking a value leaves its siblings with the counts you would
34
+ get by switching to them; closed sets keep their authored order, zeros included.
35
+ The server sends no option labels — they are keys in the category's feature
36
+ schema — so `categoryFeatures` is an explicit input and the captions resolve
37
+ through `@stapel/attributes-react`'s `formatFeatureValue`, the same formatter a
38
+ card uses.
39
+
40
+ **What the server admits, the screen repeats.** `exact_total: false` renders as
41
+ "about N", `facet_meta.approximate` says the counts are a sample, a skipped slug
42
+ shows "not counted" rather than `0`, and every `degraded[]` literal becomes a
43
+ line in a banner — including one this build has no wording for, which arrives
44
+ with its raw text. A failed search says "we could not run this search" with a
45
+ retry, and `error.400.search_window_exceeded` says "narrow the search"; neither
46
+ is ever spelled "nothing found".
47
+
48
+ `promoted` (DSA Art. 26) rides every item under every sort and reaches the card
49
+ slot whole, so a storefront's own `<ListingCard>` can still mark it; the P2B
50
+ Art. 5 ranking disclosure ships as a headless bag and a page, listing even the
51
+ parameters the configured engine cannot evaluate.
52
+
53
+ `./default` is the antd skin (`SearchPage`, `SearchResultsPane`,
54
+ `FacetPanelPane`, `RankingDisclosurePane`); the main entry carries no antd and
55
+ no router.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Stapel contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/i18n/ru.d.ts CHANGED
@@ -7,7 +7,7 @@ export { searchErrorBundleRu } from "./generated/errors.ru.gen.js";
7
7
  * entry does not import this module — gated by size-limit + the bundle-purity
8
8
  * test).
9
9
  *
10
- * This is the storefront's DEFAULT language (darom-storefront verdict F1:
10
+ * This is the storefront's DEFAULT language (storefront spec verdict F1:
11
11
  * ru-first), which is why it is the fullest of the three bundles and why the
12
12
  * wording is checked against what a marketplace visitor is actually being
13
13
  * told — "counts are approximate" has to sound like an explanation, not an
package/dist/i18n/ru.js CHANGED
@@ -7,7 +7,7 @@ export { searchErrorBundleRu } from "./generated/errors.ru.gen.js";
7
7
  * entry does not import this module — gated by size-limit + the bundle-purity
8
8
  * test).
9
9
  *
10
- * This is the storefront's DEFAULT language (darom-storefront verdict F1:
10
+ * This is the storefront's DEFAULT language (storefront spec verdict F1:
11
11
  * ru-first), which is why it is the fullest of the three bundles and why the
12
12
  * wording is checked against what a marketplace visitor is actually being
13
13
  * told — "counts are approximate" has to sound like an explanation, not an
package/llms.txt CHANGED
@@ -1,4 +1,4 @@
1
- # @stapel/search-react 0.1.0
1
+ # @stapel/search-react 0.2.0
2
2
 
3
3
  Headless React flow pair for stapel-search (contract >=0.1 <0.2) — business + state, zero visual opinion.
4
4
  Built on @stapel/core: typed client + StapelApiError envelope, auth token refresh,
package/manifest.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$generated": "by scripts/gen-manifest.mjs — do not edit; drift-gated (pnpm gen:manifest:check)",
3
3
  "package": "@stapel/search-react",
4
- "version": "0.1.0",
4
+ "version": "0.2.0",
5
5
  "backend": {
6
6
  "module": "stapel-search",
7
7
  "contract": ">=0.1 <0.2"
package/nav-manifest.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "package": "@stapel/search-react",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "entries": [
5
5
  {
6
6
  "id": "search.results",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stapel/search-react",
3
- "version": "0.1.0",
3
+ "version": "0.2.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": {
@@ -50,13 +50,6 @@
50
50
  "nav-manifest.json",
51
51
  "llms.txt"
52
52
  ],
53
- "scripts": {
54
- "build": "tsc -p tsconfig.json",
55
- "test": "tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts",
56
- "lint": "eslint .",
57
- "size": "size-limit",
58
- "test:pack": "vitest run test/prodBundlePurity.test.ts"
59
- },
60
53
  "size-limit": [
61
54
  {
62
55
  "name": "index — the headless pair (client + hooks + URL codec + facet model): no antd, no react-router",
@@ -106,11 +99,6 @@
106
99
  },
107
100
  "devDependencies": {
108
101
  "@size-limit/preset-small-lib": "^11.2.0",
109
- "@stapel/attributes-react": "workspace:^",
110
- "@stapel/core": "workspace:^",
111
- "@stapel/showcase": "workspace:^",
112
- "@stapel/tokens": "workspace:^",
113
- "@stapel/tokens-antd": "workspace:^",
114
102
  "@tanstack/react-query": "^5.81.0",
115
103
  "@testing-library/react": "^16.3.0",
116
104
  "@types/react": "^19.1.0",
@@ -122,12 +110,24 @@
122
110
  "react-router": "^7.18.1",
123
111
  "size-limit": "^11.2.0",
124
112
  "typescript": "^5.8.3",
125
- "vitest": "^3.2.4"
113
+ "vitest": "^3.2.4",
114
+ "@stapel/attributes-react": "^0.2.0",
115
+ "@stapel/core": "^0.15.0",
116
+ "@stapel/showcase": "^0.2.0",
117
+ "@stapel/tokens": "^0.5.0",
118
+ "@stapel/tokens-antd": "^0.5.0"
126
119
  },
127
120
  "engines": {
128
121
  "node": ">=22"
129
122
  },
130
123
  "publishConfig": {
131
124
  "access": "public"
125
+ },
126
+ "scripts": {
127
+ "build": "tsc -p tsconfig.json",
128
+ "test": "tsc -p tsconfig.test.json && vitest run --exclude test/prodBundlePurity.test.ts",
129
+ "lint": "eslint .",
130
+ "size": "size-limit",
131
+ "test:pack": "vitest run test/prodBundlePurity.test.ts"
132
132
  }
133
- }
133
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$generated": "by scripts/gen-events.mjs — do not edit; drift-gated (pnpm gen:events:check)",
3
3
  "package": "@stapel/search-react",
4
- "version": "0.1.0",
4
+ "version": "0.2.0",
5
5
  "defined": [],
6
6
  "flows": []
7
7
  }