@stapel/listings-react 0.25.10 → 0.27.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 (144) hide show
  1. package/CHANGELOG.md +259 -0
  2. package/MODULE.md +3 -1
  3. package/README.md +122 -9
  4. package/dist/api/generated/schema.d.ts +22 -12
  5. package/dist/api/generated/schema.d.ts.map +1 -1
  6. package/dist/default/CardBadges.d.ts.map +1 -1
  7. package/dist/default/CardBadges.js +3 -1
  8. package/dist/default/CardBadges.js.map +1 -1
  9. package/dist/default/ListingActions.d.ts +108 -0
  10. package/dist/default/ListingActions.d.ts.map +1 -0
  11. package/dist/default/ListingActions.js +29 -0
  12. package/dist/default/ListingActions.js.map +1 -0
  13. package/dist/default/ListingCard.d.ts.map +1 -1
  14. package/dist/default/ListingCard.js +15 -8
  15. package/dist/default/ListingCard.js.map +1 -1
  16. package/dist/default/ListingDetailPane.d.ts +170 -62
  17. package/dist/default/ListingDetailPane.d.ts.map +1 -1
  18. package/dist/default/ListingDetailPane.js +284 -28
  19. package/dist/default/ListingDetailPane.js.map +1 -1
  20. package/dist/default/ListingFeedCard.d.ts.map +1 -1
  21. package/dist/default/ListingFeedCard.js +2 -1
  22. package/dist/default/ListingFeedCard.js.map +1 -1
  23. package/dist/default/ListingPhoto.d.ts.map +1 -1
  24. package/dist/default/ListingPhoto.js +5 -2
  25. package/dist/default/ListingPhoto.js.map +1 -1
  26. package/dist/default/ListingSerpCard.d.ts.map +1 -1
  27. package/dist/default/ListingSerpCard.js +18 -4
  28. package/dist/default/ListingSerpCard.js.map +1 -1
  29. package/dist/default/MyListingsPane.d.ts.map +1 -1
  30. package/dist/default/MyListingsPane.js +49 -21
  31. package/dist/default/MyListingsPane.js.map +1 -1
  32. package/dist/default/ShareAction.d.ts +32 -0
  33. package/dist/default/ShareAction.d.ts.map +1 -0
  34. package/dist/default/ShareAction.js +116 -0
  35. package/dist/default/ShareAction.js.map +1 -0
  36. package/dist/default/actionRow.d.ts +58 -0
  37. package/dist/default/actionRow.d.ts.map +1 -0
  38. package/dist/default/actionRow.js +128 -0
  39. package/dist/default/actionRow.js.map +1 -0
  40. package/dist/default/cardGallery.d.ts +2 -0
  41. package/dist/default/cardGallery.d.ts.map +1 -1
  42. package/dist/default/cardGallery.js +31 -0
  43. package/dist/default/cardGallery.js.map +1 -1
  44. package/dist/default/detailGallery.d.ts +77 -0
  45. package/dist/default/detailGallery.d.ts.map +1 -0
  46. package/dist/default/detailGallery.js +91 -0
  47. package/dist/default/detailGallery.js.map +1 -0
  48. package/dist/default/favorite.d.ts +25 -0
  49. package/dist/default/favorite.d.ts.map +1 -1
  50. package/dist/default/favorite.js +29 -3
  51. package/dist/default/favorite.js.map +1 -1
  52. package/dist/default/icons.d.ts +19 -0
  53. package/dist/default/icons.d.ts.map +1 -1
  54. package/dist/default/icons.js +23 -0
  55. package/dist/default/icons.js.map +1 -1
  56. package/dist/default/index.d.ts +11 -2
  57. package/dist/default/index.d.ts.map +1 -1
  58. package/dist/default/index.js +10 -1
  59. package/dist/default/index.js.map +1 -1
  60. package/dist/default/movableCluster.d.ts +18 -0
  61. package/dist/default/movableCluster.d.ts.map +1 -0
  62. package/dist/default/movableCluster.js +110 -0
  63. package/dist/default/movableCluster.js.map +1 -0
  64. package/dist/default/notice.d.ts +14 -0
  65. package/dist/default/notice.d.ts.map +1 -0
  66. package/dist/default/notice.js +62 -0
  67. package/dist/default/notice.js.map +1 -0
  68. package/dist/headless/MyListings.d.ts +61 -19
  69. package/dist/headless/MyListings.d.ts.map +1 -1
  70. package/dist/headless/MyListings.js +58 -19
  71. package/dist/headless/MyListings.js.map +1 -1
  72. package/dist/headless/Share.d.ts +103 -0
  73. package/dist/headless/Share.d.ts.map +1 -0
  74. package/dist/headless/Share.js +190 -0
  75. package/dist/headless/Share.js.map +1 -0
  76. package/dist/i18n/es.d.ts.map +1 -1
  77. package/dist/i18n/es.js +21 -0
  78. package/dist/i18n/es.js.map +1 -1
  79. package/dist/i18n/generated/errors.es.gen.d.ts +1 -1
  80. package/dist/i18n/generated/errors.es.gen.js +1 -1
  81. package/dist/i18n/generated/errors.gen.d.ts +18 -0
  82. package/dist/i18n/generated/errors.gen.d.ts.map +1 -1
  83. package/dist/i18n/generated/errors.gen.js +9 -0
  84. package/dist/i18n/generated/errors.gen.js.map +1 -1
  85. package/dist/i18n/generated/errors.ru.gen.d.ts +1 -1
  86. package/dist/i18n/generated/errors.ru.gen.js +1 -1
  87. package/dist/i18n/keys.d.ts +45 -0
  88. package/dist/i18n/keys.d.ts.map +1 -1
  89. package/dist/i18n/keys.js +60 -0
  90. package/dist/i18n/keys.js.map +1 -1
  91. package/dist/i18n/ru.d.ts.map +1 -1
  92. package/dist/i18n/ru.js +21 -0
  93. package/dist/i18n/ru.js.map +1 -1
  94. package/dist/index.d.ts +5 -3
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +2 -1
  97. package/dist/index.js.map +1 -1
  98. package/dist/model/cardBadges.d.ts +52 -3
  99. package/dist/model/cardBadges.d.ts.map +1 -1
  100. package/dist/model/cardBadges.js +74 -12
  101. package/dist/model/cardBadges.js.map +1 -1
  102. package/dist/model/mineSource.d.ts +9 -3
  103. package/dist/model/mineSource.d.ts.map +1 -1
  104. package/dist/model/mineSource.js.map +1 -1
  105. package/dist/model/status.d.ts +79 -15
  106. package/dist/model/status.d.ts.map +1 -1
  107. package/dist/model/status.js +86 -17
  108. package/dist/model/status.js.map +1 -1
  109. package/llms.txt +8 -3
  110. package/manifest.json +96 -4
  111. package/nav-manifest.json +1 -1
  112. package/package.json +10 -10
  113. package/src/analytics/generated/events.json +1 -1
  114. package/src/api/generated/schema.ts +22 -12
  115. package/src/default/CardBadges.tsx +3 -1
  116. package/src/default/ListingActions.tsx +196 -0
  117. package/src/default/ListingCard.tsx +79 -43
  118. package/src/default/ListingDetailPane.tsx +520 -89
  119. package/src/default/ListingFeedCard.tsx +2 -0
  120. package/src/default/ListingPhoto.tsx +28 -0
  121. package/src/default/ListingSerpCard.tsx +39 -12
  122. package/src/default/MyListingsPane.tsx +81 -44
  123. package/src/default/ShareAction.tsx +260 -0
  124. package/src/default/actionRow.ts +131 -0
  125. package/src/default/cardGallery.ts +31 -0
  126. package/src/default/detailGallery.ts +97 -0
  127. package/src/default/favorite.tsx +68 -1
  128. package/src/default/icons.tsx +60 -0
  129. package/src/default/index.ts +37 -1
  130. package/src/default/movableCluster.tsx +137 -0
  131. package/src/default/notice.ts +68 -0
  132. package/src/headless/MyListings.tsx +130 -39
  133. package/src/headless/Share.tsx +278 -0
  134. package/src/i18n/es.ts +28 -0
  135. package/src/i18n/generated/errors.es.gen.ts +1 -1
  136. package/src/i18n/generated/errors.gen.ts +9 -0
  137. package/src/i18n/generated/errors.json +31 -0
  138. package/src/i18n/generated/errors.ru.gen.ts +1 -1
  139. package/src/i18n/keys.ts +63 -0
  140. package/src/i18n/ru.ts +28 -0
  141. package/src/index.ts +22 -0
  142. package/src/model/cardBadges.ts +124 -12
  143. package/src/model/mineSource.ts +9 -3
  144. package/src/model/status.ts +102 -20
