@instruments/materia-ui 0.4.3 → 0.4.5
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/components/swatch/swatch-tile-styles.d.ts +5 -1
- package/dist/components/swatch/swatch-tile-styles.js +7 -3
- package/dist/compositions/product-card/product-card-image.js +5 -4
- package/dist/compositions/product-card/product-card-radius.d.ts +9 -0
- package/dist/compositions/product-card/product-card-radius.js +9 -0
- package/dist/compositions/product-card/product-card-skeleton.js +2 -1
- package/dist/compositions/product-card/product-card-swatch.js +2 -1
- package/package.json +1 -1
|
@@ -3,7 +3,11 @@ import type { SwatchTileSizeProp, SwatchTileVariant, TileSwatchProps } from "./s
|
|
|
3
3
|
type SizeTier = "tiny" | "small" | "standard";
|
|
4
4
|
declare const isTileSizeScale: (size: SwatchTileSizeProp) => size is SwatchTileSize;
|
|
5
5
|
declare const ringShadowMap: Record<SizeTier, string>;
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Radius of the padded ring and frame ring, concentric with the border. A bare
|
|
8
|
+
* tile has no border, so its rings sit on its edge and take whatever corner it
|
|
9
|
+
* has, including one set through `className`.
|
|
10
|
+
*/
|
|
7
11
|
declare const getInnerRingRadius: ({ compact, isCard, tier, }: {
|
|
8
12
|
compact: boolean;
|
|
9
13
|
isCard: boolean;
|
|
@@ -68,8 +68,12 @@ const pickRadius = (map, bare, tier, isCard, compactRadius) => {
|
|
|
68
68
|
}
|
|
69
69
|
return map[tier][compactRadius ? "compact" : "normal"];
|
|
70
70
|
};
|
|
71
|
-
/**
|
|
72
|
-
|
|
71
|
+
/**
|
|
72
|
+
* Radius of the padded ring and frame ring, concentric with the border. A bare
|
|
73
|
+
* tile has no border, so its rings sit on its edge and take whatever corner it
|
|
74
|
+
* has, including one set through `className`.
|
|
75
|
+
*/
|
|
76
|
+
const getInnerRingRadius = ({ compact, isCard, tier, }) => pickRadius(innerRingRadiusMap, "rounded-[inherit]", tier, isCard, compact);
|
|
73
77
|
/** Apply the tile's boolean, size and variant defaults. */
|
|
74
78
|
const withTileDefaults = (input) => ({
|
|
75
79
|
compact: input.compactRadius ?? false,
|
|
@@ -111,7 +115,7 @@ const buildTileClasses = (state, { borderColor, className, }) => {
|
|
|
111
115
|
// Round the image element itself (not just clip via `overflow-hidden`):
|
|
112
116
|
// WebKit clips in-flow replaced elements inconsistently, leaving square
|
|
113
117
|
// corners that poke past the radius.
|
|
114
|
-
pickRadius(innerImgRadiusMap, "[&_img]:rounded-
|
|
118
|
+
pickRadius(innerImgRadiusMap, "[&_img]:rounded-[inherit]", tier, isCard, compact), isCard && (dotted ? "border-2" : containerBorderMap[tier]), isCard && "shadow-xs", !isCard && "bg-muted", isCard && "bg-card", isCard && (dotted ? "border-dotted" : "border-solid"), getBorderClasses(isCard, borderColor, selected), muted && "opacity-50 hover:opacity-100", isCard && "transition-border-shadow-opacity duration-quick ease-out", disabled && "cursor-not-allowed opacity-50", size === "fluid" && "w-full", isTileSizeScale(size) && swatchTileSizeMap[size], className);
|
|
115
119
|
};
|
|
116
120
|
const buildTileStyle = (state, { borderColor, color, style, }) => {
|
|
117
121
|
const { size } = state;
|
|
@@ -6,6 +6,7 @@ import { cn } from "@instruments/materia-ui/utils/cn";
|
|
|
6
6
|
import { memo, useMemo } from "react";
|
|
7
7
|
import { ProductCardAvailabilityStatus } from "./product-card-availability.js";
|
|
8
8
|
import { useProductCard } from "./product-card-context.js";
|
|
9
|
+
import { PRODUCT_CARD_IMAGE_RADIUS, PRODUCT_CARD_SWATCH_IMAGE_RADIUS, } from "./product-card-radius.js";
|
|
9
10
|
/**
|
|
10
11
|
* Handle used when no `dragAdapter` is provided: a static, non-draggable
|
|
11
12
|
* image. Module-level so its identity is stable across renders.
|
|
@@ -24,7 +25,7 @@ const NoPhotographyState = ({ className, inspiration, productName, }) => {
|
|
|
24
25
|
if (inspiration) {
|
|
25
26
|
return (_jsx("output", { "aria-label": `Photography unavailable for ${productName}`, className: cn("bg-muted/45 absolute inset-0 overflow-hidden rounded-3xl", className), "data-component": "product-card-image-unavailable" }));
|
|
26
27
|
}
|
|
27
|
-
return (_jsx("output", { "aria-label": `Photography unavailable for ${productName}`, className: cn("block w-full @[180px]/product-card:px-4 @[180px]/product-card:pt-4", className), "data-component": "product-card-image-unavailable", children: _jsx("span", { className: "bg-muted/45 block aspect-square w-full overflow-hidden
|
|
28
|
+
return (_jsx("output", { "aria-label": `Photography unavailable for ${productName}`, className: cn("block w-full @[180px]/product-card:px-4 @[180px]/product-card:pt-4", className), "data-component": "product-card-image-unavailable", children: _jsx("span", { className: cn("bg-muted/45 block aspect-square w-full overflow-hidden", PRODUCT_CARD_IMAGE_RADIUS) }) }));
|
|
28
29
|
};
|
|
29
30
|
/**
|
|
30
31
|
* The photograph itself, filling the frame `DraggableImage` insets - the
|
|
@@ -46,7 +47,7 @@ const ImageContent = ({ imageSrc, hoverImageSrc, showingInstallShot, productName
|
|
|
46
47
|
productImageFade = showingInstallShot ? "opacity-0" : "";
|
|
47
48
|
installImageFade = showingInstallShot ? "opacity-100" : "opacity-0";
|
|
48
49
|
}
|
|
49
|
-
return (_jsx(Box, { className: "absolute inset-0 overflow-hidden", children: _jsxs(MediaFrame, { className: "size-full
|
|
50
|
+
return (_jsx(Box, { className: "absolute inset-0 overflow-hidden", children: _jsxs(MediaFrame, { className: cn("size-full", PRODUCT_CARD_IMAGE_RADIUS), children: [renderImage({
|
|
50
51
|
alt: `${productName} - Product image`,
|
|
51
52
|
className: cn("object-cover", hasHoverImage && "duration-normal transition-opacity ease-out", hasHoverImage && productImageFade),
|
|
52
53
|
draggable: false,
|
|
@@ -89,11 +90,11 @@ const DraggableImage = ({ className, imageSrc, hoverImageSrc, variantName, showS
|
|
|
89
90
|
scale: dragging ? 0.9 : 1,
|
|
90
91
|
touchAction: "none",
|
|
91
92
|
transition: "opacity 300ms ease-out, scale 300ms ease-out",
|
|
92
|
-
}, ...dragListeners, ...props, children: _jsxs(MediaFrame, { className: "@[180px]/product-card:bg-card relative aspect-square w-full
|
|
93
|
+
}, ...dragListeners, ...props, children: _jsxs(MediaFrame, { className: cn("@[180px]/product-card:bg-card relative aspect-square w-full bg-gray-100", PRODUCT_CARD_IMAGE_RADIUS), children: [_jsx(ImageContent, { hoverImageSrc: hoverImageSrc, imageSrc: imageSrc, showingInstallShot: showingInstallShot, priority: priority, productName: variantName, sizes: sizes }), shouldShowSimilarityScore ? (_jsx(Box, { className: "absolute right-2 bottom-2 z-10", children: _jsxs(Box, { as: "span", className: "glass-media text-micro rounded px-1.5 py-0.5 text-white/70", children: [(similarityScore * 100).toFixed(0), "%"] }) })) : null, _jsx(ProductCardAvailabilityStatus, {})] }) }));
|
|
93
94
|
};
|
|
94
95
|
const SwatchImage = ({ className, dragListeners, imageSizes, isDragging, mainImage, priority, ref, ...props }) => {
|
|
95
96
|
const { currentVariant, renderImage } = useProductCard();
|
|
96
|
-
return (_jsxs(Box, { className: cn("relative size-full overflow-hidden
|
|
97
|
+
return (_jsxs(Box, { className: cn("relative size-full overflow-hidden bg-transparent", PRODUCT_CARD_SWATCH_IMAGE_RADIUS, className), "data-component": "product-card-image", onClickCapture: (e) => {
|
|
97
98
|
if (isDragging) {
|
|
98
99
|
e.preventDefault();
|
|
99
100
|
e.stopPropagation();
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The photograph's corner, concentric with the card's. Below 180px the
|
|
3
|
+
* photograph is the card and takes its corner; from 180px it sits 16px inside
|
|
4
|
+
* the card, so its corner is the card's less 16px (8px, then 20px once the card
|
|
5
|
+
* takes the 4xl corner at 240px).
|
|
6
|
+
*/
|
|
7
|
+
export declare const PRODUCT_CARD_IMAGE_RADIUS = "rounded-3xl @[180px]/product-card:rounded-[calc(var(--radius-3xl)_-_1rem)] @[240px]/product-card:rounded-[calc(var(--radius-4xl)_-_1rem)]";
|
|
8
|
+
/** The swatch tile's photograph, 4px inside the tile's 3xl corner. */
|
|
9
|
+
export declare const PRODUCT_CARD_SWATCH_IMAGE_RADIUS = "rounded-[calc(var(--radius-3xl)_-_0.25rem)]";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The photograph's corner, concentric with the card's. Below 180px the
|
|
3
|
+
* photograph is the card and takes its corner; from 180px it sits 16px inside
|
|
4
|
+
* the card, so its corner is the card's less 16px (8px, then 20px once the card
|
|
5
|
+
* takes the 4xl corner at 240px).
|
|
6
|
+
*/
|
|
7
|
+
export const PRODUCT_CARD_IMAGE_RADIUS = "rounded-3xl @[180px]/product-card:rounded-[calc(var(--radius-3xl)_-_1rem)] @[240px]/product-card:rounded-[calc(var(--radius-4xl)_-_1rem)]";
|
|
8
|
+
/** The swatch tile's photograph, 4px inside the tile's 3xl corner. */
|
|
9
|
+
export const PRODUCT_CARD_SWATCH_IMAGE_RADIUS = "rounded-[calc(var(--radius-3xl)_-_0.25rem)]";
|
|
@@ -3,6 +3,7 @@ import { Box } from "@instruments/materia-ui/components/box";
|
|
|
3
3
|
import { Skeleton } from "@instruments/materia-ui/components/skeleton";
|
|
4
4
|
import { HStack, VStack } from "@instruments/materia-ui/components/stack";
|
|
5
5
|
import { cn } from "@instruments/materia-ui/utils/cn";
|
|
6
|
+
import { PRODUCT_CARD_IMAGE_RADIUS } from "./product-card-radius.js";
|
|
6
7
|
/** The fifth dot, which the card itself only shows from 240px up. */
|
|
7
8
|
const SWATCH_PLACEHOLDERS = [0, 1, 2, 3, 4];
|
|
8
9
|
const SwatchRow = () => (_jsx(HStack, { className: "min-h-5 gap-2.5", children: SWATCH_PLACEHOLDERS.map((index) => (_jsx(Skeleton, { className: cn("size-5 rounded-full", index === SWATCH_PLACEHOLDERS.length - 1 &&
|
|
@@ -29,4 +30,4 @@ const SwatchRow = () => (_jsx(HStack, { className: "min-h-5 gap-2.5", children:
|
|
|
29
30
|
* misjudged the common case instead. A grid that turns either off on every
|
|
30
31
|
* card passes the same flags here.
|
|
31
32
|
*/
|
|
32
|
-
export const ProductCardSkeleton = ({ className, showAddToCart = true, showSwatches = true, style, }) => (_jsxs(Box, { className: cn("@container/product-card w-full", className), style: style, children: [_jsxs(VStack, { className: "flex @[180px]/product-card:hidden", gap: "none", children: [_jsx(Skeleton, { className: "aspect-square w-full rounded-3xl" }), _jsxs(VStack, { className: "gap-2.5 px-1.5 py-2", gap: "none", children: [_jsxs(VStack, { className: "gap-1 px-0.5", gap: "none", children: [_jsxs(VStack, { className: "gap-0.5", gap: "none", children: [_jsx(Skeleton, { className: "h-5 w-3/5" }), _jsx(Skeleton, { className: "h-4 w-4/5" })] }), _jsx(Skeleton, { className: "h-4 w-2/3" }), showSwatches ? _jsx(SwatchRow, {}) : null] }), showAddToCart ? (_jsx(Skeleton, { className: "h-9 w-full rounded-full" })) : null] })] }), _jsxs(VStack, { className: "bg-card hidden overflow-hidden rounded-3xl shadow-xs @[180px]/product-card:flex @[240px]/product-card:rounded-4xl", gap: "none", children: [_jsx(Box, { className: "w-full px-4 pt-4", children: _jsx(Skeleton, { className: "aspect-square w-full
|
|
33
|
+
export const ProductCardSkeleton = ({ className, showAddToCart = true, showSwatches = true, style, }) => (_jsxs(Box, { className: cn("@container/product-card w-full", className), style: style, children: [_jsxs(VStack, { className: "flex @[180px]/product-card:hidden", gap: "none", children: [_jsx(Skeleton, { className: "aspect-square w-full rounded-3xl" }), _jsxs(VStack, { className: "gap-2.5 px-1.5 py-2", gap: "none", children: [_jsxs(VStack, { className: "gap-1 px-0.5", gap: "none", children: [_jsxs(VStack, { className: "gap-0.5", gap: "none", children: [_jsx(Skeleton, { className: "h-5 w-3/5" }), _jsx(Skeleton, { className: "h-4 w-4/5" })] }), _jsx(Skeleton, { className: "h-4 w-2/3" }), showSwatches ? _jsx(SwatchRow, {}) : null] }), showAddToCart ? (_jsx(Skeleton, { className: "h-9 w-full rounded-full" })) : null] })] }), _jsxs(VStack, { className: "bg-card hidden overflow-hidden rounded-3xl shadow-xs @[180px]/product-card:flex @[240px]/product-card:rounded-4xl", gap: "none", children: [_jsx(Box, { className: "w-full px-4 pt-4", children: _jsx(Skeleton, { className: cn("aspect-square w-full", PRODUCT_CARD_IMAGE_RADIUS), variant: "light" }) }), _jsx(VStack, { className: "pt-2 pb-4", gap: "none", children: _jsxs(VStack, { className: "gap-2.5 px-4 @[240px]/product-card:gap-4", gap: "none", children: [_jsxs(VStack, { className: "gap-1 px-0.5", gap: "none", children: [_jsxs(VStack, { gap: "none", children: [_jsx(Skeleton, { className: "h-5.5 w-3/5 rounded", variant: "light" }), _jsx(Skeleton, { className: "h-5 w-4/5 rounded", variant: "light" })] }), _jsx(Skeleton, { className: "h-4 w-2/3 rounded", variant: "light" }), showSwatches ? (_jsx(Box, { className: "pt-1", children: _jsx(SwatchRow, {}) })) : null] }), showAddToCart ? (_jsx(HStack, { children: _jsx(Skeleton, { className: "h-9 w-full rounded-full @[240px]/product-card:w-32", variant: "light" }) })) : null] }) })] })] }));
|
|
@@ -9,6 +9,7 @@ import { ProductCardImage } from "./product-card-image.js";
|
|
|
9
9
|
import { ProductCardLink } from "./product-card-link.js";
|
|
10
10
|
import { ProductCardProcessing } from "./product-card-processing.js";
|
|
11
11
|
import { ProductCardQuickView } from "./product-card-quick-view.js";
|
|
12
|
+
import { PRODUCT_CARD_SWATCH_IMAGE_RADIUS } from "./product-card-radius.js";
|
|
12
13
|
import { ProductCardSwatchAdd } from "./product-card-swatch-add.js";
|
|
13
14
|
const SwatchShell = ({ active, children, dragging, processing, }) => (_jsx(Box, { className: cn(
|
|
14
15
|
// Bare at rest, so the tile reads as its image alone; the card surface
|
|
@@ -32,7 +33,7 @@ const SwatchCaption = () => {
|
|
|
32
33
|
/** The square photograph with the add control and Quick view over it. */
|
|
33
34
|
const SwatchMedia = ({ overrideImageUrl, priority, }) => {
|
|
34
35
|
const { active, addGlyph, availability, currentVariant, dragging, labels, linkComponent, linkPrefetch, menuOpen, onAdd, onCardClick, onQuickView, processing, productUrl, } = useProductCard();
|
|
35
|
-
return (_jsxs(Box, { className: "relative aspect-square w-full overflow-hidden
|
|
36
|
+
return (_jsxs(Box, { className: cn("relative aspect-square w-full overflow-hidden", PRODUCT_CARD_SWATCH_IMAGE_RADIUS), children: [_jsx(ProductCardLink, { blocked: availability === "blocked", className: "block size-full", href: productUrl, label: `View ${currentVariant.name}`, linkComponent: linkComponent, onActivate: onCardClick, prefetch: linkPrefetch, children: _jsx(ProductCardImage, { overrideImageUrl: overrideImageUrl, priority: priority }) }), dragging ? null : (_jsx(ProductCardSwatchAdd, { active: active, glyph: addGlyph, labels: labels, menuOpen: menuOpen, onAdd: onAdd })), dragging || processing !== undefined ? null : (_jsx(ProductCardQuickView, { align: "start", onQuickView: onQuickView }))] }));
|
|
36
37
|
};
|
|
37
38
|
/**
|
|
38
39
|
* ProductCardSwatch - the image-first tile for boards and canvases.
|