@stapel/search-react 0.32.7 → 0.32.8

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,5 +1,21 @@
1
1
  # @stapel/search-react
2
2
 
3
+ ## 0.32.8
4
+
5
+ ### Patch Changes
6
+
7
+ - e4797ce: `<PartitionChips variant="segmented">` renders the control it declares.
8
+
9
+ The row carried `data-variant="segmented"` and `role="radiogroup"`, and inside it the walker counted `.ant-segmented` **0** and `input[type=radio]` **0** over plain `ant-btn` cells — on both axes of two categories (D304). The ARIA was real (`role="radio"`, `aria-checked`, a roving tabindex, arrow keys), but the control named in the DOM did not exist, and ~30 lines of this file re-decided joined-row geometry the design system already owns.
10
+
11
+ The segmented arm is antd's `Segmented` now: `.ant-segmented`, one real `input[type=radio]` per cell under a shared `name`, and with it the browser's own single Tab stop and arrow keys. The declaration is unchanged (`data-variant="segmented"`, `role="radiogroup"`, the group's `aria-label` still the axis's own name) and so is the contract — `value: string | null`, `onChange` reporting `null` for the parent, controlled, nothing kept here.
12
+
13
+ What moves for anything reading the DOM: the chosen cell is the radio's **`checked`** rather than `aria-checked` on a button (`aria-checked` is how a button fakes what a radio has), and it carries `.ant-segmented-item-selected`. The per-cell test ids (`partition-chip-<path>`, `partition-chip-all`) stay where they were, on the cell's own label, now with `data-checked` beside them so a probe reading a snapshot still has the chosen cell without asking the accessibility tree. A keydown belongs to the cell's input.
14
+
15
+ The `chips` variant — the phone's wrapping pill row — is untouched: same buttons, same `role="radio"`, same `aria-checked`, same roving tabindex.
16
+
17
+ Ceiling raised 31 -> 31.25 KB. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB.
18
+
3
19
  ## 0.32.7
4
20
 
5
21
  ### Patch Changes
package/README.md CHANGED
@@ -532,8 +532,13 @@ a tile grid: an "all" cell plus one per child, from `{id, path, name}`,
532
532
  controlled (the choice is a `category` in the URL), a real `radiogroup` with
533
533
  roving tabindex and arrow keys — because exactly one of them is true at a time,
534
534
  and `aria-pressed` toggles say the opposite. `variant="segmented"` is the
535
- desktop rail's shape (one joined control under its own label); the semantics do
536
- not vary with it.
535
+ desktop rail's shape: **antd's `Segmented`**, one joined control under its own
536
+ label, so its radiogroup is the browser's — real `input[type=radio]` under one
537
+ `name`, the chosen cell's own `checked` (not `aria-checked`, which is how a
538
+ button fakes what a radio has), and the arrow keys and single Tab stop that
539
+ come with them. The contract does not vary with the variant, and the per-cell
540
+ test ids (`partition-chip-<path>`, `partition-chip-all`, each with
541
+ `data-checked`) are the same in both.
537
542
 
