@utilitywarehouse/hearth-react-native 0.5.0 → 0.7.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 (213) hide show
  1. package/.storybook/main.ts +33 -7
  2. package/.turbo/turbo-build.log +1 -1
  3. package/.turbo/turbo-lint.log +1 -1
  4. package/CHANGELOG.md +14 -0
  5. package/build/components/BottomSheet/BottomSheetBackdrop.js +2 -2
  6. package/build/components/BottomSheet/BottomSheetFlatList.js +2 -2
  7. package/build/components/BottomSheet/BottomSheetHandle.js +2 -2
  8. package/build/components/Button/ButtonIcon.js +2 -1
  9. package/build/components/Button/ButtonRoot.js +2 -6
  10. package/build/components/Button/ButtonText.js +4 -1
  11. package/build/components/Card/Card.context.d.ts +7 -0
  12. package/build/components/Card/CardAction/CardAction.context.d.ts +9 -0
  13. package/build/components/Card/{CardAction.context.js → CardAction/CardAction.context.js} +7 -1
  14. package/build/components/Card/CardAction/CardAction.d.ts +18 -0
  15. package/build/components/Card/CardAction/CardAction.js +7 -0
  16. package/build/components/Card/CardAction/CardAction.props.d.ts +63 -0
  17. package/build/components/Card/CardAction/CardAction.props.js +1 -0
  18. package/build/components/Card/CardAction/CardActionContent.d.ts +6 -0
  19. package/build/components/Card/CardAction/CardActionContent.js +13 -0
  20. package/build/components/Card/CardAction/CardActionHelperText.d.ts +6 -0
  21. package/build/components/Card/CardAction/CardActionHelperText.js +13 -0
  22. package/build/components/Card/CardAction/CardActionIcon.d.ts +9 -0
  23. package/build/components/Card/CardAction/CardActionIcon.js +19 -0
  24. package/build/components/Card/CardAction/CardActionLeadingContent.d.ts +6 -0
  25. package/build/components/Card/CardAction/CardActionLeadingContent.js +5 -0
  26. package/build/components/Card/CardAction/CardActionRoot.d.ts +12 -0
  27. package/build/components/Card/CardAction/CardActionRoot.js +155 -0
  28. package/build/components/Card/CardAction/CardActionText.d.ts +6 -0
  29. package/build/components/Card/CardAction/CardActionText.js +9 -0
  30. package/build/components/Card/CardAction/CardActionTrailingContent.d.ts +6 -0
  31. package/build/components/Card/CardAction/CardActionTrailingContent.js +5 -0
  32. package/build/components/Card/CardAction/CardActionTrailingIcon.d.ts +9 -0
  33. package/build/components/Card/CardAction/CardActionTrailingIcon.js +19 -0
  34. package/build/components/Card/CardAction/index.d.ts +10 -0
  35. package/build/components/Card/CardAction/index.js +9 -0
  36. package/build/components/Card/CardContent.d.ts +6 -0
  37. package/build/components/Card/CardContent.js +33 -0
  38. package/build/components/Card/CardPressHandler.context.d.ts +6 -0
  39. package/build/components/Card/CardPressHandler.context.js +6 -0
  40. package/build/components/Card/{CardAction.d.ts → CardPressHandler.d.ts} +3 -3
  41. package/build/components/Card/CardPressHandler.js +13 -0
  42. package/build/components/Card/CardRoot.js +103 -11
  43. package/build/components/Card/index.d.ts +3 -2
  44. package/build/components/Card/index.js +3 -2
  45. package/build/components/Checkbox/CheckboxIcon.js +2 -1
  46. package/build/components/Container/Container.d.ts +6 -0
  47. package/build/components/Container/Container.js +40 -0
  48. package/build/components/Container/Container.props.d.ts +85 -0
  49. package/build/components/Container/Container.props.js +1 -0
  50. package/build/components/Container/index.d.ts +2 -0
  51. package/build/components/Container/index.js +1 -0
  52. package/build/components/CurrencyInput/CurrencyInput.js +1 -1
  53. package/build/components/Helper/HelperIcon.js +2 -1
  54. package/build/components/Icon/Icon.d.ts +2 -6
  55. package/build/components/IconButton/IconButtonIcon.js +2 -1
  56. package/build/components/IconContainer/IconContainer.d.ts +4 -3
  57. package/build/components/IconContainer/IconContainer.js +3 -3
  58. package/build/components/Input/InputField.js +4 -2
  59. package/build/components/Input/InputIcon.js +2 -1
  60. package/build/components/Link/LinkIcon.js +3 -2
  61. package/build/components/List/ListAction/ListActionTrailingIcon.js +2 -1
  62. package/build/components/List/ListItem/ListItemIcon.js +2 -1
  63. package/build/components/List/ListItem/ListItemTrailingIcon.js +2 -3
  64. package/build/components/ProgressStepper/ProgressStep.d.ts +1 -1
  65. package/build/components/ProgressStepper/ProgressStep.js +6 -6
  66. package/build/components/ProgressStepper/ProgressStepper.props.d.ts +3 -3
  67. package/build/components/ProgressStepper/index.d.ts +1 -1
  68. package/build/components/Radio/RadioIcon.js +7 -2
  69. package/build/components/RadioCard/RadioCardIcon.js +3 -2
  70. package/build/components/Spinner/Spinner.js +2 -0
  71. package/build/components/Spinner/Spinner.web.js +2 -0
  72. package/build/components/Switch/Switch.js +5 -3
  73. package/build/components/Switch/Switch.web.js +1 -0
  74. package/build/components/Tabs/TabsList.js +6 -1
  75. package/build/components/Textarea/TextareaField.js +1 -1
  76. package/build/components/ThemedImage/ThemedImage.d.ts +12 -0
  77. package/build/components/ThemedImage/ThemedImage.js +27 -0
  78. package/build/components/ThemedImage/ThemedImage.props.d.ts +13 -0
  79. package/build/components/ThemedImage/ThemedImage.props.js +1 -0
  80. package/build/components/ThemedImage/index.d.ts +2 -0
  81. package/build/components/ThemedImage/index.js +1 -0
  82. package/build/components/ToggleButton/ToggleButtonIcon.js +2 -1
  83. package/build/components/ToggleButton/ToggleButtonRoot.js +2 -2
  84. package/build/components/UnstyledIconButton/UnstyledIconButtonIcon.js +2 -1
  85. package/build/components/index.d.ts +3 -1
  86. package/build/components/index.js +3 -1
  87. package/build/core/index.d.ts +3 -3
  88. package/build/core/index.js +3 -3
  89. package/build/core/themes.d.ts +24 -12
  90. package/build/hooks/useColorMode.d.ts +1 -1
  91. package/build/hooks/useColorMode.js +7 -8
  92. package/build/hooks/useStyleProps.js +1 -1
  93. package/build/tokens/components/dark/banner.d.ts +19 -0
  94. package/build/tokens/components/dark/banner.js +19 -0
  95. package/build/tokens/components/dark/card-action.d.ts +11 -0
  96. package/build/tokens/components/dark/card-action.js +10 -0
  97. package/build/tokens/components/dark/card-content.d.ts +25 -0
  98. package/build/tokens/components/dark/card-content.js +24 -0
  99. package/build/tokens/components/dark/drawer.d.ts +29 -0
  100. package/build/tokens/components/dark/drawer.js +28 -0
  101. package/build/tokens/components/dark/illustrations.d.ts +0 -1
  102. package/build/tokens/components/dark/illustrations.js +0 -1
  103. package/build/tokens/components/dark/index.d.ts +3 -0
  104. package/build/tokens/components/dark/index.js +3 -0
  105. package/build/tokens/components/light/banner.d.ts +19 -0
  106. package/build/tokens/components/light/banner.js +19 -0
  107. package/build/tokens/components/light/card-action.d.ts +11 -0
  108. package/build/tokens/components/light/card-action.js +10 -0
  109. package/build/tokens/components/light/card-content.d.ts +25 -0
  110. package/build/tokens/components/light/card-content.js +24 -0
  111. package/build/tokens/components/light/drawer.d.ts +29 -0
  112. package/build/tokens/components/light/drawer.js +28 -0
  113. package/build/tokens/components/light/illustrations.d.ts +0 -1
  114. package/build/tokens/components/light/illustrations.js +0 -1
  115. package/build/tokens/components/light/index.d.ts +3 -0
  116. package/build/tokens/components/light/index.js +3 -0
  117. package/build/tokens/layout.d.ts +6 -6
  118. package/build/tokens/layout.js +3 -3
  119. package/build/tokens/typography.d.ts +6 -0
  120. package/build/tokens/typography.js +3 -0
  121. package/docs/components/AllComponents.web.tsx +38 -3
  122. package/docs/components/NextPrevPage.tsx +5 -5
  123. package/docs/components/VariantTitle.tsx +17 -7
  124. package/docs/layout-components.docs.mdx +30 -0
  125. package/package.json +18 -14
  126. package/src/components/BottomSheet/BottomSheetBackdrop.tsx +2 -2
  127. package/src/components/BottomSheet/BottomSheetFlatList.tsx +2 -3
  128. package/src/components/BottomSheet/BottomSheetHandle.tsx +1 -1
  129. package/src/components/Button/ButtonIcon.tsx +2 -1
  130. package/src/components/Button/ButtonRoot.tsx +2 -6
  131. package/src/components/Button/ButtonText.tsx +4 -1
  132. package/src/components/Card/Card.context.ts +7 -0
  133. package/src/components/Card/Card.docs.mdx +212 -14
  134. package/src/components/Card/Card.stories.tsx +50 -3
  135. package/src/components/Card/CardAction/CardAction.context.ts +22 -0
  136. package/src/components/Card/CardAction/CardAction.props.ts +87 -0
  137. package/src/components/Card/CardAction/CardAction.stories.tsx +265 -0
  138. package/src/components/Card/CardAction/CardAction.tsx +10 -0
  139. package/src/components/Card/CardAction/CardActionContent.tsx +20 -0
  140. package/src/components/Card/CardAction/CardActionHelperText.tsx +21 -0
  141. package/src/components/Card/CardAction/CardActionIcon.tsx +32 -0
  142. package/src/components/Card/CardAction/CardActionLeadingContent.tsx +9 -0
  143. package/src/components/Card/CardAction/CardActionRoot.tsx +258 -0
  144. package/src/components/Card/CardAction/CardActionText.tsx +17 -0
  145. package/src/components/Card/CardAction/CardActionTrailingContent.tsx +9 -0
  146. package/src/components/Card/CardAction/CardActionTrailingIcon.tsx +32 -0
  147. package/src/components/Card/CardAction/index.ts +10 -0
  148. package/src/components/Card/CardContent.tsx +40 -0
  149. package/src/components/Card/CardPressHandler.context.ts +12 -0
  150. package/src/components/Card/CardPressHandler.tsx +20 -0
  151. package/src/components/Card/CardRoot.tsx +128 -13
  152. package/src/components/Card/index.ts +3 -2
  153. package/src/components/Checkbox/CheckboxIcon.tsx +2 -1
  154. package/src/components/Container/Container.docs.mdx +168 -0
  155. package/src/components/Container/Container.props.ts +89 -0
  156. package/src/components/Container/Container.stories.tsx +274 -0
  157. package/src/components/Container/Container.tsx +52 -0
  158. package/src/components/Container/index.tsx +2 -0
  159. package/src/components/CurrencyInput/CurrencyInput.tsx +1 -1
  160. package/src/components/Helper/HelperIcon.tsx +2 -1
  161. package/src/components/Icon/Icon.tsx +4 -3
  162. package/src/components/IconButton/IconButtonIcon.tsx +2 -1
  163. package/src/components/IconContainer/IconContainer.tsx +17 -19
  164. package/src/components/Input/InputField.tsx +2 -1
  165. package/src/components/Input/InputIcon.tsx +2 -1
  166. package/src/components/Link/LinkIcon.tsx +3 -2
  167. package/src/components/List/ListAction/ListActionTrailingIcon.tsx +2 -1
  168. package/src/components/List/ListItem/ListItemIcon.tsx +2 -1
  169. package/src/components/List/ListItem/ListItemTrailingIcon.tsx +2 -3
  170. package/src/components/ProgressStepper/ProgressStep.tsx +8 -8
  171. package/src/components/ProgressStepper/ProgressStepper.docs.mdx +11 -11
  172. package/src/components/ProgressStepper/ProgressStepper.props.ts +3 -3
  173. package/src/components/ProgressStepper/ProgressStepper.stories.tsx +27 -27
  174. package/src/components/ProgressStepper/index.ts +1 -1
  175. package/src/components/Radio/RadioIcon.tsx +8 -3
  176. package/src/components/RadioCard/RadioCardIcon.tsx +4 -3
  177. package/src/components/Spinner/Spinner.tsx +2 -0
  178. package/src/components/Spinner/Spinner.web.tsx +2 -0
  179. package/src/components/Switch/Switch.tsx +10 -5
  180. package/src/components/Switch/Switch.web.tsx +5 -0
  181. package/src/components/Tabs/TabsList.tsx +2 -0
  182. package/src/components/Textarea/TextareaField.tsx +1 -1
  183. package/src/components/ThemedImage/ThemedImage.docs.mdx +208 -0
  184. package/src/components/ThemedImage/ThemedImage.props.ts +15 -0
  185. package/src/components/ThemedImage/ThemedImage.stories.tsx +175 -0
  186. package/src/components/ThemedImage/ThemedImage.tsx +34 -0
  187. package/src/components/ThemedImage/index.tsx +2 -0
  188. package/src/components/ToggleButton/ToggleButtonIcon.tsx +2 -1
  189. package/src/components/ToggleButton/ToggleButtonRoot.tsx +2 -2
  190. package/src/components/UnstyledIconButton/UnstyledIconButtonIcon.tsx +2 -1
  191. package/src/components/index.ts +3 -9
  192. package/src/core/index.ts +14 -11
  193. package/src/hooks/useColorMode.ts +9 -12
  194. package/src/hooks/useStyleProps.ts +1 -1
  195. package/src/tokens/components/dark/banner.ts +19 -0
  196. package/src/tokens/components/dark/card-action.ts +11 -0
  197. package/src/tokens/components/dark/card-content.ts +25 -0
  198. package/src/tokens/components/dark/drawer.ts +29 -0
  199. package/src/tokens/components/dark/illustrations.ts +0 -1
  200. package/src/tokens/components/dark/index.ts +3 -0
  201. package/src/tokens/components/light/banner.ts +19 -0
  202. package/src/tokens/components/light/card-action.ts +11 -0
  203. package/src/tokens/components/light/card-content.ts +25 -0
  204. package/src/tokens/components/light/drawer.ts +29 -0
  205. package/src/tokens/components/light/illustrations.ts +0 -1
  206. package/src/tokens/components/light/index.ts +3 -0
  207. package/src/tokens/layout.ts +3 -3
  208. package/src/tokens/typography.ts +3 -0
  209. package/src/vite-env.d.ts +6 -0
  210. package/build/components/Card/CardAction.context.d.ts +0 -6
  211. package/build/components/Card/CardAction.js +0 -13
  212. package/src/components/Card/CardAction.context.ts +0 -12
  213. package/src/components/Card/CardAction.tsx +0 -18
