@stapel/listings-react 0.29.0 → 0.30.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 (77) hide show
  1. package/CHANGELOG.md +145 -0
  2. package/MODULE.md +9 -7
  3. package/README.md +5 -4
  4. package/dist/default/CardBadges.d.ts +32 -0
  5. package/dist/default/CardBadges.d.ts.map +1 -1
  6. package/dist/default/CardBadges.js +41 -3
  7. package/dist/default/CardBadges.js.map +1 -1
  8. package/dist/default/ListingDetailPane.d.ts +115 -8
  9. package/dist/default/ListingDetailPane.d.ts.map +1 -1
  10. package/dist/default/ListingDetailPane.js +358 -177
  11. package/dist/default/ListingDetailPane.js.map +1 -1
  12. package/dist/default/ListingRelated.d.ts +88 -0
  13. package/dist/default/ListingRelated.d.ts.map +1 -0
  14. package/dist/default/ListingRelated.js +41 -0
  15. package/dist/default/ListingRelated.js.map +1 -0
  16. package/dist/default/ListingSpecList.d.ts +29 -34
  17. package/dist/default/ListingSpecList.d.ts.map +1 -1
  18. package/dist/default/ListingSpecList.js +67 -12
  19. package/dist/default/ListingSpecList.js.map +1 -1
  20. package/dist/default/condensedBar.d.ts +17 -0
  21. package/dist/default/condensedBar.d.ts.map +1 -0
  22. package/dist/default/condensedBar.js +73 -0
  23. package/dist/default/condensedBar.js.map +1 -0
  24. package/dist/default/detailGallery.d.ts +40 -40
  25. package/dist/default/detailGallery.d.ts.map +1 -1
  26. package/dist/default/detailGallery.js +129 -0
  27. package/dist/default/detailGallery.js.map +1 -1
  28. package/dist/default/detailRhythm.d.ts +15 -0
  29. package/dist/default/detailRhythm.d.ts.map +1 -0
  30. package/dist/default/detailRhythm.js +74 -0
  31. package/dist/default/detailRhythm.js.map +1 -0
  32. package/dist/default/icons.d.ts +13 -0
  33. package/dist/default/icons.d.ts.map +1 -1
  34. package/dist/default/icons.js +15 -0
  35. package/dist/default/icons.js.map +1 -1
  36. package/dist/default/index.d.ts +9 -5
  37. package/dist/default/index.d.ts.map +1 -1
  38. package/dist/default/index.js +13 -4
  39. package/dist/default/index.js.map +1 -1
  40. package/dist/i18n/es.d.ts.map +1 -1
  41. package/dist/i18n/es.js +12 -6
  42. package/dist/i18n/es.js.map +1 -1
  43. package/dist/i18n/generated/errors.es.gen.js +1 -1
  44. package/dist/i18n/generated/errors.es.gen.js.map +1 -1
  45. package/dist/i18n/generated/errors.gen.d.ts +2 -2
  46. package/dist/i18n/generated/errors.gen.js +2 -2
  47. package/dist/i18n/generated/errors.gen.js.map +1 -1
  48. package/dist/i18n/generated/errors.ru.gen.js +1 -1
  49. package/dist/i18n/generated/errors.ru.gen.js.map +1 -1
  50. package/dist/i18n/keys.d.ts +23 -0
  51. package/dist/i18n/keys.d.ts.map +1 -1
  52. package/dist/i18n/keys.js +38 -7
  53. package/dist/i18n/keys.js.map +1 -1
  54. package/dist/i18n/ru.d.ts.map +1 -1
  55. package/dist/i18n/ru.js +14 -9
  56. package/dist/i18n/ru.js.map +1 -1
  57. package/llms.txt +3 -3
  58. package/manifest.json +29 -4
  59. package/nav-manifest.json +1 -1
  60. package/package.json +8 -8
  61. package/src/analytics/generated/events.json +1 -1
  62. package/src/default/CardBadges.tsx +65 -4
  63. package/src/default/ListingDetailPane.tsx +490 -52
  64. package/src/default/ListingRelated.tsx +154 -0
  65. package/src/default/ListingSpecList.tsx +64 -1
  66. package/src/default/condensedBar.ts +74 -0
  67. package/src/default/detailGallery.ts +141 -0
  68. package/src/default/detailRhythm.ts +78 -0
  69. package/src/default/icons.tsx +32 -0
  70. package/src/default/index.ts +45 -2
  71. package/src/i18n/es.ts +12 -7
  72. package/src/i18n/generated/errors.es.gen.ts +1 -1
  73. package/src/i18n/generated/errors.gen.ts +2 -2
  74. package/src/i18n/generated/errors.json +2 -4
  75. package/src/i18n/generated/errors.ru.gen.ts +1 -1
  76. package/src/i18n/keys.ts +38 -7
  77. package/src/i18n/ru.ts +14 -10