538
543
  ```tsx
539
544
  <PartitionChips items={children} value={state.category ?? null}
@@ -21,15 +21,14 @@ export interface PartitionChipsProps {
21
21
  /**
22
22
  * Which shape the row takes. `"chips"` (the default) is the phone's: a
23
23
  * wrapping row of rounded pills above the feed. `"segmented"` is the
24
- * desktop RAIL's — one joined control under the axis's own label, which is
25
- * how the reference classified draws the same choice (a car-type row:
26
- * all, used, new) and what a 280px column has room for.
24
+ * desktop RAIL's — antd's `Segmented`, one joined control under the axis's
25
+ * own label, which is how the reference classified draws the same choice (a
26
+ * car-type row: all, used, new) and what a 280px column has room for.
27
27
  *
28
- * The SEMANTICS do not vary with it. Both are the same `radiogroup` with
29
- * the same roving tabindex and the same arrow keys a segmented look is a
30
- * border-radius decision, and swapping in a component that draws joined
31
- * cells by giving up "exactly one of these is true" would trade the
32
- * accessible half of this control for the visible half.
28
+ * The SEMANTICS do not vary with it: both are a `radiogroup` naming itself,
29
+ * with one Tab stop and the arrow keys moving the choice. What varies is
30
+ * who provides them this file's `role="radio"` buttons in `chips`, the
31
+ * browser's own `input[type=radio]` in `segmented`.
33
32
  */
34
33
  readonly variant?: "chips" | "segmented";
35
34
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PartitionChips.d.ts","sourceRoot":"","sources":["../../src/default/PartitionChips.tsx"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAGV,YAAY,EACZ,SAAS,EACV,MAAM,OAAO,CAAC;AAMf;;oDAEoD;AACpD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IAC1C;iFAC6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACjD,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;IAC9B,uEAAuE;IACvE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;CAC1C;AAiDD,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,YAAY,CAgFvE"}
1
+ {"version":3,"file":"PartitionChips.d.ts","sourceRoot":"","sources":["../../src/default/PartitionChips.tsx"],"names":[],"mappings":"AAmDA,OAAO,KAAK,EAGV,YAAY,EACZ,SAAS,EACV,MAAM,OAAO,CAAC;AAMf;;oDAEoD;AACpD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IAC1C;iFAC6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACjD,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;IAC9B,uEAAuE;IACvE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;CAC1C;AA8BD,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,YAAY,CAsHvE"}
@@ -26,43 +26,47 @@ import { jsx as _jsx } from "react/jsx-runtime";
26
26
  * with roving tabindex is the pattern for "one of these": Tab reaches the row
27
27
  * once and lands on the chosen chip, the arrow keys move along it, and the
28
28
  * group's own name says what is being chosen.
29
+ *
30
+ * ── The two variants are two CONTROLS, and each one is real ───────────────
31
+ *
32
+ * `chips` is this file's own row of `role="radio"` buttons — pills that wrap,
33
+ * the phone's shape.
34
+ *
35
+ * `segmented` is antd's `Segmented`, and it used to be this same row with a
36
+ * shared border drawn round it. That was a claim nothing backed: the walker
37
+ * read `data-variant="segmented"` with `role="radiogroup"` and found
38
+ * `.ant-segmented` zero times, `input[type=radio]` zero times, and plain
39
+ * `ant-btn` inside — on both axes of two categories (D304). A row that names
40
+ * a control it does not render sends the next reader looking for a bug in the
41
+ * wrong place, and hand-rolling the joined look was ~30 lines re-deciding
42
+ * geometry the design system already owns.
43
+ *
44
+ * So the segmented arm IS the design system's control now, and its radiogroup
45
+ * is the browser's rather than ours: real `input[type=radio]` sharing one
46
+ * `name`, so the selected state is the radio's own `checked` (`aria-checked`
47
+ * is how a BUTTON fakes what a radio has), the arrow keys are the control's,
48
+ * and one Tab stop is the platform's doing. The per-cell test ids stay where
49
+ * they were, plus `data-checked`, so a probe that reads a snapshot still has
50
+ * the chosen cell without asking the accessibility tree.
29
51
  */
30
52
  import { useRef } from "react";
31
- import { Button } from "antd";
53
+ import { Button, Segmented } from "antd";
32
54
  import { useT } from "@stapel/core";
33
- import { cssVar, radii, spacing } from "@stapel/tokens";
55
+ import { radii, spacing } from "@stapel/tokens";
34
56
  import { SEARCH_I18N_KEYS } from "../i18n/keys.js";
57
+ /**
58
+ * The `value` of the parent cell inside the segmented control. `null` is this
59
+ * component's word for "the parent, unnarrowed" and a radio's value is a
60
+ * string, so the sentinel exists only between here and antd — it never
61
+ * reaches {@link PartitionChipsProps.onChange}, which still reports `null`.
62
+ */
63
+ const ALL = "__all__";
35
64
  const CHIP = { borderRadius: radii.full };
36
65
  const ROW = {
37
66
  display: "flex",
38
67
  flexWrap: "wrap",
39
68
  gap: spacing[2],
40
69
  };
41
- /**
42
- * The segmented row: one joined control, no gaps, the group's own outline.
43
- *
44
- * `gap: 0` plus a shared border is what makes three buttons read as one
45
- * control — the thing a rail needs, because a wrapping pill row in a 280px
46
- * column is two ragged lines. `overflow: hidden` clips the cells' own corners
47
- * to the group's radius so the ends are round and the joins are square.
48
- */
49
- const SEGMENTED_ROW = {
50
- display: "flex",
51
- gap: 0,
52
- inlineSize: "100%",
53
- border: `1px solid ${cssVar("border")}`,
54
- borderRadius: cssVar("radius-md"),
55
- overflow: "hidden",
56
- };
57
- /** One cell of the segmented row: an equal share of the width, square joins,
58
- * no border of its own — the group draws the outline. */
59
- const SEGMENTED_CELL = {
60
- flex: "1 1 0",
61
- minInlineSize: 0,
62
- borderRadius: 0,
63
- borderInline: "none",
64
- borderBlock: "none",
65
- };
66
70
  /** The row's cells, as `[value, label]` — the parent first, then the
67
71
  * children in catalogue order. */
68
72
  function cells(items, allLabel) {
@@ -106,15 +110,33 @@ export function PartitionChips(props) {
106
110
  // parent chip rather than vanishing.
107
111
  const active = options.findIndex(([value]) => value === props.value);
108
112
  const stop = active >= 0 ? active : 0;
109
- const segmented = props.variant === "segmented";
110
- return (_jsx("div", { style: segmented ? SEGMENTED_ROW : ROW, "data-variant": segmented ? "segmented" : "chips", ref: row, role: "radiogroup", "aria-label": props.label ?? t(SEARCH_I18N_KEYS.partitionLabel), "data-testid": "partition-chips", children: options.map(([value, label], index) => {
113
+ const name = props.label ?? t(SEARCH_I18N_KEYS.partitionLabel);
114
+ if (props.variant === "segmented") {
115
+ // antd's own control: `.ant-segmented`, one `input[type=radio]` per cell
116
+ // under a shared `name`, the selected cell's `checked`, and the arrow keys
117
+ // — the radiogroup this variant used to only claim to be. `role` and
118
+ // `aria-label` reach the root because the component spreads what it is
119
+ // given over its own defaults (which are `radiogroup` and the string
120
+ // "segmented control").
121
+ return (_jsx(Segmented, { block: true, size: "small", role: "radiogroup", "aria-label": name, "data-variant": "segmented", "data-testid": "partition-chips", value: props.value ?? ALL, options: options.map(([value, label]) => ({
122
+ value: value ?? ALL,
123
+ label: (
124
+ // The cell's test id and its chosen state, on the one node inside
125
+ // a cell this component owns — antd names the cells itself, and a
126
+ // label a radio is bound to is what a click has to land on.
127
+ _jsx("span", { "data-testid": `partition-chip-${value ?? "all"}`, "data-checked": value === props.value ? "true" : "false", children: label })),
128
+ })), onChange: (next) => {
129
+ props.onChange(next === ALL ? null : String(next));
130
+ } }));
131
+ }
132
+ return (_jsx("div", { style: ROW, "data-variant": "chips", ref: row, role: "radiogroup", "aria-label": name, "data-testid": "partition-chips", children: options.map(([value, label], index) => {
111
133
  const selected = value === props.value;
112
- return (_jsx(Button, { size: "small", ...(segmented ? {} : { shape: "round" }), type: selected ? "primary" : "default", role: "radio", "aria-checked": selected,
134
+ return (_jsx(Button, { size: "small", shape: "round", type: selected ? "primary" : "default", role: "radio", "aria-checked": selected,
113
135
  // Roving tabindex: the row is ONE Tab stop and it lands on the
114
136
  // chosen chip, not on the first of eight.
115
- tabIndex: index === stop ? 0 : -1, style: segmented ? SEGMENTED_CELL : CHIP, "data-testid": `partition-chip-${value ?? "all"}`, "data-analytics": "none", "data-analytics-reason": "choosing a section is a read, not a flow step", onKeyDown: onKeyDown(index), onClick: () => {
137
+ tabIndex: index === stop ? 0 : -1, style: CHIP, "data-testid": `partition-chip-${value ?? "all"}`, "data-analytics": "none", "data-analytics-reason": "choosing a section is a read, not a flow step", onKeyDown: onKeyDown(index), onClick: () => {
116
138
  props.onChange(value);
117
- }, children: label }, value ?? "__all__"));
139
+ }, children: label }, value ?? ALL));
118
140
  }) }));
119
141
  }
120
142
  //# sourceMappingURL=PartitionChips.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PartitionChips.js","sourceRoot":"","sources":["../../src/default/PartitionChips.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PartitionChips.js","sourceRoot":"","sources":["../../src/default/PartitionChips.tsx"],"names":[],"mappings":"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"}
package/llms.txt CHANGED
@@ -1,4 +1,4 @@
1
- # @stapel/search-react 0.32.7
1
+ # @stapel/search-react 0.32.8
2
2
 
3
3
  Headless React flow pair for stapel-search (contract >=0.16 <0.17) — 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.32.7",
4
+ "version": "0.32.8",
5
5
  "backend": {
6
6
  "module": "stapel-search",
7
7
  "contract": ">=0.16 <0.17"
package/nav-manifest.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "package": "@stapel/search-react",
3
- "version": "0.32.7",
3
+ "version": "0.32.8",
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.32.7",
3
+ "version": "0.32.8",
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": {
@@ -57,9 +57,9 @@
57
57
  "limit": "14.5 KB"
58
58
  },
59
59
  {
60
- "name": "default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back",
60
+ "name": "default — the antd skin (query box + a typeahead that offers CATEGORY destinations with their live counts, filters incl. ranges/geo/category slots + the phone chip row with its leading category chip and the location summary row + the rail's evidence-ranked disclosure groups, panel search and sticky count/clear footer, results incl. the view switch, the card photo GALLERY as a SkinCarousel strip, the empty state's derived exits, ranking, the dictionary control for a vocabulary facet, the popular-values block, the partition row in both its chip and segmented variants, the select-style dictionary FIELD the desktop rail opens, the from/to pickers a bounded integer axis draws and the rail's own scrollbar sheet) must stay out of the main bundle. Raised 24.5 → 25.5 KB for those four controls, then 25.5 → 26.25 KB for the chip row's APPLIED mode — one chip per applied value and per numeric bound, each removing that one constraint beside a rail that is already on screen (a storefront was carrying its own copy of it), then 26.25 → 27 KB for the \"search in other categories\" LINE — which is a net deletion on the page that mounts it, replacing a full-width block of one row per section that arrived after the results and pushed them, then 27 → 27.75 KB for the two frames the page now tells apart: the dictionary FIELD reaching `<SearchPage>` at all (per-layout default, field in the rail and inline in the sheet) and the footer bar being static in a column and sticky in a sheet, where it used to be pinned over the last two groups everywhere, then 27.75 → 28.5 KB for `categoryHref` on the other-categories line — a real `<a href>` per row with a modifier-click left to the browser, instead of a `<button>` with no address a person could open in a new tab, then 28.5 → 29.25 KB for the phone's dictionary SHEET — a trigger row over the shared `SkinPickerSheet` with a recommended band, an alphabetical rest paged fifty at a time and a draft committed in one write, which is the control the composer's vocabulary picker already was while the buyer got a wall of checkboxes, then 29.25 → 30.5 KB for the panel that draws all of it: groups and ranges as one ordered sequence with one «Apply» for the panel rather than one per row, the empty-group heading rule, `categoryFilter={false}` and the `resultsLead` slot for a page reached by walking the catalogue, `PopularValues columns=\\\"responsive\\\"` on a container query, `SortSelect` annotating a blocked option at every width, a loading arm that covers the whole pane (0.34 CLS on a live host), and the chip row reserving its own box (a further 0.045). Measured with dependencies held constant, this package's src at the commit before that work and then at it: 29.05 -> 30.16 KB — 1.11 KB, and every part of it is a shift or a mislabelled control a host was living with, then 30.5 -> 31 KB for `<SearchResultsPane columns>` and its pass-through on `<SearchPage resultsColumns>`: a fixed track count or a per-breakpoint map, emitted as a hoisted container-query sheet (the results block is the window minus a 280px rail, so a media query would answer about a width the cards never have). Measured with dependencies held constant, this package's src before and after: 30.40 -> 30.65 KB — 250 B, and what it replaces is a host's `!important` rule against a grid declaration it could not read back, then 31 -> 31.25 KB for the segmented partition being antd's `Segmented` rather than a row of buttons wearing a border: the walker read `data-variant=\"segmented\"` with `role=\"radiogroup\"` and found `.ant-segmented` zero times and `input[type=radio]` zero times (D304), so the cells are the design system's now — real radios under one name, the browser's own arrow keys and Tab stop. Measured with dependencies held constant, this package's src before and after: 30.95 -> 31.05 KB — 100 B, against ~30 lines of hand-rolled joined-row geometry deleted",
61
61
  "path": "dist/default/index.js",
