@stapel/listings-react 0.2.0 → 0.3.1

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 (55) hide show
  1. package/CHANGELOG.md +162 -0
  2. package/MODULE.md +107 -3
  3. package/README.md +67 -2
  4. package/dist/default/FavoritesPane.d.ts +19 -4
  5. package/dist/default/FavoritesPane.d.ts.map +1 -1
  6. package/dist/default/FavoritesPane.js +13 -3
  7. package/dist/default/FavoritesPane.js.map +1 -1
  8. package/dist/default/ListingCard.d.ts +54 -11
  9. package/dist/default/ListingCard.d.ts.map +1 -1
  10. package/dist/default/ListingCard.js +32 -5
  11. package/dist/default/ListingCard.js.map +1 -1
  12. package/dist/default/ListingComposerPage.d.ts +59 -4
  13. package/dist/default/ListingComposerPage.d.ts.map +1 -1
  14. package/dist/default/ListingComposerPage.js +12 -3
  15. package/dist/default/ListingComposerPage.js.map +1 -1
  16. package/dist/default/ListingDetailPane.d.ts.map +1 -1
  17. package/dist/default/ListingDetailPane.js +1 -1
  18. package/dist/default/ListingDetailPane.js.map +1 -1
  19. package/dist/default/SignInLink.d.ts +28 -0
  20. package/dist/default/SignInLink.d.ts.map +1 -0
  21. package/dist/default/SignInLink.js +17 -0
  22. package/dist/default/SignInLink.js.map +1 -0
  23. package/dist/default/index.d.ts +5 -3
  24. package/dist/default/index.d.ts.map +1 -1
  25. package/dist/default/index.js +1 -0
  26. package/dist/default/index.js.map +1 -1
  27. package/dist/headless/ListingComposer.d.ts +17 -0
  28. package/dist/headless/ListingComposer.d.ts.map +1 -1
  29. package/dist/headless/ListingComposer.js +26 -10
  30. package/dist/headless/ListingComposer.js.map +1 -1
  31. package/dist/i18n/es.d.ts.map +1 -1
  32. package/dist/i18n/es.js +2 -1
  33. package/dist/i18n/es.js.map +1 -1
  34. package/dist/i18n/keys.d.ts +5 -0
  35. package/dist/i18n/keys.d.ts.map +1 -1
  36. package/dist/i18n/keys.js +7 -1
  37. package/dist/i18n/keys.js.map +1 -1
  38. package/dist/i18n/ru.d.ts.map +1 -1
  39. package/dist/i18n/ru.js +2 -1
  40. package/dist/i18n/ru.js.map +1 -1
  41. package/llms.txt +1 -1
  42. package/manifest.json +2 -1
  43. package/nav-manifest.json +1 -1
  44. package/package.json +4 -4
  45. package/src/analytics/generated/events.json +1 -1
  46. package/src/default/FavoritesPane.tsx +40 -11
  47. package/src/default/ListingCard.tsx +144 -27
  48. package/src/default/ListingComposerPage.tsx +79 -14
  49. package/src/default/ListingDetailPane.tsx +6 -1
  50. package/src/default/SignInLink.tsx +54 -0
  51. package/src/default/index.ts +15 -3
  52. package/src/headless/ListingComposer.tsx +43 -10
  53. package/src/i18n/es.ts +2 -1
  54. package/src/i18n/keys.ts +7 -1
  55. package/src/i18n/ru.ts +2 -1
