@utilitywarehouse/hearth-react-native 0.2.0 → 0.3.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 (187) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-lint.log +1 -1
  3. package/CHANGELOG.md +22 -0
  4. package/build/components/Badge/Badge.js +101 -14
  5. package/build/components/Badge/Badge.props.d.ts +2 -2
  6. package/build/components/Badge/BadgeIcon.js +5 -79
  7. package/build/components/Badge/BadgeText.js +7 -81
  8. package/build/components/Button/Button.d.ts +2 -2
  9. package/build/components/Button/ButtonGroupRoot.d.ts +3 -2
  10. package/build/components/Button/ButtonGroupRoot.js +9 -0
  11. package/build/components/Card/Card.props.d.ts +2 -2
  12. package/build/components/CurrencyInput/CurrencyInput.d.ts +6 -0
  13. package/build/components/CurrencyInput/CurrencyInput.js +47 -0
  14. package/build/components/CurrencyInput/CurrencyInput.props.d.ts +14 -0
  15. package/build/components/CurrencyInput/CurrencyInput.props.js +1 -0
  16. package/build/components/CurrencyInput/index.d.ts +1 -0
  17. package/build/components/CurrencyInput/index.js +1 -0
  18. package/build/components/DescriptionList/DescriptionList.context.d.ts +6 -0
  19. package/build/components/DescriptionList/DescriptionList.context.js +9 -0
  20. package/build/components/DescriptionList/DescriptionList.d.ts +6 -0
  21. package/build/components/DescriptionList/DescriptionList.js +25 -0
  22. package/build/components/DescriptionList/DescriptionList.props.d.ts +18 -0
  23. package/build/components/DescriptionList/DescriptionList.props.js +1 -0
  24. package/build/components/DescriptionList/DescriptionListItem.d.ts +6 -0
  25. package/build/components/DescriptionList/DescriptionListItem.js +49 -0
  26. package/build/components/DescriptionList/DescriptionListItem.props.d.ts +17 -0
  27. package/build/components/DescriptionList/DescriptionListItem.props.js +1 -0
  28. package/build/components/DescriptionList/index.d.ts +4 -0
  29. package/build/components/DescriptionList/index.js +2 -0
  30. package/build/components/Divider/Divider.js +46 -0
  31. package/build/components/Divider/Divider.props.d.ts +2 -2
  32. package/build/components/Flex/Flex.props.d.ts +3 -2
  33. package/build/components/Grid/Grid.props.d.ts +2 -2
  34. package/build/components/IconContainer/IconContainer.d.ts +5 -0
  35. package/build/components/IconContainer/IconContainer.js +161 -0
  36. package/build/components/IconContainer/IconContainer.props.d.ts +15 -0
  37. package/build/components/IconContainer/IconContainer.props.js +1 -0
  38. package/build/components/IconContainer/index.d.ts +2 -0
  39. package/build/components/IconContainer/index.js +1 -0
  40. package/build/components/Icons/CircleIcon.js +3 -3
  41. package/build/components/Input/Input.js +2 -34
  42. package/build/components/Input/Input.props.d.ts +1 -17
  43. package/build/components/Input/InputField.js +0 -7
  44. package/build/components/Modal/Modal.js +17 -1
  45. package/build/components/SectionHeader/SectionHeader.js +1 -0
  46. package/build/components/Tabs/Tab.d.ts +18 -0
  47. package/build/components/Tabs/Tab.js +74 -0
  48. package/build/components/Tabs/Tab.props.d.ts +14 -0
  49. package/build/components/Tabs/Tab.props.js +1 -0
  50. package/build/components/Tabs/TabPanel.d.ts +3 -0
  51. package/build/components/Tabs/TabPanel.js +34 -0
  52. package/build/components/Tabs/TabPanel.props.d.ts +8 -0
  53. package/build/components/Tabs/TabPanel.props.js +1 -0
  54. package/build/components/Tabs/Tabs.context.d.ts +23 -0
  55. package/build/components/Tabs/Tabs.context.js +8 -0
  56. package/build/components/Tabs/Tabs.d.ts +6 -0
  57. package/build/components/Tabs/Tabs.js +114 -0
  58. package/build/components/Tabs/Tabs.props.d.ts +19 -0
  59. package/build/components/Tabs/Tabs.props.js +1 -0
  60. package/build/components/Tabs/TabsList.d.ts +6 -0
  61. package/build/components/Tabs/TabsList.js +112 -0
  62. package/build/components/Tabs/TabsList.props.d.ts +6 -0
  63. package/build/components/Tabs/TabsList.props.js +1 -0
  64. package/build/components/Tabs/index.d.ts +8 -0
  65. package/build/components/Tabs/index.js +4 -0
  66. package/build/components/index.d.ts +4 -0
  67. package/build/components/index.js +4 -0
  68. package/build/core/themes.d.ts +416 -148
  69. package/build/core/themes.js +57 -1
  70. package/build/tokens/color.d.ts +76 -68
  71. package/build/tokens/color.js +38 -34
  72. package/build/tokens/components/dark/button.d.ts +1 -0
  73. package/build/tokens/components/dark/button.js +1 -0
  74. package/build/tokens/components/dark/checkbox.d.ts +1 -1
  75. package/build/tokens/components/dark/checkbox.js +1 -1
  76. package/build/tokens/components/dark/icon-button.d.ts +3 -3
  77. package/build/tokens/components/dark/icon-button.js +3 -3
  78. package/build/tokens/components/dark/radio.d.ts +1 -1
  79. package/build/tokens/components/dark/radio.js +1 -1
  80. package/build/tokens/components/dark/tabs.d.ts +2 -0
  81. package/build/tokens/components/dark/tabs.js +2 -0
  82. package/build/tokens/components/light/badge.d.ts +1 -1
  83. package/build/tokens/components/light/badge.js +1 -1
  84. package/build/tokens/components/light/button.d.ts +1 -0
  85. package/build/tokens/components/light/button.js +1 -0
  86. package/build/tokens/components/light/checkbox.d.ts +3 -3
  87. package/build/tokens/components/light/checkbox.js +3 -3
  88. package/build/tokens/components/light/icon-button.d.ts +1 -1
  89. package/build/tokens/components/light/icon-button.js +1 -1
  90. package/build/tokens/components/light/radio.d.ts +3 -3
  91. package/build/tokens/components/light/radio.js +3 -3
  92. package/build/tokens/components/light/tabs.d.ts +2 -0
  93. package/build/tokens/components/light/tabs.js +2 -0
  94. package/build/tokens/layout.d.ts +48 -30
  95. package/build/tokens/layout.js +24 -15
  96. package/build/tokens/semantic-dark.d.ts +21 -19
  97. package/build/tokens/semantic-dark.js +21 -19
  98. package/build/tokens/semantic-light.d.ts +17 -15
  99. package/build/tokens/semantic-light.js +17 -15
  100. package/build/types/values.d.ts +2 -1
  101. package/build/utils/formatThousands.d.ts +2 -0
  102. package/build/utils/formatThousands.js +16 -0
  103. package/build/utils/index.d.ts +1 -0
  104. package/build/utils/index.js +1 -0
  105. package/docs/components/AllComponents.web.tsx +97 -8
  106. package/docs/components/NextPrevPage.tsx +11 -3
  107. package/docs/components/UsageWrap.tsx +2 -2
  108. package/docs/heplers/addReactNativePrefix.ts +8 -0
  109. package/docs/heplers/index.ts +1 -0
  110. package/docs/theme-tokens.mdx +42 -0
  111. package/package.json +2 -3
  112. package/src/components/Badge/Badge.docs.mdx +7 -7
  113. package/src/components/Badge/Badge.props.ts +3 -2
  114. package/src/components/Badge/Badge.stories.tsx +81 -92
  115. package/src/components/Badge/Badge.tsx +101 -14
  116. package/src/components/Badge/BadgeIcon.tsx +5 -79
  117. package/src/components/Badge/BadgeText.tsx +7 -81
  118. package/src/components/Button/ButtonGroupRoot.tsx +12 -2
  119. package/src/components/Card/Card.docs.mdx +1 -1
  120. package/src/components/Card/Card.props.ts +2 -2
  121. package/src/components/CurrencyInput/CurrencyInput.docs.mdx +120 -0
  122. package/src/components/CurrencyInput/CurrencyInput.props.ts +19 -0
  123. package/src/components/CurrencyInput/CurrencyInput.stories.tsx +116 -0
  124. package/src/components/CurrencyInput/CurrencyInput.tsx +91 -0
  125. package/src/components/CurrencyInput/index.ts +1 -0
  126. package/src/components/DescriptionList/DescriptionList.context.ts +18 -0
  127. package/src/components/DescriptionList/DescriptionList.docs.mdx +98 -0
  128. package/src/components/DescriptionList/DescriptionList.props.ts +20 -0
  129. package/src/components/DescriptionList/DescriptionList.stories.tsx +154 -0
  130. package/src/components/DescriptionList/DescriptionList.tsx +64 -0
  131. package/src/components/DescriptionList/DescriptionListItem.props.ts +19 -0
  132. package/src/components/DescriptionList/DescriptionListItem.tsx +101 -0
  133. package/src/components/DescriptionList/index.ts +4 -0
  134. package/src/components/Divider/Divider.props.ts +2 -2
  135. package/src/components/Divider/Divider.stories.tsx +3 -3
  136. package/src/components/Divider/Divider.tsx +46 -0
  137. package/src/components/Flex/Flex.docs.mdx +4 -4
  138. package/src/components/Flex/Flex.props.ts +3 -2
  139. package/src/components/Flex/Flex.stories.tsx +1 -1
  140. package/src/components/Grid/Grid.docs.mdx +12 -12
  141. package/src/components/Grid/Grid.props.ts +2 -2
  142. package/src/components/Grid/Grid.stories.tsx +2 -2
  143. package/src/components/IconContainer/IconContainer.docs.mdx +90 -0
  144. package/src/components/IconContainer/IconContainer.props.ts +17 -0
  145. package/src/components/IconContainer/IconContainer.stories.tsx +130 -0
  146. package/src/components/IconContainer/IconContainer.tsx +180 -0
  147. package/src/components/IconContainer/index.tsx +2 -0
  148. package/src/components/Icons/CircleIcon.tsx +9 -11
  149. package/src/components/Input/Input.docs.mdx +3 -3
  150. package/src/components/Input/Input.props.ts +0 -20
  151. package/src/components/Input/Input.stories.tsx +0 -6
  152. package/src/components/Input/Input.tsx +2 -49
  153. package/src/components/Input/InputField.tsx +0 -7
  154. package/src/components/Modal/Modal.tsx +18 -0
  155. package/src/components/SectionHeader/SectionHeader.tsx +1 -0
  156. package/src/components/Tabs/Tab.props.ts +16 -0
  157. package/src/components/Tabs/Tab.tsx +113 -0
  158. package/src/components/Tabs/TabPanel.props.ts +10 -0
  159. package/src/components/Tabs/TabPanel.tsx +46 -0
  160. package/src/components/Tabs/Tabs.context.ts +26 -0
  161. package/src/components/Tabs/Tabs.docs.mdx +214 -0
  162. package/src/components/Tabs/Tabs.props.ts +21 -0
  163. package/src/components/Tabs/Tabs.stories.tsx +270 -0
  164. package/src/components/Tabs/Tabs.tsx +139 -0
  165. package/src/components/Tabs/TabsList.props.ts +8 -0
  166. package/src/components/Tabs/TabsList.tsx +194 -0
  167. package/src/components/Tabs/index.ts +8 -0
  168. package/src/components/index.ts +4 -0
  169. package/src/core/themes.ts +57 -1
  170. package/src/tokens/color.ts +38 -34
  171. package/src/tokens/components/dark/button.ts +1 -0
  172. package/src/tokens/components/dark/checkbox.ts +1 -1
  173. package/src/tokens/components/dark/icon-button.ts +3 -3
  174. package/src/tokens/components/dark/radio.ts +1 -1
  175. package/src/tokens/components/dark/tabs.ts +2 -0
  176. package/src/tokens/components/light/badge.ts +1 -1
  177. package/src/tokens/components/light/button.ts +1 -0
  178. package/src/tokens/components/light/checkbox.ts +3 -3
  179. package/src/tokens/components/light/icon-button.ts +1 -1
  180. package/src/tokens/components/light/radio.ts +3 -3
  181. package/src/tokens/components/light/tabs.ts +2 -0
  182. package/src/tokens/layout.ts +24 -15
  183. package/src/tokens/semantic-dark.ts +21 -19
  184. package/src/tokens/semantic-light.ts +17 -15
  185. package/src/types/values.ts +3 -1
  186. package/src/utils/formatThousands.ts +14 -0
  187. package/src/utils/index.ts +1 -0
