@stapel/listings-react 0.15.1 → 0.17.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 (48) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/dist/default/GateReasonPopover.d.ts +24 -0
  3. package/dist/default/GateReasonPopover.d.ts.map +1 -0
  4. package/dist/default/GateReasonPopover.js +45 -0
  5. package/dist/default/GateReasonPopover.js.map +1 -0
  6. package/dist/default/ListingCard.d.ts +26 -5
  7. package/dist/default/ListingCard.d.ts.map +1 -1
  8. package/dist/default/ListingCard.js +14 -5
  9. package/dist/default/ListingCard.js.map +1 -1
  10. package/dist/default/ListingComposerPage.d.ts.map +1 -1
  11. package/dist/default/ListingComposerPage.js +7 -1
  12. package/dist/default/ListingComposerPage.js.map +1 -1
  13. package/dist/default/ListingDetailPane.d.ts +60 -1
  14. package/dist/default/ListingDetailPane.d.ts.map +1 -1
  15. package/dist/default/ListingDetailPane.js +135 -38
  16. package/dist/default/ListingDetailPane.js.map +1 -1
  17. package/dist/default/index.d.ts +1 -1
  18. package/dist/default/index.d.ts.map +1 -1
  19. package/dist/default/index.js +4 -1
  20. package/dist/default/index.js.map +1 -1
  21. package/dist/headless/ListingDetail.d.ts +11 -0
  22. package/dist/headless/ListingDetail.d.ts.map +1 -1
  23. package/dist/headless/ListingDetail.js +7 -0
  24. package/dist/headless/ListingDetail.js.map +1 -1
  25. package/dist/i18n/es.d.ts.map +1 -1
  26. package/dist/i18n/es.js +4 -1
  27. package/dist/i18n/es.js.map +1 -1
  28. package/dist/i18n/keys.d.ts +11 -0
  29. package/dist/i18n/keys.d.ts.map +1 -1
  30. package/dist/i18n/keys.js +15 -1
  31. package/dist/i18n/keys.js.map +1 -1
  32. package/dist/i18n/ru.d.ts.map +1 -1
  33. package/dist/i18n/ru.js +4 -1
  34. package/dist/i18n/ru.js.map +1 -1
  35. package/llms.txt +1 -1
  36. package/manifest.json +4 -1
  37. package/nav-manifest.json +1 -1
  38. package/package.json +8 -8
  39. package/src/analytics/generated/events.json +1 -1
  40. package/src/default/GateReasonPopover.tsx +95 -0
  41. package/src/default/ListingCard.tsx +100 -43
  42. package/src/default/ListingComposerPage.tsx +12 -2
  43. package/src/default/ListingDetailPane.tsx +362 -114
  44. package/src/default/index.ts +9 -1
  45. package/src/headless/ListingDetail.tsx +19 -0
  46. package/src/i18n/es.ts +5 -1
  47. package/src/i18n/keys.ts +16 -1
  48. package/src/i18n/ru.ts +5 -1
