@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.
Files changed (30) hide show
  1. package/.turbo/turbo-build.log +9 -9
  2. package/CHANGELOG.md +8 -0
  3. package/dist/index.cjs +965 -151
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +246 -5
  6. package/dist/index.d.ts +246 -5
  7. package/dist/index.js +960 -151
  8. package/dist/index.js.map +1 -1
  9. package/package.json +2 -1
  10. package/src/components/atoms/Hint/Hint.tsx +1 -2
  11. package/src/components/atoms/Input/InputField.tsx +7 -1
  12. package/src/components/molecules/Animated/Animated.tsx +12 -3
  13. package/src/components/molecules/Countdown/Countdown.stories.tsx +218 -0
  14. package/src/components/molecules/Countdown/Countdown.tsx +315 -0
  15. package/src/components/molecules/Countdown/index.ts +2 -0
  16. package/src/components/molecules/ProductDisplayCard/ProductDisplayCard.stories.tsx +248 -0
  17. package/src/components/molecules/ProductDisplayCard/ProductDisplayCard.test.tsx +198 -0
  18. package/src/components/molecules/ProductDisplayCard/ProductDisplayCard.tsx +243 -0
  19. package/src/components/molecules/ProductDisplayCard/index.ts +5 -0
  20. package/src/components/molecules/ProductListingCard/Badge.tsx +65 -0
  21. package/src/components/molecules/ProductListingCard/Grid.tsx +59 -0
  22. package/src/components/molecules/ProductListingCard/ProductListingCard.stories.tsx +209 -0
  23. package/src/components/molecules/ProductListingCard/ProductListingCard.tsx +235 -0
  24. package/src/components/molecules/ProductListingCard/index.ts +2 -0
  25. package/src/components/molecules/TabNavigation/TabNavigation.stories.tsx +183 -0
  26. package/src/components/molecules/TabNavigation/TabNavigation.tsx +354 -0
  27. package/src/components/molecules/TabNavigation/index.ts +7 -0
  28. package/src/components/molecules/index.ts +4 -0
  29. package/src/utils/index.ts +1 -0
  30. package/src/utils/token.ts +1 -0