@@ -80,6 +80,13 @@ export function badgeValueText(row, locale) {
80
80
  function isTrue(raw) {
81
81
  return raw === true || raw === 1 || raw === "true";
82
82
  }
83
+ /** A caption and its answer, joined the way this surface separates them. */
84
+ function caption(name, body, style) {
85
+ // A SPACE in a chip and a COLON in a line. "Floor 3" is a caption inside a
86
+ // border; "Floor: 3" is what the same pair has to become when the border is
87
+ // gone and the neighbours are a dot away.
88
+ return style === "line" ? `${name}: ${body}` : `${name} ${body}`;
89
+ }
83
90
  /**
84
91
  * One badge element → the text a card prints, or `undefined` for an element
85
92
  * that has nothing to say (a false boolean, a blank value).
@@ -89,7 +96,7 @@ function isTrue(raw) {
89
96
  * exists: three cards each re-deciding what a badge says is three places for
90
97
  * "Brick · 3 · 9" to come back.
91
98
  */
92
- export function cardBadgeText(row, locale) {
99
+ export function cardBadgeText(row, locale, style = "badge") {
93
100
  const presentation = badgePresentation(row);
94
101
  const name = text(row.name);
95
102
  const unit = text(row.unit);
@@ -105,26 +112,81 @@ export function cardBadgeText(row, locale) {
105
112
  case "value_unit":
106
113
  return withUnit;
107
114
  case "name_value":
108
- // A SPACE, not a colon. "Floor 3" is a caption; "Floor: 3" is a form
109
- // field, and a card is neither a form nor a table the colon is the
110
- // punctuation the spec list uses because a spec list IS the table.
111
- // The unit rides along: a named row that dropped it reads "Mileage
112
- // 20 000", which is the defect this contract exists to close.
113
- return name.length > 0 ? `${name} ${withUnit}` : withUnit;
115
+ // Joined by the SURFACE's own punctuation (D421): a space inside a
116
+ // chip, a colon inside a line. The unit rides along either way a
117
+ // named row that dropped it reads "Mileage 20 000", which is the defect
118
+ // this contract exists to close.
119
+ return name.length > 0 ? caption(name, withUnit, style) : withUnit;
114
120
  default:
115
121
  // `value`, and an element the server left plain in a list that speaks
116
122
  // the contract. The value alone, never the unit — the server said so.
117
123
  return value;
118
124
  }
119
125
  }
120
- /** Every element that has something to say, in the server's order. */
121
- export function cardBadgeTexts(rows, locale) {
126
+ /**
127
+ * Does this element already print its own caption?
128
+ *
129
+ * `name` IS the caption, and a `name_value` with a name to print carries one.
130
+ * Everything else is a bare answer, and two bare answers are what can collide.
131
+ */
132
+ function alreadyCaptioned(row) {
133
+ const presentation = badgePresentation(row);
134
+ if (presentation === "name")
135
+ return true;
136
+ return presentation === "name_value" && text(row.name).length > 0;
137
+ }
138
+ /**
139
+ * How a bare answer could be MISTAKEN for its neighbour: by measuring the
140
+ * same thing (one unit, two axes) or by reading identically.
141
+ */
142
+ function ambiguityKey(row, printed) {
143
+ const unit = text(row.unit);
144
+ return unit.length > 0 ? `unit:${unit}` : `text:${printed}`;
145
+ }
146
+ /**
147
+ * Every element that has something to say, in the server's order, with two
148
+ * axes that would read alike told apart — see the module header (D421).
149
+ */
150
+ export function cardBadgeTexts(rows, locale, style = "badge") {
122
151
  const out = [];
152
+ const printedRows = [];
153
+ /** Ambiguity key → the positions in `out` that could be confused. */
154
+ const groups = new Map();
123
155
  for (const row of rows) {
124
- const printed = cardBadgeText(row, locale);
125
- if (printed !== undefined && typeof row.slug === "string" && row.slug.length > 0) {
126
- out.push({ slug: row.slug, text: printed });
156
+ const printed = cardBadgeText(row, locale, style);
157
+ if (printed === undefined || typeof row.slug !== "string" || row.slug.length === 0) {
158
+ continue;
127
159
  }
160
+ const at = out.length;
161
+ out.push({ slug: row.slug, text: printed });
162
+ printedRows.push(row);
163
+ if (alreadyCaptioned(row))
164
+ continue;
165
+ const key = ambiguityKey(row, printed);
166
+ const seen = groups.get(key);
167
+ if (seen === undefined)
168
+ groups.set(key, [at]);
169
+ else
170
+ seen.push(at);
171
+ }
172
+ for (const positions of groups.values()) {
173
+ if (positions.length < 2)
174
+ continue;
175
+ const names = positions.map((at) => text(printedRows[at]?.name));
176
+ // Nothing to caption with, or one word for both axes: leave the line as
177
+ // the server wrote it rather than adding a caption that tells a reader
178
+ // nothing they did not already have.
179
+ if (names.some((name) => name.length === 0))
180
+ continue;
181
+ if (new Set(names).size !== names.length)
182
+ continue;
183
+ positions.forEach((at, index) => {
184
+ const entry = out[at];
185
+ const name = names[index];
186
+ if (entry === undefined || name === undefined)
187
+ return;
188
+ out[at] = { slug: entry.slug, text: caption(name, entry.text, style) };
189
+ });
128
190
  }
129
191
  return out;
130
192
  }
@@ -1 +1 @@
1
- {"version":3,"file":"cardBadges.js","sourceRoot":"","sources":["../../src/model/cardBadges.ts"],"names":[],"mappings":"AAmGA;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAiB;IACjD,MAAM,GAAG,GAAG,GAAG,CAAC,YAAY,CAAC;IAC7B,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAC9C,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,OAAO,CAAC;QACb,KAAK,YAAY,CAAC;QAClB,KAAK,YAAY,CAAC;QAClB,KAAK,MAAM;YACT,OAAO,GAAG,CAAC;QACb;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAA6B;IAChE,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC,CAAC;AAClE,CAAC;AAED,4EAA4E;AAC5E,SAAS,IAAI,CAAC,KAAgC;IAC5C,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACvD,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,cAAc,CAAC,GAAY;IAClC,MAAM,OAAO,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC5D,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACnC,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC;AACrE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,GAAiB,EAAE,MAAe;IAC/D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC9B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACnC,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC;IACtB,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,EAAE;QAAE,OAAO,EAAE,CAAC;IAC/D,IAAI,OAAO,GAAG,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACxC,MAAM,MAAM,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3D,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACvD,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,CAAC;YACH,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE;gBACnC,qBAAqB,EAAE,MAAM;gBAC7B,qBAAqB,EAAE,MAAM;aAC9B,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IACD,OAAO,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACpD,CAAC;AAED,2EAA2E;AAC3E,SAAS,MAAM,CAAC,GAAY;IAC1B,OAAO,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,CAAC,IAAI,GAAG,KAAK,MAAM,CAAC;AACrD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,GAAiB,EAAE,MAAe;IAC9D,MAAM,YAAY,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAE5B,IAAI,YAAY,KAAK,MAAM,EAAE,CAAC;QAC5B,2DAA2D;QAC3D,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IACjE,CAAC;IAED,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC1C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAEzC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;IAE9D,QAAQ,YAAY,EAAE,CAAC;QACrB,KAAK,YAAY;YACf,OAAO,QAAQ,CAAC;QAClB,KAAK,YAAY;YACf,qEAAqE;YACrE,qEAAqE;YACrE,mEAAmE;YACnE,mEAAmE;YACnE,8DAA8D;YAC9D,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC5D;YACE,sEAAsE;YACtE,sEAAsE;YACtE,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,cAAc,CAC5B,IAA6B,EAC7B,MAAe;IAEf,MAAM,GAAG,GAAqC,EAAE,CAAC;IACjD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC3C,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACjF,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"cardBadges.js","sourceRoot":"","sources":["../../src/model/cardBadges.ts"],"names":[],"mappings":"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"}
@@ -32,10 +32,16 @@
32
32
  */
33
33
  import type { ListingsApi } from "../api/listingsApi.js";
34
34
  import type { MyListingsParams, PaginatedMyListingCards } from "../api/types.js";
35
- import type { MyListingsTab } from "./status.js";
36
- /** One page of the caller's own listings, however the host gets them. */
35
+ import type { MyListingsCountedTab } from "./status.js";
36
+ /**
37
+ * One page of the caller's own listings, however the host gets them.
38
+ *
39
+ * `tab` is one of the three COUNTED tabs and not the fourth: the removed tab
40
+ * (D407) reads takedowns off `?status=blocked` directly and unpaged, so a host
41
+ * source is never handed a tab it was not written for.
42
+ */
37
43
  export type MyListingsSource = (args: {
38
- readonly tab: MyListingsTab;
44
+ readonly tab: MyListingsCountedTab;
39
45
  readonly page: MyListingsParams;
40
46
  readonly signal?: AbortSignal;
41
47
  }) => Promise<PaginatedMyListingCards>;
@@ -1 +1 @@
1
- {"version":3,"file":"mineSource.d.ts","sourceRoot":"","sources":["../../src/model/mineSource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AACjF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,yEAAyE;AACzE,MAAM,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE;IACpC,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAC;AAEvC;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,WAAW,GAAG,gBAAgB,CAM1E"}
1
+ {"version":3,"file":"mineSource.d.ts","sourceRoot":"","sources":["../../src/model/mineSource.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AACjF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGxD;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE;IACpC,QAAQ,CAAC,GAAG,EAAE,oBAAoB,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B,KAAK,OAAO,CAAC,uBAAuB,CAAC,CAAC;AAEvC;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,WAAW,GAAG,gBAAgB,CAM1E"}
@@ -1 +1 @@
1
- {"version":3,"file":"mineSource.js","sourceRoot":"","sources":["../../src/model/mineSource.ts"],"names":[],"mappings":"AAmCA,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AASvD;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CAAC,GAAgB;IACtD,OAAO,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAC/B,GAAG,CAAC,UAAU,CACZ,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,wBAAwB,CAAC,GAAG,CAAC,EAAE,EAClD,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CACvC,CAAC;AACN,CAAC"}
1
+ {"version":3,"file":"mineSource.js","sourceRoot":"","sources":["../../src/model/mineSource.ts"],"names":[],"mappings":"AAmCA,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAevD;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CAAC,GAAgB;IACtD,OAAO,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAC/B,GAAG,CAAC,UAAU,CACZ,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,wBAAwB,CAAC,GAAG,CAAC,EAAE,EAClD,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CACvC,CAAC;AACN,CAAC"}
@@ -67,7 +67,8 @@ export interface ListingStatusView {
67
67
  }
68
68
  export declare function listingStatusView(status: ListingLifecycleStatus, moderationStatus: ListingModerationStatus): ListingStatusView;
69
69
  /**
70
- * The dashboard tabs, and the statuses each one folds together.
70
+ * The three tabs whose ROWS come off a keyset page, and the statuses each one
71
+ * folds together.
71
72
  *
72
73
  * The grouping is the SERVER's (`views.my_counters`), copied here so a tab's
73
74
  * caption and its count cannot describe different sets: `active` includes
@@ -75,24 +76,87 @@ export declare function listingStatusView(status: ListingLifecycleStatus, modera
75
76
  * both because a listing in those states is something the owner is still
76
77
  * working on. A client that grouped them its own way would show "3 active"
77
78
  * over two rows.
79
+ *
80
+ * The name is about the SOURCE, not about the counter: `MyCountersResponse`
81
+ * carries four integers since stapel-listings 0.22.4 (`blocked` joined the
82
+ * three), and this is still the set a {@link MyListingsCountedTab} —
83
+ * `MyListingsSource`'s whole parameter type — may name. The removed tab reads
84
+ * its rows off `?status=blocked` directly and unpaged, so a host that
85
+ * implemented the seam before the fourth tab existed is never handed it.
78
86
  */
79
- export declare const MY_LISTINGS_TABS: readonly ["active", "drafts", "archived"];
80
- export type MyListingsTab = (typeof MY_LISTINGS_TABS)[number];
81
- export declare const MY_LISTINGS_TAB_STATUSES: Readonly<Record<MyListingsTab, readonly ListingLifecycleStatus[]>>;
82
- /** Which tab a listing belongs to, or `undefined` for BLOCKED — the one
83
- * status `my/counters` counts in no tab at all. A dashboard that silently
84
- * dropped it would hide exactly the listing whose owner most needs to know. */
85
- export declare function tabOf(status: ListingLifecycleStatus): MyListingsTab | undefined;
87
+ export declare const MY_LISTINGS_COUNTED_TABS: readonly ["active", "drafts", "archived"];
88
+ /** One of the three tabs a `MyListingsSource` is asked for. */
89
+ export type MyListingsCountedTab = (typeof MY_LISTINGS_COUNTED_TABS)[number];
90
+ /** Which of the three keyset-paged tabs a status belongs to, or `undefined`
91
+ * for one none of them folds in `blocked`, today, which has a tab and a
92
+ * counter of its own and a different row source under it. */
93
+ export declare function countedTabOf(status: ListingLifecycleStatus): MyListingsCountedTab | undefined;
86
94
  /**
87
- * The statuses no tab folds in — `blocked`, and nothing else today.
95
+ * The statuses none of the three paged tabs folds in — `blocked`, and nothing
96
+ * else today.
88
97
  *
89
98
  * DERIVED, not written down a second time: a status added upstream and left
90
- * out of the counter groupings lands here automatically and gets shown, which
91
- * is the opposite of what a hardcoded `["blocked"]` would do the day it goes
92
- * stale. The dashboard renders these rows OUTSIDE the tabs (see
93
- * `default/MyListingsPane.tsx`) rather than folding them into one, because a
94
- * tab's rows and its `my/counters` badge have to describe the same set and
95
- * `my/counters` counts a takedown in no tab at all.
99
+ * out of the tab groupings lands here automatically and gets shown, which is
100
+ * the opposite of what a hardcoded `["blocked"]` would do the day it goes
101
+ * stale. That the server now has a `blocked` COUNTER for the same set does not
102
+ * make the derivation redundant: the counter names one status and this names
103
+ * whatever the three groupings leave over, which is the set the fourth tab
104
+ * must ASK for.
96
105
  */
97
106
  export declare const MY_LISTINGS_UNTABBED_STATUSES: readonly ListingLifecycleStatus[];
107
+ /**
108
+ * The fourth tab: the rows `my/counters` counts in NO tab at all.
109
+ *
110
+ * ── What was on screen (D407) ────────────────────────────────────────────
111
+ *
112
+ * A listing pulled by moderation showed "Taken down by a moderator" over a
113
+ * counter row reading "Active 0 · Drafts 0 · Archived 0", beside the active
114
+ * tab's own "nothing of yours is live". The object was on the page and in no
115
+ * tab and in no number — three statements, and the two loudest of them said
116
+ * the seller had nothing.
117
+ *
118
+ * The takedowns had a home before this (a block above the tabs) and that was
119
+ * the half that was wrong: a row outside the tab strip is a row the counters
120
+ * do not describe, and a person reads the counters. So they get a TAB, with a
121
+ * count, like every other state a listing can be in.
122
+ *
123
+ * ── Why a fourth tab and not the archive ─────────────────────────────────
124
+ *
125
+ * Folding `blocked` into `archived` is the other shape this could take, and
126
+ * it cost the count: when D407 was written `my/counters` had three integers
127
+ * and no fourth, so an archive tab holding takedowns would have read the
128
+ * server's `archived` number — `0` — until the tab was opened and its rows
129
+ * could raise it. The fourth tab was counted from its OWN read
130
+ * (`?status=blocked`, unpaged) so that the number was right while the seller
131
+ * was looking at a different tab, which is exactly the moment D407 was
132
+ * measured at. stapel-listings 0.22.4 puts `blocked` in the counter, so the
133
+ * number is the server's now and that read is only the tab's rows — but the
134
+ * property it was there to defend is the same one, and it is now defended by
135
+ * the wire instead of by a page.
136
+ *
137
+ * The archive keeps its meaning too, which is not nothing: "I put this away"
138
+ * and "a moderator took this down" are not the same sentence and a tab that
139
+ * said one over rows that meant the other would be the D407 defect wearing a
140
+ * label.
141
+ */
142
+ export declare const MY_LISTINGS_REMOVED_TAB = "removed";
143
+ /**
144
+ * Every tab the dashboard can show: the server's three, then the removed one.
145
+ *
146
+ * The removed tab is DRAWN only where there is something in it (see
147
+ * `headless/MyListings.tsx`) — an empty "Taken down" tab is a scare — but it
148
+ * is in this list unconditionally, because `?tab=removed` must parse and a
149
+ * host must be able to name it.
150
+ */
151
+ export declare const MY_LISTINGS_TABS: readonly [
152
+ ...typeof MY_LISTINGS_COUNTED_TABS,
153
+ typeof MY_LISTINGS_REMOVED_TAB
154
+ ];
155
+ export type MyListingsTab = (typeof MY_LISTINGS_TABS)[number];
156
+ export declare const MY_LISTINGS_TAB_STATUSES: Readonly<Record<MyListingsTab, readonly ListingLifecycleStatus[]>>;
157
+ /** Which tab a listing belongs to. Every status has one: the three counted
158
+ * groupings, and the removed tab for whatever they leave out. `undefined` is
159
+ * unreachable today and stays in the signature so a status this build has
160
+ * never heard of cannot be filed under a tab by accident. */
161
+ export declare function tabOf(status: ListingLifecycleStatus): MyListingsTab | undefined;
98
162
  //# sourceMappingURL=status.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/model/status.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EACV,sBAAsB,EACtB,uBAAuB,EACxB,MAAM,iBAAiB,CAAC;AAIzB;;;;;;;;;GASG;AACH,MAAM,MAAM,iBAAiB,GACzB,SAAS,GACT,SAAS,GACT,MAAM,GACN,SAAS,GACT,SAAS,CAAC;AAEd,mDAAmD;AACnD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,sBAAsB,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC;8DAC0D;IAC1D,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;CACnC;AAoDD,4CAA4C;AAC5C,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,sBAAsB,GAC7B,gBAAgB,CAElB;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAEzE;AAED,0EAA0E;AAC1E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,gBAAgB,EAAE,uBAAuB,CAAC;IACnD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,sBAAsB,EAC9B,gBAAgB,EAAE,uBAAuB,GACxC,gBAAgB,GAAG,SAAS,CAiG9B;AAED,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;IACrC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAClD;;;2BAGuB;IACvB,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC;sCACkC;IAClC,QAAQ,CAAC,kBAAkB,EAAE,SAAS,sBAAsB,EAAE,CAAC;CAChE;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,sBAAsB,EAC9B,gBAAgB,EAAE,uBAAuB,GACxC,iBAAiB,CAQnB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,2CAA4C,CAAC;AAE1E,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9D,eAAO,MAAM,wBAAwB,EAAE,QAAQ,CAC7C,MAAM,CAAC,aAAa,EAAE,SAAS,sBAAsB,EAAE,CAAC,CAKzD,CAAC;AAEF;;+EAE+E;AAC/E,wBAAgB,KAAK,CACnB,MAAM,EAAE,sBAAsB,GAC7B,aAAa,GAAG,SAAS,CAK3B;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,6BAA6B,EAAE,SAAS,sBAAsB,EACT,CAAC"}
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/model/status.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EACV,sBAAsB,EACtB,uBAAuB,EACxB,MAAM,iBAAiB,CAAC;AAIzB;;;;;;;;;GASG;AACH,MAAM,MAAM,iBAAiB,GACzB,SAAS,GACT,SAAS,GACT,MAAM,GACN,SAAS,GACT,SAAS,CAAC;AAEd,mDAAmD;AACnD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,sBAAsB,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC;8DAC0D;IAC1D,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;CACnC;AAoDD,4CAA4C;AAC5C,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,sBAAsB,GAC7B,gBAAgB,CAElB;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAEzE;AAED,0EAA0E;AAC1E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,gBAAgB,EAAE,uBAAuB,CAAC;IACnD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,sBAAsB,EAC9B,gBAAgB,EAAE,uBAAuB,GACxC,gBAAgB,GAAG,SAAS,CAiG9B;AAED,6EAA6E;AAC7E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;IACrC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAClD;;;2BAGuB;IACvB,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC;sCACkC;IAClC,QAAQ,CAAC,kBAAkB,EAAE,SAAS,sBAAsB,EAAE,CAAC;CAChE;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,sBAAsB,EAC9B,gBAAgB,EAAE,uBAAuB,GACxC,iBAAiB,CAQnB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,wBAAwB,2CAA4C,CAAC;AAElF,+DAA+D;AAC/D,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,MAAM,CAAC,CAAC;AAU7E;;6DAE6D;AAC7D,wBAAgB,YAAY,CAC1B,MAAM,EAAE,sBAAsB,GAC7B,oBAAoB,GAAG,SAAS,CAKlC;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,6BAA6B,EAAE,SAAS,sBAAsB,EACF,CAAC;AAE1E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,eAAO,MAAM,uBAAuB,YAAY,CAAC;AAEjD;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAAS;IACtC,GAAG,OAAO,wBAAwB;IAClC,OAAO,uBAAuB;CAC0B,CAAC;AAE3D,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9D,eAAO,MAAM,wBAAwB,EAAE,QAAQ,CAC7C,MAAM,CAAC,aAAa,EAAE,SAAS,sBAAsB,EAAE,CAAC,CAIzD,CAAC;AAEF;;;6DAG6D;AAC7D,wBAAgB,KAAK,CACnB,MAAM,EAAE,sBAAsB,GAC7B,aAAa,GAAG,SAAS,CAK3B"}
@@ -206,7 +206,8 @@ export function listingStatusView(status, moderationStatus) {
206
206
  };
207
207
  }
208
208
  /**
209
- * The dashboard tabs, and the statuses each one folds together.
209
+ * The three tabs whose ROWS come off a keyset page, and the statuses each one
210
+ * folds together.
210
211
  *
211
212
  * The grouping is the SERVER's (`views.my_counters`), copied here so a tab's
212
213
  * caption and its count cannot describe different sets: `active` includes
@@ -214,33 +215,101 @@ export function listingStatusView(status, moderationStatus) {
214
215
  * both because a listing in those states is something the owner is still
215
216
  * working on. A client that grouped them its own way would show "3 active"
216
217
  * over two rows.
218
+ *
219
+ * The name is about the SOURCE, not about the counter: `MyCountersResponse`
220
+ * carries four integers since stapel-listings 0.22.4 (`blocked` joined the
221
+ * three), and this is still the set a {@link MyListingsCountedTab} —
222
+ * `MyListingsSource`'s whole parameter type — may name. The removed tab reads
223
+ * its rows off `?status=blocked` directly and unpaged, so a host that
224
+ * implemented the seam before the fourth tab existed is never handed it.
217
225
  */
218
- export const MY_LISTINGS_TABS = ["active", "drafts", "archived"];
219
- export const MY_LISTINGS_TAB_STATUSES = {
226
+ export const MY_LISTINGS_COUNTED_TABS = ["active", "drafts", "archived"];
227
+ const COUNTED_TAB_STATUSES = {
220
228
  active: ["published", "pending"],
221
229
  drafts: ["draft", "rejected"],
222
230
  archived: ["archived", "paused", "expired", "sold"],
223
231
  };
224
- /** Which tab a listing belongs to, or `undefined` for BLOCKED — the one
225
- * status `my/counters` counts in no tab at all. A dashboard that silently
226
- * dropped it would hide exactly the listing whose owner most needs to know. */
227
- export function tabOf(status) {
228
- for (const tab of MY_LISTINGS_TABS) {
229
- if (MY_LISTINGS_TAB_STATUSES[tab].includes(status))
232
+ /** Which of the three keyset-paged tabs a status belongs to, or `undefined`
233
+ * for one none of them folds in `blocked`, today, which has a tab and a
234
+ * counter of its own and a different row source under it. */
235
+ export function countedTabOf(status) {
236
+ for (const tab of MY_LISTINGS_COUNTED_TABS) {
237
+ if (COUNTED_TAB_STATUSES[tab].includes(status))
230
238
  return tab;
231
239
  }
232
240
  return undefined;
233
241
  }
234
242
  /**
235
- * The statuses no tab folds in — `blocked`, and nothing else today.
243
+ * The statuses none of the three paged tabs folds in — `blocked`, and nothing
244
+ * else today.
236
245
  *
237
246
  * DERIVED, not written down a second time: a status added upstream and left
238
- * out of the counter groupings lands here automatically and gets shown, which
239
- * is the opposite of what a hardcoded `["blocked"]` would do the day it goes
240
- * stale. The dashboard renders these rows OUTSIDE the tabs (see
241
- * `default/MyListingsPane.tsx`) rather than folding them into one, because a
242
- * tab's rows and its `my/counters` badge have to describe the same set and
243
- * `my/counters` counts a takedown in no tab at all.
247
+ * out of the tab groupings lands here automatically and gets shown, which is
248
+ * the opposite of what a hardcoded `["blocked"]` would do the day it goes
249
+ * stale. That the server now has a `blocked` COUNTER for the same set does not
250
+ * make the derivation redundant: the counter names one status and this names
251
+ * whatever the three groupings leave over, which is the set the fourth tab
252
+ * must ASK for.
253
+ */
254
+ export const MY_LISTINGS_UNTABBED_STATUSES = LISTING_STATUSES.filter((status) => countedTabOf(status) === undefined);
255
+ /**
256
+ * The fourth tab: the rows `my/counters` counts in NO tab at all.
257
+ *
258
+ * ── What was on screen (D407) ────────────────────────────────────────────
259
+ *
260
+ * A listing pulled by moderation showed "Taken down by a moderator" over a
261
+ * counter row reading "Active 0 · Drafts 0 · Archived 0", beside the active
262
+ * tab's own "nothing of yours is live". The object was on the page and in no
263
+ * tab and in no number — three statements, and the two loudest of them said
264
+ * the seller had nothing.
265
+ *
266
+ * The takedowns had a home before this (a block above the tabs) and that was
267
+ * the half that was wrong: a row outside the tab strip is a row the counters
268
+ * do not describe, and a person reads the counters. So they get a TAB, with a
269
+ * count, like every other state a listing can be in.
270
+ *
271
+ * ── Why a fourth tab and not the archive ─────────────────────────────────
272
+ *
273
+ * Folding `blocked` into `archived` is the other shape this could take, and
274
+ * it cost the count: when D407 was written `my/counters` had three integers
275
+ * and no fourth, so an archive tab holding takedowns would have read the
276
+ * server's `archived` number — `0` — until the tab was opened and its rows
277
+ * could raise it. The fourth tab was counted from its OWN read
278
+ * (`?status=blocked`, unpaged) so that the number was right while the seller
279
+ * was looking at a different tab, which is exactly the moment D407 was
280
+ * measured at. stapel-listings 0.22.4 puts `blocked` in the counter, so the
281
+ * number is the server's now and that read is only the tab's rows — but the
282
+ * property it was there to defend is the same one, and it is now defended by
283
+ * the wire instead of by a page.
284
+ *
285
+ * The archive keeps its meaning too, which is not nothing: "I put this away"
286
+ * and "a moderator took this down" are not the same sentence and a tab that
287
+ * said one over rows that meant the other would be the D407 defect wearing a
288
+ * label.
244
289
  */
245
- export const MY_LISTINGS_UNTABBED_STATUSES = LISTING_STATUSES.filter((status) => tabOf(status) === undefined);
290
+ export const MY_LISTINGS_REMOVED_TAB = "removed";
291
+ /**
292
+ * Every tab the dashboard can show: the server's three, then the removed one.
293
+ *
294
+ * The removed tab is DRAWN only where there is something in it (see
295
+ * `headless/MyListings.tsx`) — an empty "Taken down" tab is a scare — but it
296
+ * is in this list unconditionally, because `?tab=removed` must parse and a
297
+ * host must be able to name it.
298
+ */
299
+ export const MY_LISTINGS_TABS = [...MY_LISTINGS_COUNTED_TABS, MY_LISTINGS_REMOVED_TAB];
300
+ export const MY_LISTINGS_TAB_STATUSES = {
301
+ ...COUNTED_TAB_STATUSES,
302
+ [MY_LISTINGS_REMOVED_TAB]: MY_LISTINGS_UNTABBED_STATUSES,
303
+ };
304
+ /** Which tab a listing belongs to. Every status has one: the three counted
305
+ * groupings, and the removed tab for whatever they leave out. `undefined` is
306
+ * unreachable today and stays in the signature so a status this build has
307
+ * never heard of cannot be filed under a tab by accident. */
308
+ export function tabOf(status) {
309
+ for (const tab of MY_LISTINGS_TABS) {
310
+ if (MY_LISTINGS_TAB_STATUSES[tab].includes(status))
311
+ return tab;
312
+ }
313
+ return undefined;
314
+ }
246
315
  //# sourceMappingURL=status.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/model/status.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/model/status.ts"],"names":[],"mappings":"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"}
package/llms.txt CHANGED
@@ -1,6 +1,6 @@
1
- # @stapel/listings-react 0.25.10
1
+ # @stapel/listings-react 0.27.0
2
2
 
3
- Headless React flow pair for stapel-listings (contract >=0.21 <0.22) — business + state, zero visual opinion.
3
+ Headless React flow pair for stapel-listings (contract >=0.22 <0.23) — business + state, zero visual opinion.
4
4
  Built on @stapel/core: typed client + StapelApiError envelope, auth token refresh,
5
5
  verification-403 interception, i18n engine, analytics facade, TanStack Query layer.
6
6
 
@@ -61,7 +61,7 @@ Paths are relative to `/listings/api/v1/`.
61
61
  - useValidateDraft (query) → validateDraft
62
62
 
63
63
  ## Errors (render t(code, params); UX from remediation)
64
- 69 keys (full catalog: manifest.json §errors). By remediation: fix_input 40 · retry 16 · verify 5 · wait_and_retry 5 · contact_support 2 · reauthenticate 1.
64
+ 72 keys (full catalog: manifest.json §errors). By remediation: fix_input 43 · retry 16 · verify 5 · wait_and_retry 5 · contact_support 2 · reauthenticate 1.
65
65
  Param-bearing keys (interpolation slots matter):
66
66
  - error.400.description_too_long [400] → fix_input {max_length}
67
67
  - error.400.description_too_short [400] → fix_input {min_length}
@@ -89,6 +89,9 @@ Param-bearing keys (interpolation slots matter):
89
89
  - error.400.field.unique [400] → fix_input {field}
90
90
  - error.400.listing_draft_meta_too_large [400] → fix_input {max_bytes}
91
91
  - error.400.listing_feature_not_allowed [400] → fix_input {feature}
92
+ - error.400.listing_features_draft_shape [400] → fix_input {got_type,example}
93
+ - error.400.listing_features_draft_unknown_slug [400] → fix_input {index,example}
94
+ - error.400.listing_features_draft_value_shape [400] → fix_input {slug,got_type,example}
92
95
  - error.400.listing_invalid_status_filter [400] → fix_input {status}
93
96
  - error.409.invalid_listing_transition [409] → fix_input {from_status}
94
97
  - error.429.rate_limit [429] → wait_and_retry {retry_after_minutes}
@@ -113,6 +116,7 @@ const { tracked } = useTracked();
113
116
  ```
114
117
 
115
118
  ## Demos (defineDemo → manifest.demos; compiled, linted, rendered examples)
119
+ - listings.actions → <ListingActions> [default|blocked] demo/ListingActions.demo.tsx
116
120
  - listings.card → <ListingCard> [default|saved|visitor|grid cell|list row|no-photo] demo/ListingCard.demo.tsx
117
121
  - listings.composer → <ListingComposerPage> [default|unwired|photos-in-flight|unsupported-type] demo/ListingComposer.demo.tsx
118
122
  - listings.detail → <ListingDetailPane> [default|contact-unwired|owner|not-found] demo/ListingDetail.demo.tsx
@@ -123,6 +127,7 @@ const { tracked } = useTracked();
123
127
  - listings.parts → <ListingStatusBlock> [default|tags|notes|media|door] demo/ListingParts.demo.tsx
124
128
  - listings.photo-strip → <ListingPhotoStrip> [default|single|no photos] demo/ListingPhotoStrip.demo.tsx
125
129
  - listings.serp-card → <ListingSerpCard> [default|trend|visitor|desktop row|bare] demo/ListingSerpCard.demo.tsx
130
+ - listings.share → <ShareAction> [default|menu] demo/Share.demo.tsx
126
131
  - listings.spec-parts → <CardBadges> [contract|legacy|specs|specs-split] demo/ListingSpecParts.demo.tsx
127
132
  Each source file is the canonical usage snippet (open the default variant).
128
133