@stapel/search-react 0.7.0 → 0.9.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 +61 -0
- package/dist/default/FacetGroupControl.d.ts +40 -0
- package/dist/default/FacetGroupControl.d.ts.map +1 -0
- package/dist/default/FacetGroupControl.js +176 -0
- package/dist/default/FacetGroupControl.js.map +1 -0
- package/dist/default/FacetPanelPane.d.ts +30 -0
- package/dist/default/FacetPanelPane.d.ts.map +1 -1
- package/dist/default/FacetPanelPane.js +28 -16
- package/dist/default/FacetPanelPane.js.map +1 -1
- package/dist/default/FilterChips.d.ts +37 -0
- package/dist/default/FilterChips.d.ts.map +1 -0
- package/dist/default/FilterChips.js +203 -0
- package/dist/default/FilterChips.js.map +1 -0
- package/dist/default/SearchPage.d.ts +59 -0
- package/dist/default/SearchPage.d.ts.map +1 -1
- package/dist/default/SearchPage.js +60 -10
- package/dist/default/SearchPage.js.map +1 -1
- package/dist/default/SearchResultsPane.d.ts +19 -0
- package/dist/default/SearchResultsPane.d.ts.map +1 -1
- package/dist/default/SearchResultsPane.js +15 -2
- package/dist/default/SearchResultsPane.js.map +1 -1
- package/dist/default/ViewSwitch.d.ts +66 -0
- package/dist/default/ViewSwitch.d.ts.map +1 -0
- package/dist/default/ViewSwitch.js +49 -0
- package/dist/default/ViewSwitch.js.map +1 -0
- package/dist/default/index.d.ts +12 -1
- package/dist/default/index.d.ts.map +1 -1
- package/dist/default/index.js +9 -1
- package/dist/default/index.js.map +1 -1
- package/dist/headless/SearchStateProvider.d.ts +35 -0
- package/dist/headless/SearchStateProvider.d.ts.map +1 -1
- package/dist/headless/SearchStateProvider.js +38 -3
- package/dist/headless/SearchStateProvider.js.map +1 -1
- package/dist/i18n/es.d.ts.map +1 -1
- package/dist/i18n/es.js +9 -1
- package/dist/i18n/es.js.map +1 -1
- package/dist/i18n/keys.d.ts +32 -1
- package/dist/i18n/keys.d.ts.map +1 -1
- package/dist/i18n/keys.js +42 -2
- package/dist/i18n/keys.js.map +1 -1
- package/dist/i18n/ru.d.ts.map +1 -1
- package/dist/i18n/ru.js +9 -1
- package/dist/i18n/ru.js.map +1 -1
- package/llms.txt +2 -1
- package/manifest.json +32 -3
- package/nav-manifest.json +1 -1
- package/package.json +8 -8
- package/src/analytics/generated/events.json +1 -1
- package/src/default/FacetGroupControl.tsx +312 -0
- package/src/default/FacetPanelPane.tsx +57 -63
- package/src/default/FilterChips.tsx +423 -0
- package/src/default/SearchPage.tsx +158 -16
- package/src/default/SearchResultsPane.tsx +39 -2
- package/src/default/ViewSwitch.tsx +147 -0
- package/src/default/index.ts +23 -1
- package/src/headless/SearchStateProvider.tsx +80 -3
- package/src/i18n/es.ts +10 -1
- package/src/i18n/keys.ts +44 -2
- package/src/i18n/ru.ts +10 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,66 @@
|
|
|
1
1
|
# @stapel/search-react
|
|
2
2
|
|
|
3
|
+
## 0.9.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e1b1d9b: **A location is now said in words, and a search can open where the visitor is.** `geoLabel` and `defaultGeo` on `<SearchPage>`; `geoLabel` on `<FacetPanelPane>` and `<FilterChips>`; `defaultGeo` on `<SearchStateProvider>`.
|
|
8
|
+
|
|
9
|
+
**The panel printed coordinates.** Under the "Location" heading, on the desktop rail and on the phone's location chip, a person who had chosen a place on a map read `Around 55.756, 37.617`. That is the pair's own storage leaking onto the screen: `lat`/`lon`/`radius_km` are URL parameters because the URL is the state, and none of that is a display concern. Two numbers to three decimals cannot be checked by the one reader who could have checked an address — so a point that landed in the wrong suburb looked exactly as authoritative as the right one, and the right one looked like machinery. It is the same defect class this pair is careful about everywhere else: a value rendered as if it were an answer, when nobody can tell whether it is.
|
|
10
|
+
|
|
11
|
+
**`geoLabel`** is what the constraint is CALLED. Whoever turned an address into that point still has the address — the geocoder's own answer, the city an IP guess named, the text on the map pin — and hands it back: `geoLabel="Tverskaya, Moscow"`. Set it once on `<SearchPage>` and both filter surfaces take it, so the chip row and the rail cannot drift into describing the same URL two different ways. Without one the line reads **"A chosen place on the map"** (`search.geo.chosen_place`, en/ru/es) — an honest sentence about a place this package genuinely cannot name, because naming it needs a geocoder and a search package must not grow one to fix a bad line. `search.geo.center` (`"Around {lat}, {lon}"`) is **removed** from the key registry and from all three bundles; the bbox sentence is unchanged, since an area on the screen was always describable without measuring it.
|
|
12
|
+
|
|
13
|
+
**`defaultGeo` — the search opens where the visitor is.** A storefront that knows roughly where somebody is standing should not make them type it: a granted browser prompt, or the server's IP guess when there was none. The host resolves it — `usePermission("geolocation")` and a geocoder both live outside this pair — and passes the two numbers in. The page still does not know what a map is.
|
|
14
|
+
|
|
15
|
+
Everything hard about the feature is about not overruling anybody, and the URL is what makes the rules statable:
|
|
16
|
+
|
|
17
|
+
- **Only into a URL that carries no geo at all.** A link with `lat`/`lon` or `bbox` already means a place, and it must mean the same place for everyone who opens it. A default that overwrote it would turn one address bar into two different searches.
|
|
18
|
+
- **Once, and never again after a clear.** Tracked as "has anyone spoken about location yet" in a ref, not by comparing the default against the current value — a cleared location and an unapplied default are identical in the state, and only the record of who spoke tells them apart. `setGeo` marks the question answered, including when the answer is "anywhere".
|
|
19
|
+
- **Late is fine.** A permission prompt and an IP round trip both resolve after the first paint, so `undefined` on mount and a value three renders later still applies — provided the URL is still empty of geo at that moment. The prop is typed `SearchGeo | undefined` for exactly this, so a host passes what it has without a conditional spread.
|
|
20
|
+
- **It replaces the history entry rather than pushing one.** The visitor did not perform this change; Back should leave the page, not undo a centring they never asked for. The adapter seam has carried `{ replace: true }` since it was written, and the react-router binding honours it.
|
|
21
|
+
|
|
22
|
+
Tests cover all four rules plus the wire the centred search actually goes out on, and assert the coordinate's own digits appear nowhere in the rendered page — on either surface, in a chip, a heading or an aria-label — because a future sentence that quietly reintroduces them under a different key is the same defect.
|
|
23
|
+
|
|
24
|
+
## 0.8.0
|
|
25
|
+
|
|
26
|
+
### Minor Changes
|
|
27
|
+
|
|
28
|
+
- 62c70ac: The classified layout, in the default skins.
|
|
29
|
+
|
|
30
|
+
Built where the doctrine says the product lives, so every future classified
|
|
31
|
+
deployment gets it rather than rebuilding it.
|
|
32
|
+
|
|
33
|
+
- `shell-react` — `NavDock`, a floating translucent island rather than a flat
|
|
34
|
+
bar: inset from every edge, real border and shadow, safe-area aware. The
|
|
35
|
+
glass is progressive enhancement, not the design — the opaque elevated fill
|
|
36
|
+
is the base and the blur is swapped in only inside an `@supports` for
|
|
37
|
+
`backdrop-filter`, so text contrast never depends on transparency being
|
|
38
|
+
available. Destinations are the first five top-level nav entries in the
|
|
39
|
+
order the manifest already declares, so there is no second selection axis.
|
|
40
|
+
Real links, `aria-current`, and the badge count folded into each link's
|
|
41
|
+
accessible name.
|
|
42
|
+
- `search-react` — a phone gets a scrollable chip row instead of one
|
|
43
|
+
"Filters" button, each chip opening its own `SkinDialog`, and chips carry
|
|
44
|
+
the CHOICE rather than the group name. A desktop gets a sticky full-height
|
|
45
|
+
rail. Both render through one `FacetGroupControl`, so the rail and the
|
|
46
|
+
sheets cannot drift into two implementations — and a group's shape is
|
|
47
|
+
derived from the schema keys the composer's editor already reads
|
|
48
|
+
(`maxSelected: 1` → pills, `hierarchical_select` → indented children)
|
|
49
|
+
rather than a new presentation flag. Plus a list/grid view switch, which is
|
|
50
|
+
not URL state because it changes how an answer is drawn and never what it
|
|
51
|
+
is.
|
|
52
|
+
- `listings-react` — the whole card is one real anchor: photo, price, title
|
|
53
|
+
and location inside it, the favourite heart a sibling button outside it so
|
|
54
|
+
the link cannot swallow it. The separate "open" control is gone and its
|
|
55
|
+
i18n key is retired. Middle-click, open-in-new-tab and crawlers still work,
|
|
56
|
+
and the anchor's accessible name is the title alone.
|
|
57
|
+
|
|
58
|
+
Parts of the reference layout that do not fit a generic contract are slots
|
|
59
|
+
with a stated reason rather than invented content: "notify me about new ones"
|
|
60
|
+
(a saved search has an owner, a schedule and a consent record this pair has
|
|
61
|
+
none of), the breadcrumb (a walk up a tree search cannot see), and map view
|
|
62
|
+
(a `SearchView` whose tiles belong to geo-react).
|
|
63
|
+
|
|
3
64
|
## 0.7.0
|
|
4
65
|
|
|
5
66
|
### Minor Changes
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
import type { FacetGroup, FacetOption } from "../state/facets.js";
|
|
3
|
+
/**
|
|
4
|
+
* How many options a group shows before the rest go behind "Show all".
|
|
5
|
+
*
|
|
6
|
+
* Eight is the count at which a group stops being readable at a glance and
|
|
7
|
+
* starts being a scroll: it is two more than the six the visual pass measured
|
|
8
|
+
* as the fold on a 390px phone with the sheet's own chrome above it, which
|
|
9
|
+
* leaves a group of seven whole rather than truncated by one row.
|
|
10
|
+
*/
|
|
11
|
+
export declare const FACET_VISIBLE_OPTIONS = 8;
|
|
12
|
+
/** The three shapes a facet group takes. */
|
|
13
|
+
export type FacetGroupShape = "segmented" | "nested" | "checkbox";
|
|
14
|
+
/** The option rows of a group, already nested where the schema nests them. */
|
|
15
|
+
export interface FacetOptionNode {
|
|
16
|
+
readonly option: FacetOption;
|
|
17
|
+
/** 0 for a root option; 1+ for a child of a `hierarchical_select` tree. */
|
|
18
|
+
readonly depth: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Which of the three shapes a group takes.
|
|
22
|
+
*
|
|
23
|
+
* Order matters: a hierarchical facet is nested even when it is single-choice,
|
|
24
|
+
* because losing the tree costs more than losing the pills.
|
|
25
|
+
*/
|
|
26
|
+
export declare function facetGroupShape(group: FacetGroup): FacetGroupShape;
|
|
27
|
+
/** The group's options in render order, carrying the depth the schema gives. */
|
|
28
|
+
export declare function facetOptionNodes(group: FacetGroup): readonly FacetOptionNode[];
|
|
29
|
+
export interface FacetGroupControlProps {
|
|
30
|
+
readonly group: FacetGroup;
|
|
31
|
+
readonly onToggle: (slug: string, value: string) => void;
|
|
32
|
+
/** Draw the group's own name above its options. `false` for a surface that
|
|
33
|
+
* has already said it — a per-group sheet whose title IS the group. */
|
|
34
|
+
readonly heading?: boolean;
|
|
35
|
+
/** How many options before "Show all". Default {@link FACET_VISIBLE_OPTIONS};
|
|
36
|
+
* `null` shows every option (a sheet devoted to one group has the room). */
|
|
37
|
+
readonly visibleOptions?: number | null;
|
|
38
|
+
}
|
|
39
|
+
export declare function FacetGroupControl(props: FacetGroupControlProps): ReactElement;
|
|
40
|
+
//# sourceMappingURL=FacetGroupControl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FacetGroupControl.d.ts","sourceRoot":"","sources":["../../src/default/FacetGroupControl.tsx"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAAiB,YAAY,EAAE,MAAM,OAAO,CAAC;AAMzD,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGlE;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC,4CAA4C;AAC5C,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,QAAQ,GAAG,UAAU,CAAC;AAElE,8EAA8E;AAC9E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAwCD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,eAAe,CAMlE;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,eAAe,EAAE,CAqB9E;AA6FD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACzD;2EACuE;IACvE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B;gFAC4E;IAC5E,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzC;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,YAAY,CAqE7E"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* `<FacetGroupControl>` — ONE facet group, drawn the way its own schema says
|
|
4
|
+
* it should be drawn.
|
|
5
|
+
*
|
|
6
|
+
* Until this release every group was the same thing: a flat column of
|
|
7
|
+
* checkboxes, however many options it had and whatever the category schema
|
|
8
|
+
* said about it. That is wrong in three ways a person meets on the first
|
|
9
|
+
* screen of a real catalogue:
|
|
10
|
+
*
|
|
11
|
+
* 1. **A single-choice facet is not a checkbox list.** `maxSelected: 1` is a
|
|
12
|
+
* fact the schema already carries, and `@stapel/attributes-react`'s editor
|
|
13
|
+
* already reads it to draw a segmented control rather than a set of boxes.
|
|
14
|
+
* A filter that says "pick one" with controls that say "pick any" teaches
|
|
15
|
+
* the wrong thing before the click and surprises after it.
|
|
16
|
+
* 2. **A hierarchical facet is not flat.** `hierarchical_select` carries a
|
|
17
|
+
* TREE in `config.options`; rendering its values as one alphabetical
|
|
18
|
+
* column hides that "Sedan" is under "Cars" and puts a child next to its
|
|
19
|
+
* own parent as if they were siblings.
|
|
20
|
+
* 3. **A 60-option facet is not a list, it is a wall.** Every catalogue has
|
|
21
|
+
* one — brand, model, city — and printing all of it pushes every group
|
|
22
|
+
* under it off the screen.
|
|
23
|
+
*
|
|
24
|
+
* ── The presentation is DERIVED, never configured here ────────────────────
|
|
25
|
+
*
|
|
26
|
+
* {@link facetGroupShape} reads the same `config` keys the attributes editor
|
|
27
|
+
* reads (`maxSelected`, `type`, `options`), so a facet cannot look one way in
|
|
28
|
+
* the filter and another way in the composer that produced the value. There is
|
|
29
|
+
* no `presentation` prop on this component and there must not be one: a
|
|
30
|
+
* per-call-site override is how the two halves drift.
|
|
31
|
+
*
|
|
32
|
+
* A group with NO schema (the host passed no `categoryFeatures`, or the slug
|
|
33
|
+
* is not in it) is a flat checkbox list — the honest default, and the shape
|
|
34
|
+
* every group had before.
|
|
35
|
+
*/
|
|
36
|
+
import { useState } from "react";
|
|
37
|
+
import { Button, Checkbox, Flex, Typography } from "antd";
|
|
38
|
+
import { useT } from "@stapel/core";
|
|
39
|
+
import { radii, spacing } from "@stapel/tokens";
|
|
40
|
+
import { featureConfig, featureType } from "@stapel/attributes-react";
|
|
41
|
+
import { SEARCH_I18N_KEYS } from "../i18n/keys.js";
|
|
42
|
+
/**
|
|
43
|
+
* How many options a group shows before the rest go behind "Show all".
|
|
44
|
+
*
|
|
45
|
+
* Eight is the count at which a group stops being readable at a glance and
|
|
46
|
+
* starts being a scroll: it is two more than the six the visual pass measured
|
|
47
|
+
* as the fold on a 390px phone with the sheet's own chrome above it, which
|
|
48
|
+
* leaves a group of seven whole rather than truncated by one row.
|
|
49
|
+
*/
|
|
50
|
+
export const FACET_VISIBLE_OPTIONS = 8;
|
|
51
|
+
function numberish(value) {
|
|
52
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The DEPTH of every value a `hierarchical_select` config declares, walked
|
|
56
|
+
* once — `{value: depth}`.
|
|
57
|
+
*
|
|
58
|
+
* The tree lives in `config.options[].children[]` (the same shape
|
|
59
|
+
* `@stapel/attributes-react`'s `Cascader` reads). The facets themselves arrive
|
|
60
|
+
* FLAT from the server, because an index term has no parent; the schema is the
|
|
61
|
+
* only thing that knows one value sits under another.
|
|
62
|
+
*/
|
|
63
|
+
function optionDepths(raw, depth = 0, into = new Map()) {
|
|
64
|
+
if (!Array.isArray(raw))
|
|
65
|
+
return into;
|
|
66
|
+
for (const option of raw) {
|
|
67
|
+
if (option === null || typeof option !== "object")
|
|
68
|
+
continue;
|
|
69
|
+
const entry = option;
|
|
70
|
+
if (entry.value !== undefined && entry.value !== null) {
|
|
71
|
+
into.set(String(entry.value), depth);
|
|
72
|
+
}
|
|
73
|
+
optionDepths(entry.children, depth + 1, into);
|
|
74
|
+
}
|
|
75
|
+
return into;
|
|
76
|
+
}
|
|
77
|
+
/** Is this feature single-choice? The schema's own answer, not a guess. */
|
|
78
|
+
function singleChoice(feature) {
|
|
79
|
+
if (feature === undefined)
|
|
80
|
+
return false;
|
|
81
|
+
// `maxSelected` ABSENT means unlimited — the engine's own default. Reading
|
|
82
|
+
// an absent key as 1 would turn every unconfigured facet into a radio group.
|
|
83
|
+
return numberish(featureConfig(feature)["maxSelected"]) === 1;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Which of the three shapes a group takes.
|
|
87
|
+
*
|
|
88
|
+
* Order matters: a hierarchical facet is nested even when it is single-choice,
|
|
89
|
+
* because losing the tree costs more than losing the pills.
|
|
90
|
+
*/
|
|
91
|
+
export function facetGroupShape(group) {
|
|
92
|
+
const feature = group.feature;
|
|
93
|
+
if (feature !== undefined && featureType(feature) === "hierarchical_select") {
|
|
94
|
+
return "nested";
|
|
95
|
+
}
|
|
96
|
+
return singleChoice(feature) ? "segmented" : "checkbox";
|
|
97
|
+
}
|
|
98
|
+
/** The group's options in render order, carrying the depth the schema gives. */
|
|
99
|
+
export function facetOptionNodes(group) {
|
|
100
|
+
if (facetGroupShape(group) !== "nested" || group.feature === undefined) {
|
|
101
|
+
return group.options.map((option) => ({ option, depth: 0 }));
|
|
102
|
+
}
|
|
103
|
+
const depths = optionDepths(featureConfig(group.feature)["options"]);
|
|
104
|
+
// Depth alone would leave children beside strangers: the options are
|
|
105
|
+
// re-ordered so each child follows its own parent, and a value the schema
|
|
106
|
+
// does not know keeps depth 0 rather than being hidden under someone.
|
|
107
|
+
const byValue = new Map(group.options.map((option) => [option.value, option]));
|
|
108
|
+
const out = [];
|
|
109
|
+
const emitted = new Set();
|
|
110
|
+
for (const [value, depth] of depths) {
|
|
111
|
+
const option = byValue.get(value);
|
|
112
|
+
if (option === undefined)
|
|
113
|
+
continue;
|
|
114
|
+
out.push({ option, depth });
|
|
115
|
+
emitted.add(value);
|
|
116
|
+
}
|
|
117
|
+
for (const option of group.options) {
|
|
118
|
+
if (!emitted.has(option.value))
|
|
119
|
+
out.push({ option, depth: 0 });
|
|
120
|
+
}
|
|
121
|
+
return out;
|
|
122
|
+
}
|
|
123
|
+
/** A count, or the honest "we did not count this". Never a zero standing in
|
|
124
|
+
* for an absent answer. */
|
|
125
|
+
function OptionCount(props) {
|
|
126
|
+
const t = useT();
|
|
127
|
+
return (_jsx(Typography.Text, { type: "secondary", "data-testid": `facet-count-${props.group.slug}-${props.option.value}`, children: props.option.count === null
|
|
128
|
+
? t(SEARCH_I18N_KEYS.facetsNotCounted)
|
|
129
|
+
: props.option.count }));
|
|
130
|
+
}
|
|
131
|
+
/** The indent one level of a hierarchical facet is drawn with. */
|
|
132
|
+
const NEST_STEP = spacing[5];
|
|
133
|
+
function CheckboxRow(props) {
|
|
134
|
+
const { group, node } = props;
|
|
135
|
+
return (_jsxs(Flex, { justify: "space-between", align: "center", gap: spacing[2], style: node.depth > 0
|
|
136
|
+
? { paddingInlineStart: node.depth * NEST_STEP }
|
|
137
|
+
: undefined, "data-depth": node.depth, children: [_jsx(Checkbox, { checked: node.option.selected, "data-testid": `facet-option-${group.slug}-${node.option.value}`, "data-analytics": "none", "data-analytics-reason": "a filter is a read, not a flow step", onChange: () => {
|
|
138
|
+
props.onToggle(group.slug, node.option.value);
|
|
139
|
+
}, children: node.option.label }), _jsx(OptionCount, { group: group, option: node.option })] }));
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* One pill of a single-choice group.
|
|
143
|
+
*
|
|
144
|
+
* A real `<button aria-pressed>` rather than antd's `Segmented`: the count has
|
|
145
|
+
* to sit inside the pill (a filter without its remaining count is the
|
|
146
|
+
* drill-down facet turned naive), and `Segmented` takes labels, not rows.
|
|
147
|
+
* `aria-pressed` is what makes a styled button a TOGGLE to a screen reader
|
|
148
|
+
* instead of a link-shaped thing that mysteriously changes the page.
|
|
149
|
+
*/
|
|
150
|
+
function OptionPill(props) {
|
|
151
|
+
const { group, option } = props;
|
|
152
|
+
const style = { borderRadius: radii.full };
|
|
153
|
+
return (_jsx(Button, { size: "small", shape: "round", type: option.selected ? "primary" : "default", "aria-pressed": option.selected, style: style, "data-testid": `facet-option-${group.slug}-${option.value}`, "data-analytics": "none", "data-analytics-reason": "a filter is a read, not a flow step", onClick: () => {
|
|
154
|
+
props.onToggle(group.slug, option.value);
|
|
155
|
+
}, children: option.count === null ? option.label : `${option.label} ${option.count}` }));
|
|
156
|
+
}
|
|
157
|
+
export function FacetGroupControl(props) {
|
|
158
|
+
const t = useT();
|
|
159
|
+
const { group } = props;
|
|
160
|
+
const [expanded, setExpanded] = useState(false);
|
|
161
|
+
const shape = facetGroupShape(group);
|
|
162
|
+
const nodes = facetOptionNodes(group);
|
|
163
|
+
const limit = props.visibleOptions === null
|
|
164
|
+
? null
|
|
165
|
+
: (props.visibleOptions ?? FACET_VISIBLE_OPTIONS);
|
|
166
|
+
// A group one row over the limit is not truncated: hiding a single option
|
|
167
|
+
// behind "Show all (9)" costs a tap to reveal exactly one thing.
|
|
168
|
+
const collapsible = limit !== null && nodes.length > limit + 1;
|
|
169
|
+
const shown = collapsible && !expanded ? nodes.slice(0, limit) : nodes;
|
|
170
|
+
return (_jsxs(Flex, { vertical: true, gap: shape === "segmented" ? spacing[2] : spacing[1], "data-testid": `facet-group-${group.slug}`, "data-counted": group.counted ? "true" : "false", "data-shape": shape, children: [props.heading !== false && (_jsx(Typography.Text, { strong: true, children: group.label })), shape === "segmented" ? (_jsx(Flex, { wrap: true, gap: spacing[2], children: shown.map((node) => (_jsx(OptionPill, { group: group, option: node.option, onToggle: props.onToggle }, node.option.value))) })) : (shown.map((node) => (_jsx(CheckboxRow, { group: group, node: node, onToggle: props.onToggle }, node.option.value)))), collapsible && (_jsx(Button, { type: "link", size: "small", style: { alignSelf: "flex-start", paddingInline: 0 }, "data-testid": `facet-more-${group.slug}`, "data-analytics": "none", "data-analytics-reason": "expanding a filter group is a read, not a flow step", onClick: () => {
|
|
171
|
+
setExpanded((was) => !was);
|
|
172
|
+
}, children: expanded
|
|
173
|
+
? t(SEARCH_I18N_KEYS.facetsShowLess)
|
|
174
|
+
: t(SEARCH_I18N_KEYS.facetsShowAll, { count: nodes.length }) }))] }));
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=FacetGroupControl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FacetGroupControl.js","sourceRoot":"","sources":["../../src/default/FacetGroupControl.tsx"],"names":[],"mappings":"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"}
|
|
@@ -62,6 +62,22 @@ export interface FacetPanelPaneProps extends ThemeModeProp {
|
|
|
62
62
|
/** The location control (`geo-react`). Unfilled, a location that arrived in
|
|
63
63
|
* the URL still gets its radius and a "clear" control. */
|
|
64
64
|
readonly renderGeoFilter?: (slot: GeoFilterSlotProps) => ReactNode;
|
|
65
|
+
/**
|
|
66
|
+
* What the current location constraint is CALLED, in words — the address or
|
|
67
|
+
* the city the host resolved.
|
|
68
|
+
*
|
|
69
|
+
* The panel owns `lat`/`lon`/`radius_km` as URL state and must never render
|
|
70
|
+
* them: a coordinate is what gets STORED, and storage is not a display
|
|
71
|
+
* concern. `55.756, 37.617` is unreadable to the one person who could have
|
|
72
|
+
* caught the mistake, so a wrong point looks as authoritative as a right one
|
|
73
|
+
* and a right one looks like machinery.
|
|
74
|
+
*
|
|
75
|
+
* Whoever turned an address into that point still has the address — the
|
|
76
|
+
* geocoder's own answer, the city an IP guess named, the label on the map
|
|
77
|
+
* pin — and hands it back here. Absent, the panel says a location is applied
|
|
78
|
+
* without pretending to name it (`search.geo.chosen_place`).
|
|
79
|
+
*/
|
|
80
|
+
readonly geoLabel?: ReactNode;
|
|
65
81
|
/** BCP-47 tags this deployment indexes — see {@link LanguageSelect}. */
|
|
66
82
|
readonly languages?: readonly string[];
|
|
67
83
|
/**
|
|
@@ -73,5 +89,19 @@ export interface FacetPanelPaneProps extends ThemeModeProp {
|
|
|
73
89
|
*/
|
|
74
90
|
readonly heading?: ReactNode;
|
|
75
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* What a location constraint is called when the host handed down no name.
|
|
94
|
+
*
|
|
95
|
+
* Two sentences, and neither of them is a number. A box is describable without
|
|
96
|
+
* one — it is the area on the screen — and a point is not, so the point's
|
|
97
|
+
* sentence says a place was chosen and stops there. The alternative that was
|
|
98
|
+
* shipped for four releases printed `Around 55.756, 37.617`, which is the
|
|
99
|
+
* defect class this pair is otherwise careful about everywhere else: a value
|
|
100
|
+
* the reader cannot check, rendered as if it were an answer.
|
|
101
|
+
*
|
|
102
|
+
* Shared with `<FilterChips>` so the phone row and the desktop panel cannot
|
|
103
|
+
* drift into saying two different things about the same URL.
|
|
104
|
+
*/
|
|
105
|
+
export declare function geoSummaryFallback(geo: SearchGeo, t: (key: string) => string): string;
|
|
76
106
|
export declare function FacetPanelPane(props: FacetPanelPaneProps): ReactElement;
|
|
77
107
|
//# sourceMappingURL=FacetPanelPane.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FacetPanelPane.d.ts","sourceRoot":"","sources":["../../src/default/FacetPanelPane.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"FacetPanelPane.d.ts","sourceRoot":"","sources":["../../src/default/FacetPanelPane.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAkBrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAQjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,gDAAgD;AAChD,MAAM,WAAW,uBAAuB;IACtC,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CAClD;AAED,gDAAgD;AAChD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CAAC;IACtC,6CAA6C;IAC7C,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI,KAAK,IAAI,CAAC;CACpD;AAED,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACxD;wCACoC;IACpC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAClD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B;gFAC4E;IAC5E,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,uBAAuB,KAAK,SAAS,CAAC;IAC7E;8DAC0D;IAC1D,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,SAAS,CAAC;IACnE;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;IAC9B,wEAAwE;IACxE,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;CAC9B;AAiDD;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,SAAS,EACd,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GACzB,MAAM,CAIR;AAuHD,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,YAAY,CA6IvE"}
|
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Alert, Button,
|
|
2
|
+
import { Alert, Button, Divider, Flex, InputNumber, Typography, } from "antd";
|
|
3
3
|
import { SlotPlaceholder, isDevBuild, useT } from "@stapel/core";
|
|
4
4
|
import { EmptyState, ErrorAlert, LoadList, SkinTheme, } from "@stapel/tokens-antd/skin";
|
|
5
5
|
import { spacing } from "@stapel/tokens";
|
|
6
6
|
import { featureName } from "@stapel/attributes-react";
|
|
7
7
|
import { FacetPanel } from "../headless/FacetPanel.js";
|
|
8
8
|
import { useSearchState } from "../headless/SearchStateProvider.js";
|
|
9
|
+
import { FacetGroupControl } from "./FacetGroupControl.js";
|
|
9
10
|
import { buildRangeGroups } from "../state/ranges.js";
|
|
10
11
|
import { SEARCH_I18N_KEYS } from "../i18n/keys.js";
|
|
11
12
|
import { LanguageSelect } from "./LanguageSelect.js";
|
|
12
13
|
import { RangeFilterRow } from "./RangeFilterRow.js";
|
|
13
|
-
function OptionRow(props) {
|
|
14
|
-
const t = useT();
|
|
15
|
-
const { option, group } = props;
|
|
16
|
-
return (_jsxs(Flex, { justify: "space-between", align: "center", gap: spacing[2], children: [_jsx(Checkbox, { checked: option.selected, "data-testid": `facet-option-${group.slug}-${option.value}`, "data-analytics": "none", "data-analytics-reason": "a filter is a read, not a flow step", onChange: () => {
|
|
17
|
-
props.onToggle(group.slug, option.value);
|
|
18
|
-
}, children: option.label }), option.count === null ? (_jsx(Typography.Text, { type: "secondary", "data-testid": `facet-count-${group.slug}-${option.value}`, children: t(SEARCH_I18N_KEYS.facetsNotCounted) })) : (_jsx(Typography.Text, { type: "secondary", "data-testid": `facet-count-${group.slug}-${option.value}`, children: option.count }))] }));
|
|
19
|
-
}
|
|
20
14
|
/** The category constraint: the host's control, or the door out of it. */
|
|
21
15
|
function CategoryFilter(props) {
|
|
22
16
|
const t = useT();
|
|
@@ -37,6 +31,24 @@ function CategoryFilter(props) {
|
|
|
37
31
|
setCategory(null);
|
|
38
32
|
}, children: t(SEARCH_I18N_KEYS.categoryClear) })] }));
|
|
39
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* What a location constraint is called when the host handed down no name.
|
|
36
|
+
*
|
|
37
|
+
* Two sentences, and neither of them is a number. A box is describable without
|
|
38
|
+
* one — it is the area on the screen — and a point is not, so the point's
|
|
39
|
+
* sentence says a place was chosen and stops there. The alternative that was
|
|
40
|
+
* shipped for four releases printed `Around 55.756, 37.617`, which is the
|
|
41
|
+
* defect class this pair is otherwise careful about everywhere else: a value
|
|
42
|
+
* the reader cannot check, rendered as if it were an answer.
|
|
43
|
+
*
|
|
44
|
+
* Shared with `<FilterChips>` so the phone row and the desktop panel cannot
|
|
45
|
+
* drift into saying two different things about the same URL.
|
|
46
|
+
*/
|
|
47
|
+
export function geoSummaryFallback(geo, t) {
|
|
48
|
+
return geo.kind === "bbox"
|
|
49
|
+
? t(SEARCH_I18N_KEYS.geoBox)
|
|
50
|
+
: t(SEARCH_I18N_KEYS.geoChosenPlace);
|
|
51
|
+
}
|
|
40
52
|
/**
|
|
41
53
|
* The location constraint.
|
|
42
54
|
*
|
|
@@ -45,6 +57,11 @@ function CategoryFilter(props) {
|
|
|
45
57
|
* number in the URL, and a link shared with `lat/lon/radius_km` is a link this
|
|
46
58
|
* panel can widen, tighten and clear without knowing what a map is. That is the
|
|
47
59
|
* difference between a slot and a hole.
|
|
60
|
+
*
|
|
61
|
+
* NAMING the centre is a third thing again, and it is the host's: this panel
|
|
62
|
+
* has two numbers and no way to turn them into a place. So it either says the
|
|
63
|
+
* name it was handed (`label`) or says that a place is chosen — never the
|
|
64
|
+
* numbers themselves. See {@link FacetPanelPaneProps.geoLabel}.
|
|
48
65
|
*/
|
|
49
66
|
function GeoFilter(props) {
|
|
50
67
|
const t = useT();
|
|
@@ -70,12 +87,7 @@ function GeoFilter(props) {
|
|
|
70
87
|
return null;
|
|
71
88
|
return slot === null ? null : (_jsxs(Flex, { vertical: true, gap: spacing[1], "data-testid": "search-geo", children: [_jsx(Typography.Text, { strong: true, children: t(SEARCH_I18N_KEYS.geoTitle) }), slot] }));
|
|
72
89
|
}
|
|
73
|
-
return (_jsxs(Flex, { vertical: true, gap: spacing[1], "data-testid": "search-geo", children: [_jsx(Typography.Text, { strong: true, children: t(SEARCH_I18N_KEYS.geoTitle) }), slot, _jsx(Typography.Text, { type: "secondary", "data-testid": "search-geo-summary", children: geo.kind === "
|
|
74
|
-
? t(SEARCH_I18N_KEYS.geoBox)
|
|
75
|
-
: t(SEARCH_I18N_KEYS.geoCenter, {
|
|
76
|
-
lat: geo.lat.toFixed(3),
|
|
77
|
-
lon: geo.lon.toFixed(3),
|
|
78
|
-
}) }), geo.kind === "center" && (_jsxs(Flex, { gap: spacing[2], align: "center", wrap: true, children: [_jsx(Typography.Text, { type: "secondary", "aria-hidden": "true", children: t(SEARCH_I18N_KEYS.geoRadiusLabel) }), _jsx(InputNumber, { min: 1, value: geo.radiusKm ?? null, "aria-label": t(SEARCH_I18N_KEYS.geoRadiusLabel), "data-testid": "search-geo-radius", onChange: (value) => {
|
|
90
|
+
return (_jsxs(Flex, { vertical: true, gap: spacing[1], "data-testid": "search-geo", children: [_jsx(Typography.Text, { strong: true, children: t(SEARCH_I18N_KEYS.geoTitle) }), slot, _jsx(Typography.Text, { type: "secondary", "data-testid": "search-geo-summary", children: props.label ?? geoSummaryFallback(geo, t) }), geo.kind === "center" && (_jsxs(Flex, { gap: spacing[2], align: "center", wrap: true, children: [_jsx(Typography.Text, { type: "secondary", "aria-hidden": "true", children: t(SEARCH_I18N_KEYS.geoRadiusLabel) }), _jsx(InputNumber, { min: 1, value: geo.radiusKm ?? null, "aria-label": t(SEARCH_I18N_KEYS.geoRadiusLabel), "data-testid": "search-geo-radius", onChange: (value) => {
|
|
79
91
|
setGeo({
|
|
80
92
|
kind: "center",
|
|
81
93
|
lat: geo.lat,
|
|
@@ -123,10 +135,10 @@ export function FacetPanelPane(props) {
|
|
|
123
135
|
? { render: props.renderCategoryFilter }
|
|
124
136
|
: {}) }), _jsx(LanguageSelect, { ...(props.languages !== undefined ? { languages: props.languages } : {}) }), _jsx(GeoFilter, { ...(props.renderGeoFilter !== undefined
|
|
125
137
|
? { render: props.renderGeoFilter }
|
|
126
|
-
: {}) }), bag.approximate && (_jsx(Alert, { type: "info", showIcon: true, "data-testid": "facets-approximate", title: t(SEARCH_I18N_KEYS.facetsApproximate) })), bag.skipped.length > 0 && (_jsx(Alert, { type: "warning", showIcon: true, "data-testid": "facets-skipped", title: t(SEARCH_I18N_KEYS.facetsSkipped, {
|
|
138
|
+
: {}), ...(props.geoLabel !== undefined ? { label: props.geoLabel } : {}) }), bag.approximate && (_jsx(Alert, { type: "info", showIcon: true, "data-testid": "facets-approximate", title: t(SEARCH_I18N_KEYS.facetsApproximate) })), bag.skipped.length > 0 && (_jsx(Alert, { type: "warning", showIcon: true, "data-testid": "facets-skipped", title: t(SEARCH_I18N_KEYS.facetsSkipped, {
|
|
127
139
|
slugs: skippedNames(bag.skipped, props.categoryFeatures, t),
|
|
128
140
|
}) })), ranges.length > 0 && (_jsx(Flex, { vertical: true, gap: spacing[3], "data-testid": "search-ranges", children: ranges.map((group) => (_jsx(RangeFilterRow, { group: group, onApply: bag.setRange }, group.slug))) })), ranges.length > 0 && _jsx(Divider, { style: { margin: 0 } }), _jsx(LoadList, { state: bag.state, testId: "facets", skeletonRows: 4, empty: _jsx(EmptyState, { compact: true, title: t(SEARCH_I18N_KEYS.facetsEmpty), testId: "facets-empty" }), failed: (error) => (_jsx(ErrorAlert, { testId: "facets-failed", thrown: error, message: t(SEARCH_I18N_KEYS.facetsLoadFailed) })), children: (groups) => (_jsxs(Flex, { vertical: true, gap: spacing[4], children: [groups
|
|
129
141
|
.filter((group) => group.options.length > 0)
|
|
130
|
-
.map((group) => (
|
|
142
|
+
.map((group) => (_jsx(FacetGroupControl, { group: group, onToggle: bag.toggle }, group.slug))), _jsx(Typography.Text, { type: "secondary", children: t(SEARCH_I18N_KEYS.facetsDrillDownHint) })] })) })] })) }) }));
|
|
131
143
|
}
|
|
132
144
|
//# sourceMappingURL=FacetPanelPane.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FacetPanelPane.js","sourceRoot":"","sources":["../../src/default/FacetPanelPane.tsx"],"names":[],"mappings":";AAoCA,OAAO,EACL,KAAK,EACL,MAAM,EACN,
|
|
1
|
+
{"version":3,"file":"FacetPanelPane.js","sourceRoot":"","sources":["../../src/default/FacetPanelPane.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ReactElement, ReactNode } from "react";
|
|
2
|
+
import type { FeatureDef } from "@stapel/attributes-react";
|
|
3
|
+
import type { GeoFilterSlotProps } from "./FacetPanelPane.js";
|
|
4
|
+
/** The class the scroller carries, for {@link chipRowCss}. */
|
|
5
|
+
export declare const CHIP_ROW_CLASS = "stapel-filter-chips";
|
|
6
|
+
/** The `href` the hoisted chip-row stylesheet is deduplicated by. */
|
|
7
|
+
export declare const CHIP_ROW_STYLE_HREF = "stapel-search-filter-chips";
|
|
8
|
+
/**
|
|
9
|
+
* The two rules an inline style cannot express: Firefox's `scrollbar-width`
|
|
10
|
+
* and WebKit's `::-webkit-scrollbar`. Static (no theme values), so one hoisted
|
|
11
|
+
* copy serves the document.
|
|
12
|
+
*/
|
|
13
|
+
export declare function chipRowCss(): string;
|
|
14
|
+
export interface FilterChipsProps {
|
|
15
|
+
/** The category's feature schema — the source of option labels, of which
|
|
16
|
+
* slugs get a range chip, and of how each group is drawn. */
|
|
17
|
+
readonly categoryFeatures?: readonly FeatureDef[];
|
|
18
|
+
readonly locale?: string;
|
|
19
|
+
/** The location control (`geo-react`), same slot the panel takes. Without
|
|
20
|
+
* it the location chip appears only when the URL already carries a point,
|
|
21
|
+
* so a shared link can still be widened. */
|
|
22
|
+
readonly renderGeoFilter?: (slot: GeoFilterSlotProps) => ReactNode;
|
|
23
|
+
/**
|
|
24
|
+
* What the current location constraint is CALLED — see
|
|
25
|
+
* {@link FacetPanelPaneProps.geoLabel}. The chip carries it as its own text,
|
|
26
|
+
* which is the whole point of a chip row: "Berlin Mitte" states the filter
|
|
27
|
+
* on the results page, where `55.756, 37.617` stated only that a machine was
|
|
28
|
+
* involved. Absent, the chip reads `search.geo.chosen_place`; never a
|
|
29
|
+
* coordinate, on either surface.
|
|
30
|
+
*/
|
|
31
|
+
readonly geoLabel?: ReactNode;
|
|
32
|
+
/** Open the whole panel — the leading chip's action. The page owns that
|
|
33
|
+
* sheet, because the page is the surface it covers. */
|
|
34
|
+
readonly onOpenAll: () => void;
|
|
35
|
+
}
|
|
36
|
+
export declare function FilterChips(props: FilterChipsProps): ReactElement;
|
|
37
|
+
//# sourceMappingURL=FilterChips.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FilterChips.d.ts","sourceRoot":"","sources":["../../src/default/FilterChips.tsx"],"names":[],"mappings":"AAkDA,OAAO,KAAK,EAAiB,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAKpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAU3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE9D,8DAA8D;AAC9D,eAAO,MAAM,cAAc,wBAAwB,CAAC;AAEpD,qEAAqE;AACrE,eAAO,MAAM,mBAAmB,+BAA+B,CAAC;AAEhE;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAKnC;AAqBD,MAAM,WAAW,gBAAgB;IAC/B;iEAC6D;IAC7D,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAClD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;gDAE4C;IAC5C,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,SAAS,CAAC;IACnE;;;;;;;OAOG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;IAC9B;2DACuD;IACvD,QAAQ,CAAC,SAAS,EAAE,MAAM,IAAI,CAAC;CAChC;AAiBD,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,YAAY,CA6OjE"}
|