package/dist/i18n/ru.js CHANGED
@@ -79,6 +79,7 @@ export const listingsI18nBundleRu = {
79
79
  "listings.detail.retry": "Повторить",
80
80
  "listings.detail.not_found": "По этому адресу объявления нет",
81
81
  "listings.detail.removed": "Это объявление удалено",
82
+ "listings.detail.withdrawn": "Объявление снято с публикации",
82
83
  "listings.detail.not_published": "Объявление сейчас не в продаже, и то, что вы видите, может быть неактуальным",
83
84
  "listings.detail.owner_only_view": "Это видите только вы — объявление ещё не опубликовано",
84
85
  "listings.detail.description": "Описание",
@@ -118,10 +119,12 @@ export const listingsI18nBundleRu = {
118
119
  "listings.compose.stock": "Сколько штук",
119
120
  "listings.compose.auto_republish": "Публиковать заново, когда истечёт срок",
120
121
  "listings.compose.save": "Сохранить черновик",
122
+ "listings.compose.save_live": "Отложить правки в черновик",
123
+ "listings.compose.saved_live": "Правки отложены в черновик — опубликованное объявление не изменилось",
121
124
  "listings.compose.saving": "Сохраняем…",
122
125
  "listings.compose.saved": "Черновик сохранён",
123
126
  "listings.compose.publish": "Опубликовать",
124
- "listings.compose.republish": "Отправить правки",
127
+ "listings.compose.republish": "Сохранить изменения",
125
128
  "listings.compose.publishing": "Отправляем…",
126
129
  "listings.compose.published_first": "Отправлено на проверку. Объявление появится в продаже после одобрения модератора.",
127
130
  "listings.compose.published_live": "Правки отправлены. Объявление остаётся опубликованным, пока мы их проверяем.",
@@ -1 +1 @@
1
- {"version":3,"file":"ru.js","sourceRoot":"","sources":["../../src/i18n/ru.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ru.js","sourceRoot":"","sources":["../../src/i18n/ru.ts"],"names":[],"mappings":"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"}
package/llms.txt CHANGED
@@ -1,4 +1,4 @@
1
- # @stapel/listings-react 0.15.1
1
+ # @stapel/listings-react 0.17.0
2
2
 
3
3
  Headless React flow pair for stapel-listings (contract >=0.12 <0.13) — 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/listings-react",
4
- "version": "0.15.1",
4
+ "version": "0.17.0",
5
5
  "backend": {
6
6
  "module": "stapel-listings",
7
7
  "contract": ">=0.12 <0.13"
@@ -956,7 +956,9 @@
956
956
  "listings.compose.publishing",
957
957
  "listings.compose.republish",
958
958
  "listings.compose.save",
959
+ "listings.compose.save_live",
959
960
  "listings.compose.saved",
961
+ "listings.compose.saved_live",
960
962
  "listings.compose.saving",
961
963
  "listings.compose.show_first_missing",
962
964
  "listings.compose.stock",
@@ -981,6 +983,7 @@
981
983
  "listings.detail.stock",
982
984
  "listings.detail.take_down",
983
985
  "listings.detail.unreadable_features",
986
+ "listings.detail.withdrawn",
984
987
  "listings.error.unknown",
985
988
  "listings.favorites.empty",
986
989
  "listings.favorites.empty_hint",
package/nav-manifest.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "package": "@stapel/listings-react",
3
- "version": "0.15.1",
3
+ "version": "0.17.0",
4
4
  "entries": [
5
5
  {
6
6
  "id": "listings.detail",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stapel/listings-react",
3
- "version": "0.15.1",
3
+ "version": "0.17.0",
4
4
  "description": "Headless React pair for stapel-listings: a typed client over the draft twin, the composer that turns a category schema into a submittable listing, and the owner's dashboard. Two independent axes are rendered as two — lifecycle `status` decides visibility and `moderation_status` decides nothing about it, so an edit to a live listing stays live and says 'under review' instead of vanishing. Feature values are drawn and mirrored by @stapel/attributes-react; photos arrive as an injected upload bag whose `refs` ARE `images_draft` and whose `settled` gates the submit; a publish refusal is routed onto the control that caused it by slug. Zero visual opinion in the main entry; an opt-in /default subpath ships the antd skin.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -53,9 +53,9 @@
53
53
  "limit": "13 KB"
54
54
  },
55
55
  {
56
- "name": "default — the antd skin (three cards, detail, composer, dashboard, the named slots and the delete confirmation) must stay out of the main bundle. Raised 17 -> 19 KB for the mobile wave: <ListingSerpCard> (photo strip + price-first block + action rail), <ListingFeedCard> and <FeedGrid> are two more card surfaces on the same shared target/favourite/photo parts, not three copies of one",
56
+ "name": "default — the antd skin (three cards, detail, composer, dashboard, the named slots and the delete confirmation) must stay out of the main bundle. Raised 17 -> 19 KB for the mobile wave: <ListingSerpCard> (photo strip + price-first block + action rail), <ListingFeedCard> and <FeedGrid> are two more card surfaces on the same shared target/favourite/photo parts, not three copies of one Raised 19 -> 20 KB for the desktop wave of the detail page: layout=\"split\" is a second ASSEMBLY of the money page (the sticky buy column, the two-column spec table, the widened measure) over the same parts, and GateReasonPopover is the blocked heart's third volume — the reason and the door disclosed on interaction, with the visually-hidden copy that keeps the refusal in the accessibility tree. Both are geometry and wiring, not new widgets",
57
57
  "path": "dist/default/index.js",
58
- "limit": "19 KB"
58
+ "limit": "20 KB"
59
59
  },
60
60
  {
61
61
  "name": "i18n/ru — the Russian bundle is opt-in, not carried by the main entry",
@@ -73,7 +73,7 @@
73
73
  "@stapel/core": ">=0.19.0 <1.0.0",
74
74
  "@stapel/currencies-react": ">=0.2.0",
75
75
  "@stapel/image": ">=0.2.0",
76
- "@stapel/tokens-antd": ">=0.9.0",
76
+ "@stapel/tokens-antd": ">=0.11.0",
77
77
  "@tanstack/react-query": "^5.0.0",
78
78
  "antd": ">=5.20.0 <7",
79
79
  "react": ">=19"
@@ -102,13 +102,13 @@
102
102
  "size-limit": "^11.2.0",
103
103
  "typescript": "^5.8.3",
104
104
  "vitest": "^3.2.4",
105
- "@stapel/attributes-react": "^0.11.0",
106
- "@stapel/core": "^0.23.0",
105
+ "@stapel/attributes-react": "^0.11.1",
106
+ "@stapel/core": "^0.23.1",
107
107
  "@stapel/currencies-react": "^0.3.0",
108
108
  "@stapel/image": "^0.4.2",
109
109
  "@stapel/showcase": "^0.3.0",
110
- "@stapel/tokens": "^0.6.0",
111
- "@stapel/tokens-antd": "^0.13.0"
110
+ "@stapel/tokens": "^0.7.0",
111
+ "@stapel/tokens-antd": "^0.14.0"
112
112
  },
113
113
  "engines": {
114
114
  "node": ">=22"
@@ -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/listings-react",
4
- "version": "0.15.1",
4
+ "version": "0.17.0",
5
5
  "defined": [],
6
6
  "flows": []
7
7
  }
@@ -0,0 +1,95 @@
1
+ /**
2
+ * `GateReasonPopover` — a blocked control's reason and its sign-in door,
3
+ * disclosed on interaction instead of standing in the layout.
4
+ *
5
+ * ── Why this exists next to a house rule that bans hovers ──────────────────
6
+ *
7
+ * `stapel/no-tooltip-in-skin` bans tooltips for two failure modes: hover-only
8
+ * text that a touch device never shows, and text anchored to a disabled antd
9
+ * button — which swallows the very pointer events the tooltip listens for.
10
+ * Both were about the reason becoming UNREACHABLE. This component is built so
11
+ * that neither can happen, which is the whole argument for the exception:
12
+ *
13
+ * - it opens on click/tap as well as hover and focus, so a thumb has a
14
+ * gesture where a cursor has a hover;
15
+ * - the anchor is NEVER an html-disabled control. The caller renders it
16
+ * `aria-disabled` and keeps it focusable and pointer-live (its action is
17
+ * already refused by the gate, so the click is a safe no-op), which is
18
+ * what lets focus and click open the disclosure at all;
19
+ * - the reason never leaves the accessibility tree: a visually-hidden copy
20
+ * stays in the DOM, wired to the control via `aria-describedby`, so
21
+ * assistive tech reads the refusal with the control's name whether or not
22
+ * a pointer ever arrives.
23
+ *
24
+ * What moved on interaction is only the VISUAL standing copy — the measured
25
+ * defect it answers is 24 copies of "sign in to do this" per catalogue
26
+ * screen (see `ListingCardBlockedReason`). The rule's disables below are the
27
+ * documented decision §2.4 asks for, not a hole.
28
+ *
29
+ * Deliberately NOT exported from `src/default/index.ts`: it is how this
30
+ * pair's own gated hearts speak, not a control a host composes with — the
31
+ * same standing `favorite.tsx` has.
32
+ */
33
+ import { useId } from "react";
34
+ import type { ReactElement, ReactNode } from "react";
35
+ import { Flex, Typography } from "antd";
36
+ // eslint-disable-next-line stapel/no-tooltip-in-skin -- interaction disclosure, not a hover: opens on click/tap and focus too, anchored to a non-disabled control, with the reason kept in the a11y tree via aria-describedby (see this file's header)
37
+ import { Popover } from "antd";
38
+ import { visuallyHidden } from "@stapel/tokens-antd/skin";
39
+ import type { SignInCta } from "@stapel/core";
40
+ import { spacing } from "@stapel/tokens";
41
+ import { SignInLink } from "./SignInLink.js";
42
+
43
+ /** What the render prop hands the anchor control: point the control's
44
+ * `aria-describedby` at the hidden copy of the reason. */
45
+ export interface GateReasonPopoverBinding {
46
+ readonly "aria-describedby": string;
47
+ }
48
+
49
+ export interface GateReasonPopoverProps {
50
+ /** The gate's reason, already localized (`useActionGate(...).reason`). */
51
+ readonly reason: string;
52
+ /** The container's sign-in door. Absent: the disclosure holds the reason
53
+ * alone, exactly as the standing volumes do. */
54
+ readonly cta: SignInCta | undefined;
55
+ /** Test id of the disclosure's content. */
56
+ readonly testId: string;
57
+ /** Test id of the door inside it — each surface names its own, so a screen
58
+ * holding both a card and the pane hands a test one element per name. */
59
+ readonly signInTestId: string;
60
+ /** The anchor control. Spread the binding onto it, render it
61
+ * `aria-disabled` (not `disabled`) so it stays focusable and pointer-live. */
62
+ readonly children: (binding: GateReasonPopoverBinding) => ReactNode;
63
+ }
64
+
65
+ export function GateReasonPopover(props: GateReasonPopoverProps): ReactElement {
66
+ const reasonId = useId();
67
+ return (
68
+ <>
69
+ {/* The floor: the reason reaches AT without a pointer, popover or no
70
+ popover. Off-screen, never `display:none` — hidden text is not
71
+ announced at all. */}
72
+ <span id={reasonId} style={visuallyHidden}>
73
+ {props.reason}
74
+ </span>
75
+ {/* eslint-disable-next-line stapel/no-tooltip-in-skin -- interaction disclosure, not a hover: click/tap and focus open it too, and the reason stays in the a11y tree (header) */}
76
+ <Popover
77
+ trigger={["hover", "focus", "click"]}
78
+ content={
79
+ <Flex vertical gap={spacing[1]} data-testid={props.testId}>
80
+ <Typography.Text>{props.reason}</Typography.Text>
81
+ <SignInLink cta={props.cta} testId={props.signInTestId} />
82
+ </Flex>
83
+ }
84
+ >
85
+ {/* A plain wrapper takes the props Popover clones onto its direct
86
+ child — its open/close listeners and its own aria plumbing, which
87
+ OVERWRITES that child's `aria-describedby` in both states. With
88
+ the wrapper in between, the control keeps its own wiring to the
89
+ hidden copy whether the disclosure is open or closed, and the
90
+ events still arrive: hover, focus and click all bubble. */}
91
+ <div>{props.children({ "aria-describedby": reasonId })}</div>
92
+ </Popover>
93
+ </>
94
+ );
95
+ }
@@ -94,7 +94,11 @@
94
94
  * a disabled antd button receives no pointer events and is not focusable, so
95
95
  * the `Tooltip` this component used to offer as a "quieter" volume was a
96
96
  * reason nobody could read on any device. That arm is gone; `blockedReason`
97
- * is now "text" (reason + door) or "line" (reason alone, for a grid).
97
+ * is "text" (reason + door), "line" (reason alone, for a grid), or
98
+ * "popover" — the reason and the door disclosed on the heart itself, with
99
+ * the reason still in the accessibility tree. The third arm is NOT the old
100
+ * tooltip back under a new name; see `ListingCardBlockedReason` for what
101
+ * changed and why.
98
102
  */
99
103
  import type { CSSProperties, ReactElement, ReactNode } from "react";
100
104
  import { Button, Card, Flex, Typography, theme as antdTheme } from "antd";
@@ -109,6 +113,7 @@ import type { FeatureCopySource } from "../model/features.js";
109
113
  import { lifecycleCaption } from "../model/status.js";
110
114
  import { useFavoriteToggle } from "../headless/Favorites.js";
111
115
  import { LISTINGS_I18N_KEYS } from "../i18n/keys.js";
116
+ import { GateReasonPopover } from "./GateReasonPopover.js";
112
117
  import { HeartIcon } from "./icons.js";
113
118
  import { SignInLink } from "./SignInLink.js";
114
119
  import { ListingPhotoStrip } from "./ListingPhoto.js";
@@ -166,11 +171,28 @@ export type ListingCardOpenProps =
166
171
  * help, it is the loudest thing on the page, and every one of those doors
167
172
  * leads where the header's own sign-in button already leads.
168
173
  *
169
- * There is no third setting. The reason is on screen in both, because the only
170
- * way to make it quieter than a line of text is to hide it behind hover, and
171
- * hover does not exist on the device most of these cards are read on.
174
+ * `"popover"` takes the standing copy out of the card's layout entirely: the
175
+ * reason and the door render in a disclosure anchored to the heart itself,
176
+ * opening on hover AND focus AND click/tap, while a visually-hidden copy of
177
+ * the reason stays wired to the button via `aria-describedby`.
178
+ *
179
+ * This docstring used to end "there is no third setting", on the argument
180
+ * that the only way to be quieter than a line of text is to hide the reason
181
+ * behind hover, and hover does not exist on the device most of these cards
182
+ * are read on. Half of that argument held up and half was answered. What
183
+ * held: the desktop walk measured the standing caption printed under EVERY
184
+ * card — 24 copies per screen — and the product ruling is that the door
185
+ * belongs on interaction, not as standing copy; a pooled scope and a
186
+ * per-card line are both still STANDING copy, so neither volume above can
187
+ * satisfy it. What was answered: the disclosure is not hover-gated (a tap
188
+ * opens it, so a thumb is one gesture from the reason — the same distance
189
+ * as a cursor), its anchor is never an html-disabled control (the events
190
+ * arrive), and the reason never leaves the accessibility tree. Interaction
191
+ * disclosure keeps the reason one gesture away on both pointer and touch;
192
+ * what it stops doing is shouting it twenty-four times. Mechanics in
193
+ * `GateReasonPopover`.
172
194
  */
173
- export type ListingCardBlockedReason = "text" | "line";
195
+ export type ListingCardBlockedReason = "text" | "line" | "popover";
174
196
 
175
197
  /** The class the whole-card target carries, for {@link cardTargetCss}. */
176
198
  export const CARD_TARGET_CLASS = "stapel-listing-card-target";
@@ -539,45 +561,80 @@ export function ListingCard(props: ListingCardProps): ReactElement {
539
561
  paddingBlockEnd: token.paddingSM,
540
562
  }}
541
563
  >
542
- <GatedControl
543
- gate={favorite.gate}
544
- testId="listings-card-actions"
545
- style={{ width: "100%" }}
546
- >
547
- {(bind) => (
548
- <Flex justify="flex-end" style={{ width: "100%" }}>
549
- <Button
550
- disabled={bind.disabled}
551
- data-disabled-reason="the enclosing <GatedControl> renders the gate's reason beside this button"
552
- {...(bind["aria-describedby"] !== undefined
553
- ? { "aria-describedby": bind["aria-describedby"] }
554
- : {})}
555
- aria-label={favoriteLabel}
556
- aria-pressed={favorite.favorited}
557
- data-testid="listings-card-favorite"
558
- data-favorited={String(favorite.favorited)}
559
- data-analytics="none"
560
- data-analytics-reason="business action — host app wraps with its own tracked()"
561
- onClick={favorite.toggle}
562
- icon={<HeartIcon filled={favorite.favorited} />}
563
- />
564
- </Flex>
565
- )}
566
- </GatedControl>
567
-
568
- {/* The door. `GatedControl` above already prints the reason and
569
- wires `aria-describedby` to it; what it cannot know is WHERE a
570
- visitor signs in, which is the container's business and arrives
571
- as `signIn`. On a grid `blockedReason="line"` drops the door and
572
- keeps the sentence — twenty-four doors to one place is not
573
- twenty-four pieces of help. */}
574
- {favoriteGate.reason === undefined || blockedReason === "line" ? null : (
575
- <Typography.Text
576
- type="secondary"
577
- data-testid="listings-card-favorite-blocked"
564
+ {blockedReason === "popover" &&
565
+ favoriteGate.reason !== undefined ? (
566
+ /* The third volume: nothing standing in the layout. The
567
+ heart is `aria-disabled`, NOT `disabled` — the gate
568
+ already refuses the action (`toggle` is a no-op while
569
+ blocked), and an html-disabled button would swallow
570
+ the hover, the focus and the tap the disclosure opens
571
+ on, which is the exact grave the old Tooltip died in. */
572
+ <GateReasonPopover
573
+ reason={favoriteGate.reason}
574
+ cta={props.signIn}
575
+ testId="listings-card-favorite-reason"
576
+ signInTestId="listings-card-sign-in"
578
577
  >
579
- <SignInLink cta={props.signIn} testId="listings-card-sign-in" />
580
- </Typography.Text>
578
+ {(bind) => (
579
+ <Flex justify="flex-end" style={{ width: "100%" }}>
580
+ <Button
581
+ aria-disabled
582
+ {...bind}
583
+ aria-label={favoriteLabel}
584
+ aria-pressed={favorite.favorited}
585
+ data-testid="listings-card-favorite"
586
+ data-favorited={String(favorite.favorited)}
587
+ data-analytics="none"
588
+ data-analytics-reason="business action — host app wraps with its own tracked()"
589
+ onClick={favorite.toggle}
590
+ icon={<HeartIcon filled={favorite.favorited} />}
591
+ />
592
+ </Flex>
593
+ )}
594
+ </GateReasonPopover>
595
+ ) : (
596
+ <>
597
+ <GatedControl
598
+ gate={favorite.gate}
599
+ testId="listings-card-actions"
600
+ style={{ width: "100%" }}
601
+ >
602
+ {(bind) => (
603
+ <Flex justify="flex-end" style={{ width: "100%" }}>
604
+ <Button
605
+ disabled={bind.disabled}
606
+ data-disabled-reason="the enclosing <GatedControl> renders the gate's reason beside this button"
607
+ {...(bind["aria-describedby"] !== undefined
608
+ ? { "aria-describedby": bind["aria-describedby"] }
609
+ : {})}
610
+ aria-label={favoriteLabel}
611
+ aria-pressed={favorite.favorited}
612
+ data-testid="listings-card-favorite"
613
+ data-favorited={String(favorite.favorited)}
614
+ data-analytics="none"
615
+ data-analytics-reason="business action — host app wraps with its own tracked()"
616
+ onClick={favorite.toggle}
617
+ icon={<HeartIcon filled={favorite.favorited} />}
618
+ />
619
+ </Flex>
620
+ )}
621
+ </GatedControl>
622
+
623
+ {/* The door. `GatedControl` above already prints the reason and
624
+ wires `aria-describedby` to it; what it cannot know is WHERE a
625
+ visitor signs in, which is the container's business and arrives
626
+ as `signIn`. On a grid `blockedReason="line"` drops the door and
627
+ keeps the sentence — twenty-four doors to one place is not
628
+ twenty-four pieces of help. */}
629
+ {favoriteGate.reason === undefined || blockedReason === "line" ? null : (
630
+ <Typography.Text
631
+ type="secondary"
632
+ data-testid="listings-card-favorite-blocked"
633
+ >
634
+ <SignInLink cta={props.signIn} testId="listings-card-sign-in" />
635
+ </Typography.Text>
636
+ )}
637
+ </>
581
638
  )}
582
639
  </div>
583
640
  )}
@@ -948,12 +948,22 @@ export function ListingComposerPage(
948
948
  data-analytics-reason="business action — host app wraps with its own tracked()"
949
949
  onClick={bag.save}
950
950
  >
951
- {t(bag.saving ? LISTINGS_I18N_KEYS.composeSaving : LISTINGS_I18N_KEYS.composeSave)}
951
+ {t(
952
+ bag.saving
953
+ ? LISTINGS_I18N_KEYS.composeSaving
954
+ : bag.isLiveEdit
955
+ ? LISTINGS_I18N_KEYS.composeSaveLive
956
+ : LISTINGS_I18N_KEYS.composeSave
957
+ )}
952
958
  </GatedButton>
953
959
 
954
960
  {bag.saved ? (
955
961
  <Typography.Text type="success" data-testid="listings-composer-saved">
956
- {t(LISTINGS_I18N_KEYS.composeSaved)}
962
+ {t(
963
+ bag.isLiveEdit
964
+ ? LISTINGS_I18N_KEYS.composeSavedLive
965
+ : LISTINGS_I18N_KEYS.composeSaved
966
+ )}
957
967
  </Typography.Text>
958
968
  ) : null}
959
969
  </Flex>