@utilitywarehouse/hearth-react-native 0.8.1 → 0.9.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 (135) 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 +24 -0
  5. package/build/components/Banner/Banner.js +49 -10
  6. package/build/components/Banner/Banner.props.d.ts +4 -9
  7. package/build/components/BottomSheet/BottomSheetHandle.js +8 -0
  8. package/build/components/Card/Card.props.d.ts +1 -0
  9. package/build/components/Card/CardRoot.d.ts +1 -1
  10. package/build/components/Card/CardRoot.js +28 -1
  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/Menu/Menu.context.d.ts +5 -0
  15. package/build/components/Menu/Menu.context.js +9 -0
  16. package/build/components/Menu/Menu.d.ts +4 -0
  17. package/build/components/Menu/Menu.js +25 -0
  18. package/build/components/Menu/Menu.props.d.ts +21 -0
  19. package/build/components/Menu/Menu.props.js +1 -0
  20. package/build/components/Menu/MenuItem.d.ts +18 -0
  21. package/build/components/Menu/MenuItem.js +115 -0
  22. package/build/components/Menu/MenuItem.props.d.ts +27 -0
  23. package/build/components/Menu/MenuItem.props.js +1 -0
  24. package/build/components/Menu/MenuTrigger.d.ts +9 -0
  25. package/build/components/Menu/MenuTrigger.js +11 -0
  26. package/build/components/Menu/MenuTrigger.props.d.ts +12 -0
  27. package/build/components/Menu/MenuTrigger.props.js +1 -0
  28. package/build/components/Menu/index.d.ts +7 -0
  29. package/build/components/Menu/index.js +4 -0
  30. package/build/components/Modal/Modal.d.ts +1 -1
  31. package/build/components/Modal/Modal.js +32 -30
  32. package/build/components/Modal/Modal.props.d.ts +1 -0
  33. package/build/components/Modal/Modal.web.d.ts +1 -1
  34. package/build/components/Modal/Modal.web.js +25 -25
  35. package/build/components/RadioCard/RadioCardGroup.context.d.ts +12 -0
  36. package/build/components/RadioCard/RadioCardGroup.context.js +3 -0
  37. package/build/components/RadioCard/RadioCardGroup.js +15 -10
  38. package/build/components/RadioCard/RadioCardLabel.d.ts +1 -1
  39. package/build/components/RadioCard/RadioCardLabel.js +7 -1
  40. package/build/components/RadioCard/RadioCardRoot.js +13 -0
  41. package/build/components/index.d.ts +1 -0
  42. package/build/components/index.js +1 -0
  43. package/build/core/themes.d.ts +40 -0
  44. package/build/core/themes.js +20 -0
  45. package/build/tokens/components/dark/index.d.ts +3 -1
  46. package/build/tokens/components/dark/index.js +3 -1
  47. package/build/tokens/components/dark/input.d.ts +3 -0
  48. package/build/tokens/components/dark/input.js +3 -0
  49. package/build/tokens/components/dark/modal.d.ts +7 -4
  50. package/build/tokens/components/dark/modal.js +7 -4
  51. package/build/tokens/components/dark/rating.d.ts +8 -0
  52. package/build/tokens/components/dark/rating.js +7 -0
  53. package/build/tokens/components/dark/table.d.ts +0 -3
  54. package/build/tokens/components/dark/table.js +0 -3
  55. package/build/tokens/components/dark/time-picker.d.ts +29 -0
  56. package/build/tokens/components/dark/time-picker.js +28 -0
  57. package/build/tokens/components/dark/timeline.d.ts +27 -0
  58. package/build/tokens/components/dark/timeline.js +26 -0
  59. package/build/tokens/components/light/index.d.ts +3 -1
  60. package/build/tokens/components/light/index.js +3 -1
  61. package/build/tokens/components/light/input.d.ts +3 -0
  62. package/build/tokens/components/light/input.js +3 -0
  63. package/build/tokens/components/light/modal.d.ts +7 -4
  64. package/build/tokens/components/light/modal.js +7 -4
  65. package/build/tokens/components/light/rating.d.ts +8 -0
  66. package/build/tokens/components/light/rating.js +7 -0
  67. package/build/tokens/components/light/table.d.ts +0 -3
  68. package/build/tokens/components/light/table.js +0 -3
  69. package/build/tokens/components/light/time-picker.d.ts +29 -0
  70. package/build/tokens/components/light/time-picker.js +28 -0
  71. package/build/tokens/components/light/timeline.d.ts +27 -0
  72. package/build/tokens/components/light/timeline.js +26 -0
  73. package/docs/adding-shadows.mdx +43 -0
  74. package/docs/components/AllComponents.web.tsx +33 -0
  75. package/docs/components/BackToTopButton.tsx +1 -1
  76. package/package.json +3 -3
  77. package/src/components/Banner/Banner.docs.mdx +20 -11
  78. package/src/components/Banner/Banner.props.ts +4 -9
  79. package/src/components/Banner/Banner.stories.tsx +17 -4
  80. package/src/components/Banner/Banner.tsx +92 -37
  81. package/src/components/BottomSheet/BottomSheetHandle.tsx +12 -0
  82. package/src/components/Card/Card.docs.mdx +20 -1
  83. package/src/components/Card/Card.props.ts +9 -0
  84. package/src/components/Card/Card.stories.tsx +39 -0
  85. package/src/components/Card/CardRoot.tsx +29 -0
  86. package/src/components/Checkbox/CheckboxGroup.stories.tsx +19 -1
  87. package/src/components/DatePickerInput/DatePickerInput.docs.mdx +1 -1
  88. package/src/components/HighlightBanner/HighlightBanner.docs.mdx +1 -1
  89. package/src/components/HighlightBanner/HighlightBanner.props.ts +1 -0
  90. package/src/components/HighlightBanner/HighlightBanner.stories.tsx +15 -1
  91. package/src/components/List/List.tsx +5 -3
  92. package/src/components/List/ListAction/ListActionTrailingIcon.tsx +2 -2
  93. package/src/components/Menu/Menu.context.ts +15 -0
  94. package/src/components/Menu/Menu.docs.mdx +158 -0
  95. package/src/components/Menu/Menu.props.ts +24 -0
  96. package/src/components/Menu/Menu.stories.tsx +292 -0
  97. package/src/components/Menu/Menu.tsx +54 -0
  98. package/src/components/Menu/MenuItem.props.ts +29 -0
  99. package/src/components/Menu/MenuItem.tsx +145 -0
  100. package/src/components/Menu/MenuTrigger.props.ts +14 -0
  101. package/src/components/Menu/MenuTrigger.tsx +20 -0
  102. package/src/components/Menu/index.ts +7 -0
  103. package/src/components/Modal/Modal.docs.mdx +34 -5
  104. package/src/components/Modal/Modal.props.ts +1 -0
  105. package/src/components/Modal/Modal.stories.tsx +46 -0
  106. package/src/components/Modal/Modal.tsx +37 -33
  107. package/src/components/Modal/Modal.web.tsx +27 -27
  108. package/src/components/Radio/RadioGroup.stories.tsx +18 -0
  109. package/src/components/RadioCard/RadioCardGroup.context.ts +16 -0
  110. package/src/components/RadioCard/RadioCardGroup.stories.tsx +24 -0
  111. package/src/components/RadioCard/RadioCardGroup.tsx +28 -19
  112. package/src/components/RadioCard/RadioCardLabel.tsx +12 -1
  113. package/src/components/RadioCard/RadioCardRoot.tsx +15 -0
  114. package/src/components/index.ts +1 -0
  115. package/src/core/themes.ts +20 -0
  116. package/src/tokens/components/dark/index.ts +3 -1
  117. package/src/tokens/components/dark/input.ts +3 -0
  118. package/src/tokens/components/dark/modal.ts +7 -4
  119. package/src/tokens/components/dark/rating.ts +8 -0
  120. package/src/tokens/components/dark/table.ts +0 -3
  121. package/src/tokens/components/dark/time-picker.ts +29 -0
  122. package/src/tokens/components/dark/timeline.ts +27 -0
  123. package/src/tokens/components/light/index.ts +3 -1
  124. package/src/tokens/components/light/input.ts +3 -0
  125. package/src/tokens/components/light/modal.ts +7 -4
  126. package/src/tokens/components/light/rating.ts +8 -0
  127. package/src/tokens/components/light/table.ts +0 -3
  128. package/src/tokens/components/light/time-picker.ts +29 -0
  129. package/src/tokens/components/light/timeline.ts +27 -0
  130. package/build/tokens/components/dark/dialog.d.ts +0 -25
  131. package/build/tokens/components/dark/dialog.js +0 -24
  132. package/build/tokens/components/light/dialog.d.ts +0 -25
  133. package/build/tokens/components/light/dialog.js +0 -24
  134. package/src/tokens/components/dark/dialog.ts +0 -25
  135. package/src/tokens/components/light/dialog.ts +0 -25