62
- "limit": "31 KB"
62
+ "limit": "31.25 KB"
63
63
  },
64
64
  {
65
65
  "name": "router — the react-router binding is opt-in; the main entry must never pull a router",
@@ -115,7 +115,7 @@
115
115
  "size-limit": "^11.2.0",
116
116
  "typescript": "^5.8.3",
117
117
  "vitest": "^3.2.4",
118
- "@stapel/attributes-react": "^0.16.4",
118
+ "@stapel/attributes-react": "^0.16.5",
119
119
  "@stapel/core": "^0.25.4",
120
120
  "@stapel/image": "^0.4.2",
121
121
  "@stapel/showcase": "^0.3.0",
@@ -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.32.7",
4
+ "version": "0.32.8",
5
5
  "defined": [],
6
6
  "flows": []
7
7
  }
@@ -25,6 +25,28 @@
25
25
  * with roving tabindex is the pattern for "one of these": Tab reaches the row
26
26
  * once and lands on the chosen chip, the arrow keys move along it, and the
27
27
  * group's own name says what is being chosen.
28
+ *
29
+ * ── The two variants are two CONTROLS, and each one is real ───────────────
30
+ *
31
+ * `chips` is this file's own row of `role="radio"` buttons — pills that wrap,
32
+ * the phone's shape.
33
+ *
34
+ * `segmented` is antd's `Segmented`, and it used to be this same row with a
35
+ * shared border drawn round it. That was a claim nothing backed: the walker
36
+ * read `data-variant="segmented"` with `role="radiogroup"` and found
37
+ * `.ant-segmented` zero times, `input[type=radio]` zero times, and plain
38
+ * `ant-btn` inside — on both axes of two categories (D304). A row that names
39
+ * a control it does not render sends the next reader looking for a bug in the
40
+ * wrong place, and hand-rolling the joined look was ~30 lines re-deciding
41
+ * geometry the design system already owns.
42
+ *
43
+ * So the segmented arm IS the design system's control now, and its radiogroup
44
+ * is the browser's rather than ours: real `input[type=radio]` sharing one
45
+ * `name`, so the selected state is the radio's own `checked` (`aria-checked`
46
+ * is how a BUTTON fakes what a radio has), the arrow keys are the control's,
47
+ * and one Tab stop is the platform's doing. The per-cell test ids stay where
48
+ * they were, plus `data-checked`, so a probe that reads a snapshot still has
49
+ * the chosen cell without asking the accessibility tree.
28
50
  */
