@stapel/listings-react 0.4.0 → 0.8.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 (133) hide show
  1. package/CHANGELOG.md +180 -0
  2. package/dist/api/generated/schema.d.ts +94 -4
  3. package/dist/api/generated/schema.d.ts.map +1 -1
  4. package/dist/default/FavoritesPane.d.ts +40 -3
  5. package/dist/default/FavoritesPane.d.ts.map +1 -1
  6. package/dist/default/FavoritesPane.js +30 -18
  7. package/dist/default/FavoritesPane.js.map +1 -1
  8. package/dist/default/ListingCard.d.ts +81 -4
  9. package/dist/default/ListingCard.d.ts.map +1 -1
  10. package/dist/default/ListingCard.js +97 -27
  11. package/dist/default/ListingCard.js.map +1 -1
  12. package/dist/default/ListingComposerPage.d.ts +163 -23
  13. package/dist/default/ListingComposerPage.d.ts.map +1 -1
  14. package/dist/default/ListingComposerPage.js +85 -43
  15. package/dist/default/ListingComposerPage.js.map +1 -1
  16. package/dist/default/ListingDetailPane.d.ts +41 -4
  17. package/dist/default/ListingDetailPane.d.ts.map +1 -1
  18. package/dist/default/ListingDetailPane.js +38 -25
  19. package/dist/default/ListingDetailPane.js.map +1 -1
  20. package/dist/default/ListingPhoto.d.ts +13 -1
  21. package/dist/default/ListingPhoto.d.ts.map +1 -1
  22. package/dist/default/ListingPhoto.js +47 -9
  23. package/dist/default/ListingPhoto.js.map +1 -1
  24. package/dist/default/ListingPrice.d.ts +13 -0
  25. package/dist/default/ListingPrice.d.ts.map +1 -0
  26. package/dist/default/ListingPrice.js +60 -0
  27. package/dist/default/ListingPrice.js.map +1 -0
  28. package/dist/default/MyListingsPane.d.ts +7 -28
  29. package/dist/default/MyListingsPane.d.ts.map +1 -1
  30. package/dist/default/MyListingsPane.js +136 -67
  31. package/dist/default/MyListingsPane.js.map +1 -1
  32. package/dist/default/SignInLink.js +8 -7
  33. package/dist/default/SignInLink.js.map +1 -1
  34. package/dist/default/StatusTags.d.ts +16 -5
  35. package/dist/default/StatusTags.d.ts.map +1 -1
  36. package/dist/default/StatusTags.js +19 -13
  37. package/dist/default/StatusTags.js.map +1 -1
  38. package/dist/default/index.d.ts +15 -9
  39. package/dist/default/index.d.ts.map +1 -1
  40. package/dist/default/index.js +13 -6
  41. package/dist/default/index.js.map +1 -1
  42. package/dist/headless/Favorites.d.ts +6 -0
  43. package/dist/headless/Favorites.d.ts.map +1 -1
  44. package/dist/headless/Favorites.js +23 -7
  45. package/dist/headless/Favorites.js.map +1 -1
  46. package/dist/headless/ListingActions.d.ts +12 -0
  47. package/dist/headless/ListingActions.d.ts.map +1 -1
  48. package/dist/headless/ListingActions.js +3 -0
  49. package/dist/headless/ListingActions.js.map +1 -1
  50. package/dist/headless/ListingComposer.d.ts +23 -0
  51. package/dist/headless/ListingComposer.d.ts.map +1 -1
  52. package/dist/headless/ListingComposer.js +33 -7
  53. package/dist/headless/ListingComposer.js.map +1 -1
  54. package/dist/headless/ListingDetail.d.ts.map +1 -1
  55. package/dist/headless/ListingDetail.js +7 -5
  56. package/dist/headless/ListingDetail.js.map +1 -1
  57. package/dist/headless/useMandateGate.d.ts +33 -2
  58. package/dist/headless/useMandateGate.d.ts.map +1 -1
  59. package/dist/headless/useMandateGate.js +42 -4
  60. package/dist/headless/useMandateGate.js.map +1 -1
  61. package/dist/i18n/es.d.ts +6 -1
  62. package/dist/i18n/es.d.ts.map +1 -1
  63. package/dist/i18n/es.js +23 -5
  64. package/dist/i18n/es.js.map +1 -1
  65. package/dist/i18n/generated/errors.es.gen.d.ts +1 -1
  66. package/dist/i18n/generated/errors.es.gen.js +1 -1
  67. package/dist/i18n/generated/errors.gen.d.ts +6 -0
  68. package/dist/i18n/generated/errors.gen.d.ts.map +1 -1
  69. package/dist/i18n/generated/errors.gen.js +3 -0
  70. package/dist/i18n/generated/errors.gen.js.map +1 -1
  71. package/dist/i18n/generated/errors.ru.gen.d.ts +1 -1
  72. package/dist/i18n/generated/errors.ru.gen.js +1 -1
  73. package/dist/i18n/keys.d.ts +30 -3
  74. package/dist/i18n/keys.d.ts.map +1 -1
  75. package/dist/i18n/keys.js +47 -7
  76. package/dist/i18n/keys.js.map +1 -1
  77. package/dist/i18n/ru.d.ts +16 -1
  78. package/dist/i18n/ru.d.ts.map +1 -1
  79. package/dist/i18n/ru.js +35 -5
  80. package/dist/i18n/ru.js.map +1 -1
  81. package/dist/index.d.ts +1 -1
  82. package/dist/index.d.ts.map +1 -1
  83. package/dist/index.js +1 -1
  84. package/dist/index.js.map +1 -1
  85. package/dist/model/draft.d.ts +9 -6
  86. package/dist/model/draft.d.ts.map +1 -1
  87. package/dist/model/draft.js +3 -1
  88. package/dist/model/draft.js.map +1 -1
  89. package/dist/model/features.d.ts +21 -7
  90. package/dist/model/features.d.ts.map +1 -1
  91. package/dist/model/features.js +26 -0
  92. package/dist/model/features.js.map +1 -1
  93. package/llms.txt +9 -8
  94. package/manifest.json +82 -31
  95. package/nav-manifest.json +1 -1
  96. package/package.json +19 -14
  97. package/src/analytics/generated/events.json +1 -1
  98. package/src/api/generated/schema.ts +94 -4
  99. package/src/default/FavoritesPane.tsx +156 -82
  100. package/src/default/ListingCard.tsx +283 -116
  101. package/src/default/ListingComposerPage.tsx +403 -187
  102. package/src/default/ListingDetailPane.tsx +200 -98
  103. package/src/default/ListingPhoto.tsx +89 -16
  104. package/src/default/ListingPrice.tsx +77 -0
  105. package/src/default/MyListingsPane.tsx +286 -228
  106. package/src/default/SignInLink.tsx +4 -4
  107. package/src/default/StatusTags.tsx +36 -18
  108. package/src/default/index.ts +18 -7
  109. package/src/headless/Favorites.tsx +36 -7
  110. package/src/headless/ListingActions.tsx +19 -0
  111. package/src/headless/ListingComposer.tsx +56 -5
  112. package/src/headless/ListingDetail.tsx +12 -5
  113. package/src/headless/useMandateGate.ts +49 -5
  114. package/src/i18n/es.ts +29 -5
  115. package/src/i18n/generated/errors.es.gen.ts +1 -1
  116. package/src/i18n/generated/errors.gen.ts +3 -0
  117. package/src/i18n/generated/errors.json +7 -0
  118. package/src/i18n/generated/errors.ru.gen.ts +1 -1
  119. package/src/i18n/keys.ts +54 -7
  120. package/src/i18n/ru.ts +41 -5
  121. package/src/index.ts +5 -1
  122. package/src/model/draft.ts +12 -7
  123. package/src/model/features.ts +48 -7
  124. package/dist/default/ErrorAlert.d.ts +0 -9
  125. package/dist/default/ErrorAlert.d.ts.map +0 -1
  126. package/dist/default/ErrorAlert.js +0 -27
  127. package/dist/default/ErrorAlert.js.map +0 -1
  128. package/dist/default/theme.d.ts +0 -25
  129. package/dist/default/theme.d.ts.map +0 -1
  130. package/dist/default/theme.js +0 -40
  131. package/dist/default/theme.js.map +0 -1
  132. package/src/default/ErrorAlert.tsx +0 -46
  133. package/src/default/theme.tsx +0 -67