@@ -22,26 +22,26 @@ export const Playground: Story = {
22
22
  children: (
23
23
  <Flex space="xl" direction="column" align="center" style={{ flex: 1, minWidth: 200 }}>
24
24
  <ProgressStepper>
25
- <ProgressStep id={'1'} state="complete" />
26
- <ProgressStep id={'2'} state="complete" />
27
- <ProgressStep id={'3'} state="active" />
28
- <ProgressStep id={'4'} state="incomplete" />
25
+ <ProgressStep id={'1'} status="complete" />
26
+ <ProgressStep id={'2'} status="complete" />
27
+ <ProgressStep id={'3'} status="active" />
28
+ <ProgressStep id={'4'} status="incomplete" />
29
29
  </ProgressStepper>
30
30
  <Flex direction="row" space="lg" style={{ width: '100%' }}>
31
- <ProgressStep id={'1'} state="complete" />
31
+ <ProgressStep id={'1'} status="complete" />
32
32
  </Flex>
33
33
  <Flex direction="row" space="lg" style={{ width: '100%' }}>
34
- <ProgressStep id={'3'} state="active" />
34
+ <ProgressStep id={'3'} status="active" />
35
35
  </Flex>
36
36
  <Flex direction="row" space="lg" style={{ width: '100%' }}>
37
- <ProgressStep id={'5'} state="incomplete" />
37
+ <ProgressStep id={'5'} status="incomplete" />
38
38
  </Flex>
39
39
  </Flex>
40
40
  ),
41
41
  },
