@utilitywarehouse/hearth-react-native 0.8.0 → 0.8.2

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 (45) hide show
  1. package/.storybook/preview.tsx +1 -0
  2. package/.turbo/turbo-build.log +1 -1
  3. package/.turbo/turbo-lint.log +1 -1
  4. package/CHANGELOG.md +22 -0
  5. package/build/components/Banner/Banner.js +27 -7
  6. package/build/components/Banner/Banner.props.d.ts +4 -9
  7. package/build/components/Card/Card.props.d.ts +1 -0
  8. package/build/components/Card/CardRoot.d.ts +1 -1
  9. package/build/components/Card/CardRoot.js +28 -1
  10. package/build/components/HighlightBanner/HighlightBanner.js +12 -2
  11. package/build/components/HighlightBanner/HighlightBanner.props.d.ts +1 -1
  12. package/build/components/List/List.js +1 -1
  13. package/build/components/List/ListAction/ListActionTrailingIcon.js +2 -2
  14. package/build/components/RadioCard/RadioCardGroup.context.d.ts +12 -0
  15. package/build/components/RadioCard/RadioCardGroup.context.js +3 -0
  16. package/build/components/RadioCard/RadioCardGroup.js +15 -10
  17. package/build/components/RadioCard/RadioCardLabel.d.ts +1 -1
  18. package/build/components/RadioCard/RadioCardLabel.js +7 -1
  19. package/build/components/RadioCard/RadioCardRoot.js +13 -0
  20. package/build/core/themes.d.ts +40 -0
  21. package/build/core/themes.js +20 -0
  22. package/docs/adding-shadows.mdx +43 -0
  23. package/package.json +3 -3
  24. package/src/components/Banner/Banner.docs.mdx +1 -1
  25. package/src/components/Banner/Banner.props.ts +4 -9
  26. package/src/components/Banner/Banner.stories.tsx +16 -0
  27. package/src/components/Banner/Banner.tsx +46 -31
  28. package/src/components/Card/Card.docs.mdx +20 -1
  29. package/src/components/Card/Card.props.ts +9 -0
  30. package/src/components/Card/Card.stories.tsx +39 -0
  31. package/src/components/Card/CardRoot.tsx +29 -0
  32. package/src/components/Checkbox/CheckboxGroup.stories.tsx +19 -1
  33. package/src/components/HighlightBanner/HighlightBanner.docs.mdx +21 -2
  34. package/src/components/HighlightBanner/HighlightBanner.props.ts +1 -0
  35. package/src/components/HighlightBanner/HighlightBanner.stories.tsx +31 -1
  36. package/src/components/HighlightBanner/HighlightBanner.tsx +16 -4
  37. package/src/components/List/List.tsx +5 -3
  38. package/src/components/List/ListAction/ListActionTrailingIcon.tsx +2 -2
  39. package/src/components/Radio/RadioGroup.stories.tsx +18 -0
  40. package/src/components/RadioCard/RadioCardGroup.context.ts +16 -0
  41. package/src/components/RadioCard/RadioCardGroup.stories.tsx +24 -0
  42. package/src/components/RadioCard/RadioCardGroup.tsx +28 -19
  43. package/src/components/RadioCard/RadioCardLabel.tsx +12 -1
  44. package/src/components/RadioCard/RadioCardRoot.tsx +15 -0
  45. package/src/core/themes.ts +20 -0
@@ -54,6 +54,20 @@ const meta = {
54
54
  description: 'Icon container size',
55
55
  options: ['sm', 'md', 'lg'],
56
56
  },
57
+ shadowColor: {
58
+ control: 'select',
59
+ description: 'The shadow color of the banner',
60
+ options: [
61
+ 'functional',
62
+ 'brand',
63
+ 'energy',
64
+ 'broadband',
65
+ 'mobile',
66
+ 'insurance',
67
+ 'cashback',
68
+ 'pig',
69
+ ],
70
+ },
57
71
  },
