@ledgerhq/lumen-ui-rnative 0.1.24 → 0.1.26
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/index.js +1 -0
- package/dist/module/index.js.map +1 -1
- package/dist/module/lib/Components/Avatar/Avatar.js +22 -23
- package/dist/module/lib/Components/Avatar/Avatar.js.map +1 -1
- package/dist/module/lib/Components/Avatar/Avatar.test.js +17 -23
- package/dist/module/lib/Components/Avatar/Avatar.test.js.map +1 -1
- package/dist/module/lib/Components/DotCount/DotCount.js +128 -0
- package/dist/module/lib/Components/DotCount/DotCount.js.map +1 -0
- package/dist/module/lib/Components/DotCount/DotCount.mdx +86 -0
- package/dist/module/lib/Components/DotCount/DotCount.stories.js +172 -0
- package/dist/module/lib/Components/DotCount/DotCount.stories.js.map +1 -0
- package/dist/module/lib/Components/DotCount/DotCount.test.js +174 -0
- package/dist/module/lib/Components/DotCount/DotCount.test.js.map +1 -0
- package/dist/module/lib/Components/DotCount/index.js +5 -0
- package/dist/module/lib/Components/DotCount/index.js.map +1 -0
- package/dist/module/lib/Components/DotCount/types.js +4 -0
- package/dist/module/lib/Components/DotCount/types.js.map +1 -0
- package/dist/module/lib/Components/DotIcon/DotIcon.js +134 -0
- package/dist/module/lib/Components/DotIcon/DotIcon.js.map +1 -0
- package/dist/module/lib/Components/DotIcon/DotIcon.mdx +56 -0
- package/dist/module/lib/Components/DotIcon/DotIcon.stories.js +217 -0
- package/dist/module/lib/Components/DotIcon/DotIcon.stories.js.map +1 -0
- package/dist/module/lib/Components/DotIcon/DotIcon.test.js +238 -0
- package/dist/module/lib/Components/DotIcon/DotIcon.test.js.map +1 -0
- package/dist/module/lib/Components/DotIcon/index.js +5 -0
- package/dist/module/lib/Components/DotIcon/index.js.map +1 -0
- package/dist/module/lib/Components/DotIcon/types.js +4 -0
- package/dist/module/lib/Components/DotIcon/types.js.map +1 -0
- package/dist/module/lib/Components/DotIndicator/DotIndicator.js +89 -0
- package/dist/module/lib/Components/DotIndicator/DotIndicator.js.map +1 -0
- package/dist/module/lib/Components/DotIndicator/DotIndicator.mdx +82 -0
- package/dist/module/lib/Components/DotIndicator/DotIndicator.stories.js +84 -0
- package/dist/module/lib/Components/DotIndicator/DotIndicator.stories.js.map +1 -0
- package/dist/module/lib/Components/DotIndicator/DotIndicator.test.js +136 -0
- package/dist/module/lib/Components/DotIndicator/DotIndicator.test.js.map +1 -0
- package/dist/module/lib/Components/DotIndicator/index.js +5 -0
- package/dist/module/lib/Components/DotIndicator/index.js.map +1 -0
- package/dist/module/lib/Components/DotIndicator/types.js +4 -0
- package/dist/module/lib/Components/DotIndicator/types.js.map +1 -0
- package/dist/module/lib/Components/DotSymbol/DotSymbol.js +29 -22
- package/dist/module/lib/Components/DotSymbol/DotSymbol.js.map +1 -1
- package/dist/module/lib/Components/DotSymbol/DotSymbol.stories.js +31 -9
- package/dist/module/lib/Components/DotSymbol/DotSymbol.stories.js.map +1 -1
- package/dist/module/lib/Components/MediaImage/MediaImage.js +2 -1
- package/dist/module/lib/Components/MediaImage/MediaImage.js.map +1 -1
- package/dist/module/lib/Components/MediaImage/MediaImage.stories.js +4 -0
- package/dist/module/lib/Components/MediaImage/MediaImage.stories.js.map +1 -1
- package/dist/module/lib/Components/Spinner/Spinner.js +6 -1
- package/dist/module/lib/Components/Spinner/Spinner.js.map +1 -1
- package/dist/module/lib/Components/TabBar/TabBar.js +16 -13
- package/dist/module/lib/Components/TabBar/TabBar.js.map +1 -1
- package/dist/module/lib/Components/Tag/Tag.js +2 -0
- package/dist/module/lib/Components/Tag/Tag.js.map +1 -1
- package/dist/module/lib/Components/Tag/Tag.stories.js +8 -1
- package/dist/module/lib/Components/Tag/Tag.stories.js.map +1 -1
- package/dist/module/lib/Components/index.js +3 -0
- package/dist/module/lib/Components/index.js.map +1 -1
- package/dist/typescript/src/index.d.ts +1 -0
- package/dist/typescript/src/index.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Avatar/Avatar.d.ts +1 -1
- package/dist/typescript/src/lib/Components/Avatar/Avatar.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/DotCount/DotCount.d.ts +3 -0
- package/dist/typescript/src/lib/Components/DotCount/DotCount.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/DotCount/index.d.ts +3 -0
- package/dist/typescript/src/lib/Components/DotCount/index.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/DotCount/types.d.ts +40 -0
- package/dist/typescript/src/lib/Components/DotCount/types.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/DotIcon/DotIcon.d.ts +30 -0
- package/dist/typescript/src/lib/Components/DotIcon/DotIcon.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/DotIcon/index.d.ts +3 -0
- package/dist/typescript/src/lib/Components/DotIcon/index.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/DotIcon/types.d.ts +40 -0
- package/dist/typescript/src/lib/Components/DotIcon/types.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/DotIndicator/DotIndicator.d.ts +3 -0
- package/dist/typescript/src/lib/Components/DotIndicator/DotIndicator.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/DotIndicator/index.d.ts +3 -0
- package/dist/typescript/src/lib/Components/DotIndicator/index.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/DotIndicator/types.d.ts +25 -0
- package/dist/typescript/src/lib/Components/DotIndicator/types.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/DotSymbol/DotSymbol.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/MediaImage/MediaImage.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/MediaImage/types.d.ts +1 -1
- package/dist/typescript/src/lib/Components/MediaImage/types.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Spinner/Spinner.d.ts +1 -1
- package/dist/typescript/src/lib/Components/Spinner/Spinner.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/TabBar/TabBar.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Tag/Tag.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/Tag/types.d.ts +1 -1
- package/dist/typescript/src/lib/Components/Tag/types.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/index.d.ts +3 -0
- package/dist/typescript/src/lib/Components/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/lib/Components/Avatar/Avatar.test.tsx +17 -27
- package/src/lib/Components/Avatar/Avatar.tsx +24 -21
- package/src/lib/Components/DotCount/DotCount.mdx +86 -0
- package/src/lib/Components/DotCount/DotCount.stories.tsx +124 -0
- package/src/lib/Components/DotCount/DotCount.test.tsx +150 -0
- package/src/lib/Components/DotCount/DotCount.tsx +130 -0
- package/src/lib/Components/DotCount/index.ts +2 -0
- package/src/lib/Components/DotCount/types.ts +40 -0
- package/src/lib/Components/DotIcon/DotIcon.mdx +56 -0
- package/src/lib/Components/DotIcon/DotIcon.stories.tsx +154 -0
- package/src/lib/Components/DotIcon/DotIcon.test.tsx +224 -0
- package/src/lib/Components/DotIcon/DotIcon.tsx +146 -0
- package/src/lib/Components/DotIcon/index.ts +6 -0
- package/src/lib/Components/DotIcon/types.ts +44 -0
- package/src/lib/Components/DotIndicator/DotIndicator.mdx +82 -0
- package/src/lib/Components/DotIndicator/DotIndicator.stories.tsx +67 -0
- package/src/lib/Components/DotIndicator/DotIndicator.test.tsx +132 -0
- package/src/lib/Components/DotIndicator/DotIndicator.tsx +97 -0
- package/src/lib/Components/DotIndicator/index.ts +2 -0
- package/src/lib/Components/DotIndicator/types.ts +25 -0
- package/src/lib/Components/DotSymbol/DotSymbol.stories.tsx +26 -7
- package/src/lib/Components/DotSymbol/DotSymbol.tsx +22 -23
- package/src/lib/Components/MediaImage/MediaImage.stories.tsx +1 -0
- package/src/lib/Components/MediaImage/MediaImage.tsx +3 -1
- package/src/lib/Components/MediaImage/types.ts +1 -1
- package/src/lib/Components/Spinner/Spinner.tsx +6 -2
- package/src/lib/Components/TabBar/TabBar.tsx +17 -16
- package/src/lib/Components/Tag/Tag.stories.tsx +11 -1
- package/src/lib/Components/Tag/Tag.tsx +2 -0
- package/src/lib/Components/Tag/types.ts +8 -1
- package/src/lib/Components/index.ts +3 -0
|
@@ -4,12 +4,15 @@ export * from './AmountInput';
|
|
|
4
4
|
export * from './Avatar';
|
|
5
5
|
export * from './Banner';
|
|
6
6
|
export * from './BottomSheet';
|
|
7
|
+
export * from './DotCount';
|
|
8
|
+
export * from './DotIndicator';
|
|
7
9
|
export * from './Button';
|
|
8
10
|
export * from './Card';
|
|
9
11
|
export * from './CardButton';
|
|
10
12
|
export * from './ContentBanner';
|
|
11
13
|
export * from './Checkbox';
|
|
12
14
|
export * from './Divider';
|
|
15
|
+
export * from './DotIcon';
|
|
13
16
|
export * from './DotSymbol';
|
|
14
17
|
export * from './Icon';
|
|
15
18
|
export * from './IconButton';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/lib/Components/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,OAAO,CAAC;AACtB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/lib/Components/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,OAAO,CAAC;AACtB,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC"}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { render, waitFor } from '@testing-library/react-native';
|
|
|
4
4
|
import { ThemeProvider } from '../ThemeProvider/ThemeProvider';
|
|
5
5
|
import { Avatar } from './Avatar';
|
|
6
6
|
|
|
7
|
-
const {
|
|
7
|
+
const { sizes } = ledgerLiveThemes.dark;
|
|
8
8
|
|
|
9
9
|
const TestWrapper = ({ children }: { children: React.ReactNode }) => (
|
|
10
10
|
<ThemeProvider themes={ledgerLiveThemes} colorScheme='dark' locale='en'>
|
|
@@ -145,45 +145,39 @@ describe('Avatar Component', () => {
|
|
|
145
145
|
});
|
|
146
146
|
|
|
147
147
|
it('should show notification indicator when showNotification is true', () => {
|
|
148
|
-
const { getByTestId } = render(
|
|
148
|
+
const { getByTestId, toJSON } = render(
|
|
149
149
|
<TestWrapper>
|
|
150
150
|
<Avatar testID='avatar-id' showNotification />
|
|
151
151
|
</TestWrapper>,
|
|
152
152
|
);
|
|
153
153
|
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
expect(
|
|
158
|
-
expect(
|
|
159
|
-
colors.bg.errorStrong,
|
|
160
|
-
);
|
|
154
|
+
const tree = toJSON();
|
|
155
|
+
expect(tree.children).toHaveLength(2);
|
|
156
|
+
expect(tree.children[0].props.accessibilityRole).toBe('image');
|
|
157
|
+
expect(tree.children[0].props.pointerEvents).toBe('none');
|
|
158
|
+
expect(getByTestId('avatar-id')).toBeTruthy();
|
|
161
159
|
});
|
|
162
160
|
|
|
163
161
|
it('should not show notification indicator by default', () => {
|
|
164
|
-
const {
|
|
162
|
+
const { toJSON } = render(
|
|
165
163
|
<TestWrapper>
|
|
166
164
|
<Avatar testID='avatar-id' />
|
|
167
165
|
</TestWrapper>,
|
|
168
166
|
);
|
|
169
167
|
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
expect(notificationIndicator).toBe(false);
|
|
168
|
+
const tree = toJSON();
|
|
169
|
+
expect(tree.props.testID).toBe('avatar-id');
|
|
174
170
|
});
|
|
175
171
|
|
|
176
172
|
it('should apply correct notification indicator size based on avatar size', () => {
|
|
177
|
-
const {
|
|
173
|
+
const { toJSON, rerender } = render(
|
|
178
174
|
<TestWrapper>
|
|
179
175
|
<Avatar testID='avatar-id' size='sm' showNotification />
|
|
180
176
|
</TestWrapper>,
|
|
181
177
|
);
|
|
182
178
|
|
|
183
|
-
let
|
|
184
|
-
|
|
185
|
-
expect(notificationIndicator.props.style.width).toBe(sizes.s10);
|
|
186
|
-
expect(notificationIndicator.props.style.height).toBe(sizes.s10);
|
|
179
|
+
let dot = toJSON().children[0];
|
|
180
|
+
expect(dot.props.style.height).toBe(sizes.s10);
|
|
187
181
|
|
|
188
182
|
rerender(
|
|
189
183
|
<TestWrapper>
|
|
@@ -191,10 +185,8 @@ describe('Avatar Component', () => {
|
|
|
191
185
|
</TestWrapper>,
|
|
192
186
|
);
|
|
193
187
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
expect(notificationIndicator.props.style.width).toBe(sizes.s12);
|
|
197
|
-
expect(notificationIndicator.props.style.height).toBe(sizes.s12);
|
|
188
|
+
dot = toJSON().children[0];
|
|
189
|
+
expect(dot.props.style.height).toBe(sizes.s12);
|
|
198
190
|
|
|
199
191
|
rerender(
|
|
200
192
|
<TestWrapper>
|
|
@@ -202,10 +194,8 @@ describe('Avatar Component', () => {
|
|
|
202
194
|
</TestWrapper>,
|
|
203
195
|
);
|
|
204
196
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
expect(notificationIndicator.props.style.width).toBe(sizes.s16);
|
|
208
|
-
expect(notificationIndicator.props.style.height).toBe(sizes.s16);
|
|
197
|
+
dot = toJSON().children[0];
|
|
198
|
+
expect(dot.props.style.height).toBe(sizes.s16);
|
|
209
199
|
});
|
|
210
200
|
|
|
211
201
|
it('should apply custom styles', () => {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { useState, useEffect } from 'react';
|
|
2
|
-
import { StyleSheet, Image
|
|
2
|
+
import { StyleSheet, Image } from 'react-native';
|
|
3
3
|
import { useCommonTranslation } from '../../../i18n';
|
|
4
4
|
import { useStyleSheet } from '../../../styles';
|
|
5
5
|
import { User } from '../../Symbols';
|
|
6
|
+
import { DotIndicator } from '../DotIndicator';
|
|
6
7
|
import { Box } from '../Utility';
|
|
7
8
|
import type { AvatarProps } from './types';
|
|
8
9
|
|
|
@@ -14,6 +15,15 @@ const fallbackSizes = {
|
|
|
14
15
|
lg: 32,
|
|
15
16
|
} as const;
|
|
16
17
|
|
|
18
|
+
const dotSizeMap: Record<
|
|
19
|
+
Size,
|
|
20
|
+
NonNullable<React.ComponentProps<typeof DotIndicator>['size']>
|
|
21
|
+
> = {
|
|
22
|
+
sm: 'xs',
|
|
23
|
+
md: 'sm',
|
|
24
|
+
lg: 'md',
|
|
25
|
+
};
|
|
26
|
+
|
|
17
27
|
const useStyles = ({ size }: { size: Size }) => {
|
|
18
28
|
return useStyleSheet(
|
|
19
29
|
(t) => {
|
|
@@ -23,12 +33,6 @@ const useStyles = ({ size }: { size: Size }) => {
|
|
|
23
33
|
lg: { size: t.sizes.s72, padding: t.spacings.s4 },
|
|
24
34
|
};
|
|
25
35
|
|
|
26
|
-
const notificationsMap = {
|
|
27
|
-
sm: t.sizes.s10,
|
|
28
|
-
md: t.sizes.s12,
|
|
29
|
-
lg: t.sizes.s16,
|
|
30
|
-
};
|
|
31
|
-
|
|
32
36
|
return {
|
|
33
37
|
root: {
|
|
34
38
|
position: 'relative',
|
|
@@ -40,16 +44,6 @@ const useStyles = ({ size }: { size: Size }) => {
|
|
|
40
44
|
justifyContent: 'center',
|
|
41
45
|
padding: sizeMap[size].padding,
|
|
42
46
|
},
|
|
43
|
-
notification: {
|
|
44
|
-
position: 'absolute',
|
|
45
|
-
top: 0,
|
|
46
|
-
right: 0,
|
|
47
|
-
width: notificationsMap[size],
|
|
48
|
-
height: notificationsMap[size],
|
|
49
|
-
borderRadius: 9999,
|
|
50
|
-
backgroundColor: t.colors.bg.errorStrong,
|
|
51
|
-
zIndex: 1,
|
|
52
|
-
},
|
|
53
47
|
image: {
|
|
54
48
|
width: '100%',
|
|
55
49
|
height: '100%',
|
|
@@ -85,6 +79,7 @@ export const Avatar = ({
|
|
|
85
79
|
alt = 'avatar',
|
|
86
80
|
size = 'md',
|
|
87
81
|
showNotification = false,
|
|
82
|
+
testID,
|
|
88
83
|
ref,
|
|
89
84
|
...props
|
|
90
85
|
}: AvatarProps) => {
|
|
@@ -103,18 +98,16 @@ export const Avatar = ({
|
|
|
103
98
|
setError(false);
|
|
104
99
|
}, [src]);
|
|
105
100
|
|
|
106
|
-
|
|
101
|
+
const avatarContent = (
|
|
107
102
|
<Box
|
|
108
103
|
ref={ref}
|
|
109
104
|
lx={lx}
|
|
110
105
|
style={StyleSheet.flatten([styles.root, style])}
|
|
111
106
|
accessibilityRole='image'
|
|
112
107
|
accessibilityLabel={accessibilityLabel}
|
|
108
|
+
testID={showNotification ? undefined : testID}
|
|
113
109
|
{...props}
|
|
114
110
|
>
|
|
115
|
-
{showNotification && (
|
|
116
|
-
<View style={styles.notification} accessible={false} />
|
|
117
|
-
)}
|
|
118
111
|
{shouldFallback ? (
|
|
119
112
|
<User
|
|
120
113
|
size={fallbackSizes[size]}
|
|
@@ -132,4 +125,14 @@ export const Avatar = ({
|
|
|
132
125
|
)}
|
|
133
126
|
</Box>
|
|
134
127
|
);
|
|
128
|
+
|
|
129
|
+
if (showNotification) {
|
|
130
|
+
return (
|
|
131
|
+
<DotIndicator size={dotSizeMap[size]} appearance='red' testID={testID}>
|
|
132
|
+
{avatarContent}
|
|
133
|
+
</DotIndicator>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return avatarContent;
|
|
135
138
|
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Meta, Canvas, Controls } from '@storybook/addon-docs/blocks';
|
|
2
|
+
import * as DotCountStories from './DotCount.stories';
|
|
3
|
+
import { CustomTabs, Tab } from '../../../../.storybook/components';
|
|
4
|
+
|
|
5
|
+
<Meta title='Communication/DotCount' of={DotCountStories} />
|
|
6
|
+
|
|
7
|
+
# DotCount
|
|
8
|
+
|
|
9
|
+
<CustomTabs>
|
|
10
|
+
<Tab label="Overview">
|
|
11
|
+
|
|
12
|
+
## Introduction
|
|
13
|
+
|
|
14
|
+
DotCount displays a numeric count inside a colored pill. It supports two sizes (`lg` and `md`), two appearances (`base` and `red`), and can be pinned to the top-right of a child element.
|
|
15
|
+
|
|
16
|
+
> View in [Figma](https://www.figma.com/design/JxaLVMTWirCpU0rsbZ30k7/2.-Components-Library?node-id=38-998).
|
|
17
|
+
|
|
18
|
+
## Properties
|
|
19
|
+
|
|
20
|
+
<Canvas of={DotCountStories.Base} />
|
|
21
|
+
<Controls of={DotCountStories.Base} />
|
|
22
|
+
|
|
23
|
+
## Sizes
|
|
24
|
+
|
|
25
|
+
DotCount comes in two sizes:
|
|
26
|
+
|
|
27
|
+
- **lg** - large pill size for prominent counters.
|
|
28
|
+
- **md** (default) - standard pill size, suitable for most use cases.
|
|
29
|
+
|
|
30
|
+
<Canvas of={DotCountStories.SizeShowcase} />
|
|
31
|
+
|
|
32
|
+
## Appearances
|
|
33
|
+
|
|
34
|
+
Two color schemes are available:
|
|
35
|
+
|
|
36
|
+
- **base** (default) - neutral tone for general-purpose counters.
|
|
37
|
+
- **red** - attention-grabbing, typically used for unread counts or alerts.
|
|
38
|
+
|
|
39
|
+
<Canvas of={DotCountStories.AppearanceShowcase} />
|
|
40
|
+
|
|
41
|
+
## Overflow & Max
|
|
42
|
+
|
|
43
|
+
When `value` exceeds `max`, the display shows `[max]+`. Values of `0` or below hide the text. If you need a DotCount-like component but without the count, consider the DotIndicator instead.
|
|
44
|
+
|
|
45
|
+
<Canvas of={DotCountStories.OverflowShowcase} />
|
|
46
|
+
|
|
47
|
+
## With Children
|
|
48
|
+
|
|
49
|
+
When wrapping a child element, the count pill pins itself to the top-right corner.
|
|
50
|
+
|
|
51
|
+
<Canvas of={DotCountStories.WithChildren} />
|
|
52
|
+
|
|
53
|
+
</Tab>
|
|
54
|
+
<Tab label="Implementation">
|
|
55
|
+
|
|
56
|
+
## Setup
|
|
57
|
+
|
|
58
|
+
Install and set up the library with our [Setup Guide →](?path=/docs/getting-started-setup--docs).
|
|
59
|
+
|
|
60
|
+
## Basic Usage
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
import { DotCount } from '@ledgerhq/lumen-ui-rnative';
|
|
64
|
+
|
|
65
|
+
function MyComponent() {
|
|
66
|
+
return <DotCount value={5} size="lg" />;
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Pinned to a child
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
<DotCount value={3} size="md">
|
|
74
|
+
<Avatar src="..." size="md" />
|
|
75
|
+
</DotCount>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Custom max
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
<DotCount value={150} max={50} size="lg" />
|
|
82
|
+
{/* Renders "50+" */}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
</Tab>
|
|
86
|
+
</CustomTabs>
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-native-web-vite';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Avatar } from '../Avatar/Avatar';
|
|
4
|
+
import { MediaImage } from '../MediaImage/MediaImage';
|
|
5
|
+
import {
|
|
6
|
+
SegmentedControl,
|
|
7
|
+
SegmentedControlButton,
|
|
8
|
+
} from '../SegmentedControl/SegmentedControl';
|
|
9
|
+
import { Box } from '../Utility/Box';
|
|
10
|
+
import { DotCount } from './DotCount';
|
|
11
|
+
|
|
12
|
+
const meta = {
|
|
13
|
+
component: DotCount,
|
|
14
|
+
title: 'Communication/DotCount',
|
|
15
|
+
parameters: {
|
|
16
|
+
docs: {
|
|
17
|
+
source: {
|
|
18
|
+
language: 'tsx',
|
|
19
|
+
format: true,
|
|
20
|
+
type: 'code',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
argTypes: {
|
|
25
|
+
size: {
|
|
26
|
+
control: 'radio',
|
|
27
|
+
options: ['lg', 'md'],
|
|
28
|
+
},
|
|
29
|
+
appearance: {
|
|
30
|
+
control: 'radio',
|
|
31
|
+
options: ['base', 'red'],
|
|
32
|
+
},
|
|
33
|
+
value: {
|
|
34
|
+
control: 'number',
|
|
35
|
+
},
|
|
36
|
+
max: {
|
|
37
|
+
control: 'number',
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
} satisfies Meta<typeof DotCount>;
|
|
41
|
+
|
|
42
|
+
export default meta;
|
|
43
|
+
type Story = StoryObj<typeof meta>;
|
|
44
|
+
|
|
45
|
+
export const Base: Story = {
|
|
46
|
+
args: {
|
|
47
|
+
value: 3,
|
|
48
|
+
size: 'lg',
|
|
49
|
+
appearance: 'base',
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const SizeShowcase: Story = {
|
|
54
|
+
args: { value: 5 },
|
|
55
|
+
render: () => (
|
|
56
|
+
<Box lx={{ flexDirection: 'row', alignItems: 'center', gap: 's12' }}>
|
|
57
|
+
<DotCount value={5} size='lg' />
|
|
58
|
+
<DotCount value={5} size='md' />
|
|
59
|
+
</Box>
|
|
60
|
+
),
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const AppearanceShowcase: Story = {
|
|
64
|
+
args: { value: 3 },
|
|
65
|
+
render: () => (
|
|
66
|
+
<Box lx={{ flexDirection: 'row', alignItems: 'center', gap: 's12' }}>
|
|
67
|
+
<DotCount value={3} size='lg' appearance='base' />
|
|
68
|
+
<DotCount value={3} size='lg' appearance='red' />
|
|
69
|
+
<DotCount value={3} size='lg' disabled />
|
|
70
|
+
</Box>
|
|
71
|
+
),
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const OverflowShowcase: Story = {
|
|
75
|
+
args: { value: 100 },
|
|
76
|
+
render: () => (
|
|
77
|
+
<Box lx={{ flexDirection: 'row', alignItems: 'center', gap: 's12' }}>
|
|
78
|
+
<DotCount value={100} size='lg' />
|
|
79
|
+
<DotCount value={100} max={50} size='lg' />
|
|
80
|
+
<DotCount value={0} size='lg' />
|
|
81
|
+
</Box>
|
|
82
|
+
),
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export const WithChildren: Story = {
|
|
86
|
+
args: { value: 5 },
|
|
87
|
+
render: () => {
|
|
88
|
+
const [fitState, setFitState] = useState('preview');
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
<Box lx={{ gap: 's24' }}>
|
|
92
|
+
<Box lx={{ flexDirection: 'row', alignItems: 'center', gap: 's12' }}>
|
|
93
|
+
<DotCount value={5} size='md'>
|
|
94
|
+
<MediaImage
|
|
95
|
+
src='https://crypto-icons.ledger.com/BTC.png'
|
|
96
|
+
alt='Bitcoin'
|
|
97
|
+
size={40}
|
|
98
|
+
shape='circle'
|
|
99
|
+
/>
|
|
100
|
+
</DotCount>
|
|
101
|
+
<DotCount value={100} size='md'>
|
|
102
|
+
<Avatar
|
|
103
|
+
src='https://plus.unsplash.com/premium_photo-1689551670902-19b441a6afde?q=80&w=774&auto=format&fit=crop'
|
|
104
|
+
size='md'
|
|
105
|
+
/>
|
|
106
|
+
</DotCount>
|
|
107
|
+
</Box>
|
|
108
|
+
<SegmentedControl
|
|
109
|
+
selectedValue={fitState}
|
|
110
|
+
onSelectedChange={setFitState}
|
|
111
|
+
tabLayout='fit'
|
|
112
|
+
accessibilityLabel='Fit layout'
|
|
113
|
+
>
|
|
114
|
+
<SegmentedControlButton value='preview'>
|
|
115
|
+
Preview
|
|
116
|
+
<DotCount value={3} size='md' style={{ marginLeft: 6 }} />
|
|
117
|
+
</SegmentedControlButton>
|
|
118
|
+
<SegmentedControlButton value='raw'>Raw</SegmentedControlButton>
|
|
119
|
+
<SegmentedControlButton value='blame'>Blame</SegmentedControlButton>
|
|
120
|
+
</SegmentedControl>
|
|
121
|
+
</Box>
|
|
122
|
+
);
|
|
123
|
+
},
|
|
124
|
+
};
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { describe, it, expect } from '@jest/globals';
|
|
2
|
+
import { ledgerLiveThemes } from '@ledgerhq/lumen-design-core';
|
|
3
|
+
import { render } from '@testing-library/react-native';
|
|
4
|
+
import { createRef } from 'react';
|
|
5
|
+
import { Text, type View } from 'react-native';
|
|
6
|
+
import { ThemeProvider } from '../ThemeProvider/ThemeProvider';
|
|
7
|
+
import { DotCount } from './DotCount';
|
|
8
|
+
|
|
9
|
+
const TestWrapper = ({ children }: { children: React.ReactNode }) => (
|
|
10
|
+
<ThemeProvider themes={ledgerLiveThemes} colorScheme='dark' locale='en'>
|
|
11
|
+
{children}
|
|
12
|
+
</ThemeProvider>
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
describe('DotCount', () => {
|
|
16
|
+
it('should render the value', () => {
|
|
17
|
+
const { getByText } = render(
|
|
18
|
+
<TestWrapper>
|
|
19
|
+
<DotCount value={5} size='lg' />
|
|
20
|
+
</TestWrapper>,
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
expect(getByText('5')).toBeTruthy();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should hide text when value is 0', () => {
|
|
27
|
+
const { queryByText } = render(
|
|
28
|
+
<TestWrapper>
|
|
29
|
+
<DotCount value={0} size='lg' />
|
|
30
|
+
</TestWrapper>,
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
expect(queryByText('0')).toBeNull();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should cap value at max and show overflow indicator', () => {
|
|
37
|
+
const { getByText } = render(
|
|
38
|
+
<TestWrapper>
|
|
39
|
+
<DotCount value={100} max={50} size='lg' />
|
|
40
|
+
</TestWrapper>,
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
expect(getByText('50+')).toBeTruthy();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should default max to 99', () => {
|
|
47
|
+
const { getByText } = render(
|
|
48
|
+
<TestWrapper>
|
|
49
|
+
<DotCount value={150} size='lg' />
|
|
50
|
+
</TestWrapper>,
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
expect(getByText('99+')).toBeTruthy();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should clamp max to 1 when given zero or negative', () => {
|
|
57
|
+
const { getByText } = render(
|
|
58
|
+
<TestWrapper>
|
|
59
|
+
<DotCount value={5} max={0} size='lg' />
|
|
60
|
+
</TestWrapper>,
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
expect(getByText('1+')).toBeTruthy();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should render children alongside the count', () => {
|
|
67
|
+
const { getByText } = render(
|
|
68
|
+
<TestWrapper>
|
|
69
|
+
<DotCount value={3} size='md'>
|
|
70
|
+
<Text>Child</Text>
|
|
71
|
+
</DotCount>
|
|
72
|
+
</TestWrapper>,
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
expect(getByText('3')).toBeTruthy();
|
|
76
|
+
expect(getByText('Child')).toBeTruthy();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should forward testID to the outer wrapper', () => {
|
|
80
|
+
const { getByTestId } = render(
|
|
81
|
+
<TestWrapper>
|
|
82
|
+
<DotCount testID='dot-count' value={3} size='lg' />
|
|
83
|
+
</TestWrapper>,
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
expect(getByTestId('dot-count')).toBeTruthy();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should forward pointerEvents to the outer wrapper', () => {
|
|
90
|
+
const { getByTestId } = render(
|
|
91
|
+
<TestWrapper>
|
|
92
|
+
<DotCount testID='dot-count' value={3} size='lg' pointerEvents='none' />
|
|
93
|
+
</TestWrapper>,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
expect(getByTestId('dot-count').props.pointerEvents).toBe('none');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should forward ref to the outer wrapper', () => {
|
|
100
|
+
const ref = createRef<View>();
|
|
101
|
+
|
|
102
|
+
render(
|
|
103
|
+
<TestWrapper>
|
|
104
|
+
<DotCount ref={ref} value={3} size='lg' />
|
|
105
|
+
</TestWrapper>,
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
expect(ref.current).toBeTruthy();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should render with red appearance', () => {
|
|
112
|
+
const { getByText } = render(
|
|
113
|
+
<TestWrapper>
|
|
114
|
+
<DotCount value={5} size='lg' appearance='red' />
|
|
115
|
+
</TestWrapper>,
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
expect(getByText('5')).toBeTruthy();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should render with disabled state', () => {
|
|
122
|
+
const { getByText } = render(
|
|
123
|
+
<TestWrapper>
|
|
124
|
+
<DotCount value={5} size='lg' disabled />
|
|
125
|
+
</TestWrapper>,
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
expect(getByText('5')).toBeTruthy();
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should render in md size', () => {
|
|
132
|
+
const { getByText } = render(
|
|
133
|
+
<TestWrapper>
|
|
134
|
+
<DotCount value={5} size='md' />
|
|
135
|
+
</TestWrapper>,
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
expect(getByText('5')).toBeTruthy();
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('should default size to md when omitted', () => {
|
|
142
|
+
const { getByText } = render(
|
|
143
|
+
<TestWrapper>
|
|
144
|
+
<DotCount value={5} />
|
|
145
|
+
</TestWrapper>,
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
expect(getByText('5')).toBeTruthy();
|
|
149
|
+
});
|
|
150
|
+
});
|