42
42
  };
43
43
 
44
- export const StepStates: Story = {
44
+ export const StepStatuses: Story = {
45
45
  args: {
46
46
  children: <></>,
47
47
  },
@@ -53,31 +53,31 @@ export const StepStates: Story = {
53
53
  <Flex space="xl" direction="column" align="center">
54
54
  <VariantTitle title="All Uncompleted Steps">
55
55
  <ProgressStepper {...props}>
56
- <ProgressStep id={'1'} state="incomplete" />
57
- <ProgressStep id={'2'} state="incomplete" />
58
- <ProgressStep id={'3'} state="incomplete" />
56
+ <ProgressStep id={'1'} status="incomplete" />
57
+ <ProgressStep id={'2'} status="incomplete" />
58
+ <ProgressStep id={'3'} status="incomplete" />
59
59
  </ProgressStepper>
60
60
  </VariantTitle>
61
61
  <VariantTitle title="One Active Step">
62
62
  <ProgressStepper {...props}>
63
- <ProgressStep id={'1'} state="active" />
64
- <ProgressStep id={'2'} state="incomplete" />
65
- <ProgressStep id={'3'} state="incomplete" />
63
+ <ProgressStep id={'1'} status="active" />
64
+ <ProgressStep id={'2'} status="incomplete" />
65
+ <ProgressStep id={'3'} status="incomplete" />
66
66
  </ProgressStepper>
67
67
  </VariantTitle>
68
- <VariantTitle title="Mixed States">
68
+ <VariantTitle title="Mixed Statuses">
69
69
  <ProgressStepper {...props}>
70
- <ProgressStep id={'1'} state="complete" />
71
- <ProgressStep id={'2'} state="complete" />
72
- <ProgressStep id={'3'} state="active" />
73
- <ProgressStep id={'4'} state="incomplete" />
70
+ <ProgressStep id={'1'} status="complete" />
71
+ <ProgressStep id={'2'} status="complete" />
72
+ <ProgressStep id={'3'} status="active" />
73
+ <ProgressStep id={'4'} status="incomplete" />
74
74
  </ProgressStepper>
75
75
  </VariantTitle>
76
76
  <VariantTitle title="All Completed">
77
77
  <ProgressStepper {...props}>
78
- <ProgressStep id={'1'} state="complete" />
79
- <ProgressStep id={'2'} state="complete" />
80
- <ProgressStep id={'3'} state="complete" />
78
+ <ProgressStep id={'1'} status="complete" />
79
+ <ProgressStep id={'2'} status="complete" />
80
+ <ProgressStep id={'3'} status="complete" />
81
81
  </ProgressStepper>
82
82
  </VariantTitle>
83
83
  </Flex>
@@ -95,11 +95,11 @@ export const BasicExample: Story = {
95
95
  <Heading size="md">Progress Stepper</Heading>
96
96
  <BodyText>Shows progress through multi-step processes</BodyText>
97
97
  <ProgressStepper {...props}>
98
- <ProgressStep id="services-data" state="complete" />
99
- <ProgressStep id="customer-data" state="complete" />
100
- <ProgressStep id="shipping-data" state="active" />
101
- <ProgressStep id="payment-data" state="incomplete" />
102
- <ProgressStep id="summary" state="incomplete" />
98
+ <ProgressStep id="services-data" status="complete" />
99
+ <ProgressStep id="customer-data" status="complete" />
100
+ <ProgressStep id="shipping-data" status="active" />
101
+ <ProgressStep id="payment-data" status="incomplete" />
102
+ <ProgressStep id="summary" status="incomplete" />
103
103
  </ProgressStepper>
104
104
  <BodyText>Step 3 of 5</BodyText>
105
105
  </Flex>
@@ -1,3 +1,3 @@
1
1
  export { default as ProgressStepper } from './ProgressStepper';
2
2
  export { default as ProgressStep } from './ProgressStep';
3
- export type { ProgressStepperProps, ProgressStepProps, StepState } from './ProgressStepper.props';
3
+ export type { ProgressStepperProps, ProgressStepProps, StepStatus } from './ProgressStepper.props';
@@ -1,8 +1,8 @@
1
+ import { Platform, StyleProp, ViewStyle } from 'react-native';
1
2
  import { StyleSheet } from 'react-native-unistyles';
2
3
  import { Icon } from '../Icon';
3
- import { CircleIcon } from '../Icons';
4
4
  import IconProps from '../Icon/Icon.props';
5
- import { Platform } from 'react-native';
5
+ import { CircleIcon } from '../Icons';
6
6
 
7
7
  const RadioIcon = ({ style, ...props }: IconProps) => {
8
8
  return (
@@ -11,7 +11,12 @@ const RadioIcon = ({ style, ...props }: IconProps) => {
11
11
  {...props}
12
12
  style={
13
13
  Platform.OS === 'web'
14
- ? StyleSheet.compose(styles.container, style)
14
+ ? {
15
+ // @ts-expect-error - style prop type issue
16
+ ...(styles.container as StyleProp<ViewStyle>),
17
+ // @ts-expect-error - style prop type issue
18
+ ...(props.style as StyleProp<ViewStyle>),
19
+ }
15
20
  : ([styles.container, style] as any)
16
21
  }
17
22
  />
@@ -1,8 +1,8 @@
1
+ import { Platform, StyleProp, ViewStyle } from 'react-native';
1
2
  import { StyleSheet } from 'react-native-unistyles';
2
3
  import { Icon } from '../Icon';
3
- import { CircleIcon } from '../Icons';
4
4
  import IconProps from '../Icon/Icon.props';
5
- import { Platform } from 'react-native';
5
+ import { CircleIcon } from '../Icons';
6
6
 
7
7
  const RadioCardIcon = ({ style, ...props }: IconProps) => {
8
8
  return (
@@ -11,7 +11,8 @@ const RadioCardIcon = ({ style, ...props }: IconProps) => {
11
11
  {...props}
12
12
  style={
13
13
  Platform.OS === 'web'
14
- ? StyleSheet.compose(styles.container, style)
14
+ ? // @ts-expect-error - style prop type issue
15
+ { ...(styles.container as StyleProp<ViewStyle>), ...props.style }
15
16
  : ([styles.container, style] as any)
16
17
  }
17
18
  />
@@ -18,7 +18,9 @@ import { ColorValue } from '../../types';
18
18
  import { getFlattenedColorValue } from '../../utils';
19
19
  import type SpinnerProps from './Spinner.props';
20
20
 
21
+ // @ts-expect-error - Animated.View type issue
21
22
  const AnimatedSvg = Animated.createAnimatedComponent(Svg as React.ComponentType<any>);
23
+ // @ts-expect-error - Animated.View type issue
22
24
  const AnimatedCircle = Animated.createAnimatedComponent(Circle as React.ComponentType<any>);
23
25
 
24
26
  const SpinnerRoot = ({ size = 'md', color, ...props }: SpinnerProps) => {
@@ -18,7 +18,9 @@ import { ColorValue } from '../../types';
18
18
  import { getFlattenedColorValue } from '../../utils';
19
19
  import type SpinnerProps from './Spinner.props';
20
20
 
21
+ // @ts-expect-error - Animated.View type issue
21
22
  const AnimatedSvg = Animated.createAnimatedComponent(Svg as React.ComponentType<any>);
23
+ // @ts-expect-error - Animated.View type issue
22
24
  const AnimatedCircle = Animated.createAnimatedComponent(Circle as React.ComponentType<any>);
23
25
 
24
26
  const SpinnerRoot = ({ size = 'md', color, ...props }: SpinnerProps) => {
@@ -11,6 +11,7 @@ import Animated, {
11
11
  withTiming,
12
12
  } from 'react-native-reanimated';
13
13
  import { StyleSheet } from 'react-native-unistyles';
14
+ import { useAnimatedTheme } from 'react-native-unistyles/reanimated';
14
15
  import { useTheme } from '../../hooks';
15
16
  import { Icon } from '../Icon';
16
17
  import SwitchProps from './Switch.props';
@@ -23,6 +24,7 @@ const CustomSwitch = ({
23
24
  ...accessibilityProps
24
25
  }: SwitchProps) => {
25
26
  const { components, color } = useTheme();
27
+ const theme = useAnimatedTheme();
26
28
  const SWITCH_WIDTH = size === 'medium' ? components.switch.md.width : components.switch.sm.width;
27
29
  const THUMB_SIZE =
28
30
  size === 'medium' ? components.switch.md.circle.size : components.switch.sm.circle.size;
@@ -34,17 +36,20 @@ const CustomSwitch = ({
34
36
  const offset = useSharedValue(value ? SWITCH_WIDTH - THUMB_SIZE - PADDING * 2 : 0);
35
37
  const progress = useSharedValue(value ? 1 : 0);
36
38
 
37
- const animatedThumbStyle = useAnimatedStyle(() => ({
38
- transform: [{ translateX: offset.value }],
39
- }));
39
+ const animatedThumbStyle = useAnimatedStyle(
40
+ () => ({
41
+ transform: [{ translateX: offset.value }],
42
+ }),
43
+ [offset]
44
+ );
40
45
 
41
46
  const animatedSwitchBackgroundStyle = useAnimatedStyle(() => {
42
47
  const backgroundColor = interpolateColor(
43
48
  progress.value,
44
49
  [0, 1],
45
50
  [
46
- color.interactive.functional.surface.strong.default,
47
- color.interactive.brand.surface.strong.default,
51
+ theme.value.color.interactive.functional.surface.strong.default,
52
+ theme.value.color.interactive.brand.surface.strong.default,
48
53
  ]
49
54
  );
50
55
  return { backgroundColor };
@@ -15,6 +15,7 @@ import { useTheme } from '../../hooks';
15
15
  import { Icon } from '../Icon';
16
16
  import SwitchProps from './Switch.props';
17
17
 
18
+ // @ts-expect-error - Animated.View type issue
18
19
  const AnimatedView = Animated.createAnimatedComponent(View);
19
20
 
20
21
  const CustomSwitch = ({
@@ -114,14 +115,18 @@ const CustomSwitch = ({
114
115
  accessibilityHint={accessibilityProps.accessibilityHint}
115
116
  {...accessibilityProps}
116
117
  >
118
+ {/* @ts-expect-error - Animated.View type issue */}
117
119
  <AnimatedView style={[styles.switch, animatedSwitchBackgroundStyle, animatedSwitchStyle]}>
120
+ {/* @ts-expect-error - Animated.View type issue */}
118
121
  <AnimatedView style={[styles.thumb, animatedThumbStyle]}>
122
+ {/* @ts-expect-error - Animated.View type issue */}
119
123
  <AnimatedView style={[styles.iconWrap, animatedTickStyle]}>
120
124
  {(() => {
121
125
  const IconAny = Icon as any;
122
126
  return <IconAny as={TickSmallIcon} style={styles.icon as any} />;
123
127
  })()}
124
128
  </AnimatedView>
129
+ {/* @ts-expect-error - Animated.View type issue */}
125
130
  <AnimatedView style={[styles.iconWrap, animatedCrossStyle]}>
126
131
  {(() => {
127
132
  const IconAny = Icon as any;
@@ -15,6 +15,7 @@ import { UnstyledIconButton } from '../UnstyledIconButton';
15
15
  import { useTabsContext } from './Tabs.context';
16
16
  import type TabsListProps from './TabsList.props';
17
17
 
18
+ // @ts-expect-error - Animated.View type issue
18
19
  const Indicator = Animated.createAnimatedComponent(View);
19
20
 
20
21
  const SCROLL_STEP_RATIO = 0.6;
@@ -112,6 +113,7 @@ const TabsList = ({ children, style, ...rest }: TabsListProps) => {
112
113
  <View style={styles.container}>
113
114
  {children}
114
115
  <Indicator
116
+ // @ts-expect-error - Animated.View type issue
115
117
  accessibilityElementsHidden
116
118
  importantForAccessibility="no-hide-descendants"
117
119
  style={[styles.indicator, indicatorStyle]}
@@ -33,7 +33,7 @@ const styles = StyleSheet.create(theme => ({
33
33
  color: theme.color.text.primary,
34
34
  fontSize: theme.typography.mobile.bodyText.md.fontSize,
35
35
  fontFamily: theme.typography.mobile.bodyText.fontFamily,
36
- fontWeight: theme.typography.mobile.bodyText.fontWeight,
36
+ fontWeight: `${theme.typography.mobile.bodyText.fontWeight}`,
37
37
  borderWidth: 0,
38
38
  outlineWidth: 0,
39
39
  _web: {
@@ -0,0 +1,208 @@
1
+ import { Canvas, Controls, Meta, Story } from '@storybook/addon-docs/blocks';
2
+ import * as ThemedImageStories from './ThemedImage.stories';
3
+
4
+ <Meta title="Utility Components / Themed Image" />
5
+
6
+ # Themed Image
7
+
8
+ The `ThemedImage` component automatically switches between light and dark mode images or SVG components based on the current theme. It's perfect for illustrations, logos, or any visual assets that need different appearances for light and dark modes.
9
+
10
+ - [Features](#features)
11
+ - [Basic Usage](#basic-usage)
12
+ - [Props](#props)
13
+ - [Examples](#examples)
14
+
15
+ ## Features
16
+
17
+ - **Automatic theme switching** - Responds to color mode changes
18
+ - **Flexible sources** - Accepts both regular image sources and React components (like SVGs)
19
+ - **Accessible** - Supports all standard Image accessibility props
20
+ - **Works with svg-assets** - Seamlessly integrates with the `@utilitywarehouse/hearth-svg-assets` package
21
+
22
+ ## Basic Usage
23
+
24
+ <Canvas of={ThemedImageStories.Playground} />
25
+
26
+ ## Props
27
+
28
+ | Prop | Type | Required | Description |
29
+ | ------- | ------------------------------------- | -------- | -------------------------------------------------- |
30
+ | `light` | `ImageSourcePropType \| ReactElement` | Yes | Image source or component to display in light mode |
31
+ | `dark` | `ImageSourcePropType \| ReactElement` | Yes | Image source or component to display in dark mode |
32
+ | ...rest | `ImageProps` | No | All other standard React Native Image props |
33
+
34
+ ### Additional Props
35
+
36
+ `ThemedImage` extends React Native's `Image` component, so it accepts all standard `ImageProps` including:
37
+
38
+ - `style` - Custom styling for the image container
39
+ - `resizeMode` - How to resize the image when the frame doesn't match the raw image dimensions
40
+ - `accessible` - Whether the element is an accessibility element
41
+ - `accessibilityLabel` - Text to be announced by screen readers
42
+ - `testID` - Used to locate this view in end-to-end tests
43
+
44
+ ## Examples
45
+
46
+ ### With SVG Assets
47
+
48
+ The most common use case is with SVG components from the `@utilitywarehouse/hearth-svg-assets` package:
49
+
50
+ ```tsx
51
+ import { View } from 'react-native';
52
+ import { ThemedImage } from '@utilitywarehouse/hearth-react-native';
53
+ import SpotBillingDark from '@utilitywarehouse/hearth-svg-assets/lib/spot-billing-dark.svg';
54
+ import SpotBillingLight from '@utilitywarehouse/hearth-svg-assets/lib/spot-billing-light.svg';
55
+
56
+ function MyComponent() {
57
+ return <ThemedImage light={SpotBillingLight} dark={SpotBillingDark} width={200} height={200} />;
58
+ }
59
+ ```
60
+
61
+ <Canvas of={ThemedImageStories.WithSpotIllustrations} />
62
+
63
+ ### With Regular Images
64
+
65
+ You can also use regular image sources (not just SVG components):
66
+
67
+ ```tsx
68
+ import { ThemedImage } from '@utilitywarehouse/hearth-react-native';
69
+ import logoLight from './assets/logo-light.png';
70
+ import logoDark from './assets/logo-dark.png';
71
+
72
+ function MyComponent() {
73
+ return <ThemedImage light={logoLight} dark={logoDark} />;
74
+ }
75
+ ```
76
+
77
+ <Canvas of={ThemedImageStories.WithRegularImages} />
78
+
79
+ ### With Custom Sizes
80
+
81
+ When using SVG components, control the size by passing a `style` prop with `width` and `height` to the component:
82
+
83
+ <Canvas of={ThemedImageStories.WithCustomSize} />
84
+
85
+ ### With Accessibility
86
+
87
+ Support screen readers and assistive technologies:
88
+
89
+ ```tsx
90
+ import { View } from 'react-native';
91
+ import { ThemedImage } from '@utilitywarehouse/hearth-react-native';
92
+ import MascotEnergyDark from '@utilitywarehouse/hearth-svg-assets/lib/mascot-energy-dark.svg';
93
+ import MascotEnergyLight from '@utilitywarehouse/hearth-svg-assets/lib/mascot-energy-light.svg';
94
+
95
+ function MyComponent() {
96
+ return (
97
+ <ThemedImage
98
+ light={MascotEnergyLight}
99
+ dark={MascotEnergyDark}
100
+ width={150}
101
+ height={150}
102
+ accessible={true}
103
+ accessibilityLabel="Energy service mascot illustration"
104
+ />
105
+ );
106
+ }
107
+ ```
108
+
109
+ <Canvas of={ThemedImageStories.WithAccessibility} />
110
+
111
+ ## Usage with svg-assets Package
112
+
113
+ The `@utilitywarehouse/hearth-svg-assets` package provides themed illustrations in three categories:
114
+
115
+ ### Spot Illustrations
116
+
117
+ Small, focused illustrations for specific concepts:
118
+
119
+ - `spot-billing` - Billing and payments
120
+ - `spot-celebratory` - Success and celebration
121
+ - `spot-error` - Error states
122
+ - `spot-help` - Help and support
123
+ - `spot-innovation` - New features
124
+ - `spot-savings` - Cost savings
125
+ - And more...
126
+
127
+ ### Mascots
128
+
129
+ Service-specific character illustrations:
130
+
131
+ - `mascot-energy` - Energy service
132
+ - `mascot-broadband` - Broadband service
133
+ - `mascot-mobile` - Mobile service
134
+ - `mascot-insurance` - Insurance service
135
+ - `mascot-cashback` - Cashback rewards
136
+
137
+ ### Scene Illustrations
138
+
139
+ Large, detailed illustrations for landing pages:
140
+
141
+ - `scene-energy` - Energy service scenes
142
+ - `scene-broadband` - Broadband service scenes
143
+ - `scene-mobile` - Mobile service scenes
144
+ - `scene-insurance` - Insurance service scenes
145
+ - `scene-bundle` - Service bundle scenes
146
+
147
+ All assets come in both `-light.svg` and `-dark.svg` variants.
148
+
149
+ ## Integration with react-native-svg-transformer
150
+
151
+ To use SVG files as React components in React Native, you'll need `react-native-svg-transformer`:
152
+
153
+ ```bash
154
+ # Install dependencies
155
+ npm install react-native-svg react-native-svg-transformer --save-dev
156
+ ```
157
+
158
+ Configure your `metro.config.js`:
159
+
160
+ ```js
161
+ const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
162
+
163
+ const config = {
164
+ transformer: {
165
+ babelTransformerPath: require.resolve('react-native-svg-transformer'),
166
+ },
167
+ resolver: {
168
+ assetExts: getDefaultConfig(__dirname).resolver.assetExts.filter(ext => ext !== 'svg'),
169
+ sourceExts: [...getDefaultConfig(__dirname).resolver.sourceExts, 'svg'],
170
+ },
171
+ };
172
+
173
+ module.exports = mergeConfig(getDefaultConfig(__dirname), config);
174
+ ```
175
+
176
+ Add TypeScript declarations (optional):
177
+
178
+ ```typescript
179
+ // svg.d.ts
180
+ declare module '*.svg' {
181
+ import React from 'react';
182
+ import { SvgProps } from 'react-native-svg';
183
+ const content: React.FC<SvgProps>;
184
+ export default content;
185
+ }
186
+ ```
187
+
188
+ ## Best Practices
189
+
190
+ 1. **Always provide both variants** - Ensure you have both light and dark versions of your assets
191
+ 2. **Use appropriate sizes** - Match illustration sizes to your design specifications
192
+ 3. **Add accessibility labels** - Make your images accessible to screen readers
193
+ 4. **Consider performance** - Large SVG files may impact performance on older devices
194
+ 5. **Test in both modes** - Always test your themed images in both light and dark modes
195
+
196
+ ## Troubleshooting
197
+
198
+ ### SVG not displaying
199
+
200
+ Make sure you have configured `react-native-svg-transformer` correctly and that your SVG files are valid.
201
+
202
+ ### Theme not switching
203
+
204
+ The component uses `useColorMode` hook which relies on the Unistyles theme system. Ensure your app is properly configured with Unistyles.
205
+
206
+ ### TypeScript errors with SVG imports
207
+
208
+ Add the TypeScript declaration file for `.svg` modules as shown in the integration section above.
@@ -0,0 +1,15 @@
1
+ import type { ComponentType, ReactElement } from 'react';
2
+ import type { ImageProps, ImageSourcePropType } from 'react-native';
3
+
4
+ interface ThemedImageProps extends Omit<ImageProps, 'source'> {
5
+ /**
6
+ * Image source or component to display in light mode
7
+ */
8
+ light: ImageSourcePropType | ReactElement | ComponentType<any>;
9
+ /**
10
+ * Image source or component to display in dark mode
11
+ */
12
+ dark: ImageSourcePropType | ReactElement | ComponentType<any>;
13
+ }
14
+
15
+ export default ThemedImageProps;
@@ -0,0 +1,175 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import MascotEnergyDark from '@utilitywarehouse/hearth-svg-assets/lib/mascot-energy-dark.svg';
3
+ import MascotEnergyLight from '@utilitywarehouse/hearth-svg-assets/lib/mascot-energy-light.svg';
4
+ import SceneBroadbandDark from '@utilitywarehouse/hearth-svg-assets/lib/scene-broadband-dark.svg';
5
+ import SceneBroadbandLight from '@utilitywarehouse/hearth-svg-assets/lib/scene-broadband-light.svg';
6
+ import SpotBillingDark from '@utilitywarehouse/hearth-svg-assets/lib/spot-billing-dark.svg';
7
+ import SpotBillingLight from '@utilitywarehouse/hearth-svg-assets/lib/spot-billing-light.svg';
8
+ import { SvgProps } from 'react-native-svg';
9
+ import pig from '../../../docs/assets/pigs.png';
10
+ import { Box } from '../Box';
11
+ import { ThemedImage } from './';
12
+
13
+ const meta: Meta<typeof ThemedImage> = {
14
+ title: 'Stories / ThemedImage',
15
+ component: ThemedImage,
16
+ argTypes: {},
17
+ parameters: {
18
+ docs: {
19
+ description: {
20
+ component:
21
+ 'ThemedImage component that automatically switches between light and dark mode images or SVG components based on the current theme.',
22
+ },
23
+ },
24
+ },
25
+ };
26
+
27
+ export default meta;
28
+
29
+ type Story = StoryObj<typeof ThemedImage>;
30
+
31
+ export const Playground: Story = {
32
+ args: {},
33
+ render: () => (
34
+ <Box gap="200">
35
+ <ThemedImage
36
+ // @ts-ignore
37
+ light={<SpotBillingLight width={200} height={200} />}
38
+ // @ts-ignore
39
+ dark={<SpotBillingDark width={200} height={200} />}
40
+ />
41
+ </Box>
42
+ ),
43
+ };
44
+
45
+ export const WithSpotIllustrations: Story = {
46
+ parameters: {
47
+ controls: { include: [] },
48
+ },
49
+ render: () => (
50
+ <Box flexDirection="row" flexWrap="wrap" gap="200">
51
+ <ThemedImage
52
+ // @ts-ignore
53
+ light={<SpotBillingLight width={120} height={120} />}
54
+ // @ts-ignore
55
+ dark={<SpotBillingDark width={120} height={120} />}
56
+ />
57
+ </Box>
58
+ ),
59
+ };
60
+
61
+ export const WithMascots: Story = {
62
+ parameters: {
63
+ controls: { include: [] },
64
+ },
65
+ render: () => (
66
+ <Box flexDirection="row" flexWrap="wrap" gap="200" alignItems="center">
67
+ <ThemedImage
68
+ light={MascotEnergyLight as unknown as React.FC<SvgProps>}
69
+ dark={MascotEnergyDark as unknown as React.FC<SvgProps>}
70
+ width={120}
71
+ height={120}
72
+ />
73
+ </Box>
74
+ ),
75
+ };
76
+
77
+ export const WithSceneIllustrations: Story = {
78
+ parameters: {
79
+ controls: { include: [] },
80
+ },
81
+ render: () => (
82
+ <Box gap="200">
83
+ <ThemedImage
84
+ // @ts-ignore
85
+ light={<SceneBroadbandLight width={300} height={200} />}
86
+ // @ts-ignore
87
+ dark={<SceneBroadbandDark width={300} height={200} />}
88
+ />
89
+ </Box>
90
+ ),
91
+ };
92
+
93
+ export const WithRegularImages: Story = {
94
+ parameters: {
95
+ controls: { include: [] },
96
+ docs: {
97
+ description: {
98
+ story:
99
+ 'ThemedImage also works with regular image sources (using `require` or `uri`), not just SVG components.',
100
+ },
101
+ },
102
+ },
103
+ render: () => (
104
+ <Box gap="200">
105
+ <ThemedImage
106
+ light={{
107
+ uri: pig,
108
+ }}
109
+ dark={{
110
+ uri: pig,
111
+ }}
112
+ width={200}
113
+ height={200}
114
+ style={{ width: 200, height: 200, borderRadius: 8 }}
115
+ />
116
+ </Box>
117
+ ),
118
+ };
119
+
120
+ export const WithCustomSize: Story = {
121
+ parameters: {
122
+ controls: { include: [] },
123
+ docs: {
124
+ description: {
125
+ story: 'When using SVG components, control their size with width and height props.',
126
+ },
127
+ },
128
+ },
129
+ render: () => (
130
+ <Box flexDirection="row" flexWrap="wrap" gap="200" alignItems="center">
131
+ <ThemedImage
132
+ // @ts-ignore
133
+ light={<SpotBillingLight width={80} height={80} />}
134
+ // @ts-ignore
135
+ dark={<SpotBillingDark width={80} height={80} />}
136
+ />
137
+ <ThemedImage
138
+ // @ts-ignore
139
+ light={<SpotBillingLight width={120} height={120} />}
140
+ // @ts-ignore
141
+ dark={<SpotBillingDark width={120} height={120} />}
142
+ />
143
+ <ThemedImage
144
+ // @ts-ignore
145
+ light={<SpotBillingLight width={160} height={160} />}
146
+ // @ts-ignore
147
+ dark={<SpotBillingDark width={160} height={160} />}
148
+ />
149
+ </Box>
150
+ ),
151
+ };
152
+
153
+ export const WithAccessibility: Story = {
154
+ parameters: {
155
+ controls: { include: [] },
156
+ docs: {
157
+ description: {
158
+ story:
159
+ 'ThemedImage supports all standard Image accessibility props like `accessibilityLabel` and `accessible`.',
160
+ },
161
+ },
162
+ },
163
+ render: () => (
164
+ <Box gap="200">
165
+ <ThemedImage
166
+ // @ts-ignore
167
+ light={<MascotEnergyLight width={150} height={150} />}
168
+ // @ts-ignore
169
+ dark={<MascotEnergyDark width={150} height={150} />}
170
+ accessible={true}
171
+ accessibilityLabel="Energy service mascot illustration"
172
+ />
173
+ </Box>
174
+ ),
175
+ };