@@ -1,11 +1,20 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Alert, Button, Empty, Flex, Space, Spin, Typography } from "antd";
3
- import { matchList, useDescribeFlowError, useT } from "@stapel/core";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Button, Flex, Typography } from "antd";
3
+ import { EmptyState, ErrorAlert, SkinTheme, } from "@stapel/tokens-antd/skin";
4
+ import { matchList, useT } from "@stapel/core";
5
+ import { spacing } from "@stapel/tokens";
4
6
  import { useFavorites } from "../headless/Favorites.js";
5
7
  import { LISTINGS_I18N_KEYS } from "../i18n/keys.js";
6
- import { ErrorAlert } from "./ErrorAlert.js";
7
8
  import { ListingCard } from "./ListingCard.js";
8
- import { ListingsSkinTheme } from "./theme.js";
9
+ import { SignInLink } from "./SignInLink.js";
10
+ /** The narrowest a card may get before the grid drops a column — the same
11
+ * element-relative rule the detail gallery uses. It was `width: 240`, which
12
+ * left two cards floating in a 2560px pane and overflowed a 390px one. */
13
+ export const FAVORITES_CARD_MIN = "15rem";
14
+ /** How wide the saved grid may get before it stops being a grid and becomes
15
+ * three cards adrift in a 1280px window. A measure, not a breakpoint: the
16
+ * cards keep filling it, and past it the page centres. */
17
+ export const FAVORITES_MEASURE = "72rem";
9
18
  /** The card's own open props for one row. One arm, never two. */
