@thorprovider/blocks 0.1.1 → 0.1.3

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 (70) hide show
  1. package/.turbo/turbo-build.log +15 -15
  2. package/.turbo/turbo-test.log +42 -5
  3. package/AGENTS.md +1 -1
  4. package/README.md +94 -1
  5. package/dist/.tsbuildinfo +1 -1
  6. package/dist/contracts.d.mts +1266 -97
  7. package/dist/contracts.d.ts +1266 -97
  8. package/dist/contracts.js +225 -9
  9. package/dist/contracts.js.map +1 -1
  10. package/dist/contracts.mjs +207 -10
  11. package/dist/contracts.mjs.map +1 -1
  12. package/dist/index.d.mts +756 -96
  13. package/dist/index.d.ts +756 -96
  14. package/dist/index.js +5114 -3702
  15. package/dist/index.js.map +1 -1
  16. package/dist/index.mjs +4939 -3551
  17. package/dist/index.mjs.map +1 -1
  18. package/docs/standards/theming.md +32 -5
  19. package/package.json +2 -2
  20. package/src/blocks/e-commerce/category-filters/category-filter-2-filter-panel.tsx +136 -93
  21. package/src/blocks/e-commerce/category-filters/category-filter-2.test.tsx +513 -0
  22. package/src/blocks/e-commerce/category-filters/category-filter-2.tsx +728 -148
  23. package/src/blocks/e-commerce/checkout-forms/checkout-confirmation-fulfilment-progress.tsx +14 -8
  24. package/src/blocks/e-commerce/checkout-forms/checkout-confirmation.test.tsx +136 -0
  25. package/src/blocks/e-commerce/checkout-forms/checkout-confirmation.tsx +145 -99
  26. package/src/blocks/e-commerce/checkout-forms/checkout-form-1-order-summary.tsx +215 -102
  27. package/src/blocks/e-commerce/checkout-forms/checkout-form-1-payment-step.tsx +6 -2
  28. package/src/blocks/e-commerce/checkout-forms/checkout-form-1-shipping-step.tsx +51 -2
  29. package/src/blocks/e-commerce/checkout-forms/checkout-form-1.test.tsx +216 -0
  30. package/src/blocks/e-commerce/checkout-forms/checkout-form-1.tsx +114 -11
  31. package/src/blocks/e-commerce/navigation/back-to-top.test.tsx +27 -0
  32. package/src/blocks/e-commerce/navigation/back-to-top.tsx +71 -0
  33. package/src/blocks/e-commerce/navigation/breadcrumb.test.tsx +174 -0
  34. package/src/blocks/e-commerce/navigation/breadcrumb.tsx +130 -0
  35. package/src/blocks/e-commerce/navigation/mobile-bottom-nav.test.tsx +74 -0
  36. package/src/blocks/e-commerce/navigation/mobile-bottom-nav.tsx +78 -0
  37. package/src/blocks/e-commerce/navigation/mobile-category-drawer.test.tsx +42 -2
  38. package/src/blocks/e-commerce/navigation/mobile-category-drawer.tsx +10 -8
  39. package/src/blocks/e-commerce/navigation/skip-to-content.test.tsx +35 -0
  40. package/src/blocks/e-commerce/navigation/skip-to-content.tsx +37 -0
  41. package/src/blocks/e-commerce/product-categories/product-category-2.test.tsx +51 -0
  42. package/src/blocks/e-commerce/product-categories/product-category-2.tsx +56 -36
  43. package/src/blocks/e-commerce/product-list/product-card-1.test.tsx +88 -0
  44. package/src/blocks/e-commerce/product-list/product-card-1.tsx +141 -80
  45. package/src/blocks/e-commerce/product-list/product-showcase-1.test.tsx +78 -0
  46. package/src/blocks/e-commerce/product-list/product-showcase-1.tsx +277 -0
  47. package/src/blocks/e-commerce/product-overview/product-overview-1.test.tsx +182 -0
  48. package/src/blocks/e-commerce/product-overview/product-overview-1.tsx +298 -129
  49. package/src/blocks/e-commerce/shopping-carts/shopping-cart-4.test.tsx +229 -0
  50. package/src/blocks/e-commerce/shopping-carts/shopping-cart-4.tsx +313 -110
  51. package/src/blocks/e-commerce/storefront-hero/storefront-hero-1.test.tsx +72 -0
  52. package/src/blocks/e-commerce/storefront-hero/storefront-hero-1.tsx +20 -1
  53. package/src/blocks/marketing/footers/footer-section-1.test.tsx +117 -0
  54. package/src/blocks/marketing/footers/footer-section-1.tsx +46 -9
  55. package/src/blocks/marketing/navbars/navbar-4-account-menu.test.tsx +38 -0
  56. package/src/blocks/marketing/navbars/navbar-4-account-menu.tsx +30 -14
  57. package/src/blocks/marketing/navbars/navbar-4-cart-sheet.test.tsx +204 -0
  58. package/src/blocks/marketing/navbars/navbar-4-cart-sheet.tsx +144 -21
  59. package/src/blocks/marketing/navbars/navbar-4.test.tsx +233 -0
  60. package/src/blocks/marketing/navbars/navbar-4.tsx +235 -60
  61. package/src/index.ts +56 -0
  62. package/src/lib/cart.test.ts +15 -0
  63. package/src/lib/cart.ts +11 -0
  64. package/src/lib/contracts-curated.test.ts +207 -0
  65. package/src/lib/contracts-server-boundary.test.ts +52 -0
  66. package/src/lib/contracts.ts +234 -6
  67. package/src/lib/money.test.ts +64 -0
  68. package/src/lib/money.ts +65 -0
  69. package/tsup.config.ts +0 -1
  70. package/vitest.config.ts +9 -1