29
51
  import { useRef } from "react";
30
52
  import type {
@@ -33,9 +55,9 @@ import type {
33
55
  ReactElement,
34
56
  ReactNode,
35
57
  } from "react";
36
- import { Button } from "antd";
58
+ import { Button, Segmented } from "antd";
37
59
  import { useT } from "@stapel/core";
38
- import { cssVar, radii, spacing } from "@stapel/tokens";
60
+ import { radii, spacing } from "@stapel/tokens";
39
61
  import { SEARCH_I18N_KEYS } from "../i18n/keys.js";
40
62
 
41
63
  /** One child of a partitioned category. `path` is the slash-joined id path
@@ -61,19 +83,26 @@ export interface PartitionChipsProps {
61
83
  /**
62
84
  * Which shape the row takes. `"chips"` (the default) is the phone's: a
63
85
  * wrapping row of rounded pills above the feed. `"segmented"` is the
64
- * desktop RAIL's — one joined control under the axis's own label, which is
65
- * how the reference classified draws the same choice (a car-type row:
66
- * all, used, new) and what a 280px column has room for.
86
+ * desktop RAIL's — antd's `Segmented`, one joined control under the axis's
87
+ * own label, which is how the reference classified draws the same choice (a
88
+ * car-type row: all, used, new) and what a 280px column has room for.
67
89
  *
68
- * The SEMANTICS do not vary with it. Both are the same `radiogroup` with
69
- * the same roving tabindex and the same arrow keys a segmented look is a
70
- * border-radius decision, and swapping in a component that draws joined
71
- * cells by giving up "exactly one of these is true" would trade the
72
- * accessible half of this control for the visible half.
90
+ * The SEMANTICS do not vary with it: both are a `radiogroup` naming itself,
91
+ * with one Tab stop and the arrow keys moving the choice. What varies is
92
+ * who provides them this file's `role="radio"` buttons in `chips`, the
93
+ * browser's own `input[type=radio]` in `segmented`.
73
94
  */
74
95
  readonly variant?: "chips" | "segmented";
75
96
  }
