@butternutbox/pawprint-native 0.3.2 → 0.4.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 +9 -9
- package/CHANGELOG.md +8 -0
- package/dist/index.cjs +965 -151
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +246 -5
- package/dist/index.d.ts +246 -5
- package/dist/index.js +960 -151
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/src/components/atoms/Hint/Hint.tsx +1 -2
- package/src/components/atoms/Input/InputField.tsx +7 -1
- package/src/components/molecules/Animated/Animated.tsx +12 -3
- package/src/components/molecules/Countdown/Countdown.stories.tsx +218 -0
- package/src/components/molecules/Countdown/Countdown.tsx +315 -0
- package/src/components/molecules/Countdown/index.ts +2 -0
- package/src/components/molecules/ProductDisplayCard/ProductDisplayCard.stories.tsx +248 -0
- package/src/components/molecules/ProductDisplayCard/ProductDisplayCard.test.tsx +198 -0
- package/src/components/molecules/ProductDisplayCard/ProductDisplayCard.tsx +243 -0
- package/src/components/molecules/ProductDisplayCard/index.ts +5 -0
- package/src/components/molecules/ProductListingCard/Badge.tsx +65 -0
- package/src/components/molecules/ProductListingCard/Grid.tsx +59 -0
- package/src/components/molecules/ProductListingCard/ProductListingCard.stories.tsx +209 -0
- package/src/components/molecules/ProductListingCard/ProductListingCard.tsx +235 -0
- package/src/components/molecules/ProductListingCard/index.ts +2 -0
- package/src/components/molecules/TabNavigation/TabNavigation.stories.tsx +183 -0
- package/src/components/molecules/TabNavigation/TabNavigation.tsx +354 -0
- package/src/components/molecules/TabNavigation/index.ts +7 -0
- package/src/components/molecules/index.ts +4 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/token.ts +1 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { View, ViewProps } from "react-native"
|
|
3
|
+
import styled from "@emotion/native"
|
|
4
|
+
import { Typography } from "../../atoms/Typography"
|
|
5
|
+
|
|
6
|
+
const parseTokenValue = (value: string | number): number => {
|
|
7
|
+
if (typeof value === "number") return value
|
|
8
|
+
return parseFloat(value)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
type BadgeOwnProps = {
|
|
12
|
+
icon?: React.ReactNode
|
|
13
|
+
text: React.ReactNode
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type BadgeProps = BadgeOwnProps & Omit<ViewProps, keyof BadgeOwnProps>
|
|
17
|
+
|
|
18
|
+
const BadgeContainer = styled(View)(({ theme }) => {
|
|
19
|
+
const spacing = theme.tokens.semantics.dimensions.spacing
|
|
20
|
+
const { sizing, borderRadius } = theme.tokens.semantics.dimensions
|
|
21
|
+
const { colour } = theme.tokens.semantics
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
display: "flex",
|
|
25
|
+
flexDirection: "row",
|
|
26
|
+
gap: parseTokenValue(spacing["2xs"]),
|
|
27
|
+
alignItems: "center",
|
|
28
|
+
justifyContent: "center",
|
|
29
|
+
height: parseTokenValue(sizing["2xl"]),
|
|
30
|
+
paddingRight: parseTokenValue(spacing.sm),
|
|
31
|
+
backgroundColor: colour.background.container.alt,
|
|
32
|
+
borderTopRightRadius: parseTokenValue(borderRadius.xs),
|
|
33
|
+
borderBottomRightRadius: parseTokenValue(borderRadius.xs)
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
const BadgeIcon = styled(View)(({ theme }) => {
|
|
38
|
+
const spacing = theme.tokens.semantics.dimensions.spacing
|
|
39
|
+
const sizing = theme.tokens.semantics.dimensions.sizing
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
display: "flex",
|
|
43
|
+
alignItems: "center",
|
|
44
|
+
justifyContent: "center",
|
|
45
|
+
width: parseTokenValue(sizing.md),
|
|
46
|
+
height: parseTokenValue(sizing.md),
|
|
47
|
+
marginLeft: parseTokenValue(spacing.xs),
|
|
48
|
+
flexShrink: 0
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
export const Badge = React.forwardRef<View, BadgeProps>(
|
|
53
|
+
({ icon, text, ...rest }, ref) => {
|
|
54
|
+
return (
|
|
55
|
+
<BadgeContainer ref={ref} {...rest}>
|
|
56
|
+
{icon && <BadgeIcon>{icon}</BadgeIcon>}
|
|
57
|
+
<Typography variant="body" size="sm" weight="bold">
|
|
58
|
+
{text}
|
|
59
|
+
</Typography>
|
|
60
|
+
</BadgeContainer>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
Badge.displayName = "ProductListingCard.Badge"
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { View, ViewProps, useWindowDimensions } from "react-native"
|
|
3
|
+
import styled from "@emotion/native"
|
|
4
|
+
import { DEFAULT_THEME_OPTIONS } from "@butternutbox/pawprint-tokens"
|
|
5
|
+
|
|
6
|
+
type ProductListingCardGridOwnProps = {
|
|
7
|
+
children: React.ReactNode
|
|
8
|
+
xs?: number
|
|
9
|
+
md?: number
|
|
10
|
+
lg?: number
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type ProductListingCardGridProps = ProductListingCardGridOwnProps &
|
|
14
|
+
Omit<ViewProps, keyof ProductListingCardGridOwnProps>
|
|
15
|
+
|
|
16
|
+
const StyledGrid = styled(View)(({ theme }) => {
|
|
17
|
+
const spacing = theme.tokens.semantics.dimensions.spacing
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
display: "grid",
|
|
21
|
+
"grid-column-gap": spacing.sm,
|
|
22
|
+
"grid-row-gap": spacing.xl
|
|
23
|
+
} as any
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
export const Grid = React.forwardRef<View, ProductListingCardGridProps>(
|
|
27
|
+
({ children, xs = 1, md = 2, lg = 3, ...rest }, ref) => {
|
|
28
|
+
const { width } = useWindowDimensions()
|
|
29
|
+
|
|
30
|
+
const breakpoints =
|
|
31
|
+
DEFAULT_THEME_OPTIONS.tokens.semantics.dimensions.breakpoints.spacing
|
|
32
|
+
const SM_BREAKPOINT = parseFloat(String(breakpoints.sm))
|
|
33
|
+
const MD_BREAKPOINT = parseFloat(String(breakpoints.md))
|
|
34
|
+
|
|
35
|
+
const getItemsPerRow = () => {
|
|
36
|
+
if (width >= MD_BREAKPOINT) return lg
|
|
37
|
+
if (width >= SM_BREAKPOINT) return md
|
|
38
|
+
return xs
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const itemsPerRow = getItemsPerRow()
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<StyledGrid
|
|
45
|
+
ref={ref}
|
|
46
|
+
style={
|
|
47
|
+
{
|
|
48
|
+
gridTemplateColumns: `repeat(${itemsPerRow}, 1fr)`
|
|
49
|
+
} as any
|
|
50
|
+
}
|
|
51
|
+
{...rest}
|
|
52
|
+
>
|
|
53
|
+
{children}
|
|
54
|
+
</StyledGrid>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
Grid.displayName = "ProductListingCard.Grid"
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { View } from "react-native"
|
|
3
|
+
import { ProductListingCard } from "./ProductListingCard"
|
|
4
|
+
import { Badge } from "./Badge"
|
|
5
|
+
import { ThumbsUpFilledPrimary } from "@butternutbox/pawprint-icons/marketing"
|
|
6
|
+
|
|
7
|
+
const defaultBadge = (
|
|
8
|
+
<Badge icon={<ThumbsUpFilledPrimary />} text="New & improved" />
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
const placeholderImage = {
|
|
12
|
+
uri: "https://placehold.co/232x232"
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default {
|
|
16
|
+
title: "Molecules/ProductListingCard",
|
|
17
|
+
component: ProductListingCard,
|
|
18
|
+
argTypes: {
|
|
19
|
+
image: {
|
|
20
|
+
description: "Product image source"
|
|
21
|
+
},
|
|
22
|
+
imageAlt: {
|
|
23
|
+
control: "text",
|
|
24
|
+
description: "Alt text for the product image"
|
|
25
|
+
},
|
|
26
|
+
badge: {
|
|
27
|
+
description: "Badge content to display in the top-left corner"
|
|
28
|
+
},
|
|
29
|
+
category: {
|
|
30
|
+
description: "Product category Typography element(s)"
|
|
31
|
+
},
|
|
32
|
+
title: {
|
|
33
|
+
description: "Product name/title Typography element(s)"
|
|
34
|
+
},
|
|
35
|
+
size: {
|
|
36
|
+
description: "Product size or variant Typography element(s)"
|
|
37
|
+
},
|
|
38
|
+
price: {
|
|
39
|
+
description: "Price content Typography element(s)"
|
|
40
|
+
},
|
|
41
|
+
showBadge: {
|
|
42
|
+
control: "boolean",
|
|
43
|
+
description: "Toggle badge visibility"
|
|
44
|
+
},
|
|
45
|
+
showCategory: {
|
|
46
|
+
control: "boolean",
|
|
47
|
+
description: "Toggle category visibility"
|
|
48
|
+
},
|
|
49
|
+
showTitle: {
|
|
50
|
+
control: "boolean",
|
|
51
|
+
description: "Toggle product title visibility"
|
|
52
|
+
},
|
|
53
|
+
showSize: {
|
|
54
|
+
control: "boolean",
|
|
55
|
+
description: "Toggle product size visibility"
|
|
56
|
+
},
|
|
57
|
+
showPrice: {
|
|
58
|
+
control: "boolean",
|
|
59
|
+
description: "Toggle price visibility"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const Default = {
|
|
65
|
+
render: () => (
|
|
66
|
+
<View style={{ width: 232, alignSelf: "flex-start" }}>
|
|
67
|
+
<ProductListingCard
|
|
68
|
+
image={placeholderImage}
|
|
69
|
+
imageAlt="Fish Oil Product"
|
|
70
|
+
badge={defaultBadge}
|
|
71
|
+
category="Daily supplements"
|
|
72
|
+
title="Fish Oil"
|
|
73
|
+
size="200ml"
|
|
74
|
+
price="From £7.49"
|
|
75
|
+
showBadge={true}
|
|
76
|
+
showCategory={true}
|
|
77
|
+
showTitle={true}
|
|
78
|
+
showSize={true}
|
|
79
|
+
showPrice={true}
|
|
80
|
+
/>
|
|
81
|
+
</View>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export const WithoutBadge = {
|
|
86
|
+
render: () => (
|
|
87
|
+
<View style={{ width: 232, alignSelf: "flex-start" }}>
|
|
88
|
+
<ProductListingCard
|
|
89
|
+
image={placeholderImage}
|
|
90
|
+
imageAlt="Fish Oil Product"
|
|
91
|
+
category="Daily supplements"
|
|
92
|
+
title="Fish Oil"
|
|
93
|
+
size="200ml"
|
|
94
|
+
price="From £7.49"
|
|
95
|
+
showBadge={false}
|
|
96
|
+
showCategory={true}
|
|
97
|
+
showTitle={true}
|
|
98
|
+
showSize={true}
|
|
99
|
+
showPrice={true}
|
|
100
|
+
/>
|
|
101
|
+
</View>
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export const MinimalInfo = {
|
|
106
|
+
render: () => (
|
|
107
|
+
<View style={{ width: 232, alignSelf: "flex-start" }}>
|
|
108
|
+
<ProductListingCard
|
|
109
|
+
image={{ uri: "https://placeholder.co/232x232" }}
|
|
110
|
+
imageAlt="Product"
|
|
111
|
+
title="Product Name"
|
|
112
|
+
price="£9.99"
|
|
113
|
+
showBadge={false}
|
|
114
|
+
showCategory={false}
|
|
115
|
+
showSize={false}
|
|
116
|
+
/>
|
|
117
|
+
</View>
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export const FullyCustomized = {
|
|
122
|
+
render: () => (
|
|
123
|
+
<View style={{ width: 232, alignSelf: "flex-start" }}>
|
|
124
|
+
<ProductListingCard
|
|
125
|
+
image={{ uri: "https://placehold.co/232x232" }}
|
|
126
|
+
imageAlt="Premium Item"
|
|
127
|
+
badge={<Badge icon="⭐" text="Premium" />}
|
|
128
|
+
category="Premium Collection"
|
|
129
|
+
title="Deluxe Supplement Pack"
|
|
130
|
+
size="500ml x 3 bottles"
|
|
131
|
+
price="From £24.99"
|
|
132
|
+
showBadge={true}
|
|
133
|
+
showCategory={true}
|
|
134
|
+
showTitle={true}
|
|
135
|
+
showSize={true}
|
|
136
|
+
showPrice={true}
|
|
137
|
+
/>
|
|
138
|
+
</View>
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export const Grid = {
|
|
143
|
+
render: () => (
|
|
144
|
+
<View style={{ width: "100%", padding: 16 }}>
|
|
145
|
+
<ProductListingCard.Grid xs={1} md={2} lg={3}>
|
|
146
|
+
{Array.from({ length: 6 }).map((_, i) => (
|
|
147
|
+
<ProductListingCard
|
|
148
|
+
key={i}
|
|
149
|
+
image={placeholderImage}
|
|
150
|
+
imageAlt="Fish Oil Product"
|
|
151
|
+
badge={defaultBadge}
|
|
152
|
+
category="Daily supplements"
|
|
153
|
+
title="Fish Oil"
|
|
154
|
+
size="200ml"
|
|
155
|
+
price="From £7.49"
|
|
156
|
+
showBadge={true}
|
|
157
|
+
showCategory={true}
|
|
158
|
+
showTitle={true}
|
|
159
|
+
showSize={true}
|
|
160
|
+
showPrice={true}
|
|
161
|
+
/>
|
|
162
|
+
))}
|
|
163
|
+
</ProductListingCard.Grid>
|
|
164
|
+
</View>
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export const Playground = {
|
|
169
|
+
render: () => (
|
|
170
|
+
<View style={{ width: 232, alignSelf: "flex-start" }}>
|
|
171
|
+
<ProductListingCard
|
|
172
|
+
image={placeholderImage}
|
|
173
|
+
imageAlt="Fish Oil Product"
|
|
174
|
+
badge={defaultBadge}
|
|
175
|
+
category="Daily supplements"
|
|
176
|
+
title="Fish Oil"
|
|
177
|
+
size="200ml"
|
|
178
|
+
price="From £7.49"
|
|
179
|
+
showBadge={true}
|
|
180
|
+
showCategory={true}
|
|
181
|
+
showTitle={true}
|
|
182
|
+
showSize={true}
|
|
183
|
+
showPrice={true}
|
|
184
|
+
/>
|
|
185
|
+
</View>
|
|
186
|
+
)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export const WithWasPrice = {
|
|
190
|
+
render: () => (
|
|
191
|
+
<View style={{ width: 232, alignSelf: "flex-start" }}>
|
|
192
|
+
<ProductListingCard
|
|
193
|
+
image={placeholderImage}
|
|
194
|
+
imageAlt="Fish Oil Product"
|
|
195
|
+
badge={defaultBadge}
|
|
196
|
+
category="Daily supplements"
|
|
197
|
+
title="Fish Oil"
|
|
198
|
+
size="200ml"
|
|
199
|
+
price="From £7.49"
|
|
200
|
+
wasPrice="£12.50"
|
|
201
|
+
showBadge={true}
|
|
202
|
+
showCategory={true}
|
|
203
|
+
showTitle={true}
|
|
204
|
+
showSize={true}
|
|
205
|
+
showPrice={true}
|
|
206
|
+
/>
|
|
207
|
+
</View>
|
|
208
|
+
)
|
|
209
|
+
}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
Image,
|
|
5
|
+
ImageSourcePropType,
|
|
6
|
+
Pressable,
|
|
7
|
+
PressableProps
|
|
8
|
+
} from "react-native"
|
|
9
|
+
import styled from "@emotion/native"
|
|
10
|
+
import { Typography } from "../../atoms/Typography"
|
|
11
|
+
import { Badge } from "./Badge"
|
|
12
|
+
import { Grid } from "./Grid"
|
|
13
|
+
|
|
14
|
+
type ProductListingCardOwnProps = {
|
|
15
|
+
image?: ImageSourcePropType
|
|
16
|
+
imageAlt?: string
|
|
17
|
+
badge?: React.ReactNode
|
|
18
|
+
category?: string
|
|
19
|
+
title?: string
|
|
20
|
+
size?: string
|
|
21
|
+
price?: string
|
|
22
|
+
wasPrice?: string
|
|
23
|
+
showBadge?: boolean
|
|
24
|
+
showCategory?: boolean
|
|
25
|
+
showTitle?: boolean
|
|
26
|
+
showSize?: boolean
|
|
27
|
+
showPrice?: boolean
|
|
28
|
+
onPress?: () => void
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type ProductListingCardProps = ProductListingCardOwnProps &
|
|
32
|
+
Omit<PressableProps, keyof ProductListingCardOwnProps>
|
|
33
|
+
|
|
34
|
+
const parseTokenValue = (value: string | number): number => {
|
|
35
|
+
if (typeof value === "number") return value
|
|
36
|
+
return parseFloat(value)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const StyledRoot = styled(Pressable)(({ theme }) => {
|
|
40
|
+
const spacing = theme.tokens.semantics.dimensions.spacing
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
display: "flex",
|
|
44
|
+
flexDirection: "column",
|
|
45
|
+
gap: parseTokenValue(spacing.md),
|
|
46
|
+
alignItems: "flex-start",
|
|
47
|
+
width: "100%"
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const ImageContainer = styled(View)({
|
|
52
|
+
position: "relative",
|
|
53
|
+
width: "100%",
|
|
54
|
+
aspectRatio: 1,
|
|
55
|
+
overflow: "hidden"
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
const StyledImage = styled(Image)({
|
|
59
|
+
width: "100%",
|
|
60
|
+
height: "100%",
|
|
61
|
+
resizeMode: "cover"
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
const BadgeContainer = styled(View)(({ theme }) => {
|
|
65
|
+
const spacing = theme.tokens.semantics.dimensions.spacing
|
|
66
|
+
const { sizing, borderRadius } = theme.tokens.semantics.dimensions
|
|
67
|
+
const { colour } = theme.tokens.semantics
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
position: "absolute",
|
|
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
|
+
})
|
|
85
|
+
|
|
86
|
+
const ContentContainer = styled(View)(({ theme }) => {
|
|
87
|
+
const spacing = theme.tokens.semantics.dimensions.spacing
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
display: "flex",
|
|
91
|
+
flexDirection: "column",
|
|
92
|
+
gap: parseTokenValue(spacing.md),
|
|
93
|
+
alignItems: "flex-start",
|
|
94
|
+
width: "100%"
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
const DetailsContainer = styled(View)({
|
|
99
|
+
display: "flex",
|
|
100
|
+
flexDirection: "column",
|
|
101
|
+
alignItems: "flex-start",
|
|
102
|
+
width: "100%"
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
const CategoryWrapper = styled(View)(({ theme }) => {
|
|
106
|
+
const spacing = theme.tokens.semantics.dimensions.spacing
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
marginBottom: parseTokenValue(spacing["3xs"])
|
|
110
|
+
}
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
const TitleContainer = styled(View)(({ theme }) => {
|
|
114
|
+
const spacing = theme.tokens.semantics.dimensions.spacing
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
display: "flex",
|
|
118
|
+
flexDirection: "row",
|
|
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
|
+
}
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
const PricingContainer = styled(View)(({ theme }) => {
|
|
133
|
+
const spacing = theme.tokens.semantics.dimensions.spacing
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
display: "flex",
|
|
137
|
+
flexDirection: "row",
|
|
138
|
+
gap: Math.round(parseFloat(spacing["2xs"] as string)),
|
|
139
|
+
alignItems: "center",
|
|
140
|
+
width: "100%"
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
const _ProductListingCard = React.forwardRef<View, ProductListingCardProps>(
|
|
145
|
+
(
|
|
146
|
+
{
|
|
147
|
+
image,
|
|
148
|
+
imageAlt,
|
|
149
|
+
badge,
|
|
150
|
+
category,
|
|
151
|
+
title,
|
|
152
|
+
size,
|
|
153
|
+
price,
|
|
154
|
+
wasPrice,
|
|
155
|
+
showBadge = true,
|
|
156
|
+
showCategory = true,
|
|
157
|
+
showTitle = true,
|
|
158
|
+
showSize = true,
|
|
159
|
+
showPrice = true,
|
|
160
|
+
onPress,
|
|
161
|
+
...rest
|
|
162
|
+
},
|
|
163
|
+
ref
|
|
164
|
+
) => {
|
|
165
|
+
return (
|
|
166
|
+
<StyledRoot ref={ref} onPress={onPress} {...rest}>
|
|
167
|
+
<ImageContainer>
|
|
168
|
+
{image && (
|
|
169
|
+
<View style={{ flex: 1, width: "100%", height: "100%" }}>
|
|
170
|
+
<StyledImage
|
|
171
|
+
source={image}
|
|
172
|
+
accessibilityLabel={imageAlt}
|
|
173
|
+
accessible
|
|
174
|
+
/>
|
|
175
|
+
</View>
|
|
176
|
+
)}
|
|
177
|
+
{showBadge && badge && <BadgeContainer>{badge}</BadgeContainer>}
|
|
178
|
+
</ImageContainer>
|
|
179
|
+
|
|
180
|
+
<ContentContainer>
|
|
181
|
+
<DetailsContainer>
|
|
182
|
+
{showCategory && category && (
|
|
183
|
+
<CategoryWrapper>
|
|
184
|
+
<Typography variant="body" size="sm" color="secondary">
|
|
185
|
+
{category}
|
|
186
|
+
</Typography>
|
|
187
|
+
</CategoryWrapper>
|
|
188
|
+
)}
|
|
189
|
+
{showTitle && (
|
|
190
|
+
<TitleContainer>
|
|
191
|
+
<Typography variant="heading" size="xs">
|
|
192
|
+
{title}
|
|
193
|
+
</Typography>
|
|
194
|
+
</TitleContainer>
|
|
195
|
+
)}
|
|
196
|
+
{showSize && size && (
|
|
197
|
+
<SizeWrapper>
|
|
198
|
+
<Typography variant="body" size="md" color="secondary">
|
|
199
|
+
{size}
|
|
200
|
+
</Typography>
|
|
201
|
+
</SizeWrapper>
|
|
202
|
+
)}
|
|
203
|
+
</DetailsContainer>
|
|
204
|
+
|
|
205
|
+
{showPrice && price && (
|
|
206
|
+
<PricingContainer>
|
|
207
|
+
<Typography variant="body" size="md" color="secondary">
|
|
208
|
+
{price}
|
|
209
|
+
</Typography>
|
|
210
|
+
{wasPrice && (
|
|
211
|
+
<Typography
|
|
212
|
+
variant="body"
|
|
213
|
+
size="md"
|
|
214
|
+
color="secondary"
|
|
215
|
+
textDecoration="line-through"
|
|
216
|
+
>
|
|
217
|
+
{wasPrice}
|
|
218
|
+
</Typography>
|
|
219
|
+
)}
|
|
220
|
+
</PricingContainer>
|
|
221
|
+
)}
|
|
222
|
+
</ContentContainer>
|
|
223
|
+
</StyledRoot>
|
|
224
|
+
)
|
|
225
|
+
}
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
_ProductListingCard.displayName = "ProductListingCard"
|
|
229
|
+
|
|
230
|
+
const ProductListingCardWithBadgeAndGrid = Object.assign(_ProductListingCard, {
|
|
231
|
+
Badge,
|
|
232
|
+
Grid
|
|
233
|
+
}) as typeof _ProductListingCard & { Badge: typeof Badge; Grid: typeof Grid }
|
|
234
|
+
|
|
235
|
+
export { ProductListingCardWithBadgeAndGrid as ProductListingCard }
|