@@ -6,19 +6,19 @@ CLI Target: esnext
6
6
  CLI Cleaning output folder
7
7
  CJS Build start
8
8
  ESM Build start
9
- CJS dist/contracts.js 8.15 KB
10
- CJS dist/index.js 801.34 KB
11
- CJS dist/contracts.js.map 12.65 KB
12
- CJS dist/index.js.map 1.13 MB
13
- CJS ⚡️ Build success in 801ms
14
- ESM dist/contracts.mjs 5.12 KB
15
- ESM dist/index.mjs 708.79 KB
16
- ESM dist/contracts.mjs.map 12.54 KB
17
- ESM dist/index.mjs.map 1.14 MB
18
- ESM ⚡️ Build success in 815ms
9
+ ESM dist/contracts.mjs 11.75 KB
10
+ ESM dist/index.mjs 778.08 KB
11
+ ESM dist/contracts.mjs.map 29.49 KB
12
+ ESM dist/index.mjs.map 1.29 MB
13
+ ESM ⚡️ Build success in 228ms
14
+ CJS dist/contracts.js 16.83 KB
15
+ CJS dist/index.js 878.89 KB
16
+ CJS dist/contracts.js.map 29.69 KB
17
+ CJS dist/index.js.map 1.27 MB
18
+ CJS ⚡️ Build success in 229ms
19
19
  DTS Build start
20
- DTS ⚡️ Build success in 17297ms
21
- DTS dist/index.d.ts 86.38 KB
22
- DTS dist/contracts.d.ts 17.94 KB
23
- DTS dist/index.d.mts 86.38 KB
24
- DTS dist/contracts.d.mts 17.94 KB
20
+ DTS ⚡️ Build success in 10197ms
21
+ DTS dist/index.d.ts 120.86 KB
22
+ DTS dist/contracts.d.ts 57.89 KB
23
+ DTS dist/index.d.mts 120.86 KB
24
+ DTS dist/contracts.d.mts 57.89 KB
@@ -1,10 +1,47 @@
1
1
 
2
2
  RUN v3.2.4 /home/nelson/dev/active/thorprovider/repos/thorcommerce/packages/blocks
3
3
 
4
- ✓ src/blocks/e-commerce/checkout-forms/card-formatting.test.ts (10 tests) 14ms
4
+ ✓ src/blocks/e-commerce/navigation/mega-menu.test.tsx (9 tests) 1189ms
5
+ ✓ MegaMenu > renders category columns from the categories prop 627ms
6
+ ✓ src/blocks/e-commerce/navigation/mobile-category-drawer.test.tsx (12 tests) 1191ms
7
+ ✓ MobileCategoryDrawer > keeps the drawer mounted off-screen with aria-hidden when closed 728ms
8
+ ✓ src/blocks/e-commerce/product-categories/product-category-2.test.tsx (5 tests) 329ms
9
+ stderr | src/blocks/e-commerce/checkout-forms/checkout-form-1.test.tsx > CheckoutForm1 payment step — launch flow collects no raw card data > renders card fields only in the explicit legacy mode
10
+ Received `true` for a non-boolean attribute `inline-end`.
5
11
 