76
97
 
98
+ /**
99
+ * The `value` of the parent cell inside the segmented control. `null` is this
100
+ * component's word for "the parent, unnarrowed" and a radio's value is a
101
+ * string, so the sentinel exists only between here and antd — it never
102
+ * reaches {@link PartitionChipsProps.onChange}, which still reports `null`.
103
+ */
104
+ const ALL = "__all__";
105
+
77
106
  const CHIP: CSSProperties = { borderRadius: radii.full };
78
107
 
79
108
  const ROW: CSSProperties = {
@@ -82,33 +111,6 @@ const ROW: CSSProperties = {
82
111
  gap: spacing[2],
83
112
  };
84
113
 
85
- /**
86
- * The segmented row: one joined control, no gaps, the group's own outline.
87
- *
88
- * `gap: 0` plus a shared border is what makes three buttons read as one
89
- * control — the thing a rail needs, because a wrapping pill row in a 280px
90
- * column is two ragged lines. `overflow: hidden` clips the cells' own corners
91
- * to the group's radius so the ends are round and the joins are square.
92
- */
93
- const SEGMENTED_ROW: CSSProperties = {
94
- display: "flex",
95
- gap: 0,
96
- inlineSize: "100%",
97
- border: `1px solid ${cssVar("border")}`,
98
- borderRadius: cssVar("radius-md"),
99
- overflow: "hidden",
100
- };
101
-
102
- /** One cell of the segmented row: an equal share of the width, square joins,
103
- * no border of its own — the group draws the outline. */
104
- const SEGMENTED_CELL: CSSProperties = {
105
- flex: "1 1 0",
106
- minInlineSize: 0,
107
- borderRadius: 0,
108
- borderInline: "none",
109
- borderBlock: "none",
110
- };
111
-
112
114
  /** The row's cells, as `[value, label]` — the parent first, then the
113
115
  * children in catalogue order. */
114
116
  function cells(
@@ -163,30 +165,68 @@ export function PartitionChips(props: PartitionChipsProps): ReactElement {
163
165
  const active = options.findIndex(([value]) => value === props.value);
164
166
  const stop = active >= 0 ? active : 0;
165
167
 
166
- const segmented = props.variant === "segmented";
168
+ const name = props.label ?? t(SEARCH_I18N_KEYS.partitionLabel);
169
+
170
+ if (props.variant === "segmented") {
171
+ // antd's own control: `.ant-segmented`, one `input[type=radio]` per cell
172
+ // under a shared `name`, the selected cell's `checked`, and the arrow keys
173
+ // — the radiogroup this variant used to only claim to be. `role` and
174
+ // `aria-label` reach the root because the component spreads what it is
175
+ // given over its own defaults (which are `radiogroup` and the string
176
+ // "segmented control").
177
+ return (
178
+ <Segmented
179
+ block
180
+ size="small"
181
+ role="radiogroup"
182
+ aria-label={name}
183
+ data-variant="segmented"
184
+ data-testid="partition-chips"
185
+ value={props.value ?? ALL}
186
+ options={options.map(([value, label]) => ({
187
+ value: value ?? ALL,
188
+ label: (
189
+ // The cell's test id and its chosen state, on the one node inside
190
+ // a cell this component owns — antd names the cells itself, and a
191
+ // label a radio is bound to is what a click has to land on.
192
+ <span
193
+ data-testid={`partition-chip-${value ?? "all"}`}
194
+ data-checked={value === props.value ? "true" : "false"}
195
+ >
196
+ {label}
197
+ </span>
198
+ ),
199
+ }))}
200
+ onChange={(next) => {
201
+ props.onChange(next === ALL ? null : String(next));
202
+ }}
203
+ />
204
+ );
205
+ }
206
+
167
207
  return (
168
208
  <div
169
- style={segmented ? SEGMENTED_ROW : ROW}
170
- data-variant={segmented ? "segmented" : "chips"}
209
+ style={ROW}
210
+ data-variant="chips"
171
211
  ref={row}
172
212
  role="radiogroup"
173
- aria-label={props.label ?? t(SEARCH_I18N_KEYS.partitionLabel)}
213
+ aria-label={name}
174
214
  data-testid="partition-chips"
175
215
  >
176
216
  {options.map(([value, label], index) => {
177
217
  const selected = value === props.value;
178
218
  return (
179
219
  <Button
180
- key={value ?? "__all__"}
220
+ key={value ?? ALL}
181
221
  size="small"
182
- {...(segmented ? {} : { shape: "round" as const })}
222
+ shape="round"
183
223
  type={selected ? "primary" : "default"}
184
224
  role="radio"
185
225
  aria-checked={selected}
186
226
  // Roving tabindex: the row is ONE Tab stop and it lands on the
187
227
  // chosen chip, not on the first of eight.
188
228
  tabIndex={index === stop ? 0 : -1}
189
- style={segmented ? SEGMENTED_CELL : CHIP}
229
+ style={CHIP}
190
230
  data-testid={`partition-chip-${value ?? "all"}`}
191
231
  data-analytics="none"
192
232
  data-analytics-reason="choosing a section is a read, not a flow step"