@utilitywarehouse/hearth-react-native 0.8.2 → 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.
Files changed (157) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-lint.log +1 -1
  3. package/CHANGELOG.md +16 -0
  4. package/build/components/Banner/Banner.js +25 -6
  5. package/build/components/Banner/Banner.props.d.ts +2 -2
  6. package/build/components/BottomSheet/BottomSheetHandle.js +8 -0
  7. package/build/components/Menu/Menu.context.d.ts +5 -0
  8. package/build/components/Menu/Menu.context.js +9 -0
  9. package/build/components/Menu/Menu.d.ts +4 -0
  10. package/build/components/Menu/Menu.js +25 -0
  11. package/build/components/Menu/Menu.props.d.ts +21 -0
  12. package/build/components/Menu/Menu.props.js +1 -0
  13. package/build/components/Menu/MenuItem.d.ts +18 -0
  14. package/build/components/Menu/MenuItem.js +115 -0
  15. package/build/components/Menu/MenuItem.props.d.ts +27 -0
  16. package/build/components/Menu/MenuItem.props.js +1 -0
  17. package/build/components/Menu/MenuTrigger.d.ts +9 -0
  18. package/build/components/Menu/MenuTrigger.js +11 -0
  19. package/build/components/Menu/MenuTrigger.props.d.ts +12 -0
  20. package/build/components/Menu/MenuTrigger.props.js +1 -0
  21. package/build/components/Menu/index.d.ts +7 -0
  22. package/build/components/Menu/index.js +4 -0
  23. package/build/components/Modal/Modal.d.ts +1 -1
  24. package/build/components/Modal/Modal.js +32 -30
  25. package/build/components/Modal/Modal.props.d.ts +1 -0
  26. package/build/components/Modal/Modal.web.d.ts +1 -1
  27. package/build/components/Modal/Modal.web.js +25 -25
  28. package/build/components/PillGroup/Pill.d.ts +16 -0
  29. package/build/components/PillGroup/Pill.js +94 -0
  30. package/build/components/PillGroup/Pill.props.d.ts +10 -0
  31. package/build/components/PillGroup/Pill.props.js +1 -0
  32. package/build/components/PillGroup/PillGroup.context.d.ts +6 -0
  33. package/build/components/PillGroup/PillGroup.context.js +5 -0
  34. package/build/components/PillGroup/PillGroup.d.ts +5 -0
  35. package/build/components/PillGroup/PillGroup.js +34 -0
  36. package/build/components/PillGroup/PillGroup.props.d.ts +15 -0
  37. package/build/components/PillGroup/PillGroup.props.js +1 -0
  38. package/build/components/PillGroup/index.d.ts +4 -0
  39. package/build/components/PillGroup/index.js +2 -0
  40. package/build/components/Select/Select.js +2 -1
  41. package/build/components/Toast/Toast.context.d.ts +9 -0
  42. package/build/components/Toast/Toast.context.js +90 -0
  43. package/build/components/Toast/Toast.props.d.ts +29 -0
  44. package/build/components/Toast/Toast.props.js +1 -0
  45. package/build/components/Toast/ToastItem.d.ts +10 -0
  46. package/build/components/Toast/ToastItem.js +129 -0
  47. package/build/components/Toast/index.d.ts +3 -0
  48. package/build/components/Toast/index.js +2 -0
  49. package/build/components/index.d.ts +3 -0
  50. package/build/components/index.js +3 -0
  51. package/build/tokens/components/dark/checkbox.d.ts +3 -0
  52. package/build/tokens/components/dark/checkbox.js +3 -0
  53. package/build/tokens/components/dark/index.d.ts +3 -1
  54. package/build/tokens/components/dark/index.js +3 -1
  55. package/build/tokens/components/dark/input.d.ts +9 -0
  56. package/build/tokens/components/dark/input.js +9 -0
  57. package/build/tokens/components/dark/modal.d.ts +7 -4
  58. package/build/tokens/components/dark/modal.js +7 -4
  59. package/build/tokens/components/dark/radio.d.ts +3 -0
  60. package/build/tokens/components/dark/radio.js +3 -0
  61. package/build/tokens/components/dark/rating.d.ts +8 -0
  62. package/build/tokens/components/dark/rating.js +7 -0
  63. package/build/tokens/components/dark/table.d.ts +2 -3
  64. package/build/tokens/components/dark/table.js +2 -3
  65. package/build/tokens/components/dark/time-picker.d.ts +29 -0
  66. package/build/tokens/components/dark/time-picker.js +28 -0
  67. package/build/tokens/components/dark/timeline.d.ts +27 -0
  68. package/build/tokens/components/dark/timeline.js +26 -0
  69. package/build/tokens/components/dark/toast.d.ts +6 -2
  70. package/build/tokens/components/dark/toast.js +6 -2
  71. package/build/tokens/components/light/checkbox.d.ts +3 -0
  72. package/build/tokens/components/light/checkbox.js +3 -0
  73. package/build/tokens/components/light/index.d.ts +3 -1
  74. package/build/tokens/components/light/index.js +3 -1
  75. package/build/tokens/components/light/input.d.ts +9 -0
  76. package/build/tokens/components/light/input.js +9 -0
  77. package/build/tokens/components/light/modal.d.ts +7 -4
  78. package/build/tokens/components/light/modal.js +7 -4
  79. package/build/tokens/components/light/radio.d.ts +3 -0
  80. package/build/tokens/components/light/radio.js +3 -0
  81. package/build/tokens/components/light/rating.d.ts +8 -0
  82. package/build/tokens/components/light/rating.js +7 -0
  83. package/build/tokens/components/light/table.d.ts +2 -3
  84. package/build/tokens/components/light/table.js +2 -3
  85. package/build/tokens/components/light/time-picker.d.ts +29 -0
  86. package/build/tokens/components/light/time-picker.js +28 -0
  87. package/build/tokens/components/light/timeline.d.ts +27 -0
  88. package/build/tokens/components/light/timeline.js +26 -0
  89. package/build/tokens/components/light/toast.d.ts +6 -2
  90. package/build/tokens/components/light/toast.js +6 -2
  91. package/docs/assets/toast-ios.MP4 +0 -0
  92. package/docs/components/AllComponents.web.tsx +59 -0
  93. package/docs/components/BackToTopButton.tsx +1 -1
  94. package/package.json +4 -4
  95. package/src/components/Banner/Banner.docs.mdx +19 -10
  96. package/src/components/Banner/Banner.props.ts +2 -2
  97. package/src/components/Banner/Banner.stories.tsx +1 -4
  98. package/src/components/Banner/Banner.tsx +47 -7
  99. package/src/components/BottomSheet/BottomSheetHandle.tsx +12 -0
  100. package/src/components/DatePickerInput/DatePickerInput.docs.mdx +1 -1
  101. package/src/components/Menu/Menu.context.ts +15 -0
  102. package/src/components/Menu/Menu.docs.mdx +158 -0
  103. package/src/components/Menu/Menu.props.ts +24 -0
  104. package/src/components/Menu/Menu.stories.tsx +292 -0
  105. package/src/components/Menu/Menu.tsx +54 -0
  106. package/src/components/Menu/MenuItem.props.ts +29 -0
  107. package/src/components/Menu/MenuItem.tsx +145 -0
  108. package/src/components/Menu/MenuTrigger.props.ts +14 -0
  109. package/src/components/Menu/MenuTrigger.tsx +20 -0
  110. package/src/components/Menu/index.ts +7 -0
  111. package/src/components/Modal/Modal.docs.mdx +34 -5
  112. package/src/components/Modal/Modal.props.ts +1 -0
  113. package/src/components/Modal/Modal.stories.tsx +46 -0
  114. package/src/components/Modal/Modal.tsx +37 -33
  115. package/src/components/Modal/Modal.web.tsx +27 -27
  116. package/src/components/PillGroup/Pill.props.ts +13 -0
  117. package/src/components/PillGroup/Pill.tsx +120 -0
  118. package/src/components/PillGroup/PillGroup.context.tsx +12 -0
  119. package/src/components/PillGroup/PillGroup.docs.mdx +96 -0
  120. package/src/components/PillGroup/PillGroup.props.ts +22 -0
  121. package/src/components/PillGroup/PillGroup.stories.tsx +159 -0
  122. package/src/components/PillGroup/PillGroup.tsx +66 -0
  123. package/src/components/PillGroup/index.ts +4 -0
  124. package/src/components/Select/Select.tsx +2 -0
  125. package/src/components/Toast/Toast.context.tsx +118 -0
  126. package/src/components/Toast/Toast.docs.mdx +164 -0
  127. package/src/components/Toast/Toast.props.ts +33 -0
  128. package/src/components/Toast/Toast.stories.tsx +356 -0
  129. package/src/components/Toast/ToastItem.tsx +200 -0
  130. package/src/components/Toast/index.ts +3 -0
  131. package/src/components/index.ts +3 -0
  132. package/src/tokens/components/dark/checkbox.ts +3 -0
  133. package/src/tokens/components/dark/index.ts +3 -1
  134. package/src/tokens/components/dark/input.ts +9 -0
  135. package/src/tokens/components/dark/modal.ts +7 -4
  136. package/src/tokens/components/dark/radio.ts +3 -0
  137. package/src/tokens/components/dark/rating.ts +8 -0
  138. package/src/tokens/components/dark/table.ts +2 -3
  139. package/src/tokens/components/dark/time-picker.ts +29 -0
  140. package/src/tokens/components/dark/timeline.ts +27 -0
  141. package/src/tokens/components/dark/toast.ts +6 -2
  142. package/src/tokens/components/light/checkbox.ts +3 -0
  143. package/src/tokens/components/light/index.ts +3 -1
  144. package/src/tokens/components/light/input.ts +9 -0
  145. package/src/tokens/components/light/modal.ts +7 -4
  146. package/src/tokens/components/light/radio.ts +3 -0
  147. package/src/tokens/components/light/rating.ts +8 -0
  148. package/src/tokens/components/light/table.ts +2 -3
  149. package/src/tokens/components/light/time-picker.ts +29 -0
  150. package/src/tokens/components/light/timeline.ts +27 -0
  151. package/src/tokens/components/light/toast.ts +6 -2
  152. package/build/tokens/components/dark/dialog.d.ts +0 -25
  153. package/build/tokens/components/dark/dialog.js +0 -24
  154. package/build/tokens/components/light/dialog.d.ts +0 -25
  155. package/build/tokens/components/light/dialog.js +0 -24
  156. package/src/tokens/components/dark/dialog.ts +0 -25
  157. package/src/tokens/components/light/dialog.ts +0 -25