6
- Test Files 1 passed (1)
7
- Tests 10 passed (10)
8
- Start at 16:54:02
9
- Duration 1.03s (transform 162ms, setup 0ms, collect 93ms, tests 14ms, environment 0ms, prepare 252ms)
12
+ If you want to write it to the DOM, pass a string instead: inline-end="true" or inline-end={value.toString()}.
13
+
14
+ ✓ src/blocks/e-commerce/checkout-forms/checkout-form-1.test.tsx (10 tests) 337ms
15
+ ✓ src/blocks/e-commerce/checkout-forms/checkout-confirmation.test.tsx (7 tests) 567ms
16
+ ✓ src/blocks/marketing/footers/footer-section-1.test.tsx (9 tests) 208ms
17
+ ✓ src/blocks/e-commerce/shopping-carts/shopping-cart-4.test.tsx (17 tests) 704ms
18
+ ✓ src/blocks/e-commerce/product-list/product-card-1.test.tsx (8 tests) 855ms
19
+ ✓ src/blocks/marketing/navbars/navbar-4-cart-sheet.test.tsx (15 tests) 583ms
20
+ ✓ Navbar4CartSheet — authoritative subtotal > never renders a fake zero for a supplied but absent/malformed subtotal 430ms
21
+ ✓ src/blocks/e-commerce/navigation/skip-to-content.test.tsx (5 tests) 52ms
22
+ ✓ src/blocks/marketing/navbars/navbar-4.test.tsx (19 tests) 851ms
23
+ ✓ src/lib/money.test.ts (10 tests) 473ms
24
+ ✓ formatMoney > uses the money currency rather than a hardcoded one 371ms
25
+ ✓ src/lib/contracts-server-boundary.test.ts (3 tests) 92ms
26
+ ✓ src/blocks/e-commerce/navigation/mobile-bottom-nav.test.tsx (7 tests) 446ms
27
+ ✓ src/blocks/e-commerce/category-filters/category-filter-2.test.tsx (39 tests) 2736ms
28
+ ✓ CategoryFilter2 — controlled canonical query > renders the query-selected search, category, sort and page values 428ms
29
+ ✓ CategoryFilter2 — controlled canonical query > renders collection controls when collections are supplied 354ms
30
+ ✓ CategoryFilter2 — no fabricated price or sort choices > omits the price control without a real backend range 301ms
31
+ ✓ src/blocks/e-commerce/navigation/category-icon.test.tsx (7 tests) 584ms
32
+ ✓ src/blocks/e-commerce/storefront-hero/storefront-hero-1.test.tsx (6 tests) 867ms
33
+ ✓ StorefrontHero1 — optional editorial image > renders no editorial image when none is supplied 325ms
34
+ ✓ src/lib/contracts.test.ts (3 tests) 33ms
35
+ ✓ src/lib/cart.test.ts (2 tests) 23ms
36
+ ✓ src/blocks/e-commerce/product-overview/product-overview-1.test.tsx (14 tests) 200ms
37
+ ✓ src/blocks/e-commerce/navigation/breadcrumb.test.tsx (12 tests) 80ms
38
+ ✓ src/blocks/e-commerce/navigation/back-to-top.test.tsx (5 tests) 23ms
39
+ ✓ src/blocks/e-commerce/checkout-forms/card-formatting.test.ts (10 tests) 10ms
40
+ ✓ src/lib/contracts-curated.test.ts (22 tests) 550ms
41
+ ✓ src/blocks/e-commerce/product-list/product-showcase-1.test.tsx (7 tests) 498ms
42
+
43
+ Test Files 25 passed (25)
44
+ Tests 263 passed (263)
45
+ Start at 11:37:52
46
+ Duration 16.34s (transform 12.71s, setup 0ms, collect 81.98s, tests 13.48s, environment 33ms, prepare 18.67s)
10
47
 
package/AGENTS.md CHANGED
@@ -1 +1 @@
1
- <!-- BLOCKS-AGENTS-MD-START -->[@thorprovider/blocks Docs]|root: ./blocks|Documentation for @thorprovider/blocks. Always read package docs before making changes.|To regenerate: yarn workspace @thorprovider/blocks generate:agent-index|.:{README.md}|docs/standards:{data-contracts.md,theming.md}<!-- BLOCKS-AGENTS-MD-END -->
1
+ <!-- BLOCKS-AGENTS-MD-START -->[@thorprovider/blocks Docs]|root: ./blocks|Electrostore MVP: see director roadmap.|To regenerate: yarn workspace @thorprovider/blocks generate:agent-index|.:{README.md}|docs/standards:{data-contracts.md,theming.md}<!-- BLOCKS-AGENTS-MD-END -->
package/README.md CHANGED
@@ -60,6 +60,7 @@ Blocks follow `src/blocks/<category>/<section>/<block>.tsx`. Each block co-locat
60
60
  | `ProductCard2` | E-commerce | Clean three-up grid with ratings |
