@butternutbox/pawprint-native 0.8.0 → 0.10.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.
@@ -1,5 +1,5 @@
1
1
  import React from "react"
2
- import { View, ViewProps, Image } from "react-native"
2
+ import { View, ViewProps, Image, Pressable } from "react-native"
3
3
  import styled from "@emotion/native"
4
4
  import { Typography } from "../../atoms/Typography"
5
5
  import { NumberField } from "../../molecules/NumberField"
@@ -15,107 +15,74 @@ 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
20
+ minQuantity?: number
22
21
  image?: string | React.ReactNode
23
22
  imageBackgroundColor?: string
24
23
  thumbnailWidth?: number
25
- thumbnailBackgroundColor?: string
26
- showImageQuantityBadge?: boolean
27
- borderless?: boolean
24
+ onImagePress?: () => void
28
25
  banner?: React.ReactNode
29
26
  showBanner?: boolean
30
27
  bannerType?: "error" | "success" | "warning" | "info"
31
28
  showBannerIcon?: boolean
32
29
  }
33
30
 
34
- const StyledCardContainer = styled(View)<{ borderless?: boolean }>(({
35
- theme,
36
- borderless
37
- }) => {
31
+ const StyledCardContainer = styled(View, {
32
+ shouldForwardProp: (prop) => prop !== "showBanner"
33
+ })<{ showBanner?: boolean }>(({ theme }) => {
38
34
  const { spacing, borderRadius } = theme.tokens.semantics.dimensions
39
35
  const { colour } = theme.tokens.semantics
40
36
  const spacingMd = parseTokenValue(spacing.md)
41
37
  const spacingXl = parseTokenValue(spacing.xl)
38
+ const radiusMd = parseTokenValue(borderRadius.md)
42
39
  return {
43
40
  flexDirection: "row",
44
41
  width: "100%",
45
- height: borderless ? undefined : "100%",
46
- maxHeight: spacingXl * 6 + spacingMd,
42
+ // The 148px image sets the baseline height; the card grows if the content
43
+ // is taller (e.g. a long or translated title wrapping to multiple lines)
44
+ // so nothing is clipped.
45
+ minHeight: 148,
47
46
  backgroundColor: colour.background.surface.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
- }),
59
- borderRadius: parseTokenValue(borderRadius.md),
47
+ borderWidth: 1,
48
+ borderColor: colour.border.default,
49
+ shadowColor: "#522a10",
50
+ shadowOffset: { width: 0, height: spacingMd / 4 },
51
+ shadowOpacity: 0.05,
52
+ shadowRadius: spacingXl - 4,
53
+ elevation: 5,
54
+ borderRadius: radiusMd,
60
55
  overflow: "hidden",
61
- zIndex: 1
56
+ zIndex: 1,
57
+ // Don't apply negative margin when banner is shown; banner wrapper handles positioning
58
+ marginBottom: 0,
59
+ flex: 1
62
60
  }
63
61
  })
64
62
 
65
63
  const StyledImage = styled(View)<{
66
64
  imageBackgroundColor?: string
67
65
  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
- )
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
- })
66
+ }>(({ theme, imageBackgroundColor, thumbnailWidth = 148 }) => ({
67
+ flexShrink: 0,
68
+ backgroundColor:
69
+ imageBackgroundColor ||
70
+ theme.tokens.semantics.colour.background.container.secondary,
71
+ overflow: "hidden",
72
+ width: thumbnailWidth,
73
+ // Square (148) by default; stretches taller to fill the card when the
74
+ // content makes it taller than the image.
75
+ minHeight: thumbnailWidth,
76
+ position: "relative"
77
+ }))
108
78
 
