@butternutbox/pawprint-native 0.4.0 → 0.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@butternutbox/pawprint-native",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "description": "ButternutBox Pawprint Design System - React Native Components",
6
6
  "main": "./dist/index.cjs",
@@ -40,6 +40,11 @@ export default {
40
40
  label: {
41
41
  control: { type: "text" },
42
42
  description: "Customizable prefix label (inline layout only)"
43
+ },
44
+ labels: {
45
+ control: { type: "object" },
46
+ description:
47
+ "Per-unit labels (days/hours/minutes/seconds). Pass translated strings; omitted units fall back to the English defaults."
43
48
  }
44
49
  }
45
50
  }
@@ -139,6 +144,36 @@ export const WithoutSeconds = {
139
144
  )
140
145
  }
141
146
 
147
+ export const TranslatedLabels = {
148
+ name: "Translated Labels",
149
+ render: () => (
150
+ <View style={styles.column}>
151
+ <Countdown
152
+ layout="stacked"
153
+ labels={{
154
+ days: { singular: "jour", plural: "jours" },
155
+ hours: { singular: "heure", plural: "heures" },
156
+ minutes: { singular: "min", plural: "min" },
157
+ seconds: { singular: "sec", plural: "sec" }
158
+ }}
159
+ days={1}
160
+ hours={2}
161
+ minutes={48}
162
+ seconds={38}
163
+ />
164
+ <Countdown
165
+ layout="inline"
166
+ label="La vente se termine dans :"
167
+ labels={{ days: "j", hours: "h", minutes: "min", seconds: "s" }}
168
+ days={2}
169
+ hours={9}
170
+ minutes={48}
171
+ seconds={38}
172
+ />
173
+ </View>
174
+ )
175
+ }
176
+
142
177
  export const AllVariants = {
143
178
  name: "All Variants",
144
179
  render: () => (
@@ -12,6 +12,20 @@ type CountdownUnit = {
12
12
  label: string
13
13
  }
14
14
 
15
+ /**
16
+ * A unit label. Pass a plain string to use it regardless of count, or a
17
+ * `{ singular, plural }` pair to pluralise based on the unit's value
18
+ * (`singular` when the value is exactly 1, `plural` otherwise).
19
+ */
20
+ export type CountdownUnitLabel = string | { singular: string; plural: string }
21
+
22
+ export type CountdownLabels = {
23
+ days?: CountdownUnitLabel
24
+ hours?: CountdownUnitLabel
25
+ minutes?: CountdownUnitLabel
26
+ seconds?: CountdownUnitLabel
27
+ }
28
+
15
29
  type CountdownOwnProps = {
16
30
  layout?: CountdownLayout
17
31
  days?: number
@@ -21,17 +35,25 @@ type CountdownOwnProps = {
21
35
  showDays?: boolean
22
36
  showSeconds?: boolean
23
37
  label?: React.ReactNode
38
+ labels?: CountdownLabels
24
39
  }
25
40
 
26
41
  export type CountdownProps = CountdownOwnProps &
27
42
  Omit<ViewProps, keyof CountdownOwnProps>
28
43
 
29
- const UNIT_LABELS = {
30
- days: "days",
31
- hours: "hrs",
32
- minutes: "min",
33
- seconds: "secs"
34
- } as const
44
+ const DEFAULT_UNIT_LABELS: Required<CountdownLabels> = {
45
+ days: { singular: "day", plural: "days" },
46
+ hours: { singular: "hr", plural: "hrs" },
47
+ minutes: { singular: "min", plural: "min" },
48
+ seconds: { singular: "sec", plural: "secs" }
49
+ }
50
+
51
+ const resolveLabel = (label: CountdownUnitLabel, value: number): string =>
52
+ typeof label === "string"
53
+ ? label
54
+ : value === 1
55
+ ? label.singular
56
+ : label.plural
35
57
 
36
58
  const parseTokenValue = (value: string): number => parseFloat(value)
37
59
 
@@ -154,6 +176,7 @@ const InlineCount = styled(View)<{ countGap: number }>(({ countGap }) => ({
154
176
  * @param {boolean} [showDays=true] - Whether to render the days unit and its separator.
155
177
  * @param {boolean} [showSeconds=true] - Whether to render the seconds unit and its separator.
156
178
  * @param {React.ReactNode} [label] - Customizable prefix label, rendered in the `inline` layout only.
179
+ * @param {CountdownLabels} [labels] - Overrides the per-unit labels (`days`/`hours`/`minutes`/`seconds`). Each label is either a plain string or a `{ singular, plural }` pair that resolves against the unit's value. Pass translated strings here; any omitted unit falls back to its English default.
157
180
  *
158
181
  * @example
159
182
  * ```tsx
@@ -161,6 +184,14 @@ const InlineCount = styled(View)<{ countGap: number }>(({ countGap }) => ({
161
184
  *
162
185
  * <Countdown layout="stacked" days={2} hours={9} minutes={48} seconds={38} />
163
186
  * <Countdown layout="inline" label="Sale ends:" showDays={false} hours={3} minutes={49} seconds={38} />
187
+ * <Countdown
188
+ * labels={{
189
+ * days: { singular: "jour", plural: "jours" },
190
+ * hours: { singular: "heure", plural: "heures" }
191
+ * }}
192
+ * days={1}
193
+ * hours={2}
194
+ * />
164
195
  * ```
165
196
  */
166
197
  export const Countdown = React.forwardRef<View, CountdownProps>(
@@ -174,6 +205,7 @@ export const Countdown = React.forwardRef<View, CountdownProps>(
174
205
  showDays = true,
175
206
  showSeconds = true,
176
207
  label,
208
+ labels,
177
209
  ...rest
178
210
  },
179
211
  ref
@@ -182,18 +214,28 @@ export const Countdown = React.forwardRef<View, CountdownProps>(
182
214
  const { countdown } = theme.tokens.components
183
215
  const { countdownItem } = countdown
184
216
 
217
+ const unitLabels = { ...DEFAULT_UNIT_LABELS, ...labels }
218
+
185
219
  const units: CountdownUnit[] = [
186
220
  showDays && {
187
221
  key: "days" as const,
188
222
  value: days,
189
- label: UNIT_LABELS.days
223
+ label: resolveLabel(unitLabels.days, days)
224
+ },
225
+ {
226
+ key: "hours" as const,
227
+ value: hours,
228
+ label: resolveLabel(unitLabels.hours, hours)
229
+ },
230
+ {
231
+ key: "minutes" as const,
232
+ value: minutes,
233
+ label: resolveLabel(unitLabels.minutes, minutes)
190
234
  },
191
- { key: "hours" as const, value: hours, label: UNIT_LABELS.hours },
192
- { key: "minutes" as const, value: minutes, label: UNIT_LABELS.minutes },
193
235
  showSeconds && {
194
236
  key: "seconds" as const,
195
237
  value: seconds,
196
- label: UNIT_LABELS.seconds
238
+ label: resolveLabel(unitLabels.seconds, seconds)
197
239
  }
198
240
  ].filter(Boolean) as CountdownUnit[]
199
241
 
@@ -1,2 +1,6 @@
1
1
  export { Countdown } from "./Countdown"
2
- export type { CountdownProps } from "./Countdown"
2
+ export type {
3
+ CountdownProps,
4
+ CountdownLabels,
5
+ CountdownUnitLabel
6
+ } from "./Countdown"
@@ -74,29 +74,20 @@ const StyledTextInput = styled(TextInput)<{
74
74
  inputFontFamily: string
75
75
  inputFontWeight?: FontWeight
76
76
  inputFontSize: number
77
- inputLineHeight: number
78
- }>(
79
- ({
80
- inputColor,
81
- inputFontFamily,
82
- inputFontWeight,
83
- inputFontSize,
84
- inputLineHeight
85
- }) => ({
86
- textAlign: "center" as const,
87
- outlineStyle: "none" as unknown as undefined,
88
- padding: 0,
89
- minWidth: 0,
90
- minHeight: 0,
91
- width: "100%",
92
- height: "100%",
93
- color: inputColor,
94
- fontFamily: inputFontFamily,
95
- ...(inputFontWeight ? { fontWeight: inputFontWeight } : {}),
96
- fontSize: inputFontSize,
97
- lineHeight: inputLineHeight
98
- })
99
- )
77
+ }>(({ inputColor, inputFontFamily, inputFontWeight, inputFontSize }) => ({
78
+ textAlign: "center" as const,
79
+ outlineStyle: "none" as unknown as undefined,
80
+ padding: 0,
81
+ minWidth: 0,
82
+ minHeight: 0,
83
+ width: "100%",
84
+ height: "100%",
85
+ color: inputColor,
86
+ fontFamily: inputFontFamily,
87
+ ...(inputFontWeight ? { fontWeight: inputFontWeight } : {}),
88
+ fontSize: inputFontSize,
89
+ lineHeight: 0
90
+ }))
100
91
 
101
92
  const StyledRow = styled(View)<{
102
93
  rowGap: number
@@ -256,7 +247,6 @@ export const NumberFieldInput = React.forwardRef<
256
247
  : undefined
257
248
  }
258
249
  inputFontSize={parseTokenValue(typographyToken.fontSize)}
259
- inputLineHeight={parseTokenValue(typographyToken.lineHeight)}
260
250
  keyboardType="numeric"
261
251
  editable={!disabled}
262
252
  onFocus={handleFocus}
@@ -1,14 +1,9 @@
1
1
  import React from "react"
2
- import { View, StyleSheet, Image } from "react-native"
2
+ import { View, StyleSheet } from "react-native"
3
3
  import { ProductDisplayCard } from "./ProductDisplayCard"
4
4
  import type { ProductDisplayCardProps } from "./ProductDisplayCard"
5
5
 
6
- const PlaceholderImage = () => (
7
- <Image
8
- source={{ uri: "https://placeholder.co/148x148?text=Recipe" }}
9
- style={{ width: "100%", height: "100%" }}
10
- />
11
- )
6
+ const placeholderImageUrl = "https://placeholder.co/100x100?text=Recipe"
12
7
 
13
8
  const styles = StyleSheet.create({
14
9
  column: { flexDirection: "column", gap: 24, padding: 16 }
@@ -43,6 +38,10 @@ export default {
43
38
  control: { type: "boolean" },
44
39
  description: "Show/hide quantity picker"
45
40
  },
41
+ showImageQuantityBadge: {
42
+ control: { type: "boolean" },
43
+ description: "Show/hide quantity badge overlay on image"
44
+ },
46
45
  disableQuantityButtons: {
47
46
  control: { type: "boolean" },
48
47
  description: "Disable quantity buttons"
@@ -111,20 +110,19 @@ Playground.args = {
111
110
  bannerType: "info",
112
111
  showBannerIcon: false,
113
112
  banner: " High in protein • Natural ingredients • Vet approved",
114
- image: <PlaceholderImage />
113
+ image: placeholderImageUrl
115
114
  }
116
115
 
117
116
  export const Default = () => (
118
117
  <View style={styles.column}>
119
118
  <ProductDisplayCard
120
- device="mobile"
121
119
  title="Recipe Name"
122
120
  subtext="+£0.00/pouch"
123
121
  showSubtext
124
122
  quantity={1}
125
123
  showQuantityPicker={false}
126
124
  showBanner={false}
127
- image={<PlaceholderImage />}
125
+ image={placeholderImageUrl}
128
126
  />
129
127
  </View>
130
128
  )
@@ -132,14 +130,13 @@ export const Default = () => (
132
130
  export const Desktop = () => (
133
131
  <View style={styles.column}>
134
132
  <ProductDisplayCard
135
- device="desktop"
136
133
  title="Recipe Name"
137
134
  subtext="+£0.00/pouch"
138
135
  showSubtext
139
136
  quantity={1}
140
137
  showQuantityPicker
141
138
  showBanner={false}
142
- image={<PlaceholderImage />}
139
+ image={placeholderImageUrl}
143
140
  />
144
141
  </View>
145
142
  )
@@ -147,14 +144,13 @@ export const Desktop = () => (
147
144
  export const Mobile = () => (
148
145
  <View style={styles.column}>
149
146
  <ProductDisplayCard
150
- device="mobile"
151
147
  title="Recipe Name"
152
148
  subtext="+£0.50/pouch"
153
149
  showSubtext
154
150
  quantity={1}
155
151
  showQuantityPicker
156
152
  showBanner={false}
157
- image={<PlaceholderImage />}
153
+ image={placeholderImageUrl}
158
154
  />
159
155
  </View>
160
156
  )
@@ -162,7 +158,6 @@ export const Mobile = () => (
162
158
  export const WithBanner = () => (
163
159
  <View style={styles.column}>
164
160
  <ProductDisplayCard
165
- device="mobile"
166
161
  title="Recipe Name"
167
162
  subtext="+£0.00/pouch"
168
163
  showSubtext
@@ -172,7 +167,7 @@ export const WithBanner = () => (
172
167
  bannerType="success"
173
168
  showBannerIcon={false}
174
169
  banner="High in protein • Natural ingredients • Vet approved"
175
- image={<PlaceholderImage />}
170
+ image={placeholderImageUrl}
176
171
  />
177
172
  </View>
178
173
  )
@@ -180,7 +175,6 @@ export const WithBanner = () => (
180
175
  export const WithBannerIcon = () => (
181
176
  <View style={styles.column}>
182
177
  <ProductDisplayCard
183
- device="mobile"
184
178
  title="Recipe Name"
185
179
  subtext="+£0.00/pouch"
186
180
  showSubtext
@@ -190,7 +184,7 @@ export const WithBannerIcon = () => (
190
184
  bannerType="success"
191
185
  showBannerIcon
192
186
  banner="High in protein • Natural ingredients • Vet approved"
193
- image={<PlaceholderImage />}
187
+ image={placeholderImageUrl}
194
188
  />
195
189
  </View>
196
190
  )
@@ -198,13 +192,38 @@ export const WithBannerIcon = () => (
198
192
  export const NoSubtext = () => (
199
193
  <View style={styles.column}>
200
194
  <ProductDisplayCard
201
- device="mobile"
202
195
  title="Recipe Name"
203
196
  showSubtext={false}
204
197
  quantity={1}
205
198
  showQuantityPicker
206
199
  showBanner={false}
207
- image={<PlaceholderImage />}
200
+ image={placeholderImageUrl}
201
+ />
202
+ </View>
203
+ )
204
+
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}
208
227
  />
209
228
  </View>
210
229
  )
@@ -212,29 +231,26 @@ export const NoSubtext = () => (
212
231
  export const AllVariants = () => (
213
232
  <View style={styles.column}>
214
233
  <ProductDisplayCard
215
- device="desktop"
216
234
  title="Recipe Name"
217
235
  subtext="+£0.00/pouch"
218
236
  showSubtext
219
237
  quantity={1}
220
238
  showQuantityPicker
221
239
  showBanner={false}
222
- image={<PlaceholderImage />}
240
+ image={placeholderImageUrl}
223
241
  />
224
242
 
225
243
  <ProductDisplayCard
226
- device="mobile"
227
244
  title="Recipe Name"
228
245
  subtext="+£0.50/pouch"
229
246
  showSubtext
230
247
  quantity={2}
231
248
  showQuantityPicker
232
249
  showBanner={false}
233
- image={<PlaceholderImage />}
250
+ image={placeholderImageUrl}
234
251
  />
235
252
 
236
253
  <ProductDisplayCard
237
- device="mobile"
238
254
  title="Recipe Name"
239
255
  subtext="+£0.00/pouch"
240
256
  showSubtext
@@ -242,7 +258,32 @@ export const AllVariants = () => (
242
258
  showQuantityPicker
243
259
  showBanner
244
260
  banner=" High in protein • Natural ingredients"
245
- image={<PlaceholderImage />}
261
+ image={placeholderImageUrl}
262
+ />
263
+ </View>
264
+ )
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}
246
287
  />
247
288
  </View>
248
289
  )
@@ -102,7 +102,7 @@ describe("ProductDisplayCard (Native)", () => {
102
102
  })
103
103
 
104
104
  it("renders with mobile device variant when specified", () => {
105
- renderWithTheme(<ProductDisplayCard title="Test Product" device="mobile" />)
105
+ renderWithTheme(<ProductDisplayCard title="Test Product" />)
106
106
 
107
107
  expect(screen.getByText("Test Product")).toBeTruthy()
108
108
  })
@@ -1,17 +1,14 @@
1
1
  import React from "react"
2
- import { View, ViewProps } from "react-native"
2
+ import { View, ViewProps, Image } from "react-native"
3
3
  import styled from "@emotion/native"
4
4
  import { Typography } from "../../atoms/Typography"
5
5
  import { NumberField } from "../../molecules/NumberField"
6
6
  import { Notification } from "../Notification"
7
7
  import { parseTokenValue } from "../../../utils"
8
8
 
9
- export type ProductDisplayCardDevice = "desktop" | "mobile"
10
-
11
9
  export type ProductDisplayCardProps = ViewProps & {
12
- device?: ProductDisplayCardDevice
13
10
  title: string
14
- subtext?: string
11
+ subtext?: string | React.ReactNode
15
12
  showSubtext?: boolean
16
13
  quantity?: number
17
14
  onQuantityChange?: (quantity: number) => void
@@ -22,16 +19,22 @@ export type ProductDisplayCardProps = ViewProps & {
22
19
  showDecrementButton?: boolean
23
20
  incrementDisabled?: boolean
24
21
  decrementDisabled?: boolean
25
- image?: React.ReactNode
22
+ image?: string | React.ReactNode
23
+ imageBackgroundColor?: string
24
+ thumbnailWidth?: number
25
+ thumbnailBackgroundColor?: string
26
+ showImageQuantityBadge?: boolean
27
+ borderless?: boolean
26
28
  banner?: React.ReactNode
27
29
  showBanner?: boolean
28
30
  bannerType?: "error" | "success" | "warning" | "info"
29
31
  showBannerIcon?: boolean
30
32
  }
31
33
 
32
- const StyledCardContainer = styled(View)<{
33
- cardDevice: ProductDisplayCardDevice
34
- }>(({ theme }) => {
34
+ const StyledCardContainer = styled(View)<{ borderless?: boolean }>(({
35
+ theme,
36
+ borderless
37
+ }) => {
35
38
  const { spacing, borderRadius } = theme.tokens.semantics.dimensions
36
39
  const { colour } = theme.tokens.semantics
37
40
  const spacingMd = parseTokenValue(spacing.md)
@@ -39,38 +42,80 @@ const StyledCardContainer = styled(View)<{
39
42
  return {
40
43
  flexDirection: "row",
41
44
  width: "100%",
42
- height: "100%",
45
+ height: borderless ? undefined : "100%",
43
46
  maxHeight: spacingXl * 6 + spacingMd,
44
47
  backgroundColor: colour.background.surface.default,
45
- borderWidth: 1,
46
- borderColor: colour.border.default,
48
+ ...(borderless
49
+ ? {}
50
+ : {
51
+ borderWidth: 1,
52
+ borderColor: colour.border.default,
53
+ shadowColor: "#522a10",
54
+ shadowOffset: { width: 0, height: spacingMd / 4 },
55
+ shadowOpacity: 0.05,
56
+ shadowRadius: spacingXl - 4,
57
+ elevation: 5
58
+ }),
47
59
  borderRadius: parseTokenValue(borderRadius.md),
48
60
  overflow: "hidden",
49
- shadowColor: "#522a10",
50
- shadowOffset: { width: 0, height: spacingMd / 4 },
51
- shadowOpacity: 0.05,
52
- shadowRadius: spacingXl - 4,
53
- elevation: 5,
54
61
  zIndex: 1
55
62
  }
56
63
  })
57
64
 
58
- const StyledImage = styled(View)(() => ({
59
- flexShrink: 0,
60
- backgroundColor: "#f5f5f5",
61
- overflow: "hidden",
62
- aspectRatio: "1 / 1",
63
- height: "100%"
64
- }))
65
+ const StyledImage = styled(View)<{
66
+ imageBackgroundColor?: string
67
+ thumbnailWidth?: number
68
+ thumbnailBackgroundColor?: string
69
+ }>(
70
+ ({
71
+ theme,
72
+ imageBackgroundColor,
73
+ thumbnailWidth = 100,
74
+ thumbnailBackgroundColor
75
+ }) => ({
76
+ flexShrink: 0,
77
+ backgroundColor:
78
+ thumbnailBackgroundColor ||
79
+ imageBackgroundColor ||
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
+ )
65
88
 
66
- const StyledContentArea = styled(View)<{
67
- contentDevice: ProductDisplayCardDevice
68
- }>(({ theme }) => {
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
+ })
108
+
109
+ const StyledContentArea = styled(View)<{ borderless?: boolean }>(({
110
+ theme,
111
+ borderless
112
+ }) => {
69
113
  const { spacing } = theme.tokens.semantics.dimensions
114
+ const paddingValue = parseTokenValue(spacing.md)
70
115
  return {
71
116
  flex: 1,
72
- paddingHorizontal: parseTokenValue(spacing.md),
73
- paddingVertical: parseTokenValue(spacing.md),
117
+ paddingHorizontal: paddingValue,
118
+ paddingVertical: borderless ? 0 : paddingValue,
74
119
  gap: parseTokenValue(spacing.xs),
75
120
  justifyContent: "space-between"
76
121
  }
@@ -112,7 +157,6 @@ const StyledNotification = styled(Notification as any)(({ theme }) => {
112
157
  * import { ProductDisplayCard } from "@butternutbox/pawprint-native"
113
158
  *
114
159
  * <ProductDisplayCard
115
- * device="mobile"
116
160
  * title="Premium Recipe"
117
161
  * subtext="+£0.00/pouch"
118
162
  * quantity={1}
@@ -120,7 +164,6 @@ const StyledNotification = styled(Notification as any)(({ theme }) => {
120
164
  * />
121
165
  * ```
122
166
  *
123
- * @param device - *(optional)* Device variant: "desktop" or "mobile" (default)
124
167
  * @param title - Product title
125
168
  * @param subtext - *(optional)* Subtitle text (e.g. price)
126
169
  * @param showSubtext - *(optional)* Show/hide subtext
@@ -139,7 +182,6 @@ export const ProductDisplayCard = React.forwardRef<
139
182
  >(
140
183
  (
141
184
  {
142
- device = "mobile",
143
185
  title,
144
186
  subtext,
145
187
  showSubtext = true,
@@ -153,6 +195,11 @@ export const ProductDisplayCard = React.forwardRef<
153
195
  incrementDisabled = false,
154
196
  decrementDisabled = false,
155
197
  image,
198
+ imageBackgroundColor,
199
+ thumbnailWidth,
200
+ thumbnailBackgroundColor,
201
+ showImageQuantityBadge = false,
202
+ borderless = false,
156
203
  banner,
157
204
  showBanner = false,
158
205
  bannerType = "info",
@@ -168,12 +215,34 @@ export const ProductDisplayCard = React.forwardRef<
168
215
  }
169
216
 
170
217
  const cardContent = (
171
- <StyledCardContainer ref={ref} cardDevice={device} {...rest}>
172
- {image && <StyledImage>{image}</StyledImage>}
218
+ <StyledCardContainer ref={ref} borderless={borderless} {...rest}>
219
+ {image && (
220
+ <StyledImage
221
+ imageBackgroundColor={imageBackgroundColor}
222
+ thumbnailWidth={thumbnailWidth}
223
+ thumbnailBackgroundColor={thumbnailBackgroundColor}
224
+ >
225
+ {typeof image === "string" ? (
226
+ <Image
227
+ source={{ uri: image }}
228
+ style={{ width: "100%", height: "100%" }}
229
+ />
230
+ ) : (
231
+ image
232
+ )}
233
+ {showImageQuantityBadge && quantity && (
234
+ <StyledQuantityBadge>
235
+ <Typography variant="body" size="sm" weight="bold">
236
+ {quantity}
237
+ </Typography>
238
+ </StyledQuantityBadge>
239
+ )}
240
+ </StyledImage>
241
+ )}
173
242
 
174
- <StyledContentArea contentDevice={device}>
243
+ <StyledContentArea borderless={borderless}>
175
244
  <StyledTextContainer>
176
- <Typography variant="heading" size="xs" color="primary">
245
+ <Typography variant="heading" size="2xs" color="primary">
177
246
  {title}
178
247
  </Typography>
179
248
 
@@ -1,5 +1,2 @@
1
1
  export { ProductDisplayCard } from "./ProductDisplayCard"
2
- export type {
3
- ProductDisplayCardProps,
4
- ProductDisplayCardDevice
5
- } from "./ProductDisplayCard"
2
+ export type { ProductDisplayCardProps } from "./ProductDisplayCard"