@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.
- package/.turbo/turbo-build.log +15 -15
- package/.turbo/turbo-test.log +42 -5
- package/AGENTS.md +1 -1
- package/README.md +94 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/contracts.d.mts +1266 -97
- package/dist/contracts.d.ts +1266 -97
- package/dist/contracts.js +225 -9
- package/dist/contracts.js.map +1 -1
- package/dist/contracts.mjs +207 -10
- package/dist/contracts.mjs.map +1 -1
- package/dist/index.d.mts +756 -96
- package/dist/index.d.ts +756 -96
- package/dist/index.js +5114 -3702
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4939 -3551
- package/dist/index.mjs.map +1 -1
- package/docs/standards/theming.md +32 -5
- package/package.json +2 -2
- package/src/blocks/e-commerce/category-filters/category-filter-2-filter-panel.tsx +136 -93
- package/src/blocks/e-commerce/category-filters/category-filter-2.test.tsx +513 -0
- package/src/blocks/e-commerce/category-filters/category-filter-2.tsx +728 -148
- package/src/blocks/e-commerce/checkout-forms/checkout-confirmation-fulfilment-progress.tsx +14 -8
- package/src/blocks/e-commerce/checkout-forms/checkout-confirmation.test.tsx +136 -0
- package/src/blocks/e-commerce/checkout-forms/checkout-confirmation.tsx +145 -99
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1-order-summary.tsx +215 -102
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1-payment-step.tsx +6 -2
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1-shipping-step.tsx +51 -2
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1.test.tsx +216 -0
- package/src/blocks/e-commerce/checkout-forms/checkout-form-1.tsx +114 -11
- package/src/blocks/e-commerce/navigation/back-to-top.test.tsx +27 -0
- package/src/blocks/e-commerce/navigation/back-to-top.tsx +71 -0
- package/src/blocks/e-commerce/navigation/breadcrumb.test.tsx +174 -0
- package/src/blocks/e-commerce/navigation/breadcrumb.tsx +130 -0
- package/src/blocks/e-commerce/navigation/mobile-bottom-nav.test.tsx +74 -0
- package/src/blocks/e-commerce/navigation/mobile-bottom-nav.tsx +78 -0
- package/src/blocks/e-commerce/navigation/mobile-category-drawer.test.tsx +42 -2
- package/src/blocks/e-commerce/navigation/mobile-category-drawer.tsx +10 -8
- package/src/blocks/e-commerce/navigation/skip-to-content.test.tsx +35 -0
- package/src/blocks/e-commerce/navigation/skip-to-content.tsx +37 -0
- package/src/blocks/e-commerce/product-categories/product-category-2.test.tsx +51 -0
- package/src/blocks/e-commerce/product-categories/product-category-2.tsx +56 -36
- package/src/blocks/e-commerce/product-list/product-card-1.test.tsx +88 -0
- package/src/blocks/e-commerce/product-list/product-card-1.tsx +141 -80
- package/src/blocks/e-commerce/product-list/product-showcase-1.test.tsx +78 -0
- package/src/blocks/e-commerce/product-list/product-showcase-1.tsx +277 -0
- package/src/blocks/e-commerce/product-overview/product-overview-1.test.tsx +182 -0
- package/src/blocks/e-commerce/product-overview/product-overview-1.tsx +298 -129
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-4.test.tsx +229 -0
- package/src/blocks/e-commerce/shopping-carts/shopping-cart-4.tsx +313 -110
- package/src/blocks/e-commerce/storefront-hero/storefront-hero-1.test.tsx +72 -0
- package/src/blocks/e-commerce/storefront-hero/storefront-hero-1.tsx +20 -1
- package/src/blocks/marketing/footers/footer-section-1.test.tsx +117 -0
- package/src/blocks/marketing/footers/footer-section-1.tsx +46 -9
- package/src/blocks/marketing/navbars/navbar-4-account-menu.test.tsx +38 -0
- package/src/blocks/marketing/navbars/navbar-4-account-menu.tsx +30 -14
- package/src/blocks/marketing/navbars/navbar-4-cart-sheet.test.tsx +204 -0
- package/src/blocks/marketing/navbars/navbar-4-cart-sheet.tsx +144 -21
- package/src/blocks/marketing/navbars/navbar-4.test.tsx +233 -0
- package/src/blocks/marketing/navbars/navbar-4.tsx +235 -60
- package/src/index.ts +56 -0
- package/src/lib/cart.test.ts +15 -0
- package/src/lib/cart.ts +11 -0
- package/src/lib/contracts-curated.test.ts +207 -0
- package/src/lib/contracts-server-boundary.test.ts +52 -0
- package/src/lib/contracts.ts +234 -6
- package/src/lib/money.test.ts +64 -0
- package/src/lib/money.ts +65 -0
- package/tsup.config.ts +0 -1
- package/vitest.config.ts +9 -1
package/src/lib/money.ts
ADDED
|
@@ -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
|
+
})
|