109
- const StyledContentArea = styled(View)<{ borderless?: boolean }>(({
110
- theme,
111
- borderless
112
- }) => {
79
+ const StyledContentArea = styled(View)(({ theme }) => {
113
80
  const { spacing } = theme.tokens.semantics.dimensions
114
81
  const paddingValue = parseTokenValue(spacing.md)
115
82
  return {
116
83
  flex: 1,
117
84
  paddingHorizontal: paddingValue,
118
- paddingVertical: borderless ? 0 : paddingValue,
85
+ paddingVertical: paddingValue,
119
86
  gap: parseTokenValue(spacing.xs),
120
87
  justifyContent: "space-between"
121
88
  }
@@ -125,27 +92,44 @@ const StyledTextContainer = styled(View)(() => ({
125
92
  gap: 2
126
93
  }))
127
94
 
128
- const StyledBannerWrapper = styled(View)(() => ({
129
- width: "100%",
130
- marginTop: -48,
131
- paddingTop: 24,
132
- paddingBottom: 16
133
- }))
95
+ const StyledBannerWrapper = styled(View)(({ theme }) => {
96
+ const { spacing, borderRadius } = theme.tokens.semantics.dimensions
97
+ const radiusMd = parseTokenValue(borderRadius.md)
98
+ const spacingMd = parseTokenValue(spacing.md)
99
+ return {
100
+ width: "100%",
101
+ // Tuck the banner up to overlap with card bottom; the 27px notification padding
102
+ // shows the cream reveal under the card's rounded corners
103
+ marginTop: -(radiusMd + spacingMd),
104
+ marginBottom: 0,
105
+ paddingTop: spacingMd,
106
+ paddingBottom: spacingMd
107
+ }
108
+ })
134
109
 
135
110
  const StyledRootWrapper = styled(View)(() => {
136
111
  return {
137
112
  flexDirection: "column",
138
113
  width: "100%",
139
- height: "100%"
114
+ maxWidth: 358
140
115
  }
141
116
  })
142
117
 
143
118
  const StyledNotification = styled(Notification as any)(({ theme }) => {
144
- const { spacing } = theme.tokens.semantics.dimensions
119
+ const { spacing, borderRadius } = theme.tokens.semantics.dimensions
120
+ const spacingMd = parseTokenValue(spacing.md)
121
+ const radiusMd = parseTokenValue(borderRadius.md)
145
122
  return {
146
- top: parseTokenValue(spacing.md),
147
- paddingHorizontal: parseTokenValue(spacing.xl),
148
- paddingVertical: parseTokenValue(spacing.md)
123
+ paddingHorizontal: spacingMd,
124
+ // 27px top padding (Figma) leaves a small cream reveal above the text once
125
+ // the banner tucks behind the card.
126
+ paddingTop: 27,
127
+ paddingBottom: spacingMd,
128
+ // Square top corners, rounded bottom corners (banner tucks under the card).
129
+ borderTopLeftRadius: 0,
130
+ borderTopRightRadius: 0,
131
+ borderBottomLeftRadius: radiusMd,
132
+ borderBottomRightRadius: radiusMd
149
133
  }
150
134
  })
151
135
 
@@ -190,16 +174,13 @@ export const ProductDisplayCard = React.forwardRef<
190
174
  showQuantityPicker = false,
191
175
  disableQuantityButtons = false,
192
176
  hideQuantityButtons = false,
193
- showIncrementButton,
194
- showDecrementButton,
195
177
  incrementDisabled = false,
196
178
  decrementDisabled = false,
179
+ minQuantity = 1,
197
180
  image,
198
181
  imageBackgroundColor,
199
182
  thumbnailWidth,
200
- thumbnailBackgroundColor,
201
- showImageQuantityBadge = false,
202
- borderless = false,
183
+ onImagePress,
203
184
  banner,
204
185
  showBanner = false,
205
186
  bannerType = "info",
@@ -209,38 +190,37 @@ export const ProductDisplayCard = React.forwardRef<
209
190
  ref
210
191
  ) => {
211
192
  const handleQuantityChange = (newQuantity: number) => {
212
- if (newQuantity >= 1) {
193
+ if (newQuantity >= minQuantity) {
213
194
  onQuantityChange?.(newQuantity)
214
195
  }
215
196
  }
216
197
 
217
198
  const cardContent = (
218
- <StyledCardContainer ref={ref} borderless={borderless} {...rest}>
199
+ <StyledCardContainer
200
+ ref={ref}
201
+ showBanner={showBanner && !!banner}
202
+ {...rest}
203
+ >
219
204
  {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>
205
+ <Pressable disabled={!onImagePress} onPress={onImagePress}>
206
+ <StyledImage
207
+ imageBackgroundColor={imageBackgroundColor}
208
+ thumbnailWidth={thumbnailWidth}
209
+ >
210
+ {typeof image === "string" ? (
211
+ <Image
212
+ source={{ uri: image }}
213
+ resizeMode="cover"
214
+ style={{ flex: 1, width: "100%" }}
215
+ />
216
+ ) : (
217
+ image
218
+ )}
219
+ </StyledImage>
220
+ </Pressable>
241
221
  )}
242
222
 
243
- <StyledContentArea borderless={borderless}>
223
+ <StyledContentArea>
244
224
  <StyledTextContainer>
245
225
  <Typography variant="heading" size="2xs" color="primary">
246
226
  {title}
@@ -266,19 +246,11 @@ export const ProductDisplayCard = React.forwardRef<
266
246
  }}
267
247
  onIncrement={() => handleQuantityChange(quantity + 1)}
268
248
  onDecrement={() => handleQuantityChange(quantity - 1)}
269
- min={1}
249
+ min={minQuantity}
270
250
  accessible
271
251
  accessibilityLabel={`Quantity: ${quantity}`}
272
- showIncrementButton={
273
- showIncrementButton !== undefined
274
- ? showIncrementButton
275
- : !hideQuantityButtons
276
- }
277
- showDecrementButton={
278
- showDecrementButton !== undefined
279
- ? showDecrementButton
280
- : !hideQuantityButtons
281
- }
252
+ showIncrementButton={!hideQuantityButtons}
253
+ showDecrementButton={!hideQuantityButtons}
282
254
  incrementDisabled={incrementDisabled || disableQuantityButtons}
283
255
  decrementDisabled={decrementDisabled || disableQuantityButtons}
284
256
  />
@@ -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.sm),
31
- backgroundColor: colour.background.container.alt,
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
  }
@@ -1,5 +1,5 @@
1
1
  import React from "react"
2
- import { View } from "react-native"
2
+ import { View, Text } from "react-native"
3
3
  import { ProductListingCard } from "./ProductListingCard"
4
4
  import { Badge } from "./Badge"
5
5
  import { ThumbsUpFilledPrimary } from "@butternutbox/pawprint-icons/marketing"
@@ -207,3 +207,67 @@ export const WithWasPrice = {
207
207
  </View>
208
208
  )
209
209
  }