package/dist/i18n/keys.js CHANGED
@@ -58,6 +58,8 @@ export const LISTINGS_I18N_KEYS = {
58
58
  cardFavoriteAdd: "listings.card.favorite_add",
59
59
  cardFavoriteRemove: "listings.card.favorite_remove",
60
60
  cardOpen: "listings.card.open",
61
+ /** The door beside a blocked favourite: the container supplies WHERE. */
62
+ cardSignIn: "listings.card.sign_in",
61
63
  // ── detail ───────────────────────────────────────────────────────────────
62
64
  detailLoading: "listings.detail.loading",
63
65
  detailLoadFailed: "listings.detail.load_failed",
@@ -76,6 +78,9 @@ export const LISTINGS_I18N_KEYS = {
76
78
  detailPhotoAlt: "listings.detail.photo_alt",
77
79
  detailPublishedAt: "listings.detail.published_at",
78
80
  detailExpiresAt: "listings.detail.expires_at",
81
+ /** The stock ROW'S LABEL. antd's `<Descriptions>` renders the colon and the
82
+ * quantity in the value cell, so this key carries no `{count}` — it used to,
83
+ * and the live page printed the placeholder. */
79
84
  detailStock: "listings.detail.stock",
80
85
  // ── composer ─────────────────────────────────────────────────────────────
81
86
  composeNewTitle: "listings.compose.new_title",
@@ -190,6 +195,7 @@ export const listingsI18nBundleEn = {
190
195
  "listings.card.favorite_add": "Save to favourites",
191
196
  "listings.card.favorite_remove": "Remove from favourites",
192
197
  "listings.card.open": "Open",
198
+ "listings.card.sign_in": "Sign in",
193
199
  "listings.detail.loading": "Loading the listing…",
194
200
  "listings.detail.load_failed": "We could not load this listing",
195
201
  "listings.detail.retry": "Try again",
@@ -205,7 +211,7 @@ export const listingsI18nBundleEn = {
205
211
  "listings.detail.photo_alt": "Photo {index} of {total}",
206
212
  "listings.detail.published_at": "Published {date}",
207
213
  "listings.detail.expires_at": "Listed until {date}",
208
- "listings.detail.stock": "{count} available",
214
+ "listings.detail.stock": "In stock",
209
215
  "listings.compose.new_title": "New listing",
210
216
  "listings.compose.edit_title": "Edit listing",
211
217
  "listings.compose.category": "Category",
@@ -1 +1 @@
1
- {"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/i18n/keys.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/i18n/keys.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAElE;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,YAAY,EAAE,wBAAwB;IAEtC,4EAA4E;IAC5E,WAAW,EAAE,uBAAuB;IACpC,aAAa,EAAE,yBAAyB;IACxC,eAAe,EAAE,2BAA2B;IAC5C,YAAY,EAAE,wBAAwB;IACtC,aAAa,EAAE,yBAAyB;IACxC,UAAU,EAAE,sBAAsB;IAClC,cAAc,EAAE,0BAA0B;IAC1C,aAAa,EAAE,yBAAyB;IACxC,cAAc,EAAE,0BAA0B;IAE1C,4EAA4E;IAC5E,+CAA+C;IAC/C,qBAAqB,EAAE,kCAAkC;IACzD,qEAAqE;IACrE,yBAAyB,EAAE,uCAAuC;IAClE,yEAAyE;IACzE,wBAAwB,EAAE,qCAAqC;IAC/D,qBAAqB,EAAE,kCAAkC;IACzD,yBAAyB,EAAE,uCAAuC;IAClE,kBAAkB,EAAE,8BAA8B;IAClD,oEAAoE;IACpE,2BAA2B,EAAE,yCAAyC;IAEtE,4EAA4E;IAC5E,WAAW,EAAE,wBAAwB;IACrC,oBAAoB,EAAE,iCAAiC;IACvD,eAAe,EAAE,4BAA4B;IAC7C,eAAe,EAAE,4BAA4B;IAC7C,kBAAkB,EAAE,+BAA+B;IACnD,QAAQ,EAAE,oBAAoB;IAC9B,yEAAyE;IACzE,UAAU,EAAE,uBAAuB;IAEnC,4EAA4E;IAC5E,aAAa,EAAE,yBAAyB;IACxC,gBAAgB,EAAE,6BAA6B;IAC/C,WAAW,EAAE,uBAAuB;IACpC,cAAc,EAAE,2BAA2B;IAC3C,oEAAoE;IACpE,aAAa,EAAE,yBAAyB;IACxC,8EAA8E;IAC9E,kBAAkB,EAAE,+BAA+B;IACnD,mBAAmB,EAAE,iCAAiC;IACtD,iBAAiB,EAAE,6BAA6B;IAChD,WAAW,EAAE,uBAAuB;IACpC,aAAa,EAAE,0BAA0B;IACzC,wBAAwB,EAAE,qCAAqC;IAC/D,uBAAuB,EAAE,oCAAoC;IAC7D,cAAc,EAAE,2BAA2B;IAC3C,iBAAiB,EAAE,8BAA8B;IACjD,eAAe,EAAE,4BAA4B;IAC7C;;oDAEgD;IAChD,WAAW,EAAE,uBAAuB;IAEpC,4EAA4E;IAC5E,eAAe,EAAE,4BAA4B;IAC7C,gBAAgB,EAAE,6BAA6B;IAC/C,eAAe,EAAE,2BAA2B;IAC5C,mBAAmB,EAAE,gCAAgC;IACrD,uBAAuB,EAAE,oCAAoC;IAC7D,6BAA6B,EAAE,2CAA2C;IAC1E,iBAAiB,EAAE,8BAA8B;IACjD,mBAAmB,EAAE,iCAAiC;IACtD,uBAAuB,EAAE,oCAAoC;IAC7D,iBAAiB,EAAE,8BAA8B;IACjD,mBAAmB,EAAE,gCAAgC;IACrD,oBAAoB,EAAE,iCAAiC;IACvD,oBAAoB,EAAE,iCAAiC;IACvD,eAAe,EAAE,4BAA4B;IAC7C,eAAe,EAAE,4BAA4B;IAC7C,oBAAoB,EAAE,iCAAiC;IACvD,aAAa,EAAE,yBAAyB;IACxC,oBAAoB,EAAE,kCAAkC;IACxD,cAAc,EAAE,0BAA0B;IAC1C,qBAAqB,EAAE,kCAAkC;IACzD,oBAAoB,EAAE,iCAAiC;IACvD,mBAAmB,EAAE,gCAAgC;IACrD,gBAAgB,EAAE,4BAA4B;IAC9C,YAAY,EAAE,wBAAwB;IACtC,oBAAoB,EAAE,iCAAiC;IACvD,WAAW,EAAE,uBAAuB;IACpC,aAAa,EAAE,yBAAyB;IACxC,YAAY,EAAE,wBAAwB;IACtC,cAAc,EAAE,0BAA0B;IAC1C,gBAAgB,EAAE,4BAA4B;IAC9C,iBAAiB,EAAE,6BAA6B;IAChD,qBAAqB,EAAE,kCAAkC;IACzD,oBAAoB,EAAE,iCAAiC;IACvD,qBAAqB,EAAE,kCAAkC;IAEzD,4EAA4E;IAC5E,wBAAwB,EAAE,sCAAsC;IAChE,6BAA6B,EAAE,2CAA2C;IAC1E,2BAA2B,EAAE,yCAAyC;IACtE,qBAAqB,EAAE,mCAAmC;IAC1D,kBAAkB,EAAE,+BAA+B;IACnD,oBAAoB,EAAE,iCAAiC;IACvD,gCAAgC,EAAE,8CAA8C;IAEhF,4EAA4E;IAC5E,SAAS,EAAE,qBAAqB;IAChC,aAAa,EAAE,0BAA0B;IACzC,aAAa,EAAE,0BAA0B;IACzC,eAAe,EAAE,4BAA4B;IAC7C,WAAW,EAAE,uBAAuB;IACpC,cAAc,EAAE,2BAA2B;IAC3C,SAAS,EAAE,qBAAqB;IAChC,SAAS,EAAE,qBAAqB;IAChC,kBAAkB,EAAE,+BAA+B;IACnD,yEAAyE;IACzE,iBAAiB,EAAE,8BAA8B;IACjD,mBAAmB,EAAE,iCAAiC;IACtD,QAAQ,EAAE,oBAAoB;IAC9B,WAAW,EAAE,uBAAuB;IACpC,YAAY,EAAE,wBAAwB;IACtC,UAAU,EAAE,sBAAsB;IAElC,4EAA4E;IAC5E,cAAc,EAAE,0BAA0B;IAC1C,gBAAgB,EAAE,4BAA4B;IAC9C,mBAAmB,EAAE,gCAAgC;IACrD,cAAc,EAAE,0BAA0B;IAE1C,4EAA4E;IAC5E,aAAa,EAAE,0BAA0B;IACzC,YAAY,EAAE,wBAAwB;IACtC,qBAAqB,EAAE,kCAAkC;IACzD;yCACqC;IACrC,iBAAiB,EAAE,6BAA6B;IAChD,mBAAmB,EAAE,gCAAgC;IACrD,eAAe,EAAE,4BAA4B;IAE7C,4EAA4E;IAC5E,QAAQ,EAAE,oBAAoB;IAC9B,QAAQ,EAAE,oBAAoB;IAE9B,4EAA4E;IAC5E,SAAS,EAAE,qBAAqB;IAChC,UAAU,EAAE,sBAAsB;IAClC,OAAO,EAAE,mBAAmB;IAC5B,YAAY,EAAE,wBAAwB;CAC9B,CAAC;AAKX;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAA2B;IAC1D,GAAG,qBAAqB;IAExB,wBAAwB,EAAE,wCAAwC;IAElE,uBAAuB,EAAE,OAAO;IAChC,yBAAyB,EAAE,iBAAiB;IAC5C,2BAA2B,EAAE,WAAW;IACxC,wBAAwB,EAAE,QAAQ;IAClC,yBAAyB,EAAE,SAAS;IACpC,sBAAsB,EAAE,MAAM;IAC9B,0BAA0B,EAAE,UAAU;IACtC,yBAAyB,EAAE,YAAY;IACvC,0BAA0B,EAAE,UAAU;IAEtC,kCAAkC,EAChC,gEAAgE;IAClE,uCAAuC,EACrC,yFAAyF;IAC3F,qCAAqC,EACnC,gEAAgE;IAClE,kCAAkC,EAChC,6CAA6C;IAC/C,uCAAuC,EACrC,+DAA+D;IACjE,8BAA8B,EAC5B,8DAA8D;IAChE,yCAAyC,EACvC,8EAA8E;IAEhF,wBAAwB,EAAE,UAAU;IACpC,iCAAiC,EAAE,mBAAmB;IACtD,4BAA4B,EAAE,kBAAkB;IAChD,4BAA4B,EAAE,oBAAoB;IAClD,+BAA+B,EAAE,wBAAwB;IACzD,oBAAoB,EAAE,MAAM;IAC5B,uBAAuB,EAAE,SAAS;IAElC,yBAAyB,EAAE,sBAAsB;IACjD,6BAA6B,EAAE,gCAAgC;IAC/D,uBAAuB,EAAE,WAAW;IACpC,2BAA2B,EAAE,qCAAqC;IAClE,yBAAyB,EAAE,0BAA0B;IACrD,+BAA+B,EAC7B,2EAA2E;IAC7E,iCAAiC,EAC/B,iDAAiD;IACnD,6BAA6B,EAAE,aAAa;IAC5C,uBAAuB,EAAE,SAAS;IAClC,0BAA0B,EAAE,oCAAoC;IAChE,qCAAqC,EACnC,mEAAmE;IACrE,oCAAoC,EAClC,mEAAmE;IACrE,2BAA2B,EAAE,0BAA0B;IACvD,8BAA8B,EAAE,kBAAkB;IAClD,4BAA4B,EAAE,qBAAqB;IACnD,uBAAuB,EAAE,UAAU;IAEnC,4BAA4B,EAAE,aAAa;IAC3C,6BAA6B,EAAE,cAAc;IAC7C,2BAA2B,EAAE,UAAU;IACvC,gCAAgC,EAC9B,yDAAyD;IAC3D,oCAAoC,EAAE,yBAAyB;IAC/D,2CAA2C,EACzC,gEAAgE;IAClE,8BAA8B,EAAE,OAAO;IACvC,iCAAiC,EAC/B,mDAAmD;IACrD,oCAAoC,EAAE,aAAa;IACnD,8BAA8B,EAAE,OAAO;IACvC,gCAAgC,EAC9B,sDAAsD;IACxD,iCAAiC,EAAE,UAAU;IAC7C,iCAAiC,EAAE,aAAa;IAChD,4BAA4B,EAAE,UAAU;IACxC,4BAA4B,EAAE,WAAW;IACzC,iCAAiC,EAC/B,2EAA2E;IAC7E,yBAAyB,EAAE,QAAQ;IACnC,kCAAkC,EAChC,0CAA0C;IAC5C,0BAA0B,EAAE,SAAS;IACrC,kCAAkC,EAAE,sCAAsC;IAC1E,iCAAiC,EAC/B,+CAA+C;IACjD,gCAAgC,EAAE,yCAAyC;IAC3E,4BAA4B,EAAE,+BAA+B;IAC7D,wBAAwB,EAAE,UAAU;IACpC,iCAAiC,EAAE,0CAA0C;IAC7E,uBAAuB,EAAE,YAAY;IACrC,yBAAyB,EAAE,SAAS;IACpC,wBAAwB,EAAE,aAAa;IACvC,0BAA0B,EAAE,SAAS;IACrC,4BAA4B,EAAE,cAAc;IAC5C,6BAA6B,EAAE,UAAU;IACzC,kCAAkC,EAChC,gEAAgE;IAClE,iCAAiC,EAC/B,kEAAkE;IACpE,kCAAkC,EAChC,4DAA4D;IAE9D,sCAAsC,EACpC,wDAAwD;IAC1D,2CAA2C,EACzC,6GAA6G;IAC/G,yCAAyC,EACvC,yCAAyC;IAC3C,mCAAmC,EAAE,oCAAoC;IACzE,+BAA+B,EAAE,8CAA8C;IAC/E,iCAAiC,EAC/B,kCAAkC;IACpC,8CAA8C,EAC5C,4EAA4E;IAE9E,qBAAqB,EAAE,aAAa;IACpC,0BAA0B,EAAE,QAAQ;IACpC,0BAA0B,EAAE,QAAQ;IACpC,4BAA4B,EAAE,UAAU;IACxC,uBAAuB,EAAE,wBAAwB;IACjD,2BAA2B,EAAE,iCAAiC;IAC9D,qBAAqB,EAAE,kBAAkB;IACzC,qBAAqB,EAAE,WAAW;IAClC,+BAA+B,EAAE,kCAAkC;IACnE,8BAA8B,EAC5B,iIAAiI;IACnI,iCAAiC,EAC/B,iCAAiC;IACnC,oBAAoB,EAAE,MAAM;IAC5B,uBAAuB,EAAE,SAAS;IAClC,wBAAwB,EAAE,WAAW;IACrC,sBAAsB,EAAE,QAAQ;IAEhC,0BAA0B,EAAE,YAAY;IACxC,4BAA4B,EAAE,0BAA0B;IACxD,gCAAgC,EAAE,mCAAmC;IACrE,0BAA0B,EAAE,iCAAiC;IAE7D,0BAA0B,EAAE,oBAAoB;IAChD,wBAAwB,EACtB,8DAA8D;IAChE,kCAAkC,EAChC,iFAAiF;IACnF,6BAA6B,EAC3B,0DAA0D;IAC5D,gCAAgC,EAC9B,gEAAgE;IAClE,4BAA4B,EAAE,wCAAwC;IAEtE,oBAAoB,EAAE,UAAU;IAChC,oBAAoB,EAAE,MAAM;IAE5B,qBAAqB,EAAE,SAAS;IAChC,sBAAsB,EAAE,gBAAgB;IACxC,mBAAmB,EAAE,aAAa;IAClC,wBAAwB,EAAE,YAAY;CACvC,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAgB;IACnD,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,oBAAsC,CAAC,CAAC;AACpE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ru.d.ts","sourceRoot":"","sources":["../../src/i18n/ru.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAErE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,oBAAoB,EAAE,cA6KlC,CAAC;AAEF,2DAA2D;AAC3D,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAE7D"}
1
+ {"version":3,"file":"ru.d.ts","sourceRoot":"","sources":["../../src/i18n/ru.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAErE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,oBAAoB,EAAE,cA8KlC,CAAC;AAEF,2DAA2D;AAC3D,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAE7D"}
package/dist/i18n/ru.js CHANGED
@@ -66,6 +66,7 @@ export const listingsI18nBundleRu = {
66
66
  "listings.card.favorite_add": "В избранное",
67
67
  "listings.card.favorite_remove": "Убрать из избранного",
68
68
  "listings.card.open": "Открыть",
69
+ "listings.card.sign_in": "Войти",
69
70
  "listings.detail.loading": "Загружаем объявление…",
70
71
  "listings.detail.load_failed": "Не удалось загрузить объявление",
71
72
  "listings.detail.retry": "Повторить",
@@ -81,7 +82,7 @@ export const listingsI18nBundleRu = {
81
82
  "listings.detail.photo_alt": "Фото {index} из {total}",
82
83
  "listings.detail.published_at": "Опубликовано {date}",
83
84
  "listings.detail.expires_at": "В продаже до {date}",
84
- "listings.detail.stock": "В наличии: {count}",
85
+ "listings.detail.stock": "В наличии",
85
86
  "listings.compose.new_title": "Новое объявление",
86
87
  "listings.compose.edit_title": "Редактирование объявления",
87
88
  "listings.compose.category": "Категория",
@@ -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.2.0
1
+ # @stapel/listings-react 0.3.1
2
2
 
3
3
  Headless React flow pair for stapel-listings (contract >=0.6 <0.7) — 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.2.0",
4
+ "version": "0.3.1",
5
5
  "backend": {
6
6
  "module": "stapel-listings",
7
7
  "contract": ">=0.6 <0.7"
@@ -788,6 +788,7 @@
788
788
  "listings.card.open",
789
789
  "listings.card.photo_unavailable",
790
790
  "listings.card.price_absent",
791
+ "listings.card.sign_in",
791
792
  "listings.compose.auto_republish",
792
793
  "listings.compose.blocked.busy",
793
794
  "listings.compose.blocked.details_unavailable",
package/nav-manifest.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "package": "@stapel/listings-react",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
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.2.0",
3
+ "version": "0.3.1",
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": {
@@ -70,7 +70,7 @@
70
70
  ],
71
71
  "peerDependencies": {
72
72
  "@stapel/attributes-react": ">=0.1.0",
73
- "@stapel/core": ">=0.15.0 <1.0.0",
73
+ "@stapel/core": ">=0.16.0 <1.0.0",
74
74
  "@stapel/image": ">=0.2.0",
75
75
  "@stapel/tokens-antd": ">=0.5.0",
76
76
  "@tanstack/react-query": "^5.0.0",
@@ -99,8 +99,8 @@
99
99
  "typescript": "^5.8.3",
100
100
  "vitest": "^3.2.4",
101
101
  "@stapel/attributes-react": "^0.2.0",
102
- "@stapel/core": "^0.15.0",
103
- "@stapel/image": "^0.2.0",
102
+ "@stapel/core": "^0.17.0",
103
+ "@stapel/image": "^0.3.0",
104
104
  "@stapel/showcase": "^0.2.0",
105
105
  "@stapel/tokens": "^0.5.0",
106
106
  "@stapel/tokens-antd": "^0.5.0"
@@ -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.2.0",
4
+ "version": "0.3.1",
5
5
  "defined": [],
6
6
  "flows": []
7
7
  }
@@ -10,17 +10,52 @@
10
10
  import type { ReactElement } from "react";
11
11
  import { Alert, Button, Empty, Flex, Space, Spin, Typography } from "antd";
12
12
  import { matchList, useDescribeFlowError, useT } from "@stapel/core";
13
+ import type { LinkComponent } from "@stapel/core";
13
14
  import { useFavorites } from "../headless/Favorites.js";
14
15
  import { LISTINGS_I18N_KEYS } from "../i18n/keys.js";
15
16
  import { ErrorAlert } from "./ErrorAlert.js";
16
17
  import { ListingCard } from "./ListingCard.js";
18
+ import type { ListingCardOpenProps } from "./ListingCard.js";
17
19
  import { ListingsSkinTheme } from "./theme.js";
18
20
  import type { ThemeModeProp } from "./types.js";
19
21
 
20
- export interface FavoritesPaneProps extends ThemeModeProp {
21
- /** Where a card leads. The container owns routing. */
22
- readonly hrefFor?: (id: number) => string;
23
- readonly onOpen?: (id: number) => void;
22
+ /** How a card in this grid opens — the same one-contract union `<ListingCard>`
23
+ * takes, one level up, so a pane cannot re-introduce the double navigation the
24
+ * card no longer allows. */
25
+ export type FavoritesPaneOpenProps =
26
+ | {
27
+ /** Where a card leads. The container owns routing. */
28
+ readonly hrefFor: (id: number) => string;
29
+ /** The host's `<Link>`, so a click stays inside the SPA. */
30
+ readonly linkComponent?: LinkComponent;
31
+ readonly onOpen?: undefined;
32
+ }
33
+ | {
34
+ readonly onOpen: (id: number) => void;
35
+ readonly hrefFor?: undefined;
36
+ readonly linkComponent?: undefined;
37
+ }
38
+ | {
39
+ readonly hrefFor?: undefined;
40
+ readonly onOpen?: undefined;
41
+ readonly linkComponent?: undefined;
42
+ };
43
+
44
+ export type FavoritesPaneProps = ThemeModeProp & FavoritesPaneOpenProps;
45
+
46
+ /** The card's own open props for one row. One arm, never two. */
47
+ function cardOpenProps(
48
+ props: FavoritesPaneOpenProps,
49
+ id: number
50
+ ): ListingCardOpenProps {
51
+ if (props.hrefFor !== undefined) {
52
+ const href = props.hrefFor(id);
53
+ return props.linkComponent !== undefined
54
+ ? { href, linkComponent: props.linkComponent }
55
+ : { href };
56
+ }
57
+ if (props.onOpen !== undefined) return { onOpen: props.onOpen };
58
+ return {};
24
59
  }
25
60
 
26
61
  export function FavoritesPane(props: FavoritesPaneProps): ReactElement {
@@ -82,13 +117,7 @@ export function FavoritesPane(props: FavoritesPaneProps): ReactElement {
82
117
  <Flex wrap gap={16} data-testid="listings-favorites-grid">
83
118
  {rows.map((row) => (
84
119
  <div key={row.id} style={{ width: 240 }}>
85
- <ListingCard
86
- listing={row}
87
- {...(props.hrefFor !== undefined
88
- ? { href: props.hrefFor(row.id) }
89
- : {})}
90
- {...(props.onOpen !== undefined ? { onOpen: props.onOpen } : {})}
91
- />
120
+ <ListingCard listing={row} {...cardOpenProps(props, row.id)} />
92
121
  </div>
93
122
  ))}
94
123
  </Flex>
@@ -4,7 +4,15 @@
4
4
  * `@stapel/search-react` takes a `renderCard` slot and the container fills it
5
5
  * with this (spec §3.7 / §6.2 item 1). The two pairs never import each other;
6
6
  * the CONTAINER is the seam, which is why this component takes a plain card
7
- * row and a plain `href`/`onOpen` rather than reaching for a router.
7
+ * row and a plain `href` rather than reaching for a router.
8
+ *
9
+ * ── One click, one navigation ──────────────────────────────────────────────
10
+ *
11
+ * `href` and `onOpen` used to be two optional props, and a card given both
12
+ * navigated TWICE: the handler ran, and the browser then followed the anchor
13
+ * that was still on the button. They are now three arms of a union — link,
14
+ * button, or neither — and `linkComponent` rides on the link arm so a
15
+ * container can hand in its router's `<Link>` and keep the anchor.
8
16
  *
9
17
  * ── What it renders without asking the server anything else ────────────────
10
18
  *
@@ -16,13 +24,17 @@
16
24
  *
17
25
  * ── The heart is never hidden ──────────────────────────────────────────────
18
26
  *
19
- * A visitor sees it, blocked, with the reason and the sign-in CTA the
20
- * container attaches (`?next=`). Hiding it would teach nobody that
21
- * favourites exist (private-space canon §6.3, spec §6.2 item 6).
27
+ * A visitor sees it, blocked, with the reason IN WORDS beside it and the
28
+ * sign-in link the container supplies (`signIn`, typically `?next=<current>`).
29
+ * 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.
22
33
  */
23
34
  import type { ReactElement, ReactNode } from "react";
24
35
  import { Button, Card, Flex, Tooltip, Typography } from "antd";
25
- import { useT } from "@stapel/core";
36
+ import { useActionGate, useT } from "@stapel/core";
37
+ import type { LinkComponent, SignInCtaProp } from "@stapel/core";
26
38
  import { FeatureBadges } from "@stapel/attributes-react/default";
27
39
  import type { ListingCard as ListingCardData } from "../api/types.js";
28
40
  import { asFeatureDaoList, featuresDtoFromDaoList, featuresFromDaoList } from "../model/features.js";
@@ -30,18 +42,53 @@ import { lifecycleCaption } from "../model/status.js";
30
42
  import { useFavoriteToggle } from "../headless/Favorites.js";
31
43
  import { LISTINGS_I18N_KEYS } from "../i18n/keys.js";
32
44
  import { HeartIcon } from "./icons.js";
45
+ import { SignInLink } from "./SignInLink.js";
33
46
  import { ListingPhoto } from "./ListingPhoto.js";
34
47
  import { ListingsSkinTheme } from "./theme.js";
35
48
  import type { ThemeModeProp } from "./types.js";
36
49
 
37
- export interface ListingCardProps extends ThemeModeProp {
50
+ /**
51
+ * How the card opens — ONE of three, and the type says so.
52
+ *
53
+ * It used to be two optional props, and a caller that passed both got two
54
+ * navigations for one click: the handler ran and the browser then followed the
55
+ * anchor anyway. The storefront worked around it by passing `onOpen` only,
56
+ * which cost it a real anchor (no middle-click, no "open in new tab", nothing
57
+ * for a crawler to follow) on the most linkable element in the app.
58
+ *
59
+ * So the union has three arms and no fourth: a link, a button, or neither.
60
+ * `linkComponent` belongs to the link arm because it IS the link — handing a
61
+ * `<Link>` to a card that navigates by callback would be two answers to one
62
+ * question again.
63
+ */
64
+ export type ListingCardOpenProps =
65
+ | {
66
+ /** Where the card leads. A plain path — the pair never calls
67
+ * `window.location` and never builds a router descriptor. */
68
+ readonly href: string;
69
+ /** The host's `<Link>`, so the click stays inside the SPA. Absent: an
70
+ * antd link-button carrying the `href`, which reloads the page in a
71
+ * router app — correct, just not fast. */
72
+ readonly linkComponent?: LinkComponent;
73
+ readonly onOpen?: undefined;
74
+ }
75
+ | {
76
+ /** The card opens by callback: rendered as a button, with no `href` for
77
+ * the browser to follow after the handler has already navigated. */
78
+ readonly onOpen: (id: number) => void;
79
+ readonly href?: undefined;
80
+ readonly linkComponent?: undefined;
81
+ }
82
+ | {
83
+ /** No open control at all — a card inside a screen that is already the
84
+ * listing. */
85
+ readonly href?: undefined;
86
+ readonly onOpen?: undefined;
87
+ readonly linkComponent?: undefined;
88
+ };
89
+
90
+ export interface ListingCardBaseProps extends ThemeModeProp, SignInCtaProp {
38
91
  readonly listing: ListingCardData;
39
- /** Where the card leads. The container owns routing, so this is a plain
40
- * href a `<Link>` or an `<a>` can carry — the pair never calls
41
- * `window.location`. */
42
- readonly href?: string;
43
- /** Called instead of following `href`, for a host with its own navigation. */
44
- readonly onOpen?: (id: number) => void;
45
92
  /** Extra chrome the container adds (a `promoted` tag from search, say —
46
93
  * DSA Art. 26 marking belongs to the pair that receives it). */
47
94
  readonly badge?: ReactNode;
@@ -50,6 +97,73 @@ export interface ListingCardProps extends ThemeModeProp {
50
97
  readonly showFavorite?: boolean;
51
98
  }
52
99
 
100
+ export type ListingCardProps = ListingCardBaseProps & ListingCardOpenProps;
101
+
102
+ /**
103
+ * The one control that opens the card: an anchor, a button, or nothing.
104
+ *
105
+ * Exactly one of the three renders, so exactly one navigation happens per
106
+ * click. That is the whole fix — the branch below has no arm in which both a
107
+ * handler and an `href` reach the DOM.
108
+ */
109
+ function OpenControl(
110
+ props: ListingCardOpenProps & { readonly listingId: number }
111
+ ): ReactElement | null {
112
+ const t = useT();
113
+ const label = t(LISTINGS_I18N_KEYS.cardOpen);
114
+
115
+ if (props.href !== undefined) {
116
+ const Link = props.linkComponent;
117
+ // The host's component is rendered as it comes: this pair has no CSS and
118
+ // no way to hand antd's button styling to a foreign element, and a wrapper
119
+ // element around a link is a click target that is not the link. A host
120
+ // that wants the antd look styles its own `<Link>` — it is one component,
121
+ // written once, and it is already the thing that knows the design system.
122
+ return Link !== undefined ? (
123
+ <Link
124
+ href={props.href}
125
+ aria-label={label}
126
+ data-testid="listings-card-open"
127
+ data-analytics="none"
128
+ data-analytics-reason="business action — host app wraps with its own tracked()"
129
+ >
130
+ {label}
131
+ </Link>
132
+ ) : (
133
+ <Button
134
+ size="small"
135
+ type="link"
136
+ href={props.href}
137
+ data-testid="listings-card-open"
138
+ data-analytics="none"
139
+ data-analytics-reason="business action — host app wraps with its own tracked()"
140
+ >
141
+ {label}
142
+ </Button>
143
+ );
144
+ }
145
+
146
+ if (props.onOpen !== undefined) {
147
+ const onOpen = props.onOpen;
148
+ return (
149
+ <Button
150
+ size="small"
151
+ type="link"
152
+ data-testid="listings-card-open"
153
+ data-analytics="none"
154
+ data-analytics-reason="business action — host app wraps with its own tracked()"
155
+ onClick={() => {
156
+ onOpen(props.listingId);
157
+ }}
158
+ >
159
+ {label}
160
+ </Button>
161
+ );
162
+ }
163
+
164
+ return null;
165
+ }
166
+
53
167
  export function ListingCard(props: ListingCardProps): ReactElement {
54
168
  const t = useT();
55
169
  const { listing } = props;
@@ -66,6 +180,8 @@ export function ListingCard(props: ListingCardProps): ReactElement {
66
180
  ? `${listing.price} ${listing.currency ?? ""}`.trim()
67
181
  : t(LISTINGS_I18N_KEYS.cardPriceAbsent);
68
182
 
183
+ const favoriteGate = useActionGate(favorite.gate);
184
+
69
185
  const favoriteLabel = t(
70
186
  favorite.favorited
71
187
  ? LISTINGS_I18N_KEYS.cardFavoriteRemove
@@ -127,21 +243,7 @@ export function ListingCard(props: ListingCardProps): ReactElement {
127
243
  ) : null}
128
244
 
129
245
  <Flex gap={8} align="center">
130
- {props.href !== undefined || props.onOpen !== undefined ? (
131
- <Button
132
- size="small"
133
- type="link"
134
- {...(props.href !== undefined ? { href: props.href } : {})}
135
- data-testid="listings-card-open"
136
- data-analytics="none"
137
- data-analytics-reason="business action — host app wraps with its own tracked()"
138
- onClick={() => {
139
- props.onOpen?.(listing.id);
140
- }}
141
- >
142
- {t(LISTINGS_I18N_KEYS.cardOpen)}
143
- </Button>
144
- ) : null}
246
+ <OpenControl {...props} listingId={listing.id} />
145
247
 
146
248
  {props.showFavorite === false ? null : (
147
249
  <Tooltip
@@ -171,6 +273,21 @@ export function ListingCard(props: ListingCardProps): ReactElement {
171
273
  </Tooltip>
172
274
  )}
173
275
  </Flex>
276
+
277
+ {/* The reason IN WORDS, plus the door. A tooltip on a disabled
278
+ button is a reason nobody can read (core's actionGate.ts says so
279
+ in as many words), and a reason with no next action leaves the
280
+ visitor hunting for the header — which is what the storefront
281
+ had to write a paragraph about instead of shipping the screen. */}
282
+ {props.showFavorite === false || favoriteGate.reason === undefined ? null : (
283
+ <Typography.Text
284
+ type="secondary"
285
+ data-testid="listings-card-favorite-blocked"
286
+ >
287
+ {favoriteGate.reason}
288
+ <SignInLink cta={props.signIn} testId="listings-card-sign-in" />
289
+ </Typography.Text>
290
+ )}
174
291
  </Flex>
175
292
  </Card>
176
293
  </ListingsSkinTheme>
@@ -5,12 +5,29 @@
5
5
  * the component can be read top to bottom without knowing any of the other
6
6
  * pairs:
7
7
  *
8
- * category `categorySlot` — the container's `<CategoryPickerField>`
8
+ * category `renderCategoryPicker` — the container's `<CategoryPickerField>`,
9
+ * given `setCategory` to call
9
10
  * details `features` — the schema, drawn by `<FeatureFields>` (L0)
10
- * photos `gallerySlot` — the container's `<MediaGalleryField>`, whose
11
- * bag is handed to the composer as `images`
11
+ * photos `gallerySlot` — the container's `<MediaGalleryField bag>`,
12
+ * whose bag is handed here as `images`
12
13
  * the draft this pair
13
14
  *
15
+ * ── Why the category slot is a render prop and not a node ──────────────────
16
+ *
17
+ * It was a node (`categorySlot`), and a node cannot be mounted: the composer's
18
+ * category moves only through `bag.setCategory`, and a `ReactNode` handed in
19
+ * from outside has no way to reach it. There was no `onCategoryChange`either,
20
+ * so a container could neither set the category nor learn it — and `features`,
21
+ * the schema of the chosen category, was therefore unreachable rather than
22
+ * merely withheld. The screen could not be mounted at all (storefront Wave D,
23
+ * named gap G-1).
24
+ *
25
+ * `renderCategoryPicker({ value, setCategory })` is the shape
26
+ * `<CategoryPage renderListings>` already uses in the sibling pair, and the
27
+ * controlled pair `category` / `onCategoryChange` is there for the container
28
+ * that holds the id anyway — it must, because the schema read
29
+ * (`useCategoryFeatures(id)`) that fills `features` is keyed by it.
30
+ *
14
31
  * ── Every blocked control says which of six reasons it is ──────────────────
15
32
  *
16
33
  * The publish button is the most-gated control in the fleet, and that is the
@@ -55,6 +72,19 @@ import { ErrorAlert } from "./ErrorAlert.js";
55
72
  import { ListingsSkinTheme } from "./theme.js";
56
73
  import type { ThemeModeProp } from "./types.js";
57
74
 
75
+ /**
76
+ * What `renderCategoryPicker` is handed: the current category and the ONLY
77
+ * function that changes it. Same shape as any other bag in this monorepo — the
78
+ * value plus the setter, never a setter alone.
79
+ */
80
+ export interface ComposerCategorySlot {
81
+ /** The category the draft currently carries. Empty string: none chosen. */
82
+ readonly value: string;
83
+ /** Choose a category. Prunes the answers the new schema does not ask for
84
+ * (one render later, once `features` arrives) and reports upwards. */
85
+ readonly setCategory: (categoryId: string) => void;
86
+ }
87
+
58
88
  export interface ListingComposerPageProps extends ThemeModeProp {
59
89
  /** Editing an existing listing; absent for a new one. */
60
90
  readonly listingId?: number;
@@ -63,7 +93,33 @@ export interface ListingComposerPageProps extends ThemeModeProp {
63
93
  readonly features: readonly FeatureDef[];
64
94
  readonly featuresLoading?: boolean;
65
95
  readonly featuresError?: unknown;
66
- /** The category chooser. A slot for the same reason. */
96
+ /**
97
+ * The category chooser, handed the value and the setter. This is the slot a
98
+ * container fills with `@stapel/categories-react`'s `<CategoryPickerField>`:
99
+ *
100
+ * ```tsx
101
+ * renderCategoryPicker={({ value, setCategory }) => (
102
+ * <CategoryPickerField
103
+ * value={value === "" ? null : Number(value)}
104
+ * onChange={(id) => setCategory(id === null ? "" : String(id))}
105
+ * />
106
+ * )}
107
+ * ```
108
+ */
109
+ readonly renderCategoryPicker?: (slot: ComposerCategorySlot) => ReactNode;
110
+ /**
111
+ * The chosen category, when the container owns that state — the usual case,
112
+ * since the same id keys the `features` read.
113
+ */
114
+ readonly category?: string;
115
+ /** Called whenever the category changes, controlled or not. */
116
+ readonly onCategoryChange?: (categoryId: string) => void;
117
+ /**
118
+ * @deprecated A node cannot reach `setCategory`, so a picker rendered into
119
+ * this slot could never tell the composer what was chosen. Use
120
+ * `renderCategoryPicker` (or the controlled `category` /
121
+ * `onCategoryChange` pair). Still rendered, so nothing that passed it breaks.
122
+ */
67
123
  readonly categorySlot?: ReactNode;
68
124
  /** The photo grid. Its bag is what `images` carries. */
69
125
  readonly gallerySlot?: ReactNode;
@@ -89,6 +145,10 @@ export function ListingComposerPage(
89
145
  : {}),
90
146
  editorTypes: BUILTIN_VALUE_EDITOR_TYPES,
91
147
  ...(props.images !== undefined ? { images: props.images } : {}),
148
+ ...(props.category !== undefined ? { category: props.category } : {}),
149
+ ...(props.onCategoryChange !== undefined
150
+ ? { onCategoryChange: props.onCategoryChange }
151
+ : {}),
92
152
  ...(props.onPublished !== undefined
93
153
  ? {
94
154
  // `listing_id` comes back in the response, so the callback never
@@ -160,16 +220,21 @@ export function ListingComposerPage(
160
220
  extra={t(LISTINGS_I18N_KEYS.composeCategoryHelp)}
161
221
  {...errorOf(CATEGORY_FIELD)}
162
222
  >
163
- {props.categorySlot ?? (
164
- <Input
165
- value={bag.values.categoryId}
166
- aria-label={t(LISTINGS_I18N_KEYS.composeCategory)}
167
- data-testid="listings-composer-category"
168
- onChange={(event) => {
169
- bag.setCategory(event.target.value);
170
- }}
171
- />
172
- )}
223
+ {props.renderCategoryPicker !== undefined
224
+ ? props.renderCategoryPicker({
225
+ value: bag.values.categoryId,
226
+ setCategory: bag.setCategory,
227
+ })
228
+ : (props.categorySlot ?? (
229
+ <Input
230
+ value={bag.values.categoryId}
231
+ aria-label={t(LISTINGS_I18N_KEYS.composeCategory)}
232
+ data-testid="listings-composer-category"
233
+ onChange={(event) => {
234
+ bag.setCategory(event.target.value);
235
+ }}
236
+ />
237
+ ))}
173
238
  </Form.Item>
174
239
 
175
240
  {bag.droppedOnCategoryChange.length > 0 ? (
@@ -246,9 +246,14 @@ export function ListingDetailPane(props: ListingDetailPaneProps): ReactElement {
246
246
  ) : null}
247
247
 
248
248
  <Descriptions size="small" column={1}>
249
+ {/* Label cell and value cell, which is what a `<Descriptions>`
250
+ row IS: the label key carries no `{count}` (it did, and the
251
+ page printed the placeholder), the quantity is the value. */}
249
252
  {listing.stock_quantity != null ? (
250
253
  <Descriptions.Item label={t(LISTINGS_I18N_KEYS.detailStock)}>
251
- {listing.stock_quantity}
254
+ <span data-testid="listings-detail-stock">
255
+ {listing.stock_quantity}
256
+ </span>
252
257
  </Descriptions.Item>
253
258
  ) : null}
254
259
  {listing.location_label !== undefined &&