@@ -0,0 +1,154 @@
1
+ import { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { DescriptionList, DescriptionListItem } from '.';
3
+ import { VariantTitle } from '../../../docs/components';
4
+ import { Flex } from '../Flex';
5
+
6
+ const meta: Meta<typeof DescriptionList> = {
7
+ title: 'Stories / DescriptionList',
8
+ component: DescriptionList,
9
+ parameters: { layout: 'centered' },
10
+ argTypes: {
11
+ direction: {
12
+ control: 'select',
13
+ options: ['row', 'column'],
14
+ description: 'Orientation of heading & description pairs',
15
+ },
16
+ itemHeadingWidth: {
17
+ control: 'number',
18
+ description: 'Override width (px) for heading column when direction is row',
19
+ },
20
+ heading: {
21
+ control: 'text',
22
+ description:
23
+ 'Optional overall heading (renders a SectionHeader). Playground only – prefer SectionHeader directly when composing.',
24
+ },
25
+ helperText: {
26
+ control: 'text',
27
+ description: 'Supporting text shown under heading (Playground only).',
28
+ },
29
+ linkText: { control: 'text', description: 'Header link text (Playground only).' },
30
+ linkHref: { control: 'text', description: 'Header link href (web).' },
31
+ linkIconPosition: {
32
+ control: 'select',
33
+ options: ['left', 'right'],
34
+ description: 'Header link icon position.',
35
+ },
36
+ linkShowIcon: { control: 'boolean', description: 'Show header link icon.' },
37
+ linkTarget: {
38
+ control: 'select',
39
+ options: ['_blank', '_self', '_parent', '_top'],
40
+ description: 'Header link target (web).',
41
+ },
42
+ },
43
+ args: {
44
+ direction: 'column',
45
+ heading: 'Account details',
46
+ helperText: 'Static account metadata',
47
+ },
48
+ };
49
+
50
+ export default meta;
51
+ type Story = StoryObj<typeof meta>;
52
+
53
+ const sampleData = [
54
+ { heading: 'Account Number', description: '123456789' },
55
+ { heading: 'Sort Code', description: '12-34-56' },
56
+ { heading: 'Status', description: 'Active' },
57
+ ];
58
+
59
+ export const Playground: Story = {
60
+ render: args => (
61
+ <DescriptionList {...args}>
62
+ {sampleData.map(item => (
63
+ <DescriptionListItem
64
+ key={item.heading}
65
+ heading={item.heading}
66
+ description={item.description}
67
+ />
68
+ ))}
69
+ </DescriptionList>
70
+ ),
71
+ };
72
+
73
+ export const Row: Story = {
74
+ args: { direction: 'row' },
75
+ render: args => (
76
+ <DescriptionList {...args}>
77
+ {sampleData.map(item => (
78
+ <DescriptionListItem
79
+ key={item.heading}
80
+ heading={item.heading}
81
+ description={item.description}
82
+ />
83
+ ))}
84
+ </DescriptionList>
85
+ ),
86
+ };
87
+
88
+ export const Column: Story = {
89
+ args: { direction: 'column' },
90
+ render: args => (
91
+ <DescriptionList {...args}>
92
+ {sampleData.map(item => (
93
+ <DescriptionListItem
94
+ key={item.heading}
95
+ heading={item.heading}
96
+ description={item.description}
97
+ />
98
+ ))}
99
+ </DescriptionList>
100
+ ),
101
+ };
102
+
103
+ export const KitchenSink: Story = {
104
+ parameters: { controls: { include: [] } },
105
+ render: () => (
106
+ <Flex direction="column" space="lg" style={{ width: '100%' }}>
107
+ <VariantTitle title="Row direction">
108
+ <DescriptionList direction="row">
109
+ {sampleData.map(item => (
110
+ <DescriptionListItem
111
+ key={item.heading}
112
+ heading={item.heading}
113
+ description={item.description}
114
+ />
115
+ ))}
116
+ </DescriptionList>
117
+ </VariantTitle>
118
+ <VariantTitle title="Column direction">
119
+ <DescriptionList direction="column">
120
+ {sampleData.map(item => (
121
+ <DescriptionListItem
122
+ key={item.heading}
123
+ heading={item.heading}
124
+ description={item.description}
125
+ />
126
+ ))}
127
+ </DescriptionList>
128
+ </VariantTitle>
129
+ </Flex>
130
+ ),
131
+ };
132
+
133
+ export const WithLinks: Story = {
134
+ parameters: { controls: { include: ['direction', 'itemHeadingWidth'] } },
135
+ args: { direction: 'row' },
136
+ render: args => (
137
+ <DescriptionList {...args}>
138
+ <DescriptionListItem
139
+ heading="Account Number"
140
+ description="123456789"
141
+ linkText="Manage"
142
+ linkHref="https://example.com/account"
143
+ linkShowIcon
144
+ />
145
+ <DescriptionListItem
146
+ heading="Status"
147
+ description="Active"
148
+ linkText="Change"
149
+ linkHref="https://example.com/status"
150
+ />
151
+ <DescriptionListItem heading="Region" description="United Kingdom" />
152
+ </DescriptionList>
153
+ ),
154
+ };
@@ -0,0 +1,64 @@
1
+ import { useMemo } from 'react';
2
+ import { View } from 'react-native';
3
+ import { StyleSheet } from 'react-native-unistyles';
4
+ import { SectionHeader } from '../SectionHeader';
5
+ import { DescriptionListContext } from './DescriptionList.context';
6
+ import type DescriptionListProps from './DescriptionList.props';
7
+
8
+ const DescriptionList = ({
9
+ direction = 'column',
10
+ itemHeadingWidth,
11
+ heading,
12
+ helperText,
13
+ linkText,
14
+ linkHref,
15
+ linkIcon,
16
+ linkIconPosition,
17
+ linkOnPress,
18
+ linkTarget,
19
+ linkShowIcon,
20
+ children,
21
+ style,
22
+ ...props
23
+ }: DescriptionListProps) => {
24
+ styles.useVariants({ direction });
25
+ const value = useMemo(() => ({ direction, itemHeadingWidth }), [direction, itemHeadingWidth]);
26
+
27
+ return (
28
+ <DescriptionListContext.Provider value={value}>
29
+ <View accessibilityRole="list" {...props} style={[styles.container, style]}>
30
+ {heading ? (
31
+ <SectionHeader
32
+ heading={heading}
33
+ helperText={helperText}
34
+ linkText={linkText}
35
+ linkHref={linkHref}
36
+ linkIcon={linkIcon}
37
+ linkIconPosition={linkIconPosition}
38
+ linkOnPress={linkOnPress}
39
+ linkTarget={linkTarget}
40
+ linkShowIcon={linkShowIcon}
41
+ />
42
+ ) : null}
43
+ {children}
44
+ </View>
45
+ </DescriptionListContext.Provider>
46
+ );
47
+ };
48
+
49
+ DescriptionList.displayName = 'DescriptionList';
50
+
51
+ const styles = StyleSheet.create(theme => ({
52
+ container: {
53
+ width: theme.space.full,
54
+ gap: theme.components.descriptionList.gap,
55
+ variants: {
56
+ direction: {
57
+ row: {},
58
+ column: {},
59
+ },
60
+ },
61
+ },
62
+ }));
63
+
64
+ export default DescriptionList;
@@ -0,0 +1,19 @@
1
+ import type { ComponentType, ReactNode } from 'react';
2
+ import type { ViewProps } from 'react-native';
3
+
4
+ export interface DescriptionListItemProps extends ViewProps {
5
+ /** Heading / label part */
6
+ heading: ReactNode;
7
+ /** Description / value part */
8
+ description: ReactNode;
9
+ headingWidth?: number;
10
+ linkText?: string;
11
+ linkHref?: string;
12
+ linkIcon?: ComponentType;
13
+ linkIconPosition?: 'left' | 'right';
14
+ linkOnPress?: () => void;
15
+ linkTarget?: '_blank' | '_self' | '_parent' | '_top';
16
+ linkShowIcon?: boolean;
17
+ }
18
+
19
+ export default DescriptionListItemProps;
@@ -0,0 +1,101 @@
1
+ import { View } from 'react-native';
2
+ import { StyleSheet } from 'react-native-unistyles';
3
+ import { useTheme } from '../../hooks';
4
+ import { BodyText } from '../BodyText';
5
+ import { Link } from '../Link';
6
+ import { useDescriptionListContext } from './DescriptionList.context';
7
+ import type DescriptionListItemProps from './DescriptionListItem.props';
8
+
9
+ const DescriptionListItem = ({
10
+ heading,
11
+ description,
12
+ headingWidth,
13
+ linkText,
14
+ linkHref,
15
+ linkIcon,
16
+ linkIconPosition,
17
+ linkOnPress,
18
+ linkTarget,
19
+ linkShowIcon,
20
+ style,
21
+ ...props
22
+ }: DescriptionListItemProps) => {
23
+ const { components } = useTheme();
24
+ const { direction, itemHeadingWidth = components.descriptionList.item.row.headingWidth } =
25
+ useDescriptionListContext();
26
+ styles.useVariants({ direction });
27
+ const headingIsText = typeof heading === 'string' || typeof heading === 'number';
28
+ const descIsText = typeof description === 'string' || typeof description === 'number';
29
+ const combinedLabel = headingIsText && descIsText ? `${heading}: ${description}` : undefined;
30
+ const hideDescendants = !!combinedLabel;
31
+ return (
32
+ <View
33
+ accessibilityRole="text"
34
+ accessible={!!combinedLabel}
35
+ accessibilityLabel={combinedLabel}
36
+ {...props}
37
+ style={[styles.item, style]}
38
+ >
39
+ <View
40
+ style={styles.textWrap}
41
+ importantForAccessibility={hideDescendants ? 'no-hide-descendants' : undefined}
42
+ accessibilityElementsHidden={hideDescendants || undefined}
43
+ >
44
+ <View style={[direction === 'row' && { width: headingWidth || itemHeadingWidth }]}>
45
+ {headingIsText ? <BodyText style={styles.headingText}>{heading}</BodyText> : heading}
46
+ </View>
47
+ <View style={styles.descriptionWrapper}>
48
+ {descIsText ? <BodyText>{description}</BodyText> : description}
49
+ </View>
50
+ </View>
51
+ {linkText ? (
52
+ <Link
53
+ href={linkHref}
54
+ onPress={linkOnPress}
55
+ target={linkTarget}
56
+ showIcon={linkShowIcon}
57
+ icon={linkIcon}
58
+ iconPosition={linkIconPosition}
59
+ accessibilityRole="link"
60
+ >
61
+ {linkText}
62
+ </Link>
63
+ ) : null}
64
+ </View>
65
+ );
66
+ };
67
+
68
+ DescriptionListItem.displayName = 'DescriptionListItem';
69
+
70
+ const styles = StyleSheet.create(theme => ({
71
+ item: {
72
+ width: theme.space.full,
73
+ flexDirection: 'row',
74
+ alignItems: 'flex-start',
75
+ gap: theme.components.descriptionList.item.gap,
76
+ },
77
+ textWrap: {
78
+ flex: 1,
79
+ variants: {
80
+ direction: {
81
+ row: {
82
+ flexDirection: 'row',
83
+ alignItems: 'flex-start',
84
+ gap: theme.components.descriptionList.item.row.gap,
85
+ },
86
+ column: {
87
+ flexDirection: 'column',
88
+ gap: theme.components.descriptionList.item.column.gap,
89
+ },
90
+ },
91
+ },
92
+ },
93
+ headingText: {
94
+ color: theme.color.text.secondary,
95
+ },
96
+ descriptionWrapper: {
97
+ flex: 1,
98
+ },
99
+ }));
100
+
101
+ export default DescriptionListItem;
@@ -0,0 +1,4 @@
1
+ export { default as DescriptionList } from './DescriptionList';
2
+ export type { default as DescriptionListProps } from './DescriptionList.props';
3
+ export { default as DescriptionListItem } from './DescriptionListItem';
4
+ export type { default as DescriptionListItemProps } from './DescriptionListItem.props';
@@ -1,9 +1,9 @@
1
1
  import type { DimensionValue, ViewProps } from 'react-native';
2
- import type { ColorValue } from '../../types';
2
+ import type { ColorValue, SpacingValues } from '../../types';
3
3
 
4
4
  interface DividerProps extends Omit<ViewProps, 'children'> {
5
5
  color?: ColorValue;
6
- space?: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
6
+ space?: SpacingValues;
7
7
  orientation?: 'horizontal' | 'vertical';
8
8
  height?: DimensionValue;
9
9
  width?: DimensionValue;
@@ -1,7 +1,7 @@
1
- import { Divider } from '.';
2
1
  import { Meta, StoryObj } from '@storybook/react-vite';
3
- import { Box } from '../Box';
2
+ import { Divider } from '.';
4
3
  import { coloursAsArray } from '../../utils';
4
+ import { Box } from '../Box';
5
5
 
6
6
  const meta = {
7
7
  title: 'Stories / Divider',
@@ -21,7 +21,7 @@ const meta = {
21
21
  description: 'Color of the divider',
22
22
  },
23
23
  space: {
24
- options: ['none', 'xs', 'sm', 'md', 'lg', 'xl'],
24
+ options: ['none', '2xs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl'],
25
25
  control: 'select',
26
26
  description: 'Space between the divider',
27
27
  },
@@ -44,11 +44,13 @@ const styles = StyleSheet.create(theme => ({
44
44
  },
45
45
  space: {
46
46
  none: {},
47
+ '2xs': {},
47
48
  xs: {},
48
49
  sm: {},
49
50
  md: {},
50
51
  lg: {},
51
52
  xl: {},
53
+ '2xl': {},
52
54
  },
53
55
  flexItem: {
54
56
  true: {
@@ -64,6 +66,17 @@ const styles = StyleSheet.create(theme => ({
64
66
  marginVertical: 0,
65
67
  },
66
68
  },
69
+ {
70
+ orientation: 'horizontal',
71
+ space: '2xs',
72
+ styles: {
73
+ marginVertical: {
74
+ base: theme.layout.mobile.spacing['2xs'],
75
+ md: theme.layout.tablet.spacing['2xs'],
76
+ lg: theme.layout.desktop.spacing['2xs'],
77
+ },
78
+ },
79
+ },
67
80
  {
68
81
  orientation: 'horizontal',
69
82
  space: 'xs',
@@ -119,6 +132,17 @@ const styles = StyleSheet.create(theme => ({
119
132
  },
120
133
  },
121
134
  },
135
+ {
136
+ orientation: 'horizontal',
137
+ space: '2xl',
138
+ styles: {
139
+ marginVertical: {
140
+ base: theme.layout.mobile.spacing['2xl'],
141
+ md: theme.layout.tablet.spacing['2xl'],
142
+ lg: theme.layout.desktop.spacing['2xl'],
143
+ },
144
+ },
145
+ },
122
146
  {
123
147
  orientation: 'vertical',
124
148
  space: 'none',
@@ -126,6 +150,17 @@ const styles = StyleSheet.create(theme => ({
126
150
  marginHorizontal: 0,
127
151
  },
128
152
  },
153
+ {
154
+ orientation: 'vertical',
155
+ space: '2xs',
156
+ styles: {
157
+ marginHorizontal: {
158
+ base: theme.layout.mobile.spacing['2xs'],
159
+ md: theme.layout.tablet.spacing['2xs'],
160
+ lg: theme.layout.desktop.spacing['2xs'],
161
+ },
162
+ },
163
+ },
129
164
  {
130
165
  orientation: 'vertical',
131
166
  space: 'xs',
@@ -181,6 +216,17 @@ const styles = StyleSheet.create(theme => ({
181
216
  },
182
217
  },
183
218
  },
219
+ {
220
+ orientation: 'vertical',
221
+ space: '2xl',
222
+ styles: {
223
+ marginHorizontal: {
224
+ base: theme.layout.mobile.spacing['2xl'],
225
+ md: theme.layout.tablet.spacing['2xl'],
226
+ lg: theme.layout.desktop.spacing['2xl'],
227
+ },
228
+ },
229
+ },
184
230
  ],
185
231
  },
186
232
  extraStyles: (color, width, height) => ({
@@ -1,7 +1,7 @@
1
- import { Meta, Canvas, Story, Controls, Primary } from '@storybook/addon-docs/blocks';
1
+ import { Canvas, Controls, Meta, Primary, Story } from '@storybook/addon-docs/blocks';
2
+ import { BodyText, Center, Flex, Pressable } from '../..';
3
+ import { BackToTopButton, UsageWrap, ViewFigmaButton } from '../../../docs/components';
2
4
  import * as Stories from './Flex.stories';
3
- import { Center, Pressable, Flex, BodyText } from '../..';
4
- import { UsageWrap, BackToTopButton, ViewFigmaButton } from '../../../docs/components';
5
5
 
6
6
  <Meta title="Primitives / Flex" />
7
7
 
@@ -57,4 +57,4 @@ const MyComponent = () => (
57
57
  | `wrap` | `'wrap' \| 'nowrap' \| 'wrap-reverse'` | `nowrap` | The wrap of the flex container. |
58
58
  | `justify` | `'flex-start' \| 'flex-end' \| 'center' \| `<br />`'space-between' \| 'space-around' \| 'space-evenly'` | `flex-start` | The justify content of the flex container. |
59
59
  | `align` | `'flex-start' \| 'flex-end' \| 'center' \| 'stretch' \| 'baseline'` | `flex-start` | The align items of the flex container. |
60
- | `space` | `'none' \| 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `md` | The space between the content. |
60
+ | `space` | `'none' \| '2xs' \| 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl'` | `md` | The space between the content. |
@@ -1,11 +1,12 @@
1
- import type { ViewProps, ViewStyle, FlexAlignType } from 'react-native';
1
+ import type { FlexAlignType, ViewProps, ViewStyle } from 'react-native';
2
+ import { SpacingValues } from '../../types';
2
3
 
3
4
  interface FlexProps extends ViewProps {
4
5
  direction?: ViewStyle['flexDirection'];
5
6
  align?: FlexAlignType;
6
7
  justify?: ViewStyle['justifyContent'];
7
8
  wrap?: ViewStyle['flexWrap'];
8
- space?: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
9
+ space?: SpacingValues;
9
10
  }
10
11
 
11
12
  export default FlexProps;
@@ -40,7 +40,7 @@ const meta = {
40
40
  description: 'The justify of the flex container.',
41
41
  },
42
42
  space: {
43
- options: ['none', 'xs', 'sm', 'md', 'lg', 'xl'],
43
+ options: ['none', '2xs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl'],
44
44
  control: 'radio',
45
45
  description: 'The space of the flex container.',
46
46
  },
@@ -1,7 +1,7 @@
1
- import { Meta, Canvas, Story, Controls, Primary } from '@storybook/addon-docs/blocks';
1
+ import { Canvas, Controls, Meta, Primary, Story } from '@storybook/addon-docs/blocks';
2
+ import { BodyText, Box, Center, Grid } from '../..';
3
+ import { BackToTopButton, UsageWrap, ViewFigmaButton } from '../../../docs/components';
2
4
  import * as Stories from './Grid.stories';
3
- import { Center, Grid, Box, BodyText } from '../..';
4
- import { UsageWrap, BackToTopButton, ViewFigmaButton } from '../../../docs/components';
5
5
 
6
6
  <Meta title="Primitives / Grid" />
7
7
 
@@ -173,15 +173,15 @@ const MyComponent = () => (
173
173
 
174
174
  The Grid component extends all the props from the [View component](https://reactnative.dev/docs/view), and adds the following:
175
175
 
176
- | Name | Type | Default | Description |
177
- | ---------------- | ------------------------------------------------ | ------- | ------------------------------------------------------------- |
178
- | `columns` | `number` or `GridColumns` | 2 | Number of columns or responsive object with breakpoint values |
179
- | `space` | `'none' \| 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | - | Spacing between grid items (both rows and columns) |
180
- | `columnGap` | `number` | - | Gap between columns (overrides spacing if provided) |
181
- | `rowGap` | `number` | - | Gap between rows (overrides spacing if provided) |
182
- | `containerStyle` | `StyleProp\<ViewStyle\>` | - | Style for the grid container |
183
- | `itemStyle` | `StyleProp\<ViewStyle\>` | - | Style applied to each grid item |
184
- | `rowStyle` | `StyleProp\<ViewStyle\>` | - | Style applied to each row |
176
+ | Name | Type | Default | Description |
177
+ | ---------------- | ------------------------------------------------------------------ | ------- | ------------------------------------------------------------- |
178
+ | `columns` | `number` or `GridColumns` | 2 | Number of columns or responsive object with breakpoint values |
179
+ | `space` | `'none' \| '2xs' \| 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl'` | - | Spacing between grid items (both rows and columns) |
180
+ | `columnGap` | `number` | - | Gap between columns (overrides spacing if provided) |
181
+ | `rowGap` | `number` | - | Gap between rows (overrides spacing if provided) |
182
+ | `containerStyle` | `StyleProp\<ViewStyle\>` | - | Style for the grid container |
183
+ | `itemStyle` | `StyleProp\<ViewStyle\>` | - | Style applied to each grid item |
184
+ | `rowStyle` | `StyleProp\<ViewStyle\>` | - | Style applied to each row |
185
185
 
186
186
  Where `GridColumns` is defined as:
187
187
 
@@ -1,6 +1,6 @@
1
1
  import { StyleProp, ViewProps, ViewStyle } from 'react-native';
2
2
  import { UnistylesBreakpoints } from 'react-native-unistyles';
3
- import { SpaceValue } from '../../types';
3
+ import { SpaceValue, SpacingValues } from '../../types';
4
4
 
5
5
  // Create a type that uses the keys from our breakpoints object
6
6
  export type GridColumns = {
@@ -17,7 +17,7 @@ export interface GridProps extends ViewProps {
17
17
  /**
18
18
  * Spacing between grid items (applies to both rows and columns)
19
19
  */
20
- space?: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
20
+ space?: SpacingValues;
21
21
 
22
22
  /**
23
23
  * Gap between items (overrides spacing if provided)
@@ -1,5 +1,5 @@
1
1
  import { Meta, StoryObj } from '@storybook/react-vite';
2
- import { View, Text } from 'react-native';
2
+ import { Text, View } from 'react-native';
3
3
  import { Grid } from '.';
4
4
 
5
5
  const meta = {
@@ -14,7 +14,7 @@ const meta = {
14
14
  description: 'Number of columns or responsive object with breakpoints',
15
15
  },
16
16
  space: {
17
- options: ['none', 'xs', 'sm', 'md', 'lg', 'xl'],
17
+ options: ['none', '2xs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl'],
18
18
  control: 'radio',
19
19
  description: 'Responsive spacing between grid items (applied to both rows and columns).',
20
20
  },
@@ -0,0 +1,90 @@
1
+ import { Canvas, Controls, Meta, Story } from '@storybook/addon-docs/blocks';
2
+ import {
3
+ BroadbandMediumIcon,
4
+ CashbackCardMediumIcon,
5
+ ConfettiMediumIcon,
6
+ ElectricityMediumIcon,
7
+ InsuranceMediumIcon,
8
+ MobileMediumIcon,
9
+ } from '@utilitywarehouse/hearth-react-native-icons';
10
+ import { Center, Flex, IconContainer } from '../../';
11
+ import { BackToTopButton, UsageWrap } from '../../../docs/components';
12
+ import * as Stories from './IconContainer.stories';
13
+
14
+ <BackToTopButton />
15
+
16
+ <Meta title="Components / Icon Container" />
17
+
18
+ # Icon Container
19
+
20
+ The `IconContainer` component provides a consistent background and sizing (via component tokens) for any standalone icon, with semantic colour families and subtle/emphasis variants.
21
+
22
+ - [Playground](#playground)
23
+ - [Usage](#usage)
24
+ - [Props](#props)
25
+ - [Variants](#variants)
26
+
27
+ ## Playground
28
+
29
+ <Canvas of={Stories.Playground} />
30
+
31
+ <Controls of={Stories.Playground} />
32
+
33
+ ## Usage
34
+
35
+ Wrap an icon with the `IconContainer` to apply sizing + background styles without repeating layout code.
36
+
37
+ <UsageWrap>
38
+ <Center>
39
+ <Flex direction="row" space="lg" alignItems="center">
40
+ <IconContainer icon={ElectricityMediumIcon} size="md" variant="emphasis" color="energy" />
41
+ <IconContainer icon={BroadbandMediumIcon} size="md" variant="emphasis" color="broadband" />
42
+ <IconContainer icon={MobileMediumIcon} size="md" variant="emphasis" color="mobile" />
43
+ <IconContainer icon={InsuranceMediumIcon} size="md" variant="emphasis" color="insurance" />
44
+ <IconContainer icon={CashbackCardMediumIcon} size="md" variant="emphasis" color="cashback" />
45
+ <IconContainer icon={ConfettiMediumIcon} size="md" variant="emphasis" color="pig" />
46
+ </Flex>
47
+ </Center>
48
+ </UsageWrap>
49
+
50
+ ```jsx
51
+ import { IconContainer } from '@utilitywarehouse/hearth-react-native';
52
+ import {
53
+ ElectricityMediumIcon,
54
+ BroadbandMediumIcon,
55
+ MobileMediumIcon,
56
+ InsuranceMediumIcon,
57
+ CashbackCardMediumIcon,
58
+ ConfettiMediumIcon,
59
+ } from '@utilitywarehouse/hearth-react-native-icons';
60
+
61
+ const MyComponent = () => (
62
+ <>
63
+ <IconContainer icon={ElectricityMediumIcon} size="md" variant="emphasis" color="energy" />
64
+ <IconContainer icon={BroadbandMediumIcon} size="md" variant="emphasis" color="broadband" />
65
+ <IconContainer icon={MobileMediumIcon} size="md" variant="emphasis" color="mobile" />
66
+ <IconContainer icon={InsuranceMediumIcon} size="md" variant="emphasis" color="insurance" />
67
+ <IconContainer icon={CashbackCardMediumIcon} size="md" variant="emphasis" color="cashback" />
68
+ <IconContainer icon={ConfettiMediumIcon} size="md" variant="emphasis" color="pig" />
69
+ </>
70
+ );
71
+ ```
72
+
73
+ ## Props
74
+
75
+ | Name | Type | Description | Default |
76
+ | ------------ | -------------------------------------------------------------------------------------------------- | ----------------------------------------------- | ---------- |
77
+ | `icon` | `React.ComponentType` | Icon component rendered inside the container | (required) |
78
+ | `size` | `'sm' \| 'md' \| 'lg'` | Size variant (token-based width/height/padding) | `md` |
79
+ | `radiusNone` | `boolean` | Remove border radius (square container) | `false` |
80
+ | `variant` | `'subtle' \| 'emphasis'` | Background emphasis level | `subtle` |
81
+ | `color` | `'pig' \| 'energy' \| 'broadband' \| 'mobile' \|` <br />`'insurance' \| 'cashback' \| 'highlight'` | Semantic colour family for surface tokens | `pig` |
82
+ | `...View` | React Native `ViewProps` | Any additional View props | - |
83
+
84
+ > Colours resolve to `theme.color.surface.<family>.{subtle|default}` depending on variant.
85
+
86
+ ## Variants
87
+
88
+ Use the matrix below to compare every combination of size, variant, and color.
89
+
90
+ <Canvas of={Stories.KitchenSink} />