210
+
211
+ export const WithStringImage = {
212
+ render: () => (
213
+ <View style={{ width: 232, alignSelf: "flex-start" }}>
214
+ <ProductListingCard
215
+ image="https://placehold.co/232x232/E8E8E8/666?text=Product"
216
+ imageAlt="Product Image"
217
+ badge={defaultBadge}
218
+ category="Daily supplements"
219
+ title="Fish Oil"
220
+ size="200ml"
221
+ price="From £7.49"
222
+ showBadge={true}
223
+ showCategory={true}
224
+ showTitle={true}
225
+ showSize={true}
226
+ showPrice={true}
227
+ />
228
+ </View>
229
+ )
230
+ }
231
+
232
+ export const WithCustomComponent = {
233
+ render: () => (
234
+ <View style={{ width: 232, alignSelf: "flex-start" }}>
235
+ <ProductListingCard
236
+ image={
237
+ <View
238
+ style={{
239
+ flex: 1,
240
+ backgroundColor: "#F5E6D3",
241
+ justifyContent: "center",
242
+ alignItems: "center"
243
+ }}
244
+ >
245
+ <View
246
+ style={{
247
+ width: 80,
248
+ height: 80,
249
+ backgroundColor: "#D4A574",
250
+ borderRadius: 40,
251
+ justifyContent: "center",
252
+ alignItems: "center"
253
+ }}
254
+ >
255
+ <Text style={{ fontSize: 40 }}>🐟</Text>
256
+ </View>
257
+ </View>
258
+ }
259
+ imageAlt="Custom component"
260
+ badge={defaultBadge}
261
+ category="Daily supplements"
262
+ title="Fish Oil"
263
+ size="200ml"
264
+ price="From £7.49"
265
+ showBadge={true}
266
+ showCategory={true}
267
+ showTitle={true}
268
+ showSize={true}
269
+ showPrice={true}
270
+ />
271
+ </View>
272
+ )
273
+ }
@@ -12,7 +12,7 @@ import { Badge } from "./Badge"
12
12
  import { Grid } from "./Grid"