@@ -5,6 +5,7 @@ export default {
5
5
  borderRadius: 16,
6
6
  cell: {
7
7
  borderWidth: 1,
8
+ minHeight: 48,
8
9
  padding: 12,
9
10
  },
10
11
  emphasis: {
@@ -13,9 +14,7 @@ export default {
13
14
  headerCell: {
14
15
  borderWidth: 2,
15
16
  gap: 8,
16
- neutral: {
17
- backgroundColor: '#f1efe4',
18
- },
17
+ height: 56,
19
18
  paddingHorizontal: 12,
20
19
  paddingVertical: 16,
21
20
  },
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Do not edit directly, this file was auto-generated.
3
+ */
4
+ declare const _default: {
5
+ readonly gap: 6;
6
+ readonly gapContainer: 4;
7
+ readonly minWidth: 288;
8
+ readonly paddingHorizontal: 16;
9
+ readonly paddingVertical: 12;
10
+ readonly time: {
11
+ readonly columnGap: 4;
12
+ readonly content: {
13
+ readonly gap: 8;
14
+ readonly item: {
15
+ readonly gap: 2;
16
+ };
17
+ };
18
+ readonly footer: {
19
+ readonly gap: 8;
20
+ };
21
+ readonly gap: 16;
22
+ readonly item: {
23
+ readonly height: 40;
24
+ readonly width: 64;
25
+ };
26
+ readonly rowGap: 2;
27
+ };
28
+ };
29
+ export default _default;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Do not edit directly, this file was auto-generated.
3
+ */
4
+ export default {
5
+ gap: 6,
6
+ gapContainer: 4,
7
+ minWidth: 288,
8
+ paddingHorizontal: 16,
9
+ paddingVertical: 12,
10
+ time: {
11
+ columnGap: 4,
12
+ content: {
13
+ gap: 8,
14
+ item: {
15
+ gap: 2,
16
+ },
17
+ },
18
+ footer: {
19
+ gap: 8,
20
+ },
21
+ gap: 16,
22
+ item: {
23
+ height: 40,
24
+ width: 64,
25
+ },
26
+ rowGap: 2,
27
+ },
28
+ };
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Do not edit directly, this file was auto-generated.
3
+ */
4
+ declare const _default: {
5
+ readonly bar: {
6
+ readonly width: 2;
7
+ };
8
+ readonly content: {
9
+ readonly gap: 8;
10
+ readonly paddingBottom: 24;
11
+ readonly paddingTop: 2;
12
+ };
13
+ readonly gap: 12;
14
+ readonly progress: {
15
+ readonly circle: {
16
+ readonly height: 28;
17
+ readonly width: 28;
18
+ };
19
+ };
20
+ readonly static: {
21
+ readonly circle: {
22
+ readonly height: 12;
23
+ readonly width: 12;
24
+ };
25
+ };
26
+ };
27
+ export default _default;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Do not edit directly, this file was auto-generated.
3
+ */
4
+ export default {
5
+ bar: {
6
+ width: 2,
7
+ },
8
+ content: {
9
+ gap: 8,
10
+ paddingBottom: 24,
11
+ paddingTop: 2,
12
+ },
13
+ gap: 12,
14
+ progress: {
15
+ circle: {
16
+ height: 28,
17
+ width: 28,
18
+ },
19
+ },
20
+ static: {
21
+ circle: {
22
+ height: 12,
23
+ width: 12,
24
+ },
25
+ },
26
+ };
@@ -4,10 +4,14 @@
4
4
  declare const _default: {
5
5
  readonly backgroundColor: "#101010";
6
6
  readonly borderRadius: 8;
7
- readonly gapHorizontal: 16;
7
+ readonly bottomPosition: 32;
8
+ readonly gap: 16;
8
9
  readonly padding: 14;
9
10
  readonly stack: {
10
- readonly gapHorizontal: 8;
11
+ readonly gap: 12;
12
+ };
13
+ readonly text: {
14
+ readonly gap: 8;
11
15
  };
12
16
  };
13
17
  export default _default;
@@ -4,9 +4,13 @@
4
4
  export default {
5
5
  backgroundColor: '#101010',
6
6
  borderRadius: 8,
7
- gapHorizontal: 16,
7
+ bottomPosition: 32,
8
+ gap: 16,
8
9
  padding: 14,
9
10
  stack: {
10
- gapHorizontal: 8,
11
+ gap: 12,
12
+ },
13
+ text: {
14
+ gap: 8,
11
15
  },
12
16
  };
Binary file
@@ -6,9 +6,12 @@ import {
6
6
  BroadbandMediumIcon,
7
7
  CashbackCardMediumIcon,
8
8
  ChevronRightMediumIcon,
9
+ EditSmallIcon,
9
10
  ElectricityMediumIcon,
10
11
  InsuranceMediumIcon,
11
12
  MobileMediumIcon,
13
+ ShareSmallIcon,
14
+ TrashSmallIcon,
12
15
  } from '@utilitywarehouse/hearth-react-native-icons';
13
16
  // @ts-ignore
14
17
  import SpotBillingDark from '@utilitywarehouse/hearth-svg-assets/lib/spot-billing-dark.svg';
@@ -60,8 +63,13 @@ import {
60
63
  Link,
61
64
  List,
62
65
  ListItem,
66
+ Menu,
67
+ MenuItem,
68
+ MenuTrigger,
63
69
  Modal,
64
70
  OL,
71
+ Pill,
72
+ PillGroup,
65
73
  ProgressStep,
66
74
  ProgressStepper,
67
75
  Radio,
@@ -79,6 +87,7 @@ import {
79
87
  TabsList,
80
88
  Textarea,
81
89
  ThemedImage,
90
+ ToastItem,
82
91
  ToggleButtonCard,
83
92
  ToggleButtonCardGroup,
84
93
  UL,
@@ -159,6 +168,10 @@ const AllComponents: React.FC = () => {
159
168
  }, [datePickerRef]);
160
169
  const [switchEnabled, setSwitchEnabled] = React.useState(false);
161
170
  const toggleSwitch = () => setSwitchEnabled(!switchEnabled);
171
+ const menuRef = useRef<any>(null);
172
+ const handleMenuOpenPress = useCallback(() => {
173
+ menuRef.current?.present();
174
+ }, []);
162
175
 
163
176
  const [colorMode] = useColorMode();
164
177
  const isDark = colorMode === 'dark';
@@ -564,6 +577,29 @@ const AllComponents: React.FC = () => {
564
577
  </List>
565
578
  </Center>
566
579
  </ComponentWrapper>
580
+ <ComponentWrapper name="Menu" link="/?path=/docs/components-menu--docs">
581
+ <Center flex={1}>
582
+ <BottomSheetModalProvider>
583
+ <MenuTrigger onPress={handleMenuOpenPress}>
584
+ <Button>Open Menu</Button>
585
+ </MenuTrigger>
586
+ <Menu ref={menuRef} heading="Actions">
587
+ <MenuItem icon={EditSmallIcon} text="Edit" onPress={() => console.log('Edit')} />
588
+ <MenuItem
589
+ icon={ShareSmallIcon}
590
+ text="Share"
591
+ onPress={() => console.log('Share')}
592
+ />
593
+ <MenuItem
594
+ icon={TrashSmallIcon}
595
+ text="Delete"
596
+ colorScheme="destructive"
597
+ onPress={() => console.log('Delete')}
598
+ />
599
+ </Menu>
600
+ </BottomSheetModalProvider>
601
+ </Center>
602
+ </ComponentWrapper>
567
603
  <ComponentWrapper name="Modal" link="/?path=/docs/components-modal--docs">
568
604
  <Center flex={1}>
569
605
  <Button onPress={handleModalOpenPress}>Open Modal</Button>
@@ -594,6 +630,21 @@ const AllComponents: React.FC = () => {
594
630
  </OL>
595
631
  </Center>
596
632
  </ComponentWrapper>
633
+ <ComponentWrapper name="Pill Group" link="/?path=/docs/components-pill-group--docs">
634
+ <Center flex={1} p="200">
635
+ {(() => {
636
+ const [pillValue, setPillValue] = React.useState<string[]>(['energy', 'mobile']);
637
+ return (
638
+ <PillGroup value={pillValue} onChange={v => setPillValue(v as string[])} wrap={false} multiple>
639
+ <Pill value="all" label="All" />
640
+ <Pill value="energy" label="Energy" icon={ElectricityMediumIcon} />
641
+ <Pill value="broadband" label="Broadband" icon={BroadbandMediumIcon} />
642
+ <Pill value="mobile" label="Mobile" icon={MobileMediumIcon} />
643
+ </PillGroup>
644
+ );
645
+ })()}
646
+ </Center>
647
+ </ComponentWrapper>
597
648
  <ComponentWrapper
598
649
  name="Progress Stepper"
599
650
  link="/?path=/docs/components-progress-stepper--docs"
@@ -712,6 +763,14 @@ const AllComponents: React.FC = () => {
712
763
  />
713
764
  </Center>
714
765
  </ComponentWrapper>
766
+ <ComponentWrapper name="Toast" link="/?path=/docs/components-toast--docs">
767
+ <Center flex={1} p="200">
768
+ <ToastItem
769
+ onClose={() => {}}
770
+ toast={{ id: 'tst', text: "I'm a toast", duration: 0 }}
771
+ />
772
+ </Center>
773
+ </ComponentWrapper>
715
774
  <ComponentWrapper
716
775
  name="Toggle Button Card"
717
776
  link="/?path=/docs/components-toggle-button-card--docs"
@@ -29,7 +29,7 @@ const ScrollButton = () => {
29
29
  <Button
30
30
  onPress={scrollToTop}
31
31
  variant="ghost"
32
- colorScheme="grey"
32
+ colorScheme="functional"
33
33
  size="sm"
34
34
  // @ts-expect-error - This is a playground
35
35
  style={{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@utilitywarehouse/hearth-react-native",
3
- "version": "0.8.2",
3
+ "version": "0.10.0",
4
4
  "description": "Utility Warehouse React Native UI library",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -57,10 +57,10 @@
57
57
  "vite-plugin-svgr": "^4.5.0",
58
58
  "vitest": "^3.2.4",
59
59
  "@utilitywarehouse/hearth-fonts": "^0.0.4",
60
- "@utilitywarehouse/hearth-react-icons": "^0.7.3",
61
- "@utilitywarehouse/hearth-react-native-icons": "^0.7.3",
60
+ "@utilitywarehouse/hearth-react-icons": "^0.7.4",
61
+ "@utilitywarehouse/hearth-react-native-icons": "^0.7.4",
62
62
  "@utilitywarehouse/hearth-svg-assets": "^0.2.0",
63
- "@utilitywarehouse/hearth-tokens": "^0.1.3"
63
+ "@utilitywarehouse/hearth-tokens": "^0.2.0"
64
64
  },
65
65
  "peerDependencies": {
66
66
  "@gorhom/bottom-sheet": "^5.0.0",
@@ -69,8 +69,8 @@ const MyComponent = () => (
69
69
  | iconContainerVariant | `'subtle' \| 'emphasis'` | Icon container visual style | `'subtle'` |
70
70
  | iconContainerSize | `'sm' \| 'md' \| 'lg'` | Icon container size | `'md'` |
71
71
  | iconContainerColor | `'pig' \| 'energy' \| 'broadband' \| 'mobile' \|` <br />`'insurance' \| 'cashback' \| 'highlight'` | Icon container color scheme | `'pig'` |
72
- | illustration | `{ light: ImageSource, dark: ImageSource }` | Themed illustration object (mutually exclusive with icon/image) | `-` |
73
- | image | `{ light: ImageSource, dark: ImageSource }` | Themed image object (mutually exclusive with icon/illustration) | `-` |
72
+ | illustration | `ThemedImageProps \| ImageProps` | Themed illustration object (mutually exclusive with icon/image) | `-` |
73
+ | image | `ThemedImageProps \| ImageProps` | Themed image object (mutually exclusive with icon/illustration) | `-` |
74
74
  | heading | `string` | Heading text | `-` (required) |
75
75
  | description | `string` | Description text | `-` (required) |
76
76
  | direction | `'horizontal' \| 'vertical'` | Layout direction for icon/image and content | `'horizontal'` |
@@ -156,14 +156,23 @@ Display a themed image that automatically switches between light and dark modes:
156
156
  import { Banner } from '@utilitywarehouse/hearth-react-native';
157
157
 
158
158
  const MyComponent = () => (
159
- <Banner
160
- image={{
161
- light: { uri: 'https://example.com/light-image.jpg' },
162
- dark: { uri: 'https://example.com/dark-image.jpg' },
163
- }}
164
- heading="Featured Content"
165
- description="Discover amazing content curated just for you."
166
- />
159
+ <>
160
+ <Banner
161
+ image={{
162
+ source: { uri: 'https://example.com/image.jpg' },
163
+ }}
164
+ heading="Featured Content"
165
+ description="Discover amazing content curated just for you."
166
+ />
167
+ <Banner
168
+ image={{
169
+ light: { uri: 'https://example.com/light-image.jpg' },
170
+ dark: { uri: 'https://example.com/dark-image.jpg' },
171
+ }}
172
+ heading="Featured Content"
173
+ description="Discover amazing content curated just for you."
174
+ />
175
+ </>
167
176
  );
168
177
  ```
169
178
 
@@ -51,12 +51,12 @@ export interface BannerProps
51
51
  * Illustration to display in the banner
52
52
  * Mutually exclusive with icon and image
53
53
  */
54
- illustration?: ThemedImageProps & ImageProps;
54
+ illustration?: ThemedImageProps | ImageProps;
55
55
  /**
56
56
  * Image to display in the banner
57
57
  * Mutually exclusive with icon and illustration
58
58
  */
59
- image?: ThemedImageProps & ImageProps;
59
+ image?: ThemedImageProps | ImageProps;
60
60
  /**
61
61
  * Heading text
62
62
  */
@@ -326,10 +326,7 @@ export const VerticalLayout: Story = {
326
326
  <Banner
327
327
  variant="emphasis"
328
328
  image={{
329
- light: {
330
- uri: 'https://images.unsplash.com/photo-1506126613408-eca07ce68773?w=200&q=80',
331
- },
332
- dark: {
329
+ source: {
333
330
  uri: 'https://images.unsplash.com/photo-1506126613408-eca07ce68773?w=200&q=80',
334
331
  },
335
332
  }}
@@ -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,8 +48,17 @@ 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
61
+ <Image
49
62
  {...illustration}
50
63
  resizeMode="cover"
51
64
  style={[styles.media, styles.imageWrapper, illustration.style]}
@@ -53,9 +66,16 @@ const Banner = ({
53
66
  );
54
67
  }
55
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
+ }
56
76
  return (
57
77
  <View style={[styles.media, styles.imageWrapper]}>
58
- <ThemedImage {...image} style={[styles.image, image.style]} />
78
+ <Image {...image} style={[styles.image, image.style]} />
59
79
  </View>
60
80
  );
61
81
  }
@@ -74,7 +94,17 @@ const Banner = ({
74
94
 
75
95
  const content = (
76
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
+ )}
77
106
  {renderIconOrImage()}
107
+
78
108
  <View style={styles.contentContainer}>
79
109
  <View style={styles.contentTextContainer}>
80
110
  <View style={styles.textContainer}>
@@ -104,7 +134,7 @@ const Banner = ({
104
134
  style={styles.chevron}
105
135
  />
106
136
  )}
107
- {onClose && (
137
+ {onClose && direction === 'horizontal' && (
108
138
  <UnstyledIconButton
109
139
  icon={CloseSmallIcon}
110
140
  size="sm"
@@ -137,9 +167,9 @@ const Banner = ({
137
167
  Banner.displayName = 'Banner';
138
168
 
139
169
  const styles = StyleSheet.create(theme => ({
140
- card: {},
170
+ card: { flexDirection: 'row', _web: { flexDirection: 'column' } },
141
171
  pressable: {
142
- width: '100%',
172
+ flex: 1,
143
173
  },
144
174
  container: {
145
175
  flexDirection: 'row',
@@ -273,6 +303,16 @@ const styles = StyleSheet.create(theme => ({
273
303
  },
274
304
  closeButton: {
275
305
  alignSelf: 'flex-start',
306
+ variants: {
307
+ direction: {
308
+ vertical: {
309
+ position: 'absolute',
310
+ top: 0,
311
+ right: 0,
312
+ },
313
+ horizontal: {},
314
+ },
315
+ },
276
316
  },
277
317
  }));
278
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,
@@ -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.
@@ -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
+ };