@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
@@ -0,0 +1,65 @@
1
+ import type { Money } from '@thorprovider/types'
2
+
3
+ /**
4
+ * Pure monetary helpers shared by the curated commerce blocks.
5
+ *
6
+ * Canonical `Money` (`@thorprovider/types`) carries a decimal string in major
7
+ * units (e.g. `"69.99"`) — never cents. A missing, invalid, or unresolved
8
+ * amount is *unavailable*, which is a different state from a legitimate `"0"`.
9
+ * These helpers keep that distinction in the presentation layer: they validate
10
+ * a complete finite decimal before any display conversion, and they never
11
+ * invent a currency.
12
+ */
13
+
14
+ const COMPLETE_FINITE_DECIMAL = /^-?(?:\d+)(?:\.\d+)?$/
15
+
16
+ /**
17
+ * True only for a complete, finite decimal string (`"0"`, `"69.99"`, `"-3.5"`).
18
+ * Rejects `""`, `" "`, `"1."`, `".5"`, `"1e3"`, `"abc"`, and non-strings.
19
+ */
20
+ export function isCompleteFiniteDecimal(value: unknown): value is string {
21
+ if (typeof value !== 'string') return false
22
+ const trimmed = value.trim()
23
+ if (trimmed === '' || !COMPLETE_FINITE_DECIMAL.test(trimmed)) return false
24
+ return Number.isFinite(Number(trimmed))
25
+ }
26
+
27
+ /**
28
+ * True when a `Money` value is safe to display and price a purchase with: a
29
+ * complete finite decimal amount and a non-empty currency code. A valid zero
30
+ * (`{ amount: '0', currencyCode: 'USD' }`) is available — zero alone does not
31
+ * make a price unavailable.
32
+ */
33
+ export function isAvailableMoney(money: Money | null | undefined): money is Money {
34
+ return (
35
+ !!money &&
36
+ typeof money.currencyCode === 'string' &&
37
+ money.currencyCode.trim() !== '' &&
38
+ isCompleteFiniteDecimal(money.amount)
39
+ )
40
+ }
41
+
42
+ /**
43
+ * Formats a `Money` for display, or `null` when the value is unavailable.
44
+ *
45
+ * This is the safety gate the whole curated surface relies on: an absent or
46
+ * malformed amount (`""`, `" "`, `"abc"`, a non-string, a missing currency)
47
+ * MUST NOT reach `Intl.NumberFormat`, because `Number("")` is `0` and would
48
+ * render a fake `$0.00` for missing data. A backend-resolved valid zero
49
+ * (`{ amount: "0", currencyCode: "USD" }`) is available and formats as zero.
50
+ *
51
+ * When no `formatter` is supplied the currency comes from
52
+ * `money.currencyCode`, so no currency is hardcoded. Callers render their own
53
+ * unavailable/pending/recovery state when this returns `null`.
54
+ */
55
+ export function formatMoney(
56
+ money: Money | null | undefined,
57
+ formatter?: (money: Money) => string,
58
+ ): string | null {
59
+ if (!isAvailableMoney(money)) return null
60
+ if (formatter) return formatter(money)
61
+ return new Intl.NumberFormat(undefined, {
62
+ style: 'currency',
63
+ currency: money.currencyCode,
64
+ }).format(Number(money.amount))
65
+ }
package/tsup.config.ts CHANGED
@@ -11,6 +11,5 @@ export default defineConfig({
11
11
  sourcemap: true,
12
12
  clean: true,
13
13
  external: ['react', 'react-dom', 'clsx', 'tailwind-merge', 'lucide-react'],
14
- banner: { js: "'use client';" },
15
14
  onSuccess: process.env.SKIP_TYPE_CHECK === 'true' ? undefined : 'tsc --noEmit --skipLibCheck'
16
15
  })
package/vitest.config.ts CHANGED
@@ -1,9 +1,17 @@
1
+ import { fileURLToPath } from 'node:url'
1
2
  import { defineConfig } from 'vitest/config'
2
3
 
3
4
  export default defineConfig({
5
+ resolve: {
6
+ // Vendored shadcn primitives under src/ui use the `@/` alias; mirror the
7
+ // tsconfig paths so component tests can import them.
8
+ alias: {
9
+ '@': fileURLToPath(new URL('./src', import.meta.url)),
10
+ },
11
+ },
4
12
  test: {
5
13
  environment: 'node',
6
14
  globals: true,
7
15
  include: ['src/**/*.test.{ts,tsx}'],
8
16
  },
9
- })
17
+ })