@butternutbox/pawprint-native 0.19.2 → 0.20.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 +8 -0
- package/dist/index.cjs +26 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +26 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/molecules/ProductDisplayCard/ProductDisplayCard.stories.tsx +31 -0
- package/src/components/molecules/ProductDisplayCard/ProductDisplayCard.test.tsx +54 -0
- package/src/components/molecules/ProductDisplayCard/ProductDisplayCard.tsx +34 -1
package/package.json
CHANGED
|
@@ -35,6 +35,11 @@ export default {
|
|
|
35
35
|
control: { type: "boolean" },
|
|
36
36
|
description: "Show/hide quantity picker"
|
|
37
37
|
},
|
|
38
|
+
quantityBadge: {
|
|
39
|
+
control: { type: "boolean" },
|
|
40
|
+
description:
|
|
41
|
+
"Show a quantity badge over the image instead of the picker (mutually exclusive with the quantity picker)"
|
|
42
|
+
},
|
|
38
43
|
disableQuantityButtons: {
|
|
39
44
|
control: { type: "boolean" },
|
|
40
45
|
description: "Disable quantity buttons"
|
|
@@ -271,3 +276,29 @@ export const WithCustomBanner = () => (
|
|
|
271
276
|
/>
|
|
272
277
|
</View>
|
|
273
278
|
)
|
|
279
|
+
|
|
280
|
+
export const WithQuantityBadge = () => (
|
|
281
|
+
<View style={styles.column}>
|
|
282
|
+
{/* OOB recipe / Extras card: quantity shown as a badge over the image
|
|
283
|
+
instead of the picker. The two are mutually exclusive. */}
|
|
284
|
+
<ProductDisplayCard
|
|
285
|
+
title="Recipe Name"
|
|
286
|
+
subtext="+£0.00/pouch"
|
|
287
|
+
showSubtext
|
|
288
|
+
quantity={6}
|
|
289
|
+
quantityBadge
|
|
290
|
+
image={placeholderImageUrl}
|
|
291
|
+
/>
|
|
292
|
+
{/* Even with showQuantityPicker set, the badge wins and the picker is
|
|
293
|
+
suppressed. */}
|
|
294
|
+
<ProductDisplayCard
|
|
295
|
+
title="Recipe Name"
|
|
296
|
+
subtext="+£0.00/pouch"
|
|
297
|
+
showSubtext
|
|
298
|
+
quantity={2}
|
|
299
|
+
quantityBadge
|
|
300
|
+
showQuantityPicker
|
|
301
|
+
image={placeholderImageUrl}
|
|
302
|
+
/>
|
|
303
|
+
</View>
|
|
304
|
+
)
|
|
@@ -188,4 +188,58 @@ describe("ProductDisplayCard (Native)", () => {
|
|
|
188
188
|
|
|
189
189
|
expect(screen.getByText("Test Banner")).toBeTruthy()
|
|
190
190
|
})
|
|
191
|
+
|
|
192
|
+
it("renders the quantity badge over the image when quantityBadge is true", () => {
|
|
193
|
+
renderWithTheme(
|
|
194
|
+
<ProductDisplayCard
|
|
195
|
+
title="Test Product"
|
|
196
|
+
quantity={6}
|
|
197
|
+
quantityBadge
|
|
198
|
+
image={
|
|
199
|
+
<View>
|
|
200
|
+
<Text>Image</Text>
|
|
201
|
+
</View>
|
|
202
|
+
}
|
|
203
|
+
/>
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
expect(screen.getByText("6")).toBeTruthy()
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
it("does not render the quantity badge by default", () => {
|
|
210
|
+
renderWithTheme(
|
|
211
|
+
<ProductDisplayCard
|
|
212
|
+
title="Test Product"
|
|
213
|
+
quantity={6}
|
|
214
|
+
image={
|
|
215
|
+
<View>
|
|
216
|
+
<Text>Image</Text>
|
|
217
|
+
</View>
|
|
218
|
+
}
|
|
219
|
+
/>
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
expect(screen.queryByText("6")).toBeFalsy()
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
it("suppresses the quantity picker when quantityBadge is set (mutually exclusive)", () => {
|
|
226
|
+
renderWithTheme(
|
|
227
|
+
<ProductDisplayCard
|
|
228
|
+
title="Test Product"
|
|
229
|
+
quantity={3}
|
|
230
|
+
quantityBadge
|
|
231
|
+
showQuantityPicker
|
|
232
|
+
image={
|
|
233
|
+
<View>
|
|
234
|
+
<Text>Image</Text>
|
|
235
|
+
</View>
|
|
236
|
+
}
|
|
237
|
+
/>
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
// The badge shows the quantity...
|
|
241
|
+
expect(screen.getByText("3")).toBeTruthy()
|
|
242
|
+
// ...and the picker input is not rendered.
|
|
243
|
+
expect(screen.queryByDisplayValue("3")).toBeFalsy()
|
|
244
|
+
})
|
|
191
245
|
})
|
|
@@ -3,6 +3,7 @@ import { View, ViewProps, Image, Pressable } from "react-native"
|
|
|
3
3
|
import styled from "@emotion/native"
|
|
4
4
|
import { useTheme } from "@emotion/react"
|
|
5
5
|
import { Typography } from "../../atoms/Typography"
|
|
6
|
+
import { Badge } from "../../atoms/Badge"
|
|
6
7
|
import { NumberField } from "../../molecules/NumberField"
|
|
7
8
|
import { Notification } from "../Notification"
|
|
8
9
|
import { parseTokenValue } from "../../../utils"
|
|
@@ -14,6 +15,13 @@ export type ProductDisplayCardProps = ViewProps & {
|
|
|
14
15
|
quantity?: number
|
|
15
16
|
onQuantityChange?: (quantity: number) => void
|
|
16
17
|
showQuantityPicker?: boolean
|
|
18
|
+
/**
|
|
19
|
+
* Show a quantity badge overlaid on the top-right of the image (rendering the
|
|
20
|
+
* current `quantity`) instead of the quantity picker. Defaults to `false`.
|
|
21
|
+
* The badge and the quantity picker are mutually exclusive — only one shows
|
|
22
|
+
* at a time; when `quantityBadge` is true the picker is never rendered.
|
|
23
|
+
*/
|
|
24
|
+
quantityBadge?: boolean
|
|
17
25
|
disableQuantityButtons?: boolean
|
|
18
26
|
hideQuantityButtons?: boolean
|
|
19
27
|
incrementDisabled?: boolean
|
|
@@ -77,6 +85,20 @@ const StyledImage = styled(View)<{
|
|
|
77
85
|
position: "relative"
|
|
78
86
|
}))
|
|
79
87
|
|
|
88
|
+
// Anchors the quantity badge to the top-right corner of the image, inset by
|
|
89
|
+
// `spacing.2xs` (4px) per the Figma spec (node 10864:736).
|
|
90
|
+
const StyledBadgeOverlay = styled(View)(({ theme }) => {
|
|
91
|
+
const offset = parseTokenValue(
|
|
92
|
+
theme.tokens.semantics.dimensions.spacing["2xs"]
|
|
93
|
+
)
|
|
94
|
+
return {
|
|
95
|
+
position: "absolute",
|
|
96
|
+
top: offset,
|
|
97
|
+
right: offset,
|
|
98
|
+
zIndex: 2
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
|
|
80
102
|
const StyledContentArea = styled(View)(({ theme }) => {
|
|
81
103
|
const { spacing } = theme.tokens.semantics.dimensions
|
|
82
104
|
const paddingValue = parseTokenValue(spacing.md)
|
|
@@ -171,6 +193,9 @@ const StyledNoneBanner = styled(View)(({ theme }) => {
|
|
|
171
193
|
* @param quantity - *(optional)* Current quantity value
|
|
172
194
|
* @param onQuantityChange - *(optional)* Callback when quantity changes
|
|
173
195
|
* @param showQuantityPicker - *(optional)* Show/hide quantity picker
|
|
196
|
+
* @param quantityBadge - *(optional)* Show a quantity badge over the image instead
|
|
197
|
+
* of the picker (renders the current `quantity`). Mutually exclusive with the
|
|
198
|
+
* quantity picker; defaults to `false`. Used on OOB recipe and Extras cards.
|
|
174
199
|
* @param image - *(optional)* Image URL string or React element
|
|
175
200
|
* @param banner - *(optional)* Banner content string or React element to show below card
|
|
176
201
|
* @param showBanner - *(optional)* Show/hide banner
|
|
@@ -189,6 +214,7 @@ export const ProductDisplayCard = React.forwardRef<
|
|
|
189
214
|
quantity = 1,
|
|
190
215
|
onQuantityChange,
|
|
191
216
|
showQuantityPicker = false,
|
|
217
|
+
quantityBadge = false,
|
|
192
218
|
disableQuantityButtons = false,
|
|
193
219
|
hideQuantityButtons = false,
|
|
194
220
|
incrementDisabled = false,
|
|
@@ -233,6 +259,13 @@ export const ProductDisplayCard = React.forwardRef<
|
|
|
233
259
|
) : (
|
|
234
260
|
image
|
|
235
261
|
)}
|
|
262
|
+
{quantityBadge && (
|
|
263
|
+
<StyledBadgeOverlay pointerEvents="none">
|
|
264
|
+
<Badge variant="primary" size="large">
|
|
265
|
+
{String(quantity)}
|
|
266
|
+
</Badge>
|
|
267
|
+
</StyledBadgeOverlay>
|
|
268
|
+
)}
|
|
236
269
|
</StyledImage>
|
|
237
270
|
</Pressable>
|
|
238
271
|
)}
|
|
@@ -250,7 +283,7 @@ export const ProductDisplayCard = React.forwardRef<
|
|
|
250
283
|
)}
|
|
251
284
|
</StyledTextContainer>
|
|
252
285
|
|
|
253
|
-
{showQuantityPicker && (
|
|
286
|
+
{showQuantityPicker && !quantityBadge && (
|
|
254
287
|
<View style={{ marginLeft: "auto" }}>
|
|
255
288
|
<NumberField
|
|
256
289
|
size="sm"
|