@enadhq/enad-react-sdk 1.2.0 → 1.3.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/storefront/blocks/card-video.mjs +1 -1
- package/dist/client/storefront/blocks/card-video.mjs.map +1 -1
- package/dist/client/storefront/blocks/gallery-with-link-blocks.d.ts.map +1 -1
- package/dist/client/storefront/blocks/gallery-with-link-blocks.mjs +13 -5
- package/dist/client/storefront/blocks/gallery-with-link-blocks.mjs.map +1 -1
- package/dist/client/storefront/blocks/gallery.d.ts +10 -1
- package/dist/client/storefront/blocks/gallery.d.ts.map +1 -1
- package/dist/client/storefront/blocks/gallery.mjs +51 -27
- package/dist/client/storefront/blocks/gallery.mjs.map +1 -1
- package/dist/client/storefront/blocks/hero.d.ts +12 -1
- package/dist/client/storefront/blocks/hero.d.ts.map +1 -1
- package/dist/client/storefront/blocks/hero.mjs +143 -145
- package/dist/client/storefront/blocks/hero.mjs.map +1 -1
- package/dist/client/storefront/blocks/link-block-small.d.ts.map +1 -1
- package/dist/client/storefront/blocks/link-block-small.mjs +1 -1
- package/dist/client/storefront/blocks/link-block-small.mjs.map +1 -1
- package/dist/client/storefront/blocks/link-block.d.ts.map +1 -1
- package/dist/client/storefront/blocks/link-block.mjs +4 -4
- package/dist/client/storefront/blocks/link-block.mjs.map +1 -1
- package/dist/client/storefront/blocks/product-card-parts.d.ts +1 -1
- package/dist/client/storefront/blocks/product-card-parts.d.ts.map +1 -1
- package/dist/client/storefront/blocks/product-card-parts.mjs +2 -2
- package/dist/client/storefront/blocks/product-card-parts.mjs.map +1 -1
- package/dist/client/storefront/blocks/product-card.d.ts +10 -1
- package/dist/client/storefront/blocks/product-card.d.ts.map +1 -1
- package/dist/client/storefront/blocks/product-card.mjs +122 -116
- package/dist/client/storefront/blocks/product-card.mjs.map +1 -1
- package/dist/client/storefront/blocks/product-image.mjs +2 -2
- package/dist/client/storefront/blocks/product-image.mjs.map +1 -1
- package/dist/client/storefront/blocks/text-content-with-image.d.ts +14 -1
- package/dist/client/storefront/blocks/text-content-with-image.d.ts.map +1 -1
- package/dist/client/storefront/blocks/text-content-with-image.mjs +141 -164
- package/dist/client/storefront/blocks/text-content-with-image.mjs.map +1 -1
- package/dist/client/storefront/carousel/swipeable-carousel.d.ts +5 -1
- package/dist/client/storefront/carousel/swipeable-carousel.d.ts.map +1 -1
- package/dist/client/storefront/carousel/swipeable-carousel.mjs +2 -1
- package/dist/client/storefront/carousel/swipeable-carousel.mjs.map +1 -1
- package/dist/client/storefront/components/product-recommendations.d.ts.map +1 -1
- package/dist/client/storefront/components/product-recommendations.mjs +29 -37
- package/dist/client/storefront/components/product-recommendations.mjs.map +1 -1
- package/dist/client/storefront/filters/filter-chip.d.ts +5 -2
- package/dist/client/storefront/filters/filter-chip.d.ts.map +1 -1
- package/dist/client/storefront/filters/filter-chip.mjs +5 -3
- 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/index.d.ts +12 -1
- package/dist/client/storefront/index.mjs +12 -1
- package/dist/client/storefront/layout/header.d.ts.map +1 -1
- package/dist/client/storefront/layout/header.mjs +1 -1
- package/dist/client/storefront/layout/header.mjs.map +1 -1
- package/dist/client/storefront/layout/mobile-menu-drawer.mjs +1 -1
- package/dist/client/storefront/primitives/block-heading.d.ts +40 -0
- package/dist/client/storefront/primitives/block-heading.d.ts.map +1 -0
- package/dist/client/storefront/primitives/block-heading.mjs +43 -0
- package/dist/client/storefront/primitives/block-heading.mjs.map +1 -0
- package/dist/client/storefront/primitives/cta-group.d.ts +25 -0
- package/dist/client/storefront/primitives/cta-group.d.ts.map +1 -0
- package/dist/client/storefront/primitives/cta-group.mjs +27 -0
- package/dist/client/storefront/primitives/cta-group.mjs.map +1 -0
- package/dist/client/storefront/primitives/image-with-hover.d.ts +18 -0
- package/dist/client/storefront/primitives/image-with-hover.d.ts.map +1 -0
- package/dist/client/storefront/primitives/image-with-hover.mjs +16 -0
- package/dist/client/storefront/primitives/image-with-hover.mjs.map +1 -0
- package/dist/client/storefront/primitives/index.d.ts +4 -1
- package/dist/client/storefront/primitives/index.mjs +4 -1
- package/dist/client/theme/apply.d.ts +1 -1
- package/dist/client/theme/apply.d.ts.map +1 -1
- package/dist/client/theme/apply.mjs +0 -12
- package/dist/client/theme/apply.mjs.map +1 -1
- package/dist/client/theme/cli.mjs +0 -16
- package/dist/client/theme/cli.mjs.map +1 -1
- package/dist/client/theme/codec.d.ts.map +1 -1
- package/dist/client/theme/codec.mjs +0 -2
- package/dist/client/theme/codec.mjs.map +1 -1
- package/dist/client/theme/defaults.d.ts +0 -2
- package/dist/client/theme/defaults.mjs +0 -2
- package/dist/client/theme/defaults.mjs.map +1 -1
- package/dist/client/ui/carousel.d.ts +9 -1
- package/dist/client/ui/carousel.d.ts.map +1 -1
- package/dist/client/ui/carousel.mjs +18 -2
- package/dist/client/ui/carousel.mjs.map +1 -1
- package/dist/client/ui-resolver/index.d.ts +2 -2
- package/dist/client/ui-resolver/index.mjs +2 -2
- package/dist/styles.css +1 -1
- package/package.json +3 -2
|
@@ -1,108 +1,111 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn } from "../../ui/utils.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { defineSlotRecipe } from "../../ui-resolver/recipe.mjs";
|
|
4
|
+
import { BlockHeading } from "../primitives/block-heading.mjs";
|
|
5
|
+
import { CTAGroup } from "../primitives/cta-group.mjs";
|
|
5
6
|
import { colorThemeClasses, isThemeDark } from "../types.mjs";
|
|
6
7
|
import "react";
|
|
7
|
-
import {
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
9
|
//#region src/client/storefront/blocks/text-content-with-image.tsx
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
10
|
+
const textContentWithImageRecipe = defineSlotRecipe({
|
|
11
|
+
slots: [
|
|
12
|
+
"root",
|
|
13
|
+
"inner",
|
|
14
|
+
"imageArea",
|
|
15
|
+
"image",
|
|
16
|
+
"textArea"
|
|
17
|
+
],
|
|
18
|
+
base: {
|
|
19
|
+
root: "",
|
|
20
|
+
inner: "",
|
|
21
|
+
imageArea: "relative overflow-hidden rounded-[var(--enad-image-radius)] bg-muted",
|
|
22
|
+
image: "size-full object-cover",
|
|
23
|
+
textArea: "min-w-0"
|
|
24
|
+
},
|
|
25
|
+
variants: {
|
|
26
|
+
variant: {
|
|
27
|
+
"side-by-side": { imageArea: "aspect-[4/5]" },
|
|
28
|
+
stacked: {
|
|
29
|
+
imageArea: "aspect-[16/9] w-full",
|
|
30
|
+
textArea: "py-8"
|
|
31
|
+
},
|
|
32
|
+
overlap: {
|
|
33
|
+
imageArea: "lg:w-3/5",
|
|
34
|
+
textArea: "relative z-10 min-w-0 rounded-[var(--enad-card-radius)] p-8 shadow-[var(--enad-card-shadow)] lg:p-10"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
fullWidth: {
|
|
38
|
+
true: {},
|
|
39
|
+
false: {}
|
|
40
|
+
},
|
|
41
|
+
imagePosition: {
|
|
42
|
+
first: {},
|
|
43
|
+
last: {}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
defaultVariants: {
|
|
47
|
+
variant: "side-by-side",
|
|
48
|
+
fullWidth: "false",
|
|
49
|
+
imagePosition: "first"
|
|
50
|
+
},
|
|
51
|
+
compoundVariants: [
|
|
52
|
+
{
|
|
53
|
+
variant: "side-by-side",
|
|
54
|
+
fullWidth: "true",
|
|
55
|
+
css: {
|
|
56
|
+
inner: "grid lg:grid-cols-2",
|
|
57
|
+
textArea: "px-8 py-12 lg:px-16 lg:py-20"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
variant: "side-by-side",
|
|
62
|
+
fullWidth: "false",
|
|
63
|
+
css: {
|
|
64
|
+
inner: "mx-auto grid max-w-7xl gap-[var(--enad-text-content-gap,2rem)] px-4 py-12 md:px-8 lg:items-center lg:gap-[calc(var(--enad-text-content-gap,2rem)*1.5)] lg:grid-cols-2",
|
|
65
|
+
textArea: "py-8 lg:py-0"
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
variant: "stacked",
|
|
70
|
+
fullWidth: "true",
|
|
71
|
+
css: { textArea: "px-8 lg:px-16" }
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
variant: "stacked",
|
|
75
|
+
fullWidth: "false",
|
|
76
|
+
css: { inner: "mx-auto max-w-7xl px-4 py-12 md:px-8" }
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
variant: "overlap",
|
|
80
|
+
css: { inner: "mx-auto max-w-7xl px-4 py-12 md:px-8" }
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
});
|
|
84
|
+
function StandardLayout({ image, imagePosition = "first", fullWidth = false, variant, preheader, heading, body, buttonLabel, buttonHref, textLinkLabel, textLinkHref, dark, themeClasses, className }) {
|
|
47
85
|
const hasImage = Boolean(image?.src);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
children: [hasImage && /* @__PURE__ */ jsx("div", {
|
|
53
|
-
className: cn("relative overflow-hidden rounded-[var(--enad-image-radius)] bg-muted", "aspect-[16/9] w-full"),
|
|
54
|
-
children: /* @__PURE__ */ jsx("img", {
|
|
55
|
-
src: image?.src,
|
|
56
|
-
alt: image?.alt ?? "",
|
|
57
|
-
loading: "lazy",
|
|
58
|
-
className: "size-full object-cover"
|
|
59
|
-
})
|
|
60
|
-
}), /* @__PURE__ */ jsxs("div", {
|
|
61
|
-
className: cn("min-w-0 py-8", fullWidth && "px-8 lg:px-16"),
|
|
62
|
-
children: [/* @__PURE__ */ jsx(TextBlockContent, {
|
|
63
|
-
preheader,
|
|
64
|
-
heading,
|
|
65
|
-
body,
|
|
66
|
-
dark,
|
|
67
|
-
bodyMaxWidth: "max-w-2xl"
|
|
68
|
-
}), /* @__PURE__ */ jsx(CTAElement, {
|
|
69
|
-
buttonLabel,
|
|
70
|
-
buttonHref,
|
|
71
|
-
textLinkLabel,
|
|
72
|
-
textLinkHref,
|
|
73
|
-
dark
|
|
74
|
-
})]
|
|
75
|
-
})]
|
|
76
|
-
})
|
|
86
|
+
const classes = textContentWithImageRecipe({
|
|
87
|
+
variant,
|
|
88
|
+
fullWidth: fullWidth ? "true" : "false",
|
|
89
|
+
imagePosition
|
|
77
90
|
});
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
children: textLinkLabel
|
|
91
|
-
})]
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
function OverlapTextCard({ preheader, heading, body, buttonLabel, buttonHref, textLinkLabel, textLinkHref, dark, hasImage, overlapPositionClass }) {
|
|
95
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
96
|
-
className: cn("relative z-10 min-w-0 rounded-[var(--enad-card-radius)] shadow-[var(--enad-card-shadow)]", hasImage ? "lg:w-2/5" : "w-full", dark ? "bg-foreground text-background" : "bg-background", "p-8 lg:p-10", hasImage ? "-mt-16 mx-4 lg:mt-0 lg:mx-0" : "", overlapPositionClass),
|
|
97
|
-
children: [/* @__PURE__ */ jsx(TextBlockContent, {
|
|
91
|
+
const imageEl = hasImage ? /* @__PURE__ */ jsx("div", {
|
|
92
|
+
className: cn(classes.imageArea, fullWidth && variant === "side-by-side" && "lg:aspect-auto"),
|
|
93
|
+
children: /* @__PURE__ */ jsx("img", {
|
|
94
|
+
src: image?.src,
|
|
95
|
+
alt: image?.alt ?? "",
|
|
96
|
+
loading: "lazy",
|
|
97
|
+
className: classes.image
|
|
98
|
+
})
|
|
99
|
+
}) : null;
|
|
100
|
+
const textEl = /* @__PURE__ */ jsxs("div", {
|
|
101
|
+
className: cn(classes.textArea, "flex flex-col justify-center"),
|
|
102
|
+
children: [/* @__PURE__ */ jsx(BlockHeading, {
|
|
98
103
|
preheader,
|
|
99
104
|
heading,
|
|
100
105
|
body,
|
|
101
106
|
dark,
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
bodyColor: dark ? "text-background/80" : "text-muted-foreground"
|
|
105
|
-
}), /* @__PURE__ */ jsx(OverlapCTA, {
|
|
107
|
+
bodyMaxWidth: variant === "side-by-side" ? "max-w-lg" : "max-w-2xl"
|
|
108
|
+
}), /* @__PURE__ */ jsx(CTAGroup, {
|
|
106
109
|
buttonLabel,
|
|
107
110
|
buttonHref,
|
|
108
111
|
textLinkLabel,
|
|
@@ -110,109 +113,83 @@ function OverlapTextCard({ preheader, heading, body, buttonLabel, buttonHref, te
|
|
|
110
113
|
dark
|
|
111
114
|
})]
|
|
112
115
|
});
|
|
116
|
+
const showImageFirst = hasImage && imagePosition === "first";
|
|
117
|
+
const showImageLast = hasImage && imagePosition === "last";
|
|
118
|
+
return /* @__PURE__ */ jsx("section", {
|
|
119
|
+
className: cn(themeClasses, className),
|
|
120
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
121
|
+
className: cn(classes.inner, hasImage && variant === "side-by-side" && fullWidth && "lg:grid-cols-2"),
|
|
122
|
+
children: [
|
|
123
|
+
showImageFirst && imageEl,
|
|
124
|
+
textEl,
|
|
125
|
+
showImageLast && imageEl,
|
|
126
|
+
!hasImage && null
|
|
127
|
+
]
|
|
128
|
+
})
|
|
129
|
+
});
|
|
113
130
|
}
|
|
114
|
-
function
|
|
131
|
+
function OverlapLayout({ image, imagePosition = "first", preheader, heading, body, buttonLabel, buttonHref, textLinkLabel, textLinkHref, dark, themeClasses, className }) {
|
|
115
132
|
const hasImage = Boolean(image?.src);
|
|
133
|
+
const classes = textContentWithImageRecipe({ variant: "overlap" });
|
|
116
134
|
const overlapPositionClass = (() => {
|
|
117
|
-
if (!hasImage) return "";
|
|
118
|
-
if (imagePosition === "last") return "lg:order-1 lg:-me-16";
|
|
119
|
-
return "lg:-ms-16";
|
|
135
|
+
if (!hasImage) return "w-full";
|
|
136
|
+
if (imagePosition === "last") return "lg:order-1 lg:-me-16 lg:w-2/5";
|
|
137
|
+
return "lg:-ms-16 lg:w-2/5";
|
|
120
138
|
})();
|
|
121
139
|
return /* @__PURE__ */ jsx("section", {
|
|
122
140
|
className: cn(themeClasses, className),
|
|
123
141
|
children: /* @__PURE__ */ jsx("div", {
|
|
124
|
-
className:
|
|
142
|
+
className: classes.inner,
|
|
125
143
|
children: /* @__PURE__ */ jsxs("div", {
|
|
126
144
|
className: cn("relative", hasImage && "lg:flex lg:items-center"),
|
|
127
145
|
children: [hasImage && /* @__PURE__ */ jsx("div", {
|
|
128
|
-
className: cn(
|
|
146
|
+
className: cn(classes.imageArea, imagePosition === "last" ? "lg:order-2" : ""),
|
|
129
147
|
children: /* @__PURE__ */ jsx("div", {
|
|
130
148
|
className: "aspect-[4/5] lg:aspect-[3/2]",
|
|
131
149
|
children: /* @__PURE__ */ jsx("img", {
|
|
132
150
|
src: image?.src,
|
|
133
151
|
alt: image?.alt ?? "",
|
|
134
152
|
loading: "lazy",
|
|
135
|
-
className:
|
|
153
|
+
className: classes.image
|
|
136
154
|
})
|
|
137
155
|
})
|
|
138
|
-
}), /* @__PURE__ */
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
156
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
157
|
+
className: cn(classes.textArea, hasImage ? overlapPositionClass : "w-full", hasImage ? "-mt-16 mx-4 lg:mt-0 lg:mx-0" : "", dark ? "bg-foreground text-background" : "bg-background"),
|
|
158
|
+
children: [/* @__PURE__ */ jsx(BlockHeading, {
|
|
159
|
+
preheader,
|
|
160
|
+
heading,
|
|
161
|
+
body,
|
|
162
|
+
dark,
|
|
163
|
+
preheaderColor: dark ? "text-background/70" : "text-muted-foreground",
|
|
164
|
+
headingColor: dark ? "text-background" : "text-foreground",
|
|
165
|
+
bodyColor: dark ? "text-background/80" : "text-muted-foreground"
|
|
166
|
+
}), /* @__PURE__ */ jsx(CTAGroup, {
|
|
167
|
+
buttonLabel,
|
|
168
|
+
buttonHref,
|
|
169
|
+
textLinkLabel,
|
|
170
|
+
textLinkHref,
|
|
171
|
+
dark
|
|
172
|
+
})]
|
|
149
173
|
})]
|
|
150
174
|
})
|
|
151
175
|
})
|
|
152
176
|
});
|
|
153
177
|
}
|
|
154
|
-
function SideBySideContent({ hasImage, imagePosition, imageEl, textEl }) {
|
|
155
|
-
if (!hasImage) return textEl;
|
|
156
|
-
if (imagePosition === "first") return /* @__PURE__ */ jsxs(Fragment, { children: [imageEl, textEl] });
|
|
157
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [textEl, imageEl] });
|
|
158
|
-
}
|
|
159
|
-
function SideBySideVariant({ image, imagePosition = "first", fullWidth = false, preheader, heading, body, buttonLabel, buttonHref, textLinkLabel, textLinkHref, dark, themeClasses, className }) {
|
|
160
|
-
const hasImage = Boolean(image?.src);
|
|
161
|
-
const imageEl = hasImage ? /* @__PURE__ */ jsx("div", {
|
|
162
|
-
className: cn("relative overflow-hidden rounded-[var(--enad-image-radius)] bg-muted", fullWidth ? "aspect-[4/5] lg:aspect-auto" : "aspect-[4/5]"),
|
|
163
|
-
children: /* @__PURE__ */ jsx("img", {
|
|
164
|
-
src: image?.src,
|
|
165
|
-
alt: image?.alt ?? "",
|
|
166
|
-
loading: "lazy",
|
|
167
|
-
className: "size-full object-cover"
|
|
168
|
-
})
|
|
169
|
-
}) : null;
|
|
170
|
-
const textEl = /* @__PURE__ */ jsxs("div", {
|
|
171
|
-
className: cn("flex min-w-0 flex-col justify-center", fullWidth ? "px-8 py-12 lg:px-16 lg:py-20" : "py-8 lg:py-0"),
|
|
172
|
-
children: [/* @__PURE__ */ jsx(TextBlockContent, {
|
|
173
|
-
preheader,
|
|
174
|
-
heading,
|
|
175
|
-
body,
|
|
176
|
-
dark,
|
|
177
|
-
bodyMaxWidth: "max-w-lg"
|
|
178
|
-
}), /* @__PURE__ */ jsx(CTAElement, {
|
|
179
|
-
buttonLabel,
|
|
180
|
-
buttonHref,
|
|
181
|
-
textLinkLabel,
|
|
182
|
-
textLinkHref,
|
|
183
|
-
dark
|
|
184
|
-
})]
|
|
185
|
-
});
|
|
186
|
-
return /* @__PURE__ */ jsx("section", {
|
|
187
|
-
className: cn(themeClasses, className),
|
|
188
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
189
|
-
className: cn(fullWidth ? cn("grid", hasImage && "lg:grid-cols-2") : cn("mx-auto grid max-w-7xl gap-8 px-4 py-12 md:px-8 lg:items-center lg:gap-12", hasImage && "lg:grid-cols-2")),
|
|
190
|
-
children: /* @__PURE__ */ jsx(SideBySideContent, {
|
|
191
|
-
hasImage,
|
|
192
|
-
imagePosition,
|
|
193
|
-
imageEl,
|
|
194
|
-
textEl
|
|
195
|
-
})
|
|
196
|
-
})
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
178
|
function TextContentWithImage(props) {
|
|
200
179
|
const { variant = "side-by-side", colorTheme, className } = props;
|
|
201
180
|
const dark = isThemeDark(colorTheme);
|
|
202
181
|
const themeClasses = colorThemeClasses(colorTheme);
|
|
203
|
-
const
|
|
182
|
+
const layoutProps = {
|
|
204
183
|
...props,
|
|
184
|
+
variant,
|
|
205
185
|
dark,
|
|
206
186
|
themeClasses,
|
|
207
187
|
className
|
|
208
188
|
};
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
case "overlap": return /* @__PURE__ */ jsx(OverlapVariant, { ...variantProps });
|
|
212
|
-
default: return /* @__PURE__ */ jsx(SideBySideVariant, { ...variantProps });
|
|
213
|
-
}
|
|
189
|
+
if (variant === "overlap") return /* @__PURE__ */ jsx(OverlapLayout, { ...layoutProps });
|
|
190
|
+
return /* @__PURE__ */ jsx(StandardLayout, { ...layoutProps });
|
|
214
191
|
}
|
|
215
192
|
//#endregion
|
|
216
|
-
export { TextContentWithImage };
|
|
193
|
+
export { TextContentWithImage, textContentWithImageRecipe };
|
|
217
194
|
|
|
218
195
|
//# sourceMappingURL=text-content-with-image.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text-content-with-image.mjs","names":[],"sources":["../../../../src/client/storefront/blocks/text-content-with-image.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"../../ui/utils\"\nimport { StorefrontButton } from \"../primitives/button\"\nimport { StorefrontTextLink } from \"../primitives/text-link\"\nimport { colorThemeClasses, isThemeDark, type TextContentWithImageProps } from \"../types\"\n\n/* ─── Shared props for variant sub-components ─── */\n\ntype VariantProps = Omit<TextContentWithImageProps, \"variant\" | \"className\"> & {\n dark: boolean\n themeClasses: string\n className?: string\n}\n\n/* ─── Shared CTA element builder ─── */\n\nfunction CTAElement({\n buttonLabel,\n buttonHref,\n textLinkLabel,\n textLinkHref,\n dark,\n}: {\n buttonLabel?: string\n buttonHref?: string\n textLinkLabel?: string\n textLinkHref?: string\n dark: boolean\n}) {\n if (!buttonLabel && !textLinkLabel) return null\n return (\n <div className=\"mt-6 flex flex-wrap items-center gap-4\">\n {buttonLabel && buttonHref && (\n <StorefrontButton href={buttonHref} variant={dark ? \"outline\" : \"primary\"}>\n {buttonLabel}\n </StorefrontButton>\n )}\n {textLinkLabel && textLinkHref && (\n <StorefrontTextLink href={textLinkHref} className={dark ? \"text-white\" : undefined}>\n {textLinkLabel}\n </StorefrontTextLink>\n )}\n </div>\n )\n}\n\n/* ─── Heading style constant ─── */\n\nconst headingStyle = { fontWeight: \"var(--enad-heading-weight)\", letterSpacing: \"var(--enad-heading-tracking)\", textTransform: \"var(--enad-heading-transform)\" } as unknown as React.CSSProperties\n\n/* ─── Shared text block (preheader + heading + body) ─── */\n\nfunction TextBlockContent({\n preheader,\n heading,\n body,\n dark,\n preheaderColor = dark ? \"text-white/70\" : \"text-muted-foreground\",\n headingColor = dark ? \"text-white\" : \"text-foreground\",\n bodyColor = dark ? \"text-white/80\" : \"text-muted-foreground\",\n bodyMaxWidth = \"\",\n}: {\n preheader?: string\n heading?: string\n body?: string\n dark: boolean\n preheaderColor?: string\n headingColor?: string\n bodyColor?: string\n bodyMaxWidth?: string\n}) {\n return (\n <>\n {preheader && (\n <p className={cn(\"mb-2 text-sm uppercase tracking-widest\", preheaderColor)}>\n {preheader}\n </p>\n )}\n {heading && (\n <h2\n className={cn(\"text-2xl font-heading md:text-3xl\", headingColor)}\n style={headingStyle}\n >\n {heading}\n </h2>\n )}\n {body && (\n <p className={cn(\"mt-4 text-base leading-relaxed\", bodyColor, bodyMaxWidth)}>\n {body}\n </p>\n )}\n </>\n )\n}\n\n/* ─── Stacked variant ─── */\n\nfunction StackedVariant({\n image,\n fullWidth = false,\n preheader,\n heading,\n body,\n buttonLabel,\n buttonHref,\n textLinkLabel,\n textLinkHref,\n dark,\n themeClasses,\n className,\n}: VariantProps) {\n const hasImage = Boolean(image?.src)\n\n return (\n <section className={cn(themeClasses, className)}>\n <div className={cn(fullWidth ? \"\" : \"mx-auto max-w-7xl px-4 py-12 md:px-8\")}>\n {hasImage && (\n <div className={cn(\"relative overflow-hidden rounded-[var(--enad-image-radius)] bg-muted\", \"aspect-[16/9] w-full\")}>\n <img src={image?.src} alt={image?.alt ?? \"\"} loading=\"lazy\" className=\"size-full object-cover\" />\n </div>\n )}\n <div className={cn(\"min-w-0 py-8\", fullWidth && \"px-8 lg:px-16\")}>\n <TextBlockContent preheader={preheader} heading={heading} body={body} dark={dark} bodyMaxWidth=\"max-w-2xl\" />\n <CTAElement buttonLabel={buttonLabel} buttonHref={buttonHref} textLinkLabel={textLinkLabel} textLinkHref={textLinkHref} dark={dark} />\n </div>\n </div>\n </section>\n )\n}\n\n/* ─── Overlap text card (extracted to reduce complexity) ─── */\n\nfunction OverlapCTA({\n buttonLabel,\n buttonHref,\n textLinkLabel,\n textLinkHref,\n dark,\n}: {\n buttonLabel?: string\n buttonHref?: string\n textLinkLabel?: string\n textLinkHref?: string\n dark: boolean\n}) {\n if (!buttonLabel && !textLinkLabel) return null\n return (\n <div className=\"mt-6 flex flex-wrap items-center gap-4\">\n {buttonLabel && buttonHref && (\n <StorefrontButton href={buttonHref} variant={dark ? \"outline\" : \"primary\"}>\n {buttonLabel}\n </StorefrontButton>\n )}\n {textLinkLabel && textLinkHref && (\n <StorefrontTextLink href={textLinkHref} className={dark ? \"text-background\" : undefined}>\n {textLinkLabel}\n </StorefrontTextLink>\n )}\n </div>\n )\n}\n\nfunction OverlapTextCard({\n preheader,\n heading,\n body,\n buttonLabel,\n buttonHref,\n textLinkLabel,\n textLinkHref,\n dark,\n hasImage,\n overlapPositionClass,\n}: {\n preheader?: string\n heading?: string\n body?: string\n buttonLabel?: string\n buttonHref?: string\n textLinkLabel?: string\n textLinkHref?: string\n dark: boolean\n hasImage: boolean\n overlapPositionClass: string\n}) {\n return (\n <div className={cn(\n \"relative z-10 min-w-0 rounded-[var(--enad-card-radius)] shadow-[var(--enad-card-shadow)]\",\n hasImage ? \"lg:w-2/5\" : \"w-full\",\n dark ? \"bg-foreground text-background\" : \"bg-background\",\n \"p-8 lg:p-10\",\n hasImage ? \"-mt-16 mx-4 lg:mt-0 lg:mx-0\" : \"\",\n overlapPositionClass,\n )}>\n <TextBlockContent\n preheader={preheader}\n heading={heading}\n body={body}\n dark={dark}\n preheaderColor={dark ? \"text-background/70\" : \"text-muted-foreground\"}\n headingColor={dark ? \"text-background\" : \"text-foreground\"}\n bodyColor={dark ? \"text-background/80\" : \"text-muted-foreground\"}\n />\n <OverlapCTA buttonLabel={buttonLabel} buttonHref={buttonHref} textLinkLabel={textLinkLabel} textLinkHref={textLinkHref} dark={dark} />\n </div>\n )\n}\n\n/* ─── Overlap variant ─── */\n\nfunction OverlapVariant({\n image,\n imagePosition = \"first\",\n preheader,\n heading,\n body,\n buttonLabel,\n buttonHref,\n textLinkLabel,\n textLinkHref,\n dark,\n themeClasses,\n className,\n}: VariantProps) {\n const hasImage = Boolean(image?.src)\n\n const overlapPositionClass = (() => {\n if (!hasImage) return \"\"\n if (imagePosition === \"last\") return \"lg:order-1 lg:-me-16\"\n return \"lg:-ms-16\"\n })()\n\n return (\n <section className={cn(themeClasses, className)}>\n <div className=\"mx-auto max-w-7xl px-4 py-12 md:px-8\">\n <div className={cn(\"relative\", hasImage && \"lg:flex lg:items-center\")}>\n {hasImage && (\n <div className={cn(\n \"relative overflow-hidden rounded-[var(--enad-image-radius)] bg-muted lg:w-3/5\",\n imagePosition === \"last\" ? \"lg:order-2\" : \"\",\n )}>\n <div className=\"aspect-[4/5] lg:aspect-[3/2]\">\n <img src={image?.src} alt={image?.alt ?? \"\"} loading=\"lazy\" className=\"size-full object-cover\" />\n </div>\n </div>\n )}\n\n <OverlapTextCard\n preheader={preheader}\n heading={heading}\n body={body}\n buttonLabel={buttonLabel}\n buttonHref={buttonHref}\n textLinkLabel={textLinkLabel}\n textLinkHref={textLinkHref}\n dark={dark}\n hasImage={hasImage}\n overlapPositionClass={overlapPositionClass}\n />\n </div>\n </div>\n </section>\n )\n}\n\n/* ─── Side-by-side content ordering helper ─── */\n\nfunction SideBySideContent({\n hasImage,\n imagePosition,\n imageEl,\n textEl,\n}: {\n hasImage: boolean\n imagePosition: string\n imageEl: React.ReactNode\n textEl: React.ReactNode\n}) {\n if (!hasImage) return textEl\n if (imagePosition === \"first\") {\n return (\n <>\n {imageEl}\n {textEl}\n </>\n )\n }\n return (\n <>\n {textEl}\n {imageEl}\n </>\n )\n}\n\n/* ─── Side-by-side variant ─── */\n\nfunction SideBySideVariant({\n image,\n imagePosition = \"first\",\n fullWidth = false,\n preheader,\n heading,\n body,\n buttonLabel,\n buttonHref,\n textLinkLabel,\n textLinkHref,\n dark,\n themeClasses,\n className,\n}: VariantProps) {\n const hasImage = Boolean(image?.src)\n\n const imageEl = hasImage ? (\n <div className={cn(\"relative overflow-hidden rounded-[var(--enad-image-radius)] bg-muted\", fullWidth ? \"aspect-[4/5] lg:aspect-auto\" : \"aspect-[4/5]\")}>\n <img src={image?.src} alt={image?.alt ?? \"\"} loading=\"lazy\" className=\"size-full object-cover\" />\n </div>\n ) : null\n\n const textEl = (\n <div className={cn(\"flex min-w-0 flex-col justify-center\", fullWidth ? \"px-8 py-12 lg:px-16 lg:py-20\" : \"py-8 lg:py-0\")}>\n <TextBlockContent preheader={preheader} heading={heading} body={body} dark={dark} bodyMaxWidth=\"max-w-lg\" />\n <CTAElement buttonLabel={buttonLabel} buttonHref={buttonHref} textLinkLabel={textLinkLabel} textLinkHref={textLinkHref} dark={dark} />\n </div>\n )\n\n return (\n <section className={cn(themeClasses, className)}>\n <div className={cn(\n fullWidth\n ? cn(\"grid\", hasImage && \"lg:grid-cols-2\")\n : cn(\"mx-auto grid max-w-7xl gap-8 px-4 py-12 md:px-8 lg:items-center lg:gap-12\", hasImage && \"lg:grid-cols-2\"),\n )}>\n <SideBySideContent\n hasImage={hasImage}\n imagePosition={imagePosition}\n imageEl={imageEl}\n textEl={textEl}\n />\n </div>\n </section>\n )\n}\n\n/* ─── Main component ─── */\n\nfunction TextContentWithImage(props: TextContentWithImageProps) {\n const { variant = \"side-by-side\", colorTheme, className } = props\n const dark = isThemeDark(colorTheme)\n const themeClasses = colorThemeClasses(colorTheme)\n\n const variantProps: VariantProps = { ...props, dark, themeClasses, className }\n\n switch (variant) {\n case \"stacked\":\n return <StackedVariant {...variantProps} />\n case \"overlap\":\n return <OverlapVariant {...variantProps} />\n default:\n return <SideBySideVariant {...variantProps} />\n }\n}\n\nexport { TextContentWithImage, type TextContentWithImageProps }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"text-content-with-image.mjs","names":[],"sources":["../../../../src/client/storefront/blocks/text-content-with-image.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"../../ui/utils\";\nimport { defineSlotRecipe } from \"../../ui-resolver/recipe\";\nimport { colorThemeClasses, isThemeDark, type TextContentWithImageProps } from \"../types\";\nimport { BlockHeading } from \"../primitives/block-heading\";\nimport { CTAGroup } from \"../primitives/cta-group\";\n\n/* ─── Recipe ─── */\n\nconst textContentWithImageRecipe = defineSlotRecipe({\n slots: [\"root\", \"inner\", \"imageArea\", \"image\", \"textArea\"] as const,\n base: {\n root: \"\",\n inner: \"\",\n imageArea: \"relative overflow-hidden rounded-[var(--enad-image-radius)] bg-muted\",\n image: \"size-full object-cover\",\n textArea: \"min-w-0\",\n },\n variants: {\n variant: {\n \"side-by-side\": {\n imageArea: \"aspect-[4/5]\",\n },\n stacked: {\n imageArea: \"aspect-[16/9] w-full\",\n textArea: \"py-8\",\n },\n overlap: {\n imageArea: \"lg:w-3/5\",\n textArea:\n \"relative z-10 min-w-0 rounded-[var(--enad-card-radius)] p-8 shadow-[var(--enad-card-shadow)] lg:p-10\",\n },\n },\n fullWidth: {\n true: {},\n false: {},\n },\n imagePosition: {\n first: {},\n last: {},\n },\n },\n defaultVariants: {\n variant: \"side-by-side\",\n fullWidth: \"false\",\n imagePosition: \"first\",\n },\n compoundVariants: [\n {\n variant: \"side-by-side\",\n fullWidth: \"true\",\n css: {\n inner: \"grid lg:grid-cols-2\",\n textArea: \"px-8 py-12 lg:px-16 lg:py-20\",\n },\n },\n {\n variant: \"side-by-side\",\n fullWidth: \"false\",\n css: {\n inner:\n \"mx-auto grid max-w-7xl gap-[var(--enad-text-content-gap,2rem)] px-4 py-12 md:px-8 lg:items-center lg:gap-[calc(var(--enad-text-content-gap,2rem)*1.5)] lg:grid-cols-2\",\n textArea: \"py-8 lg:py-0\",\n },\n },\n {\n variant: \"stacked\",\n fullWidth: \"true\",\n css: {\n textArea: \"px-8 lg:px-16\",\n },\n },\n {\n variant: \"stacked\",\n fullWidth: \"false\",\n css: {\n inner: \"mx-auto max-w-7xl px-4 py-12 md:px-8\",\n },\n },\n {\n variant: \"overlap\",\n css: {\n inner: \"mx-auto max-w-7xl px-4 py-12 md:px-8\",\n },\n },\n ],\n});\n\n/* ─── Standard layout (side-by-side + stacked) ─── */\n\nfunction StandardLayout({\n image,\n imagePosition = \"first\",\n fullWidth = false,\n variant,\n preheader,\n heading,\n body,\n buttonLabel,\n buttonHref,\n textLinkLabel,\n textLinkHref,\n dark,\n themeClasses,\n className,\n}: LayoutProps) {\n const hasImage = Boolean(image?.src);\n const classes = textContentWithImageRecipe({\n variant,\n fullWidth: fullWidth ? \"true\" : \"false\",\n imagePosition: imagePosition,\n });\n\n const imageEl = hasImage ? (\n <div\n className={cn(classes.imageArea, fullWidth && variant === \"side-by-side\" && \"lg:aspect-auto\")}\n >\n <img src={image?.src} alt={image?.alt ?? \"\"} loading=\"lazy\" className={classes.image} />\n </div>\n ) : null;\n\n const textEl = (\n <div className={cn(classes.textArea, \"flex flex-col justify-center\")}>\n <BlockHeading\n preheader={preheader}\n heading={heading}\n body={body}\n dark={dark}\n bodyMaxWidth={variant === \"side-by-side\" ? \"max-w-lg\" : \"max-w-2xl\"}\n />\n <CTAGroup\n buttonLabel={buttonLabel}\n buttonHref={buttonHref}\n textLinkLabel={textLinkLabel}\n textLinkHref={textLinkHref}\n dark={dark}\n />\n </div>\n );\n\n const showImageFirst = hasImage && imagePosition === \"first\";\n const showImageLast = hasImage && imagePosition === \"last\";\n\n return (\n <section className={cn(themeClasses, className)}>\n <div\n className={cn(\n classes.inner,\n hasImage && variant === \"side-by-side\" && fullWidth && \"lg:grid-cols-2\",\n )}\n >\n {showImageFirst && imageEl}\n {textEl}\n {showImageLast && imageEl}\n {!hasImage && null}\n </div>\n </section>\n );\n}\n\n/* ─── Overlap layout ─── */\n\nfunction OverlapLayout({\n image,\n imagePosition = \"first\",\n preheader,\n heading,\n body,\n buttonLabel,\n buttonHref,\n textLinkLabel,\n textLinkHref,\n dark,\n themeClasses,\n className,\n}: LayoutProps) {\n const hasImage = Boolean(image?.src);\n const classes = textContentWithImageRecipe({ variant: \"overlap\" });\n\n const overlapPositionClass = (() => {\n if (!hasImage) return \"w-full\";\n if (imagePosition === \"last\") return \"lg:order-1 lg:-me-16 lg:w-2/5\";\n return \"lg:-ms-16 lg:w-2/5\";\n })();\n\n return (\n <section className={cn(themeClasses, className)}>\n <div className={classes.inner}>\n <div className={cn(\"relative\", hasImage && \"lg:flex lg:items-center\")}>\n {hasImage && (\n <div className={cn(classes.imageArea, imagePosition === \"last\" ? \"lg:order-2\" : \"\")}>\n <div className=\"aspect-[4/5] lg:aspect-[3/2]\">\n <img\n src={image?.src}\n alt={image?.alt ?? \"\"}\n loading=\"lazy\"\n className={classes.image}\n />\n </div>\n </div>\n )}\n\n <div\n className={cn(\n classes.textArea,\n hasImage ? overlapPositionClass : \"w-full\",\n hasImage ? \"-mt-16 mx-4 lg:mt-0 lg:mx-0\" : \"\",\n dark ? \"bg-foreground text-background\" : \"bg-background\",\n )}\n >\n <BlockHeading\n preheader={preheader}\n heading={heading}\n body={body}\n dark={dark}\n preheaderColor={dark ? \"text-background/70\" : \"text-muted-foreground\"}\n headingColor={dark ? \"text-background\" : \"text-foreground\"}\n bodyColor={dark ? \"text-background/80\" : \"text-muted-foreground\"}\n />\n <CTAGroup\n buttonLabel={buttonLabel}\n buttonHref={buttonHref}\n textLinkLabel={textLinkLabel}\n textLinkHref={textLinkHref}\n dark={dark}\n />\n </div>\n </div>\n </div>\n </section>\n );\n}\n\n/* ─── Internal layout prop type ─── */\n\ntype LayoutProps = TextContentWithImageProps & {\n variant: \"side-by-side\" | \"stacked\" | \"overlap\";\n dark: boolean;\n themeClasses: string;\n};\n\n/* ─── Main component ─── */\n\nfunction TextContentWithImage(props: TextContentWithImageProps) {\n const { variant = \"side-by-side\", colorTheme, className } = props;\n const dark = isThemeDark(colorTheme);\n const themeClasses = colorThemeClasses(colorTheme);\n\n const layoutProps: LayoutProps = {\n ...props,\n variant,\n dark,\n themeClasses,\n className,\n };\n\n if (variant === \"overlap\") {\n return <OverlapLayout {...layoutProps} />;\n }\n\n return <StandardLayout {...layoutProps} />;\n}\n\nexport { TextContentWithImage, textContentWithImageRecipe, type TextContentWithImageProps };\n"],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CarouselWheelAxis } from "../../ui/carousel.js";
|
|
1
2
|
import * as React$1 from "react";
|
|
2
3
|
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
4
|
|
|
@@ -11,6 +12,8 @@ interface SwipeableCarouselProps {
|
|
|
11
12
|
dotsClassName?: string;
|
|
12
13
|
activeSlide?: number;
|
|
13
14
|
onSlideChange?: (index: number) => void;
|
|
15
|
+
/** Controls which wheel/trackpad axes scroll the carousel. Defaults to "vertical". */
|
|
16
|
+
wheelAxis?: CarouselWheelAxis;
|
|
14
17
|
}
|
|
15
18
|
declare function SwipeableCarousel({
|
|
16
19
|
items,
|
|
@@ -19,7 +22,8 @@ declare function SwipeableCarousel({
|
|
|
19
22
|
showDots,
|
|
20
23
|
dotsClassName,
|
|
21
24
|
activeSlide,
|
|
22
|
-
onSlideChange
|
|
25
|
+
onSlideChange,
|
|
26
|
+
wheelAxis
|
|
23
27
|
}: SwipeableCarouselProps): react_jsx_runtime0.JSX.Element | null;
|
|
24
28
|
//#endregion
|
|
25
29
|
export { SwipeableCarousel, type SwipeableCarouselProps };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"swipeable-carousel.d.ts","names":[],"sources":["../../../../src/client/storefront/carousel/swipeable-carousel.tsx"],"mappings":"
|
|
1
|
+
{"version":3,"file":"swipeable-carousel.d.ts","names":[],"sources":["../../../../src/client/storefront/carousel/swipeable-carousel.tsx"],"mappings":";;;;;UAcU,sBAAA;EACR,KAAA,EAAO,OAAA,CAAM,SAAA;EACb,SAAA;EAFQ;EAIR,MAAA;EACA,QAAA;EACA,aAAA;EACA,WAAA;EACA,aAAA,IAAiB,KAAA;EAPJ;EASb,SAAA,GAAY,iBAAA;AAAA;AAAA,iBAGL,iBAAA,CAAA;EACP,KAAA;EACA,SAAA;EACA,MAAA;EACA,QAAA;EACA,aAAA;EACA,WAAA;EACA,aAAA;EACA;AAAA,GACC,sBAAA,GAAsB,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -4,7 +4,7 @@ import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious
|
|
|
4
4
|
import * as React$1 from "react";
|
|
5
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
6
|
//#region src/client/storefront/carousel/swipeable-carousel.tsx
|
|
7
|
-
function SwipeableCarousel({ items, className, arrows, showDots = true, dotsClassName, activeSlide, onSlideChange }) {
|
|
7
|
+
function SwipeableCarousel({ items, className, arrows, showDots = true, dotsClassName, activeSlide, onSlideChange, wheelAxis }) {
|
|
8
8
|
const [api, setApi] = React$1.useState();
|
|
9
9
|
const [current, setCurrent] = React$1.useState(0);
|
|
10
10
|
const [count, setCount] = React$1.useState(0);
|
|
@@ -29,6 +29,7 @@ function SwipeableCarousel({ items, className, arrows, showDots = true, dotsClas
|
|
|
29
29
|
children: [/* @__PURE__ */ jsxs(Carousel, {
|
|
30
30
|
setApi,
|
|
31
31
|
opts: { loop: !singleItem },
|
|
32
|
+
wheelAxis,
|
|
32
33
|
children: [/* @__PURE__ */ jsx(CarouselContent, { children: items.map((item, index) => /* @__PURE__ */ jsx(CarouselItem, { children: item }, index)) }), arrows && !singleItem && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(CarouselPrevious, { className: arrows === "inset" ? "left-3 -translate-x-0" : void 0 }), /* @__PURE__ */ jsx(CarouselNext, { className: arrows === "inset" ? "right-3 translate-x-0" : void 0 })] })]
|
|
33
34
|
}), showDots && !singleItem && count > 1 && /* @__PURE__ */ jsx("div", {
|
|
34
35
|
className: cn("absolute inset-x-0 bottom-3 z-10 flex items-center justify-center gap-1.5", dotsClassName),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"swipeable-carousel.mjs","names":["React"],"sources":["../../../../src/client/storefront/carousel/swipeable-carousel.tsx"],"sourcesContent":["\"use client\"
|
|
1
|
+
{"version":3,"file":"swipeable-carousel.mjs","names":["React"],"sources":["../../../../src/client/storefront/carousel/swipeable-carousel.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport {\n Carousel,\n CarouselContent,\n CarouselItem,\n CarouselPrevious,\n CarouselNext,\n type CarouselApi,\n} from \"../../ui-resolver/carousel\";\nimport { type CarouselWheelAxis } from \"../../ui/carousel\";\nimport { cn } from \"../../ui/utils\";\n\ninterface SwipeableCarouselProps {\n items: React.ReactNode[];\n className?: string;\n /** 'inset' — arrows float over the image edges; 'outset' — arrows sit outside the image bounds */\n arrows?: \"inset\" | \"outset\";\n showDots?: boolean;\n dotsClassName?: string;\n activeSlide?: number;\n onSlideChange?: (index: number) => void;\n /** Controls which wheel/trackpad axes scroll the carousel. Defaults to \"vertical\". */\n wheelAxis?: CarouselWheelAxis;\n}\n\nfunction SwipeableCarousel({\n items,\n className,\n arrows,\n showDots = true,\n dotsClassName,\n activeSlide,\n onSlideChange,\n wheelAxis,\n}: SwipeableCarouselProps) {\n const [api, setApi] = React.useState<CarouselApi>();\n const [current, setCurrent] = React.useState(0);\n const [count, setCount] = React.useState(0);\n\n React.useEffect(() => {\n if (!api) return;\n\n setCount(api.scrollSnapList().length);\n setCurrent(api.selectedScrollSnap());\n\n api.on(\"select\", () => {\n const idx = api.selectedScrollSnap();\n setCurrent(idx);\n onSlideChange?.(idx);\n });\n }, [api, onSlideChange]);\n\n React.useEffect(() => {\n if (!api || activeSlide === undefined) return;\n if (api.selectedScrollSnap() !== activeSlide) {\n api.scrollTo(activeSlide);\n }\n }, [api, activeSlide]);\n\n if (items.length === 0) return null;\n\n const singleItem = items.length === 1;\n\n return (\n <div className={cn(\"relative\", arrows === \"outset\" && \"mx-12\", className)}>\n <Carousel setApi={setApi} opts={{ loop: !singleItem }} wheelAxis={wheelAxis}>\n <CarouselContent>\n {items.map((item, index) => (\n <CarouselItem key={index}>{item}</CarouselItem>\n ))}\n </CarouselContent>\n\n {arrows && !singleItem && (\n <>\n <CarouselPrevious\n className={arrows === \"inset\" ? \"left-3 -translate-x-0\" : undefined}\n />\n <CarouselNext className={arrows === \"inset\" ? \"right-3 translate-x-0\" : undefined} />\n </>\n )}\n </Carousel>\n\n {showDots && !singleItem && count > 1 && (\n <div\n className={cn(\n \"absolute inset-x-0 bottom-3 z-10 flex items-center justify-center gap-1.5\",\n dotsClassName,\n )}\n role=\"tablist\"\n >\n {Array.from({ length: count }).map((_, index) => (\n <button\n key={index}\n type=\"button\"\n role=\"tab\"\n aria-selected={index === current}\n aria-label={`Go to slide ${index + 1}`}\n onClick={() => api?.scrollTo(index)}\n className={cn(\n \"size-2 rounded-full transition-all shadow-sm\",\n index === current ? \"bg-primary\" : \"bg-background/70 hover:bg-background/90\",\n )}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n\nexport { SwipeableCarousel, type SwipeableCarouselProps };\n"],"mappings":";;;;;;AA2BA,SAAS,kBAAkB,EACzB,OACA,WACA,QACA,WAAW,MACX,eACA,aACA,eACA,aACyB;CACzB,MAAM,CAAC,KAAK,UAAUA,QAAM,UAAuB;CACnD,MAAM,CAAC,SAAS,cAAcA,QAAM,SAAS,EAAE;CAC/C,MAAM,CAAC,OAAO,YAAYA,QAAM,SAAS,EAAE;AAE3C,SAAM,gBAAgB;AACpB,MAAI,CAAC,IAAK;AAEV,WAAS,IAAI,gBAAgB,CAAC,OAAO;AACrC,aAAW,IAAI,oBAAoB,CAAC;AAEpC,MAAI,GAAG,gBAAgB;GACrB,MAAM,MAAM,IAAI,oBAAoB;AACpC,cAAW,IAAI;AACf,mBAAgB,IAAI;IACpB;IACD,CAAC,KAAK,cAAc,CAAC;AAExB,SAAM,gBAAgB;AACpB,MAAI,CAAC,OAAO,gBAAgB,KAAA,EAAW;AACvC,MAAI,IAAI,oBAAoB,KAAK,YAC/B,KAAI,SAAS,YAAY;IAE1B,CAAC,KAAK,YAAY,CAAC;AAEtB,KAAI,MAAM,WAAW,EAAG,QAAO;CAE/B,MAAM,aAAa,MAAM,WAAW;AAEpC,QACE,qBAAC,OAAD;EAAK,WAAW,GAAG,YAAY,WAAW,YAAY,SAAS,UAAU;YAAzE,CACE,qBAAC,UAAD;GAAkB;GAAQ,MAAM,EAAE,MAAM,CAAC,YAAY;GAAa;aAAlE,CACE,oBAAC,iBAAD,EAAA,UACG,MAAM,KAAK,MAAM,UAChB,oBAAC,cAAD,EAAA,UAA2B,MAAoB,EAA5B,MAA4B,CAC/C,EACc,CAAA,EAEjB,UAAU,CAAC,cACV,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,kBAAD,EACE,WAAW,WAAW,UAAU,0BAA0B,KAAA,GAC1D,CAAA,EACF,oBAAC,cAAD,EAAc,WAAW,WAAW,UAAU,0BAA0B,KAAA,GAAa,CAAA,CACpF,EAAA,CAAA,CAEI;MAEV,YAAY,CAAC,cAAc,QAAQ,KAClC,oBAAC,OAAD;GACE,WAAW,GACT,6EACA,cACD;GACD,MAAK;aAEJ,MAAM,KAAK,EAAE,QAAQ,OAAO,CAAC,CAAC,KAAK,GAAG,UACrC,oBAAC,UAAD;IAEE,MAAK;IACL,MAAK;IACL,iBAAe,UAAU;IACzB,cAAY,eAAe,QAAQ;IACnC,eAAe,KAAK,SAAS,MAAM;IACnC,WAAW,GACT,gDACA,UAAU,UAAU,eAAe,0CACpC;IACD,EAVK,MAUL,CACF;GACE,CAAA,CAEJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"product-recommendations.d.ts","names":[],"sources":["../../../../src/client/storefront/components/product-recommendations.tsx"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"product-recommendations.d.ts","names":[],"sources":["../../../../src/client/storefront/components/product-recommendations.tsx"],"mappings":";;;;UAgBiB,2BAAA;EACf,KAAA;;EAEA,OAAA;EAH0C;EAK1C,QAAA,EAAU,OAAA,CAAM,SAAA;EAAS;EAEzB,WAAA;EACA,YAAA;EAHA;EAKA,UAAA;EALgB;EAOhB,OAAA;EACA,SAAA;AAAA;AAAA,iBAKc,sBAAA,CAAA;EACd,KAAA;EACA,QAAA;EACA,WAAA;EACA,YAAA;EACA,UAAA;EACA,OAAA;EACA;AAAA,GACC,2BAAA,GAA2B,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -3,43 +3,31 @@ import { useIcon } from "../../icons/icon-context.mjs";
|
|
|
3
3
|
import { cn } from "../../ui/utils.mjs";
|
|
4
4
|
import { getMotionConfig } from "../../motion/config.mjs";
|
|
5
5
|
import { staggerChildStyle, staggerEntryClass } from "../../motion/stagger.mjs";
|
|
6
|
+
import { Carousel, CarouselContent, CarouselItem } from "../../ui-resolver/carousel.mjs";
|
|
6
7
|
import * as React$1 from "react";
|
|
7
8
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
9
|
//#region src/client/storefront/components/product-recommendations.tsx
|
|
9
10
|
function ProductRecommendations({ title, children, viewAllHref, viewAllLabel = "View all", showArrows = true, delight = 0, className }) {
|
|
10
|
-
const
|
|
11
|
+
const [api, setApi] = React$1.useState();
|
|
12
|
+
const [canScrollPrev, setCanScrollPrev] = React$1.useState(false);
|
|
13
|
+
const [canScrollNext, setCanScrollNext] = React$1.useState(false);
|
|
11
14
|
const motion = React$1.useMemo(() => getMotionConfig(delight), [delight]);
|
|
12
|
-
const [canScrollLeft, setCanScrollLeft] = React$1.useState(false);
|
|
13
|
-
const [canScrollRight, setCanScrollRight] = React$1.useState(false);
|
|
14
15
|
const ChevronLeftIcon = useIcon("chevronLeft");
|
|
15
16
|
const ChevronRightIcon = useIcon("chevronRight");
|
|
16
|
-
const updateScrollState = React$1.useCallback(() => {
|
|
17
|
-
const el = scrollRef.current;
|
|
18
|
-
if (!el) return;
|
|
19
|
-
setCanScrollLeft(el.scrollLeft > 1);
|
|
20
|
-
setCanScrollRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
|
|
21
|
-
}, []);
|
|
22
17
|
React$1.useEffect(() => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
18
|
+
if (!api) return;
|
|
19
|
+
const onSelect = () => {
|
|
20
|
+
setCanScrollPrev(api.canScrollPrev());
|
|
21
|
+
setCanScrollNext(api.canScrollNext());
|
|
22
|
+
};
|
|
23
|
+
onSelect();
|
|
24
|
+
api.on("reInit", onSelect);
|
|
25
|
+
api.on("select", onSelect);
|
|
29
26
|
return () => {
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
api.off("reInit", onSelect);
|
|
28
|
+
api.off("select", onSelect);
|
|
32
29
|
};
|
|
33
|
-
}, [
|
|
34
|
-
const scroll = (direction) => {
|
|
35
|
-
const el = scrollRef.current;
|
|
36
|
-
if (!el) return;
|
|
37
|
-
const distance = el.clientWidth * .8;
|
|
38
|
-
el.scrollBy({
|
|
39
|
-
left: direction === "left" ? -distance : distance,
|
|
40
|
-
behavior: "smooth"
|
|
41
|
-
});
|
|
42
|
-
};
|
|
30
|
+
}, [api]);
|
|
43
31
|
return /* @__PURE__ */ jsxs("section", {
|
|
44
32
|
className: cn("flex flex-col gap-4", className),
|
|
45
33
|
children: [(title || viewAllHref) && /* @__PURE__ */ jsxs("div", {
|
|
@@ -55,25 +43,29 @@ function ProductRecommendations({ title, children, viewAllHref, viewAllLabel = "
|
|
|
55
43
|
}), /* @__PURE__ */ jsxs("div", {
|
|
56
44
|
className: "relative group/recs",
|
|
57
45
|
children: [
|
|
58
|
-
showArrows &&
|
|
46
|
+
showArrows && canScrollPrev && /* @__PURE__ */ jsx("button", {
|
|
59
47
|
type: "button",
|
|
60
|
-
onClick: () =>
|
|
48
|
+
onClick: () => api?.scrollPrev(),
|
|
61
49
|
className: "absolute left-0 top-1/2 -translate-y-1/2 z-10 hidden md:flex size-10 items-center justify-center rounded-full bg-(--enad-surface)/90 shadow-md border border-(--enad-border-color)/50 opacity-0 group-hover/recs:opacity-100 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 transition-opacity hover:bg-(--enad-surface)",
|
|
62
50
|
"aria-label": "Scroll left",
|
|
63
51
|
children: /* @__PURE__ */ jsx(ChevronLeftIcon, { className: "size-5" })
|
|
64
52
|
}),
|
|
65
|
-
/* @__PURE__ */ jsx(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
53
|
+
/* @__PURE__ */ jsx(Carousel, {
|
|
54
|
+
setApi,
|
|
55
|
+
opts: {
|
|
56
|
+
align: "start",
|
|
57
|
+
slidesToScroll: "auto",
|
|
58
|
+
containScroll: "trimSnaps"
|
|
59
|
+
},
|
|
60
|
+
children: /* @__PURE__ */ jsx(CarouselContent, { children: React$1.Children.map(children, (child, i) => /* @__PURE__ */ jsx(CarouselItem, {
|
|
61
|
+
className: cn("basis-auto w-[260px] sm:w-[280px] lg:w-[300px]", staggerEntryClass(motion)),
|
|
70
62
|
style: staggerChildStyle(i, motion),
|
|
71
63
|
children: child
|
|
72
|
-
}, i))
|
|
64
|
+
}, i)) })
|
|
73
65
|
}),
|
|
74
|
-
showArrows &&
|
|
66
|
+
showArrows && canScrollNext && /* @__PURE__ */ jsx("button", {
|
|
75
67
|
type: "button",
|
|
76
|
-
onClick: () =>
|
|
68
|
+
onClick: () => api?.scrollNext(),
|
|
77
69
|
className: "absolute right-0 top-1/2 -translate-y-1/2 z-10 hidden md:flex size-10 items-center justify-center rounded-full bg-(--enad-surface)/90 shadow-md border border-(--enad-border-color)/50 opacity-0 group-hover/recs:opacity-100 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 transition-opacity hover:bg-(--enad-surface)",
|
|
78
70
|
"aria-label": "Scroll right",
|
|
79
71
|
children: /* @__PURE__ */ jsx(ChevronRightIcon, { className: "size-5" })
|