61
61
  | `ProductCard3` | E-commerce | Deals grid with badges, low-stock and wishlist |
62
62
  | `ProductCard5` | E-commerce | Table-style comparison with sorting and filtering |
63
+ | `ProductShowcase1` | E-commerce | Combined grid-and-carousel of product cards with manual paging |
63
64
  | `ProductOverview1` | E-commerce | Product detail with gallery, variants and add-to-cart |
64
65
  | `ProductQuickView` | E-commerce | Quick-view dialog with gallery, variants and quantity |
65
66
  | `ReviewRating1` | E-commerce | Review list with rating summary |
@@ -72,7 +73,7 @@ Blocks follow `src/blocks/<category>/<section>/<block>.tsx`. Each block co-locat
72
73
  | `CategoryFilter2` | E-commerce | Filter sidebar with mobile sheet |
73
74
  | `ShoppingCart1` | E-commerce | Detailed cart summary |
74
75
  | `ShoppingCart2` | E-commerce | Cart with promo code and shipping |
75
- | `ShoppingCart4` | E-commerce | Collapsible cart drawer with promotion progress |
76
+ | `ShoppingCart4` | E-commerce | Cart review with backend-authoritative totals; `presentation` `compact` (collapsible card) or `page` (full-width review) |
76
77
  | `CheckoutForm1` | E-commerce | Essential checkout fields |
77
78
  | `CheckoutForm2` | E-commerce | Single-page checkout with order summary beside |
78
79
  | `CheckoutConfirmation` | E-commerce | Order confirmation with fulfilment timeline |
@@ -91,6 +92,84 @@ Blocks follow `src/blocks/<category>/<section>/<block>.tsx`. Each block co-locat
91
92
 
92
93
  Interactions are exposed as callbacks (e.g. `onAddToCart`, `onBuyNow`, `onSelectColor`). Elements stay in the DOM with no-op behavior when a callback is absent.
93
94
 