@@ -1,6 +1,7 @@
1
1
  import type { ComponentType, ReactElement } from 'react';
2
- import type { ImageSourcePropType } from 'react-native';
2
+ import { ImageProps } from 'react-native';
3
3
  import type CardProps from '../Card/Card.props';
4
+ import { ThemedImageProps } from '../ThemedImage';
4
5
 
5
6
  export type BannerDirection = 'horizontal' | 'vertical';
6
7
 
@@ -50,18 +51,12 @@ export interface BannerProps
50
51
  * Illustration to display in the banner
51
52
  * Mutually exclusive with icon and image
52
53
  */
53
- illustration?: {
54
- light: ImageSourcePropType | ReactElement | ComponentType;
55
- dark: ImageSourcePropType | ReactElement | ComponentType;
56
- };
54
+ illustration?: ThemedImageProps | ImageProps;
57
55
  /**
58
56
  * Image to display in the banner
59
57
  * Mutually exclusive with icon and illustration
60
58
  */
61
- image?: {
62
- light: ImageSourcePropType | ReactElement | ComponentType;
63
- dark: ImageSourcePropType | ReactElement | ComponentType;
64
- };
59
+ image?: ThemedImageProps | ImageProps;
65
60
  /**
66
61
  * Heading text
67
62
  */
