@utilitywarehouse/hearth-react-native 0.6.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 (179) hide show
  1. package/.storybook/main.ts +12 -6
  2. package/.turbo/turbo-build.log +1 -1
  3. package/.turbo/turbo-lint.log +1 -1
  4. package/CHANGELOG.md +6 -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.js +3 -3
  47. package/build/components/CurrencyInput/CurrencyInput.js +1 -1
  48. package/build/components/Helper/HelperIcon.js +2 -1
  49. package/build/components/Icon/Icon.d.ts +2 -6
  50. package/build/components/IconButton/IconButtonIcon.js +2 -1
  51. package/build/components/IconContainer/IconContainer.d.ts +4 -3
  52. package/build/components/IconContainer/IconContainer.js +3 -3
  53. package/build/components/Input/InputField.js +4 -2
  54. package/build/components/Input/InputIcon.js +2 -1
  55. package/build/components/Link/LinkIcon.js +3 -2
  56. package/build/components/List/ListAction/ListActionTrailingIcon.js +2 -1
  57. package/build/components/List/ListItem/ListItemIcon.js +2 -1
  58. package/build/components/List/ListItem/ListItemTrailingIcon.js +2 -3
  59. package/build/components/Radio/RadioIcon.js +7 -2
  60. package/build/components/RadioCard/RadioCardIcon.js +3 -2
  61. package/build/components/Spinner/Spinner.js +2 -0
  62. package/build/components/Spinner/Spinner.web.js +2 -0
  63. package/build/components/Switch/Switch.js +5 -3
  64. package/build/components/Switch/Switch.web.js +1 -0
  65. package/build/components/Tabs/TabsList.js +6 -1
  66. package/build/components/Textarea/TextareaField.js +1 -1
  67. package/build/components/ToggleButton/ToggleButtonIcon.js +2 -1
  68. package/build/components/ToggleButton/ToggleButtonRoot.js +2 -2
  69. package/build/components/UnstyledIconButton/UnstyledIconButtonIcon.js +2 -1
  70. package/build/components/index.d.ts +1 -1
  71. package/build/components/index.js +1 -1
  72. package/build/core/index.d.ts +3 -3
  73. package/build/core/index.js +3 -3
  74. package/build/core/themes.d.ts +24 -12
  75. package/build/hooks/useColorMode.d.ts +1 -1
  76. package/build/hooks/useColorMode.js +7 -8
  77. package/build/tokens/components/dark/banner.d.ts +19 -0
  78. package/build/tokens/components/dark/banner.js +19 -0
  79. package/build/tokens/components/dark/card-action.d.ts +11 -0
  80. package/build/tokens/components/dark/card-action.js +10 -0
  81. package/build/tokens/components/dark/card-content.d.ts +25 -0
  82. package/build/tokens/components/dark/card-content.js +24 -0
  83. package/build/tokens/components/dark/drawer.d.ts +29 -0
  84. package/build/tokens/components/dark/drawer.js +28 -0
  85. package/build/tokens/components/dark/illustrations.d.ts +0 -1
  86. package/build/tokens/components/dark/illustrations.js +0 -1
  87. package/build/tokens/components/dark/index.d.ts +3 -0
  88. package/build/tokens/components/dark/index.js +3 -0
  89. package/build/tokens/components/light/banner.d.ts +19 -0
  90. package/build/tokens/components/light/banner.js +19 -0
  91. package/build/tokens/components/light/card-action.d.ts +11 -0
  92. package/build/tokens/components/light/card-action.js +10 -0
  93. package/build/tokens/components/light/card-content.d.ts +25 -0
  94. package/build/tokens/components/light/card-content.js +24 -0
  95. package/build/tokens/components/light/drawer.d.ts +29 -0
  96. package/build/tokens/components/light/drawer.js +28 -0
  97. package/build/tokens/components/light/illustrations.d.ts +0 -1
  98. package/build/tokens/components/light/illustrations.js +0 -1
  99. package/build/tokens/components/light/index.d.ts +3 -0
  100. package/build/tokens/components/light/index.js +3 -0
  101. package/build/tokens/layout.d.ts +6 -6
  102. package/build/tokens/layout.js +3 -3
  103. package/build/tokens/typography.d.ts +6 -0
  104. package/build/tokens/typography.js +3 -0
  105. package/docs/components/NextPrevPage.tsx +5 -5
  106. package/docs/components/VariantTitle.tsx +17 -7
  107. package/package.json +16 -14
  108. package/src/components/BottomSheet/BottomSheetBackdrop.tsx +2 -2
  109. package/src/components/BottomSheet/BottomSheetFlatList.tsx +2 -3
  110. package/src/components/BottomSheet/BottomSheetHandle.tsx +1 -1
  111. package/src/components/Button/ButtonIcon.tsx +2 -1
  112. package/src/components/Button/ButtonRoot.tsx +2 -6
  113. package/src/components/Button/ButtonText.tsx +4 -1
  114. package/src/components/Card/Card.context.ts +7 -0
  115. package/src/components/Card/Card.docs.mdx +212 -14
  116. package/src/components/Card/Card.stories.tsx +50 -3
  117. package/src/components/Card/CardAction/CardAction.context.ts +22 -0
  118. package/src/components/Card/CardAction/CardAction.props.ts +87 -0
  119. package/src/components/Card/CardAction/CardAction.stories.tsx +265 -0
  120. package/src/components/Card/CardAction/CardAction.tsx +10 -0
  121. package/src/components/Card/CardAction/CardActionContent.tsx +20 -0
  122. package/src/components/Card/CardAction/CardActionHelperText.tsx +21 -0
  123. package/src/components/Card/CardAction/CardActionIcon.tsx +32 -0
  124. package/src/components/Card/CardAction/CardActionLeadingContent.tsx +9 -0
  125. package/src/components/Card/CardAction/CardActionRoot.tsx +258 -0
  126. package/src/components/Card/CardAction/CardActionText.tsx +17 -0
  127. package/src/components/Card/CardAction/CardActionTrailingContent.tsx +9 -0
  128. package/src/components/Card/CardAction/CardActionTrailingIcon.tsx +32 -0
  129. package/src/components/Card/CardAction/index.ts +10 -0
  130. package/src/components/Card/CardContent.tsx +40 -0
  131. package/src/components/Card/CardPressHandler.context.ts +12 -0
  132. package/src/components/Card/CardPressHandler.tsx +20 -0
  133. package/src/components/Card/CardRoot.tsx +128 -13
  134. package/src/components/Card/index.ts +3 -2
  135. package/src/components/Checkbox/CheckboxIcon.tsx +2 -1
  136. package/src/components/Container/Container.tsx +3 -3
  137. package/src/components/CurrencyInput/CurrencyInput.tsx +1 -1
  138. package/src/components/Helper/HelperIcon.tsx +2 -1
  139. package/src/components/Icon/Icon.tsx +4 -3
  140. package/src/components/IconButton/IconButtonIcon.tsx +2 -1
  141. package/src/components/IconContainer/IconContainer.tsx +17 -19
  142. package/src/components/Input/InputField.tsx +2 -1
  143. package/src/components/Input/InputIcon.tsx +2 -1
  144. package/src/components/Link/LinkIcon.tsx +3 -2
  145. package/src/components/List/ListAction/ListActionTrailingIcon.tsx +2 -1
  146. package/src/components/List/ListItem/ListItemIcon.tsx +2 -1
  147. package/src/components/List/ListItem/ListItemTrailingIcon.tsx +2 -3
  148. package/src/components/Radio/RadioIcon.tsx +8 -3
  149. package/src/components/RadioCard/RadioCardIcon.tsx +4 -3
  150. package/src/components/Spinner/Spinner.tsx +2 -0
  151. package/src/components/Spinner/Spinner.web.tsx +2 -0
  152. package/src/components/Switch/Switch.tsx +10 -5
  153. package/src/components/Switch/Switch.web.tsx +5 -0
  154. package/src/components/Tabs/TabsList.tsx +2 -0
  155. package/src/components/Textarea/TextareaField.tsx +1 -1
  156. package/src/components/ToggleButton/ToggleButtonIcon.tsx +2 -1
  157. package/src/components/ToggleButton/ToggleButtonRoot.tsx +2 -2
  158. package/src/components/UnstyledIconButton/UnstyledIconButtonIcon.tsx +2 -1
  159. package/src/components/index.ts +1 -9
  160. package/src/core/index.ts +14 -11
  161. package/src/hooks/useColorMode.ts +9 -12
  162. package/src/tokens/components/dark/banner.ts +19 -0
  163. package/src/tokens/components/dark/card-action.ts +11 -0
  164. package/src/tokens/components/dark/card-content.ts +25 -0
  165. package/src/tokens/components/dark/drawer.ts +29 -0
  166. package/src/tokens/components/dark/illustrations.ts +0 -1
  167. package/src/tokens/components/dark/index.ts +3 -0
  168. package/src/tokens/components/light/banner.ts +19 -0
  169. package/src/tokens/components/light/card-action.ts +11 -0
  170. package/src/tokens/components/light/card-content.ts +25 -0
  171. package/src/tokens/components/light/drawer.ts +29 -0
  172. package/src/tokens/components/light/illustrations.ts +0 -1
  173. package/src/tokens/components/light/index.ts +3 -0
  174. package/src/tokens/layout.ts +3 -3
  175. package/src/tokens/typography.ts +3 -0
  176. package/build/components/Card/CardAction.context.d.ts +0 -6
  177. package/build/components/Card/CardAction.js +0 -13
  178. package/src/components/Card/CardAction.context.ts +0 -12
  179. package/src/components/Card/CardAction.tsx +0 -18
