@utilitywarehouse/hearth-react-native 0.7.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-lint.log +1 -1
  3. package/CHANGELOG.md +18 -0
  4. package/build/components/Banner/Banner.d.ts +6 -0
  5. package/build/components/Banner/Banner.js +161 -0
  6. package/build/components/Banner/Banner.props.d.ts +82 -0
  7. package/build/components/Banner/Banner.props.js +1 -0
  8. package/build/components/Banner/index.d.ts +2 -0
  9. package/build/components/Banner/index.js +1 -0
  10. package/build/components/BottomSheet/BottomSheetBackdrop.js +1 -5
  11. package/build/components/BottomSheet/BottomSheetFlatList.js +1 -5
  12. package/build/components/BottomSheet/BottomSheetHandle.js +1 -5
  13. package/build/components/BottomSheet/useBottomSheetLogic.d.ts +1 -1
  14. package/build/components/Expandable/Expandable.d.ts +6 -0
  15. package/build/components/Expandable/Expandable.js +44 -0
  16. package/build/components/Expandable/Expandable.props.d.ts +38 -0
  17. package/build/components/Expandable/Expandable.props.js +1 -0
  18. package/build/components/Expandable/index.d.ts +2 -0
  19. package/build/components/Expandable/index.js +1 -0
  20. package/build/components/ExpandableCard/ExpandableCard.d.ts +6 -0
  21. package/build/components/ExpandableCard/ExpandableCard.js +23 -0
  22. package/build/components/ExpandableCard/ExpandableCard.props.d.ts +69 -0
  23. package/build/components/ExpandableCard/ExpandableCard.props.js +1 -0
  24. package/build/components/ExpandableCard/ExpandableCardContent.d.ts +6 -0
  25. package/build/components/ExpandableCard/ExpandableCardContent.js +14 -0
  26. package/build/components/ExpandableCard/ExpandableCardExpandedContent.d.ts +11 -0
  27. package/build/components/ExpandableCard/ExpandableCardExpandedContent.js +18 -0
  28. package/build/components/ExpandableCard/ExpandableCardGroup.d.ts +6 -0
  29. package/build/components/ExpandableCard/ExpandableCardGroup.js +17 -0
  30. package/build/components/ExpandableCard/ExpandableCardGroup.props.d.ts +25 -0
  31. package/build/components/ExpandableCard/ExpandableCardGroup.props.js +1 -0
  32. package/build/components/ExpandableCard/ExpandableCardHelperText.d.ts +6 -0
  33. package/build/components/ExpandableCard/ExpandableCardHelperText.js +13 -0
  34. package/build/components/ExpandableCard/ExpandableCardIcon.d.ts +9 -0
  35. package/build/components/ExpandableCard/ExpandableCardIcon.js +19 -0
  36. package/build/components/ExpandableCard/ExpandableCardLeadingContent.d.ts +6 -0
  37. package/build/components/ExpandableCard/ExpandableCardLeadingContent.js +5 -0
  38. package/build/components/ExpandableCard/ExpandableCardText.d.ts +6 -0
  39. package/build/components/ExpandableCard/ExpandableCardText.js +7 -0
  40. package/build/components/ExpandableCard/ExpandableCardTrailingContent.d.ts +6 -0
  41. package/build/components/ExpandableCard/ExpandableCardTrailingContent.js +5 -0
  42. package/build/components/ExpandableCard/ExpandableCardTrailingIcon.d.ts +9 -0
  43. package/build/components/ExpandableCard/ExpandableCardTrailingIcon.js +17 -0
  44. package/build/components/ExpandableCard/ExpandableCardTrigger.d.ts +17 -0
  45. package/build/components/ExpandableCard/ExpandableCardTrigger.js +7 -0
  46. package/build/components/ExpandableCard/ExpandableCardTrigger.props.d.ts +44 -0
  47. package/build/components/ExpandableCard/ExpandableCardTrigger.props.js +1 -0
  48. package/build/components/ExpandableCard/ExpandableCardTriggerRoot.d.ts +11 -0
  49. package/build/components/ExpandableCard/ExpandableCardTriggerRoot.js +91 -0
  50. package/build/components/ExpandableCard/index.d.ts +14 -0
  51. package/build/components/ExpandableCard/index.js +11 -0
  52. package/build/components/HighlightBanner/HighlightBanner.d.ts +6 -0
  53. package/build/components/HighlightBanner/HighlightBanner.js +96 -0
  54. package/build/components/HighlightBanner/HighlightBanner.props.d.ts +14 -0
  55. package/build/components/HighlightBanner/HighlightBanner.props.js +1 -0
  56. package/build/components/HighlightBanner/index.d.ts +2 -0
  57. package/build/components/HighlightBanner/index.js +1 -0
  58. package/build/components/Spinner/Spinner.js +0 -2
  59. package/build/components/Spinner/Spinner.web.d.ts +2 -1
  60. package/build/components/Spinner/Spinner.web.js +0 -2
  61. package/build/components/Switch/Switch.web.js +0 -1
  62. package/build/components/Tabs/TabsList.js +1 -6
  63. package/build/components/index.d.ts +4 -0
  64. package/build/components/index.js +4 -0
  65. package/docs/components/AllComponents.web.tsx +75 -4
  66. package/docs/components/VariantTitle.tsx +1 -1
  67. package/package.json +4 -4
  68. package/src/components/Banner/Banner.docs.mdx +402 -0
  69. package/src/components/Banner/Banner.props.ts +106 -0
  70. package/src/components/Banner/Banner.stories.tsx +494 -0
  71. package/src/components/Banner/Banner.tsx +264 -0
  72. package/src/components/Banner/index.ts +2 -0
  73. package/src/components/BottomSheet/BottomSheetBackdrop.tsx +0 -1
  74. package/src/components/BottomSheet/BottomSheetFlatList.tsx +0 -1
  75. package/src/components/BottomSheet/BottomSheetHandle.tsx +0 -1
  76. package/src/components/Card/Card.docs.mdx +10 -2
  77. package/src/components/Expandable/Expandable.docs.mdx +201 -0
  78. package/src/components/Expandable/Expandable.props.ts +46 -0
  79. package/src/components/Expandable/Expandable.stories.tsx +284 -0
  80. package/src/components/Expandable/Expandable.tsx +92 -0
  81. package/src/components/Expandable/index.ts +2 -0
  82. package/src/components/ExpandableCard/ExpandableCard.docs.mdx +312 -0
  83. package/src/components/ExpandableCard/ExpandableCard.props.ts +85 -0
  84. package/src/components/ExpandableCard/ExpandableCard.stories.tsx +326 -0
  85. package/src/components/ExpandableCard/ExpandableCard.tsx +76 -0
  86. package/src/components/ExpandableCard/ExpandableCardContent.tsx +21 -0
  87. package/src/components/ExpandableCard/ExpandableCardExpandedContent.tsx +42 -0
  88. package/src/components/ExpandableCard/ExpandableCardGroup.props.ts +31 -0
  89. package/src/components/ExpandableCard/ExpandableCardGroup.tsx +40 -0
  90. package/src/components/ExpandableCard/ExpandableCardHelperText.tsx +21 -0
  91. package/src/components/ExpandableCard/ExpandableCardIcon.tsx +32 -0
  92. package/src/components/ExpandableCard/ExpandableCardLeadingContent.tsx +9 -0
  93. package/src/components/ExpandableCard/ExpandableCardText.tsx +14 -0
  94. package/src/components/ExpandableCard/ExpandableCardTrailingContent.tsx +9 -0
  95. package/src/components/ExpandableCard/ExpandableCardTrailingIcon.tsx +30 -0
  96. package/src/components/ExpandableCard/ExpandableCardTrigger.props.ts +47 -0
  97. package/src/components/ExpandableCard/ExpandableCardTrigger.tsx +10 -0
  98. package/src/components/ExpandableCard/ExpandableCardTriggerRoot.tsx +154 -0
  99. package/src/components/ExpandableCard/index.ts +14 -0
  100. package/src/components/HighlightBanner/HighlightBanner.docs.mdx +296 -0
  101. package/src/components/HighlightBanner/HighlightBanner.props.ts +29 -0
  102. package/src/components/HighlightBanner/HighlightBanner.stories.tsx +275 -0
  103. package/src/components/HighlightBanner/HighlightBanner.tsx +134 -0
  104. package/src/components/HighlightBanner/index.ts +2 -0
  105. package/src/components/Spinner/Spinner.tsx +0 -2
  106. package/src/components/Spinner/Spinner.web.tsx +0 -2
  107. package/src/components/Switch/Switch.web.tsx +1 -5
  108. package/src/components/Tabs/TabsList.tsx +0 -2
  109. package/src/components/index.ts +4 -0