@@ -66,6 +66,7 @@ export type { FeedGridProps } from "./FeedGrid.js";
66
66
  export {
67
67
  ListingDetailPane,
68
68
  DETAIL_MEASURE,
69
+ QUICK_QUESTIONS_MAX,
69
70
  // The split layout's two geometry constants, for a container laying out
70
71
  // against the same tracks (and for a test that measures them).
71
72
  DETAIL_SPLIT_MEASURE,
@@ -82,11 +83,45 @@ export type {
82
83
  // inline `display`.
83
84
  export {
84
85
  LISTINGS_GALLERY_CLASS,
86
+ LISTINGS_GALLERY_COUNTER_CLASS,
87
+ LISTINGS_GALLERY_FRAME_CLASS,
85
88
  LISTINGS_GALLERY_STYLE_HREF,
86
89
  LISTINGS_GALLERY_STRIP_BASIS,
87
90
  detailGalleryCss,
91
+ nearestPhotoIndex,
92
+ useGalleryPosition,
88
93
  } from "./detailGallery.js";
89
- export type { ListingGalleryLayout } from "./detailGallery.js";
94
+ export type { GalleryPosition, ListingGalleryLayout } from "./detailGallery.js";
95
+ // The listing page's block rhythm: the reset that keeps a child's own margin
96
+ // out of the column's gap, and the section rule's own token spacing.
97
+ export {
98
+ DETAIL_RHYTHM_CLASS,
99
+ DETAIL_RHYTHM_STYLE_HREF,
100
+ DETAIL_RULE_CLASS,
101
+ DETAIL_RULE_SPACE,
102
+ detailRhythmCss,
103
+ } from "./detailRhythm.js";
104
+ // The condensed top bar the pane draws for `actionsPlacement="condensed-top"`
105
+ // — its classes and sheet, so a container retunes the geometry with a selector
106
+ // rather than `!important` over a pair's own.
107
+ export {
108
+ CONDENSED_BAR_CLASS,
109
+ CONDENSED_BAR_STYLE_HREF,
110
+ CONDENSED_TITLE_CLASS,
111
+ condensedBarCss,
112
+ } from "./condensedBar.js";
113
+ // The two "find more" strips, for a host composing them itself.
114
+ export {
115
+ ListingRelatedStrip,
116
+ RELATED_CARD_BASIS,
117
+ RELATED_STRIP_CLASS,
118
+ RELATED_STYLE_HREF,
119
+ relatedStripCss,
120
+ } from "./ListingRelated.js";
121
+ export type {
122
+ ListingRelatedContext,
123
+ ListingRelatedStripProps,
124
+ } from "./ListingRelated.js";
90
125
  export {
91
126
  ListingComposerPage,
92
127
  COMPOSER_DETAILS_PLACEMENT,
@@ -123,10 +158,18 @@ export type { ListingPhotoProps } from "./ListingPhoto.js";
123
158
  export {
124
159
  ListingSpecColumns,
125
160
  ListingSpecList,
161
+ SPEC_FOLD_MIN_HIDDEN,
126
162
  specListCss,
127
163
  } from "./ListingSpecList.js";
128
164
  export type { ListingSpecListProps } from "./ListingSpecList.js";
129
- export { CardBadges, CardSpecLine } from "./CardBadges.js";
165
+ export {
166
+ CardBadges,
167
+ CardSpecLine,
168
+ CARD_SPEC_LINE_CLASS,
169
+ CARD_SPEC_STYLE_HREF,
170
+ CARD_SPEC_TEXT_CLASS,
171
+ cardSpecLineCss,
172
+ } from "./CardBadges.js";
130
173
  export type { CardBadgesProps } from "./CardBadges.js";
131
174
 
132
175
  // ── the card gallery's two gestures ─────────────────────────────────────────
package/src/i18n/es.ts CHANGED
@@ -32,13 +32,9 @@ export const listingsI18nBundleEs: I18nDictionary = {
32
32
  // source. The reasoning, and the single surviving override, are spelled out
33
33
  // once in `./ru.ts`; this is its es half.
34
34
  //
35
- // Upstream's es interpolates {from_status} the WIRE value ('draft',
36
- // 'archived') into translated prose. The status is already named, in the
37
- // reader's own words, beside every control this refusal appears under; see
38
- // the note on this pair of keys in keys.ts. Remove this override when
39
- // stapel-listings drops the placeholder.
40
- "error.409.invalid_listing_transition":
41
- "Desde su estado actual, el anuncio no se puede mover así",
35
+ // The one override that survived 0.22.8 is gone with it: stapel-listings
36
+ // 0.22.10 dropped the {from_status} slot from all three languages, so there
37
+ // is nothing left for this pair to correct.
42
38
 
43
39
  "listings.error.unknown": "Algo salió mal con este anuncio",
44
40
 
@@ -116,6 +112,15 @@ export const listingsI18nBundleEs: I18nDictionary = {
116
112
  "listings.detail.views": "Visitas",
117
113
  "listings.detail.edit": "Editar el anuncio",
118
114
  "listings.detail.take_down": "Retirarlo",
115
+ "listings.detail.back": "Atrás",
116
+ "listings.detail.ask_seller": "Pregunta al vendedor",
117
+ "listings.detail.question_available": "¿Sigue disponible?",
118
+ "listings.detail.question_price": "¿El precio es negociable?",
119
+ "listings.detail.question_viewing": "¿Puedo verlo en persona?",
120
+ "listings.detail.question_delivery": "¿Hacen envíos?",
121
+ "listings.detail.similar": "Anuncios similares",
122
+ "listings.detail.from_seller": "Más de este vendedor",
123
+ "listings.detail.show_all": "Ver todo",
119
124
 
120
125
  "listings.compose.new_title": "Anuncio nuevo",
121
126
  "listings.compose.edit_title": "Editar el anuncio",
@@ -66,7 +66,7 @@ export const listingsErrorBundleEs: Partial<Record<ListingsErrorCode, string>> =
66
66
  "error.408.request_timeout": "Tiempo de espera de la solicitud agotado",
67
67
  "error.409.already_favorited": "El anuncio ya está en favoritos",
68
68
  "error.409.conflict": "El recurso ya existe",
69
- "error.409.invalid_listing_transition": "Cambio de estado no válido para {from_status}",
69
+ "error.409.invalid_listing_transition": "El anuncio no puede pasar de su estado actual al estado elegido",
70
70
  "error.409.listing_cannot_delete_active": "No se puede eliminar un anuncio activo. Archívalo primero.",
71
71
  "error.410.gone": "El recurso se ha eliminado permanentemente",
72
72
  "error.413.payload_too_large": "El cuerpo de la solicitud es demasiado grande",
@@ -95,7 +95,7 @@ export const LISTINGS_ERRORS = {
95
95
  "error.408.request_timeout": { status: 408, params: [], remediation: "retry", en: "Request timeout" },
96
96
  "error.409.already_favorited": { status: 409, params: [], remediation: "fix_input", en: "Listing already favorited" },
97
97
  "error.409.conflict": { status: 409, params: [], remediation: "fix_input", en: "Resource already exists" },
98
- "error.409.invalid_listing_transition": { status: 409, params: ["from_status"], remediation: "fix_input", en: "Invalid status transition for {from_status}" },
98
+ "error.409.invalid_listing_transition": { status: 409, params: [], remediation: "fix_input", en: "This listing cannot move to that status from the one it is in now" },
99
99
  "error.409.listing_cannot_delete_active": { status: 409, params: [], remediation: "fix_input", en: "Cannot delete an active listing. Archive it first." },
100
100
  "error.410.gone": { status: 410, params: [], remediation: "retry", en: "Resource has been permanently removed" },
101
101
  "error.413.payload_too_large": { status: 413, params: [], remediation: "retry", en: "Request body is too large" },
@@ -253,7 +253,7 @@ export const listingsErrorBundleEn: Record<ListingsErrorCode, string> = {
253
253
  "error.408.request_timeout": "Request timeout",
254
254
  "error.409.already_favorited": "Listing already favorited",
255
255
  "error.409.conflict": "Resource already exists",
256
- "error.409.invalid_listing_transition": "Invalid status transition for {from_status}",
256
+ "error.409.invalid_listing_transition": "This listing cannot move to that status from the one it is in now",
257
257
  "error.409.listing_cannot_delete_active": "Cannot delete an active listing. Archive it first.",
258
258
  "error.410.gone": "Resource has been permanently removed",
259
259
  "error.413.payload_too_large": "Request body is too large",
@@ -490,11 +490,9 @@
490
490
  {
491
491
  "code": "error.409.invalid_listing_transition",
492
492
  "status": 409,
493
- "params": [
494
- "from_status"
495
- ],
493
+ "params": [],
496
494
  "remediation": "fix_input",
497
- "en": "Invalid status transition for {from_status}"
495
+ "en": "This listing cannot move to that status from the one it is in now"
498
496
  },
499
497
  {
500
498
  "code": "error.409.listing_cannot_delete_active",
@@ -66,7 +66,7 @@ export const listingsErrorBundleRu: Partial<Record<ListingsErrorCode, string>> =
66
66
  "error.408.request_timeout": "Время ожидания запроса истекло",
67
67
  "error.409.already_favorited": "Объявление уже в избранном",
68
68
  "error.409.conflict": "Ресурс уже существует",
69
- "error.409.invalid_listing_transition": "Недопустимая смена статуса для «{from_status}»",
69
+ "error.409.invalid_listing_transition": "Из текущего статуса объявление нельзя перевести в выбранный",
70
70
  "error.409.listing_cannot_delete_active": "Активное объявление нельзя удалить. Сначала перенесите его в архив.",
71
71
  "error.410.gone": "Ресурс был безвозвратно удалён",
72
72
  "error.413.payload_too_large": "Тело запроса слишком большое",
package/src/i18n/keys.ts CHANGED
@@ -157,6 +157,29 @@ export const LISTINGS_I18N_KEYS = {
157
157
  /** The owner's two primaries on their own listing page. */
158
158
  detailEdit: "listings.detail.edit",
159
159
  detailTakeDown: "listings.detail.take_down",
160
+ /** The condensed bar's back control. Icon-only, so this string IS the whole
161
+ * announcement — the bar has a glyph, the title and the two verbs, and a
162
+ * nameless arrow is the one of the four nothing can read. */
163
+ detailBack: "listings.detail.back",
164
+ /**
165
+ * "Ask the seller" — the caption over the canned questions.
166
+ *
167
+ * The chips underneath are DEFAULTS, not content: four questions every
168
+ * classified's buyers ask, in the pair's own three locales, which a host
169
+ * replaces wholesale through `quickQuestions`. A pair that shipped none
170
+ * would leave every deployment writing the same four sentences.
171
+ */
172
+ detailAskSeller: "listings.detail.ask_seller",
173
+ detailQuestionAvailable: "listings.detail.question_available",
174
+ detailQuestionPrice: "listings.detail.question_price",
175
+ detailQuestionViewing: "listings.detail.question_viewing",
176
+ detailQuestionDelivery: "listings.detail.question_delivery",
177
+ /** The two "find more" strips' captions — see `<ListingRelatedStrip>`. */
178
+ detailSimilar: "listings.detail.similar",
179
+ detailFromSeller: "listings.detail.from_seller",
180
+ /** One verb for three folds: the spec table past its limit, and either
181
+ * strip's link into the search that holds the rest of it. */
182
+ detailShowAll: "listings.detail.show_all",
160
183
 
161
184
  // ── composer ─────────────────────────────────────────────────────────────
162
185
  composeNewTitle: "listings.compose.new_title",
@@ -407,6 +430,15 @@ export const listingsI18nBundleEn: Record<string, string> = {
407
430
  "listings.detail.views": "Views",
408
431
  "listings.detail.edit": "Edit listing",
409
432
  "listings.detail.take_down": "Take it down",
433
+ "listings.detail.back": "Back",
434
+ "listings.detail.ask_seller": "Ask the seller",
435
+ "listings.detail.question_available": "Is it still available?",
436
+ "listings.detail.question_price": "Is the price negotiable?",
437
+ "listings.detail.question_viewing": "Can I come and see it?",
438
+ "listings.detail.question_delivery": "Do you deliver?",
439
+ "listings.detail.similar": "Similar listings",
440
+ "listings.detail.from_seller": "More from this seller",
441
+ "listings.detail.show_all": "Show all",
410
442
 
411
443
  "listings.compose.new_title": "New listing",
412
444
  "listings.compose.edit_title": "Edit listing",
@@ -546,13 +578,12 @@ export const listingsI18nBundleEn: Record<string, string> = {
546
578
  * the reader needs is which MOVE is impossible, and that is the control
547
579
  * they are looking at.
548
580
  *
549
- * The SERVER's own 409 (`error.409.invalid_listing_transition`) carries the
550
- * same placeholder and is reworded in the ru and es bundles beside this
551
- * one, where a real reader met it. It is deliberately NOT overridden in the
552
- * English bundle: that bundle spreads the generated backend texts whole,
553
- * and a hand-written entry for one error code makes this pair's catalogue
554
- * claim a namespace it does not own `stapel/i18n-locale-parity` says so
555
- * and is right. The refusal is in any case now close to unreachable: the
581
+ * The SERVER's own 409 (`error.409.invalid_listing_transition`) carried the
582
+ * same placeholder and was reworded here, in the ru and es bundles, for the
583
+ * same reason. That override is GONE as of stapel-listings 0.22.10, which
584
+ * dropped the slot upstream in all three languages so the refusal now
585
+ * arrives already free of the wire value and this pair authors nothing under
586
+ * `error.*` at all. The refusal is in any case close to unreachable: the
556
587
  * dashboard offers only the moves the server declared.
557
588
  */
558
589
  "listings.blocked.transition":
package/src/i18n/ru.ts CHANGED
@@ -54,16 +54,11 @@ export const listingsI18nBundleRu: I18nDictionary = {
54
54
  // it: a key with two sources drifts, and nothing in this file could tell a
55
55
  // reader which of the two a screen had shown them.
56
56
  //
57
- // Exactly ONE key is still overridden, and it is a defect in the upstream
58
- // text rather than a preference: upstream's ru interpolates {from_status}
59
- // — the WIRE value ('draft', 'archived') — into translated prose, which is
60
- // the sentence a live cabinet already showed a seller once. The placeholder
61
- // carries nothing the screen lacks: the status is named, in the reader's
62
- // own words, beside every control this refusal appears under. See the long
63
- // note on this pair of keys in keys.ts. Remove this override when
64
- // stapel-listings drops the placeholder from the ru/es catalogues.
65
- "error.409.invalid_listing_transition":
66
- "Из текущего состояния объявление так перевести нельзя",
57
+ // The ONE override this pair kept at 0.22.8 is gone too, as its own note
58
+ // said it should be: upstream's text interpolated {from_status} — the WIRE
59
+ // value ('draft', 'archived') — into translated prose, and stapel-listings
60
+ // 0.22.10 dropped the placeholder from all three languages. The pair now
61
+ // authors nothing at all under `error.*`.
67
62
 
68
63
  "listings.error.unknown": "Что-то пошло не так с этим объявлением",
69
64
 
@@ -141,6 +136,15 @@ export const listingsI18nBundleRu: I18nDictionary = {
141
136
  "listings.detail.views": "Просмотры",
142
137
  "listings.detail.edit": "Редактировать объявление",
143
138
  "listings.detail.take_down": "Снять с публикации",
139
+ "listings.detail.back": "Назад",
140
+ "listings.detail.ask_seller": "Спросите у продавца",
141
+ "listings.detail.question_available": "Ещё продаётся?",
142
+ "listings.detail.question_price": "Торг уместен?",
143
+ "listings.detail.question_viewing": "Можно посмотреть?",
144
+ "listings.detail.question_delivery": "Доставка есть?",
145
+ "listings.detail.similar": "Похожие объявления",
146
+ "listings.detail.from_seller": "Другие объявления продавца",
147
+ "listings.detail.show_all": "Показать все",
144
148
 
145
149
  "listings.compose.new_title": "Новое объявление",
146
150
  "listings.compose.edit_title": "Редактирование объявления",