@enadhq/enad-react-sdk 1.1.0 → 1.2.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/dist/client/cart/components/cart-drawer.mjs +3 -3
- package/dist/client/cart/components/cart-drawer.mjs.map +1 -1
- package/dist/client/cart/components/cart-trigger.mjs +1 -1
- package/dist/client/cart/components/cart-trigger.mjs.map +1 -1
- package/dist/client/storefront/checkout/cart-summary.mjs +1 -1
- package/dist/client/storefront/checkout/cart-summary.mjs.map +1 -1
- package/dist/client/storefront/components/language-selector.d.ts.map +1 -1
- package/dist/client/storefront/components/language-selector.mjs +1 -1
- package/dist/client/storefront/components/language-selector.mjs.map +1 -1
- package/dist/client/storefront/filters/filter-chip.mjs +1 -1
- package/dist/client/storefront/filters/filter-chip.mjs.map +1 -1
- package/dist/client/storefront/filters/filter-panel.mjs +1 -1
- package/dist/client/storefront/filters/filter-panel.mjs.map +1 -1
- package/dist/client/storefront/filters/toggle-list-view.mjs +1 -1
- package/dist/client/storefront/filters/toggle-list-view.mjs.map +1 -1
- package/dist/client/storefront/layout/promotion-bar.d.ts.map +1 -1
- package/dist/client/storefront/layout/promotion-bar.mjs +3 -3
- package/dist/client/storefront/layout/promotion-bar.mjs.map +1 -1
- package/dist/client/storefront/primitives/button.d.ts +2 -2
- package/dist/client/storefront/primitives/button.d.ts.map +1 -1
- package/dist/client/storefront/primitives/button.mjs +4 -4
- package/dist/client/storefront/primitives/button.mjs.map +1 -1
- package/dist/client/storefront/primitives/input.d.ts +1 -1
- package/dist/client/storefront/primitives/input.mjs.map +1 -1
- package/dist/client/storefront/primitives/pagination.mjs +2 -2
- package/dist/client/storefront/primitives/pagination.mjs.map +1 -1
- package/dist/client/storefront/product/quantity-picker.mjs +2 -2
- package/dist/client/storefront/product/quantity-picker.mjs.map +1 -1
- package/dist/client/storefront/types.d.ts +1 -1
- package/dist/client/storefront/types.d.ts.map +1 -1
- package/dist/client/storefront/types.mjs.map +1 -1
- package/dist/client/ui/accordion.d.ts +12 -1
- package/dist/client/ui/accordion.d.ts.map +1 -1
- package/dist/client/ui/accordion.mjs +23 -5
- package/dist/client/ui/accordion.mjs.map +1 -1
- package/dist/client/ui/alert.d.ts +16 -7
- package/dist/client/ui/alert.d.ts.map +1 -1
- package/dist/client/ui/alert.mjs +21 -8
- package/dist/client/ui/alert.mjs.map +1 -1
- package/dist/client/ui/avatar.d.ts +10 -1
- package/dist/client/ui/avatar.d.ts.map +1 -1
- package/dist/client/ui/avatar.mjs +18 -4
- package/dist/client/ui/avatar.mjs.map +1 -1
- package/dist/client/ui/breadcrumb.d.ts +13 -1
- package/dist/client/ui/breadcrumb.d.ts.map +1 -1
- package/dist/client/ui/breadcrumb.mjs +27 -7
- package/dist/client/ui/breadcrumb.mjs.map +1 -1
- package/dist/client/ui/button.d.ts +28 -10
- package/dist/client/ui/button.d.ts.map +1 -1
- package/dist/client/ui/button.mjs +45 -20
- package/dist/client/ui/button.mjs.map +1 -1
- package/dist/client/ui/card.d.ts +20 -1
- package/dist/client/ui/card.d.ts.map +1 -1
- package/dist/client/ui/card.mjs +36 -8
- package/dist/client/ui/card.mjs.map +1 -1
- package/dist/client/ui/carousel.d.ts.map +1 -1
- package/dist/client/ui/carousel.mjs +2 -2
- package/dist/client/ui/carousel.mjs.map +1 -1
- package/dist/client/ui/checkbox.d.ts +9 -1
- package/dist/client/ui/checkbox.d.ts.map +1 -1
- package/dist/client/ui/checkbox.mjs +12 -3
- package/dist/client/ui/checkbox.mjs.map +1 -1
- package/dist/client/ui/dialog.d.ts +13 -1
- package/dist/client/ui/dialog.d.ts.map +1 -1
- package/dist/client/ui/dialog.mjs +27 -7
- package/dist/client/ui/dialog.mjs.map +1 -1
- package/dist/client/ui/hover-card.d.ts +6 -1
- package/dist/client/ui/hover-card.d.ts.map +1 -1
- package/dist/client/ui/hover-card.mjs +4 -2
- package/dist/client/ui/hover-card.mjs.map +1 -1
- package/dist/client/ui/input.d.ts +20 -7
- package/dist/client/ui/input.d.ts.map +1 -1
- package/dist/client/ui/input.mjs +33 -9
- package/dist/client/ui/input.mjs.map +1 -1
- package/dist/client/ui/label.d.ts +6 -1
- package/dist/client/ui/label.d.ts.map +1 -1
- package/dist/client/ui/label.mjs +4 -2
- package/dist/client/ui/label.mjs.map +1 -1
- package/dist/client/ui/navigation-menu.d.ts +20 -3
- package/dist/client/ui/navigation-menu.d.ts.map +1 -1
- package/dist/client/ui/navigation-menu.mjs +34 -12
- package/dist/client/ui/navigation-menu.mjs.map +1 -1
- package/dist/client/ui/pagination.d.ts.map +1 -1
- package/dist/client/ui/pagination.mjs +3 -3
- package/dist/client/ui/pagination.mjs.map +1 -1
- package/dist/client/ui/popover.d.ts +11 -1
- package/dist/client/ui/popover.d.ts.map +1 -1
- package/dist/client/ui/popover.mjs +21 -5
- package/dist/client/ui/popover.mjs.map +1 -1
- package/dist/client/ui/progress.d.ts +9 -1
- package/dist/client/ui/progress.d.ts.map +1 -1
- package/dist/client/ui/progress.mjs +12 -3
- package/dist/client/ui/progress.mjs.map +1 -1
- package/dist/client/ui/select.d.ts +14 -2
- package/dist/client/ui/select.d.ts.map +1 -1
- package/dist/client/ui/select.mjs +35 -9
- package/dist/client/ui/select.mjs.map +1 -1
- package/dist/client/ui/separator.d.ts +6 -1
- package/dist/client/ui/separator.d.ts.map +1 -1
- package/dist/client/ui/separator.mjs +4 -2
- package/dist/client/ui/separator.mjs.map +1 -1
- package/dist/client/ui/sheet.d.ts +13 -1
- package/dist/client/ui/sheet.d.ts.map +1 -1
- package/dist/client/ui/sheet.mjs +35 -7
- package/dist/client/ui/sheet.mjs.map +1 -1
- package/dist/client/ui/slot-wrapper.d.ts +28 -0
- package/dist/client/ui/slot-wrapper.d.ts.map +1 -0
- package/dist/client/ui/slot-wrapper.mjs +38 -0
- package/dist/client/ui/slot-wrapper.mjs.map +1 -0
- package/dist/client/ui/tabs.d.ts +11 -1
- package/dist/client/ui/tabs.d.ts.map +1 -1
- package/dist/client/ui/tabs.mjs +21 -5
- package/dist/client/ui/tabs.mjs.map +1 -1
- package/dist/client/ui/toggle-group.d.ts +7 -4
- package/dist/client/ui/toggle-group.d.ts.map +1 -1
- package/dist/client/ui/toggle-group.mjs +4 -4
- package/dist/client/ui/toggle-group.mjs.map +1 -1
- package/dist/client/ui/toggle.d.ts +17 -8
- package/dist/client/ui/toggle.d.ts.map +1 -1
- package/dist/client/ui/toggle.mjs +11 -9
- package/dist/client/ui/toggle.mjs.map +1 -1
- package/dist/client/ui/tooltip.d.ts +6 -1
- package/dist/client/ui/tooltip.d.ts.map +1 -1
- package/dist/client/ui/tooltip.mjs +4 -2
- package/dist/client/ui/tooltip.mjs.map +1 -1
- package/dist/client/ui-resolver/button.d.ts +3 -4
- package/dist/client/ui-resolver/button.d.ts.map +1 -1
- package/dist/client/ui-resolver/button.mjs +2 -2
- package/dist/client/ui-resolver/button.mjs.map +1 -1
- package/dist/client/ui-resolver/card.d.ts +14 -1
- package/dist/client/ui-resolver/card.d.ts.map +1 -1
- package/dist/client/ui-resolver/card.mjs +3 -2
- package/dist/client/ui-resolver/card.mjs.map +1 -1
- package/dist/client/ui-resolver/context.mjs +1 -1
- package/dist/client/ui-resolver/context.mjs.map +1 -1
- package/dist/client/ui-resolver/index.d.ts +7 -4
- package/dist/client/ui-resolver/index.mjs +6 -4
- package/dist/client/ui-resolver/input.d.ts +3 -4
- package/dist/client/ui-resolver/input.d.ts.map +1 -1
- package/dist/client/ui-resolver/input.mjs +2 -2
- package/dist/client/ui-resolver/input.mjs.map +1 -1
- package/dist/client/ui-resolver/navigation-menu.d.ts +1 -2
- package/dist/client/ui-resolver/navigation-menu.d.ts.map +1 -1
- package/dist/client/ui-resolver/recipe.d.ts +95 -0
- package/dist/client/ui-resolver/recipe.d.ts.map +1 -0
- package/dist/client/ui-resolver/recipe.mjs +134 -0
- package/dist/client/ui-resolver/recipe.mjs.map +1 -0
- package/dist/client/ui-resolver/toggle.d.ts +2 -2
- package/dist/client/ui-resolver/toggle.mjs +2 -2
- package/dist/client/ui-resolver/toggle.mjs.map +1 -1
- package/dist/client/ui-resolver/types.d.ts +14 -0
- package/dist/client/ui-resolver/types.d.ts.map +1 -0
- package/dist/client/ui-resolver/types.mjs +1 -0
- package/dist/client/wishlist/wishlist-drawer.mjs +4 -4
- package/dist/client/wishlist/wishlist-drawer.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +2 -2
|
@@ -37,7 +37,7 @@ function CartEmptyState({ message, onClose, buttonLabel }) {
|
|
|
37
37
|
children: message
|
|
38
38
|
}), /* @__PURE__ */ jsx(Button, {
|
|
39
39
|
onClick: onClose,
|
|
40
|
-
variant: "
|
|
40
|
+
variant: "outlined",
|
|
41
41
|
children: buttonLabel
|
|
42
42
|
})]
|
|
43
43
|
});
|
|
@@ -64,7 +64,7 @@ function CartItemDetails({ item, currencyCode, onClose, onUpdateQuantity, onRemo
|
|
|
64
64
|
onClick: onClose,
|
|
65
65
|
children: item.displayName
|
|
66
66
|
}), /* @__PURE__ */ jsx(Button, {
|
|
67
|
-
variant: "
|
|
67
|
+
variant: "plain",
|
|
68
68
|
size: "icon",
|
|
69
69
|
className: "h-5 w-5 flex-shrink-0",
|
|
70
70
|
onClick: () => onRemove(item.id),
|
|
@@ -236,7 +236,7 @@ function CartDrawer({ isOpen, onClose, className, labels = {} }) {
|
|
|
236
236
|
children: title
|
|
237
237
|
}), /* @__PURE__ */ jsx(Button, {
|
|
238
238
|
ref: closeButtonRef,
|
|
239
|
-
variant: "
|
|
239
|
+
variant: "plain",
|
|
240
240
|
size: "icon",
|
|
241
241
|
onClick: onClose,
|
|
242
242
|
"aria-label": "Close cart",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cart-drawer.mjs","names":[],"sources":["../../../../src/client/cart/components/cart-drawer.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useCallback } from \"react\";\nimport { useCart } from \"../../cart/hooks/useCart\";\nimport type { CartItem, CartTotals as CartTotalsType } from \"../../cart/types/adapter\";\nimport { useIcon } from \"../../icons/icon-context\";\nimport { Button } from \"../../ui/button\";\nimport { Price } from \"../../storefront/components/price\";\nimport { QuantityPicker } from \"../../storefront/product/quantity-picker\";\n\nexport interface CartDrawerProps {\n isOpen: boolean;\n onClose: () => void;\n className?: string;\n labels?: {\n title?: string;\n emptyCartMessage?: string;\n continueShopping?: string;\n subtotal?: string;\n discount?: string;\n tax?: string;\n total?: string;\n proceedToCheckout?: string;\n };\n}\n\nfunction CartLoadingSkeleton() {\n return (\n <div className=\"space-y-6\" aria-busy=\"true\" aria-label=\"Loading cart items\">\n {[1, 2, 3].map((i) => (\n <div key={i} className=\"flex gap-4 animate-pulse\">\n <div className=\"w-24 h-24 flex-shrink-0 bg-(--enad-border-color) rounded-(--enad-border-radius)\" />\n <div className=\"flex flex-1 flex-col gap-2\">\n <div className=\"h-4 w-3/4 bg-(--enad-border-color) rounded-(--enad-border-radius)\" />\n <div className=\"h-4 w-1/3 bg-(--enad-border-color) rounded-(--enad-border-radius)\" />\n <div className=\"h-4 w-1/4 bg-(--enad-border-color) rounded-(--enad-border-radius)\" />\n </div>\n </div>\n ))}\n </div>\n );\n}\n\nfunction CartEmptyState({\n message,\n onClose,\n buttonLabel,\n}: {\n message: string;\n onClose: () => void;\n buttonLabel: string;\n}) {\n return (\n <div className=\"flex flex-col items-center justify-center h-full text-center\">\n <p className=\"text-(--enad-text-muted-color) mb-4\">{message}</p>\n <Button onClick={onClose} variant=\"outline\">\n {buttonLabel}\n </Button>\n </div>\n );\n}\n\nfunction CartItemImage({ imageUrl, alt }: { imageUrl?: string; alt: string }) {\n return (\n <div className=\"relative w-24 h-24 flex-shrink-0 bg-(--enad-border-color) rounded-(--enad-border-radius) overflow-hidden\">\n {imageUrl ? (\n <img src={imageUrl} alt={alt} className=\"object-cover\" />\n ) : (\n <div className=\"w-full h-full bg-(--enad-border-color)\" />\n )}\n </div>\n );\n}\n\nfunction CartItemDetails({\n item,\n currencyCode,\n onClose,\n onUpdateQuantity,\n onRemove,\n}: {\n item: CartItem;\n currencyCode: string;\n onClose: () => void;\n onUpdateQuantity: (itemId: string, quantity: number) => void;\n onRemove: (itemId: string) => void;\n}) {\n const TrashIcon = useIcon(\"trash\");\n\n return (\n <div className=\"flex flex-1 min-w-0 justify-between flex-col\">\n <div className=\"flex justify-between gap-2 mb-2\">\n <a\n href={`/products/${item.productSlug || item.productVariantId}`}\n className=\"font-medium text-sm text-(--enad-link-color) hover:text-(--enad-link-hover-color) transition-colors\"\n onClick={onClose}\n >\n {item.displayName}\n </a>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-5 w-5 flex-shrink-0\"\n onClick={() => onRemove(item.id)}\n aria-label={`Remove ${item.displayName}`}\n >\n <TrashIcon className=\"h-4 w-4\" />\n </Button>\n </div>\n\n <div>\n <Price\n amount={item.unitPrice.amount / 100}\n currency={currencyCode}\n className=\"text-sm text-(--enad-text-muted-color) mb-1\"\n />\n\n <QuantityPicker\n value={item.quantity}\n onChange={(qty) => onUpdateQuantity(item.id, qty)}\n size=\"sm\"\n />\n </div>\n </div>\n );\n}\n\nfunction CartItemRow({\n item,\n currencyCode,\n onClose,\n onUpdateQuantity,\n onRemove,\n}: {\n item: CartItem;\n currencyCode: string;\n onClose: () => void;\n onUpdateQuantity: (itemId: string, quantity: number) => void;\n onRemove: (itemId: string) => void;\n}) {\n return (\n <div className=\"flex gap-4\" role=\"listitem\">\n <CartItemImage imageUrl={item.imageUrl} alt={item.displayName} />\n <CartItemDetails\n item={item}\n currencyCode={currencyCode}\n onClose={onClose}\n onUpdateQuantity={onUpdateQuantity}\n onRemove={onRemove}\n />\n </div>\n );\n}\n\nfunction CartTotals({\n totals,\n currencyCode,\n labels,\n}: {\n totals: CartTotalsType;\n currencyCode: string;\n labels: {\n subtotal: string;\n discount: string;\n tax: string;\n total: string;\n proceedToCheckout: string;\n };\n}) {\n return (\n <div className=\"p-6 space-y-4\">\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-(--enad-text-muted-color)\">{labels.subtotal}</span>\n <Price amount={totals.subtotal.amount / 100} currency={currencyCode} />\n </div>\n\n {totals.discount.amount > 0 && (\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-(--enad-text-muted-color)\">{labels.discount}</span>\n <span className=\"text-(--enad-success-color)\">\n -<Price amount={totals.discount.amount / 100} currency={currencyCode} />\n </span>\n </div>\n )}\n\n {totals.tax.amount > 0 && (\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-(--enad-text-muted-color)\">{labels.tax}</span>\n <Price amount={totals.tax.amount / 100} currency={currencyCode} />\n </div>\n )}\n\n <div className=\"flex justify-between text-lg font-bold pt-4 border-t border-(--enad-border-color)\">\n <span className=\"text-(--enad-text-primary-color)\">{labels.total}</span>\n <Price amount={totals.total.amount / 100} currency={currencyCode} />\n </div>\n\n <Button className=\"w-full py-6 text-sm font-medium uppercase tracking-wider\" size=\"lg\">\n {labels.proceedToCheckout}\n </Button>\n </div>\n );\n}\n\nfunction useCartDrawer(isOpen: boolean, onClose: () => void) {\n const drawerRef = useRef<HTMLDivElement>(null);\n const closeButtonRef = useRef<HTMLButtonElement>(null);\n const { cart, isLoading, removeItem, updateItem } = useCart();\n\n useEffect(() => {\n if (isOpen) {\n const timer = setTimeout(() => closeButtonRef.current?.focus(), 100);\n return () => clearTimeout(timer);\n }\n }, [isOpen]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.stopPropagation();\n onClose();\n }\n },\n [onClose],\n );\n\n const handleUpdateQuantity = (itemId: string, newQuantity: number) => {\n updateItem({ itemId, quantity: newQuantity });\n };\n\n const handleRemoveItem = (itemId: string) => {\n removeItem({ itemId });\n };\n\n return {\n drawerRef,\n closeButtonRef,\n cart,\n isLoading,\n items: cart?.items || [],\n totals: cart?.totals,\n currencyCode: cart?.currencyCode || \"SEK\",\n handleKeyDown,\n handleUpdateQuantity,\n handleRemoveItem,\n };\n}\n\nfunction CartContent({\n isLoading,\n items,\n currencyCode,\n emptyCartMessage,\n continueShopping,\n onClose,\n onUpdateQuantity,\n onRemove,\n}: {\n isLoading: boolean;\n items: CartItem[];\n currencyCode: string;\n emptyCartMessage: string;\n continueShopping: string;\n onClose: () => void;\n onUpdateQuantity: (itemId: string, quantity: number) => void;\n onRemove: (itemId: string) => void;\n}) {\n if (isLoading) return <CartLoadingSkeleton />;\n if (items.length === 0) {\n return (\n <CartEmptyState message={emptyCartMessage} onClose={onClose} buttonLabel={continueShopping} />\n );\n }\n return (\n <div className=\"space-y-6\" role=\"list\" aria-label=\"Cart items\">\n {items.map((item) => (\n <CartItemRow\n key={item.id}\n item={item}\n currencyCode={currencyCode}\n onClose={onClose}\n onUpdateQuantity={onUpdateQuantity}\n onRemove={onRemove}\n />\n ))}\n </div>\n );\n}\n\nexport function CartDrawer({ isOpen, onClose, className, labels = {} }: CartDrawerProps) {\n const CloseIcon = useIcon(\"close\");\n\n const {\n title = \"Shopping Cart\",\n emptyCartMessage = \"Your cart is empty\",\n continueShopping = \"Continue Shopping\",\n subtotal = \"Subtotal\",\n discount = \"Discount\",\n tax = \"Tax\",\n total = \"Total\",\n proceedToCheckout = \"Proceed to Checkout\",\n } = labels;\n\n const {\n drawerRef,\n closeButtonRef,\n isLoading,\n items,\n totals,\n currencyCode,\n handleKeyDown,\n handleUpdateQuantity,\n handleRemoveItem,\n } = useCartDrawer(isOpen, onClose);\n\n return (\n <>\n <div\n className={`fixed font-enad inset-0 bg-black/60 backdrop-blur-sm z-50 transition-opacity duration-300 motion-reduce:transition-none ${\n isOpen ? \"opacity-100\" : \"opacity-0 pointer-events-none\"\n }`}\n onClick={onClose}\n aria-hidden=\"true\"\n />\n\n <div\n ref={drawerRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n onKeyDown={handleKeyDown}\n className={`fixed top-0 right-0 h-full w-full md:w-[480px] bg-(--enad-surface) z-50 transform transition-transform duration-300 ease-in-out motion-reduce:transition-none ${\n isOpen ? \"translate-x-0\" : \"translate-x-full\"\n } ${className ?? \"\"}`}\n >\n <div className=\"flex flex-col h-full\">\n <div className=\"flex items-center justify-between p-6\">\n <h2 className=\"text-xl font-heading font-bold tracking-wider uppercase text-(--enad-text-primary-color)\">\n {title}\n </h2>\n <Button\n ref={closeButtonRef}\n variant=\"ghost\"\n size=\"icon\"\n onClick={onClose}\n aria-label=\"Close cart\"\n >\n <CloseIcon className=\"h-5 w-5\" />\n </Button>\n </div>\n\n <div className=\"flex-1 overflow-y-auto p-6\">\n <CartContent\n isLoading={isLoading}\n items={items}\n currencyCode={currencyCode}\n emptyCartMessage={emptyCartMessage}\n continueShopping={continueShopping}\n onClose={onClose}\n onUpdateQuantity={handleUpdateQuantity}\n onRemove={handleRemoveItem}\n />\n </div>\n\n {items.length > 0 && totals && (\n <CartTotals\n totals={totals}\n currencyCode={currencyCode}\n labels={{ subtotal, discount, tax, total, proceedToCheckout }}\n />\n )}\n </div>\n </div>\n </>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cart-drawer.mjs","names":[],"sources":["../../../../src/client/cart/components/cart-drawer.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useCallback } from \"react\";\nimport { useCart } from \"../../cart/hooks/useCart\";\nimport type { CartItem, CartTotals as CartTotalsType } from \"../../cart/types/adapter\";\nimport { useIcon } from \"../../icons/icon-context\";\nimport { Button } from \"../../ui/button\";\nimport { Price } from \"../../storefront/components/price\";\nimport { QuantityPicker } from \"../../storefront/product/quantity-picker\";\n\nexport interface CartDrawerProps {\n isOpen: boolean;\n onClose: () => void;\n className?: string;\n labels?: {\n title?: string;\n emptyCartMessage?: string;\n continueShopping?: string;\n subtotal?: string;\n discount?: string;\n tax?: string;\n total?: string;\n proceedToCheckout?: string;\n };\n}\n\nfunction CartLoadingSkeleton() {\n return (\n <div className=\"space-y-6\" aria-busy=\"true\" aria-label=\"Loading cart items\">\n {[1, 2, 3].map((i) => (\n <div key={i} className=\"flex gap-4 animate-pulse\">\n <div className=\"w-24 h-24 flex-shrink-0 bg-(--enad-border-color) rounded-(--enad-border-radius)\" />\n <div className=\"flex flex-1 flex-col gap-2\">\n <div className=\"h-4 w-3/4 bg-(--enad-border-color) rounded-(--enad-border-radius)\" />\n <div className=\"h-4 w-1/3 bg-(--enad-border-color) rounded-(--enad-border-radius)\" />\n <div className=\"h-4 w-1/4 bg-(--enad-border-color) rounded-(--enad-border-radius)\" />\n </div>\n </div>\n ))}\n </div>\n );\n}\n\nfunction CartEmptyState({\n message,\n onClose,\n buttonLabel,\n}: {\n message: string;\n onClose: () => void;\n buttonLabel: string;\n}) {\n return (\n <div className=\"flex flex-col items-center justify-center h-full text-center\">\n <p className=\"text-(--enad-text-muted-color) mb-4\">{message}</p>\n <Button onClick={onClose} variant=\"outlined\">\n {buttonLabel}\n </Button>\n </div>\n );\n}\n\nfunction CartItemImage({ imageUrl, alt }: { imageUrl?: string; alt: string }) {\n return (\n <div className=\"relative w-24 h-24 flex-shrink-0 bg-(--enad-border-color) rounded-(--enad-border-radius) overflow-hidden\">\n {imageUrl ? (\n <img src={imageUrl} alt={alt} className=\"object-cover\" />\n ) : (\n <div className=\"w-full h-full bg-(--enad-border-color)\" />\n )}\n </div>\n );\n}\n\nfunction CartItemDetails({\n item,\n currencyCode,\n onClose,\n onUpdateQuantity,\n onRemove,\n}: {\n item: CartItem;\n currencyCode: string;\n onClose: () => void;\n onUpdateQuantity: (itemId: string, quantity: number) => void;\n onRemove: (itemId: string) => void;\n}) {\n const TrashIcon = useIcon(\"trash\");\n\n return (\n <div className=\"flex flex-1 min-w-0 justify-between flex-col\">\n <div className=\"flex justify-between gap-2 mb-2\">\n <a\n href={`/products/${item.productSlug || item.productVariantId}`}\n className=\"font-medium text-sm text-(--enad-link-color) hover:text-(--enad-link-hover-color) transition-colors\"\n onClick={onClose}\n >\n {item.displayName}\n </a>\n <Button\n variant=\"plain\"\n size=\"icon\"\n className=\"h-5 w-5 flex-shrink-0\"\n onClick={() => onRemove(item.id)}\n aria-label={`Remove ${item.displayName}`}\n >\n <TrashIcon className=\"h-4 w-4\" />\n </Button>\n </div>\n\n <div>\n <Price\n amount={item.unitPrice.amount / 100}\n currency={currencyCode}\n className=\"text-sm text-(--enad-text-muted-color) mb-1\"\n />\n\n <QuantityPicker\n value={item.quantity}\n onChange={(qty) => onUpdateQuantity(item.id, qty)}\n size=\"sm\"\n />\n </div>\n </div>\n );\n}\n\nfunction CartItemRow({\n item,\n currencyCode,\n onClose,\n onUpdateQuantity,\n onRemove,\n}: {\n item: CartItem;\n currencyCode: string;\n onClose: () => void;\n onUpdateQuantity: (itemId: string, quantity: number) => void;\n onRemove: (itemId: string) => void;\n}) {\n return (\n <div className=\"flex gap-4\" role=\"listitem\">\n <CartItemImage imageUrl={item.imageUrl} alt={item.displayName} />\n <CartItemDetails\n item={item}\n currencyCode={currencyCode}\n onClose={onClose}\n onUpdateQuantity={onUpdateQuantity}\n onRemove={onRemove}\n />\n </div>\n );\n}\n\nfunction CartTotals({\n totals,\n currencyCode,\n labels,\n}: {\n totals: CartTotalsType;\n currencyCode: string;\n labels: {\n subtotal: string;\n discount: string;\n tax: string;\n total: string;\n proceedToCheckout: string;\n };\n}) {\n return (\n <div className=\"p-6 space-y-4\">\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-(--enad-text-muted-color)\">{labels.subtotal}</span>\n <Price amount={totals.subtotal.amount / 100} currency={currencyCode} />\n </div>\n\n {totals.discount.amount > 0 && (\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-(--enad-text-muted-color)\">{labels.discount}</span>\n <span className=\"text-(--enad-success-color)\">\n -<Price amount={totals.discount.amount / 100} currency={currencyCode} />\n </span>\n </div>\n )}\n\n {totals.tax.amount > 0 && (\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-(--enad-text-muted-color)\">{labels.tax}</span>\n <Price amount={totals.tax.amount / 100} currency={currencyCode} />\n </div>\n )}\n\n <div className=\"flex justify-between text-lg font-bold pt-4 border-t border-(--enad-border-color)\">\n <span className=\"text-(--enad-text-primary-color)\">{labels.total}</span>\n <Price amount={totals.total.amount / 100} currency={currencyCode} />\n </div>\n\n <Button className=\"w-full py-6 text-sm font-medium uppercase tracking-wider\" size=\"lg\">\n {labels.proceedToCheckout}\n </Button>\n </div>\n );\n}\n\nfunction useCartDrawer(isOpen: boolean, onClose: () => void) {\n const drawerRef = useRef<HTMLDivElement>(null);\n const closeButtonRef = useRef<HTMLButtonElement>(null);\n const { cart, isLoading, removeItem, updateItem } = useCart();\n\n useEffect(() => {\n if (isOpen) {\n const timer = setTimeout(() => closeButtonRef.current?.focus(), 100);\n return () => clearTimeout(timer);\n }\n }, [isOpen]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.stopPropagation();\n onClose();\n }\n },\n [onClose],\n );\n\n const handleUpdateQuantity = (itemId: string, newQuantity: number) => {\n updateItem({ itemId, quantity: newQuantity });\n };\n\n const handleRemoveItem = (itemId: string) => {\n removeItem({ itemId });\n };\n\n return {\n drawerRef,\n closeButtonRef,\n cart,\n isLoading,\n items: cart?.items || [],\n totals: cart?.totals,\n currencyCode: cart?.currencyCode || \"SEK\",\n handleKeyDown,\n handleUpdateQuantity,\n handleRemoveItem,\n };\n}\n\nfunction CartContent({\n isLoading,\n items,\n currencyCode,\n emptyCartMessage,\n continueShopping,\n onClose,\n onUpdateQuantity,\n onRemove,\n}: {\n isLoading: boolean;\n items: CartItem[];\n currencyCode: string;\n emptyCartMessage: string;\n continueShopping: string;\n onClose: () => void;\n onUpdateQuantity: (itemId: string, quantity: number) => void;\n onRemove: (itemId: string) => void;\n}) {\n if (isLoading) return <CartLoadingSkeleton />;\n if (items.length === 0) {\n return (\n <CartEmptyState message={emptyCartMessage} onClose={onClose} buttonLabel={continueShopping} />\n );\n }\n return (\n <div className=\"space-y-6\" role=\"list\" aria-label=\"Cart items\">\n {items.map((item) => (\n <CartItemRow\n key={item.id}\n item={item}\n currencyCode={currencyCode}\n onClose={onClose}\n onUpdateQuantity={onUpdateQuantity}\n onRemove={onRemove}\n />\n ))}\n </div>\n );\n}\n\nexport function CartDrawer({ isOpen, onClose, className, labels = {} }: CartDrawerProps) {\n const CloseIcon = useIcon(\"close\");\n\n const {\n title = \"Shopping Cart\",\n emptyCartMessage = \"Your cart is empty\",\n continueShopping = \"Continue Shopping\",\n subtotal = \"Subtotal\",\n discount = \"Discount\",\n tax = \"Tax\",\n total = \"Total\",\n proceedToCheckout = \"Proceed to Checkout\",\n } = labels;\n\n const {\n drawerRef,\n closeButtonRef,\n isLoading,\n items,\n totals,\n currencyCode,\n handleKeyDown,\n handleUpdateQuantity,\n handleRemoveItem,\n } = useCartDrawer(isOpen, onClose);\n\n return (\n <>\n <div\n className={`fixed font-enad inset-0 bg-black/60 backdrop-blur-sm z-50 transition-opacity duration-300 motion-reduce:transition-none ${\n isOpen ? \"opacity-100\" : \"opacity-0 pointer-events-none\"\n }`}\n onClick={onClose}\n aria-hidden=\"true\"\n />\n\n <div\n ref={drawerRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n onKeyDown={handleKeyDown}\n className={`fixed top-0 right-0 h-full w-full md:w-[480px] bg-(--enad-surface) z-50 transform transition-transform duration-300 ease-in-out motion-reduce:transition-none ${\n isOpen ? \"translate-x-0\" : \"translate-x-full\"\n } ${className ?? \"\"}`}\n >\n <div className=\"flex flex-col h-full\">\n <div className=\"flex items-center justify-between p-6\">\n <h2 className=\"text-xl font-heading font-bold tracking-wider uppercase text-(--enad-text-primary-color)\">\n {title}\n </h2>\n <Button\n ref={closeButtonRef}\n variant=\"plain\"\n size=\"icon\"\n onClick={onClose}\n aria-label=\"Close cart\"\n >\n <CloseIcon className=\"h-5 w-5\" />\n </Button>\n </div>\n\n <div className=\"flex-1 overflow-y-auto p-6\">\n <CartContent\n isLoading={isLoading}\n items={items}\n currencyCode={currencyCode}\n emptyCartMessage={emptyCartMessage}\n continueShopping={continueShopping}\n onClose={onClose}\n onUpdateQuantity={handleUpdateQuantity}\n onRemove={handleRemoveItem}\n />\n </div>\n\n {items.length > 0 && totals && (\n <CartTotals\n totals={totals}\n currencyCode={currencyCode}\n labels={{ subtotal, discount, tax, total, proceedToCheckout }}\n />\n )}\n </div>\n </div>\n </>\n );\n}\n"],"mappings":"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"}
|
|
@@ -11,7 +11,7 @@ function CartTrigger({ isOpen, onOpenChange, labels = {}, className = "" }) {
|
|
|
11
11
|
const itemCount = cart?.items?.reduce((total, item) => total + item.quantity, 0) ?? 0;
|
|
12
12
|
const ariaLabel = itemCount > 0 ? `${cartLabel} (${itemCount} ${itemCount === 1 ? "item" : "items"})` : cartLabel;
|
|
13
13
|
return /* @__PURE__ */ jsxs(Button, {
|
|
14
|
-
variant: "
|
|
14
|
+
variant: "plain",
|
|
15
15
|
className: `relative size-10 ${className}`,
|
|
16
16
|
onClick: () => onOpenChange(!isOpen),
|
|
17
17
|
"aria-label": ariaLabel,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cart-trigger.mjs","names":[],"sources":["../../../../src/client/cart/components/cart-trigger.tsx"],"sourcesContent":["\"use client\"
|
|
1
|
+
{"version":3,"file":"cart-trigger.mjs","names":[],"sources":["../../../../src/client/cart/components/cart-trigger.tsx"],"sourcesContent":["\"use client\";\n\nimport { Button } from \"../../ui/button\";\nimport { useIcon } from \"../../icons/icon-context\";\nimport { useCart } from \"../hooks/useCart\";\n\nexport interface CartTriggerProps {\n isOpen: boolean;\n onOpenChange: (open: boolean) => void;\n labels?: {\n cartLabel?: string;\n };\n className?: string;\n}\n\nexport function CartTrigger({\n isOpen,\n onOpenChange,\n labels = {},\n className = \"\",\n}: CartTriggerProps) {\n const CartIcon = useIcon(\"cart\");\n const { cartLabel = \"Cart\" } = labels;\n const { cart } = useCart();\n\n const itemCount = cart?.items?.reduce((total, item) => total + item.quantity, 0) ?? 0;\n\n const ariaLabel =\n itemCount > 0 ? `${cartLabel} (${itemCount} ${itemCount === 1 ? \"item\" : \"items\"})` : cartLabel;\n\n return (\n <Button\n variant=\"plain\"\n className={`relative size-10 ${className}`}\n onClick={() => onOpenChange(!isOpen)}\n aria-label={ariaLabel}\n >\n <CartIcon className=\"size-5\" />\n {itemCount > 0 && (\n <span className=\"absolute -top-1 -right-1 flex size-5 items-center justify-center rounded-full bg-primary text-primary-foreground text-xs font-bold\">\n {itemCount}\n </span>\n )}\n </Button>\n );\n}\n"],"mappings":";;;;;;AAeA,SAAgB,YAAY,EAC1B,QACA,cACA,SAAS,EAAE,EACX,YAAY,MACO;CACnB,MAAM,WAAW,QAAQ,OAAO;CAChC,MAAM,EAAE,YAAY,WAAW;CAC/B,MAAM,EAAE,SAAS,SAAS;CAE1B,MAAM,YAAY,MAAM,OAAO,QAAQ,OAAO,SAAS,QAAQ,KAAK,UAAU,EAAE,IAAI;CAEpF,MAAM,YACJ,YAAY,IAAI,GAAG,UAAU,IAAI,UAAU,GAAG,cAAc,IAAI,SAAS,QAAQ,KAAK;AAExF,QACE,qBAAC,QAAD;EACE,SAAQ;EACR,WAAW,oBAAoB;EAC/B,eAAe,aAAa,CAAC,OAAO;EACpC,cAAY;YAJd,CAME,oBAAC,UAAD,EAAU,WAAU,UAAW,CAAA,EAC9B,YAAY,KACX,oBAAC,QAAD;GAAM,WAAU;aACb;GACI,CAAA,CAEF"}
|
|
@@ -75,7 +75,7 @@ function CartSummary({ items, subtotal, tax, shipping, total, currency = "SEK",
|
|
|
75
75
|
className: "flex-1",
|
|
76
76
|
"aria-label": promoPlaceholder
|
|
77
77
|
}), /* @__PURE__ */ jsx(Button, {
|
|
78
|
-
variant: "
|
|
78
|
+
variant: "outlined",
|
|
79
79
|
onClick: () => onPromoApply(promoInput),
|
|
80
80
|
disabled: !promoInput.trim(),
|
|
81
81
|
children: promoApply
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cart-summary.mjs","names":["React"],"sources":["../../../../src/client/storefront/checkout/cart-summary.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../ui/utils\";\nimport { useIcon } from \"../../icons/icon-context\";\nimport { Price } from \"../components/price\";\nimport { QuantityPicker } from \"../product/quantity-picker\";\nimport { Button } from \"../../ui-resolver/button\";\nimport { Input } from \"../../ui-resolver/input\";\n\nexport interface CartLineItem {\n id: string;\n name: string;\n variant?: string;\n imageUrl?: string;\n price: number;\n originalPrice?: number;\n quantity: number;\n maxQuantity?: number;\n currency?: string;\n}\n\nexport interface CartSummaryProps {\n items: CartLineItem[];\n subtotal: number;\n tax?: number;\n shipping?: number;\n total: number;\n currency?: string;\n locale?: string;\n onQuantityChange?: (itemId: string, quantity: number) => void;\n onRemoveItem?: (itemId: string) => void;\n onPromoApply?: (code: string) => void;\n promoCode?: string;\n promoError?: string;\n promoDiscount?: number;\n className?: string;\n labels?: {\n subtotal?: string;\n tax?: string;\n shipping?: string;\n total?: string;\n discount?: string;\n promoPlaceholder?: string;\n promoApply?: string;\n freeShipping?: string;\n remove?: string;\n };\n}\n\nexport function CartSummary({\n items,\n subtotal,\n tax,\n shipping,\n total,\n currency = \"SEK\",\n locale,\n onQuantityChange,\n onRemoveItem,\n onPromoApply,\n promoCode: initialPromo = \"\",\n promoError,\n promoDiscount,\n className,\n labels = {},\n}: CartSummaryProps) {\n const {\n subtotal: subtotalLabel = \"Subtotal\",\n tax: taxLabel = \"Tax\",\n shipping: shippingLabel = \"Shipping\",\n total: totalLabel = \"Total\",\n discount: discountLabel = \"Discount\",\n promoPlaceholder = \"Promo code\",\n promoApply = \"Apply\",\n freeShipping = \"Free\",\n remove: removeLabel = \"Remove\",\n } = labels;\n\n const [promoInput, setPromoInput] = React.useState(initialPromo);\n const CloseIcon = useIcon(\"close\");\n\n return (\n <div className={cn(\"font-enad space-y-4\", className)}>\n {/* Line items */}\n <ul className=\"divide-y divide-(--enad-border-color)\">\n {items.map((item) => (\n <li key={item.id} className=\"flex gap-4 py-4 first:pt-0 last:pb-0\">\n {item.imageUrl && (\n <img\n src={item.imageUrl}\n alt={item.name}\n className=\"size-16 shrink-0 rounded-(--enad-card-radius) object-cover\"\n />\n )}\n\n <div className=\"flex flex-1 flex-col gap-1\">\n <div className=\"flex items-start justify-between gap-2\">\n <div>\n <p className=\"text-sm font-medium text-(--enad-text-primary-color)\">\n {item.name}\n </p>\n {item.variant && (\n <p className=\"text-xs text-(--enad-text-muted-color)\">{item.variant}</p>\n )}\n </div>\n <Price\n amount={item.price * item.quantity}\n original={item.originalPrice ? item.originalPrice * item.quantity : undefined}\n currency={item.currency ?? currency}\n locale={locale}\n className=\"text-sm font-medium\"\n />\n </div>\n\n <div className=\"flex items-center gap-3\">\n {onQuantityChange && (\n <QuantityPicker\n value={item.quantity}\n onChange={(qty) => onQuantityChange(item.id, qty)}\n min={1}\n max={item.maxQuantity}\n />\n )}\n {onRemoveItem && (\n <button\n type=\"button\"\n onClick={() => onRemoveItem(item.id)}\n className=\"rounded-sm text-xs text-(--enad-text-muted-color) hover:text-(--enad-error-color) transition-colors focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:outline-none\"\n aria-label={`${removeLabel} ${item.name}`}\n >\n <CloseIcon className=\"size-4\" />\n </button>\n )}\n </div>\n </div>\n </li>\n ))}\n </ul>\n\n {/* Promo code */}\n {onPromoApply && (\n <div className=\"space-y-1\">\n <div className=\"flex gap-2\">\n <Input\n value={promoInput}\n onChange={(e) => setPromoInput(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && promoInput.trim()) {\n e.preventDefault();\n onPromoApply(promoInput);\n }\n }}\n placeholder={promoPlaceholder}\n className=\"flex-1\"\n aria-label={promoPlaceholder}\n />\n <Button\n variant=\"
|
|
1
|
+
{"version":3,"file":"cart-summary.mjs","names":["React"],"sources":["../../../../src/client/storefront/checkout/cart-summary.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../ui/utils\";\nimport { useIcon } from \"../../icons/icon-context\";\nimport { Price } from \"../components/price\";\nimport { QuantityPicker } from \"../product/quantity-picker\";\nimport { Button } from \"../../ui-resolver/button\";\nimport { Input } from \"../../ui-resolver/input\";\n\nexport interface CartLineItem {\n id: string;\n name: string;\n variant?: string;\n imageUrl?: string;\n price: number;\n originalPrice?: number;\n quantity: number;\n maxQuantity?: number;\n currency?: string;\n}\n\nexport interface CartSummaryProps {\n items: CartLineItem[];\n subtotal: number;\n tax?: number;\n shipping?: number;\n total: number;\n currency?: string;\n locale?: string;\n onQuantityChange?: (itemId: string, quantity: number) => void;\n onRemoveItem?: (itemId: string) => void;\n onPromoApply?: (code: string) => void;\n promoCode?: string;\n promoError?: string;\n promoDiscount?: number;\n className?: string;\n labels?: {\n subtotal?: string;\n tax?: string;\n shipping?: string;\n total?: string;\n discount?: string;\n promoPlaceholder?: string;\n promoApply?: string;\n freeShipping?: string;\n remove?: string;\n };\n}\n\nexport function CartSummary({\n items,\n subtotal,\n tax,\n shipping,\n total,\n currency = \"SEK\",\n locale,\n onQuantityChange,\n onRemoveItem,\n onPromoApply,\n promoCode: initialPromo = \"\",\n promoError,\n promoDiscount,\n className,\n labels = {},\n}: CartSummaryProps) {\n const {\n subtotal: subtotalLabel = \"Subtotal\",\n tax: taxLabel = \"Tax\",\n shipping: shippingLabel = \"Shipping\",\n total: totalLabel = \"Total\",\n discount: discountLabel = \"Discount\",\n promoPlaceholder = \"Promo code\",\n promoApply = \"Apply\",\n freeShipping = \"Free\",\n remove: removeLabel = \"Remove\",\n } = labels;\n\n const [promoInput, setPromoInput] = React.useState(initialPromo);\n const CloseIcon = useIcon(\"close\");\n\n return (\n <div className={cn(\"font-enad space-y-4\", className)}>\n {/* Line items */}\n <ul className=\"divide-y divide-(--enad-border-color)\">\n {items.map((item) => (\n <li key={item.id} className=\"flex gap-4 py-4 first:pt-0 last:pb-0\">\n {item.imageUrl && (\n <img\n src={item.imageUrl}\n alt={item.name}\n className=\"size-16 shrink-0 rounded-(--enad-card-radius) object-cover\"\n />\n )}\n\n <div className=\"flex flex-1 flex-col gap-1\">\n <div className=\"flex items-start justify-between gap-2\">\n <div>\n <p className=\"text-sm font-medium text-(--enad-text-primary-color)\">\n {item.name}\n </p>\n {item.variant && (\n <p className=\"text-xs text-(--enad-text-muted-color)\">{item.variant}</p>\n )}\n </div>\n <Price\n amount={item.price * item.quantity}\n original={item.originalPrice ? item.originalPrice * item.quantity : undefined}\n currency={item.currency ?? currency}\n locale={locale}\n className=\"text-sm font-medium\"\n />\n </div>\n\n <div className=\"flex items-center gap-3\">\n {onQuantityChange && (\n <QuantityPicker\n value={item.quantity}\n onChange={(qty) => onQuantityChange(item.id, qty)}\n min={1}\n max={item.maxQuantity}\n />\n )}\n {onRemoveItem && (\n <button\n type=\"button\"\n onClick={() => onRemoveItem(item.id)}\n className=\"rounded-sm text-xs text-(--enad-text-muted-color) hover:text-(--enad-error-color) transition-colors focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:outline-none\"\n aria-label={`${removeLabel} ${item.name}`}\n >\n <CloseIcon className=\"size-4\" />\n </button>\n )}\n </div>\n </div>\n </li>\n ))}\n </ul>\n\n {/* Promo code */}\n {onPromoApply && (\n <div className=\"space-y-1\">\n <div className=\"flex gap-2\">\n <Input\n value={promoInput}\n onChange={(e) => setPromoInput(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && promoInput.trim()) {\n e.preventDefault();\n onPromoApply(promoInput);\n }\n }}\n placeholder={promoPlaceholder}\n className=\"flex-1\"\n aria-label={promoPlaceholder}\n />\n <Button\n variant=\"outlined\"\n onClick={() => onPromoApply(promoInput)}\n disabled={!promoInput.trim()}\n >\n {promoApply}\n </Button>\n </div>\n {promoError && <p className=\"text-xs text-(--enad-error-color)\">{promoError}</p>}\n </div>\n )}\n\n {/* Totals */}\n <div className=\"space-y-2 border-t border-(--enad-border-color) pt-4\">\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-(--enad-text-muted-color)\">{subtotalLabel}</span>\n <Price amount={subtotal} currency={currency} locale={locale} />\n </div>\n\n {promoDiscount != null && promoDiscount > 0 && (\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-(--enad-text-muted-color)\">{discountLabel}</span>\n <span className=\"text-(--enad-error-color)\">\n -<Price amount={promoDiscount} currency={currency} locale={locale} />\n </span>\n </div>\n )}\n\n {tax != null && (\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-(--enad-text-muted-color)\">{taxLabel}</span>\n <Price amount={tax} currency={currency} locale={locale} />\n </div>\n )}\n\n {shipping != null && (\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-(--enad-text-muted-color)\">{shippingLabel}</span>\n {shipping === 0 ? (\n <span className=\"text-sm font-medium text-(--enad-text-primary-color)\">\n {freeShipping}\n </span>\n ) : (\n <Price amount={shipping} currency={currency} locale={locale} />\n )}\n </div>\n )}\n\n <div className=\"flex justify-between border-t border-(--enad-border-color) pt-2 text-base font-semibold\">\n <span className=\"text-(--enad-text-primary-color)\">{totalLabel}</span>\n <Price amount={total} currency={currency} locale={locale} />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"language-selector.d.ts","names":[],"sources":["../../../../src/client/storefront/components/language-selector.tsx"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"language-selector.d.ts","names":[],"sources":["../../../../src/client/storefront/components/language-selector.tsx"],"mappings":";;;;iBA6BS,gBAAA,CAAA;EACP,SAAA;EACA,KAAA;EACA,aAAA;EACA,OAAA;EACA,IAAA;EACA,SAAA;EACA;AAAA,GACC,qBAAA,GAAqB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -15,7 +15,7 @@ function LanguageItemContent({ language, variant }) {
|
|
|
15
15
|
}), language.label]
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
|
-
function LanguageSelector({ languages, value, onValueChange, variant = "full", size = "
|
|
18
|
+
function LanguageSelector({ languages, value, onValueChange, variant = "full", size = "md", className, labels }) {
|
|
19
19
|
const GlobeIcon = useIcon("globe");
|
|
20
20
|
const selected = languages.find((l) => l.code === value);
|
|
21
21
|
return /* @__PURE__ */ jsxs(Select, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"language-selector.mjs","names":[],"sources":["../../../../src/client/storefront/components/language-selector.tsx"],"sourcesContent":["\"use client\"
|
|
1
|
+
{"version":3,"file":"language-selector.mjs","names":[],"sources":["../../../../src/client/storefront/components/language-selector.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { useIcon } from \"../../icons/icon-context\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"../../ui/select\";\nimport { cn } from \"../../ui/utils\";\nimport type { LanguageSelectorProps, LanguageOption } from \"../types\";\n\nfunction LanguageItemContent({\n language,\n variant,\n}: {\n language: LanguageOption;\n variant: \"code\" | \"full\" | \"icon\";\n}) {\n if (variant === \"code\") {\n return <span>{language.code.toUpperCase()}</span>;\n }\n\n return (\n <span className=\"flex items-center gap-2\">\n {variant === \"icon\" && language.icon && (\n <span className=\"inline-flex shrink-0\">{language.icon}</span>\n )}\n {language.label}\n </span>\n );\n}\n\nfunction LanguageSelector({\n languages,\n value,\n onValueChange,\n variant = \"full\",\n size = \"md\",\n className,\n labels,\n}: LanguageSelectorProps) {\n const GlobeIcon = useIcon(\"globe\");\n\n const selected = languages.find((l) => l.code === value);\n\n return (\n <Select value={value} onValueChange={onValueChange}>\n <SelectTrigger\n size={size}\n className={cn(\n variant === \"code\" && \"border-none shadow-none bg-transparent px-1.5 gap-1\",\n className,\n )}\n aria-label={labels?.changeLanguage ?? \"Change language\"}\n >\n <SelectValue>\n {selected && (\n <span className=\"flex items-center gap-2\">\n {variant === \"icon\" && selected.icon && (\n <span className=\"inline-flex shrink-0\">{selected.icon}</span>\n )}\n {variant === \"code\" && <GlobeIcon className=\"size-4\" />}\n {variant === \"code\" ? selected.code.toUpperCase() : selected.label}\n </span>\n )}\n </SelectValue>\n </SelectTrigger>\n <SelectContent position=\"popper\" align=\"end\">\n {languages.map((lang) => (\n <SelectItem key={lang.code} value={lang.code}>\n <LanguageItemContent language={lang} variant={variant} />\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n );\n}\n\nexport { LanguageSelector };\nexport type { LanguageSelectorProps, LanguageOption };\n"],"mappings":";;;;;;;AAQA,SAAS,oBAAoB,EAC3B,UACA,WAIC;AACD,KAAI,YAAY,OACd,QAAO,oBAAC,QAAD,EAAA,UAAO,SAAS,KAAK,aAAa,EAAQ,CAAA;AAGnD,QACE,qBAAC,QAAD;EAAM,WAAU;YAAhB,CACG,YAAY,UAAU,SAAS,QAC9B,oBAAC,QAAD;GAAM,WAAU;aAAwB,SAAS;GAAY,CAAA,EAE9D,SAAS,MACL;;;AAIX,SAAS,iBAAiB,EACxB,WACA,OACA,eACA,UAAU,QACV,OAAO,MACP,WACA,UACwB;CACxB,MAAM,YAAY,QAAQ,QAAQ;CAElC,MAAM,WAAW,UAAU,MAAM,MAAM,EAAE,SAAS,MAAM;AAExD,QACE,qBAAC,QAAD;EAAe;EAAsB;YAArC,CACE,oBAAC,eAAD;GACQ;GACN,WAAW,GACT,YAAY,UAAU,uDACtB,UACD;GACD,cAAY,QAAQ,kBAAkB;aAEtC,oBAAC,aAAD,EAAA,UACG,YACC,qBAAC,QAAD;IAAM,WAAU;cAAhB;KACG,YAAY,UAAU,SAAS,QAC9B,oBAAC,QAAD;MAAM,WAAU;gBAAwB,SAAS;MAAY,CAAA;KAE9D,YAAY,UAAU,oBAAC,WAAD,EAAW,WAAU,UAAW,CAAA;KACtD,YAAY,SAAS,SAAS,KAAK,aAAa,GAAG,SAAS;KACxD;OAEG,CAAA;GACA,CAAA,EAChB,oBAAC,eAAD;GAAe,UAAS;GAAS,OAAM;aACpC,UAAU,KAAK,SACd,oBAAC,YAAD;IAA4B,OAAO,KAAK;cACtC,oBAAC,qBAAD;KAAqB,UAAU;KAAe;KAAW,CAAA;IAC9C,EAFI,KAAK,KAET,CACb;GACY,CAAA,CACT"}
|
|
@@ -10,7 +10,7 @@ function FilterChip({ label, active, onClick, onRemove, className }) {
|
|
|
10
10
|
return /* @__PURE__ */ jsxs(Toggle, {
|
|
11
11
|
pressed: active,
|
|
12
12
|
onPressedChange: () => active && onRemove ? onRemove() : onClick(),
|
|
13
|
-
variant: "
|
|
13
|
+
variant: "outlined",
|
|
14
14
|
className: cn("enad-interactive rounded-[var(--enad-button-radius)] px-3 text-sm", active && "bg-primary text-primary-foreground hover:bg-primary-hover hover:text-primary-foreground", className),
|
|
15
15
|
"aria-label": active ? `Remove ${label}` : label,
|
|
16
16
|
children: [label, active && onRemove && /* @__PURE__ */ jsx(CloseIcon, { className: "relative size-3 hit-area-6" })]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filter-chip.mjs","names":[],"sources":["../../../../src/client/storefront/filters/filter-chip.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { useIcon } from \"../../icons/icon-context\";\nimport { Toggle } from \"../../ui-resolver/toggle\";\nimport { cn } from \"../../ui/utils\";\n\ninterface FilterChipProps {\n label: string;\n active: boolean;\n onClick: () => void;\n onRemove?: () => void;\n className?: string;\n}\n\nfunction FilterChip({ label, active, onClick, onRemove, className }: FilterChipProps) {\n const CloseIcon = useIcon(\"close\");\n return (\n <Toggle\n pressed={active}\n onPressedChange={() => (active && onRemove ? onRemove() : onClick())}\n variant=\"
|
|
1
|
+
{"version":3,"file":"filter-chip.mjs","names":[],"sources":["../../../../src/client/storefront/filters/filter-chip.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { useIcon } from \"../../icons/icon-context\";\nimport { Toggle } from \"../../ui-resolver/toggle\";\nimport { cn } from \"../../ui/utils\";\n\ninterface FilterChipProps {\n label: string;\n active: boolean;\n onClick: () => void;\n onRemove?: () => void;\n className?: string;\n}\n\nfunction FilterChip({ label, active, onClick, onRemove, className }: FilterChipProps) {\n const CloseIcon = useIcon(\"close\");\n return (\n <Toggle\n pressed={active}\n onPressedChange={() => (active && onRemove ? onRemove() : onClick())}\n variant=\"outlined\"\n className={cn(\n \"enad-interactive rounded-[var(--enad-button-radius)] px-3 text-sm\",\n active &&\n \"bg-primary text-primary-foreground hover:bg-primary-hover hover:text-primary-foreground\",\n className,\n )}\n aria-label={active ? `Remove ${label}` : label}\n >\n {label}\n {active && onRemove && <CloseIcon className=\"relative size-3 hit-area-6\" />}\n </Toggle>\n );\n}\n\nexport { FilterChip, type FilterChipProps };\n"],"mappings":";;;;;;;AAeA,SAAS,WAAW,EAAE,OAAO,QAAQ,SAAS,UAAU,aAA8B;CACpF,MAAM,YAAY,QAAQ,QAAQ;AAClC,QACE,qBAAC,QAAD;EACE,SAAS;EACT,uBAAwB,UAAU,WAAW,UAAU,GAAG,SAAS;EACnE,SAAQ;EACR,WAAW,GACT,qEACA,UACE,2FACF,UACD;EACD,cAAY,SAAS,UAAU,UAAU;YAV3C,CAYG,OACA,UAAU,YAAY,oBAAC,WAAD,EAAW,WAAU,8BAA+B,CAAA,CACpE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filter-panel.mjs","names":["React"],"sources":["../../../../src/client/storefront/filters/filter-panel.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { useIcon } from \"../../icons/icon-context\";\nimport { Button } from \"../../ui/button\";\nimport { Separator } from \"../../ui-resolver/separator\";\nimport { Sheet, SheetContent, SheetTitle } from \"../../ui-resolver/sheet\";\nimport { cn } from \"../../ui/utils\";\nimport { FilterGroup, type FilterOption } from \"./filter-group\";\n\ninterface FilterDefinition {\n key: string;\n title: string;\n type: \"checkbox\" | \"color\" | \"price\";\n options: FilterOption[];\n}\n\ntype ActiveFilters = Record<string, string[]>;\n\ninterface FilterPanelProps {\n filters: FilterDefinition[];\n activeFilters: ActiveFilters;\n onFilterChange: (key: string, selected: string[]) => void;\n productCount?: number;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n labels?: {\n title?: string;\n clearAll?: string;\n showResults?: string;\n };\n className?: string;\n}\n\nfunction FilterPanelContent({\n filters,\n activeFilters,\n onFilterChange,\n productCount,\n onClose,\n labels,\n}: {\n filters: FilterDefinition[];\n activeFilters: ActiveFilters;\n onFilterChange: (key: string, selected: string[]) => void;\n productCount?: number;\n onClose: () => void;\n labels?: FilterPanelProps[\"labels\"];\n}) {\n const SlidersIcon = useIcon(\"sliders\");\n const CloseIcon = useIcon(\"close\");\n const totalActive = Object.values(activeFilters).reduce(\n (sum, arr) => sum + arr.filter(Boolean).length,\n 0,\n );\n\n const clearAll = () => {\n for (const filter of filters) {\n onFilterChange(filter.key, []);\n }\n };\n\n return (\n <div className=\"flex h-full flex-col\">\n <div className=\"flex items-center justify-between p-4\">\n <div className=\"flex items-center gap-2\">\n <SlidersIcon className=\"size-5\" />\n <span className=\"text-sm font-medium\">{labels?.title ?? \"Filter & Sort\"}</span>\n {totalActive > 0 && (\n <span className=\"flex size-5 items-center justify-center rounded-full bg-primary text-xs text-primary-foreground\">\n {totalActive}\n </span>\n )}\n </div>\n <Button variant=\"
|
|
1
|
+
{"version":3,"file":"filter-panel.mjs","names":["React"],"sources":["../../../../src/client/storefront/filters/filter-panel.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { useIcon } from \"../../icons/icon-context\";\nimport { Button } from \"../../ui/button\";\nimport { Separator } from \"../../ui-resolver/separator\";\nimport { Sheet, SheetContent, SheetTitle } from \"../../ui-resolver/sheet\";\nimport { cn } from \"../../ui/utils\";\nimport { FilterGroup, type FilterOption } from \"./filter-group\";\n\ninterface FilterDefinition {\n key: string;\n title: string;\n type: \"checkbox\" | \"color\" | \"price\";\n options: FilterOption[];\n}\n\ntype ActiveFilters = Record<string, string[]>;\n\ninterface FilterPanelProps {\n filters: FilterDefinition[];\n activeFilters: ActiveFilters;\n onFilterChange: (key: string, selected: string[]) => void;\n productCount?: number;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n labels?: {\n title?: string;\n clearAll?: string;\n showResults?: string;\n };\n className?: string;\n}\n\nfunction FilterPanelContent({\n filters,\n activeFilters,\n onFilterChange,\n productCount,\n onClose,\n labels,\n}: {\n filters: FilterDefinition[];\n activeFilters: ActiveFilters;\n onFilterChange: (key: string, selected: string[]) => void;\n productCount?: number;\n onClose: () => void;\n labels?: FilterPanelProps[\"labels\"];\n}) {\n const SlidersIcon = useIcon(\"sliders\");\n const CloseIcon = useIcon(\"close\");\n const totalActive = Object.values(activeFilters).reduce(\n (sum, arr) => sum + arr.filter(Boolean).length,\n 0,\n );\n\n const clearAll = () => {\n for (const filter of filters) {\n onFilterChange(filter.key, []);\n }\n };\n\n return (\n <div className=\"flex h-full flex-col\">\n <div className=\"flex items-center justify-between p-4\">\n <div className=\"flex items-center gap-2\">\n <SlidersIcon className=\"size-5\" />\n <span className=\"text-sm font-medium\">{labels?.title ?? \"Filter & Sort\"}</span>\n {totalActive > 0 && (\n <span className=\"flex size-5 items-center justify-center rounded-full bg-primary text-xs text-primary-foreground\">\n {totalActive}\n </span>\n )}\n </div>\n <Button variant=\"plain\" size=\"icon\" onClick={onClose} aria-label=\"Close filters\">\n <CloseIcon />\n </Button>\n </div>\n\n <Separator />\n\n <div className=\"flex-1 overflow-y-auto p-4\">\n {totalActive > 0 && (\n <button\n type=\"button\"\n onClick={clearAll}\n className=\"mb-4 text-sm text-muted-foreground underline underline-offset-4 hover:text-foreground\"\n >\n {labels?.clearAll ?? \"Clear all\"}\n </button>\n )}\n\n {filters.map((filter) => (\n <React.Fragment key={filter.key}>\n <FilterGroup\n title={filter.title}\n type={filter.type}\n options={filter.options}\n selected={activeFilters[filter.key] ?? []}\n onChange={(selected) => onFilterChange(filter.key, selected)}\n />\n <Separator />\n </React.Fragment>\n ))}\n </div>\n\n {productCount != null && (\n <>\n <Separator />\n <div className=\"p-4\">\n <Button className=\"w-full\" onClick={onClose}>\n {labels?.showResults\n ? labels.showResults.replace(\"{count}\", String(productCount))\n : `Show ${productCount} results`}\n </Button>\n </div>\n </>\n )}\n </div>\n );\n}\n\nfunction FilterPanel({\n filters,\n activeFilters,\n onFilterChange,\n productCount,\n open,\n onOpenChange,\n labels,\n className,\n}: FilterPanelProps) {\n return (\n <>\n {/* Mobile: Sheet */}\n <div className={cn(\"md:hidden\", className)}>\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent side=\"left\" className=\"w-full max-w-sm p-0\">\n <SheetTitle className=\"sr-only\" showClose={false}>\n {labels?.title ?? \"Filters\"}\n </SheetTitle>\n <FilterPanelContent\n filters={filters}\n activeFilters={activeFilters}\n onFilterChange={onFilterChange}\n productCount={productCount}\n onClose={() => onOpenChange(false)}\n labels={labels}\n />\n </SheetContent>\n </Sheet>\n </div>\n\n {/* Desktop: Sidebar */}\n {open && (\n <aside className={cn(\"hidden w-full max-w-[280px] md:block\", className)}>\n <FilterPanelContent\n filters={filters}\n activeFilters={activeFilters}\n onFilterChange={onFilterChange}\n productCount={productCount}\n onClose={() => onOpenChange(false)}\n labels={labels}\n />\n </aside>\n )}\n </>\n );\n}\n\nexport { FilterPanel, type FilterPanelProps, type FilterDefinition, type ActiveFilters };\n"],"mappings":";;;;;;;;;;AAkCA,SAAS,mBAAmB,EAC1B,SACA,eACA,gBACA,cACA,SACA,UAQC;CACD,MAAM,cAAc,QAAQ,UAAU;CACtC,MAAM,YAAY,QAAQ,QAAQ;CAClC,MAAM,cAAc,OAAO,OAAO,cAAc,CAAC,QAC9C,KAAK,QAAQ,MAAM,IAAI,OAAO,QAAQ,CAAC,QACxC,EACD;CAED,MAAM,iBAAiB;AACrB,OAAK,MAAM,UAAU,QACnB,gBAAe,OAAO,KAAK,EAAE,CAAC;;AAIlC,QACE,qBAAC,OAAD;EAAK,WAAU;YAAf;GACE,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,qBAAC,OAAD;KAAK,WAAU;eAAf;MACE,oBAAC,aAAD,EAAa,WAAU,UAAW,CAAA;MAClC,oBAAC,QAAD;OAAM,WAAU;iBAAuB,QAAQ,SAAS;OAAuB,CAAA;MAC9E,cAAc,KACb,oBAAC,QAAD;OAAM,WAAU;iBACb;OACI,CAAA;MAEL;QACN,oBAAC,QAAD;KAAQ,SAAQ;KAAQ,MAAK;KAAO,SAAS;KAAS,cAAW;eAC/D,oBAAC,WAAD,EAAa,CAAA;KACN,CAAA,CACL;;GAEN,oBAAC,WAAD,EAAa,CAAA;GAEb,qBAAC,OAAD;IAAK,WAAU;cAAf,CACG,cAAc,KACb,oBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,WAAU;eAET,QAAQ,YAAY;KACd,CAAA,EAGV,QAAQ,KAAK,WACZ,qBAACA,QAAM,UAAP,EAAA,UAAA,CACE,oBAAC,aAAD;KACE,OAAO,OAAO;KACd,MAAM,OAAO;KACb,SAAS,OAAO;KAChB,UAAU,cAAc,OAAO,QAAQ,EAAE;KACzC,WAAW,aAAa,eAAe,OAAO,KAAK,SAAS;KAC5D,CAAA,EACF,oBAAC,WAAD,EAAa,CAAA,CACE,EAAA,EATI,OAAO,IASX,CACjB,CACE;;GAEL,gBAAgB,QACf,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,WAAD,EAAa,CAAA,EACb,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,QAAD;KAAQ,WAAU;KAAS,SAAS;eACjC,QAAQ,cACL,OAAO,YAAY,QAAQ,WAAW,OAAO,aAAa,CAAC,GAC3D,QAAQ,aAAa;KAClB,CAAA;IACL,CAAA,CACL,EAAA,CAAA;GAED;;;AAIV,SAAS,YAAY,EACnB,SACA,eACA,gBACA,cACA,MACA,cACA,QACA,aACmB;AACnB,QACE,qBAAA,UAAA,EAAA,UAAA,CAEE,oBAAC,OAAD;EAAK,WAAW,GAAG,aAAa,UAAU;YACxC,oBAAC,OAAD;GAAa;GAAoB;aAC/B,qBAAC,cAAD;IAAc,MAAK;IAAO,WAAU;cAApC,CACE,oBAAC,YAAD;KAAY,WAAU;KAAU,WAAW;eACxC,QAAQ,SAAS;KACP,CAAA,EACb,oBAAC,oBAAD;KACW;KACM;KACC;KACF;KACd,eAAe,aAAa,MAAM;KAC1B;KACR,CAAA,CACW;;GACT,CAAA;EACJ,CAAA,EAGL,QACC,oBAAC,SAAD;EAAO,WAAW,GAAG,wCAAwC,UAAU;YACrE,oBAAC,oBAAD;GACW;GACM;GACC;GACF;GACd,eAAe,aAAa,MAAM;GAC1B;GACR,CAAA;EACI,CAAA,CAET,EAAA,CAAA"}
|
|
@@ -14,7 +14,7 @@ function ToggleListView({ mode, onChange, className }) {
|
|
|
14
14
|
onValueChange: (value) => {
|
|
15
15
|
if (value) onChange(value);
|
|
16
16
|
},
|
|
17
|
-
variant: "
|
|
17
|
+
variant: "outlined",
|
|
18
18
|
className: cn(className),
|
|
19
19
|
"aria-label": "View mode",
|
|
20
20
|
children: [/* @__PURE__ */ jsx(ToggleGroupItem, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toggle-list-view.mjs","names":[],"sources":["../../../../src/client/storefront/filters/toggle-list-view.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { useIcon } from \"../../icons/icon-context\";\nimport { ToggleGroup, ToggleGroupItem } from \"../../ui-resolver/toggle-group\";\nimport { cn } from \"../../ui/utils\";\n\ninterface ToggleListViewProps {\n mode: \"grid\" | \"list\";\n onChange: (mode: \"grid\" | \"list\") => void;\n className?: string;\n}\n\nfunction ToggleListView({ mode, onChange, className }: ToggleListViewProps) {\n const GridIcon = useIcon(\"grid\");\n const ListIcon = useIcon(\"list\");\n return (\n <ToggleGroup\n type=\"single\"\n value={mode}\n onValueChange={(value) => {\n if (value) onChange(value as \"grid\" | \"list\");\n }}\n variant=\"
|
|
1
|
+
{"version":3,"file":"toggle-list-view.mjs","names":[],"sources":["../../../../src/client/storefront/filters/toggle-list-view.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { useIcon } from \"../../icons/icon-context\";\nimport { ToggleGroup, ToggleGroupItem } from \"../../ui-resolver/toggle-group\";\nimport { cn } from \"../../ui/utils\";\n\ninterface ToggleListViewProps {\n mode: \"grid\" | \"list\";\n onChange: (mode: \"grid\" | \"list\") => void;\n className?: string;\n}\n\nfunction ToggleListView({ mode, onChange, className }: ToggleListViewProps) {\n const GridIcon = useIcon(\"grid\");\n const ListIcon = useIcon(\"list\");\n return (\n <ToggleGroup\n type=\"single\"\n value={mode}\n onValueChange={(value) => {\n if (value) onChange(value as \"grid\" | \"list\");\n }}\n variant=\"outlined\"\n className={cn(className)}\n aria-label=\"View mode\"\n >\n <ToggleGroupItem value=\"grid\" aria-label=\"Grid view\" className=\"relative hit-area-2\">\n <GridIcon className=\"size-4\" />\n </ToggleGroupItem>\n <ToggleGroupItem value=\"list\" aria-label=\"List view\" className=\"relative hit-area-2\">\n <ListIcon className=\"size-4\" />\n </ToggleGroupItem>\n </ToggleGroup>\n );\n}\n\nexport { ToggleListView, type ToggleListViewProps };\n"],"mappings":";;;;;;;AAaA,SAAS,eAAe,EAAE,MAAM,UAAU,aAAkC;CAC1E,MAAM,WAAW,QAAQ,OAAO;CAChC,MAAM,WAAW,QAAQ,OAAO;AAChC,QACE,qBAAC,aAAD;EACE,MAAK;EACL,OAAO;EACP,gBAAgB,UAAU;AACxB,OAAI,MAAO,UAAS,MAAyB;;EAE/C,SAAQ;EACR,WAAW,GAAG,UAAU;EACxB,cAAW;YARb,CAUE,oBAAC,iBAAD;GAAiB,OAAM;GAAO,cAAW;GAAY,WAAU;aAC7D,oBAAC,UAAD,EAAU,WAAU,UAAW,CAAA;GACf,CAAA,EAClB,oBAAC,iBAAD;GAAiB,OAAM;GAAO,cAAW;GAAY,WAAU;aAC7D,oBAAC,UAAD,EAAU,WAAU,UAAW,CAAA;GACf,CAAA,CACN"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"promotion-bar.d.ts","names":[],"sources":["../../../../src/client/storefront/layout/promotion-bar.tsx"],"mappings":";;;;iBAQS,YAAA,CAAA;
|
|
1
|
+
{"version":3,"file":"promotion-bar.d.ts","names":[],"sources":["../../../../src/client/storefront/layout/promotion-bar.tsx"],"mappings":";;;;iBAQS,YAAA,CAAA;EAAe,OAAA;EAAgB,QAAA;EAAe,SAAA;EAAW;AAAA,GAAa,iBAAA,GAAiB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -27,7 +27,7 @@ function PromotionBar({ enabled = true, messages = [], onDismiss, className }) {
|
|
|
27
27
|
className: cn("relative flex items-center justify-center bg-accent text-accent-foreground px-4 py-2 text-center text-sm", className),
|
|
28
28
|
children: [
|
|
29
29
|
hasMultiple && /* @__PURE__ */ jsx(Button, {
|
|
30
|
-
variant: "
|
|
30
|
+
variant: "plain",
|
|
31
31
|
size: "icon",
|
|
32
32
|
className: "absolute left-1 size-7 text-accent-foreground hover:bg-accent-foreground/10",
|
|
33
33
|
onClick: prev,
|
|
@@ -39,7 +39,7 @@ function PromotionBar({ enabled = true, messages = [], onDismiss, className }) {
|
|
|
39
39
|
children: messages[currentIndex]
|
|
40
40
|
}),
|
|
41
41
|
hasMultiple && /* @__PURE__ */ jsx(Button, {
|
|
42
|
-
variant: "
|
|
42
|
+
variant: "plain",
|
|
43
43
|
size: "icon",
|
|
44
44
|
className: "absolute right-8 size-7 text-accent-foreground hover:bg-accent-foreground/10",
|
|
45
45
|
onClick: next,
|
|
@@ -47,7 +47,7 @@ function PromotionBar({ enabled = true, messages = [], onDismiss, className }) {
|
|
|
47
47
|
children: /* @__PURE__ */ jsx(ChevronRightIcon, { className: "size-4" })
|
|
48
48
|
}),
|
|
49
49
|
onDismiss && /* @__PURE__ */ jsx(Button, {
|
|
50
|
-
variant: "
|
|
50
|
+
variant: "plain",
|
|
51
51
|
size: "icon",
|
|
52
52
|
className: "absolute right-1 size-7 text-accent-foreground hover:bg-accent-foreground/10",
|
|
53
53
|
onClick: handleDismiss,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"promotion-bar.mjs","names":["React"],"sources":["../../../../src/client/storefront/layout/promotion-bar.tsx"],"sourcesContent":["\"use client\"
|
|
1
|
+
{"version":3,"file":"promotion-bar.mjs","names":["React"],"sources":["../../../../src/client/storefront/layout/promotion-bar.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { useIcon } from \"../../icons/icon-context\";\nimport { Button } from \"../../ui/button\";\nimport { cn } from \"../../ui/utils\";\nimport type { PromotionBarProps } from \"../types\";\n\nfunction PromotionBar({ enabled = true, messages = [], onDismiss, className }: PromotionBarProps) {\n const ChevronLeftIcon = useIcon(\"chevronLeft\");\n const ChevronRightIcon = useIcon(\"chevronRight\");\n const CloseIcon = useIcon(\"close\");\n\n const [currentIndex, setCurrentIndex] = React.useState(0);\n const [dismissed, setDismissed] = React.useState(false);\n\n if (!enabled || dismissed || messages.length === 0) return null;\n\n const hasMultiple = messages.length > 1;\n\n const prev = () => {\n setCurrentIndex((i) => (i - 1 + messages.length) % messages.length);\n };\n\n const next = () => {\n setCurrentIndex((i) => (i + 1) % messages.length);\n };\n\n const handleDismiss = () => {\n setDismissed(true);\n onDismiss?.();\n };\n\n return (\n <div\n className={cn(\n \"relative flex items-center justify-center bg-accent text-accent-foreground px-4 py-2 text-center text-sm\",\n className,\n )}\n >\n {hasMultiple && (\n <Button\n variant=\"plain\"\n size=\"icon\"\n className=\"absolute left-1 size-7 text-accent-foreground hover:bg-accent-foreground/10\"\n onClick={prev}\n aria-label=\"Previous message\"\n >\n <ChevronLeftIcon className=\"size-4\" />\n </Button>\n )}\n\n <span className=\"px-8\">{messages[currentIndex]}</span>\n\n {hasMultiple && (\n <Button\n variant=\"plain\"\n size=\"icon\"\n className=\"absolute right-8 size-7 text-accent-foreground hover:bg-accent-foreground/10\"\n onClick={next}\n aria-label=\"Next message\"\n >\n <ChevronRightIcon className=\"size-4\" />\n </Button>\n )}\n\n {onDismiss && (\n <Button\n variant=\"plain\"\n size=\"icon\"\n className=\"absolute right-1 size-7 text-accent-foreground hover:bg-accent-foreground/10\"\n onClick={handleDismiss}\n aria-label=\"Dismiss\"\n >\n <CloseIcon className=\"size-4\" />\n </Button>\n )}\n </div>\n );\n}\n\nexport { PromotionBar, type PromotionBarProps };\n"],"mappings":";;;;;;;AAQA,SAAS,aAAa,EAAE,UAAU,MAAM,WAAW,EAAE,EAAE,WAAW,aAAgC;CAChG,MAAM,kBAAkB,QAAQ,cAAc;CAC9C,MAAM,mBAAmB,QAAQ,eAAe;CAChD,MAAM,YAAY,QAAQ,QAAQ;CAElC,MAAM,CAAC,cAAc,mBAAmBA,QAAM,SAAS,EAAE;CACzD,MAAM,CAAC,WAAW,gBAAgBA,QAAM,SAAS,MAAM;AAEvD,KAAI,CAAC,WAAW,aAAa,SAAS,WAAW,EAAG,QAAO;CAE3D,MAAM,cAAc,SAAS,SAAS;CAEtC,MAAM,aAAa;AACjB,mBAAiB,OAAO,IAAI,IAAI,SAAS,UAAU,SAAS,OAAO;;CAGrE,MAAM,aAAa;AACjB,mBAAiB,OAAO,IAAI,KAAK,SAAS,OAAO;;CAGnD,MAAM,sBAAsB;AAC1B,eAAa,KAAK;AAClB,eAAa;;AAGf,QACE,qBAAC,OAAD;EACE,WAAW,GACT,4GACA,UACD;YAJH;GAMG,eACC,oBAAC,QAAD;IACE,SAAQ;IACR,MAAK;IACL,WAAU;IACV,SAAS;IACT,cAAW;cAEX,oBAAC,iBAAD,EAAiB,WAAU,UAAW,CAAA;IAC/B,CAAA;GAGX,oBAAC,QAAD;IAAM,WAAU;cAAQ,SAAS;IAAqB,CAAA;GAErD,eACC,oBAAC,QAAD;IACE,SAAQ;IACR,MAAK;IACL,WAAU;IACV,SAAS;IACT,cAAW;cAEX,oBAAC,kBAAD,EAAkB,WAAU,UAAW,CAAA;IAChC,CAAA;GAGV,aACC,oBAAC,QAAD;IACE,SAAQ;IACR,MAAK;IACL,WAAU;IACV,SAAS;IACT,cAAW;cAEX,oBAAC,WAAD,EAAW,WAAU,UAAW,CAAA;IACzB,CAAA;GAEP"}
|
|
@@ -3,8 +3,8 @@ import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
|
3
3
|
|
|
4
4
|
//#region src/client/storefront/primitives/button.d.ts
|
|
5
5
|
type StorefrontButtonVariant = "primary" | "secondary" | "outline" | "ghost" | "link" | "soft" | "inverse";
|
|
6
|
-
type StorefrontButtonSize = "sm" | "
|
|
7
|
-
interface StorefrontButtonProps extends Omit<React$1.ComponentProps<"button">, "ref"> {
|
|
6
|
+
type StorefrontButtonSize = "sm" | "md" | "lg";
|
|
7
|
+
interface StorefrontButtonProps extends Omit<React$1.ComponentProps<"button">, "ref" | "color"> {
|
|
8
8
|
variant?: StorefrontButtonVariant;
|
|
9
9
|
size?: StorefrontButtonSize;
|
|
10
10
|
href?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.d.ts","names":[],"sources":["../../../../src/client/storefront/primitives/button.tsx"],"mappings":";;;;KAMK,uBAAA;AAAA,KAQA,oBAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"button.d.ts","names":[],"sources":["../../../../src/client/storefront/primitives/button.tsx"],"mappings":";;;;KAMK,uBAAA;AAAA,KAQA,oBAAA;AAAA,UAYK,qBAAA,SAA8B,IAAA,CAAK,OAAA,CAAM,cAAA;EACjD,OAAA,GAAU,uBAAA;EACV,IAAA,GAAO,oBAAA;EACP,IAAA;EACA,OAAA;AAAA;AAAA,iBAGO,gBAAA,CAAA;EACP,OAAA;EACA,IAAA;EACA,IAAA;EACA,SAAA;EACA,QAAA;EACA,QAAA;EACA,OAAA;EAAA,GACG;AAAA,GACF,qBAAA,GAAqB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -5,15 +5,15 @@ import "react";
|
|
|
5
5
|
import { jsx } from "react/jsx-runtime";
|
|
6
6
|
//#region src/client/storefront/primitives/button.tsx
|
|
7
7
|
const variantMap = {
|
|
8
|
-
primary: "
|
|
8
|
+
primary: "solid",
|
|
9
9
|
secondary: "secondary",
|
|
10
|
-
outline: "
|
|
11
|
-
ghost: "
|
|
10
|
+
outline: "outlined",
|
|
11
|
+
ghost: "plain",
|
|
12
12
|
link: "link",
|
|
13
13
|
soft: "soft",
|
|
14
14
|
inverse: "inverse"
|
|
15
15
|
};
|
|
16
|
-
function StorefrontButton({ variant = "primary", size = "
|
|
16
|
+
function StorefrontButton({ variant = "primary", size = "md", href, className, children, disabled, asChild, ...props }) {
|
|
17
17
|
const mappedVariant = variantMap[variant];
|
|
18
18
|
if (href && !disabled) return /* @__PURE__ */ jsx(Button, {
|
|
19
19
|
variant: mappedVariant,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.mjs","names":["BaseButton"],"sources":["../../../../src/client/storefront/primitives/button.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Button as BaseButton } from \"../../ui-resolver/button\";\nimport { cn } from \"../../ui/utils\";\n\ntype StorefrontButtonVariant =\n | \"primary\"\n | \"secondary\"\n | \"outline\"\n | \"ghost\"\n | \"link\"\n | \"soft\"\n | \"inverse\";\ntype StorefrontButtonSize = \"sm\" | \"
|
|
1
|
+
{"version":3,"file":"button.mjs","names":["BaseButton"],"sources":["../../../../src/client/storefront/primitives/button.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Button as BaseButton, type ButtonVariant } from \"../../ui-resolver/button\";\nimport { cn } from \"../../ui/utils\";\n\ntype StorefrontButtonVariant =\n | \"primary\"\n | \"secondary\"\n | \"outline\"\n | \"ghost\"\n | \"link\"\n | \"soft\"\n | \"inverse\";\ntype StorefrontButtonSize = \"sm\" | \"md\" | \"lg\";\n\nconst variantMap: Record<StorefrontButtonVariant, ButtonVariant> = {\n primary: \"solid\",\n secondary: \"secondary\",\n outline: \"outlined\",\n ghost: \"plain\",\n link: \"link\",\n soft: \"soft\",\n inverse: \"inverse\",\n};\n\ninterface StorefrontButtonProps extends Omit<React.ComponentProps<\"button\">, \"ref\" | \"color\"> {\n variant?: StorefrontButtonVariant;\n size?: StorefrontButtonSize;\n href?: string;\n asChild?: boolean;\n}\n\nfunction StorefrontButton({\n variant = \"primary\",\n size = \"md\",\n href,\n className,\n children,\n disabled,\n asChild,\n ...props\n}: StorefrontButtonProps) {\n const mappedVariant = variantMap[variant];\n\n if (href && !disabled) {\n return (\n <BaseButton\n variant={mappedVariant}\n size={size}\n className={cn(\"enad-interactive\", className)}\n asChild\n >\n <a href={href} {...(props as React.ComponentProps<\"a\">)}>\n {children}\n </a>\n </BaseButton>\n );\n }\n\n return (\n <BaseButton\n variant={mappedVariant}\n size={size}\n className={cn(\"enad-interactive\", className)}\n disabled={disabled}\n asChild={asChild}\n {...props}\n >\n {children}\n </BaseButton>\n );\n}\n\nexport {\n StorefrontButton,\n type StorefrontButtonProps,\n type StorefrontButtonVariant,\n type StorefrontButtonSize,\n};\n"],"mappings":";;;;;;AAgBA,MAAM,aAA6D;CACjE,SAAS;CACT,WAAW;CACX,SAAS;CACT,OAAO;CACP,MAAM;CACN,MAAM;CACN,SAAS;CACV;AASD,SAAS,iBAAiB,EACxB,UAAU,WACV,OAAO,MACP,MACA,WACA,UACA,UACA,SACA,GAAG,SACqB;CACxB,MAAM,gBAAgB,WAAW;AAEjC,KAAI,QAAQ,CAAC,SACX,QACE,oBAACA,QAAD;EACE,SAAS;EACH;EACN,WAAW,GAAG,oBAAoB,UAAU;EAC5C,SAAA;YAEA,oBAAC,KAAD;GAAS;GAAM,GAAK;GACjB;GACC,CAAA;EACO,CAAA;AAIjB,QACE,oBAACA,QAAD;EACE,SAAS;EACH;EACN,WAAW,GAAG,oBAAoB,UAAU;EAClC;EACD;EACT,GAAI;EAEH;EACU,CAAA"}
|
|
@@ -7,7 +7,7 @@ interface StorefrontInputProps extends Omit<React$1.ComponentProps<"input">, "re
|
|
|
7
7
|
icon?: React$1.ReactNode;
|
|
8
8
|
onIconClick?: () => void;
|
|
9
9
|
/** Visual variant of the input field */
|
|
10
|
-
variant?: "
|
|
10
|
+
variant?: "outlined" | "plain";
|
|
11
11
|
/** External error message (from react-hook-form or server validation) */
|
|
12
12
|
error?: string;
|
|
13
13
|
/** Override default validation messages per constraint */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.mjs","names":["React"],"sources":["../../../../src/client/storefront/primitives/input.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Input } from \"../../ui-resolver/input\";\nimport { Label } from \"../../ui-resolver/label\";\nimport { cn } from \"../../ui/utils\";\n\nconst defaultMessages: Record<string, string> = {\n email: \"Please enter a valid email address\",\n password: \"Password is required\",\n tel: \"Please enter a valid phone number\",\n url: \"Please enter a valid URL\",\n number: \"Please enter a valid number\",\n};\n\ninterface StorefrontInputProps extends Omit<React.ComponentProps<\"input\">, \"ref\"> {\n label?: string;\n icon?: React.ReactNode;\n onIconClick?: () => void;\n /** Visual variant of the input field */\n variant?: \"
|
|
1
|
+
{"version":3,"file":"input.mjs","names":["React"],"sources":["../../../../src/client/storefront/primitives/input.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { Input } from \"../../ui-resolver/input\";\nimport { Label } from \"../../ui-resolver/label\";\nimport { cn } from \"../../ui/utils\";\n\nconst defaultMessages: Record<string, string> = {\n email: \"Please enter a valid email address\",\n password: \"Password is required\",\n tel: \"Please enter a valid phone number\",\n url: \"Please enter a valid URL\",\n number: \"Please enter a valid number\",\n};\n\ninterface StorefrontInputProps extends Omit<React.ComponentProps<\"input\">, \"ref\"> {\n label?: string;\n icon?: React.ReactNode;\n onIconClick?: () => void;\n /** Visual variant of the input field */\n variant?: \"outlined\" | \"plain\";\n /** External error message (from react-hook-form or server validation) */\n error?: string;\n /** Override default validation messages per constraint */\n validationMessages?: {\n required?: string;\n email?: string;\n minLength?: string;\n pattern?: string;\n };\n}\n\nfunction StorefrontInput({\n label,\n icon,\n onIconClick,\n variant,\n error: externalError,\n validationMessages,\n className,\n id: idProp,\n disabled,\n required,\n type,\n onChange: onChangeProp,\n onBlur: onBlurProp,\n ...props\n}: StorefrontInputProps) {\n const generatedId = React.useId();\n const id = idProp ?? generatedId;\n const errorId = `${id}-error`;\n\n const [nativeError, setNativeError] = React.useState<string | undefined>();\n const error = externalError ?? nativeError;\n\n const resolveMessage = React.useCallback(\n (validity: ValidityState): string => {\n if (validity.valueMissing) {\n return validationMessages?.required ?? \"This field is required\";\n }\n if (validity.typeMismatch) {\n const typeMsg = type ? (validationMessages?.email ?? defaultMessages[type]) : undefined;\n return typeMsg ?? \"Please enter a valid value\";\n }\n if (validity.tooShort) {\n return validationMessages?.minLength ?? \"Value is too short\";\n }\n if (validity.patternMismatch) {\n return validationMessages?.pattern ?? \"Please match the required format\";\n }\n return \"Please enter a valid value\";\n },\n [type, validationMessages],\n );\n\n const handleInvalid = React.useCallback(\n (e: React.InvalidEvent<HTMLInputElement>) => {\n e.preventDefault();\n setNativeError(resolveMessage(e.target.validity));\n },\n [resolveMessage],\n );\n\n const handleChange = React.useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n if (nativeError && e.target.validity.valid) {\n setNativeError(undefined);\n }\n onChangeProp?.(e);\n },\n [nativeError, onChangeProp],\n );\n\n const handleBlur = React.useCallback(\n (e: React.FocusEvent<HTMLInputElement>) => {\n if (e.target.value && !e.target.validity.valid) {\n setNativeError(resolveMessage(e.target.validity));\n }\n onBlurProp?.(e);\n },\n [resolveMessage, onBlurProp],\n );\n\n return (\n <div className={cn(\"flex flex-col gap-1.5\", className)}>\n {label && (\n <Label htmlFor={id} className=\"text-xs font-medium uppercase tracking-wide\">\n {label}\n {required && <span className=\"text-(--enad-error-color) ml-0.5\">*</span>}\n </Label>\n )}\n <div className=\"relative\">\n <Input\n id={id}\n type={type}\n variant={variant}\n disabled={disabled}\n required={required}\n aria-invalid={error ? true : undefined}\n aria-describedby={error ? errorId : undefined}\n className={icon ? \"pr-10\" : undefined}\n onInvalid={handleInvalid}\n {...props}\n onChange={handleChange}\n onBlur={handleBlur}\n />\n {icon && (\n <button\n type=\"button\"\n tabIndex={-1}\n disabled={disabled}\n onClick={onIconClick}\n className=\"absolute inset-y-0 right-0 flex items-center pr-3 text-muted-foreground hover:text-foreground disabled:pointer-events-none disabled:opacity-50\"\n >\n {icon}\n </button>\n )}\n </div>\n {error && (\n <p id={errorId} role=\"alert\" className=\"text-(--enad-error-color) text-sm\">\n {error}\n </p>\n )}\n </div>\n );\n}\n\nexport { StorefrontInput, type StorefrontInputProps };\n"],"mappings":";;;;;;;AAOA,MAAM,kBAA0C;CAC9C,OAAO;CACP,UAAU;CACV,KAAK;CACL,KAAK;CACL,QAAQ;CACT;AAmBD,SAAS,gBAAgB,EACvB,OACA,MACA,aACA,SACA,OAAO,eACP,oBACA,WACA,IAAI,QACJ,UACA,UACA,MACA,UAAU,cACV,QAAQ,YACR,GAAG,SACoB;CACvB,MAAM,cAAcA,QAAM,OAAO;CACjC,MAAM,KAAK,UAAU;CACrB,MAAM,UAAU,GAAG,GAAG;CAEtB,MAAM,CAAC,aAAa,kBAAkBA,QAAM,UAA8B;CAC1E,MAAM,QAAQ,iBAAiB;CAE/B,MAAM,iBAAiBA,QAAM,aAC1B,aAAoC;AACnC,MAAI,SAAS,aACX,QAAO,oBAAoB,YAAY;AAEzC,MAAI,SAAS,aAEX,SADgB,OAAQ,oBAAoB,SAAS,gBAAgB,QAAS,KAAA,MAC5D;AAEpB,MAAI,SAAS,SACX,QAAO,oBAAoB,aAAa;AAE1C,MAAI,SAAS,gBACX,QAAO,oBAAoB,WAAW;AAExC,SAAO;IAET,CAAC,MAAM,mBAAmB,CAC3B;CAED,MAAM,gBAAgBA,QAAM,aACzB,MAA4C;AAC3C,IAAE,gBAAgB;AAClB,iBAAe,eAAe,EAAE,OAAO,SAAS,CAAC;IAEnD,CAAC,eAAe,CACjB;CAED,MAAM,eAAeA,QAAM,aACxB,MAA2C;AAC1C,MAAI,eAAe,EAAE,OAAO,SAAS,MACnC,gBAAe,KAAA,EAAU;AAE3B,iBAAe,EAAE;IAEnB,CAAC,aAAa,aAAa,CAC5B;CAED,MAAM,aAAaA,QAAM,aACtB,MAA0C;AACzC,MAAI,EAAE,OAAO,SAAS,CAAC,EAAE,OAAO,SAAS,MACvC,gBAAe,eAAe,EAAE,OAAO,SAAS,CAAC;AAEnD,eAAa,EAAE;IAEjB,CAAC,gBAAgB,WAAW,CAC7B;AAED,QACE,qBAAC,OAAD;EAAK,WAAW,GAAG,yBAAyB,UAAU;YAAtD;GACG,SACC,qBAAC,OAAD;IAAO,SAAS;IAAI,WAAU;cAA9B,CACG,OACA,YAAY,oBAAC,QAAD;KAAM,WAAU;eAAmC;KAAQ,CAAA,CAClE;;GAEV,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,OAAD;KACM;KACE;KACG;KACC;KACA;KACV,gBAAc,QAAQ,OAAO,KAAA;KAC7B,oBAAkB,QAAQ,UAAU,KAAA;KACpC,WAAW,OAAO,UAAU,KAAA;KAC5B,WAAW;KACX,GAAI;KACJ,UAAU;KACV,QAAQ;KACR,CAAA,EACD,QACC,oBAAC,UAAD;KACE,MAAK;KACL,UAAU;KACA;KACV,SAAS;KACT,WAAU;eAET;KACM,CAAA,CAEP;;GACL,SACC,oBAAC,KAAD;IAAG,IAAI;IAAS,MAAK;IAAQ,WAAU;cACpC;IACC,CAAA;GAEF"}
|
|
@@ -22,7 +22,7 @@ function StorefrontPagination({ currentPage, totalPages, onPageChange, className
|
|
|
22
22
|
children: /* @__PURE__ */ jsxs(PaginationContent, { children: [
|
|
23
23
|
/* @__PURE__ */ jsx(PaginationItem, { children: /* @__PURE__ */ jsx(PaginationPrevious, {
|
|
24
24
|
href: "#",
|
|
25
|
-
size: "
|
|
25
|
+
size: "md",
|
|
26
26
|
onClick: (e) => {
|
|
27
27
|
e.preventDefault();
|
|
28
28
|
if (currentPage > 1) onPageChange(currentPage - 1);
|
|
@@ -42,7 +42,7 @@ function StorefrontPagination({ currentPage, totalPages, onPageChange, className
|
|
|
42
42
|
}) }, page)),
|
|
43
43
|
/* @__PURE__ */ jsx(PaginationItem, { children: /* @__PURE__ */ jsx(PaginationNext, {
|
|
44
44
|
href: "#",
|
|
45
|
-
size: "
|
|
45
|
+
size: "md",
|
|
46
46
|
onClick: (e) => {
|
|
47
47
|
e.preventDefault();
|
|
48
48
|
if (currentPage < totalPages) onPageChange(currentPage + 1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.mjs","names":[],"sources":["../../../../src/client/storefront/primitives/pagination.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport {\n Pagination,\n PaginationContent,\n PaginationEllipsis,\n PaginationItem,\n PaginationLink,\n PaginationNext,\n PaginationPrevious,\n} from \"../../ui-resolver/pagination\";\n\ninterface StorefrontPaginationProps {\n currentPage: number;\n totalPages: number;\n onPageChange: (page: number) => void;\n className?: string;\n}\n\nfunction getPageNumbers(current: number, total: number): (number | \"ellipsis\")[] {\n if (total <= 7) {\n return Array.from({ length: total }, (_, i) => i + 1);\n }\n\n const pages: (number | \"ellipsis\")[] = [1];\n\n if (current > 3) {\n pages.push(\"ellipsis\");\n }\n\n const start = Math.max(2, current - 1);\n const end = Math.min(total - 1, current + 1);\n\n for (let i = start; i <= end; i++) {\n pages.push(i);\n }\n\n if (current < total - 2) {\n pages.push(\"ellipsis\");\n }\n\n pages.push(total);\n return pages;\n}\n\nfunction StorefrontPagination({\n currentPage,\n totalPages,\n onPageChange,\n className,\n}: StorefrontPaginationProps) {\n if (totalPages <= 1) return null;\n\n const pages = getPageNumbers(currentPage, totalPages);\n\n return (\n <Pagination className={className}>\n <PaginationContent>\n <PaginationItem>\n <PaginationPrevious\n href=\"#\"\n size=\"
|
|
1
|
+
{"version":3,"file":"pagination.mjs","names":[],"sources":["../../../../src/client/storefront/primitives/pagination.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport {\n Pagination,\n PaginationContent,\n PaginationEllipsis,\n PaginationItem,\n PaginationLink,\n PaginationNext,\n PaginationPrevious,\n} from \"../../ui-resolver/pagination\";\n\ninterface StorefrontPaginationProps {\n currentPage: number;\n totalPages: number;\n onPageChange: (page: number) => void;\n className?: string;\n}\n\nfunction getPageNumbers(current: number, total: number): (number | \"ellipsis\")[] {\n if (total <= 7) {\n return Array.from({ length: total }, (_, i) => i + 1);\n }\n\n const pages: (number | \"ellipsis\")[] = [1];\n\n if (current > 3) {\n pages.push(\"ellipsis\");\n }\n\n const start = Math.max(2, current - 1);\n const end = Math.min(total - 1, current + 1);\n\n for (let i = start; i <= end; i++) {\n pages.push(i);\n }\n\n if (current < total - 2) {\n pages.push(\"ellipsis\");\n }\n\n pages.push(total);\n return pages;\n}\n\nfunction StorefrontPagination({\n currentPage,\n totalPages,\n onPageChange,\n className,\n}: StorefrontPaginationProps) {\n if (totalPages <= 1) return null;\n\n const pages = getPageNumbers(currentPage, totalPages);\n\n return (\n <Pagination className={className}>\n <PaginationContent>\n <PaginationItem>\n <PaginationPrevious\n href=\"#\"\n size=\"md\"\n onClick={(e) => {\n e.preventDefault();\n if (currentPage > 1) onPageChange(currentPage - 1);\n }}\n aria-disabled={currentPage <= 1}\n className={currentPage <= 1 ? \"pointer-events-none opacity-50\" : undefined}\n />\n </PaginationItem>\n\n {pages.map((page, i) =>\n page === \"ellipsis\" ? (\n <PaginationItem key={`ellipsis-${i}`}>\n <PaginationEllipsis />\n </PaginationItem>\n ) : (\n <PaginationItem key={page}>\n <PaginationLink\n href=\"#\"\n size=\"icon\"\n isActive={page === currentPage}\n onClick={(e) => {\n e.preventDefault();\n onPageChange(page);\n }}\n >\n {page}\n </PaginationLink>\n </PaginationItem>\n ),\n )}\n\n <PaginationItem>\n <PaginationNext\n href=\"#\"\n size=\"md\"\n onClick={(e) => {\n e.preventDefault();\n if (currentPage < totalPages) onPageChange(currentPage + 1);\n }}\n aria-disabled={currentPage >= totalPages}\n className={currentPage >= totalPages ? \"pointer-events-none opacity-50\" : undefined}\n />\n </PaginationItem>\n </PaginationContent>\n </Pagination>\n );\n}\n\nexport { StorefrontPagination, type StorefrontPaginationProps };\n"],"mappings":";;;;;AAoBA,SAAS,eAAe,SAAiB,OAAwC;AAC/E,KAAI,SAAS,EACX,QAAO,MAAM,KAAK,EAAE,QAAQ,OAAO,GAAG,GAAG,MAAM,IAAI,EAAE;CAGvD,MAAM,QAAiC,CAAC,EAAE;AAE1C,KAAI,UAAU,EACZ,OAAM,KAAK,WAAW;CAGxB,MAAM,QAAQ,KAAK,IAAI,GAAG,UAAU,EAAE;CACtC,MAAM,MAAM,KAAK,IAAI,QAAQ,GAAG,UAAU,EAAE;AAE5C,MAAK,IAAI,IAAI,OAAO,KAAK,KAAK,IAC5B,OAAM,KAAK,EAAE;AAGf,KAAI,UAAU,QAAQ,EACpB,OAAM,KAAK,WAAW;AAGxB,OAAM,KAAK,MAAM;AACjB,QAAO;;AAGT,SAAS,qBAAqB,EAC5B,aACA,YACA,cACA,aAC4B;AAC5B,KAAI,cAAc,EAAG,QAAO;CAE5B,MAAM,QAAQ,eAAe,aAAa,WAAW;AAErD,QACE,oBAAC,YAAD;EAAuB;YACrB,qBAAC,mBAAD,EAAA,UAAA;GACE,oBAAC,gBAAD,EAAA,UACE,oBAAC,oBAAD;IACE,MAAK;IACL,MAAK;IACL,UAAU,MAAM;AACd,OAAE,gBAAgB;AAClB,SAAI,cAAc,EAAG,cAAa,cAAc,EAAE;;IAEpD,iBAAe,eAAe;IAC9B,WAAW,eAAe,IAAI,mCAAmC,KAAA;IACjE,CAAA,EACa,CAAA;GAEhB,MAAM,KAAK,MAAM,MAChB,SAAS,aACP,oBAAC,gBAAD,EAAA,UACE,oBAAC,oBAAD,EAAsB,CAAA,EACP,EAFI,YAAY,IAEhB,GAEjB,oBAAC,gBAAD,EAAA,UACE,oBAAC,gBAAD;IACE,MAAK;IACL,MAAK;IACL,UAAU,SAAS;IACnB,UAAU,MAAM;AACd,OAAE,gBAAgB;AAClB,kBAAa,KAAK;;cAGnB;IACc,CAAA,EACF,EAZI,KAYJ,CAEpB;GAED,oBAAC,gBAAD,EAAA,UACE,oBAAC,gBAAD;IACE,MAAK;IACL,MAAK;IACL,UAAU,MAAM;AACd,OAAE,gBAAgB;AAClB,SAAI,cAAc,WAAY,cAAa,cAAc,EAAE;;IAE7D,iBAAe,eAAe;IAC9B,WAAW,eAAe,aAAa,mCAAmC,KAAA;IAC1E,CAAA,EACa,CAAA;GACC,EAAA,CAAA;EACT,CAAA"}
|
|
@@ -15,7 +15,7 @@ function QuantityPicker({ value, onChange, min = 1, max = 99, size = "default",
|
|
|
15
15
|
className: cn("inline-flex items-center gap-0 rounded-[var(--enad-input-radius)] border border-input", className),
|
|
16
16
|
children: [
|
|
17
17
|
/* @__PURE__ */ jsx(Button, {
|
|
18
|
-
variant: "
|
|
18
|
+
variant: "plain",
|
|
19
19
|
size: "icon",
|
|
20
20
|
onClick: () => onChange(Math.max(min, value - 1)),
|
|
21
21
|
disabled: atMin,
|
|
@@ -30,7 +30,7 @@ function QuantityPicker({ value, onChange, min = 1, max = 99, size = "default",
|
|
|
30
30
|
children: value
|
|
31
31
|
}),
|
|
32
32
|
/* @__PURE__ */ jsx(Button, {
|
|
33
|
-
variant: "
|
|
33
|
+
variant: "plain",
|
|
34
34
|
size: "icon",
|
|
35
35
|
onClick: () => onChange(Math.min(max, value + 1)),
|
|
36
36
|
disabled: atMax,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quantity-picker.mjs","names":[],"sources":["../../../../src/client/storefront/product/quantity-picker.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { useIcon } from \"../../icons/icon-context\";\nimport { Button } from \"../../ui/button\";\nimport { cn } from \"../../ui/utils\";\n\ninterface QuantityPickerProps {\n value: number;\n onChange: (value: number) => void;\n min?: number;\n max?: number;\n size?: \"sm\" | \"default\";\n className?: string;\n}\n\nfunction QuantityPicker({\n value,\n onChange,\n min = 1,\n max = 99,\n size = \"default\",\n className,\n}: QuantityPickerProps) {\n const MinusIcon = useIcon(\"minus\");\n const PlusIcon = useIcon(\"plus\");\n const atMin = value <= min;\n const atMax = value >= max;\n\n const compact = size === \"sm\";\n\n return (\n <div\n className={cn(\n \"inline-flex items-center gap-0 rounded-[var(--enad-input-radius)] border border-input\",\n className,\n )}\n >\n <Button\n variant=\"
|
|
1
|
+
{"version":3,"file":"quantity-picker.mjs","names":[],"sources":["../../../../src/client/storefront/product/quantity-picker.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { useIcon } from \"../../icons/icon-context\";\nimport { Button } from \"../../ui/button\";\nimport { cn } from \"../../ui/utils\";\n\ninterface QuantityPickerProps {\n value: number;\n onChange: (value: number) => void;\n min?: number;\n max?: number;\n size?: \"sm\" | \"default\";\n className?: string;\n}\n\nfunction QuantityPicker({\n value,\n onChange,\n min = 1,\n max = 99,\n size = \"default\",\n className,\n}: QuantityPickerProps) {\n const MinusIcon = useIcon(\"minus\");\n const PlusIcon = useIcon(\"plus\");\n const atMin = value <= min;\n const atMax = value >= max;\n\n const compact = size === \"sm\";\n\n return (\n <div\n className={cn(\n \"inline-flex items-center gap-0 rounded-[var(--enad-input-radius)] border border-input\",\n className,\n )}\n >\n <Button\n variant=\"plain\"\n size=\"icon\"\n onClick={() => onChange(Math.max(min, value - 1))}\n disabled={atMin}\n aria-label=\"Decrease quantity\"\n className={cn(\n \"rounded-none rounded-l-[var(--enad-input-radius)]\",\n compact ? \"h-5 w-5\" : \"hit-area-y-1\",\n )}\n >\n <MinusIcon className={compact ? \"size-3\" : \"size-4\"} />\n </Button>\n\n <span\n className={cn(\n \"flex items-center justify-center font-medium tabular-nums\",\n compact ? \"h-5 w-8 text-xs\" : \"size-9 text-sm\",\n )}\n aria-live=\"polite\"\n aria-label={`Quantity: ${value}`}\n >\n {value}\n </span>\n\n <Button\n variant=\"plain\"\n size=\"icon\"\n onClick={() => onChange(Math.min(max, value + 1))}\n disabled={atMax}\n aria-label=\"Increase quantity\"\n className={cn(\n \"rounded-none rounded-r-[var(--enad-input-radius)]\",\n compact ? \"h-5 w-5\" : \"hit-area-y-1\",\n )}\n >\n <PlusIcon className={compact ? \"size-3\" : \"size-4\"} />\n </Button>\n </div>\n );\n}\n\nexport { QuantityPicker, type QuantityPickerProps };\n"],"mappings":";;;;;;;AAgBA,SAAS,eAAe,EACtB,OACA,UACA,MAAM,GACN,MAAM,IACN,OAAO,WACP,aACsB;CACtB,MAAM,YAAY,QAAQ,QAAQ;CAClC,MAAM,WAAW,QAAQ,OAAO;CAChC,MAAM,QAAQ,SAAS;CACvB,MAAM,QAAQ,SAAS;CAEvB,MAAM,UAAU,SAAS;AAEzB,QACE,qBAAC,OAAD;EACE,WAAW,GACT,yFACA,UACD;YAJH;GAME,oBAAC,QAAD;IACE,SAAQ;IACR,MAAK;IACL,eAAe,SAAS,KAAK,IAAI,KAAK,QAAQ,EAAE,CAAC;IACjD,UAAU;IACV,cAAW;IACX,WAAW,GACT,qDACA,UAAU,YAAY,eACvB;cAED,oBAAC,WAAD,EAAW,WAAW,UAAU,WAAW,UAAY,CAAA;IAChD,CAAA;GAET,oBAAC,QAAD;IACE,WAAW,GACT,6DACA,UAAU,oBAAoB,iBAC/B;IACD,aAAU;IACV,cAAY,aAAa;cAExB;IACI,CAAA;GAEP,oBAAC,QAAD;IACE,SAAQ;IACR,MAAK;IACL,eAAe,SAAS,KAAK,IAAI,KAAK,QAAQ,EAAE,CAAC;IACjD,UAAU;IACV,cAAW;IACX,WAAW,GACT,qDACA,UAAU,YAAY,eACvB;cAED,oBAAC,UAAD,EAAU,WAAW,UAAU,WAAW,UAAY,CAAA;IAC/C,CAAA;GACL"}
|