58
72
  args: {
59
73
  heading: 'Welcome to Banner',
@@ -310,6 +324,7 @@ export const VerticalLayout: Story = {
310
324
  direction="vertical"
311
325
  />
312
326
  <Banner
327
+ variant="emphasis"
313
328
  image={{
314
329
  light: {
315
330
  uri: 'https://images.unsplash.com/photo-1506126613408-eca07ce68773?w=200&q=80',
@@ -320,6 +335,7 @@ export const VerticalLayout: Story = {
320
335
  }}
321
336
  heading="Featured Content"
322
337
  description="Discover amazing content curated just for you."
338
+ shadowColor="brand"
323
339
  direction="vertical"
324
340
  button={
325
341
  <Button size="sm" onPress={() => console.log('Learn More pressed')}>
@@ -46,24 +46,16 @@ const Banner = ({
46
46
  if (illustration) {
47
47
  return (
48
48
  <ThemedImage
49
- light={illustration.light}
50
- dark={illustration.dark}
51
- style={styles.image}
52
- accessible
53
- accessibilityLabel={heading}
49
+ {...illustration}
50
+ resizeMode="cover"
51
+ style={[styles.media, styles.imageWrapper, illustration.style]}
54
52
  />
55
53
  );
56
54
  }
57
55
  if (image) {
58
56
  return (
59
57
  <View style={[styles.media, styles.imageWrapper]}>
60
- <ThemedImage
61
- light={image.light}
62
- dark={image.dark}
63
- style={styles.image}
64
- accessible
65
- accessibilityLabel={heading}
66
- />
58
+ <ThemedImage {...image} style={[styles.image, image.style]} />
67
59
  </View>
68
60
  );
69
61
  }
@@ -84,21 +76,24 @@ const Banner = ({
84
76
  <View style={styles.container}>
85
77
  {renderIconOrImage()}
86
78
  <View style={styles.contentContainer}>
87
- <View style={styles.textContainer}>
88
- <Heading
89
- size="sm"
90
- style={styles.heading}
91
- textAlign={hasIllustration && direction === 'vertical' ? 'center' : 'left'}
92
- >
93
- {heading}
94
- </Heading>
95
- <BodyText
96
- size="md"
97
- style={styles.description}
98
- textAlign={hasIllustration && direction === 'vertical' ? 'center' : 'left'}
99
- >
100
- {description}
101
- </BodyText>
79
+ <View style={styles.contentTextContainer}>
80
+ <View style={styles.textContainer}>
81
+ <Heading
82
+ size="sm"
83
+ style={styles.heading}
84
+ textAlign={hasIllustration && direction === 'vertical' ? 'center' : 'left'}
85
+ >
86
+ {heading}
87
+ </Heading>
88
+ <BodyText
89
+ size="md"
90
+ style={styles.description}
91
+ textAlign={hasIllustration && direction === 'vertical' ? 'center' : 'left'}
92
+ >
93
+ {description}
94
+ </BodyText>
95
+ </View>
96
+
102
97
  {renderAction()}
103
98
  </View>
104
99
  {onPress && (
@@ -194,6 +189,7 @@ const styles = StyleSheet.create(theme => ({
194
189
  },
195
190
  },
196
191
  imageWrapper: {
192
+ flexDirection: 'row',
197
193
  variants: {
198
194
  direction: {
199
195
  horizontal: {},
@@ -205,8 +201,8 @@ const styles = StyleSheet.create(theme => ({
205
201
  },
206
202
  image: {
207
203
  borderRadius: theme.borderRadius.md,
208
- borderWidth: theme.borderWidth[1],
209
204
  borderColor: theme.color.border.strong,
205
+ borderWidth: theme.borderWidth[1],
210
206
  variants: {
211
207
  direction: {
212
208
  horizontal: { width: 160, height: 95 },
@@ -218,15 +214,34 @@ const styles = StyleSheet.create(theme => ({
218
214
  },
219
215
  },
220
216
  contentContainer: {
221
- flex: 1,
222
- flexDirection: 'row',
223
217
  alignItems: 'flex-start',
224
218
  justifyContent: 'space-between',
225
219
  gap: theme.space.lg,
220
+ variants: {
221
+ direction: {
222
+ horizontal: {
223
+ flex: 1,
224
+ flexDirection: 'row',
225
+ },
226
+ vertical: {
227
+ flexDirection: 'column',
228
+ },
229
+ },
230
+ },
226
231
  },
227
232
  textContainer: {
228
- flex: 1,
233
+ gap: theme.space.sm,
234
+ },
235
+ contentTextContainer: {
229
236
  gap: theme.space.lg,
237
+ variants: {
238
+ direction: {
239
+ horizontal: {
240
+ flex: 1,
241
+ },
242
+ vertical: {},
243
+ },
244
+ },
230
245
  },
231
246
  heading: {
232
247
  compoundVariants: [
@@ -22,6 +22,7 @@ A Card component serves as a visual container that groups related content and ac
22
22
  - [Variants](#variants)
23
23
  - [Examples](#examples)
24
24
  - [Interactive](#interactive)
25
+ - [With Shadow](#with-shadow)
25
26
  - [With `CardAction`](#with-cardaction)
26
27
  - [`CardAction` Playground](#cardaction-playground)
27
28
  - [`CardAction` With Badge](#cardaction-with-badge)
@@ -64,7 +65,8 @@ const MyComponent = () => (
64
65
  | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | ----------------- |
65
66
  | variant | `'subtle' \| 'emphasis' ` | The variant of the card. | `'subtle'` |
66
67
  | colorScheme | `'neutralStrong' \| 'neutralSubtle' \| 'purple' \| 'energy'` <br /> `'broadband' \| 'mobile' \| 'insurance' \| 'cashback' \|` <br /> `'pig'` | The color scheme of the card. | `'neutralStrong'` |
67
- | noPadding | `boolean` | Wether or not the card has padding. | `false` |
68
+ | shadowColor | `'functional' \| 'brand' \| 'energy' \| 'broadband' \| 'mobile' `<br /> `'insurance' \| 'cashback' \| 'pig'` | The shadow color of the card. | `-` |
69
+ | noPadding | `boolean` | Whether or not the card has padding. | `false` |
68
70
  | selected | `boolean` | Whether the card is selected. | `false` |
69
71
  | onPress | `() => void` | Callback function to be called. | `-` |
70
72
  | disabled | `boolean` | Whether the card is disabled. | `false` |
@@ -146,6 +148,23 @@ const MyComponent = () => (
146
148
  );
147
149
  ```
148
150
 
151
+ ### With Shadow
152
+
153
+ You can add shadow to the `Card` component by using the `shadowColor` prop. This prop accepts various semantic color options to match your design needs.
154
+
155
+ <Canvas of={Stories.WithShadow} />
156
+
157
+ ```jsx
158
+ import { Card, BodyText, Heading } from '@utilitywarehouse/hearth-react-native';
159
+
160
+ const MyComponent = () => (
161
+ <Card shadowColor="functional" variant="emphasis">
162
+ <Heading size="lg">Card with Shadow</Heading>
163
+ <BodyText>This card has a shadow applied using the shadowColor prop.</BodyText>
164
+ </Card>
165
+ );
166
+ ```
167
+
149
168
  ### With `CardAction`
150
169
 
151
170
  You can use the `CardAction` component within a `Card` to create actionable items with consistent styling.
@@ -13,6 +13,15 @@ interface CardProps extends PressableProps {
13
13
  | 'insurance'
14
14
  | 'cashback'
15
15
  | 'pig';
16
+ shadowColor?:
17
+ | 'functional'
18
+ | 'brand'
19
+ | 'energy'
20
+ | 'broadband'
21
+ | 'mobile'
22
+ | 'insurance'
23
+ | 'cashback'
24
+ | 'pig';
16
25
  noPadding?: boolean;
17
26
  disabled?: boolean;
18
27
  space?: SpacingValues;
@@ -38,6 +38,20 @@ const meta = {
38
38
  ],
39
39
  description: 'Use this value to set the Card color scheme.',
40
40
  },
41
+ shadowColor: {
42
+ control: 'select',
43
+ options: [
44
+ 'functional',
45
+ 'brand',
46
+ 'energy',
47
+ 'broadband',
48
+ 'mobile',
49
+ 'insurance',
50
+ 'cashback',
51
+ 'pig',
52
+ ],
53
+ description: 'Use this value to set the Card shadow color.',
54
+ },
41
55
  },
42
56
  args: {
43
57
  children: 'This is a card',
@@ -208,6 +222,31 @@ export const Variants: Story = {
208
222
  },
209
223
  };
210
224
 
225
+ export const WithShadow: Story = {
226
+ args: {
227
+ shadowColor: 'functional',
228
+ },
229
+ parameters: {
230
+ controls: { exclude: ['variant'] },
231
+ },
232
+ render: ({ children, ...props }) => {
233
+ return (
234
+ <Flex space="lg">
235
+ <VariantTitle title="Subtle - White - Shadow">
236
+ <Card {...props} variant="subtle">
237
+ <BodyText>{children as string}</BodyText>
238
+ </Card>
239
+ </VariantTitle>
240
+ <VariantTitle title="Emphasis - White - Shadow">
241
+ <Card {...props} variant="emphasis">
242
+ <BodyText>{children as string}</BodyText>
243
+ </Card>
244
+ </VariantTitle>
245
+ </Flex>
246
+ );
247
+ },
248
+ };
249
+
211
250
  export const Interactive: Story = {
212
251
  parameters: {
213
252
  controls: { exclude: ['variant', 'colorScheme'] },
@@ -104,12 +104,14 @@ const Card = ({
104
104
  children,
105
105
  variant = 'subtle',
106
106
  colorScheme = 'neutralStrong',
107
+ shadowColor,
107
108
  noPadding = false,
108
109
  style,
109
110
  states,
110
111
  space,
111
112
  disabled = false,
112
113
  onPress,
114
+
113
115
  ...rest
114
116
  }: CardProps & { states?: { active?: boolean; disabled?: boolean } }) => {
115
117
  const { active } = states || { active: false };
@@ -165,6 +167,7 @@ const Card = ({
165
167
  showPressed,
166
168
  disabled,
167
169
  space: hasActions || hasContent ? 'none' : space,
170
+ shadowColor,
168
171
  });
169
172
 
170
173
  const renderChildren = () => {
@@ -257,6 +260,32 @@ const styles = StyleSheet.create(theme => ({
257
260
  borderWidth: theme.components.card.brand.borderWidth,
258
261
  },
259
262
  },
263
+ shadowColor: {
264
+ functional: {
265
+ boxShadow: theme.helpers.shadow.functional,
266
+ },
267
+ brand: {
268
+ boxShadow: theme.helpers.shadow.brand,
269
+ },
270
+ energy: {
271
+ boxShadow: theme.helpers.shadow.energy,
272
+ },
273
+ broadband: {
274
+ boxShadow: theme.helpers.shadow.broadband,
275
+ },
276
+ mobile: {
277
+ boxShadow: theme.helpers.shadow.mobile,
278
+ },
279
+ insurance: {
280
+ boxShadow: theme.helpers.shadow.insurance,
281
+ },
282
+ cashback: {
283
+ boxShadow: theme.helpers.shadow.cashback,
284
+ },
285
+ pig: {
286
+ boxShadow: theme.helpers.shadow.pig,
287
+ },
288
+ },
260
289
  noPadding: {
261
290
  true: {
262
291
  padding: theme.components.card.mobile.paddingNone,
@@ -1,5 +1,5 @@
1
- import { Checkbox, CheckboxGroup } from '.';
2
1
  import { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { Checkbox, CheckboxGroup } from '.';
3
3
 
4
4
  const meta = {
5
5
  title: 'Stories / CheckboxGroup',
@@ -80,3 +80,21 @@ export const Playground: Story = {
80
80
  </CheckboxGroup>
81
81
  ),
82
82
  };
83
+
84
+ export const LongContent: Story = {
85
+ args: {
86
+ type: 'tile',
87
+ },
88
+ render: args => (
89
+ <CheckboxGroup {...args}>
90
+ <Checkbox aria-label="Label 1" label="Option 1" value="Option 1" nativeID="Checkbox-1" />
91
+ <Checkbox
92
+ aria-label="Label 2"
93
+ label="Option 2 with a very long content that should wrap into multiple lines to test the layout of the checkbox component in such scenarios."
94
+ value="Option 2"
95
+ nativeID="Checkbox-2"
96
+ />
97
+ <Checkbox aria-label="Label 3" label="Option 3" value="Option 3" nativeID="Checkbox-3" />
98
+ </CheckboxGroup>
99
+ ),
100
+ };
@@ -11,7 +11,7 @@ import * as Stories from './HighlightBanner.stories';
11
11
 
12
12
  # Highlight Banner
13
13
 
14
- A `HighlightBanner` component is a specialised card layout designed for highlighting featured content with an image. It combines a colored heading banner, an image, and descriptive text with optional action buttons or links. Perfect for promotional content, featured articles, or important announcements.
14
+ A `HighlightBanner` component is a specialised card layout designed for highlighting featured content with an image. It combines a colored heading banner, an optional image, and descriptive text with optional action buttons or links. Perfect for promotional content, featured articles, or important announcements.
15
15
 
16
16
  - [Playground](#playground)
17
17
  - [Usage](#usage)
@@ -20,6 +20,7 @@ A `HighlightBanner` component is a specialised card layout designed for highligh
20
20
  - [Examples](#examples)
21
21
  - [With Button](#with-button)
22
22
  - [With Link](#with-link)
23
+ - [Without Image](#without-image)
23
24
  - [Color Variants](#color-variants)
24
25
  - [Subtle Variant](#subtle-variant)
25
26
  - [Different Images](#different-images)
@@ -78,7 +79,7 @@ const MyComponent = () => (
78
79
  | button | `ReactElement` | Optional Button component displayed below description | `-` |
79
80
  | variant | `'emphasis' \| 'subtle'` | Visual style variant with strong or subtle borders | `'emphasis'` |
80
81
 
81
- The component also accepts all standard Card props except `noPadding`, `space`, `gap`, `rowGap`, `columnGap`, `flexDirection`, `flexWrap`, `alignItems`, and `justifyContent`.
82
+ The component also accepts all standard Card props except `noPadding`, `colorScheme`, `space`, `gap`, `rowGap`, `columnGap`, `flexDirection`, `flexWrap`, `alignItems`, and `justifyContent`.
82
83
 
83
84
  ## Variants
84
85
 
@@ -137,6 +138,24 @@ const MyComponent = () => (
137
138
  );
138
139
  ```
139
140
 
141
+ ### Without Image
142
+
143
+ Display the HighlightBanner without an image by omitting the `image` prop:
144
+
145
+ <Canvas of={Stories.WithoutImage} />
146
+
147
+ ```jsx
148
+ import { HighlightBanner, Button } from '@utilitywarehouse/hearth-react-native';
149
+
150
+ const MyComponent = () => (
151
+ <HighlightBanner
152
+ heading="Content Without Image"
153
+ description="This HighlightBanner does not have an image, focusing solely on the text content."
154
+ button={<Button onPress={() => console.log('pressed')}>Discover More</Button>}
155
+ />
156
+ );
157
+ ```
158
+
140
159
  ### Color Variants
141
160
 
142
161
  The component supports seven semantic color schemes that automatically apply the appropriate subtle background colors:
@@ -15,6 +15,7 @@ interface HighlightBannerProps
15
15
  | 'flexWrap'
16
16
  | 'alignItems'
17
17
  | 'justifyContent'
18
+ | 'colorScheme'
18
19
  > {
19
20
  heading?: string;
20
21
  headingColor?: 'pig' | 'energy' | 'broadband' | 'mobile' | 'insurance' | 'cashback' | 'highlight';
@@ -1,4 +1,4 @@
1
- import { Meta, StoryObj } from '@storybook/react-vite';
1
+ import { Meta, StoryObj } from '@storybook/react-native';
2
2
  import { View } from 'react-native';
3
3
  import { Button } from '../Button';
4
4
  import { Flex } from '../Flex';
@@ -30,6 +30,20 @@ const meta = {
30
30
  description: 'The variant style of the HighlightBanner',
31
31
  options: ['emphasis', 'subtle'],
32
32
  },
33
+ shadowColor: {
34
+ control: 'select',
35
+ description: 'The shadow color of the card',
36
+ options: [
37
+ 'functional',
38
+ 'brand',
39
+ 'energy',
40
+ 'broadband',
41
+ 'mobile',
42
+ 'insurance',
43
+ 'cashback',
44
+ 'pig',
45
+ ],
46
+ },
33
47
  },
34
48
  args: {
35
49
  heading: 'Featured Content',
@@ -174,6 +188,22 @@ export const ColorVariants: Story = {
174
188
  },
175
189
  };
176
190
 
191
+ export const WithoutImage: Story = {
192
+ render: args => {
193
+ return (
194
+ <View style={{ width: 400 }}>
195
+ <HighlightBanner
196
+ {...args}
197
+ image={undefined}
198
+ heading="Content Without Image"
199
+ description="This HighlightBanner does not have an image, focusing solely on the text content."
200
+ button={<Button onPress={() => console.log('pressed')}>Discover More</Button>}
201
+ />
202
+ </View>
203
+ );
204
+ },
205
+ };
206
+
177
207
  export const SubtleCard: Story = {
178
208
  args: {
179
209
  variant: 'subtle',
@@ -16,7 +16,7 @@ const HighlightBanner = ({
16
16
  style,
17
17
  ...props
18
18
  }: HighlightBannerProps) => {
19
- styles.useVariants({ headingColor, variant });
19
+ styles.useVariants({ headingColor, variant, hasImage: Boolean(image) });
20
20
 
21
21
  return (
22
22
  <Card variant={variant} noPadding style={style} {...props}>
@@ -26,9 +26,11 @@ const HighlightBanner = ({
26
26
  {heading}
27
27
  </BodyText>
28
28
  </View>
29
- <View style={styles.imageContainer(imageContainerHeight)}>
30
- <Image resizeMode="cover" {...image} style={[styles.image, image?.style]} />
31
- </View>
29
+ {!!image && (
30
+ <View style={styles.imageContainer(imageContainerHeight)}>
31
+ <Image resizeMode="cover" {...image} style={[styles.image, image?.style]} />
32
+ </View>
33
+ )}
32
34
  <View style={styles.footer}>
33
35
  <BodyText size="md" textAlign="center">
34
36
  {description}
@@ -86,6 +88,11 @@ const styles = StyleSheet.create(theme => ({
86
88
  borderColor: theme.color.border.subtle,
87
89
  },
88
90
  },
91
+ hasImage: {
92
+ false: {
93
+ borderBottomWidth: 0,
94
+ },
95
+ },
89
96
  },
90
97
  },
91
98
  imageContainer: (height: number = 200) => ({
@@ -109,6 +116,11 @@ const styles = StyleSheet.create(theme => ({
109
116
  borderColor: theme.color.border.subtle,
110
117
  },
111
118
  },
119
+ hasImage: {
120
+ true: {
121
+ flex: 1,
122
+ },
123
+ },
112
124
  },
113
125
  },
114
126
  linkContainer: {
@@ -69,9 +69,11 @@ const List = ({ children, heading, helperText, headerTrailingContent, ...props }
69
69
  {container === 'none' ? (
70
70
  <View>{updatedChildren}</View>
71
71
  ) : (
72
- <Card {...containerToCard} noPadding style={styles.card}>
73
- <>{updatedChildren}</>
74
- </Card>
72
+ React.Children.count(updatedChildren) > 0 && (
73
+ <Card {...containerToCard} noPadding style={styles.card}>
74
+ <>{updatedChildren}</>
75
+ </Card>
76
+ )
75
77
  )}
76
78
  </View>
77
79
  </ListContext.Provider>
@@ -25,8 +25,8 @@ ListActionTrailingIcon.displayName = 'ListActionTrailingIcon';
25
25
  const styles = StyleSheet.create(theme => ({
26
26
  icon: {
27
27
  color: theme.color.icon.primary,
28
- width: 24,
29
- height: 24,
28
+ minWidth: 20,
29
+ minHeight: 20,
30
30
  },
31
31
  }));
32
32
 
@@ -105,3 +105,21 @@ export const WithGrid: Story = {
105
105
  </RadioGroup>
106
106
  ),
107
107
  };
108
+
109
+ export const LongContent: Story = {
110
+ args: {
111
+ type: 'tile',
112
+ },
113
+ render: args => (
114
+ <RadioGroup {...args}>
115
+ <Radio aria-label="Label 1" label="Option 1" value="Option 1" nativeID="Radio-1" />
116
+ <Radio
117
+ aria-label="Label 2"
118
+ label="Option 2 with a very long content that spans multiple lines to test text wrapping"
119
+ value="Option 2"
120
+ nativeID="Radio-2"
121
+ />
122
+ <Radio aria-label="Label 3" label="Option 3" value="Option 3" nativeID="Radio-3" />
123
+ </RadioGroup>
124
+ ),
125
+ };
@@ -0,0 +1,16 @@
1
+ import { createContext, useContext } from 'react';
2
+
3
+ export const RadioCardGroupContext = createContext<{
4
+ flexDirection?: 'row' | 'column' | 'row-reverse' | 'column-reverse';
5
+ flexWrap?: 'nowrap' | 'wrap' | 'wrap-reverse';
6
+ justifyContent?:
7
+ | 'flex-start'
8
+ | 'flex-end'
9
+ | 'center'
10
+ | 'space-between'
11
+ | 'space-around'
12
+ | 'space-evenly';
13
+ alignItems?: 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline';
14
+ }>({});
15
+
16
+ export const useRadioCardGroupContext = () => useContext(RadioCardGroupContext);
@@ -68,3 +68,27 @@ export const Playground: Story = {
68
68
  </RadioCardGroup>
69
69
  ),
70
70
  };
71
+
72
+ export const LongContent: Story = {
73
+ args: {
74
+ flexDirection: 'column',
75
+ },
76
+ render: args => (
77
+ <RadioCardGroup {...args}>
78
+ <RadioCard aria-label="Label 1" label="Option 1" value="Option 1" nativeID="RadioCard-1">
79
+ <BodyText>Additional content</BodyText>
80
+ </RadioCard>
81
+ <RadioCard
82
+ aria-label="Label 2"
83
+ label="Option 2 with a very long content that should wrap into multiple lines to test the layout of the RadioCard component in such scenarios."
84
+ value="Option 2"
85
+ nativeID="RadioCard-2"
86
+ >
87
+ <BodyText>Additional content</BodyText>
88
+ </RadioCard>
89
+ <RadioCard aria-label="Label 3" label="Option 3" value="Option 3" nativeID="RadioCard-3">
90
+ <BodyText>Additional content</BodyText>
91
+ </RadioCard>
92
+ </RadioCardGroup>
93
+ ),
94
+ };
@@ -1,7 +1,9 @@
1
- import RadioCardGroupProps from './RadioCardGroup.props';
1
+ import { useMemo } from 'react';
2
2
  import { View } from 'react-native';
3
3
  import { StyleSheet } from 'react-native-unistyles';
4
4
  import { Grid } from '../Grid';
5
+ import { RadioCardGroupContext } from './RadioCardGroup.context';
6
+ import RadioCardGroupProps from './RadioCardGroup.props';
5
7
 
6
8
  const RadioCardGroup = ({
7
9
  children,
@@ -14,26 +16,33 @@ const RadioCardGroup = ({
14
16
  columns,
15
17
  ...props
16
18
  }: RadioCardGroupProps) => {
19
+ const context = useMemo(() => {
20
+ return { flexDirection, flexWrap, justifyContent, alignItems };
21
+ }, [flexDirection, flexWrap, justifyContent, alignItems]);
17
22
  return columns ? (
18
- <Grid {...props} gap={gap} columns={columns} style={style}>
19
- {children as any}
20
- </Grid>
23
+ <RadioCardGroupContext.Provider value={context}>
24
+ <Grid {...props} gap={gap} columns={columns} style={style}>
25
+ {children as any}
26
+ </Grid>
27
+ </RadioCardGroupContext.Provider>
21
28
  ) : (
22
- <View
23
- {...props}
24
- style={[
25
- styles.containerGap(gap),
26
- {
27
- flexDirection,
28
- flexWrap,
29
- justifyContent,
30
- alignItems,
31
- },
32
- style,
33
- ]}
34
- >
35
- {children}
36
- </View>
29
+ <RadioCardGroupContext.Provider value={context}>
30
+ <View
31
+ {...props}
32
+ style={[
33
+ styles.containerGap(gap),
34
+ {
35
+ flexDirection,
36
+ flexWrap,
37
+ justifyContent,
38
+ alignItems,
39
+ },
40
+ style,
41
+ ]}
42
+ >
43
+ {children}
44
+ </View>
45
+ </RadioCardGroupContext.Provider>
37
46
  );
38
47
  };
39
48