13
13
 
14
14
  type ProductListingCardOwnProps = {
15
- image?: ImageSourcePropType
15
+ image?: string | React.ReactNode | ImageSourcePropType
16
16
  imageAlt?: string
17
17
  badge?: React.ReactNode
18
18
  category?: string
@@ -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
- 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
- })
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)(({ 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
- }
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 }) => {
@@ -167,11 +145,21 @@ const _ProductListingCard = React.forwardRef<View, ProductListingCardProps>(
167
145
  <ImageContainer>
168
146
  {image && (
169
147
  <View style={{ flex: 1, width: "100%", height: "100%" }}>
170
- <StyledImage
171
- source={image}
172
- accessibilityLabel={imageAlt}
173
- accessible
174
- />
148
+ {typeof image === "string" ? (
149
+ <StyledImage
150
+ source={{ uri: image }}
151
+ accessibilityLabel={imageAlt}
152
+ accessible
153
+ />
154
+ ) : React.isValidElement(image) ? (
155
+ image
156
+ ) : (
157
+ <StyledImage
158
+ source={image as ImageSourcePropType}
159
+ accessibilityLabel={imageAlt}
160
+ accessible
161
+ />
162
+ )}
175
163
  </View>
176
164
  )}
177
165
  {showBadge && badge && <BadgeContainer>{badge}</BadgeContainer>}
@@ -194,11 +182,9 @@ const _ProductListingCard = React.forwardRef<View, ProductListingCardProps>(
194
182
  </TitleContainer>
195
183
  )}
196
184
  {showSize && size && (
197
- <SizeWrapper>
198
- <Typography variant="body" size="md" color="secondary">
199
- {size}
200
- </Typography>
201
- </SizeWrapper>
185
+ <Typography variant="body" size="md" color="secondary">
186
+ {size}
187
+ </Typography>
202
188
  )}
203
189
  </DetailsContainer>
204
190
 
@@ -1,6 +1,5 @@
1
1
  import React, { useState } from "react"
2
2
  import { View, StyleSheet } from "react-native"
3
- import { PortalHost } from "@rn-primitives/portal"
4
3
  import { SelectField, useSelectField } from "."
5
4
  import { Typography } from "../../atoms/Typography"
6
5
  import { Icon } from "../../atoms/Icon"
@@ -8,10 +7,7 @@ import { Search, Settings, Lock, Info } from "@butternutbox/pawprint-icons/core"
8
7
  import type { Option } from "@rn-primitives/select"
9
8
 
10
9
  const StoryWrapper = ({ children }: { children: React.ReactNode }) => (
11
- <>
12
- {children}
13
- <PortalHost />
14
- </>
10
+ <>{children}</>
15
11
  )
16
12
 
17
13
  export default {
@@ -304,6 +300,115 @@ export const Controlled = () => {
304
300
  )
305
301
  }
306
302
 
303
+ export const Searchable = () => (
304
+ <StoryWrapper>
305
+ <View style={styles.column}>
306
+ <View style={styles.section}>
307
+ <Typography size="sm" weight="semiBold" color="tertiary">
308
+ Searchable Select
309
+ </Typography>
310
+ <SelectField
311
+ label="Country"
312
+ placeholder="Select a country"
313
+ description="Type to filter countries"
314
+ searchable
315
+ searchPlaceholder="Search countries..."
316
+ >
317
+ <SelectField.Item value="au">Australia</SelectField.Item>
318
+ <SelectField.Item value="br">Brazil</SelectField.Item>
319
+ <SelectField.Item value="ca">Canada</SelectField.Item>
320
+ <SelectField.Item value="dk">Denmark</SelectField.Item>
321
+ <SelectField.Item value="eg">Egypt</SelectField.Item>
322
+ <SelectField.Item value="fr">France</SelectField.Item>
323
+ <SelectField.Item value="de">Germany</SelectField.Item>
324
+ <SelectField.Item value="in">India</SelectField.Item>
325
+ <SelectField.Item value="jp">Japan</SelectField.Item>
326
+ <SelectField.Item value="mx">Mexico</SelectField.Item>
327
+ <SelectField.Item value="nl">Netherlands</SelectField.Item>
328
+ <SelectField.Item value="nz">New Zealand</SelectField.Item>
329
+ <SelectField.Item value="no">Norway</SelectField.Item>
330
+ <SelectField.Item value="pl">Poland</SelectField.Item>
331
+ <SelectField.Item value="pt">Portugal</SelectField.Item>
332
+ <SelectField.Item value="es">Spain</SelectField.Item>
333
+ <SelectField.Item value="se">Sweden</SelectField.Item>
334
+ <SelectField.Item value="ch">Switzerland</SelectField.Item>
335
+ <SelectField.Item value="uk">United Kingdom</SelectField.Item>
336
+ <SelectField.Item value="us">United States</SelectField.Item>
337
+ </SelectField>
338
+ </View>
339
+ </View>
340
+ </StoryWrapper>
341
+ )
342
+
343
+ export const SearchableControlled = () => {
344
+ const [value, setValue] = useState<Option | string | null>(null)
345
+
346
+ const displayValue = (() => {
347
+ if (!value) return "(none)"
348
+ if (typeof value === "object" && "value" in value) return value.value
349
+ return String(value)
350
+ })()
351
+
352
+ return (
353
+ <StoryWrapper>
354
+ <View style={styles.column}>
355
+ <View style={styles.section}>
356
+ <Typography size="sm" weight="semiBold" color="tertiary">
357
+ Controlled value: {displayValue}
358
+ </Typography>
359
+ <SelectField
360
+ label="Country"
361
+ placeholder="Select a country"
362
+ description="Select a country — the clear button resets the controlled value"
363
+ searchable
364
+ searchPlaceholder="Search countries..."
365
+ value={value}
366
+ onValueChange={(newValue) => setValue(newValue)}
367
+ >
368
+ <SelectField.Item value="au">Australia</SelectField.Item>
369
+ <SelectField.Item value="ca">Canada</SelectField.Item>
370
+ <SelectField.Item value="fr">France</SelectField.Item>
371
+ <SelectField.Item value="de">Germany</SelectField.Item>
372
+ <SelectField.Item value="jp">Japan</SelectField.Item>
373
+ <SelectField.Item value="uk">United Kingdom</SelectField.Item>
374
+ <SelectField.Item value="us">United States</SelectField.Item>
375
+ </SelectField>
376
+ </View>
377
+ </View>
378
+ </StoryWrapper>
379
+ )
380
+ }
381
+
382
+ export const SearchableDefaultPlaceholder = () => (
383
+ <StoryWrapper>
384
+ <View style={styles.column}>
385
+ <View style={styles.section}>
386
+ <Typography size="sm" weight="semiBold" color="tertiary">
387
+ Default Search Placeholder
388
+ </Typography>
389
+ <SelectField label="Pet breed" placeholder="Select a breed" searchable>
390
+ <SelectField.Item value="labrador">
391
+ Labrador Retriever
392
+ </SelectField.Item>
393
+ <SelectField.Item value="german-shepherd">
394
+ German Shepherd
395
+ </SelectField.Item>
396
+ <SelectField.Item value="golden-retriever">
397
+ Golden Retriever
398
+ </SelectField.Item>
399
+ <SelectField.Item value="bulldog">Bulldog</SelectField.Item>
400
+ <SelectField.Item value="poodle">Poodle</SelectField.Item>
401
+ <SelectField.Item value="beagle">Beagle</SelectField.Item>
402
+ <SelectField.Item value="rottweiler">Rottweiler</SelectField.Item>
403
+ <SelectField.Item value="yorkshire-terrier">
404
+ Yorkshire Terrier
405
+ </SelectField.Item>
406
+ </SelectField>
407
+ </View>
408
+ </View>
409
+ </StoryWrapper>
410
+ )
411
+
307
412
  const styles = StyleSheet.create({
308
413
  container: {
309
414
  width: 320