@@ -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,16 +324,15 @@ export const VerticalLayout: Story = {
310
324
  direction="vertical"
311
325
  />
312
326
  <Banner
327
+ variant="emphasis"
313
328
  image={{
314
- light: {
315
- uri: 'https://images.unsplash.com/photo-1506126613408-eca07ce68773?w=200&q=80',
316
- },
317
- dark: {
329
+ source: {
318
330
  uri: 'https://images.unsplash.com/photo-1506126613408-eca07ce68773?w=200&q=80',
319
331
  },
320
332
  }}
321
333
  heading="Featured Content"
322
334
  description="Discover amazing content curated just for you."
335
+ shadowColor="brand"
323
336
  direction="vertical"
324
337
  button={
325
338
  <Button size="sm" onPress={() => console.log('Learn More pressed')}>
@@ -1,14 +1,18 @@
1
1
  import { ChevronRightSmallIcon, CloseSmallIcon } from '@utilitywarehouse/hearth-react-native-icons';
2
- import { Pressable, View } from 'react-native';
2
+ import { Image, ImageProps, Pressable, View } from 'react-native';
3
3
  import { StyleSheet } from 'react-native-unistyles';
4
4
  import { BodyText } from '../BodyText';
5
5
  import { Card } from '../Card';
6
6
  import { Heading } from '../Heading';
7
7
  import { IconContainer } from '../IconContainer';
8
- import { ThemedImage } from '../ThemedImage';
8
+ import { ThemedImage, ThemedImageProps } from '../ThemedImage';
9
9
  import { UnstyledIconButton } from '../UnstyledIconButton';
10
10
  import type BannerProps from './Banner.props';
11
11
 
12
+ const isThemedImageProps = (props: ThemedImageProps | ImageProps): props is ThemedImageProps => {
13
+ return 'light' in props && 'dark' in props;
14
+ };
15
+
12
16
  const Banner = ({
13
17
  icon,
14
18
  iconContainerVariant = 'subtle',
@@ -44,26 +48,34 @@ const Banner = ({
44
48
  );
45
49
  }
46
50
  if (illustration) {
51
+ if (isThemedImageProps(illustration)) {
52
+ return (
53
+ <ThemedImage
54
+ {...illustration}
55
+ resizeMode="cover"
56
+ style={[styles.media, styles.imageWrapper, illustration.style]}
57
+ />
58
+ );
59
+ }
47
60
  return (
48
- <ThemedImage
49
- light={illustration.light}
50
- dark={illustration.dark}
51
- style={styles.image}
52
- accessible
53
- accessibilityLabel={heading}
61
+ <Image
62
+ {...illustration}
63
+ resizeMode="cover"
64
+ style={[styles.media, styles.imageWrapper, illustration.style]}
54
65
  />
55
66
  );
56
67
  }
57
68
  if (image) {
69
+ if (isThemedImageProps(image)) {
70
+ return (
71
+ <View style={[styles.media, styles.imageWrapper]}>
72
+ <ThemedImage {...image} style={[styles.image, image.style]} />
73
+ </View>
74
+ );
75
+ }
58
76
  return (
59
77
  <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
- />
78
+ <Image {...image} style={[styles.image, image.style]} />
67
79
  </View>
68
80
  );
69
81
  }
@@ -82,23 +94,36 @@ const Banner = ({
82
94
 
83
95
  const content = (
84
96
  <View style={styles.container}>
97
+ {onClose && direction === 'vertical' && (
98
+ <UnstyledIconButton
99
+ icon={CloseSmallIcon}
100
+ size="sm"
101
+ onPress={onClose}
102
+ style={styles.closeButton}
103
+ accessibilityLabel="Close banner"
104
+ />
105
+ )}
85
106
  {renderIconOrImage()}
107
+
86
108
  <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>
109
+ <View style={styles.contentTextContainer}>
110
+ <View style={styles.textContainer}>
111
+ <Heading
112
+ size="sm"
113
+ style={styles.heading}
114
+ textAlign={hasIllustration && direction === 'vertical' ? 'center' : 'left'}
115
+ >
116
+ {heading}
117
+ </Heading>
118
+ <BodyText
119
+ size="md"
120
+ style={styles.description}
121
+ textAlign={hasIllustration && direction === 'vertical' ? 'center' : 'left'}
122
+ >
123
+ {description}
124
+ </BodyText>
125
+ </View>
126
+
102
127
  {renderAction()}
103
128
  </View>
104
129
  {onPress && (
@@ -109,7 +134,7 @@ const Banner = ({
109
134
  style={styles.chevron}
110
135
  />
111
136
  )}
112
- {onClose && (
137
+ {onClose && direction === 'horizontal' && (
113
138
  <UnstyledIconButton
114
139
  icon={CloseSmallIcon}
115
140
  size="sm"
@@ -142,9 +167,9 @@ const Banner = ({
142
167
  Banner.displayName = 'Banner';
143
168
 
144
169
  const styles = StyleSheet.create(theme => ({
145
- card: {},
170
+ card: { flexDirection: 'row', _web: { flexDirection: 'column' } },
146
171
  pressable: {
147
- width: '100%',
172
+ flex: 1,
148
173
  },
149
174
  container: {
150
175
  flexDirection: 'row',
@@ -194,6 +219,7 @@ const styles = StyleSheet.create(theme => ({
194
219
  },
195
220
  },
196
221
  imageWrapper: {
222
+ flexDirection: 'row',
197
223
  variants: {
198
224
  direction: {
199
225
  horizontal: {},
@@ -205,8 +231,8 @@ const styles = StyleSheet.create(theme => ({
205
231
  },
206
232
  image: {
207
233
  borderRadius: theme.borderRadius.md,
208
- borderWidth: theme.borderWidth[1],
209
234
  borderColor: theme.color.border.strong,
235
+ borderWidth: theme.borderWidth[1],
210
236
  variants: {
211
237
  direction: {
212
238
  horizontal: { width: 160, height: 95 },
@@ -218,15 +244,34 @@ const styles = StyleSheet.create(theme => ({
218
244
  },
219
245
  },
220
246
  contentContainer: {
221
- flex: 1,
222
- flexDirection: 'row',
223
247
  alignItems: 'flex-start',
224
248
  justifyContent: 'space-between',
225
249
  gap: theme.space.lg,
250
+ variants: {
251
+ direction: {
252
+ horizontal: {
253
+ flex: 1,
254
+ flexDirection: 'row',
255
+ },
256
+ vertical: {
257
+ flexDirection: 'column',
258
+ },
259
+ },
260
+ },
226
261
  },
227
262
  textContainer: {
228
- flex: 1,
263
+ gap: theme.space.sm,
264
+ },
265
+ contentTextContainer: {
229
266
  gap: theme.space.lg,
267
+ variants: {
268
+ direction: {
269
+ horizontal: {
270
+ flex: 1,
271
+ },
272
+ vertical: {},
273
+ },
274
+ },
230
275
  },
231
276
  heading: {
232
277
  compoundVariants: [
@@ -258,6 +303,16 @@ const styles = StyleSheet.create(theme => ({
258
303
  },
259
304
  closeButton: {
260
305
  alignSelf: 'flex-start',
306
+ variants: {
307
+ direction: {
308
+ vertical: {
309
+ position: 'absolute',
310
+ top: 0,
311
+ right: 0,
312
+ },
313
+ horizontal: {},
314
+ },
315
+ },
261
316
  },
262
317
  }));
263
318
 
@@ -1,10 +1,18 @@
1
1
  import { BottomSheetHandle as Handle } from '@gorhom/bottom-sheet';
2
2
  import { BottomSheetDefaultHandleProps } from '@gorhom/bottom-sheet/lib/typescript/components/bottomSheetHandle/types';
3
+ import { Platform, View } from 'react-native';
3
4
  import { StyleSheet, withUnistyles } from 'react-native-unistyles';
4
5
 
5
6
  const StyledBottomSheetHandle = withUnistyles(Handle);
6
7
 
7
8
  const BottomSheetHandle = ({ style, indicatorStyle, ...props }: BottomSheetDefaultHandleProps) => {
9
+ if (Platform.OS === 'web') {
10
+ return (
11
+ <View style={[styles.handle, style]}>
12
+ <View style={[styles.indicator, indicatorStyle]} />
13
+ </View>
14
+ );
15
+ }
8
16
  return (
9
17
  <StyledBottomSheetHandle
10
18
  style={[styles.handle, style]}
@@ -22,6 +30,10 @@ const styles = StyleSheet.create(theme => ({
22
30
  paddingTop: theme.components.bottomSheet.padding,
23
31
  paddingHorizontal: theme.components.bottomSheet.padding,
24
32
  paddingBottom: theme.components.bottomSheet.gap,
33
+ _web: {
34
+ alignItems: 'center',
35
+ cursor: 'grab',
36
+ },
25
37
  },
26
38
  indicator: {
27
39
  width: theme.components.bottomSheet.handle.width,
@@ -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
+ };
@@ -232,6 +232,6 @@ Selection through the calendar always returns a JavaScript `Date` that is reform
232
232
  ### Best practices
233
233
 
234
234
  - Always pair with `FormField` for proper label, helper text, and error message announcements.
235
- - Use `openButtonLabel` to customize the calendar button announcement if the default doesn't fit your use case.
235
+ - Use `openButtonLabel` to customise the calendar button announcement if the default doesn't fit your use case.
236
236
  - Provide clear validation feedback through `FormField` when manual date entry doesn't match the expected format.
237
237
  - Test with VoiceOver and TalkBack to ensure the date entry flow works smoothly in your specific context.
@@ -79,7 +79,7 @@ const MyComponent = () => (
79
79
  | button | `ReactElement` | Optional Button component displayed below description | `-` |
80
80
  | variant | `'emphasis' \| 'subtle'` | Visual style variant with strong or subtle borders | `'emphasis'` |
81
81
 
82
- 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`.
83
83
 
84
84
  ## Variants
85
85
 
@@ -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',
@@ -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
 
@@ -0,0 +1,15 @@
1
+ import { createContext, useContext } from 'react';
2
+
3
+ export interface IMenuContext {
4
+ close: () => void;
5
+ }
6
+
7
+ export const MenuContext = createContext<IMenuContext | undefined>(undefined);
8
+
9
+ export const useMenuContext = () => {
10
+ const context = useContext(MenuContext);
11
+ if (!context) {
12
+ throw new Error('useMenuContext must be used within a Menu component');
13
+ }
14
+ return context;
15
+ };