@reblu/site-blocks 0.5.0 → 0.6.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # @reblu/site-blocks
2
2
 
3
+ ## 0.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 74a94ff: Add cart + checkout presentational organisms (REB-829): `AddToCartButton`,
8
+ `CartIcon`, `CartLineList`, `CartSummary`, `CheckoutLoginPrompt`,
9
+ `CheckoutForm`, `OrderConfirmation`. Same container/presentational split as
10
+ `ShopFilters` — data + optional callbacks in, no fetching, RSC-safe by
11
+ construction (callbacks only do anything when supplied from a Client
12
+ Component). Spanish-neutral default labels, all overridable via props. Wire
13
+ them to `@reblu/site-next/cart`'s `useCart()` and the
14
+ `./shop-route-handlers`/`./shop-server` Route Handlers and server helper.
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies [74a94ff]
19
+ - @reblu/site-contracts@1.5.0
20
+
21
+ ## 0.5.1
22
+
23
+ ### Patch Changes
24
+
25
+ - 75d3963: Fix `ShopFilters` stranding an active price filter when the price range
26
+ collapses (REB-827). The Price fieldset previously rendered only when
27
+ `facets.price.max > facets.price.min`; an active price band can itself
28
+ collapse that range to a single value (or every currently filtered product
29
+ can simply cost the same), which made the whole Price group — including the
30
+ active band's own click-to-clear affordance — disappear, leaving "Clear
31
+ filters" as the only way out. The group now also renders whenever
32
+ `active.priceMin`/`active.priceMax` is set, matching the same rule every
33
+ taxonomy axis already follows, and `shouldRenderShopFilters` stays consistent
34
+ with it (it already accounted for an active price selection via
35
+ `hasAnyActiveFilter`).
36
+ - Updated dependencies [87b7fa0]
37
+ - @reblu/site-contracts@1.4.0
38
+
3
39
  ## 0.5.0
4
40
 
5
41
  ### Minor Changes
package/README.md CHANGED
@@ -17,6 +17,7 @@ a different-looking site for every tenant, with zero forks.
17
17
  | `MarkdownRenderer` | `.` | Canonical Blog renderer: `marked` → **hast-util-sanitize** (XSS) → component map, with a YouTube-domain allowlist. RSC-safe. |
18
18
  | `Treatment`, `Specialty`, `ProfileCard`, `ProductCard` | `.` | Presentational organisms over the SITE API contracts. RSC-safe. |
19
19
  | `ShopFilters` | `.` | Plug-and-play shop filter chrome over `GET /api/site/shop/facets`. RSC-safe. See "Shop filters" below. |
20
+ | `AddToCartButton`, `CartIcon`, `CartLineList`, `CartSummary`, `CheckoutLoginPrompt`, `CheckoutForm`, `OrderConfirmation` | `.` | Cart & checkout organisms. RSC-safe by construction. See "Cart & checkout" below. |
20
21
  | `useCollection` | `./client` | Headless filterable/sortable/paginated collection hook (facets, category, tag, search). Serves both page and blog indexes. |
21
22
  | `Collection` | `./client` | Token-driven presentational grid over `useCollection`. |
22
23
  | `ShareButtons` | `./client` | Social share (X / LinkedIn / WhatsApp / copy). |
@@ -181,6 +182,48 @@ has a selection to clear (an active filter can legitimately collapse every
181
182
  facet option to zero; the component still renders "Clear filters" then,
182
183
  never stranding the visitor with no way back).
183
184
 
185
+ ## Cart & checkout
186
+
187
+ Seven organisms over the cart/checkout flow (REB-829), all presentational —
188
+ data + optional callbacks in, no fetching, no cart/zustand dependency of
189
+ their own. Wire them to `@reblu/site-next/cart`'s `useCart()` and the
190
+ `./shop-route-handlers` Route Handlers (see that package's README for the
191
+ wiring steps and a full example app).
192
+
193
+ | Component | Props it needs | RSC-safe without callbacks? |
194
+ | --------- | --------------- | ---------------------------- |
195
+ | `AddToCartButton` | `onAddToCart?`, `disabled?`, `outOfStock?`, `pending?` | Yes |
196
+ | `CartIcon` | `itemCount`, `href` | Yes |
197
+ | `CartLineList` | `items`, `onQuantityChange?`, `onRemove?`, `liveMessage?` | Yes |
198
+ | `CartSummary` | `subtotal`, `discount?`, `shipping?`, `shippingEnabled?`, `total` | Yes |
199
+ | `CheckoutLoginPrompt` | `open`, `email`, `onEmailChange`, `onClose`, `onSubmitEmail`, `onContinueAsGuest` | Yes (renders `null` when `open` is false) |
200
+ | `CheckoutForm` | `contact`, `onContactChange`, `discountCode`, `onDiscountCodeChange`, `onApplyDiscount`, `onRemoveDiscount`, `onSubmit` | Yes |
201
+ | `OrderConfirmation` | `status` (`'polling' \| 'found' \| 'timeout'`), `order` | Yes |
202
+
203
+ Same RSC-safety contract as `ShopFilters`'s `OptionLink`: none of these
204
+ components carry `'use client'` themselves — a Server Component may render
205
+ any of them read-only (omit the callback props), and a Client Component
206
+ wires the callbacks to real state/mutations. All labels default to
207
+ Spanish-neutral copy and are overridable via each component's `labels` prop.
208
+
209
+ `CartLineList`'s `liveMessage` prop renders inside a visually-hidden
210
+ `aria-live="polite"` region — the consuming SITE sets it (e.g. "Cantidad
211
+ actualizada", "Producto eliminado") after a successful mutation; the
212
+ component only renders the live region, it never decides when to announce.
213
+
214
+ `CheckoutForm` intentionally does NOT collect shipping/billing addresses —
215
+ those field sets vary by tenant shop config far more than the guest-email +
216
+ discount-code flow. Render them via `CheckoutForm`'s `children` slot
217
+ (rendered between the contact and discount sections) if your shop has
218
+ shipping enabled.
219
+
220
+ `validate-cart`'s rejection path (out-of-stock, price-changed, empty cart)
221
+ surfaces through `CheckoutForm`'s own error-display conventions: pass the
222
+ first `ShopCartValidationError.message` from `client.shop.validateCart(...)`
223
+ as a toast/banner in your page (the component itself has no cart-wide error
224
+ slot — it only owns contact/discount field-level errors via `contactErrors`/
225
+ `discountError`).
226
+
184
227
  ## Security boundaries
185
228
 
186
229
  Two sinks, two different helpers, in two different packages — do not reach for