10
19
  function cardOpenProps(props, id) {
11
20
  if (props.hrefFor !== undefined) {
@@ -20,19 +29,22 @@ function cardOpenProps(props, id) {
20
29
  }
21
30
  export function FavoritesPane(props) {
22
31
  const t = useT();
23
- const describe = useDescribeFlowError();
24
32
  const bag = useFavorites();
25
- return (_jsx(ListingsSkinTheme, { ...(props.mode !== undefined ? { mode: props.mode } : {}), children: _jsxs(Flex, { vertical: true, gap: 16, "data-testid": "listings-favorites", children: [_jsx(Typography.Title, { level: 3, children: t(LISTINGS_I18N_KEYS.favoritesTitle) }), !bag.gate.available ? (_jsx(Alert, { type: "info", showIcon: true, "data-testid": "listings-favorites-blocked", message: t(bag.gate.block.code, bag.gate.block.params) })) : null, matchList(bag.rows, {
26
- loading: () => (_jsx(Flex, { justify: "center", "data-testid": "listings-favorites-loading", children: _jsx(Spin, { "aria-label": t(LISTINGS_I18N_KEYS.favoritesLoading) }) })),
27
- failed: () => (_jsx(ErrorAlert, { testId: "listings-favorites-error", error: describe({
28
- code: LISTINGS_I18N_KEYS.favoritesLoadFailed,
29
- params: {},
30
- status: 0,
31
- message: undefined,
32
- language: undefined,
33
- }), action: _jsx(Button, { size: "small", "data-analytics": "none", "data-analytics-reason": "retrying a read the person already asked for; not a business action", onClick: bag.refetch, children: t(LISTINGS_I18N_KEYS.mineRetry) }) })),
34
- empty: () => (_jsx(Empty, { "data-testid": "listings-favorites-empty", description: t(LISTINGS_I18N_KEYS.favoritesEmpty) })),
35
- ready: (rows) => (_jsx(Flex, { wrap: true, gap: 16, "data-testid": "listings-favorites-grid", children: rows.map((row) => (_jsx("div", { style: { width: 240 }, children: _jsx(ListingCard, { listing: row, ...cardOpenProps(props, row.id) }) }, row.id))) })),
36
- }), _jsxs(Space, { children: [_jsx(Button, { size: "small", disabled: !bag.prevPage.available, "data-testid": "listings-favorites-prev", "data-analytics": "none", "data-analytics-reason": "paging a list the person is already reading; not a business action", onClick: bag.goPrev, children: t(LISTINGS_I18N_KEYS.pagePrev) }), _jsx(Button, { size: "small", disabled: !bag.nextPage.available, "data-testid": "listings-favorites-next", "data-analytics": "none", "data-analytics-reason": "paging a list the person is already reading; not a business action", onClick: bag.goNext, children: t(LISTINGS_I18N_KEYS.pageNext) })] })] }) }));
33
+ const paged = bag.prevPage.available || bag.nextPage.available;
34
+ return (_jsx(SkinTheme, { surface: "base", style: { padding: spacing[4], maxWidth: FAVORITES_MEASURE }, ...(props.mode !== undefined ? { mode: props.mode } : {}), children: _jsxs(Flex, { vertical: true, gap: spacing[4], "data-testid": "listings-favorites", children: [_jsx(Typography.Title, { level: 3, children: t(LISTINGS_I18N_KEYS.favoritesTitle) }), !bag.gate.available ? (
35
+ // The whole body, not a banner over a spinner. A blocked screen has
36
+ // one state and it carries its own way out.
37
+ _jsx(EmptyState, { testId: "listings-favorites-blocked", title: t(bag.gate.block.code, bag.gate.block.params), hint: t(LISTINGS_I18N_KEYS.favoritesSignInHint), action: _jsx(SignInLink, { cta: props.signIn, testId: "listings-favorites-sign-in" }) })) : (_jsxs(_Fragment, { children: [matchList(bag.rows, {
38
+ loading: () => (_jsx("div", { role: "status", "aria-busy": "true", "aria-label": t(LISTINGS_I18N_KEYS.favoritesLoading), "data-testid": "listings-favorites-loading", "data-stapel-load-state": "loading" })),
39
+ failed: (error) => (_jsx(ErrorAlert, { testId: "listings-favorites-error", thrown: error, message: t(LISTINGS_I18N_KEYS.favoritesLoadFailed), onRetry: bag.refetch, retryLabel: t(LISTINGS_I18N_KEYS.mineRetry) })),
40
+ empty: () => (_jsx(EmptyState, { testId: "listings-favorites-empty", title: t(LISTINGS_I18N_KEYS.favoritesEmpty), hint: t(LISTINGS_I18N_KEYS.favoritesEmptyHint), ...(props.browseCta !== undefined
41
+ ? { action: props.browseCta }
42
+ : {}) })),
43
+ ready: (rows) => (_jsx("div", { "data-testid": "listings-favorites-grid", style: {
44
+ display: "grid",
45
+ gridTemplateColumns: `repeat(auto-fill, minmax(${FAVORITES_CARD_MIN}, 1fr))`,
46
+ gap: spacing[4],
47
+ }, children: rows.map((row) => (_jsx(ListingCard, { listing: row, blockedReason: "line", ...(props.signIn !== undefined ? { signIn: props.signIn } : {}), ...cardOpenProps(props, row.id) }, row.id))) })),
48
+ }), paged ? (_jsxs(Flex, { gap: spacing[3], wrap: true, align: "center", children: [bag.prevPage.available ? (_jsx(Button, { size: "small", "data-testid": "listings-favorites-prev", "data-analytics": "none", "data-analytics-reason": "paging a list the person is already reading; not a business action", onClick: bag.goPrev, children: t(LISTINGS_I18N_KEYS.pagePrev) })) : null, _jsx(Typography.Text, { type: "secondary", "data-testid": "listings-favorites-page", children: t(LISTINGS_I18N_KEYS.pageIndicator, { page: bag.pageNumber }) }), bag.nextPage.available ? (_jsx(Button, { size: "small", "data-testid": "listings-favorites-next", "data-analytics": "none", "data-analytics-reason": "paging a list the person is already reading; not a business action", onClick: bag.goNext, children: t(LISTINGS_I18N_KEYS.pageNext) })) : null] })) : null] }))] }) }));
37
49
  }
38
50
  //# sourceMappingURL=FavoritesPane.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FavoritesPane.js","sourceRoot":"","sources":["../../src/default/FavoritesPane.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FavoritesPane.js","sourceRoot":"","sources":["../../src/default/FavoritesPane.tsx"],"names":[],"mappings":"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"}
@@ -6,6 +6,26 @@
6
6
  * the CONTAINER is the seam, which is why this component takes a plain card
7
7
  * row and a plain `href` rather than reaching for a router.
8
8
  *
9
+ * ── The CARD is the link ───────────────────────────────────────────────────
10
+ *
11
+ * Owner ruling (2026-08-28, from the live stand): a card carrying its own
12
+ * "view" button is plainly wrong. The card used to render a separate "Open"
13
+ * control under its own content — a full-width primary button captioned with
14
+ * `listings.card.open` — so a person looking at a photo, a price and a title
15
+ * had to find and press a fourth thing to act on the three they were reading.
16
+ * Nothing on a classified works that way: the card IS the target, and the only
17
+ * separate control on it is the favourite heart.
18
+ *
19
+ * So the photo, the price, the title, the badges and the location now live
20
+ * INSIDE one anchor that covers the whole card, and `listings.card.open` is
21
+ * retired rather than left orphaned in three catalogues.
22
+ *
23
+ * What that must not cost is the anchor semantics won earlier: this is a real
24
+ * `<a href>`, so middle-click opens a tab, ⌘-click opens a tab, "copy link
25
+ * address" works and a crawler can follow it. It is NOT an `onClick` on a div,
26
+ * which is the shape every "whole card clickable" rewrite reaches for first
27
+ * and which has none of those properties.
28
+ *
9
29
  * ── One click, one navigation ──────────────────────────────────────────────
10
30
  *
11
31
  * `href` and `onOpen` used to be two optional props, and a card given both
@@ -14,6 +34,25 @@
14
34
  * button, or neither — and `linkComponent` rides on the link arm so a
15
35
  * container can hand in its router's `<Link>` and keep the anchor.
16
36
  *
37
+ * ── The accessible name is the TITLE, and only the title ───────────────────
38
+ *
39
+ * An anchor's name is computed from its contents unless it is given one, and
40
+ * the contents here are a photo, a price, three badges and a place: a screen
41
+ * reader reading a list of forty of those announces forty paragraphs. The
42
+ * anchor therefore carries an explicit `aria-label` — the listing's title,
43
+ * nothing else — and everything inside it stays readable by ordinary browsing.
44
+ * A listing with no title falls back to `listings.card.untitled`, because a
45
+ * link announced as nothing is worse than one announced as untitled.
46
+ *
47
+ * ── Why the heart is a row under the card and not floating on the photo ────
48
+ *
49
+ * Because for a signed-out visitor — which is most of the traffic a storefront
50
+ * gets — the heart is BLOCKED, and a blocked control states its reason as text
51
+ * beside it. There is nowhere to put that sentence on top of a photograph. The
52
+ * heart therefore sits in its own row beneath the content, outside the anchor
53
+ * (a button inside a link is neither valid nor operable), where the reason has
54
+ * a line to live on.
55
+ *
17
56
  * ── What it renders without asking the server anything else ────────────────
18
57
  *
19
58
  * Badges. `features_badges` is a stored DAO projection, and a DAO carries the
@@ -22,14 +61,17 @@
22
61
  * card. That property is the whole reason the projection exists, and it is
23
62
  * what makes a grid of forty cards cost one query.
24
63
  *
25
- * ── The heart is never hidden ──────────────────────────────────────────────
64
+ * ── The heart is never hidden, and never explained by hover ────────────────
26
65
  *
27
66
  * A visitor sees it, blocked, with the reason IN WORDS beside it and the
28
67
  * sign-in link the container supplies (`signIn`, typically `?next=<current>`).
29
68
  * Hiding it would teach nobody that favourites exist (private-space canon
30
- * §6.3, spec §6.2 item 6) — and until 0.3.0 the reason lived only in a tooltip
31
- * on a disabled button, which receives no pointer events in any browser: a
32
- * reason nobody could read, and no door to walk through.
69
+ * §6.3, spec §6.2 item 6). The reason itself goes through the shared
70
+ * `<GatedControl>`, which renders it as text linked by `aria-describedby`
71
+ * a disabled antd button receives no pointer events and is not focusable, so
72
+ * the `Tooltip` this component used to offer as a "quieter" volume was a
73
+ * reason nobody could read on any device. That arm is gone; `blockedReason`
74
+ * is now "text" (reason + door) or "line" (reason alone, for a grid).
33
75
  */
34
76
  import type { ReactElement, ReactNode } from "react";
35
77
  import type { LinkComponent, SignInCtaProp } from "@stapel/core";
@@ -71,8 +113,43 @@ export type ListingCardOpenProps = {
71
113
  readonly onOpen?: undefined;
72
114
  readonly linkComponent?: undefined;
73
115
  };
116
+ /**
117
+ * How loudly a blocked favourite states its reason on THIS surface.
118
+ *
119
+ * `"text"` (the default) is the sentence under the controls, with the sign-in
120
+ * door beside it — the right volume for a card that stands alone.
121
+ *
122
+ * `"line"` collapses it to the reason alone, no door: a grid of forty cards
123
+ * repeating "sign in to do this — sign in" forty times is not forty pieces of
124
+ * help, it is the loudest thing on the page, and every one of those doors
125
+ * leads where the header's own sign-in button already leads.
126
+ *
127
+ * There is no third setting. The reason is on screen in both, because the only
128
+ * way to make it quieter than a line of text is to hide it behind hover, and
129
+ * hover does not exist on the device most of these cards are read on.
130
+ */
131
+ export type ListingCardBlockedReason = "text" | "line";
132
+ /** The class the whole-card target carries, for {@link cardTargetCss}. */
133
+ export declare const CARD_TARGET_CLASS = "stapel-listing-card-target";
134
+ /** The `href` the hoisted card stylesheet is deduplicated by. */
135
+ export declare const CARD_TARGET_STYLE_HREF = "stapel-listings-card-target";
136
+ /**
137
+ * The one rule an inline style cannot express: `:focus-visible`.
138
+ *
139
+ * A whole-card link is the largest focus target on a results page and it must
140
+ * SHOW that it has focus — a keyboard visitor tabbing a grid of forty cards
141
+ * with no ring has no idea which one Enter will open. The outline is drawn
142
+ * from the theme's own focus colour, which arrives as a custom property on the
143
+ * element (the sheet is static, so one hoisted copy serves either theme).
144
+ *
145
+ * `--listing-*` rather than `--stapel-*`: the `--stapel-` namespace is the
146
+ * design system's ROLE catalogue and this is a component's private plumbing.
147
+ */
148
+ export declare function cardTargetCss(): string;
74
149
  export interface ListingCardBaseProps extends ThemeModeProp, SignInCtaProp {
75
150
  readonly listing: ListingCardData;
151
+ /** See {@link ListingCardBlockedReason}. Default `"text"`. */
152
+ readonly blockedReason?: ListingCardBlockedReason;
76
153
  /** Extra chrome the container adds (a `promoted` tag from search, say —
77
154
  * DSA Art. 26 marking belongs to the pair that receives it). */
78
155
  readonly badge?: ReactNode;
@@ -1 +1 @@
1
- {"version":3,"file":"ListingCard.d.ts","sourceRoot":"","sources":["../../src/default/ListingCard.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGrD,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEjE,OAAO,KAAK,EAAE,WAAW,IAAI,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAStE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IACE;iEAC6D;IAC7D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;8CAE0C;IAC1C,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;IACvC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;CAC7B,GACD;IACE;wEACoE;IACpE,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,CAAC;CACpC,GACD;IACE;kBACc;IACd,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;IAC5B,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,CAAC;CACpC,CAAC;AAEN,MAAM,WAAW,oBAAqB,SAAQ,aAAa,EAAE,aAAa;IACxE,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC;oEACgE;IAChE,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC;IAC3B;gFAC4E;IAC5E,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,MAAM,MAAM,gBAAgB,GAAG,oBAAoB,GAAG,oBAAoB,CAAC;AAmE3E,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,YAAY,CAgIjE"}
1
+ {"version":3,"file":"ListingCard.d.ts","sourceRoot":"","sources":["../../src/default/ListingCard.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0EG;AACH,OAAO,KAAK,EAAiB,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIpE,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAGjE,OAAO,KAAK,EAAE,WAAW,IAAI,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAStE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IACE;iEAC6D;IAC7D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;8CAE0C;IAC1C,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;IACvC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;CAC7B,GACD;IACE;wEACoE;IACpE,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,CAAC;CACpC,GACD;IACE;kBACc;IACd,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;IAC5B,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,CAAC;CACpC,CAAC;AAEN;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,wBAAwB,GAAG,MAAM,GAAG,MAAM,CAAC;AAEvD,0EAA0E;AAC1E,eAAO,MAAM,iBAAiB,+BAA+B,CAAC;AAE9D,iEAAiE;AACjE,eAAO,MAAM,sBAAsB,gCAAgC,CAAC;AAEpE;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAKtC;AAwBD,MAAM,WAAW,oBAAqB,SAAQ,aAAa,EAAE,aAAa;IACxE,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,8DAA8D;IAC9D,QAAQ,CAAC,aAAa,CAAC,EAAE,wBAAwB,CAAC;IAClD;oEACgE;IAChE,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,CAAC;IAC3B;gFAC4E;IAC5E,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,MAAM,MAAM,gBAAgB,GAAG,oBAAoB,GAAG,oBAAoB,CAAC;AA+E3E,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,YAAY,CA6KjE"}
@@ -1,6 +1,8 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Button, Card, Flex, Tooltip, Typography } from "antd";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Button, Card, Flex, Typography, theme as antdTheme } from "antd";
3
+ import { GatedControl, SkinTheme } from "@stapel/tokens-antd/skin";
3
4
  import { useActionGate, useT } from "@stapel/core";
5
+ import { spacing } from "@stapel/tokens";
4
6
  import { FeatureBadges } from "@stapel/attributes-react/default";
5
7
  import { asFeatureDaoList, featuresDtoFromDaoList, featuresFromDaoList } from "../model/features.js";
6
8
  import { lifecycleCaption } from "../model/status.js";
@@ -9,56 +11,124 @@ import { LISTINGS_I18N_KEYS } from "../i18n/keys.js";
9
11
  import { HeartIcon } from "./icons.js";
10
12
  import { SignInLink } from "./SignInLink.js";
11
13
  import { ListingPhoto } from "./ListingPhoto.js";
12
- import { ListingsSkinTheme } from "./theme.js";
14
+ import { ListingPrice } from "./ListingPrice.js";
15
+ /** The class the whole-card target carries, for {@link cardTargetCss}. */
16
+ export const CARD_TARGET_CLASS = "stapel-listing-card-target";
17
+ /** The `href` the hoisted card stylesheet is deduplicated by. */
18
+ export const CARD_TARGET_STYLE_HREF = "stapel-listings-card-target";
13
19
  /**
14
- * The one control that opens the card: an anchor, a button, or nothing.
20
+ * The one rule an inline style cannot express: `:focus-visible`.
21
+ *
22
+ * A whole-card link is the largest focus target on a results page and it must
23
+ * SHOW that it has focus — a keyboard visitor tabbing a grid of forty cards
24
+ * with no ring has no idea which one Enter will open. The outline is drawn
25
+ * from the theme's own focus colour, which arrives as a custom property on the
26
+ * element (the sheet is static, so one hoisted copy serves either theme).
27
+ *
28
+ * `--listing-*` rather than `--stapel-*`: the `--stapel-` namespace is the
29
+ * design system's ROLE catalogue and this is a component's private plumbing.
30
+ */
31
+ export function cardTargetCss() {
32
+ return [
33
+ `.${CARD_TARGET_CLASS}{display:block;color:inherit;text-decoration:none}`,
34
+ `.${CARD_TARGET_CLASS}:focus-visible{outline:2px solid var(--listing-card-focus);outline-offset:2px}`,
35
+ ].join("");
36
+ }
37
+ /** The anchor: a block that inherits the card's own type colour rather than
38
+ * painting every card's contents link-blue. */
39
+ const TARGET_STYLE = {
40
+ display: "block",
41
+ color: "inherit",
42
+ textDecoration: "none",
43
+ };
44
+ /** The callback arm's button, reset to look like the anchor does. A card that
45
+ * is a target on one deployment and a card-plus-a-button on another would be
46
+ * two different products. */
47
+ const BUTTON_TARGET_STYLE = {
48
+ ...TARGET_STYLE,
49
+ width: "100%",
50
+ padding: 0,
51
+ border: "none",
52
+ background: "none",
53
+ font: "inherit",
54
+ textAlign: "start",
55
+ cursor: "pointer",
56
+ };
57
+ /**
58
+ * The card's own body, wrapped in whatever makes it openable: an anchor, a
59
+ * button, or nothing at all.
15
60
  *
16
61
  * Exactly one of the three renders, so exactly one navigation happens per
17
- * click. That is the whole fix — the branch below has no arm in which both a
18
- * handler and an `href` reach the DOM.
62
+ * click — the branch below has no arm in which both a handler and an `href`
63
+ * reach the DOM.
64
+ *
65
+ * The BUTTON arm exists for a container that routes by callback. It wraps the
66
+ * same content in a `<button>` reset to look like nothing, rather than drawing
67
+ * a separate captioned control: a card that is a target on one deployment and
68
+ * a card-plus-a-button on another would be two different products.
19
69
  */
20
- function OpenControl(props) {
21
- const t = useT();
22
- const label = t(LISTINGS_I18N_KEYS.cardOpen);
70
+ function CardTarget(props) {
71
+ const { label, children } = props;
23
72
  if (props.href !== undefined) {
24
73
  const Link = props.linkComponent;
25
74
  // The host's component is rendered as it comes: this pair has no CSS and
26
- // no way to hand antd's button styling to a foreign element, and a wrapper
27
- // element around a link is a click target that is not the link. A host
28
- // that wants the antd look styles its own `<Link>` it is one component,
29
- // written once, and it is already the thing that knows the design system.
30
- return Link !== undefined ? (_jsx(Link, { href: props.href, "aria-label": label, "data-testid": "listings-card-open", "data-analytics": "none", "data-analytics-reason": "business action \u2014 host app wraps with its own tracked()", children: label })) : (_jsx(Button, { size: "small", type: "link", href: props.href, "data-testid": "listings-card-open", "data-analytics": "none", "data-analytics-reason": "business action \u2014 host app wraps with its own tracked()", children: label }));
75
+ // no way to hand its own styling to a foreign element. A wrapper element
76
+ // around a link would be a click target that is not the link.
77
+ return Link !== undefined ? (_jsx(Link, { href: props.href, "aria-label": label, className: CARD_TARGET_CLASS, "data-testid": "listings-card-open", "data-analytics": "none", "data-analytics-reason": "business action \u2014 host app wraps with its own tracked()", children: children })) : (_jsx("a", { href: props.href, "aria-label": label, className: CARD_TARGET_CLASS, style: TARGET_STYLE, "data-testid": "listings-card-open", "data-analytics": "none", "data-analytics-reason": "business action \u2014 host app wraps with its own tracked()", children: children }));
31
78
  }
32
79
  if (props.onOpen !== undefined) {
33
80
  const onOpen = props.onOpen;
34
- return (_jsx(Button, { size: "small", type: "link", "data-testid": "listings-card-open", "data-analytics": "none", "data-analytics-reason": "business action \u2014 host app wraps with its own tracked()", onClick: () => {
81
+ return (_jsx("button", { type: "button", "aria-label": label, className: CARD_TARGET_CLASS, style: BUTTON_TARGET_STYLE, "data-testid": "listings-card-open", "data-analytics": "none", "data-analytics-reason": "business action \u2014 host app wraps with its own tracked()", onClick: () => {
35
82
  onOpen(props.listingId);
36
- }, children: label }));
83
+ }, children: children }));
37
84
  }
38
- return null;
85
+ // No open control at all — a card inside a screen that IS the listing.
86
+ return _jsx("div", { "data-testid": "listings-card-body", children: children });
39
87
  }
40
88
  export function ListingCard(props) {
41
89
  const t = useT();
42
90
  const { listing } = props;
43
91
  const favorite = useFavoriteToggle(listing.id, listing.is_favorited);
92
+ const { token } = antdTheme.useToken();
44
93
  const badgeDaos = asFeatureDaoList(listing.features_badges);
45
94
  const badgeFeatures = featuresFromDaoList(badgeDaos);
46
95
  const badgeValues = featuresDtoFromDaoList(badgeDaos);
47
96
  const titleDaos = asFeatureDaoList(listing.features_title);
48
97
  const status = listing.status === undefined ? undefined : lifecycleCaption(listing.status);
49
- const price = listing.price !== undefined && listing.price.length > 0
50
- ? `${listing.price} ${listing.currency ?? ""}`.trim()
51
- : t(LISTINGS_I18N_KEYS.cardPriceAbsent);
52
98
  const favoriteGate = useActionGate(favorite.gate);
99
+ const blockedReason = props.blockedReason ?? "text";
53
100
  const favoriteLabel = t(favorite.favorited
54
101
  ? LISTINGS_I18N_KEYS.cardFavoriteRemove
55
102
  : LISTINGS_I18N_KEYS.cardFavoriteAdd);
56
- return (_jsx(ListingsSkinTheme, { ...(props.mode !== undefined ? { mode: props.mode } : {}), children: _jsx(Card, { size: "small", "data-testid": "listings-card", "data-listing-id": listing.id, ...(status !== undefined
57
- ? { "data-listing-status": status.status }
58
- : {}), cover: _jsx(ListingPhoto, { imageRef: listing.images?.[0], alt: listing.title ?? String(listing.id), style: { aspectRatio: "4 / 3" } }), children: _jsxs(Flex, { vertical: true, gap: 4, children: [props.badge, _jsx(Typography.Text, { strong: true, "data-testid": "listings-card-price", children: price }), _jsx(Typography.Text, { ellipsis: true, "data-testid": "listings-card-title", children: listing.title ?? "" }), titleDaos.length > 0 ? (_jsx(Typography.Text, { type: "secondary", ellipsis: true, children: _jsx(FeatureBadges, { features: featuresFromDaoList(titleDaos)
59
- .map((view) => view.feature), values: featuresDtoFromDaoList(titleDaos) }) })) : null, badgeFeatures.length > 0 ? (_jsx(FeatureBadges, { features: badgeFeatures.map((view) => view.feature), values: badgeValues })) : null, listing.location_label !== undefined &&
60
- listing.location_label.length > 0 ? (_jsx(Typography.Text, { type: "secondary", "data-testid": "listings-card-location", children: listing.location_label })) : null, _jsxs(Flex, { gap: 8, align: "center", children: [_jsx(OpenControl, { ...props, listingId: listing.id }), props.showFavorite === false ? null : (_jsx(Tooltip, { title: favorite.gate.available
61
- ? favoriteLabel
62
- : t(favorite.gate.block.code, favorite.gate.block.params), children: _jsx("span", { "data-testid": "listings-card-favorite-wrap", children: _jsx(Button, { size: "small", disabled: !favorite.gate.available, "aria-label": favoriteLabel, "aria-pressed": favorite.favorited, "data-testid": "listings-card-favorite", "data-favorited": String(favorite.favorited), "data-analytics": "none", "data-analytics-reason": "business action \u2014 host app wraps with its own tracked()", onClick: favorite.toggle, icon: _jsx(HeartIcon, { filled: favorite.favorited }) }) }) }))] }), props.showFavorite === false || favoriteGate.reason === undefined ? null : (_jsxs(Typography.Text, { type: "secondary", "data-testid": "listings-card-favorite-blocked", children: [favoriteGate.reason, _jsx(SignInLink, { cta: props.signIn, testId: "listings-card-sign-in" })] }))] }) }) }));
103
+ const title = listing.title ?? "";
104
+ // The anchor's name is the TITLE and nothing else. A card with no title is
105
+ // still a link, and a link announced as nothing is worse than one announced
106
+ // as untitled.
107
+ const targetLabel = title.length > 0 ? title : t(LISTINGS_I18N_KEYS.cardUntitled);
108
+ /**
109
+ * Everything a person reads on the card, in the order a classified reads it:
110
+ * photo, price, title, the seller's own spec line, the badges, the place.
111
+ *
112
+ * The search projection carries `title`, `price`, `currency`,
113
+ * `location_label`, `image` and `published_at` and NO feature badges — so
114
+ * every line below is conditional and the card has to look deliberate with
115
+ * all of them absent. That is why the photo and the price carry the layout:
116
+ * they are the two fields a result always has.
117
+ */
118
+ const content = (_jsxs(_Fragment, { children: [_jsx(ListingPhoto, { imageRef: listing.images?.[0], alt: title.length > 0 ? title : String(listing.id) }), _jsxs(Flex, { vertical: true, gap: spacing[1], style: { minWidth: 0, padding: token.paddingSM }, children: [props.badge, _jsx(Typography.Text, { strong: true, "data-testid": "listings-card-price", children: _jsx(ListingPrice, { amount: listing.price, ...(listing.currency !== undefined ? { currency: listing.currency } : {}) }) }), _jsx(Typography.Text, { ellipsis: true, "data-testid": "listings-card-title", children: title }), titleDaos.length > 0 ? (_jsx(Typography.Text, { type: "secondary", ellipsis: true, children: _jsx(FeatureBadges, { features: featuresFromDaoList(titleDaos).map((view) => view.feature), values: featuresDtoFromDaoList(titleDaos) }) })) : null, badgeFeatures.length > 0 ? (_jsx(FeatureBadges, { features: badgeFeatures.map((view) => view.feature), values: badgeValues })) : null, listing.location_label !== undefined &&
119
+ listing.location_label.length > 0 ? (_jsx(Typography.Text, { type: "secondary", "data-testid": "listings-card-location", children: listing.location_label })) : null] })] }));
120
+ return (_jsxs(SkinTheme, { surface: "bare", ...(props.mode !== undefined ? { mode: props.mode } : {}), children: [_jsx("style", { href: CARD_TARGET_STYLE_HREF, precedence: "default", children: cardTargetCss() }), _jsxs(Card, { size: "small", "data-testid": "listings-card", "data-listing-id": listing.id, ...(status !== undefined
121
+ ? { "data-listing-status": status.status }
122
+ : {}),
123
+ // The body's own padding is zero because the ANCHOR fills the card:
124
+ // padding outside it would be a strip of card that looks pressable and
125
+ // is not. The text block inside the anchor carries the same padding
126
+ // back, from the same token.
127
+ styles: { body: { minWidth: 0, padding: 0 } }, style: { ["--listing-card-focus"]: token.colorPrimary }, children: [_jsx(CardTarget, { ...props, listingId: listing.id, label: targetLabel, children: content }), props.showFavorite === false ? null : (_jsxs("div", { style: {
128
+ paddingInline: token.paddingSM,
129
+ paddingBlockEnd: token.paddingSM,
130
+ }, children: [_jsx(GatedControl, { gate: favorite.gate, testId: "listings-card-actions", style: { width: "100%" }, children: (bind) => (_jsx(Flex, { justify: "flex-end", style: { width: "100%" }, children: _jsx(Button, { disabled: bind.disabled, "data-disabled-reason": "the enclosing <GatedControl> renders the gate's reason beside this button", ...(bind["aria-describedby"] !== undefined
131
+ ? { "aria-describedby": bind["aria-describedby"] }
132
+ : {}), "aria-label": favoriteLabel, "aria-pressed": favorite.favorited, "data-testid": "listings-card-favorite", "data-favorited": String(favorite.favorited), "data-analytics": "none", "data-analytics-reason": "business action \u2014 host app wraps with its own tracked()", onClick: favorite.toggle, icon: _jsx(HeartIcon, { filled: favorite.favorited }) }) })) }), favoriteGate.reason === undefined || blockedReason === "line" ? null : (_jsx(Typography.Text, { type: "secondary", "data-testid": "listings-card-favorite-blocked", children: _jsx(SignInLink, { cta: props.signIn, testId: "listings-card-sign-in" }) }))] }))] })] }));
63
133
  }
64
134
  //# sourceMappingURL=ListingCard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ListingCard.js","sourceRoot":"","sources":["../../src/default/ListingCard.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ListingCard.js","sourceRoot":"","sources":["../../src/default/ListingCard.tsx"],"names":[],"mappings":";AA4EA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAEjE,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AACrG,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AA4DjD,0EAA0E;AAC1E,MAAM,CAAC,MAAM,iBAAiB,GAAG,4BAA4B,CAAC;AAE9D,iEAAiE;AACjE,MAAM,CAAC,MAAM,sBAAsB,GAAG,6BAA6B,CAAC;AAEpE;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO;QACL,IAAI,iBAAiB,oDAAoD;QACzE,IAAI,iBAAiB,gFAAgF;KACtG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACb,CAAC;AAED;+CAC+C;AAC/C,MAAM,YAAY,GAAkB;IAClC,OAAO,EAAE,OAAO;IAChB,KAAK,EAAE,SAAS;IAChB,cAAc,EAAE,MAAM;CACvB,CAAC;AAEF;;6BAE6B;AAC7B,MAAM,mBAAmB,GAAkB;IACzC,GAAG,YAAY;IACf,KAAK,EAAE,MAAM;IACb,OAAO,EAAE,CAAC;IACV,MAAM,EAAE,MAAM;IACd,UAAU,EAAE,MAAM;IAClB,IAAI,EAAE,SAAS;IACf,SAAS,EAAE,OAAO;IAClB,MAAM,EAAE,SAAS;CAClB,CAAC;AAgBF;;;;;;;;;;;;GAYG;AACH,SAAS,UAAU,CACjB,KAIC;IAED,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAElC,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,aAAa,CAAC;QACjC,yEAAyE;QACzE,yEAAyE;QACzE,8DAA8D;QAC9D,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAC1B,KAAC,IAAI,IACH,IAAI,EAAE,KAAK,CAAC,IAAI,gBACJ,KAAK,EACjB,SAAS,EAAE,iBAAiB,iBAChB,oBAAoB,oBACjB,MAAM,2BACC,8DAAyD,YAE9E,QAAQ,GACJ,CACR,CAAC,CAAC,CAAC,CACF,YACE,IAAI,EAAE,KAAK,CAAC,IAAI,gBACJ,KAAK,EACjB,SAAS,EAAE,iBAAiB,EAC5B,KAAK,EAAE,YAAY,iBACP,oBAAoB,oBACjB,MAAM,2BACC,8DAAyD,YAE9E,QAAQ,GACP,CACL,CAAC;IACJ,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC5B,OAAO,CACL,iBACE,IAAI,EAAC,QAAQ,gBACD,KAAK,EACjB,SAAS,EAAE,iBAAiB,EAC5B,KAAK,EAAE,mBAAmB,iBACd,oBAAoB,oBACjB,MAAM,2BACC,8DAAyD,EAC/E,OAAO,EAAE,GAAG,EAAE;gBACZ,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAC1B,CAAC,YAEA,QAAQ,GACF,CACV,CAAC;IACJ,CAAC;IAED,uEAAuE;IACvE,OAAO,6BAAiB,oBAAoB,YAAE,QAAQ,GAAO,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAuB;IACjD,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;IACjB,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;IAC1B,MAAM,QAAQ,GAAG,iBAAiB,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IACrE,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC;IAEvC,MAAM,SAAS,GAAG,gBAAgB,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAC5D,MAAM,aAAa,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;IACrD,MAAM,WAAW,GAAG,sBAAsB,CAAC,SAAS,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,gBAAgB,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IAE3D,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAE3F,MAAM,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAClD,MAAM,aAAa,GAAG,KAAK,CAAC,aAAa,IAAI,MAAM,CAAC;IAEpD,MAAM,aAAa,GAAG,CAAC,CACrB,QAAQ,CAAC,SAAS;QAChB,CAAC,CAAC,kBAAkB,CAAC,kBAAkB;QACvC,CAAC,CAAC,kBAAkB,CAAC,eAAe,CACvC,CAAC;IAEF,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;IAClC,2EAA2E;IAC3E,4EAA4E;IAC5E,eAAe;IACf,MAAM,WAAW,GACf,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC;IAEhE;;;;;;;;;OASG;IACH,MAAM,OAAO,GAAG,CACd,8BACE,KAAC,YAAY,IACX,QAAQ,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAC7B,GAAG,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,GAClD,EACF,MAAC,IAAI,IACH,QAAQ,QACR,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,EACf,KAAK,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,SAAS,EAAE,aAE/C,KAAK,CAAC,KAAK,EAEZ,KAAC,UAAU,CAAC,IAAI,IAAC,MAAM,uBAAa,qBAAqB,YACvD,KAAC,YAAY,IACX,MAAM,EAAE,OAAO,CAAC,KAAK,KACjB,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,GAC1E,GACc,EAElB,KAAC,UAAU,CAAC,IAAI,IAAC,QAAQ,uBAAa,qBAAqB,YACxD,KAAK,GACU,EAIjB,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CACtB,KAAC,UAAU,CAAC,IAAI,IAAC,IAAI,EAAC,WAAW,EAAC,QAAQ,kBACxC,KAAC,aAAa,IACZ,QAAQ,EAAE,mBAAmB,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EACpE,MAAM,EAAE,sBAAsB,CAAC,SAAS,CAAC,GACzC,GACc,CACnB,CAAC,CAAC,CAAC,IAAI,EAEP,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAC1B,KAAC,aAAa,IACZ,QAAQ,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EACnD,MAAM,EAAE,WAAW,GACnB,CACH,CAAC,CAAC,CAAC,IAAI,EAEP,OAAO,CAAC,cAAc,KAAK,SAAS;wBACrC,OAAO,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAClC,KAAC,UAAU,CAAC,IAAI,IAAC,IAAI,EAAC,WAAW,iBAAa,wBAAwB,YACnE,OAAO,CAAC,cAAc,GACP,CACnB,CAAC,CAAC,CAAC,IAAI,IACH,IACN,CACJ,CAAC;IAEF,OAAO,CACL,MAAC,SAAS,IACR,OAAO,EAAC,MAAM,KACV,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAE1D,gBAAO,IAAI,EAAE,sBAAsB,EAAE,UAAU,EAAC,SAAS,YACtD,aAAa,EAAE,GACV,EACR,MAAC,IAAI,IACH,IAAI,EAAC,OAAO,iBACA,eAAe,qBACV,OAAO,CAAC,EAAE,KACvB,CAAC,MAAM,KAAK,SAAS;oBACvB,CAAC,CAAC,EAAE,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE;oBAC1C,CAAC,CAAC,EAAE,CAAC;gBACP,oEAAoE;gBACpE,uEAAuE;gBACvE,oEAAoE;gBACpE,6BAA6B;gBAC7B,MAAM,EAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,EAC7C,KAAK,EAAE,EAAE,CAAC,sBAAgC,CAAC,EAAE,KAAK,CAAC,YAAY,EAAE,aAEjE,KAAC,UAAU,OAAK,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,WAAW,YAC7D,OAAO,GACG,EAMZ,KAAK,CAAC,YAAY,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACrC,eACE,KAAK,EAAE;4BACL,aAAa,EAAE,KAAK,CAAC,SAAS;4BAC9B,eAAe,EAAE,KAAK,CAAC,SAAS;yBACjC,aAED,KAAC,YAAY,IACX,IAAI,EAAE,QAAQ,CAAC,IAAI,EACnB,MAAM,EAAC,uBAAuB,EAC9B,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,YAEvB,CAAC,IAAI,EAAE,EAAE,CAAC,CACT,KAAC,IAAI,IAAC,OAAO,EAAC,UAAU,EAAC,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,YAC/C,KAAC,MAAM,IACL,QAAQ,EAAE,IAAI,CAAC,QAAQ,0BACF,2EAA2E,KAC5F,CAAC,IAAI,CAAC,kBAAkB,CAAC,KAAK,SAAS;4CACzC,CAAC,CAAC,EAAE,kBAAkB,EAAE,IAAI,CAAC,kBAAkB,CAAC,EAAE;4CAClD,CAAC,CAAC,EAAE,CAAC,gBACK,aAAa,kBACX,QAAQ,CAAC,SAAS,iBACpB,wBAAwB,oBACpB,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,oBAC3B,MAAM,2BACC,8DAAyD,EAC/E,OAAO,EAAE,QAAQ,CAAC,MAAM,EACxB,IAAI,EAAE,KAAC,SAAS,IAAC,MAAM,EAAE,QAAQ,CAAC,SAAS,GAAI,GAC/C,GACG,CACR,GACY,EAQd,YAAY,CAAC,MAAM,KAAK,SAAS,IAAI,aAAa,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACtE,KAAC,UAAU,CAAC,IAAI,IACd,IAAI,EAAC,WAAW,iBACJ,gCAAgC,YAE5C,KAAC,UAAU,IAAC,GAAG,EAAE,KAAK,CAAC,MAAM,EAAE,MAAM,EAAC,uBAAuB,GAAG,GAChD,CACnB,IACG,CACP,IACI,IACG,CACb,CAAC;AACJ,CAAC"}