@@ -0,0 +1,265 @@
1
+ import { Meta, StoryObj } from '@storybook/react';
2
+ import * as Icons from '@utilitywarehouse/hearth-react-native-icons';
3
+ import { ElectricityMediumIcon, GasMediumIcon } from '@utilitywarehouse/hearth-react-native-icons';
4
+ import { View } from 'react-native';
5
+ import { Flex } from '../../Flex';
6
+ import Card from '../Card';
7
+ import CardAction from './CardAction';
8
+
9
+ const meta: Meta<typeof CardAction> = {
10
+ title: 'Stories / CardAction',
11
+ component: CardAction,
12
+ argTypes: {
13
+ heading: { control: 'text' },
14
+ helperText: { control: 'text' },
15
+ disabled: { control: 'boolean' },
16
+ loading: { control: 'boolean' },
17
+ size: {
18
+ control: 'select',
19
+ options: ['md', 'lg'],
20
+ },
21
+ badge: { control: 'object' },
22
+ badgePosition: {
23
+ control: 'select',
24
+ options: ['bottom', 'middle', 'right'],
25
+ },
26
+ leadingIcon: {
27
+ options: [
28
+ 'none',
29
+ ...Object.keys(Icons).filter(icon => icon.includes('Small') || icon.includes('Medium')),
30
+ ],
31
+ control: 'select',
32
+ description: 'The leading icon.',
33
+ },
34
+ trailingIcon: {
35
+ options: [
36
+ 'none',
37
+ ...Object.keys(Icons).filter(icon => icon.includes('Small') || icon.includes('Medium')),
38
+ ],
39
+ control: 'select',
40
+ description: 'The trailing icon.',
41
+ },
42
+ iconContainer: { control: 'boolean' },
43
+ iconContainerVariant: {
44
+ control: 'select',
45
+ options: ['subtle', 'emphasis'],
46
+ },
47
+ iconContainerColor: {
48
+ control: 'select',
49
+ options: ['pig', 'energy', 'broadband', 'mobile', 'insurance', 'cashback', 'highlight'],
50
+ },
51
+ },
52
+ args: {
53
+ heading: 'Card Action',
54
+ helperText: 'This is a card action component',
55
+ size: 'md',
56
+ loading: false,
57
+ disabled: false,
58
+ iconContainer: true,
59
+ },
60
+ };
61
+
62
+ export default meta;
63
+
64
+ type Story = StoryObj<typeof CardAction>;
65
+
66
+ export const Playground: Story = {
67
+ args: {
68
+ onPress: () => console.log('pressed'),
69
+ },
70
+ render: (args: any) => {
71
+ // @ts-expect-error - This is a playground
72
+ const leadingIcon = args.leadingIcon === 'none' ? undefined : Icons[args.leadingIcon];
73
+ // @ts-expect-error - This is a playground
74
+ const trailingIcon = args.trailingIcon === 'none' ? undefined : Icons[args.trailingIcon];
75
+ return (
76
+ <View style={{ width: '100%', maxWidth: 400 }}>
77
+ <Card variant="emphasis">
78
+ <CardAction {...args} leadingIcon={leadingIcon} trailingIcon={trailingIcon} />
79
+ </Card>
80
+ </View>
81
+ );
82
+ },
83
+ };
84
+
85
+ export const WithLeadingIcon: Story = {
86
+ parameters: {
87
+ controls: { include: [] },
88
+ },
89
+ render: () => (
90
+ <View style={{ width: '100%', maxWidth: 400 }}>
91
+ <Card variant="emphasis">
92
+ <CardAction
93
+ heading="Bills"
94
+ helperText="View your bills"
95
+ leadingIcon={ElectricityMediumIcon}
96
+ onPress={() => console.log('pressed')}
97
+ />
98
+ </Card>
99
+ </View>
100
+ ),
101
+ };
102
+
103
+ export const WithTrailingIcon: Story = {
104
+ parameters: {
105
+ controls: { include: [] },
106
+ },
107
+ render: () => (
108
+ <View style={{ width: '100%', maxWidth: 400 }}>
109
+ <Card variant="emphasis">
110
+ <CardAction
111
+ heading="Bills"
112
+ helperText="View your bills"
113
+ trailingIcon={ElectricityMediumIcon}
114
+ onPress={() => console.log('pressed')}
115
+ />
116
+ </Card>
117
+ </View>
118
+ ),
119
+ };
120
+
121
+ export const WithIconContainer: Story = {
122
+ args: {},
123
+ parameters: {
124
+ controls: { include: [] },
125
+ },
126
+ render: () => (
127
+ <View style={{ width: '100%', maxWidth: 400 }}>
128
+ <Card variant="emphasis">
129
+ <CardAction
130
+ heading="Electricity"
131
+ helperText="Last reading 23/03/24"
132
+ leadingIcon={ElectricityMediumIcon}
133
+ iconContainer
134
+ iconContainerVariant="emphasis"
135
+ iconContainerColor="energy"
136
+ onPress={() => console.log('pressed')}
137
+ />
138
+ <CardAction
139
+ heading="Gas"
140
+ helperText="Last reading 23/03/24"
141
+ leadingIcon={GasMediumIcon}
142
+ iconContainer
143
+ iconContainerVariant="emphasis"
144
+ iconContainerColor="energy"
145
+ onPress={() => console.log('pressed')}
146
+ />
147
+ <CardAction
148
+ heading="Gas"
149
+ helperText="Last reading 23/03/24"
150
+ leadingIcon={GasMediumIcon}
151
+ iconContainer
152
+ iconContainerVariant="emphasis"
153
+ iconContainerColor="energy"
154
+ onPress={() => console.log('pressed')}
155
+ />
156
+ </Card>
157
+ </View>
158
+ ),
159
+ };
160
+
161
+ export const WithBadge: Story = {
162
+ parameters: {
163
+ controls: { include: [] },
164
+ },
165
+ render: () => (
166
+ <Flex direction="column" space="md" style={{ width: '100%', maxWidth: 400 }}>
167
+ <Card variant="emphasis">
168
+ <CardAction
169
+ heading="Badge at bottom"
170
+ helperText="Badge positioned below text"
171
+ leadingIcon={ElectricityMediumIcon}
172
+ badge={{ text: 'New' }}
173
+ badgePosition="bottom"
174
+ onPress={() => console.log('pressed')}
175
+ />
176
+ </Card>
177
+ <Card variant="emphasis">
178
+ <CardAction
179
+ heading="Badge at middle"
180
+ helperText="Badge positioned between heading and helper text"
181
+ leadingIcon={ElectricityMediumIcon}
182
+ badge={{ text: 'New' }}
183
+ badgePosition="middle"
184
+ onPress={() => console.log('pressed')}
185
+ />
186
+ </Card>
187
+ <Card variant="emphasis">
188
+ <CardAction
189
+ heading="Badge at right"
190
+ helperText="Badge positioned on the right side"
191
+ leadingIcon={ElectricityMediumIcon}
192
+ badge={{ text: 'New' }}
193
+ badgePosition="right"
194
+ onPress={() => console.log('pressed')}
195
+ />
196
+ </Card>
197
+ </Flex>
198
+ ),
199
+ };
200
+
201
+ export const Sizes: Story = {
202
+ parameters: {
203
+ controls: { include: [] },
204
+ },
205
+ render: () => (
206
+ <Flex direction="column" space="md" style={{ width: '100%', maxWidth: 400 }}>
207
+ <Card variant="emphasis">
208
+ <CardAction
209
+ heading="Medium size (default)"
210
+ helperText="Heading size is md"
211
+ size="md"
212
+ leadingIcon={ElectricityMediumIcon}
213
+ onPress={() => console.log('pressed')}
214
+ />
215
+ </Card>
216
+ <Card variant="emphasis">
217
+ <CardAction
218
+ heading="Large size"
219
+ helperText="Heading size is lg"
220
+ size="lg"
221
+ leadingIcon={ElectricityMediumIcon}
222
+ onPress={() => console.log('pressed')}
223
+ />
224
+ </Card>
225
+ </Flex>
226
+ ),
227
+ };
228
+
229
+ export const Loading: Story = {
230
+ parameters: {
231
+ controls: { include: [] },
232
+ },
233
+ render: () => (
234
+ <View style={{ width: '100%', maxWidth: 400 }}>
235
+ <Card variant="emphasis">
236
+ <CardAction
237
+ heading="Loading"
238
+ helperText="This is loading"
239
+ loading
240
+ leadingIcon={ElectricityMediumIcon}
241
+ onPress={() => console.log('pressed')}
242
+ />
243
+ </Card>
244
+ </View>
245
+ ),
246
+ };
247
+
248
+ export const Disabled: Story = {
249
+ parameters: {
250
+ controls: { include: [] },
251
+ },
252
+ render: () => (
253
+ <View style={{ width: '100%', maxWidth: 400 }}>
254
+ <Card variant="emphasis">
255
+ <CardAction
256
+ heading="Disabled"
257
+ helperText="This is disabled"
258
+ disabled
259
+ leadingIcon={ElectricityMediumIcon}
260
+ onPress={() => console.log('pressed')}
261
+ />
262
+ </Card>
263
+ </View>
264
+ ),
265
+ };
@@ -0,0 +1,10 @@
1
+ import { createPressable } from '@gluestack-ui/pressable';
2
+ import CardActionRoot from './CardActionRoot';
3
+
4
+ const CardAction = createPressable({
5
+ Root: CardActionRoot,
6
+ });
7
+
8
+ CardAction.displayName = 'CardAction';
9
+
10
+ export default CardAction;
@@ -0,0 +1,20 @@
1
+ import { View, type ViewProps } from 'react-native';
2
+ import { StyleSheet } from 'react-native-unistyles';
3
+
4
+ const CardActionContent = ({ children, ...props }: ViewProps) => {
5
+ return (
6
+ <View {...props} style={[styles.container, props.style]}>
7
+ {children}
8
+ </View>
9
+ );
10
+ };
11
+
12
+ CardActionContent.displayName = 'CardActionContent';
13
+
14
+ const styles = StyleSheet.create({
15
+ container: {
16
+ flex: 1,
17
+ },
18
+ });
19
+
20
+ export default CardActionContent;
@@ -0,0 +1,21 @@
1
+ import { TextProps } from 'react-native';
2
+ import { StyleSheet } from 'react-native-unistyles';
3
+ import { BodyText } from '../../BodyText';
4
+
5
+ const CardActionHelperText = ({ children, ...props }: TextProps) => {
6
+ return (
7
+ <BodyText size="md" {...props} style={[styles.text, props.style]}>
8
+ {children}
9
+ </BodyText>
10
+ );
11
+ };
12
+
13
+ CardActionHelperText.displayName = 'CardActionHelperText';
14
+
15
+ const styles = StyleSheet.create(theme => ({
16
+ text: {
17
+ color: theme.color.text.secondary,
18
+ },
19
+ }));
20
+
21
+ export default CardActionHelperText;
@@ -0,0 +1,32 @@
1
+ import { ComponentType } from 'react';
2
+ import { Platform, type StyleProp, type ViewStyle } from 'react-native';
3
+ import { StyleSheet } from 'react-native-unistyles';
4
+ import { Icon, IconProps } from '../../Icon';
5
+
6
+ const CardActionIcon = ({ children, ...props }: IconProps & { as?: ComponentType }) => {
7
+ return (
8
+ <Icon
9
+ {...props}
10
+ style={
11
+ Platform.OS === 'web'
12
+ ? // @ts-expect-error - style prop type issue
13
+ { ...(styles.icon as StyleProp<ViewStyle>), ...props.style }
14
+ : ([styles.icon as StyleProp<ViewStyle>, props.style] as any)
15
+ }
16
+ >
17
+ {children}
18
+ </Icon>
19
+ );
20
+ };
21
+
22
+ CardActionIcon.displayName = 'CardActionIcon';
23
+
24
+ const styles = StyleSheet.create(theme => ({
25
+ icon: {
26
+ color: theme.color.icon.primary,
27
+ width: 24,
28
+ height: 24,
29
+ },
30
+ }));
31
+
32
+ export default CardActionIcon;
@@ -0,0 +1,9 @@
1
+ import { View, type ViewProps } from 'react-native';
2
+
3
+ const CardActionLeadingContent = ({ children, ...props }: ViewProps) => (
4
+ <View {...props}>{children}</View>
5
+ );
6
+
7
+ CardActionLeadingContent.displayName = 'CardActionLeadingContent';
8
+
9
+ export default CardActionLeadingContent;
@@ -0,0 +1,258 @@
1
+ import { ChevronRightSmallIcon } from '@utilitywarehouse/hearth-react-native-icons';
2
+ import { useMemo } from 'react';
3
+ import { Pressable, View, ViewStyle } from 'react-native';
4
+ import { StyleSheet } from 'react-native-unistyles';
5
+ import { Badge } from '../../Badge';
6
+ import { IconContainer } from '../../IconContainer';
7
+ import { Skeleton } from '../../Skeleton';
8
+ import { useCardContext } from '../Card.context';
9
+ import { CardActionContext, ICardActionContext } from './CardAction.context';
10
+ import type CardActionProps from './CardAction.props';
11
+ import CardActionContent from './CardActionContent';
12
+ import CardActionHelperText from './CardActionHelperText';
13
+ import CardActionIcon from './CardActionIcon';
14
+ import CardActionLeadingContent from './CardActionLeadingContent';
15
+ import CardActionText from './CardActionText';
16
+ import CardActionTrailingContent from './CardActionTrailingContent';
17
+ import CardActionTrailingIcon from './CardActionTrailingIcon';
18
+
19
+ const CardActionRoot = ({
20
+ heading,
21
+ helperText,
22
+ leadingContent,
23
+ trailingContent,
24
+ disabled,
25
+ loading,
26
+ children,
27
+ states,
28
+ badge,
29
+ badgePosition = 'bottom',
30
+ iconContainer = true,
31
+ iconContainerColor,
32
+ iconContainerVariant,
33
+ leadingIcon,
34
+ trailingIcon = ChevronRightSmallIcon,
35
+ size = 'md',
36
+ ...props
37
+ }: CardActionProps & { states?: { active?: boolean; disabled?: boolean }; isFirst?: boolean }) => {
38
+ const { onPress } = props;
39
+ const { active } = states || { active: false };
40
+
41
+ const isLoading = loading;
42
+ const showPressed = isLoading ? false : !!onPress;
43
+ const isDisabled = disabled || false;
44
+
45
+ const testID = props.testID || 'card-action';
46
+ const loadingTestID = isLoading ? `${testID}-loading` : testID;
47
+
48
+ const { variant, hasOnlyActions } = useCardContext();
49
+ const isFirst = props.isFirst;
50
+
51
+ styles.useVariants({
52
+ showPressed,
53
+ active,
54
+ disabled: isDisabled || isLoading,
55
+ showDisabled: disabled,
56
+ hasIconContainer: !loading && iconContainer,
57
+ variant,
58
+ isFirst: hasOnlyActions && isFirst,
59
+ });
60
+
61
+ const value: ICardActionContext = useMemo(() => {
62
+ return {
63
+ showPressed,
64
+ active: active || false,
65
+ loading: isLoading || false,
66
+ disabled: isDisabled,
67
+ size,
68
+ };
69
+ }, [active, showPressed, isLoading, isDisabled, size]);
70
+
71
+ if (loading) {
72
+ return (
73
+ <Pressable
74
+ {...props}
75
+ testID={loadingTestID}
76
+ style={[styles.container, styles.alignCenter, props.style as ViewStyle]}
77
+ disabled={isDisabled}
78
+ >
79
+ {leadingContent || leadingIcon ? (
80
+ <Skeleton width={24} height={24} style={styles.alignCenter} />
81
+ ) : null}
82
+ <CardActionContent>
83
+ <Skeleton width="80%" height={24} borderRadius="xs" />
84
+ <Skeleton width="100%" height={24} borderRadius="xs" />
85
+ </CardActionContent>
86
+ {trailingIcon || trailingContent ? (
87
+ <Skeleton width={24} height={24} borderRadius="xs" style={styles.alignCenter} />
88
+ ) : null}
89
+ </Pressable>
90
+ );
91
+ }
92
+
93
+ return (
94
+ <CardActionContext.Provider value={value}>
95
+ <Pressable
96
+ {...props}
97
+ testID={testID}
98
+ style={[styles.container, props.style as ViewStyle]}
99
+ disabled={isDisabled}
100
+ accessibilityRole={onPress ? 'button' : undefined}
101
+ >
102
+ {children ? (
103
+ children
104
+ ) : (
105
+ <>
106
+ {leadingIcon && iconContainer ? (
107
+ <View style={styles.iconContainerWrap}>
108
+ <IconContainer
109
+ style={styles.iconContainer}
110
+ icon={leadingIcon}
111
+ variant={iconContainerVariant}
112
+ color={iconContainerColor}
113
+ radiusNone
114
+ />
115
+ </View>
116
+ ) : null}
117
+ <View style={styles.withIconContainer}>
118
+ {leadingContent ? (
119
+ <CardActionLeadingContent>{leadingContent}</CardActionLeadingContent>
120
+ ) : null}
121
+ {leadingIcon && !iconContainer && !leadingContent ? (
122
+ <CardActionLeadingContent>
123
+ <CardActionIcon as={leadingIcon} />
124
+ </CardActionLeadingContent>
125
+ ) : null}
126
+ <CardActionContent>
127
+ {badgePosition === 'top' && badge ? <Badge {...badge} /> : null}
128
+ <CardActionText>{heading}</CardActionText>
129
+ {badgePosition === 'middle' && badge ? <Badge {...badge} /> : null}
130
+ {helperText ? <CardActionHelperText>{helperText}</CardActionHelperText> : null}
131
+ {badgePosition === 'bottom' && badge ? <Badge {...badge} /> : null}
132
+ </CardActionContent>
133
+ {badgePosition === 'right' && badge ? (
134
+ <Badge {...badge} style={[badge.style, styles.alignCenter]} />
135
+ ) : null}
136
+ {trailingContent ? (
137
+ <CardActionTrailingContent>{trailingContent}</CardActionTrailingContent>
138
+ ) : null}
139
+ {trailingIcon && !trailingContent ? (
140
+ <CardActionTrailingContent>
141
+ <CardActionTrailingIcon as={trailingIcon} />
142
+ </CardActionTrailingContent>
143
+ ) : null}
144
+ </View>
145
+ </>
146
+ )}
147
+ </Pressable>
148
+ </CardActionContext.Provider>
149
+ );
150
+ };
151
+
152
+ CardActionRoot.displayName = 'CardActionRoot';
153
+
154
+ const styles = StyleSheet.create(theme => ({
155
+ container: {
156
+ paddingVertical: theme.components.cardAction.content.paddingVertical,
157
+ paddingHorizontal: theme.components.cardAction.content.paddingHorizontal,
158
+ flexDirection: 'row',
159
+ gap: theme.components.cardAction.content.gap,
160
+ borderTopWidth: theme.borderWidth[1],
161
+ borderColor: theme.color.border.strong,
162
+ width: '100%',
163
+ variants: {
164
+ isFirst: {
165
+ true: {
166
+ borderTopWidth: 0,
167
+ },
168
+ },
169
+ disabled: {
170
+ true: {
171
+ cursor: 'auto',
172
+ },
173
+ },
174
+ variant: {
175
+ subtle: {
176
+ borderColor: theme.color.border.subtle,
177
+ },
178
+ emphasis: {
179
+ borderColor: theme.color.border.strong,
180
+ },
181
+ },
182
+ hasIconContainer: {
183
+ true: {
184
+ paddingHorizontal: 0,
185
+ paddingVertical: 0,
186
+ gap: 0,
187
+ },
188
+ },
189
+ showDisabled: {
190
+ true: {
191
+ opacity: theme.opacity.disabled,
192
+ },
193
+ },
194
+ showPressed: {
195
+ true: {
196
+ _web: {
197
+ _hover: {
198
+ backgroundColor: theme.color.interactive.neutral.surface.subtle.hover,
199
+ },
200
+ _active: {
201
+ backgroundColor: theme.color.interactive.neutral.surface.subtle.active,
202
+ },
203
+ },
204
+ },
205
+ false: {
206
+ cursor: 'auto',
207
+ },
208
+ },
209
+ active: {
210
+ true: {},
211
+ },
212
+ },
213
+ compoundVariants: [
214
+ {
215
+ showPressed: true,
216
+ active: true,
217
+ styles: {
218
+ backgroundColor: theme.color.interactive.neutral.surface.subtle.active,
219
+ },
220
+ },
221
+ ],
222
+ },
223
+ withIconContainer: {
224
+ alignItems: 'center',
225
+ flexDirection: 'row',
226
+ paddingVertical: theme.components.list.item.functional.padding,
227
+ paddingHorizontal: theme.components.list.item.functional.padding,
228
+ gap: theme.components.list.item.gap,
229
+ flex: 1,
230
+ variants: {
231
+ hasIconContainer: {
232
+ true: {},
233
+ false: {
234
+ flex: 1,
235
+ paddingHorizontal: 0,
236
+ paddingVertical: 0,
237
+ alignItems: 'center',
238
+ },
239
+ },
240
+ },
241
+ },
242
+ alignCenter: {
243
+ alignSelf: 'center',
244
+ alignItems: 'center',
245
+ },
246
+ iconContainer: {
247
+ flex: 1,
248
+ _web: {
249
+ overflow: 'visible',
250
+ height: '100%',
251
+ },
252
+ },
253
+ iconContainerWrap: {
254
+ flexDirection: 'column',
255
+ },
256
+ }));
257
+
258
+ export default CardActionRoot;
@@ -0,0 +1,17 @@
1
+ import { TextProps } from 'react-native';
2
+ import { BodyText } from '../../BodyText';
3
+ import { useCardActionContext } from './CardAction.context';
4
+
5
+ const CardActionText = ({ children, ...props }: TextProps) => {
6
+ const { size } = useCardActionContext();
7
+
8
+ return (
9
+ <BodyText size={size} weight="semibold" {...props}>
10
+ {children}
11
+ </BodyText>
12
+ );
13
+ };
14
+
15
+ CardActionText.displayName = 'CardActionText';
16
+
17
+ export default CardActionText;
@@ -0,0 +1,9 @@
1
+ import { View, type ViewProps } from 'react-native';
2
+
3
+ const CardActionTrailingContent = ({ children, ...props }: ViewProps) => (
4
+ <View {...props}>{children}</View>
5
+ );
6
+
7
+ CardActionTrailingContent.displayName = 'CardActionTrailingContent';
8
+
9
+ export default CardActionTrailingContent;
@@ -0,0 +1,32 @@
1
+ import { ComponentType } from 'react';
2
+ import { Platform, type StyleProp, type ViewStyle } from 'react-native';
3
+ import { StyleSheet } from 'react-native-unistyles';
4
+ import { Icon, IconProps } from '../../Icon';
5
+
6
+ const CardActionTrailingIcon = ({ children, ...props }: IconProps & { as?: ComponentType }) => {
7
+ return (
8
+ <Icon
9
+ {...props}
10
+ style={
11
+ Platform.OS === 'web'
12
+ ? // @ts-expect-error - style prop type issue
13
+ { ...(styles.icon as StyleProp<ViewStyle>), ...props.style }
14
+ : ([styles.icon as StyleProp<ViewStyle>, props.style] as any)
15
+ }
16
+ >
17
+ {children}
18
+ </Icon>
19
+ );
20
+ };
21
+
22
+ CardActionTrailingIcon.displayName = 'CardActionTrailingIcon';
23
+
24
+ const styles = StyleSheet.create(theme => ({
25
+ icon: {
26
+ color: theme.color.icon.primary,
27
+ minWidth: 20,
28
+ minHeight: 20,
29
+ },
30
+ }));
31
+
32
+ export default CardActionTrailingIcon;
@@ -0,0 +1,10 @@
1
+ export { default as CardAction } from './CardAction';
2
+ export { useCardActionContext } from './CardAction.context';
3
+ export type { default as CardActionProps } from './CardAction.props';
4
+ export { default as CardActionContent } from './CardActionContent';
5
+ export { default as CardActionHelperText } from './CardActionHelperText';
6
+ export { default as CardActionIcon } from './CardActionIcon';
7
+ export { default as CardActionLeadingContent } from './CardActionLeadingContent';
8
+ export { default as CardActionText } from './CardActionText';
9
+ export { default as CardActionTrailingContent } from './CardActionTrailingContent';
10
+ export { default as CardActionTrailingIcon } from './CardActionTrailingIcon';