@@ -0,0 +1,248 @@
1
+ import React from "react"
2
+ import { View, StyleSheet, Image } from "react-native"
3
+ import { ProductDisplayCard } from "./ProductDisplayCard"
4
+ import type { ProductDisplayCardProps } from "./ProductDisplayCard"
5
+
6
+ const PlaceholderImage = () => (
7
+ <Image
8
+ source={{ uri: "https://placeholder.co/148x148?text=Recipe" }}
9
+ style={{ width: "100%", height: "100%" }}
10
+ />
11
+ )
12
+
13
+ const styles = StyleSheet.create({
14
+ column: { flexDirection: "column", gap: 24, padding: 16 }
15
+ })
16
+
17
+ export default {
18
+ title: "Molecules/ProductDisplayCard",
19
+ component: ProductDisplayCard,
20
+ argTypes: {
21
+ device: {
22
+ control: { type: "select" },
23
+ options: ["desktop", "mobile"],
24
+ description: "Device variant affecting sizing and typography"
25
+ },
26
+ title: {
27
+ control: { type: "text" },
28
+ description: "Product title"
29
+ },
30
+ subtext: {
31
+ control: { type: "text" },
32
+ description: "Secondary text (e.g. price)"
33
+ },
34
+ showSubtext: {
35
+ control: { type: "boolean" },
36
+ description: "Show/hide subtext"
37
+ },
38
+ quantity: {
39
+ control: { type: "number", min: 1 },
40
+ description: "Current quantity"
41
+ },
42
+ showQuantityPicker: {
43
+ control: { type: "boolean" },
44
+ description: "Show/hide quantity picker"
45
+ },
46
+ disableQuantityButtons: {
47
+ control: { type: "boolean" },
48
+ description: "Disable quantity buttons"
49
+ },
50
+ hideQuantityButtons: {
51
+ control: { type: "boolean" },
52
+ description: "Hide quantity buttons"
53
+ },
54
+ showIncrementButton: {
55
+ control: { type: "boolean" },
56
+ description: "Show/hide increment button"
57
+ },
58
+ showDecrementButton: {
59
+ control: { type: "boolean" },
60
+ description: "Show/hide decrement button"
61
+ },
62
+ incrementDisabled: {
63
+ control: { type: "boolean" },
64
+ description: "Disable increment button"
65
+ },
66
+ decrementDisabled: {
67
+ control: { type: "boolean" },
68
+ description: "Disable decrement button"
69
+ },
70
+ showBanner: {
71
+ control: { type: "boolean" },
72
+ description: "Show/hide banner below card"
73
+ },
74
+ onQuantityChange: {
75
+ control: false,
76
+ description: "Callback when quantity changes"
77
+ },
78
+ image: {
79
+ control: false,
80
+ description: "Image element or content"
81
+ },
82
+ banner: {
83
+ control: { type: "text" },
84
+ description: "Banner content to show below card"
85
+ },
86
+ bannerType: {
87
+ control: { type: "select" },
88
+ options: ["error", "success", "warning", "info"],
89
+ description: "Banner notification type"
90
+ },
91
+ showBannerIcon: {
92
+ control: { type: "boolean" },
93
+ description: "Show/hide banner notification icon"
94
+ }
95
+ }
96
+ }
97
+
98
+ export const Playground = (args: ProductDisplayCardProps) => (
99
+ <View style={styles.column}>
100
+ <ProductDisplayCard {...args} />
101
+ </View>
102
+ )
103
+ Playground.args = {
104
+ device: "mobile",
105
+ title: "Recipe Name",
106
+ subtext: "+£0.00/pouch",
107
+ showSubtext: true,
108
+ quantity: 1,
109
+ showQuantityPicker: true,
110
+ showBanner: true,
111
+ bannerType: "info",
112
+ showBannerIcon: false,
113
+ banner: " High in protein • Natural ingredients • Vet approved",
114
+ image: <PlaceholderImage />
115
+ }
116
+
117
+ export const Default = () => (
118
+ <View style={styles.column}>
119
+ <ProductDisplayCard
120
+ device="mobile"
121
+ title="Recipe Name"
122
+ subtext="+£0.00/pouch"
123
+ showSubtext
124
+ quantity={1}
125
+ showQuantityPicker={false}
126
+ showBanner={false}
127
+ image={<PlaceholderImage />}
128
+ />
129
+ </View>
130
+ )
131
+
132
+ export const Desktop = () => (
133
+ <View style={styles.column}>
134
+ <ProductDisplayCard
135
+ device="desktop"
136
+ title="Recipe Name"
137
+ subtext="+£0.00/pouch"
138
+ showSubtext
139
+ quantity={1}
140
+ showQuantityPicker
141
+ showBanner={false}
142
+ image={<PlaceholderImage />}
143
+ />
144
+ </View>
145
+ )
146
+
147
+ export const Mobile = () => (
148
+ <View style={styles.column}>
149
+ <ProductDisplayCard
150
+ device="mobile"
151
+ title="Recipe Name"
152
+ subtext="+£0.50/pouch"
153
+ showSubtext
154
+ quantity={1}
155
+ showQuantityPicker
156
+ showBanner={false}
157
+ image={<PlaceholderImage />}
158
+ />
159
+ </View>
160
+ )
161
+
162
+ export const WithBanner = () => (
163
+ <View style={styles.column}>
164
+ <ProductDisplayCard
165
+ device="mobile"
166
+ title="Recipe Name"
167
+ subtext="+£0.00/pouch"
168
+ showSubtext
169
+ quantity={1}
170
+ showQuantityPicker
171
+ showBanner
172
+ bannerType="success"
173
+ showBannerIcon={false}
174
+ banner="High in protein • Natural ingredients • Vet approved"
175
+ image={<PlaceholderImage />}
176
+ />
177
+ </View>
178
+ )
179
+
180
+ export const WithBannerIcon = () => (
181
+ <View style={styles.column}>
182
+ <ProductDisplayCard
183
+ device="mobile"
184
+ title="Recipe Name"
185
+ subtext="+£0.00/pouch"
186
+ showSubtext
187
+ quantity={1}
188
+ showQuantityPicker
189
+ showBanner
190
+ bannerType="success"
191
+ showBannerIcon
192
+ banner="High in protein • Natural ingredients • Vet approved"
193
+ image={<PlaceholderImage />}
194
+ />
195
+ </View>
196
+ )
197
+
198
+ export const NoSubtext = () => (
199
+ <View style={styles.column}>
200
+ <ProductDisplayCard
201
+ device="mobile"
202
+ title="Recipe Name"
203
+ showSubtext={false}
204
+ quantity={1}
205
+ showQuantityPicker
206
+ showBanner={false}
207
+ image={<PlaceholderImage />}
208
+ />
209
+ </View>
210
+ )
211
+
212
+ export const AllVariants = () => (
213
+ <View style={styles.column}>
214
+ <ProductDisplayCard
215
+ device="desktop"
216
+ title="Recipe Name"
217
+ subtext="+£0.00/pouch"
218
+ showSubtext
219
+ quantity={1}
220
+ showQuantityPicker
221
+ showBanner={false}
222
+ image={<PlaceholderImage />}
223
+ />
224
+
225
+ <ProductDisplayCard
226
+ device="mobile"
227
+ title="Recipe Name"
228
+ subtext="+£0.50/pouch"
229
+ showSubtext
230
+ quantity={2}
231
+ showQuantityPicker
232
+ showBanner={false}
233
+ image={<PlaceholderImage />}
234
+ />
235
+
236
+ <ProductDisplayCard
237
+ device="mobile"
238
+ title="Recipe Name"
239
+ subtext="+£0.00/pouch"
240
+ showSubtext
241
+ quantity={1}
242
+ showQuantityPicker
243
+ showBanner
244
+ banner=" High in protein • Natural ingredients"
245
+ image={<PlaceholderImage />}
246
+ />
247
+ </View>
248
+ )
@@ -0,0 +1,198 @@
1
+ import { describe, it, expect } from "vitest"
2
+ import { screen } from "@testing-library/react"
3
+ import { View, Text } from "react-native"
4
+ import { ProductDisplayCard } from "./ProductDisplayCard"
5
+ import { renderWithTheme } from "../../../test-utils"
6
+
7
+ describe("ProductDisplayCard (Native)", () => {
8
+ it("renders with required title prop", () => {
9
+ renderWithTheme(<ProductDisplayCard title="Test Product" />)
10
+
11
+ expect(screen.getByText("Test Product")).toBeTruthy()
12
+ })
13
+
14
+ it("renders subtext when provided and showSubtext is true", () => {
15
+ renderWithTheme(
16
+ <ProductDisplayCard
17
+ title="Test Product"
18
+ subtext="£9.99"
19
+ showSubtext={true}
20
+ />
21
+ )
22
+
23
+ expect(screen.getByText("£9.99")).toBeTruthy()
24
+ })
25
+
26
+ it("hides subtext when showSubtext is false", () => {
27
+ renderWithTheme(
28
+ <ProductDisplayCard
29
+ title="Test Product"
30
+ subtext="£9.99"
31
+ showSubtext={false}
32
+ />
33
+ )
34
+
35
+ expect(screen.queryByText("£9.99")).toBeFalsy()
36
+ })
37
+
38
+ it("renders image when provided", () => {
39
+ renderWithTheme(
40
+ <ProductDisplayCard
41
+ title="Test Product"
42
+ image={
43
+ <View>
44
+ <Text>Image</Text>
45
+ </View>
46
+ }
47
+ />
48
+ )
49
+
50
+ expect(screen.getByText("Image")).toBeTruthy()
51
+ })
52
+
53
+ it("shows quantity picker when showQuantityPicker is true", () => {
54
+ renderWithTheme(
55
+ <ProductDisplayCard
56
+ title="Test Product"
57
+ showQuantityPicker={true}
58
+ quantity={1}
59
+ />
60
+ )
61
+
62
+ const numberInput = screen.getByDisplayValue("1")
63
+ expect(numberInput).toBeTruthy()
64
+ })
65
+
66
+ it("does not show quantity picker when showQuantityPicker is false", () => {
67
+ renderWithTheme(
68
+ <ProductDisplayCard title="Test Product" showQuantityPicker={false} />
69
+ )
70
+
71
+ expect(screen.queryByDisplayValue("1")).toBeFalsy()
72
+ })
73
+
74
+ it("renders banner when showBanner is true", () => {
75
+ renderWithTheme(
76
+ <ProductDisplayCard
77
+ title="Test Product"
78
+ showBanner={true}
79
+ banner={<Text>Test Banner</Text>}
80
+ />
81
+ )
82
+
83
+ expect(screen.getByText("Test Banner")).toBeTruthy()
84
+ })
85
+
86
+ it("does not render banner when showBanner is false", () => {
87
+ renderWithTheme(
88
+ <ProductDisplayCard
89
+ title="Test Product"
90
+ showBanner={false}
91
+ banner={<Text>Test Banner</Text>}
92
+ />
93
+ )
94
+
95
+ expect(screen.queryByText("Test Banner")).toBeFalsy()
96
+ })
97
+
98
+ it("renders with desktop device variant by default", () => {
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", () => {
105
+ renderWithTheme(<ProductDisplayCard title="Test Product" device="mobile" />)
106
+
107
+ expect(screen.getByText("Test Product")).toBeTruthy()
108
+ })
109
+
110
+ it("forwards ref correctly", () => {
111
+ const ref = { current: null as any }
112
+
113
+ renderWithTheme(<ProductDisplayCard ref={ref} title="Test Product" />)
114
+
115
+ expect(ref.current).toBeTruthy()
116
+ })
117
+
118
+ it("renders title and subtext together", () => {
119
+ renderWithTheme(
120
+ <ProductDisplayCard
121
+ title="Premium Recipe"
122
+ subtext="+£0.00/pouch"
123
+ showSubtext={true}
124
+ />
125
+ )
126
+
127
+ expect(screen.getByText("Premium Recipe")).toBeTruthy()
128
+ expect(screen.getByText("+£0.00/pouch")).toBeTruthy()
129
+ })
130
+
131
+ it("accepts React element as image", () => {
132
+ renderWithTheme(
133
+ <ProductDisplayCard
134
+ title="Test Product"
135
+ image={
136
+ <View>
137
+ <Text>Custom Image</Text>
138
+ </View>
139
+ }
140
+ />
141
+ )
142
+
143
+ expect(screen.getByText("Custom Image")).toBeTruthy()
144
+ })
145
+
146
+ it("accepts React element as banner", () => {
147
+ renderWithTheme(
148
+ <ProductDisplayCard
149
+ title="Test Product"
150
+ showBanner={true}
151
+ banner={
152
+ <View>
153
+ <Text>Custom Banner</Text>
154
+ </View>
155
+ }
156
+ />
157
+ )
158
+
159
+ expect(screen.getByText("Custom Banner")).toBeTruthy()
160
+ })
161
+
162
+ it("renders banner with different types", () => {
163
+ const { rerender } = renderWithTheme(
164
+ <ProductDisplayCard
165
+ title="Test Product"
166
+ showBanner={true}
167
+ banner={<Text>Test Banner</Text>}
168
+ bannerType="success"
169
+ />
170
+ )
171
+
172
+ expect(screen.getByText("Test Banner")).toBeTruthy()
173
+
174
+ rerender(
175
+ <ProductDisplayCard
176
+ title="Test Product"
177
+ showBanner={true}
178
+ banner={<Text>Error Banner</Text>}
179
+ bannerType="error"
180
+ />
181
+ )
182
+
183
+ expect(screen.getByText("Error Banner")).toBeTruthy()
184
+ })
185
+
186
+ it("displays banner with icon when showBannerIcon is true", () => {
187
+ renderWithTheme(
188
+ <ProductDisplayCard
189
+ title="Test Product"
190
+ showBanner={true}
191
+ banner={<Text>Test Banner</Text>}
192
+ showBannerIcon={true}
193
+ />
194
+ )
195
+
196
+ expect(screen.getByText("Test Banner")).toBeTruthy()
197
+ })
198
+ })
@@ -0,0 +1,243 @@
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
+ import { NumberField } from "../../molecules/NumberField"
6
+ import { Notification } from "../Notification"
7
+ import { parseTokenValue } from "../../../utils"
8
+
9
+ export type ProductDisplayCardDevice = "desktop" | "mobile"
10
+
11
+ export type ProductDisplayCardProps = ViewProps & {
12
+ device?: ProductDisplayCardDevice
13
+ title: string
14
+ subtext?: string
15
+ showSubtext?: boolean
16
+ quantity?: number
17
+ onQuantityChange?: (quantity: number) => void
18
+ showQuantityPicker?: boolean
19
+ disableQuantityButtons?: boolean
20
+ hideQuantityButtons?: boolean
21
+ showIncrementButton?: boolean
22
+ showDecrementButton?: boolean
23
+ incrementDisabled?: boolean
24
+ decrementDisabled?: boolean
25
+ image?: React.ReactNode
26
+ banner?: React.ReactNode
27
+ showBanner?: boolean
28
+ bannerType?: "error" | "success" | "warning" | "info"
29
+ showBannerIcon?: boolean
30
+ }
31
+
32
+ const StyledCardContainer = styled(View)<{
33
+ cardDevice: ProductDisplayCardDevice
34
+ }>(({ theme }) => {
35
+ const { spacing, borderRadius } = theme.tokens.semantics.dimensions
36
+ const { colour } = theme.tokens.semantics
37
+ const spacingMd = parseTokenValue(spacing.md)
38
+ const spacingXl = parseTokenValue(spacing.xl)
39
+ return {
40
+ flexDirection: "row",
41
+ width: "100%",
42
+ height: "100%",
43
+ maxHeight: spacingXl * 6 + spacingMd,
44
+ backgroundColor: colour.background.surface.default,
45
+ borderWidth: 1,
46
+ borderColor: colour.border.default,
47
+ borderRadius: parseTokenValue(borderRadius.md),
48
+ overflow: "hidden",
49
+ shadowColor: "#522a10",
50
+ shadowOffset: { width: 0, height: spacingMd / 4 },
51
+ shadowOpacity: 0.05,
52
+ shadowRadius: spacingXl - 4,
53
+ elevation: 5,
54
+ zIndex: 1
55
+ }
56
+ })
57
+
58
+ const StyledImage = styled(View)(() => ({
59
+ flexShrink: 0,
60
+ backgroundColor: "#f5f5f5",
61
+ overflow: "hidden",
62
+ aspectRatio: "1 / 1",
63
+ height: "100%"
64
+ }))
65
+
66
+ const StyledContentArea = styled(View)<{
67
+ contentDevice: ProductDisplayCardDevice
68
+ }>(({ theme }) => {
69
+ const { spacing } = theme.tokens.semantics.dimensions
70
+ return {
71
+ flex: 1,
72
+ paddingHorizontal: parseTokenValue(spacing.md),
73
+ paddingVertical: parseTokenValue(spacing.md),
74
+ gap: parseTokenValue(spacing.xs),
75
+ justifyContent: "space-between"
76
+ }
77
+ })
78
+
79
+ const StyledTextContainer = styled(View)(() => ({
80
+ gap: 2
81
+ }))
82
+
83
+ const StyledBannerWrapper = styled(View)(() => ({
84
+ width: "100%",
85
+ marginTop: -48,
86
+ paddingTop: 24,
87
+ paddingBottom: 16
88
+ }))
89
+
90
+ const StyledRootWrapper = styled(View)(() => {
91
+ return {
92
+ flexDirection: "column",
93
+ width: "100%",
94
+ height: "100%"
95
+ }
96
+ })
97
+
98
+ const StyledNotification = styled(Notification as any)(({ theme }) => {
99
+ const { spacing } = theme.tokens.semantics.dimensions
100
+ return {
101
+ top: parseTokenValue(spacing.md),
102
+ paddingHorizontal: parseTokenValue(spacing.xl),
103
+ paddingVertical: parseTokenValue(spacing.md)
104
+ }
105
+ })
106
+
107
+ /**
108
+ * Product Display Card component for showing product information with optional quantity picker.
109
+ *
110
+ * @example
111
+ * ```tsx
112
+ * import { ProductDisplayCard } from "@butternutbox/pawprint-native"
113
+ *
114
+ * <ProductDisplayCard
115
+ * device="mobile"
116
+ * title="Premium Recipe"
117
+ * subtext="+£0.00/pouch"
118
+ * quantity={1}
119
+ * showQuantityPicker
120
+ * />
121
+ * ```
122
+ *
123
+ * @param device - *(optional)* Device variant: "desktop" or "mobile" (default)
124
+ * @param title - Product title
125
+ * @param subtext - *(optional)* Subtitle text (e.g. price)
126
+ * @param showSubtext - *(optional)* Show/hide subtext
127
+ * @param quantity - *(optional)* Current quantity value
128
+ * @param onQuantityChange - *(optional)* Callback when quantity changes
129
+ * @param showQuantityPicker - *(optional)* Show/hide quantity picker
130
+ * @param image - *(optional)* Image element or content
131
+ * @param banner - *(optional)* Banner content to show below card
132
+ * @param showBanner - *(optional)* Show/hide banner
133
+ * @param bannerType - *(optional)* Banner notification type: "error", "success", "warning", or "info" (default)
134
+ * @param showBannerIcon - *(optional)* Show/hide banner notification icon
135
+ */
136
+ export const ProductDisplayCard = React.forwardRef<
137
+ View,
138
+ ProductDisplayCardProps
139
+ >(
140
+ (
141
+ {
142
+ device = "mobile",
143
+ title,
144
+ subtext,
145
+ showSubtext = true,
146
+ quantity = 1,
147
+ onQuantityChange,
148
+ showQuantityPicker = false,
149
+ disableQuantityButtons = false,
150
+ hideQuantityButtons = false,
151
+ showIncrementButton,
152
+ showDecrementButton,
153
+ incrementDisabled = false,
154
+ decrementDisabled = false,
155
+ image,
156
+ banner,
157
+ showBanner = false,
158
+ bannerType = "info",
159
+ showBannerIcon = false,
160
+ ...rest
161
+ },
162
+ ref
163
+ ) => {
164
+ const handleQuantityChange = (newQuantity: number) => {
165
+ if (newQuantity >= 1) {
166
+ onQuantityChange?.(newQuantity)
167
+ }
168
+ }
169
+
170
+ const cardContent = (
171
+ <StyledCardContainer ref={ref} cardDevice={device} {...rest}>
172
+ {image && <StyledImage>{image}</StyledImage>}
173
+
174
+ <StyledContentArea contentDevice={device}>
175
+ <StyledTextContainer>
176
+ <Typography variant="heading" size="xs" color="primary">
177
+ {title}
178
+ </Typography>
179
+
180
+ {showSubtext && subtext && (
181
+ <Typography variant="body" size="sm" color="secondary">
182
+ {subtext}
183
+ </Typography>
184
+ )}
185
+ </StyledTextContainer>
186
+
187
+ {showQuantityPicker && (
188
+ <View style={{ marginLeft: "auto" }}>
189
+ <NumberField
190
+ size="sm"
191
+ value={String(quantity)}
192
+ onChangeText={(text) => {
193
+ const value = parseInt(text, 10)
194
+ if (!isNaN(value)) {
195
+ handleQuantityChange(value)
196
+ }
197
+ }}
198
+ onIncrement={() => handleQuantityChange(quantity + 1)}
199
+ onDecrement={() => handleQuantityChange(quantity - 1)}
200
+ min={1}
201
+ accessible
202
+ accessibilityLabel={`Quantity: ${quantity}`}
203
+ showIncrementButton={
204
+ showIncrementButton !== undefined
205
+ ? showIncrementButton
206
+ : !hideQuantityButtons
207
+ }
208
+ showDecrementButton={
209
+ showDecrementButton !== undefined
210
+ ? showDecrementButton
211
+ : !hideQuantityButtons
212
+ }
213
+ incrementDisabled={incrementDisabled || disableQuantityButtons}
214
+ decrementDisabled={decrementDisabled || disableQuantityButtons}
215
+ />
216
+ </View>
217
+ )}
218
+ </StyledContentArea>
219
+ </StyledCardContainer>
220
+ )
221
+
222
+ if (showBanner && banner) {
223
+ return (
224
+ <StyledRootWrapper>
225
+ {cardContent}
226
+ <StyledBannerWrapper>
227
+ <StyledNotification
228
+ variant="inline"
229
+ type={bannerType}
230
+ showIcon={showBannerIcon}
231
+ >
232
+ {banner}
233
+ </StyledNotification>
234
+ </StyledBannerWrapper>
235
+ </StyledRootWrapper>
236
+ )
237
+ }
238
+
239
+ return cardContent
240
+ }
241
+ )
242
+
243
+ ProductDisplayCard.displayName = "ProductDisplayCard"
@@ -0,0 +1,5 @@
1
+ export { ProductDisplayCard } from "./ProductDisplayCard"
2
+ export type {
3
+ ProductDisplayCardProps,
4
+ ProductDisplayCardDevice
5
+ } from "./ProductDisplayCard"