@utilitywarehouse/hearth-react-native 0.31.1 → 0.32.1

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 (87) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-lint.log +15 -18
  3. package/CHANGELOG.md +62 -0
  4. package/build/components/Card/Card.props.d.ts +1 -1
  5. package/build/components/Card/CardRoot.js +19 -0
  6. package/build/components/Input/Input.js +13 -31
  7. package/build/components/Rating/Rating.d.ts +6 -0
  8. package/build/components/Rating/Rating.js +76 -0
  9. package/build/components/Rating/Rating.props.d.ts +18 -0
  10. package/build/components/Rating/Rating.props.js +1 -0
  11. package/build/components/Rating/RatingStarEmpty.d.ts +6 -0
  12. package/build/components/Rating/RatingStarEmpty.js +9 -0
  13. package/build/components/Rating/RatingStarFilled.d.ts +6 -0
  14. package/build/components/Rating/RatingStarFilled.js +9 -0
  15. package/build/components/Rating/index.d.ts +2 -0
  16. package/build/components/Rating/index.js +1 -0
  17. package/build/components/Roundel/Roundel.d.ts +6 -0
  18. package/build/components/Roundel/Roundel.js +40 -0
  19. package/build/components/Roundel/Roundel.props.d.ts +6 -0
  20. package/build/components/Roundel/Roundel.props.js +1 -0
  21. package/build/components/Roundel/index.d.ts +2 -0
  22. package/build/components/Roundel/index.js +1 -0
  23. package/build/components/StepperInput/StepperButton.d.ts +22 -0
  24. package/build/components/StepperInput/StepperButton.js +55 -0
  25. package/build/components/StepperInput/StepperInput.d.ts +6 -0
  26. package/build/components/StepperInput/StepperInput.js +179 -0
  27. package/build/components/StepperInput/StepperInput.props.d.ts +31 -0
  28. package/build/components/StepperInput/StepperInput.props.js +1 -0
  29. package/build/components/StepperInput/index.d.ts +2 -0
  30. package/build/components/StepperInput/index.js +1 -0
  31. package/build/components/Textarea/Textarea.d.ts +1 -1
  32. package/build/components/Textarea/Textarea.js +21 -32
  33. package/build/components/Textarea/Textarea.props.d.ts +11 -0
  34. package/build/components/VerificationInput/VerificationInput.js +12 -22
  35. package/build/components/index.d.ts +3 -0
  36. package/build/components/index.js +3 -0
  37. package/build/hooks/index.d.ts +1 -0
  38. package/build/hooks/index.js +1 -0
  39. package/build/hooks/useFormFieldAccessibility.d.ts +17 -0
  40. package/build/hooks/useFormFieldAccessibility.js +32 -0
  41. package/build/hooks/useFormFieldAccessibility.test.d.ts +1 -0
  42. package/build/hooks/useFormFieldAccessibility.test.js +56 -0
  43. package/docs/adding-shadows.mdx +2 -2
  44. package/docs/changelog.mdx +16 -0
  45. package/docs/components/AllComponents.web.tsx +30 -1
  46. package/docs/dark-mode-best-practice.mdx +328 -0
  47. package/package.json +6 -4
  48. package/src/components/Banner/Banner.stories.tsx +14 -0
  49. package/src/components/Card/Card.docs.mdx +16 -17
  50. package/src/components/Card/Card.props.ts +1 -0
  51. package/src/components/Card/Card.stories.tsx +35 -21
  52. package/src/components/Card/CardRoot.tsx +19 -0
  53. package/src/components/Icon/Icon.docs.mdx +1 -1
  54. package/src/components/Input/Input.tsx +14 -35
  55. package/src/components/List/List.docs.mdx +4 -2
  56. package/src/components/Modal/Modal.docs.mdx +58 -4
  57. package/src/components/NavModal/NavModal.docs.mdx +2 -2
  58. package/src/components/Rating/Rating.docs.mdx +178 -0
  59. package/src/components/Rating/Rating.figma.tsx +20 -0
  60. package/src/components/Rating/Rating.props.ts +22 -0
  61. package/src/components/Rating/Rating.stories.tsx +95 -0
  62. package/src/components/Rating/Rating.tsx +140 -0
  63. package/src/components/Rating/RatingStarEmpty.tsx +22 -0
  64. package/src/components/Rating/RatingStarFilled.tsx +27 -0
  65. package/src/components/Rating/index.ts +2 -0
  66. package/src/components/Roundel/Roundel.docs.mdx +48 -0
  67. package/src/components/Roundel/Roundel.figma.tsx +17 -0
  68. package/src/components/Roundel/Roundel.props.ts +8 -0
  69. package/src/components/Roundel/Roundel.stories.tsx +49 -0
  70. package/src/components/Roundel/Roundel.tsx +51 -0
  71. package/src/components/Roundel/index.ts +2 -0
  72. package/src/components/StepperInput/StepperButton.tsx +83 -0
  73. package/src/components/StepperInput/StepperInput.docs.mdx +121 -0
  74. package/src/components/StepperInput/StepperInput.figma.tsx +45 -0
  75. package/src/components/StepperInput/StepperInput.props.ts +39 -0
  76. package/src/components/StepperInput/StepperInput.stories.tsx +270 -0
  77. package/src/components/StepperInput/StepperInput.tsx +322 -0
  78. package/src/components/StepperInput/index.ts +2 -0
  79. package/src/components/Textarea/Textarea.docs.mdx +2 -0
  80. package/src/components/Textarea/Textarea.props.ts +11 -0
  81. package/src/components/Textarea/Textarea.stories.tsx +14 -0
  82. package/src/components/Textarea/Textarea.tsx +22 -34
  83. package/src/components/VerificationInput/VerificationInput.tsx +13 -25
  84. package/src/components/index.ts +3 -0
  85. package/src/hooks/index.ts +1 -0
  86. package/src/hooks/useFormFieldAccessibility.test.tsx +74 -0
  87. package/src/hooks/useFormFieldAccessibility.ts +67 -0
