@ledgerhq/lumen-ui-rnative 0.1.35 → 0.1.36
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.
- package/dist/module/lib/Animations/Pulse/Pulse.js +2 -2
- package/dist/module/lib/Animations/Pulse/Pulse.js.map +1 -1
- package/dist/module/lib/Components/DescriptionItem/DescriptionItem.js +184 -0
- package/dist/module/lib/Components/DescriptionItem/DescriptionItem.js.map +1 -0
- package/dist/module/lib/Components/DescriptionItem/DescriptionItem.mdx +139 -0
- package/dist/module/lib/Components/DescriptionItem/DescriptionItem.stories.js +258 -0
- package/dist/module/lib/Components/DescriptionItem/DescriptionItem.stories.js.map +1 -0
- package/dist/module/lib/Components/DescriptionItem/DescriptionItem.test.js +94 -0
- package/dist/module/lib/Components/DescriptionItem/DescriptionItem.test.js.map +1 -0
- package/dist/module/lib/Components/DescriptionItem/index.js +5 -0
- package/dist/module/lib/Components/DescriptionItem/index.js.map +1 -0
- package/dist/module/lib/Components/DescriptionItem/types.js +4 -0
- package/dist/module/lib/Components/DescriptionItem/types.js.map +1 -0
- package/dist/module/lib/Components/NavBar/CoinCapsule.js +1 -0
- package/dist/module/lib/Components/NavBar/CoinCapsule.js.map +1 -1
- package/dist/module/lib/Components/index.js +1 -0
- package/dist/module/lib/Components/index.js.map +1 -1
- package/dist/typescript/src/lib/Animations/Pulse/Pulse.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/DescriptionItem/DescriptionItem.d.ts +42 -0
- package/dist/typescript/src/lib/Components/DescriptionItem/DescriptionItem.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/DescriptionItem/index.d.ts +3 -0
- package/dist/typescript/src/lib/Components/DescriptionItem/index.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/DescriptionItem/types.d.ts +39 -0
- package/dist/typescript/src/lib/Components/DescriptionItem/types.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/index.d.ts +1 -0
- package/dist/typescript/src/lib/Components/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/lib/Animations/Pulse/Pulse.tsx +6 -3
- package/src/lib/Components/DescriptionItem/DescriptionItem.mdx +139 -0
- package/src/lib/Components/DescriptionItem/DescriptionItem.stories.tsx +234 -0
- package/src/lib/Components/DescriptionItem/DescriptionItem.test.tsx +112 -0
- package/src/lib/Components/DescriptionItem/DescriptionItem.tsx +224 -0
- package/src/lib/Components/DescriptionItem/index.ts +2 -0
- package/src/lib/Components/DescriptionItem/types.ts +44 -0
- package/src/lib/Components/NavBar/CoinCapsule.tsx +1 -0
- package/src/lib/Components/index.ts +1 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-native';
|
|
2
|
+
import { Text, View } from 'react-native';
|
|
3
|
+
import { Information } from '../../Symbols';
|
|
4
|
+
import { InteractiveIcon } from '../InteractiveIcon';
|
|
5
|
+
import { Tag } from '../Tag';
|
|
6
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from '../Tooltip';
|
|
7
|
+
import {
|
|
8
|
+
DescriptionItem,
|
|
9
|
+
DescriptionItemLabel,
|
|
10
|
+
DescriptionItemLeading,
|
|
11
|
+
DescriptionItemTrailing,
|
|
12
|
+
DescriptionItemValue,
|
|
13
|
+
} from './DescriptionItem';
|
|
14
|
+
|
|
15
|
+
const Container = ({ children }: { children: React.ReactNode }) => (
|
|
16
|
+
<View style={{ padding: 8, backgroundColor: '#ffffff', width: 320 }}>
|
|
17
|
+
{children}
|
|
18
|
+
</View>
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const meta: Meta<typeof DescriptionItem> = {
|
|
22
|
+
component: DescriptionItem,
|
|
23
|
+
title: 'Containment/DescriptionItem',
|
|
24
|
+
subcomponents: {
|
|
25
|
+
DescriptionItemLeading,
|
|
26
|
+
DescriptionItemLabel,
|
|
27
|
+
DescriptionItemTrailing,
|
|
28
|
+
DescriptionItemValue,
|
|
29
|
+
},
|
|
30
|
+
parameters: {
|
|
31
|
+
layout: 'centered',
|
|
32
|
+
docs: {
|
|
33
|
+
source: {
|
|
34
|
+
language: 'tsx',
|
|
35
|
+
format: true,
|
|
36
|
+
type: 'code',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
decorators: [
|
|
41
|
+
(Story) => (
|
|
42
|
+
<Container>
|
|
43
|
+
<Story />
|
|
44
|
+
</Container>
|
|
45
|
+
),
|
|
46
|
+
],
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export default meta;
|
|
50
|
+
type Story = StoryObj<typeof DescriptionItem>;
|
|
51
|
+
|
|
52
|
+
export const Base: Story = {
|
|
53
|
+
args: {
|
|
54
|
+
size: 'md',
|
|
55
|
+
},
|
|
56
|
+
render: (args) => (
|
|
57
|
+
<DescriptionItem {...args}>
|
|
58
|
+
<DescriptionItemLeading>
|
|
59
|
+
<DescriptionItemLabel>Fees</DescriptionItemLabel>
|
|
60
|
+
</DescriptionItemLeading>
|
|
61
|
+
<DescriptionItemTrailing>
|
|
62
|
+
<DescriptionItemValue>0.001 BTC</DescriptionItemValue>
|
|
63
|
+
</DescriptionItemTrailing>
|
|
64
|
+
</DescriptionItem>
|
|
65
|
+
),
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const SizeShowcase: Story = {
|
|
69
|
+
args: {
|
|
70
|
+
size: 'md',
|
|
71
|
+
},
|
|
72
|
+
render: () => (
|
|
73
|
+
<View style={{ gap: 16 }}>
|
|
74
|
+
<DescriptionItem size='md'>
|
|
75
|
+
<DescriptionItemLeading>
|
|
76
|
+
<DescriptionItemLabel>Network</DescriptionItemLabel>
|
|
77
|
+
</DescriptionItemLeading>
|
|
78
|
+
<DescriptionItemTrailing>
|
|
79
|
+
<DescriptionItemValue>Ethereum</DescriptionItemValue>
|
|
80
|
+
</DescriptionItemTrailing>
|
|
81
|
+
</DescriptionItem>
|
|
82
|
+
|
|
83
|
+
<DescriptionItem size='md'>
|
|
84
|
+
<DescriptionItemLeading>
|
|
85
|
+
<DescriptionItemLabel>Network</DescriptionItemLabel>
|
|
86
|
+
</DescriptionItemLeading>
|
|
87
|
+
<DescriptionItemTrailing>
|
|
88
|
+
<Tag size='md' label='Ethereum' appearance='base' />
|
|
89
|
+
</DescriptionItemTrailing>
|
|
90
|
+
</DescriptionItem>
|
|
91
|
+
<br />
|
|
92
|
+
<DescriptionItem size='sm'>
|
|
93
|
+
<DescriptionItemLeading>
|
|
94
|
+
<DescriptionItemLabel>Network</DescriptionItemLabel>
|
|
95
|
+
</DescriptionItemLeading>
|
|
96
|
+
<DescriptionItemTrailing>
|
|
97
|
+
<DescriptionItemValue>Ethereum</DescriptionItemValue>
|
|
98
|
+
</DescriptionItemTrailing>
|
|
99
|
+
</DescriptionItem>
|
|
100
|
+
|
|
101
|
+
<DescriptionItem size='sm'>
|
|
102
|
+
<DescriptionItemLeading>
|
|
103
|
+
<DescriptionItemLabel>Network</DescriptionItemLabel>
|
|
104
|
+
</DescriptionItemLeading>
|
|
105
|
+
<DescriptionItemTrailing>
|
|
106
|
+
<Tag size='sm' label='Ethereum' appearance='base' />
|
|
107
|
+
</DescriptionItemTrailing>
|
|
108
|
+
</DescriptionItem>
|
|
109
|
+
</View>
|
|
110
|
+
),
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export const TrailingVariants: Story = {
|
|
114
|
+
render: () => (
|
|
115
|
+
<View style={{ gap: 16 }}>
|
|
116
|
+
<DescriptionItem>
|
|
117
|
+
<DescriptionItemLeading>
|
|
118
|
+
<DescriptionItemLabel>Plain value</DescriptionItemLabel>
|
|
119
|
+
</DescriptionItemLeading>
|
|
120
|
+
<DescriptionItemTrailing>
|
|
121
|
+
<DescriptionItemValue>Ethereum</DescriptionItemValue>
|
|
122
|
+
</DescriptionItemTrailing>
|
|
123
|
+
</DescriptionItem>
|
|
124
|
+
|
|
125
|
+
<DescriptionItem>
|
|
126
|
+
<DescriptionItemLeading>
|
|
127
|
+
<DescriptionItemLabel>Tag</DescriptionItemLabel>
|
|
128
|
+
</DescriptionItemLeading>
|
|
129
|
+
<DescriptionItemTrailing>
|
|
130
|
+
<Tag size='md' label='Confirmed' appearance='success' />
|
|
131
|
+
</DescriptionItemTrailing>
|
|
132
|
+
</DescriptionItem>
|
|
133
|
+
|
|
134
|
+
<DescriptionItem>
|
|
135
|
+
<DescriptionItemLeading>
|
|
136
|
+
<DescriptionItemLabel>Multiple tags</DescriptionItemLabel>
|
|
137
|
+
</DescriptionItemLeading>
|
|
138
|
+
<DescriptionItemTrailing>
|
|
139
|
+
<Tag size='md' label='ERC-20' appearance='base' />
|
|
140
|
+
<Tag size='md' label='New' appearance='accent' />
|
|
141
|
+
</DescriptionItemTrailing>
|
|
142
|
+
</DescriptionItem>
|
|
143
|
+
</View>
|
|
144
|
+
),
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export const WithInfoIcon: Story = {
|
|
148
|
+
render: () => (
|
|
149
|
+
<View style={{ gap: 16 }}>
|
|
150
|
+
<DescriptionItem>
|
|
151
|
+
<DescriptionItemLeading>
|
|
152
|
+
<DescriptionItemLabel>Fees</DescriptionItemLabel>
|
|
153
|
+
<Tooltip>
|
|
154
|
+
<TooltipTrigger>
|
|
155
|
+
<InteractiveIcon
|
|
156
|
+
icon={Information}
|
|
157
|
+
size={16}
|
|
158
|
+
iconType='stroked'
|
|
159
|
+
accessibilityLabel='More information'
|
|
160
|
+
/>
|
|
161
|
+
</TooltipTrigger>
|
|
162
|
+
<TooltipContent content={<Text>Network fee paid to miners</Text>} />
|
|
163
|
+
</Tooltip>
|
|
164
|
+
</DescriptionItemLeading>
|
|
165
|
+
<DescriptionItemTrailing>
|
|
166
|
+
<DescriptionItemValue>0.001 BTC</DescriptionItemValue>
|
|
167
|
+
</DescriptionItemTrailing>
|
|
168
|
+
</DescriptionItem>
|
|
169
|
+
|
|
170
|
+
<DescriptionItem>
|
|
171
|
+
<DescriptionItemLeading>
|
|
172
|
+
<DescriptionItemLabel>Estimated time</DescriptionItemLabel>
|
|
173
|
+
<Tooltip>
|
|
174
|
+
<TooltipTrigger>
|
|
175
|
+
<InteractiveIcon
|
|
176
|
+
icon={Information}
|
|
177
|
+
size={16}
|
|
178
|
+
iconType='stroked'
|
|
179
|
+
accessibilityLabel='More information'
|
|
180
|
+
/>
|
|
181
|
+
</TooltipTrigger>
|
|
182
|
+
<TooltipContent
|
|
183
|
+
content={<Text>Time may vary based on network congestion</Text>}
|
|
184
|
+
/>
|
|
185
|
+
</Tooltip>
|
|
186
|
+
</DescriptionItemLeading>
|
|
187
|
+
<DescriptionItemTrailing>
|
|
188
|
+
<DescriptionItemValue>~30 min</DescriptionItemValue>
|
|
189
|
+
</DescriptionItemTrailing>
|
|
190
|
+
</DescriptionItem>
|
|
191
|
+
</View>
|
|
192
|
+
),
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export const TruncationBehavior: Story = {
|
|
196
|
+
render: () => (
|
|
197
|
+
<View style={{ gap: 16 }}>
|
|
198
|
+
<DescriptionItem>
|
|
199
|
+
<DescriptionItemLeading>
|
|
200
|
+
<DescriptionItemLabel>
|
|
201
|
+
This is a very long label that should go to a second line.
|
|
202
|
+
</DescriptionItemLabel>
|
|
203
|
+
</DescriptionItemLeading>
|
|
204
|
+
<DescriptionItemTrailing>
|
|
205
|
+
<DescriptionItemValue>0.001 BTC</DescriptionItemValue>
|
|
206
|
+
</DescriptionItemTrailing>
|
|
207
|
+
</DescriptionItem>
|
|
208
|
+
|
|
209
|
+
<DescriptionItem>
|
|
210
|
+
<DescriptionItemLeading>
|
|
211
|
+
<DescriptionItemLabel>Label</DescriptionItemLabel>
|
|
212
|
+
</DescriptionItemLeading>
|
|
213
|
+
<DescriptionItemTrailing>
|
|
214
|
+
<DescriptionItemValue>
|
|
215
|
+
0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
|
|
216
|
+
</DescriptionItemValue>
|
|
217
|
+
</DescriptionItemTrailing>
|
|
218
|
+
</DescriptionItem>
|
|
219
|
+
|
|
220
|
+
<DescriptionItem>
|
|
221
|
+
<DescriptionItemLeading>
|
|
222
|
+
<DescriptionItemLabel>
|
|
223
|
+
Destination address on network
|
|
224
|
+
</DescriptionItemLabel>
|
|
225
|
+
</DescriptionItemLeading>
|
|
226
|
+
<DescriptionItemTrailing>
|
|
227
|
+
<DescriptionItemValue>
|
|
228
|
+
0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
|
|
229
|
+
</DescriptionItemValue>
|
|
230
|
+
</DescriptionItemTrailing>
|
|
231
|
+
</DescriptionItem>
|
|
232
|
+
</View>
|
|
233
|
+
),
|
|
234
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { describe, it, expect } from '@jest/globals';
|
|
2
|
+
import { ledgerLiveThemes } from '@ledgerhq/lumen-design-core';
|
|
3
|
+
import { render, screen } from '@testing-library/react-native';
|
|
4
|
+
|
|
5
|
+
import { ThemeProvider } from '../ThemeProvider/ThemeProvider';
|
|
6
|
+
import {
|
|
7
|
+
DescriptionItem,
|
|
8
|
+
DescriptionItemLabel,
|
|
9
|
+
DescriptionItemLeading,
|
|
10
|
+
DescriptionItemTrailing,
|
|
11
|
+
DescriptionItemValue,
|
|
12
|
+
} from './DescriptionItem';
|
|
13
|
+
import type { DescriptionItemProps, DescriptionItemSize } from './types';
|
|
14
|
+
|
|
15
|
+
const typographyTokens = ledgerLiveThemes.dark.typographies.sm;
|
|
16
|
+
const typographies = {
|
|
17
|
+
...typographyTokens.heading,
|
|
18
|
+
...typographyTokens.body,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const TestWrapper = ({ children }: { children: React.ReactNode }) => (
|
|
22
|
+
<ThemeProvider themes={ledgerLiveThemes} colorScheme='dark' locale='en'>
|
|
23
|
+
{children}
|
|
24
|
+
</ThemeProvider>
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const renderDescriptionItem = (props: Partial<DescriptionItemProps> = {}) =>
|
|
28
|
+
render(
|
|
29
|
+
<TestWrapper>
|
|
30
|
+
<DescriptionItem testID='description-item' {...props}>
|
|
31
|
+
<DescriptionItemLeading testID='leading'>
|
|
32
|
+
<DescriptionItemLabel>Label</DescriptionItemLabel>
|
|
33
|
+
</DescriptionItemLeading>
|
|
34
|
+
<DescriptionItemTrailing testID='trailing'>
|
|
35
|
+
<DescriptionItemValue>Value</DescriptionItemValue>
|
|
36
|
+
</DescriptionItemTrailing>
|
|
37
|
+
</DescriptionItem>
|
|
38
|
+
</TestWrapper>,
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
describe('DescriptionItem', () => {
|
|
42
|
+
describe('Rendering', () => {
|
|
43
|
+
it('renders label and value', () => {
|
|
44
|
+
renderDescriptionItem();
|
|
45
|
+
|
|
46
|
+
expect(screen.getByText('Label')).toBeTruthy();
|
|
47
|
+
expect(screen.getByText('Value')).toBeTruthy();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('forwards testID to sub-components', () => {
|
|
51
|
+
renderDescriptionItem();
|
|
52
|
+
|
|
53
|
+
expect(screen.getByTestId('description-item')).toBeTruthy();
|
|
54
|
+
expect(screen.getByTestId('leading')).toBeTruthy();
|
|
55
|
+
expect(screen.getByTestId('trailing')).toBeTruthy();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe('DescriptionItemLabel', () => {
|
|
60
|
+
it.each([
|
|
61
|
+
['md', typographies.body2],
|
|
62
|
+
['sm', typographies.body3],
|
|
63
|
+
])('applies %s size typography', (size, expectedTypography) => {
|
|
64
|
+
renderDescriptionItem({ size: size as DescriptionItemSize });
|
|
65
|
+
|
|
66
|
+
const labelStyle = screen.getByText('Label').props.style;
|
|
67
|
+
expect(labelStyle.fontSize).toBe(expectedTypography.fontSize);
|
|
68
|
+
expect(labelStyle.fontWeight).toBe(expectedTypography.fontWeight);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('defaults to md typography when no size is provided', () => {
|
|
72
|
+
renderDescriptionItem();
|
|
73
|
+
|
|
74
|
+
const labelStyle = screen.getByText('Label').props.style;
|
|
75
|
+
expect(labelStyle.fontSize).toBe(typographies.body2.fontSize);
|
|
76
|
+
expect(labelStyle.fontWeight).toBe(typographies.body2.fontWeight);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('truncates label to two lines by default', () => {
|
|
80
|
+
renderDescriptionItem();
|
|
81
|
+
|
|
82
|
+
expect(screen.getByText('Label').props.numberOfLines).toBe(2);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe('DescriptionItemValue', () => {
|
|
87
|
+
it.each([
|
|
88
|
+
['md', typographies.body2SemiBold],
|
|
89
|
+
['sm', typographies.body3SemiBold],
|
|
90
|
+
])('applies %s size typography', (size, expectedTypography) => {
|
|
91
|
+
renderDescriptionItem({ size: size as DescriptionItemSize });
|
|
92
|
+
|
|
93
|
+
const valueStyle = screen.getByText('Value').props.style;
|
|
94
|
+
expect(valueStyle.fontSize).toBe(expectedTypography.fontSize);
|
|
95
|
+
expect(valueStyle.fontWeight).toBe(expectedTypography.fontWeight);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('defaults to md typography when no size is provided', () => {
|
|
99
|
+
renderDescriptionItem();
|
|
100
|
+
|
|
101
|
+
const valueStyle = screen.getByText('Value').props.style;
|
|
102
|
+
expect(valueStyle.fontSize).toBe(typographies.body2SemiBold.fontSize);
|
|
103
|
+
expect(valueStyle.fontWeight).toBe(typographies.body2SemiBold.fontWeight);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('truncates value to one line by default', () => {
|
|
107
|
+
renderDescriptionItem();
|
|
108
|
+
|
|
109
|
+
expect(screen.getByText('Value').props.numberOfLines).toBe(1);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
});
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { createSafeContext } from '@ledgerhq/lumen-utils-shared';
|
|
2
|
+
import { StyleSheet } from 'react-native';
|
|
3
|
+
import { useStyleSheet } from '../../../styles';
|
|
4
|
+
import { Box, Text } from '../Utility';
|
|
5
|
+
import type {
|
|
6
|
+
DescriptionItemLabelProps,
|
|
7
|
+
DescriptionItemLeadingProps,
|
|
8
|
+
DescriptionItemProps,
|
|
9
|
+
DescriptionItemSize,
|
|
10
|
+
DescriptionItemTrailingProps,
|
|
11
|
+
DescriptionItemValueProps,
|
|
12
|
+
} from './types';
|
|
13
|
+
|
|
14
|
+
type DescriptionItemSizeContextValue = {
|
|
15
|
+
size: DescriptionItemSize;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const [DescriptionItemSizeProvider, useDescriptionItemSizeContext] =
|
|
19
|
+
createSafeContext<DescriptionItemSizeContextValue>('DescriptionItemSize', {
|
|
20
|
+
size: 'md',
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A compound component for displaying a key-value description row.
|
|
25
|
+
* Composed with DescriptionItemLeading / DescriptionItemLabel (key side)
|
|
26
|
+
* and DescriptionItemTrailing / DescriptionItemValue (value side).
|
|
27
|
+
*
|
|
28
|
+
* @see {@link https://ldls.vercel.app/?path=/docs/containment-descriptionitem--docs Storybook}
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* <DescriptionItem size="md">
|
|
32
|
+
* <DescriptionItemLeading>
|
|
33
|
+
* <DescriptionItemLabel>Fees</DescriptionItemLabel>
|
|
34
|
+
* </DescriptionItemLeading>
|
|
35
|
+
* <DescriptionItemTrailing>
|
|
36
|
+
* <DescriptionItemValue>0.001 BTC</DescriptionItemValue>
|
|
37
|
+
* </DescriptionItemTrailing>
|
|
38
|
+
* </DescriptionItem>
|
|
39
|
+
*/
|
|
40
|
+
export const DescriptionItem = ({
|
|
41
|
+
children,
|
|
42
|
+
lx = {},
|
|
43
|
+
style,
|
|
44
|
+
size = 'md',
|
|
45
|
+
...props
|
|
46
|
+
}: DescriptionItemProps) => {
|
|
47
|
+
const styles = useStyleSheet(
|
|
48
|
+
(t) => ({
|
|
49
|
+
root: {
|
|
50
|
+
width: '100%',
|
|
51
|
+
flexDirection: 'row',
|
|
52
|
+
alignItems: 'flex-start',
|
|
53
|
+
gap: t.spacings.s12,
|
|
54
|
+
},
|
|
55
|
+
}),
|
|
56
|
+
[],
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<DescriptionItemSizeProvider value={{ size }}>
|
|
61
|
+
<Box lx={lx} style={StyleSheet.flatten([styles.root, style])} {...props}>
|
|
62
|
+
{children}
|
|
63
|
+
</Box>
|
|
64
|
+
</DescriptionItemSizeProvider>
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Layout container for the leading (left) side of the description item.
|
|
70
|
+
* Contains DescriptionItemLabel and an optional info icon sibling.
|
|
71
|
+
*/
|
|
72
|
+
export const DescriptionItemLeading = ({
|
|
73
|
+
children,
|
|
74
|
+
lx = {},
|
|
75
|
+
style,
|
|
76
|
+
...props
|
|
77
|
+
}: DescriptionItemLeadingProps) => {
|
|
78
|
+
const styles = useStyleSheet(
|
|
79
|
+
(t) => ({
|
|
80
|
+
leading: {
|
|
81
|
+
flex: 1,
|
|
82
|
+
minWidth: 0,
|
|
83
|
+
flexDirection: 'row',
|
|
84
|
+
alignItems: 'center',
|
|
85
|
+
gap: t.spacings.s4,
|
|
86
|
+
},
|
|
87
|
+
}),
|
|
88
|
+
[],
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<Box lx={lx} style={StyleSheet.flatten([styles.leading, style])} {...props}>
|
|
93
|
+
{children}
|
|
94
|
+
</Box>
|
|
95
|
+
);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Typography-bearing label for the leading side.
|
|
100
|
+
* Reads size from DescriptionItemSizeContext to apply the correct typography
|
|
101
|
+
* based on the size of the parent `DescriptionItem`.
|
|
102
|
+
*/
|
|
103
|
+
export const DescriptionItemLabel = ({
|
|
104
|
+
children,
|
|
105
|
+
lx = {},
|
|
106
|
+
style,
|
|
107
|
+
numberOfLines = 2,
|
|
108
|
+
ellipsizeMode = 'tail',
|
|
109
|
+
...props
|
|
110
|
+
}: DescriptionItemLabelProps) => {
|
|
111
|
+
const { size } = useDescriptionItemSizeContext({
|
|
112
|
+
consumerName: 'DescriptionItemLabel',
|
|
113
|
+
contextRequired: false,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const styles = useStyleSheet(
|
|
117
|
+
(t) => ({
|
|
118
|
+
label: StyleSheet.flatten([
|
|
119
|
+
size === 'md' ? t.typographies.body2 : t.typographies.body3,
|
|
120
|
+
{
|
|
121
|
+
flexShrink: 1,
|
|
122
|
+
minWidth: 0,
|
|
123
|
+
color: t.colors.text.muted,
|
|
124
|
+
},
|
|
125
|
+
]),
|
|
126
|
+
}),
|
|
127
|
+
[size],
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<Text
|
|
132
|
+
lx={lx}
|
|
133
|
+
style={StyleSheet.flatten([styles.label, style])}
|
|
134
|
+
numberOfLines={numberOfLines}
|
|
135
|
+
ellipsizeMode={ellipsizeMode}
|
|
136
|
+
allowFontScaling={false}
|
|
137
|
+
{...props}
|
|
138
|
+
>
|
|
139
|
+
{children}
|
|
140
|
+
</Text>
|
|
141
|
+
);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Layout container for the trailing (right) side of the description item.
|
|
146
|
+
* Accepts DescriptionItemValue, Tag, Link, or any custom content.
|
|
147
|
+
*/
|
|
148
|
+
export const DescriptionItemTrailing = ({
|
|
149
|
+
children,
|
|
150
|
+
lx = {},
|
|
151
|
+
style,
|
|
152
|
+
...props
|
|
153
|
+
}: DescriptionItemTrailingProps) => {
|
|
154
|
+
const styles = useStyleSheet(
|
|
155
|
+
(t) => ({
|
|
156
|
+
trailing: {
|
|
157
|
+
flexShrink: 0,
|
|
158
|
+
maxWidth: '80%',
|
|
159
|
+
flexDirection: 'row',
|
|
160
|
+
alignItems: 'center',
|
|
161
|
+
gap: t.spacings.s4,
|
|
162
|
+
},
|
|
163
|
+
}),
|
|
164
|
+
[],
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
return (
|
|
168
|
+
<Box
|
|
169
|
+
lx={lx}
|
|
170
|
+
style={StyleSheet.flatten([styles.trailing, style])}
|
|
171
|
+
{...props}
|
|
172
|
+
>
|
|
173
|
+
{children}
|
|
174
|
+
</Box>
|
|
175
|
+
);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Typography-bearing value for the trailing side.
|
|
180
|
+
* Reads size from DescriptionItemSizeContext to apply the correct typography
|
|
181
|
+
* based on the size of the parent `DescriptionItem`.
|
|
182
|
+
*/
|
|
183
|
+
export const DescriptionItemValue = ({
|
|
184
|
+
children,
|
|
185
|
+
lx = {},
|
|
186
|
+
style,
|
|
187
|
+
numberOfLines = 1,
|
|
188
|
+
ellipsizeMode = 'tail',
|
|
189
|
+
...props
|
|
190
|
+
}: DescriptionItemValueProps) => {
|
|
191
|
+
const { size } = useDescriptionItemSizeContext({
|
|
192
|
+
consumerName: 'DescriptionItemValue',
|
|
193
|
+
contextRequired: false,
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
const styles = useStyleSheet(
|
|
197
|
+
(t) => ({
|
|
198
|
+
value: StyleSheet.flatten([
|
|
199
|
+
size === 'md'
|
|
200
|
+
? t.typographies.body2SemiBold
|
|
201
|
+
: t.typographies.body3SemiBold,
|
|
202
|
+
{
|
|
203
|
+
flexShrink: 1,
|
|
204
|
+
minWidth: 0,
|
|
205
|
+
color: t.colors.text.base,
|
|
206
|
+
},
|
|
207
|
+
]),
|
|
208
|
+
}),
|
|
209
|
+
[size],
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
return (
|
|
213
|
+
<Text
|
|
214
|
+
lx={lx}
|
|
215
|
+
style={StyleSheet.flatten([styles.value, style])}
|
|
216
|
+
numberOfLines={numberOfLines}
|
|
217
|
+
ellipsizeMode={ellipsizeMode}
|
|
218
|
+
allowFontScaling={false}
|
|
219
|
+
{...props}
|
|
220
|
+
>
|
|
221
|
+
{children}
|
|
222
|
+
</Text>
|
|
223
|
+
);
|
|
224
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { StyledTextProps, StyledViewProps } from '../../../styles';
|
|
3
|
+
|
|
4
|
+
export type DescriptionItemSize = 'sm' | 'md';
|
|
5
|
+
|
|
6
|
+
export type DescriptionItemProps = {
|
|
7
|
+
/**
|
|
8
|
+
* The content of the description item (DescriptionItemLeading, DescriptionItemTrailing).
|
|
9
|
+
*/
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
/**
|
|
12
|
+
* The size of the description item.
|
|
13
|
+
* @default 'md'
|
|
14
|
+
*/
|
|
15
|
+
size?: DescriptionItemSize;
|
|
16
|
+
} & Omit<StyledViewProps, 'children'>;
|
|
17
|
+
|
|
18
|
+
export type DescriptionItemLeadingProps = {
|
|
19
|
+
/**
|
|
20
|
+
* The leading content (DescriptionItemLabel + optional info icon sibling).
|
|
21
|
+
*/
|
|
22
|
+
children: ReactNode;
|
|
23
|
+
} & Omit<StyledViewProps, 'children'>;
|
|
24
|
+
|
|
25
|
+
export type DescriptionItemLabelProps = {
|
|
26
|
+
/**
|
|
27
|
+
* The label text or custom content.
|
|
28
|
+
*/
|
|
29
|
+
children: ReactNode;
|
|
30
|
+
} & Omit<StyledTextProps, 'children'>;
|
|
31
|
+
|
|
32
|
+
export type DescriptionItemTrailingProps = {
|
|
33
|
+
/**
|
|
34
|
+
* The trailing content (DescriptionItemValue, Tag, Link, etc.).
|
|
35
|
+
*/
|
|
36
|
+
children: ReactNode;
|
|
37
|
+
} & Omit<StyledViewProps, 'children'>;
|
|
38
|
+
|
|
39
|
+
export type DescriptionItemValueProps = {
|
|
40
|
+
/**
|
|
41
|
+
* The value text or custom content.
|
|
42
|
+
*/
|
|
43
|
+
children: ReactNode;
|
|
44
|
+
} & Omit<StyledTextProps, 'children'>;
|