95
+ ## Optional brand props
96
+
97
+ Three existing blocks expose an optional brand seam. Omitting the prop renders
98
+ the block's current output unchanged; no demo content is added.
99
+
100
+ - `Navbar4` — `logoAccent?: { text: string; className?: string }` accents a
101
+ trailing segment of `logoText`. With `logoText="ElectroCuba"` and
102
+ `logoAccent={{ text: 'Cuba', className: 'text-brand-promo' }}`, the block
103
+ renders `Electro` plus an accented `Cuba` span. If `text` is not a trailing
104
+ segment of `logoText`, the wordmark renders unchanged.
105
+ - `FooterSection1` — `brandAccent?: { text: string; className?: string }` applies
106
+ the same trailing-segment accent to `brandName`.
107
+ - `StorefrontHero1` — `heroImage?: { src: string; alt: string }` renders a native
108
+ `<img>` when `src` is a non-empty string, and nothing when the prop is absent
109
+ or `src` is blank (never an empty `src`). The product grid is unaffected.
110
+
111
+ `className` carries the consumer's own semantic token (e.g. `text-brand-promo`);
112
+ the library hardcodes no brand color.
113
+
114
+ ## Custom surface `className`
115
+
116
+ `Navbar4` (outer `<header>`) and `FooterSection1` (outer `<footer>`) accept an
117
+ optional `className`, merged with the existing `cn` helper. It is purely
118
+ presentational: no layout, structure, or behavior prop, and no hardcoded color.
119
+
120
+ - **Omitted `className`** — the block renders its default surface unchanged.
121
+ `Navbar4` keeps `bg-background/95` **and** its
122
+ `supports-backdrop-filter:bg-background/80` variant; `FooterSection1` keeps
123
+ `bg-secondary`.
124
+ - **Supplied `className`** — the consumer owns the surface. The default
125
+ background **and its backdrop-filter variant** are not applied, so a semantic
126
+ surface such as `bg-brand-nav text-brand-nav-foreground` actually paints (the
127
+ `supports-backdrop-filter` variant would otherwise win on Chromium and mask
128
+ it). Layout, border, sticky, and `backdrop-blur-md` classes stay internal.
129
+
130
+ The consumer is responsible for the text, transparency, and context tokens of a
131
+ supplied surface. `Navbar4` adapts its primary nav links: they inherit the
132
+ surface text color and add `hover:text-foreground` so `hover:bg-muted` never
133
+ paints white-on-light. No magic colors are introduced by the block.
134
+
135
+ ## Footer newsletter
136
+
137
+ `FooterSection1` renders the interactive newsletter form (input + submit button)
138
+ **only** when `newsletter.onSubmit` is supplied. A `newsletter` object without
139
+ `onSubmit` renders no form, input, or button — never a fake form. Omit
140
+ `newsletter` entirely to hide the newsletter block.
141
+
142
+ ## Cart presentation (controlled)
143
+
144
+ The cart is presented in two shapes that share one data contract, so a change in
145
+ either is visible in the other.
146
+
147
+ - `ShoppingCart4` is the cart block. Its optional `presentation` prop selects
148
+ `'compact'` (default: a collapsible `max-w-md` card with an internal scroller —
149
+ the navbar lateral) or `'page'` (always expanded, full-width `max-w-3xl`, no
150
+ collapse control, ordinary page scrolling — the `/cart` review route).
151
+ Omitting `presentation` renders the compact card byte-identically to before.
152
+ - Line amounts prefer the canonical `lineTotal?: Money` and fall back to the
153
+ legacy numeric `price * quantity` only when `lineTotal` is absent. A missing or
154
+ malformed `Money` renders the `amountUnavailableLabel` (never a fabricated
155
+ zero or a currency fallback). `unitPrice?: Money` is carried verbatim.
156
+ - `totalsState` (`'idle' | 'pending' | 'error'`) plus `onRetryTotals` make the
157
+ totals controlled: pending retains the last confirmed totals and disables
158
+ conflicting mutations; error shows the error label and a retry.
159
+ `onQuantityChange(id, quantity)` reports the **absolute** line quantity (keyed
160
+ by backend line id) and `onRemove(id)` removes by the same id.
161
+ `checkoutUnavailable` hides the checkout action (e.g. no checkout installed)
162
+ and `checkoutDisabled` disables it (e.g. pending or invalid totals).
163
+
164
+ `Navbar4` owns the lateral. Pass `cartOpen` + `onCartOpenChange` to control the
165
+ sheet's visibility from host state (omit both to keep the legacy uncontrolled
166
+ sheet); the block keeps `aria-expanded`/`data-state` in sync. Its cart sheet
167
+ (`Navbar4CartSheet`) takes an optional `canonical` mode where each line shows the
168
+ canonical `lineTotal` (never the placeholder numeric price), plus
169
+ `checkoutUnavailable`/`viewCartUnavailable` to hide actions the store cannot
170
+ serve, and a `state` (`'idle' | 'pending' | 'error'`) with retry for read/mutation
171
+ feedback.
172
+
94
173
  ## Checkout blocks (controlled)
95
174
 
96
175
  `CheckoutForm1` (3-step wizard) and `CheckoutForm2` (single page) are **controlled components**: they receive the current form values through a `values` prop and report every edit through `onChange`. They hold no internal form state, so a renderer's validation context can read field values from its own state model. `CheckoutForm3` (4-step wizard) keeps the same contract with internal step state.
@@ -149,6 +228,20 @@ unique by contract, not by convention. See
149
228
  [`docs/standards/data-contracts.md`](docs/standards/data-contracts.md) for the
150
229
  rules and the review checklist.
151
230
 
231
+ Optional numeric projections are omitted rather than fabricated: e.g.
232
+ `ProductCategory2Category.itemCount` renders a count only when it is a supplied
233
+ finite non-negative number (a real `0` is preserved); an unknown count renders
234
+ no count text, never a fabricated `0`.
235
+
236
+ Product presentations (`ProductCard1`, `ProductShowcase1`) accept either the
237
+ legacy numeric-price props or a canonical `ProductPresentation` (`price`/
238
+ `compareAtPrice` as `Money`, `{ amount: string, currencyCode: string }` in
239
+ decimal major units). The canonical path formats with the store currency and
240
+ locale, renders a truthful "unavailable" state for an unresolved price (never
241
+ `$0`; a valid `0` is preserved), and shows a comparison price only when it is
242
+ valid and strictly higher. Optional rating/badge/image appear only when
243
+ supplied; a missing image is omitted, never `src=""`.
244
+
152
245
  ## Block interaction contracts
153
246
 
154
247
  State and events between a block, its host registry, and the store must follow