@@ -0,0 +1,85 @@
1
+ import type { ComponentType, ReactNode } from 'react';
2
+ import type BadgeProps from '../Badge/Badge.props';
3
+ import type CardProps from '../Card/Card.props';
4
+
5
+ export interface ExpandableCardProps extends Omit<CardProps, 'children'> {
6
+ /**
7
+ * Whether the card is expanded
8
+ */
9
+ expanded?: boolean;
10
+
11
+ /**
12
+ * Callback when expanded state changes
13
+ */
14
+ onExpandedChange?: (expanded: boolean) => void;
15
+
16
+ /**
17
+ * The heading text displayed in the trigger
18
+ */
19
+ heading?: string;
20
+
21
+ /**
22
+ * Optional helper text displayed below the heading
23
+ */
24
+ helperText?: string;
25
+
26
+ /**
27
+ * Leading icon component
28
+ */
29
+ leadingIcon?: ComponentType;
30
+
31
+ /**
32
+ * Leading content (icon or custom element)
33
+ */
34
+ leadingContent?: ReactNode;
35
+
36
+ /**
37
+ * Badge to display
38
+ */
39
+ badge?: BadgeProps;
40
+
41
+ /**
42
+ * Badge position
43
+ * @default 'bottom'
44
+ */
45
+ badgePosition?: 'top' | 'bottom';
46
+
47
+ /**
48
+ * Numeric value to display on the right
49
+ */
50
+ numericValue?: string | number;
51
+
52
+ /**
53
+ * The content to show when expanded
54
+ */
55
+ expandedContent?: ReactNode;
56
+
57
+ /**
58
+ * Duration of the expansion animation in milliseconds
59
+ * @default 200
60
+ */
61
+ duration?: number;
62
+
63
+ /**
64
+ * Whether to animate opacity during expansion
65
+ * @default true
66
+ */
67
+ animateOpacity?: boolean;
68
+
69
+ /**
70
+ * Whether the card is disabled
71
+ */
72
+ disabled?: boolean;
73
+
74
+ /**
75
+ * Test ID for testing
76
+ */
77
+ testID?: string;
78
+
79
+ /**
80
+ * Custom children for advanced composition
81
+ */
82
+ children?: ReactNode;
83
+ }
84
+
85
+ export default ExpandableCardProps;
@@ -0,0 +1,326 @@
1
+ import { Meta, StoryObj } from '@storybook/react-native';
2
+ import {
3
+ BillMediumIcon,
4
+ ElectricityMediumIcon,
5
+ GasMediumIcon,
6
+ PaymentMediumIcon,
7
+ SettingsMediumIcon,
8
+ } from '@utilitywarehouse/hearth-react-native-icons';
9
+ import React from 'react';
10
+ import { BodyText, IconContainer, Link } from '../../components';
11
+ import ExpandableCard from './ExpandableCard';
12
+ import ExpandableCardExpandedContent from './ExpandableCardExpandedContent';
13
+ import ExpandableCardGroup from './ExpandableCardGroup';
14
+ import ExpandableCardIcon from './ExpandableCardIcon';
15
+ import ExpandableCardTrigger from './ExpandableCardTrigger';
16
+
17
+ const meta = {
18
+ title: 'Stories / ExpandableCard',
19
+ component: ExpandableCard,
20
+ parameters: {
21
+ layout: 'centered',
22
+ },
23
+ argTypes: {
24
+ expanded: {
25
+ control: 'boolean',
26
+ description: 'Whether the card is expanded',
27
+ },
28
+ heading: {
29
+ control: 'text',
30
+ description: 'The heading text',
31
+ },
32
+ helperText: {
33
+ control: 'text',
34
+ description: 'Helper text below heading',
35
+ },
36
+ disabled: {
37
+ control: 'boolean',
38
+ description: 'Whether the card is disabled',
39
+ },
40
+ variant: {
41
+ control: 'radio',
42
+ description: 'The variant style of the card',
43
+ options: ['subtle', 'emphasis'],
44
+ },
45
+ duration: {
46
+ control: { type: 'number', min: 100, max: 1000, step: 50 },
47
+ description: 'Animation duration in milliseconds',
48
+ },
49
+ animateOpacity: {
50
+ control: 'boolean',
51
+ description: 'Whether to animate opacity',
52
+ },
53
+ },
54
+ args: {
55
+ heading: 'Expandable Card',
56
+ helperText: 'Click to expand',
57
+ expanded: false,
58
+ disabled: false,
59
+ duration: 200,
60
+ animateOpacity: true,
61
+ variant: 'subtle',
62
+ },
63
+ } satisfies Meta<typeof ExpandableCard>;
64
+
65
+ export default meta;
66
+ type Story = StoryObj<typeof meta>;
67
+
68
+ export const Playground: Story = {
69
+ args: {
70
+ expandedContent: (
71
+ <BodyText>
72
+ This is the expanded content. It can contain any component or content you need.
73
+ </BodyText>
74
+ ),
75
+ },
76
+ };
77
+
78
+ export const BasicExample: Story = {
79
+ render: () => (
80
+ <ExpandableCard
81
+ heading="Order Details"
82
+ helperText="View your order information"
83
+ expandedContent={
84
+ <>
85
+ <BodyText>Order #12345</BodyText>
86
+ <BodyText>Status: Delivered</BodyText>
87
+ <BodyText>Date: 10 Nov 2025</BodyText>
88
+ </>
89
+ }
90
+ style={{ width: 350 }}
91
+ />
92
+ ),
93
+ };
94
+
95
+ export const WithLeadingIcon: Story = {
96
+ render: () => (
97
+ <ExpandableCard
98
+ heading="Settings"
99
+ helperText="Configure your preferences"
100
+ leadingIcon={SettingsMediumIcon}
101
+ expandedContent={
102
+ <>
103
+ <BodyText>• Notifications</BodyText>
104
+ <BodyText>• Privacy</BodyText>
105
+ <BodyText>• Account</BodyText>
106
+ </>
107
+ }
108
+ style={{ width: 350 }}
109
+ />
110
+ ),
111
+ };
112
+
113
+ export const WithIconContainer: Story = {
114
+ render: () => (
115
+ <ExpandableCard
116
+ heading="Electricity"
117
+ helperText="Last reading 23/03/24"
118
+ leadingContent={
119
+ <IconContainer icon={ElectricityMediumIcon} size="md" variant="emphasis" color="energy" />
120
+ }
121
+ expandedContent={
122
+ <>
123
+ <BodyText>Current Usage: 245 kWh</BodyText>
124
+ <BodyText>Estimated Cost: £45.50</BodyText>
125
+ <BodyText>Next Reading: 23/04/24</BodyText>
126
+ </>
127
+ }
128
+ style={{ width: 350 }}
129
+ />
130
+ ),
131
+ };
132
+
133
+ export const WithBadge: Story = {
134
+ render: () => (
135
+ <ExpandableCard
136
+ heading="New Feature"
137
+ helperText="Check out what's new"
138
+ badge={{ text: 'New', colorScheme: 'info' }}
139
+ expandedContent={
140
+ <BodyText>We've added new features to improve your experience. Explore them now!</BodyText>
141
+ }
142
+ style={{ width: 350 }}
143
+ />
144
+ ),
145
+ };
146
+
147
+ export const WithNumericValue: Story = {
148
+ render: () => (
149
+ <ExpandableCard
150
+ heading="Total Balance"
151
+ helperText="Current account balance"
152
+ numericValue="£123.45"
153
+ expandedContent={
154
+ <>
155
+ <BodyText>Available: £100.00</BodyText>
156
+ <BodyText>Pending: £23.45</BodyText>
157
+ </>
158
+ }
159
+ style={{ width: 350 }}
160
+ />
161
+ ),
162
+ };
163
+
164
+ export const Disabled: Story = {
165
+ render: () => (
166
+ <ExpandableCard
167
+ heading="Disabled Card"
168
+ helperText="This card cannot be expanded"
169
+ disabled
170
+ expandedContent={<BodyText>This content is not accessible</BodyText>}
171
+ style={{ width: 350 }}
172
+ />
173
+ ),
174
+ };
175
+
176
+ export const Controlled: Story = {
177
+ render: () => {
178
+ const [expanded, setExpanded] = React.useState(false);
179
+
180
+ return (
181
+ <div style={{ width: 350 }}>
182
+ <BodyText style={{ marginBottom: 8 }}>
183
+ Status: {expanded ? 'Expanded' : 'Collapsed'}
184
+ </BodyText>
185
+ <ExpandableCard
186
+ heading="Controlled Card"
187
+ helperText="Externally controlled state"
188
+ expanded={expanded}
189
+ onExpandedChange={setExpanded}
190
+ expandedContent={
191
+ <BodyText>This card's state is controlled by the parent component.</BodyText>
192
+ }
193
+ />
194
+ </div>
195
+ );
196
+ },
197
+ };
198
+
199
+ export const CardGroup: Story = {
200
+ render: () => (
201
+ <ExpandableCardGroup
202
+ heading="Your Services"
203
+ helperText="View details for each service"
204
+ headerTrailingContent={<Link href="#">View all</Link>}
205
+ >
206
+ <ExpandableCard
207
+ heading="Electricity"
208
+ helperText="Last reading 23/03/24"
209
+ leadingContent={
210
+ <IconContainer icon={ElectricityMediumIcon} size="md" variant="emphasis" color="energy" />
211
+ }
212
+ expandedContent={
213
+ <>
214
+ <BodyText>Current Usage: 245 kWh</BodyText>
215
+ <BodyText>Estimated Cost: £45.50</BodyText>
216
+ </>
217
+ }
218
+ />
219
+ <ExpandableCard
220
+ heading="Gas"
221
+ helperText="Last reading 23/03/24"
222
+ leadingContent={
223
+ <IconContainer icon={GasMediumIcon} size="md" variant="emphasis" color="energy" />
224
+ }
225
+ expandedContent={
226
+ <>
227
+ <BodyText>Current Usage: 180 kWh</BodyText>
228
+ <BodyText>Estimated Cost: £32.00</BodyText>
229
+ </>
230
+ }
231
+ />
232
+ </ExpandableCardGroup>
233
+ ),
234
+ };
235
+
236
+ export const GroupWithMixedContent: Story = {
237
+ render: () => (
238
+ <ExpandableCardGroup heading="Account Overview">
239
+ <ExpandableCard
240
+ heading="Bills"
241
+ helperText="View your recent bills"
242
+ leadingContent={<ExpandableCardIcon as={BillMediumIcon} />}
243
+ expandedContent={
244
+ <>
245
+ <BodyText>• March 2025: £89.50</BodyText>
246
+ <BodyText>• February 2025: £92.00</BodyText>
247
+ <BodyText>• January 2025: £95.30</BodyText>
248
+ </>
249
+ }
250
+ />
251
+ <ExpandableCard
252
+ heading="Payments"
253
+ helperText="Payment history"
254
+ leadingContent={<ExpandableCardIcon as={PaymentMediumIcon} />}
255
+ numericValue="3"
256
+ expandedContent={
257
+ <>
258
+ <BodyText>• 05/03/25: £89.50 paid</BodyText>
259
+ <BodyText>• 05/02/25: £92.00 paid</BodyText>
260
+ <BodyText>• 05/01/25: £95.30 paid</BodyText>
261
+ </>
262
+ }
263
+ />
264
+ <ExpandableCard
265
+ heading="Settings"
266
+ leadingContent={<ExpandableCardIcon as={SettingsMediumIcon} />}
267
+ badge={{ text: 'Updated', colorScheme: 'info', size: 'sm' }}
268
+ expandedContent={
269
+ <>
270
+ <BodyText>• Notification preferences</BodyText>
271
+ <BodyText>• Payment methods</BodyText>
272
+ <BodyText>• Account details</BodyText>
273
+ </>
274
+ }
275
+ />
276
+ </ExpandableCardGroup>
277
+ ),
278
+ };
279
+
280
+ export const ColorSchemes: Story = {
281
+ render: () => (
282
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 16, width: 350 }}>
283
+ <ExpandableCard
284
+ heading="Default Card"
285
+ expandedContent={<BodyText>Default color scheme</BodyText>}
286
+ />
287
+ <ExpandableCard
288
+ heading="Subtle White Card"
289
+ colorScheme="neutralSubtle"
290
+ expandedContent={<BodyText>Subtle white color scheme</BodyText>}
291
+ />
292
+ <ExpandableCard
293
+ heading="Strong Card"
294
+ colorScheme="neutralStrong"
295
+ expandedContent={<BodyText>Strong color scheme</BodyText>}
296
+ />
297
+ </div>
298
+ ),
299
+ };
300
+
301
+ export const AdvancedComposition: Story = {
302
+ render: () => {
303
+ const [expanded, setExpanded] = React.useState(false);
304
+
305
+ return (
306
+ <ExpandableCard expanded={expanded} onExpandedChange={setExpanded}>
307
+ <ExpandableCardTrigger
308
+ onPress={() => setExpanded(!expanded)}
309
+ heading="Custom Account Details"
310
+ helperText="View your detailed account information"
311
+ leadingContent={
312
+ <IconContainer icon={BillMediumIcon} size="md" variant="emphasis" color="pig" />
313
+ }
314
+ numericValue="£123.45"
315
+ isExpanded={expanded}
316
+ />
317
+ <ExpandableCardExpandedContent isExpanded={expanded}>
318
+ <BodyText>Account Number: 1234567890</BodyText>
319
+ <BodyText>Sort Code: 12-34-56</BodyText>
320
+ <BodyText>Balance: £123.45</BodyText>
321
+ <BodyText>Last Updated: 12/11/25</BodyText>
322
+ </ExpandableCardExpandedContent>
323
+ </ExpandableCard>
324
+ );
325
+ },
326
+ };
@@ -0,0 +1,76 @@
1
+ import { useState } from 'react';
2
+ import { Card } from '../Card';
3
+ import type ExpandableCardProps from './ExpandableCard.props';
4
+ import ExpandableCardExpandedContent from './ExpandableCardExpandedContent';
5
+ import ExpandableCardTrigger from './ExpandableCardTrigger';
6
+
7
+ const ExpandableCard = ({
8
+ expanded: controlledExpanded,
9
+ onExpandedChange,
10
+ heading,
11
+ helperText,
12
+ leadingIcon,
13
+ leadingContent,
14
+ badge,
15
+ badgePosition = 'bottom',
16
+ numericValue,
17
+ expandedContent,
18
+ duration = 200,
19
+ animateOpacity = true,
20
+ disabled = false,
21
+ testID = 'expandable-card',
22
+ children,
23
+ ...cardProps
24
+ }: ExpandableCardProps) => {
25
+ const [internalExpanded, setInternalExpanded] = useState(false);
26
+
27
+ // Use controlled or uncontrolled state
28
+ const isExpanded = controlledExpanded !== undefined ? controlledExpanded : internalExpanded;
29
+
30
+ const handlePress = () => {
31
+ if (disabled) return;
32
+
33
+ const newExpanded = !isExpanded;
34
+
35
+ if (controlledExpanded === undefined) {
36
+ setInternalExpanded(newExpanded);
37
+ }
38
+
39
+ onExpandedChange?.(newExpanded);
40
+ };
41
+
42
+ const renderDefaultContent = () => (
43
+ <>
44
+ <ExpandableCardTrigger
45
+ onPress={handlePress}
46
+ disabled={disabled}
47
+ heading={heading}
48
+ helperText={helperText}
49
+ leadingIcon={leadingIcon}
50
+ leadingContent={leadingContent}
51
+ badge={badge}
52
+ badgePosition={badgePosition}
53
+ numericValue={numericValue}
54
+ isExpanded={isExpanded}
55
+ testID={`${testID}-trigger`}
56
+ />
57
+ <ExpandableCardExpandedContent
58
+ isExpanded={isExpanded}
59
+ duration={duration}
60
+ animateOpacity={animateOpacity}
61
+ >
62
+ {expandedContent}
63
+ </ExpandableCardExpandedContent>
64
+ </>
65
+ );
66
+
67
+ return (
68
+ <Card noPadding {...cardProps} testID={testID}>
69
+ {children || renderDefaultContent()}
70
+ </Card>
71
+ );
72
+ };
73
+
74
+ ExpandableCard.displayName = 'ExpandableCard';
75
+
76
+ export default ExpandableCard;
@@ -0,0 +1,21 @@
1
+ import { View, type ViewProps } from 'react-native';
2
+ import { StyleSheet } from 'react-native-unistyles';
3
+
4
+ const ExpandableCardContent = ({ children, ...props }: ViewProps) => {
5
+ return (
6
+ <View {...props} style={[styles.container, props.style]}>
7
+ {children}
8
+ </View>
9
+ );
10
+ };
11
+
12
+ ExpandableCardContent.displayName = 'ExpandableCardContent';
13
+
14
+ const styles = StyleSheet.create(theme => ({
15
+ container: {
16
+ gap: theme.components.expandableCard.gapVertical,
17
+ flex: 1,
18
+ },
19
+ }));
20
+
21
+ export default ExpandableCardContent;
@@ -0,0 +1,42 @@
1
+ import { View } from 'react-native';
2
+ import { StyleSheet } from 'react-native-unistyles';
3
+ import { Divider } from '../Divider';
4
+ import { Expandable } from '../Expandable';
5
+
6
+ interface ExpandableCardExpandedContentProps {
7
+ children: React.ReactNode;
8
+ isExpanded: boolean;
9
+ duration?: number;
10
+ animateOpacity?: boolean;
11
+ }
12
+
13
+ const ExpandableCardExpandedContent = ({
14
+ children,
15
+ isExpanded,
16
+ duration = 200,
17
+ animateOpacity = true,
18
+ }: ExpandableCardExpandedContentProps) => {
19
+ return (
20
+ <View style={styles.container}>
21
+ <Expandable expanded={isExpanded} duration={duration} animateOpacity={animateOpacity}>
22
+ <View>
23
+ <Divider space="none" />
24
+ <View style={styles.content}>{children}</View>
25
+ </View>
26
+ </Expandable>
27
+ </View>
28
+ );
29
+ };
30
+
31
+ ExpandableCardExpandedContent.displayName = 'ExpandableCardExpandedContent';
32
+
33
+ const styles = StyleSheet.create(theme => ({
34
+ container: {
35
+ width: '100%',
36
+ },
37
+ content: {
38
+ padding: theme.components.card.mobile.padding,
39
+ },
40
+ }));
41
+
42
+ export default ExpandableCardExpandedContent;
@@ -0,0 +1,31 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { ViewProps } from 'react-native';
3
+
4
+ export interface ExpandableCardGroupProps extends ViewProps {
5
+ /**
6
+ * Section heading
7
+ */
8
+ heading?: string;
9
+
10
+ /**
11
+ * Helper text displayed below the heading
12
+ */
13
+ helperText?: string;
14
+
15
+ /**
16
+ * Trailing content for the header (e.g., a link)
17
+ */
18
+ headerTrailingContent?: ReactNode;
19
+
20
+ /**
21
+ * The ExpandableCard children
22
+ */
23
+ children: ReactNode;
24
+
25
+ /**
26
+ * Test ID for testing
27
+ */
28
+ testID?: string;
29
+ }
30
+
31
+ export default ExpandableCardGroupProps;
@@ -0,0 +1,40 @@
1
+ import { View } from 'react-native';
2
+ import { StyleSheet } from 'react-native-unistyles';
3
+ import { SectionHeader } from '../SectionHeader';
4
+ import type ExpandableCardGroupProps from './ExpandableCardGroup.props';
5
+
6
+ const ExpandableCardGroup = ({
7
+ heading,
8
+ helperText,
9
+ headerTrailingContent,
10
+ children,
11
+ style,
12
+ testID = 'expandable-card-group',
13
+ ...props
14
+ }: ExpandableCardGroupProps) => {
15
+ return (
16
+ <View style={[styles.container, style]} testID={testID} {...props}>
17
+ {heading ? (
18
+ <SectionHeader
19
+ heading={heading}
20
+ helperText={helperText}
21
+ trailingContent={headerTrailingContent}
22
+ />
23
+ ) : null}
24
+ <View style={styles.cardsContainer}>{children}</View>
25
+ </View>
26
+ );
27
+ };
28
+
29
+ ExpandableCardGroup.displayName = 'ExpandableCardGroup';
30
+
31
+ const styles = StyleSheet.create(theme => ({
32
+ container: {
33
+ gap: theme.components.expandableCard.group.gap,
34
+ },
35
+ cardsContainer: {
36
+ gap: theme.components.expandableCard.group.gap,
37
+ },
38
+ }));
39
+
40
+ export default ExpandableCardGroup;
@@ -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 ExpandableCardHelperText = ({ children, ...props }: TextProps) => {
6
+ return (
7
+ <BodyText size="md" {...props} style={[styles.text, props.style]}>
8
+ {children}
9
+ </BodyText>
10
+ );
11
+ };
12
+
13
+ ExpandableCardHelperText.displayName = 'ExpandableCardHelperText';
14
+
15
+ const styles = StyleSheet.create(theme => ({
16
+ text: {
17
+ color: theme.color.text.secondary,
18
+ },
19
+ }));
20
+
21
+ export default ExpandableCardHelperText;
@@ -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 ExpandableCardIcon = ({ 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
+ ExpandableCardIcon.displayName = 'ExpandableCardIcon';
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 ExpandableCardIcon;
@@ -0,0 +1,9 @@
1
+ import { View, type ViewProps } from 'react-native';
2
+
3
+ const ExpandableCardLeadingContent = ({ children, ...props }: ViewProps) => (
4
+ <View {...props}>{children}</View>
5
+ );
6
+
7
+ ExpandableCardLeadingContent.displayName = 'ExpandableCardLeadingContent';
8
+
9
+ export default ExpandableCardLeadingContent;
@@ -0,0 +1,14 @@
1
+ import { TextProps } from 'react-native';
2
+ import { BodyText } from '../BodyText';
3
+
4
+ const ExpandableCardText = ({ children, ...props }: TextProps) => {
5
+ return (
6
+ <BodyText size="lg" {...props}>
7
+ {children}
8
+ </BodyText>
9
+ );
10
+ };
11
+
12
+ ExpandableCardText.displayName = 'ExpandableCardText';
13
+
14
+ export default ExpandableCardText;