@@ -87,12 +87,15 @@ import {
87
87
  RadioCard,
88
88
  RadioCardGroup,
89
89
  RadioGroup,
90
+ Rating,
91
+ Roundel,
90
92
  SectionHeader,
91
93
  SegmentedControl,
92
94
  SegmentedControlOption,
93
95
  Select,
94
96
  Skeleton,
95
97
  Spinner,
98
+ StepperInput,
96
99
  Switch,
97
100
  Tab,
98
101
  Table,
@@ -145,6 +148,8 @@ const ComponentWrapper = ({
145
148
  const AllComponents: React.FC = () => {
146
149
  const [comboboxValue, setComboboxValue] = React.useState<string | null>('uk');
147
150
  const [selectValue, setSelectValue] = React.useState('1');
151
+ const [stepperValue, setStepperValue] = React.useState('10');
152
+ const [ratingValue, setRatingValue] = React.useState<0 | 1 | 2 | 3 | 4 | 5>(3);
148
153
  const [toggleButtonValue, setToggleButtonValue] = React.useState('');
149
154
  const bottomSheetRef = useRef<BottomSheet>(null);
150
155
  const handleOpenPress = useCallback(() => {
@@ -233,6 +238,7 @@ const AllComponents: React.FC = () => {
233
238
  </View>
234
239
  </Center>
235
240
  </ComponentWrapper>
241
+
236
242
  <ComponentWrapper name="Banner" link="components-banner">
237
243
  <Center flex={1} p="200">
238
244
  <Banner
@@ -733,7 +739,20 @@ const AllComponents: React.FC = () => {
733
739
  </RadioCardGroup>
734
740
  </Center>
735
741
  </ComponentWrapper>
736
-
742
+ <ComponentWrapper name="Rating" link="components-rating">
743
+ <Center flex={1} padding="200">
744
+ <Rating value={ratingValue} onChange={setRatingValue} />
745
+ </Center>
746
+ </ComponentWrapper>
747
+ <ComponentWrapper name="Roundel" link="components-roundel">
748
+ <Center flex={1}>
749
+ <Flex direction="row" spacing="md" alignItems="center">
750
+ <Roundel variant="success" />
751
+ <Roundel variant="pending" />
752
+ <Roundel variant="error" />
753
+ </Flex>
754
+ </Center>
755
+ </ComponentWrapper>
737
756
  <ComponentWrapper name="Section Header" link="components-section-header">
738
757
  <Center flex={1} p="300">
739
758
  <SectionHeader
@@ -790,6 +809,16 @@ const AllComponents: React.FC = () => {
790
809
  <Switch value={switchEnabled} onValueChange={toggleSwitch} />
791
810
  </Center>
792
811
  </ComponentWrapper>
812
+ <ComponentWrapper name="Stepper Input" link="forms-stepper-input">
813
+ <Center flex={1} padding="200">
814
+ <StepperInput
815
+ label="Label"
816
+ helperText="Helper text"
817
+ value={stepperValue}
818
+ onChangeText={setStepperValue}
819
+ />
820
+ </Center>
821
+ </ComponentWrapper>
793
822
  <ComponentWrapper name="Table" link="components-table">
794
823
  <Center flex={1} px="300">
795
824
  <Box style={{ width: 360 }}>
@@ -0,0 +1,328 @@
1
+ import { Meta } from '@storybook/addon-docs/blocks';
2
+ import { SearchMediumIcon } from '@utilitywarehouse/hearth-react-native-icons';
3
+ import SceneBroadbandDark from '@utilitywarehouse/hearth-svg-assets/lib/scene-broadband-dark.svg';
4
+ import SceneBroadbandLight from '@utilitywarehouse/hearth-svg-assets/lib/scene-broadband-light.svg';
5
+ import SpotPiggyBankDark from '@utilitywarehouse/hearth-svg-assets/lib/spot-piggy-bank-dark.svg';
6
+ import SpotPiggyBankLight from '@utilitywarehouse/hearth-svg-assets/lib/spot-piggy-bank-light.svg';
7
+ import { ScopedTheme } from 'react-native-unistyles';
8
+ import StorybookLink from '../../../shared/storybook/StorybookLink';
9
+ import { Alert, BodyText, Box, Center, Flex, Heading, Icon } from '../src';
10
+ import { BackToTopButton, NextPrevPage, UsageWrap } from './components';
11
+
12
+ <Meta title="Guides / Dark Mode Best Practice" />
13
+ <BackToTopButton />
14
+
15
+ # Dark Mode Best Practice
16
+
17
+ When designing for dark mode in Hearth React Native, it's important to ensure that your UI remains visually appealing and accessible. Here are some best practices to follow:
18
+
19
+ - [Setting Up Dark Mode](#setting-up-dark-mode)
20
+ - [Use Semantic Theme Colours](#use-semantic-theme-colours)
21
+ - [Use Semantic Utility Props](#use-semantic-utility-props)
22
+ - [Use the asset libraries](#use-the-asset-libraries)
23
+ - [Icons](#icons)
24
+ - [Illustrations](#illustrations)
25
+ - [Animations](#animations)
26
+ - [`ThemedImage` component](#themedimage-component)
27
+
28
+ <br />
29
+ <Box my="400">
30
+ <Alert text="By default, all components adapt to the current themed colour mode. This guide will help you understand how to work with and easily support dark mode in your apps using Hearth React Native." />
31
+ </Box>
32
+ <br />
33
+ <br />
34
+
35
+ ## Setting Up Dark Mode
36
+
37
+ By default Hearth React Native theme is set to light mode. To enable dark mode, you can set the `colorMode` property in your theme configuration to `'dark'`.
38
+ This will automatically apply the dark mode color palette and styles across your app.
39
+
40
+ ```tsx
41
+ import { useEffect } from 'react';
42
+ import { Appearance } from 'react-native';
43
+ import { useColorMode } from '@utilitywarehouse/hearth-react-native';
44
+
45
+ const App = () => {
46
+ // To set the colour mode use the useColorMode hook and set the color mode
47
+ // to the current system preference on app load
48
+ const [colorMode, setColorMode] = useColorMode();
49
+
50
+ // You can optionally set the theme from the system preference on app load or
51
+ // load from async storage if you are persisting the user's theme choice
52
+ useEffect(() => {
53
+ setColorMode(Appearance.getColorScheme() || 'light');
54
+ }, []);
55
+
56
+ const toggleColorMode = () => {
57
+ setColorMode(colorMode === 'light' ? 'dark' : 'light');
58
+ };
59
+
60
+ return (/* Your app content */);
61
+ };
62
+ ```
63
+
64
+ You can also use the Unistyles runtime to set the theme outside of React components, [read more here](https://www.unistyl.es/v3/guides/theming/#change-theme):
65
+
66
+ ```tsx
67
+ import { UnistylesRuntime } from 'react-native-unistyles';
68
+
69
+ const toggleTheme = () => {
70
+ const theme = UnistylesRuntime.getTheme();
71
+ UnistylesRuntime.setTheme(theme === 'dark' ? 'light' : 'dark');
72
+ };
73
+ ```
74
+
75
+ ## Use Semantic Theme Colours
76
+
77
+ When styling your components, it's best to use the semantic colour tokens provided by the Hearth theme. This ensures that your colours will
78
+ automatically adapt to both light and dark modes without needing to write custom styles for each mode.
79
+
80
+ To use the semantic colours, you can access them from the theme object in your styles:
81
+
82
+ ```tsx
83
+ import { StyleSheet } from '@utilitywarehouse/hearth-react-native';
84
+
85
+ const styles = StyleSheet.create(theme => ({
86
+ text: {
87
+ color: theme.colors.text.primary, // Use semantic colour token
88
+ },
89
+ }));
90
+ ```
91
+
92
+ You can also use the `useTheme` hook to access the theme colours directly in your components:
93
+
94
+ <UsageWrap>
95
+ <Center>
96
+ <Flex direction="row" spacing="lg">
97
+ <ScopedTheme name="dark">
98
+ <Box backgroundColor="primary" p="400">
99
+ <Center>
100
+ <BodyText>This text adapts to dark mode!</BodyText>
101
+ </Center>
102
+ </Box>
103
+ </ScopedTheme>
104
+ <ScopedTheme name="light">
105
+ <Box backgroundColor="primary" p="400">
106
+ <Center>
107
+ <BodyText>This text adapts to light mode!</BodyText>
108
+ </Center>
109
+ </Box>
110
+ </ScopedTheme>
111
+ </Flex>
112
+ </Center>
113
+ </UsageWrap>
114
+
115
+ ```tsx
116
+ import { useTheme } from '@utilitywarehouse/hearth-react-native';
117
+
118
+ const MyComponent = () => {
119
+ const theme = useTheme();
120
+
121
+ return <Text style={{ color: theme.colors.text.primary }}>This text adapts to dark mode!</Text>;
122
+ };
123
+ ```
124
+
125
+ To learn more about the available colours in the Hearth theme, check out the <StorybookLink to="theme-tokens">theme tokens documentation</StorybookLink>.
126
+
127
+ ## Use Semantic Utility Props
128
+
129
+ In addition to using semantic colour tokens, you should also use the semantic utility props provided by Hearth components.
130
+ These props are designed to work with the theme and will automatically adjust their styles based on the current colour mode.
131
+
132
+ For example, instead of setting a background colour directly, you can use the `backgroundColor` or, for text, the `color` prop with a semantic colour value:
133
+
134
+ <UsageWrap>
135
+ <Center spacing="lg">
136
+ <Box>
137
+ <BodyText weight="semibold" mb="100">
138
+ {'Light Mode'}
139
+ </BodyText>
140
+ <Flex direction="row" spacing="lg">
141
+ <ScopedTheme name="light">
142
+ <Box backgroundColor="brand" p="400">
143
+ <BodyText color="inverted">
144
+ This branded box and text adapt to light or dark mode!
145
+ </BodyText>
146
+ </Box>
147
+ <Box backgroundColor="secondary" p="400">
148
+ <BodyText color="primary">This box and text adapt to light or dark mode!</BodyText>
149
+ <BodyText color="secondary">This secondary text adapt to light or dark mode!</BodyText>
150
+ </Box>
151
+ </ScopedTheme>
152
+ </Flex>
153
+ </Box>
154
+ <Box>
155
+ <BodyText weight="semibold" mb="100">
156
+ {'Dark Mode'}
157
+ </BodyText>
158
+ <Flex direction="row" spacing="lg">
159
+ <ScopedTheme name="dark">
160
+ <Box backgroundColor="brand" p="400">
161
+ <BodyText color="inverted">
162
+ This branded box and text adapt to light or dark mode!
163
+ </BodyText>
164
+ </Box>
165
+ <Box backgroundColor="secondary" p="400">
166
+ <BodyText color="primary">This box and text adapt to light or dark mode!</BodyText>
167
+ <BodyText color="secondary">This secondary text adapt to light or dark mode!</BodyText>
168
+ </Box>
169
+ </ScopedTheme>
170
+ </Flex>
171
+ </Box>
172
+ </Center>
173
+ </UsageWrap>
174
+
175
+ ```tsx
176
+ <Box backgroundColor="brand" p="400">
177
+ <BodyText color="inverted">This branded box and text adapt to light or dark mode!</BodyText>
178
+ </Box>
179
+ <Box backgroundColor="secondary" p="400">
180
+ <BodyText color="primary">This box and text adapt to light or dark mode!</BodyText>
181
+ <BodyText color="secondary">This secondary text adapt to light or dark mode!</BodyText>
182
+ </Box>
183
+ ```
184
+
185
+ By using these semantic utility props, you can ensure that your components will look great and be accessible in both light and dark
186
+ modes without needing to write custom styles for each mode.
187
+
188
+ ## Use the asset libraries
189
+
190
+ Hearth provides asset libraries for icons and illustrations that are designed to work well in both light and dark modes.
191
+ When using these assets, make sure to choose the appropriate version (light or dark) based on the current colour mode.
192
+
193
+ ### Icons
194
+
195
+ When using icons from the `@utilitywarehouse/hearth-react-native-icons` library, you can automatically handle light and dark mode
196
+ by using the `color` prop and the `Icon` component with a semantic colour token (by default the `Icon` will use the `theme.colors.icon.primary`
197
+ colour which adapts to light and dark mode):
198
+
199
+ <UsageWrap>
200
+ <Center>
201
+ <Flex direction="row" spacing="lg">
202
+ <ScopedTheme name="light">
203
+ <Box p="400" backgroundColor="secondary">
204
+ <Icon as={SearchMediumIcon} />
205
+ </Box>
206
+ </ScopedTheme>
207
+ <ScopedTheme name="dark">
208
+ <Box p="400" backgroundColor="secondary">
209
+ <Icon as={SearchMediumIcon} color="warmWhite0" />
210
+ </Box>
211
+ </ScopedTheme>
212
+ </Flex>
213
+ </Center>
214
+ </UsageWrap>
215
+
216
+ ```tsx
217
+ import { Icon , useTheme } from '@utilitywarehouse/hearth-react-native';
218
+ import { SearchMediumIcon } from '@utilitywarehouse/hearth-react-native-icons';
219
+
220
+ <Icon as={SearchMediumIcon} />;
221
+
222
+ // Or to specify a colour
223
+ const theme = useTheme();
224
+ ...
225
+ <SearchMediumIcon color={theme.colors.icon.primary} />;
226
+ ```
227
+
228
+ To learn more about the available icons, check out the [icon library documentation](https://hearth.prod.uw.systems/icons/?path=/docs/introduction--docs).
229
+
230
+ ### Illustrations
231
+
232
+ When using illustrations from the `@utilitywarehouse/hearth-svg-assets` library, you'll need to import both the light and dark versions
233
+ of the illustration and conditionally render the appropriate one based on the current colour mode.
234
+
235
+ <UsageWrap>
236
+ <Center>
237
+ <Flex direction="row" spacing="lg">
238
+ <ScopedTheme name="light">
239
+ <Box p="400" backgroundColor="secondary">
240
+ <SceneBroadbandLight width={200} height={200} />
241
+ </Box>
242
+ </ScopedTheme>
243
+ <ScopedTheme name="dark">
244
+ <Box p="400" backgroundColor="secondary">
245
+ <SceneBroadbandDark width={200} height={200} />
246
+ </Box>
247
+ </ScopedTheme>
248
+ </Flex>
249
+ </Center>
250
+ </UsageWrap>
251
+
252
+ ```tsx
253
+ import { useColorMode } from '@utilitywarehouse/hearth-react-native';
254
+ import SceneBroadbandDark from '@utilitywarehouse/hearth-svg-assets/lib/scene-broadband-dark.svg';
255
+ import SceneBroadbandLight from '@utilitywarehouse/hearth-svg-assets/lib/scene-broadband-light.svg';
256
+
257
+ const MyComponent = () => {
258
+ const [colorMode] = useColorMode();
259
+
260
+ return colorMode === 'dark' ? (
261
+ <SceneBroadbandDark width={200} height={200} />
262
+ ) : (
263
+ <SceneBroadbandLight width={200} height={200} />
264
+ );
265
+ };
266
+ ```
267
+
268
+ The above example is to illustrate the concept of handling light and dark mode with illustrations,
269
+ but you should use a reusable `ThemedImage` component to simplify this pattern, which we will cover in the next section.
270
+
271
+ You can view the available illustrations in the [Hearth SVG asset library documentation](https://hearth.prod.uw.systems/assets/?path=/docs/introduction--docs).
272
+
273
+ ### Animations
274
+
275
+ When using animations from the `@utilitywarehouse/hearth-json-assets` library, you can also import both light and dark versions of the animation.
276
+
277
+ We currently only have the light variation of the animations available, but when the dark versions are added you can use a similar approach to
278
+ the illustrations example above to conditionally render the appropriate version based on the current colour mode.
279
+
280
+ You can view the available animations in the [Hearth JSON asset library documentation](https://hearth.prod.uw.systems/assets/?path=/docs/introduction--docs).
281
+
282
+ ## `ThemedImage` component
283
+
284
+ To simplify the process of handling light and dark mode for images, you can create a reusable `ThemedImage` component that takes both light and dark versions of an image as props and automatically renders the correct one based on the current colour mode.
285
+ Here's an example implementation of a `ThemedImage` component:
286
+
287
+ <UsageWrap>
288
+ <Center>
289
+ <Flex direction="row" spacing="lg">
290
+ <ScopedTheme name="light">
291
+ <Box p="400" backgroundColor="secondary">
292
+ <SpotPiggyBankLight width={200} height={200} />
293
+ </Box>
294
+ </ScopedTheme>
295
+ <ScopedTheme name="dark">
296
+ <Box p="400" backgroundColor="secondary">
297
+ <SpotPiggyBankDark width={200} height={200} />
298
+ </Box>
299
+ </ScopedTheme>
300
+ </Flex>
301
+ </Center>
302
+ </UsageWrap>
303
+
304
+ ```tsx
305
+ import React from 'react';
306
+ import { ThemedImage } from '@utilitywarehouse/hearth-react-native';
307
+ import SpotPiggyBankLight from '@utilitywarehouse/hearth-svg-assets/lib/spot-piggy-bank-light.svg';
308
+ import SpotPiggyBankDark from '@utilitywarehouse/hearth-svg-assets/lib/spot-piggy-bank-dark.svg';
309
+
310
+ const MyComponent = () => {
311
+ return (
312
+ <ThemedImage
313
+ light={SpotPiggyBankLight}
314
+ dark={SpotPiggyBankDark}
315
+ style={{ width: 200, height: 200 }}
316
+ />
317
+ );
318
+ };
319
+ ```
320
+
321
+ See the full `ThemedImage` docs and implementation in the <StorybookLink to="utility-components-themed-image">`ThemedImage` documentation</StorybookLink>.
322
+
323
+ <NextPrevPage
324
+ prevLink="guides-adding-shadows"
325
+ prevTitle="Adding Shadows"
326
+ nextLink="primitives-box"
327
+ nextTitle="Box"
328
+ />
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@utilitywarehouse/hearth-react-native",
3
- "version": "0.31.1",
3
+ "version": "0.32.1",
4
4
  "description": "Utility Warehouse React Native UI library",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -33,6 +33,7 @@
33
33
  "@storybook/addon-vitest": "^10.2.1",
34
34
  "@storybook/react-native-web-vite": "^10.2.1",
35
35
  "@types/prismjs": "^1.26.5",
36
+ "@types/react-dom": "^19.1.6",
36
37
  "@types/react": "^19.1.10",
37
38
  "@vitest/browser": "^3.2.4",
38
39
  "@vitest/coverage-v8": "^3.2.4",
@@ -41,6 +42,7 @@
41
42
  "playwright": "^1.55.1",
42
43
  "prismjs": "^1.30.0",
43
44
  "react": "^19.1.0",
45
+ "react-dom": "^19.1.0",
44
46
  "react-native": "0.80.0",
45
47
  "react-native-edge-to-edge": "1.6.1",
46
48
  "react-native-gesture-handler": "2.28.0",
@@ -58,10 +60,10 @@
58
60
  "vite-plugin-svgr": "^4.5.0",
59
61
  "vitest": "^3.2.4",
60
62
  "@utilitywarehouse/hearth-fonts": "^0.0.4",
63
+ "@utilitywarehouse/hearth-react-icons": "^0.8.0",
61
64
  "@utilitywarehouse/hearth-react-native-icons": "^0.8.0",
62
65
  "@utilitywarehouse/hearth-svg-assets": "^0.6.0",
63
- "@utilitywarehouse/hearth-tokens": "^0.2.4",
64
- "@utilitywarehouse/hearth-react-icons": "^0.8.0"
66
+ "@utilitywarehouse/hearth-tokens": "^0.2.4"
65
67
  },
66
68
  "peerDependencies": {
67
69
  "@gorhom/bottom-sheet": ">=5.0.0",
@@ -86,7 +88,7 @@
86
88
  "watch": "tsc --watch",
87
89
  "figma:create": "figma connect create",
88
90
  "figma:publish": "figma connect publish",
89
- "test": "echo \"Error: no test specified\" && exit 1",
91
+ "test": "vitest run --config vitest.unit.config.ts",
90
92
  "test:storybook": "vitest run --project storybook",
91
93
  "dev": "npm run copyChangelog && storybook dev -p 6006",
92
94
  "dev:docs": "storybook dev -p 6002 --no-open --docs",
@@ -55,6 +55,7 @@ const meta = {
55
55
  'insurance',
56
56
  'cashback',
57
57
  'pig',
58
+ 'highlight',
58
59
  ],
59
60
  },
60
61
  iconContainerVariant: {
@@ -548,6 +549,19 @@ export const ColorSchemes: Story = {
548
549
  </Button>
549
550
  }
550
551
  />
552
+ <Banner
553
+ icon={HomeMediumIcon}
554
+ iconContainerColor="highlight"
555
+ iconContainerVariant="emphasis"
556
+ colorScheme="highlight"
557
+ heading="Highlight Yellow"
558
+ description="Banner with highlight color scheme."
559
+ button={
560
+ <Button size="sm" onPress={() => console.log('Action pressed')}>
561
+ Action
562
+ </Button>
563
+ }
564
+ />
551
565
  </Flex>
552
566
  </View>
553
567
  );
@@ -61,23 +61,22 @@ const MyComponent = () => (
61
61
 
62
62
  ## Props
63
63
 
64
- | Property | Type | Description | Default |
65
- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | ----------------- |
66
- | variant | `'subtle' \| 'emphasis' ` | The variant of the card. | `'subtle'` |
67
- | colorScheme | `'neutralStrong' \| 'neutralSubtle' \| 'purple' \| 'energy'` <br /> `'broadband' \| 'mobile' \| 'insurance' \| 'cashback' \|` <br /> `'pig'` | The color scheme of the card. | `'neutralStrong'` |
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` |
70
- | selected | `boolean` | Whether the card is selected. | `false` |
71
- | onPress | `() => void` | Callback function to be called. | `-` |
72
- | disabled | `boolean` | Whether the card is disabled. | `false` |
73
- | spacing | `'none' \| '2xs' \| 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl'` | The space between the content. | `none` |
74
- | alignItems | `'flex-start' \| 'flex-end' \| `<br />`'center' \| 'stretch' \| 'baseline'` | The align items of the flex container. | `flex-start` |
75
- | justifyContent | `'flex-start' \| 'flex-end' \| 'center' \| 'space-between' \| `<br />` 'space-around' \| 'space-evenly'` | The justify content of the flex container. | `flex-start` |
76
- | flexWrap | `'wrap' \| 'nowrap' \| 'wrap-reverse'` | The wrap of the flex container. | `nowrap` |
77
- | flexDirection | `'row' \| 'column' \| 'row-reverse' \| 'column-reverse'` | The direction of the flex container. | `column` |
78
- | gap | `number` | The gap between the content. | `0` |
79
- | rowGap | `number` | The row gap between the content. | `0` |
80
- | columnGap | `number` | The column gap between the content. | `0` |
64
+ | Property | Type | Description | Default |
65
+ | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | ----------------- |
66
+ | variant | `'subtle' \| 'emphasis' ` | The variant of the card. | `'subtle'` |
67
+ | colorScheme | `'neutralStrong' \| 'neutralSubtle' \| 'brand' \| 'energy'` <br /> `'broadband' \| 'mobile' \| 'insurance' \| 'cashback' \|` <br /> `'highlight' \| 'pig'` | The color scheme of the card. | `'neutralStrong'` |
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` |
70
+ | onPress | `() => void` | Callback function to be called. | `-` |
71
+ | disabled | `boolean` | Whether the card is disabled. | `false` |
72
+ | spacing | `'none' \| '2xs' \| 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl'` | The space between the content. | `none` |
73
+ | alignItems | `'flex-start' \| 'flex-end' \| `<br />`'center' \| 'stretch' \| 'baseline'` | The align items of the flex container. | `flex-start` |
74
+ | justifyContent | `'flex-start' \| 'flex-end' \| 'center' \| 'space-between' \| `<br />` 'space-around' \| 'space-evenly'` | The justify content of the flex container. | `flex-start` |
75
+ | flexWrap | `'wrap' \| 'nowrap' \| 'wrap-reverse'` | The wrap of the flex container. | `nowrap` |
76
+ | flexDirection | `'row' \| 'column' \| 'row-reverse' \| 'column-reverse'` | The direction of the flex container. | `column` |
77
+ | gap | `number` | The gap between the content. | `0` |
78
+ | rowGap | `number` | The row gap between the content. | `0` |
79
+ | columnGap | `number` | The column gap between the content. | `0` |
81
80
 
82
81
  ### `CardPressHandler` Props
83
82
 
@@ -10,6 +10,7 @@ interface CardProps
10
10
  | 'brand'
11
11
  | 'energy'
12
12
  | 'broadband'
13
+ | 'highlight'
13
14
  | 'mobile'
14
15
  | 'insurance'
15
16
  | 'cashback'