@butternutbox/pawprint-native 0.8.0 → 0.9.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/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +21 -0
- package/dist/index.cjs +79 -127
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +0 -10
- package/dist/index.d.ts +0 -10
- package/dist/index.js +79 -127
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/molecules/ProductDisplayCard/ProductDisplayCard.stories.tsx +2 -84
- package/src/components/molecules/ProductDisplayCard/ProductDisplayCard.test.tsx +1 -7
- package/src/components/molecules/ProductDisplayCard/ProductDisplayCard.tsx +58 -104
- package/src/components/molecules/ProductListingCard/Badge.tsx +2 -2
- package/src/components/molecules/ProductListingCard/ProductListingCard.tsx +22 -46
package/package.json
CHANGED
|
@@ -3,7 +3,8 @@ import { View, StyleSheet } from "react-native"
|
|
|
3
3
|
import { ProductDisplayCard } from "./ProductDisplayCard"
|
|
4
4
|
import type { ProductDisplayCardProps } from "./ProductDisplayCard"
|
|
5
5
|
|
|
6
|
-
const placeholderImageUrl =
|
|
6
|
+
const placeholderImageUrl =
|
|
7
|
+
"https://placehold.co/148x148/EEE/31343C?font=oswald&text=product"
|
|
7
8
|
|
|
8
9
|
const styles = StyleSheet.create({
|
|
9
10
|
column: { flexDirection: "column", gap: 24, padding: 16 }
|
|
@@ -13,11 +14,6 @@ export default {
|
|
|
13
14
|
title: "Molecules/ProductDisplayCard",
|
|
14
15
|
component: ProductDisplayCard,
|
|
15
16
|
argTypes: {
|
|
16
|
-
device: {
|
|
17
|
-
control: { type: "select" },
|
|
18
|
-
options: ["desktop", "mobile"],
|
|
19
|
-
description: "Device variant affecting sizing and typography"
|
|
20
|
-
},
|
|
21
17
|
title: {
|
|
22
18
|
control: { type: "text" },
|
|
23
19
|
description: "Product title"
|
|
@@ -38,10 +34,6 @@ export default {
|
|
|
38
34
|
control: { type: "boolean" },
|
|
39
35
|
description: "Show/hide quantity picker"
|
|
40
36
|
},
|
|
41
|
-
showImageQuantityBadge: {
|
|
42
|
-
control: { type: "boolean" },
|
|
43
|
-
description: "Show/hide quantity badge overlay on image"
|
|
44
|
-
},
|
|
45
37
|
disableQuantityButtons: {
|
|
46
38
|
control: { type: "boolean" },
|
|
47
39
|
description: "Disable quantity buttons"
|
|
@@ -50,14 +42,6 @@ export default {
|
|
|
50
42
|
control: { type: "boolean" },
|
|
51
43
|
description: "Hide quantity buttons"
|
|
52
44
|
},
|
|
53
|
-
showIncrementButton: {
|
|
54
|
-
control: { type: "boolean" },
|
|
55
|
-
description: "Show/hide increment button"
|
|
56
|
-
},
|
|
57
|
-
showDecrementButton: {
|
|
58
|
-
control: { type: "boolean" },
|
|
59
|
-
description: "Show/hide decrement button"
|
|
60
|
-
},
|
|
61
45
|
incrementDisabled: {
|
|
62
46
|
control: { type: "boolean" },
|
|
63
47
|
description: "Disable increment button"
|
|
@@ -100,7 +84,6 @@ export const Playground = (args: ProductDisplayCardProps) => (
|
|
|
100
84
|
</View>
|
|
101
85
|
)
|
|
102
86
|
Playground.args = {
|
|
103
|
-
device: "mobile",
|
|
104
87
|
title: "Recipe Name",
|
|
105
88
|
subtext: "+£0.00/pouch",
|
|
106
89
|
showSubtext: true,
|
|
@@ -127,20 +110,6 @@ export const Default = () => (
|
|
|
127
110
|
</View>
|
|
128
111
|
)
|
|
129
112
|
|
|
130
|
-
export const Desktop = () => (
|
|
131
|
-
<View style={styles.column}>
|
|
132
|
-
<ProductDisplayCard
|
|
133
|
-
title="Recipe Name"
|
|
134
|
-
subtext="+£0.00/pouch"
|
|
135
|
-
showSubtext
|
|
136
|
-
quantity={1}
|
|
137
|
-
showQuantityPicker
|
|
138
|
-
showBanner={false}
|
|
139
|
-
image={placeholderImageUrl}
|
|
140
|
-
/>
|
|
141
|
-
</View>
|
|
142
|
-
)
|
|
143
|
-
|
|
144
113
|
export const Mobile = () => (
|
|
145
114
|
<View style={styles.column}>
|
|
146
115
|
<ProductDisplayCard
|
|
@@ -202,32 +171,6 @@ export const NoSubtext = () => (
|
|
|
202
171
|
</View>
|
|
203
172
|
)
|
|
204
173
|
|
|
205
|
-
export const WithImageQuantityBadge = () => (
|
|
206
|
-
<View style={styles.column}>
|
|
207
|
-
<ProductDisplayCard
|
|
208
|
-
title="Gobble Gobble Turkey"
|
|
209
|
-
subtext="+£0.50/pouch"
|
|
210
|
-
showSubtext
|
|
211
|
-
quantity={4}
|
|
212
|
-
showQuantityPicker={false}
|
|
213
|
-
showImageQuantityBadge
|
|
214
|
-
showBanner={false}
|
|
215
|
-
image={placeholderImageUrl}
|
|
216
|
-
/>
|
|
217
|
-
|
|
218
|
-
<ProductDisplayCard
|
|
219
|
-
title="Salmon Delight"
|
|
220
|
-
subtext="+£0.25/pouch"
|
|
221
|
-
showSubtext
|
|
222
|
-
quantity={2}
|
|
223
|
-
showQuantityPicker
|
|
224
|
-
showImageQuantityBadge
|
|
225
|
-
showBanner={false}
|
|
226
|
-
image={placeholderImageUrl}
|
|
227
|
-
/>
|
|
228
|
-
</View>
|
|
229
|
-
)
|
|
230
|
-
|
|
231
174
|
export const AllVariants = () => (
|
|
232
175
|
<View style={styles.column}>
|
|
233
176
|
<ProductDisplayCard
|
|
@@ -262,28 +205,3 @@ export const AllVariants = () => (
|
|
|
262
205
|
/>
|
|
263
206
|
</View>
|
|
264
207
|
)
|
|
265
|
-
|
|
266
|
-
export const Borderless = () => (
|
|
267
|
-
<View style={styles.column}>
|
|
268
|
-
<ProductDisplayCard
|
|
269
|
-
title="Recipe Name"
|
|
270
|
-
subtext="+£0.00/pouch"
|
|
271
|
-
showSubtext
|
|
272
|
-
quantity={1}
|
|
273
|
-
showQuantityPicker
|
|
274
|
-
borderless
|
|
275
|
-
image={placeholderImageUrl}
|
|
276
|
-
/>
|
|
277
|
-
|
|
278
|
-
<ProductDisplayCard
|
|
279
|
-
title="Premium Recipe"
|
|
280
|
-
subtext="+£0.50/pouch"
|
|
281
|
-
showSubtext
|
|
282
|
-
quantity={2}
|
|
283
|
-
showQuantityPicker
|
|
284
|
-
showImageQuantityBadge
|
|
285
|
-
borderless
|
|
286
|
-
image={placeholderImageUrl}
|
|
287
|
-
/>
|
|
288
|
-
</View>
|
|
289
|
-
)
|
|
@@ -95,13 +95,7 @@ describe("ProductDisplayCard (Native)", () => {
|
|
|
95
95
|
expect(screen.queryByText("Test Banner")).toBeFalsy()
|
|
96
96
|
})
|
|
97
97
|
|
|
98
|
-
it("renders
|
|
99
|
-
renderWithTheme(<ProductDisplayCard title="Test Product" />)
|
|
100
|
-
|
|
101
|
-
expect(screen.getByText("Test Product")).toBeTruthy()
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
it("renders with mobile device variant when specified", () => {
|
|
98
|
+
it("renders as a mobile card", () => {
|
|
105
99
|
renderWithTheme(<ProductDisplayCard title="Test Product" />)
|
|
106
100
|
|
|
107
101
|
expect(screen.getByText("Test Product")).toBeTruthy()
|
|
@@ -15,26 +15,18 @@ export type ProductDisplayCardProps = ViewProps & {
|
|
|
15
15
|
showQuantityPicker?: boolean
|
|
16
16
|
disableQuantityButtons?: boolean
|
|
17
17
|
hideQuantityButtons?: boolean
|
|
18
|
-
showIncrementButton?: boolean
|
|
19
|
-
showDecrementButton?: boolean
|
|
20
18
|
incrementDisabled?: boolean
|
|
21
19
|
decrementDisabled?: boolean
|
|
22
20
|
image?: string | React.ReactNode
|
|
23
21
|
imageBackgroundColor?: string
|
|
24
22
|
thumbnailWidth?: number
|
|
25
|
-
thumbnailBackgroundColor?: string
|
|
26
|
-
showImageQuantityBadge?: boolean
|
|
27
|
-
borderless?: boolean
|
|
28
23
|
banner?: React.ReactNode
|
|
29
24
|
showBanner?: boolean
|
|
30
25
|
bannerType?: "error" | "success" | "warning" | "info"
|
|
31
26
|
showBannerIcon?: boolean
|
|
32
27
|
}
|
|
33
28
|
|
|
34
|
-
const StyledCardContainer = styled(View)
|
|
35
|
-
theme,
|
|
36
|
-
borderless
|
|
37
|
-
}) => {
|
|
29
|
+
const StyledCardContainer = styled(View)(({ theme }) => {
|
|
38
30
|
const { spacing, borderRadius } = theme.tokens.semantics.dimensions
|
|
39
31
|
const { colour } = theme.tokens.semantics
|
|
40
32
|
const spacingMd = parseTokenValue(spacing.md)
|
|
@@ -42,20 +34,20 @@ const StyledCardContainer = styled(View)<{ borderless?: boolean }>(({
|
|
|
42
34
|
return {
|
|
43
35
|
flexDirection: "row",
|
|
44
36
|
width: "100%",
|
|
45
|
-
|
|
46
|
-
|
|
37
|
+
// Cap at the Figma mobile card width (can be narrower — responsive).
|
|
38
|
+
maxWidth: 358,
|
|
39
|
+
// The 148px image sets the baseline height; the card grows if the content
|
|
40
|
+
// is taller (e.g. a long or translated title wrapping to multiple lines)
|
|
41
|
+
// so nothing is clipped.
|
|
42
|
+
minHeight: 148,
|
|
47
43
|
backgroundColor: colour.background.surface.default,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
shadowOpacity: 0.05,
|
|
56
|
-
shadowRadius: spacingXl - 4,
|
|
57
|
-
elevation: 5
|
|
58
|
-
}),
|
|
44
|
+
borderWidth: 1,
|
|
45
|
+
borderColor: colour.border.default,
|
|
46
|
+
shadowColor: "#522a10",
|
|
47
|
+
shadowOffset: { width: 0, height: spacingMd / 4 },
|
|
48
|
+
shadowOpacity: 0.05,
|
|
49
|
+
shadowRadius: spacingXl - 4,
|
|
50
|
+
elevation: 5,
|
|
59
51
|
borderRadius: parseTokenValue(borderRadius.md),
|
|
60
52
|
overflow: "hidden",
|
|
61
53
|
zIndex: 1
|
|
@@ -65,57 +57,26 @@ const StyledCardContainer = styled(View)<{ borderless?: boolean }>(({
|
|
|
65
57
|
const StyledImage = styled(View)<{
|
|
66
58
|
imageBackgroundColor?: string
|
|
67
59
|
thumbnailWidth?: number
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
theme.tokens.semantics.colour.background.container.secondary,
|
|
81
|
-
overflow: "hidden",
|
|
82
|
-
aspectRatio: "1 / 1",
|
|
83
|
-
width: thumbnailWidth,
|
|
84
|
-
height: thumbnailWidth,
|
|
85
|
-
position: "relative"
|
|
86
|
-
})
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
const StyledQuantityBadge = styled(View)(({ theme }) => {
|
|
90
|
-
const spacing = theme.tokens.semantics.dimensions.spacing
|
|
91
|
-
const borderRadius = theme.tokens.semantics.dimensions.borderRadius
|
|
92
|
-
const { colour } = theme.tokens.semantics
|
|
93
|
-
|
|
94
|
-
return {
|
|
95
|
-
position: "absolute",
|
|
96
|
-
top: parseTokenValue(spacing["2xs"]),
|
|
97
|
-
right: parseTokenValue(spacing["2xs"]),
|
|
98
|
-
backgroundColor: colour.background.container.brand,
|
|
99
|
-
borderRadius: parseTokenValue(borderRadius.xs),
|
|
100
|
-
paddingHorizontal: parseTokenValue(spacing.sm),
|
|
101
|
-
height: parseTokenValue(spacing["2xl"]),
|
|
102
|
-
minWidth: parseTokenValue(spacing["2xl"]),
|
|
103
|
-
alignItems: "center",
|
|
104
|
-
justifyContent: "center",
|
|
105
|
-
zIndex: 2
|
|
106
|
-
}
|
|
107
|
-
})
|
|
60
|
+
}>(({ theme, imageBackgroundColor, thumbnailWidth = 148 }) => ({
|
|
61
|
+
flexShrink: 0,
|
|
62
|
+
backgroundColor:
|
|
63
|
+
imageBackgroundColor ||
|
|
64
|
+
theme.tokens.semantics.colour.background.container.secondary,
|
|
65
|
+
overflow: "hidden",
|
|
66
|
+
width: thumbnailWidth,
|
|
67
|
+
// Square (148) by default; stretches taller to fill the card when the
|
|
68
|
+
// content makes it taller than the image.
|
|
69
|
+
minHeight: thumbnailWidth,
|
|
70
|
+
position: "relative"
|
|
71
|
+
}))
|
|
108
72
|
|
|
109
|
-
const StyledContentArea = styled(View)
|
|
110
|
-
theme,
|
|
111
|
-
borderless
|
|
112
|
-
}) => {
|
|
73
|
+
const StyledContentArea = styled(View)(({ theme }) => {
|
|
113
74
|
const { spacing } = theme.tokens.semantics.dimensions
|
|
114
75
|
const paddingValue = parseTokenValue(spacing.md)
|
|
115
76
|
return {
|
|
116
77
|
flex: 1,
|
|
117
78
|
paddingHorizontal: paddingValue,
|
|
118
|
-
paddingVertical:
|
|
79
|
+
paddingVertical: paddingValue,
|
|
119
80
|
gap: parseTokenValue(spacing.xs),
|
|
120
81
|
justifyContent: "space-between"
|
|
121
82
|
}
|
|
@@ -125,27 +86,40 @@ const StyledTextContainer = styled(View)(() => ({
|
|
|
125
86
|
gap: 2
|
|
126
87
|
}))
|
|
127
88
|
|
|
128
|
-
const StyledBannerWrapper = styled(View)(() =>
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
89
|
+
const StyledBannerWrapper = styled(View)(({ theme }) => {
|
|
90
|
+
const { spacing, borderRadius } = theme.tokens.semantics.dimensions
|
|
91
|
+
return {
|
|
92
|
+
width: "100%",
|
|
93
|
+
// Tuck the banner up behind the card by the corner radius so its square top
|
|
94
|
+
// corners hide under the card's rounded bottom; the rest sits below.
|
|
95
|
+
marginTop: -parseTokenValue(borderRadius.md),
|
|
96
|
+
paddingBottom: parseTokenValue(spacing.md)
|
|
97
|
+
}
|
|
98
|
+
})
|
|
134
99
|
|
|
135
100
|
const StyledRootWrapper = styled(View)(() => {
|
|
136
101
|
return {
|
|
137
102
|
flexDirection: "column",
|
|
138
103
|
width: "100%",
|
|
139
|
-
|
|
104
|
+
maxWidth: 358
|
|
140
105
|
}
|
|
141
106
|
})
|
|
142
107
|
|
|
143
108
|
const StyledNotification = styled(Notification as any)(({ theme }) => {
|
|
144
|
-
const { spacing } = theme.tokens.semantics.dimensions
|
|
109
|
+
const { spacing, borderRadius } = theme.tokens.semantics.dimensions
|
|
110
|
+
const spacingMd = parseTokenValue(spacing.md)
|
|
111
|
+
const radiusMd = parseTokenValue(borderRadius.md)
|
|
145
112
|
return {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
113
|
+
paddingHorizontal: spacingMd,
|
|
114
|
+
// 27px top padding (Figma) leaves a small cream reveal above the text once
|
|
115
|
+
// the banner tucks behind the card.
|
|
116
|
+
paddingTop: 27,
|
|
117
|
+
paddingBottom: spacingMd,
|
|
118
|
+
// Square top corners, rounded bottom corners (banner tucks under the card).
|
|
119
|
+
borderTopLeftRadius: 0,
|
|
120
|
+
borderTopRightRadius: 0,
|
|
121
|
+
borderBottomLeftRadius: radiusMd,
|
|
122
|
+
borderBottomRightRadius: radiusMd
|
|
149
123
|
}
|
|
150
124
|
})
|
|
151
125
|
|
|
@@ -190,16 +164,11 @@ export const ProductDisplayCard = React.forwardRef<
|
|
|
190
164
|
showQuantityPicker = false,
|
|
191
165
|
disableQuantityButtons = false,
|
|
192
166
|
hideQuantityButtons = false,
|
|
193
|
-
showIncrementButton,
|
|
194
|
-
showDecrementButton,
|
|
195
167
|
incrementDisabled = false,
|
|
196
168
|
decrementDisabled = false,
|
|
197
169
|
image,
|
|
198
170
|
imageBackgroundColor,
|
|
199
171
|
thumbnailWidth,
|
|
200
|
-
thumbnailBackgroundColor,
|
|
201
|
-
showImageQuantityBadge = false,
|
|
202
|
-
borderless = false,
|
|
203
172
|
banner,
|
|
204
173
|
showBanner = false,
|
|
205
174
|
bannerType = "info",
|
|
@@ -215,32 +184,25 @@ export const ProductDisplayCard = React.forwardRef<
|
|
|
215
184
|
}
|
|
216
185
|
|
|
217
186
|
const cardContent = (
|
|
218
|
-
<StyledCardContainer ref={ref}
|
|
187
|
+
<StyledCardContainer ref={ref} {...rest}>
|
|
219
188
|
{image && (
|
|
220
189
|
<StyledImage
|
|
221
190
|
imageBackgroundColor={imageBackgroundColor}
|
|
222
191
|
thumbnailWidth={thumbnailWidth}
|
|
223
|
-
thumbnailBackgroundColor={thumbnailBackgroundColor}
|
|
224
192
|
>
|
|
225
193
|
{typeof image === "string" ? (
|
|
226
194
|
<Image
|
|
227
195
|
source={{ uri: image }}
|
|
228
|
-
|
|
196
|
+
resizeMode="cover"
|
|
197
|
+
style={{ flex: 1, width: "100%" }}
|
|
229
198
|
/>
|
|
230
199
|
) : (
|
|
231
200
|
image
|
|
232
201
|
)}
|
|
233
|
-
{showImageQuantityBadge && quantity && (
|
|
234
|
-
<StyledQuantityBadge>
|
|
235
|
-
<Typography variant="body" size="sm" weight="bold">
|
|
236
|
-
{quantity}
|
|
237
|
-
</Typography>
|
|
238
|
-
</StyledQuantityBadge>
|
|
239
|
-
)}
|
|
240
202
|
</StyledImage>
|
|
241
203
|
)}
|
|
242
204
|
|
|
243
|
-
<StyledContentArea
|
|
205
|
+
<StyledContentArea>
|
|
244
206
|
<StyledTextContainer>
|
|
245
207
|
<Typography variant="heading" size="2xs" color="primary">
|
|
246
208
|
{title}
|
|
@@ -269,16 +231,8 @@ export const ProductDisplayCard = React.forwardRef<
|
|
|
269
231
|
min={1}
|
|
270
232
|
accessible
|
|
271
233
|
accessibilityLabel={`Quantity: ${quantity}`}
|
|
272
|
-
showIncrementButton={
|
|
273
|
-
|
|
274
|
-
? showIncrementButton
|
|
275
|
-
: !hideQuantityButtons
|
|
276
|
-
}
|
|
277
|
-
showDecrementButton={
|
|
278
|
-
showDecrementButton !== undefined
|
|
279
|
-
? showDecrementButton
|
|
280
|
-
: !hideQuantityButtons
|
|
281
|
-
}
|
|
234
|
+
showIncrementButton={!hideQuantityButtons}
|
|
235
|
+
showDecrementButton={!hideQuantityButtons}
|
|
282
236
|
incrementDisabled={incrementDisabled || disableQuantityButtons}
|
|
283
237
|
decrementDisabled={decrementDisabled || disableQuantityButtons}
|
|
284
238
|
/>
|
|
@@ -27,8 +27,8 @@ const BadgeContainer = styled(View)(({ theme }) => {
|
|
|
27
27
|
alignItems: "center",
|
|
28
28
|
justifyContent: "center",
|
|
29
29
|
height: parseTokenValue(sizing["2xl"]),
|
|
30
|
-
paddingRight: parseTokenValue(spacing.
|
|
31
|
-
backgroundColor: colour.background.container.
|
|
30
|
+
paddingRight: parseTokenValue(spacing.xs),
|
|
31
|
+
backgroundColor: colour.background.container.brand,
|
|
32
32
|
borderTopRightRadius: parseTokenValue(borderRadius.xs),
|
|
33
33
|
borderBottomRightRadius: parseTokenValue(borderRadius.xs)
|
|
34
34
|
}
|
|
@@ -48,12 +48,15 @@ const StyledRoot = styled(Pressable)(({ theme }) => {
|
|
|
48
48
|
}
|
|
49
49
|
})
|
|
50
50
|
|
|
51
|
-
const ImageContainer = styled(View)({
|
|
51
|
+
const ImageContainer = styled(View)(({ theme }) => ({
|
|
52
52
|
position: "relative",
|
|
53
53
|
width: "100%",
|
|
54
54
|
aspectRatio: 1,
|
|
55
|
-
overflow: "hidden"
|
|
56
|
-
|
|
55
|
+
overflow: "hidden",
|
|
56
|
+
borderRadius: parseTokenValue(
|
|
57
|
+
theme.tokens.semantics.dimensions.borderRadius.md
|
|
58
|
+
)
|
|
59
|
+
}))
|
|
57
60
|
|
|
58
61
|
const StyledImage = styled(Image)({
|
|
59
62
|
width: "100%",
|
|
@@ -61,27 +64,13 @@ const StyledImage = styled(Image)({
|
|
|
61
64
|
resizeMode: "cover"
|
|
62
65
|
})
|
|
63
66
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
top: parseTokenValue(spacing.md),
|
|
72
|
-
left: 0,
|
|
73
|
-
display: "flex",
|
|
74
|
-
flexDirection: "row",
|
|
75
|
-
gap: parseTokenValue(spacing["2xs"]),
|
|
76
|
-
alignItems: "center",
|
|
77
|
-
justifyContent: "center",
|
|
78
|
-
height: parseTokenValue(sizing["2xl"]),
|
|
79
|
-
paddingRight: parseTokenValue(spacing.sm),
|
|
80
|
-
backgroundColor: colour.background.container.alt,
|
|
81
|
-
borderTopRightRadius: parseTokenValue(borderRadius.sm),
|
|
82
|
-
borderBottomRightRadius: parseTokenValue(borderRadius.sm)
|
|
83
|
-
}
|
|
84
|
-
})
|
|
67
|
+
// Positioning only — the visual badge (background, padding, radius) is the
|
|
68
|
+
// `Badge` component rendered inside, so it isn't double-wrapped.
|
|
69
|
+
const BadgeContainer = styled(View)(({ theme }) => ({
|
|
70
|
+
position: "absolute",
|
|
71
|
+
top: parseTokenValue(theme.tokens.semantics.dimensions.spacing.md),
|
|
72
|
+
left: 0
|
|
73
|
+
}))
|
|
85
74
|
|
|
86
75
|
const ContentContainer = styled(View)(({ theme }) => {
|
|
87
76
|
const spacing = theme.tokens.semantics.dimensions.spacing
|
|
@@ -110,23 +99,12 @@ const CategoryWrapper = styled(View)(({ theme }) => {
|
|
|
110
99
|
}
|
|
111
100
|
})
|
|
112
101
|
|
|
113
|
-
const TitleContainer = styled(View)(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
width: "100%",
|
|
120
|
-
marginBottom: parseTokenValue(spacing.xs)
|
|
121
|
-
}
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
const SizeWrapper = styled(View)(({ theme }) => {
|
|
125
|
-
const spacing = theme.tokens.semantics.dimensions.spacing
|
|
126
|
-
|
|
127
|
-
return {
|
|
128
|
-
marginBottom: parseTokenValue(spacing.md)
|
|
129
|
-
}
|
|
102
|
+
const TitleContainer = styled(View)({
|
|
103
|
+
display: "flex",
|
|
104
|
+
flexDirection: "row",
|
|
105
|
+
width: "100%",
|
|
106
|
+
// 6px below the title to match Figma (4px title bottom padding + 2px gap).
|
|
107
|
+
marginBottom: 6
|
|
130
108
|
})
|
|
131
109
|
|
|
132
110
|
const PricingContainer = styled(View)(({ theme }) => {
|
|
@@ -194,11 +172,9 @@ const _ProductListingCard = React.forwardRef<View, ProductListingCardProps>(
|
|
|
194
172
|
</TitleContainer>
|
|
195
173
|
)}
|
|
196
174
|
{showSize && size && (
|
|
197
|
-
<
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
</Typography>
|
|
201
|
-
</SizeWrapper>
|
|
175
|
+
<Typography variant="body" size="md" color="secondary">
|
|
176
|
+
{size}
|
|
177
|
+
</Typography>
|
|
202
178
|
)}
|
|
203
179
|
</DetailsContainer>
|
|
204
180
|
|