@ledgerhq/lumen-ui-rnative 0.1.12 → 0.1.14
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/Components/MediaBanner/MediaBanner.js +158 -0
- package/dist/module/lib/Components/MediaBanner/MediaBanner.js.map +1 -0
- package/dist/module/lib/Components/MediaBanner/MediaBanner.mdx +150 -0
- package/dist/module/lib/Components/MediaBanner/MediaBanner.stories.js +135 -0
- package/dist/module/lib/Components/MediaBanner/MediaBanner.stories.js.map +1 -0
- package/dist/module/lib/Components/MediaBanner/MediaBanner.test.js +83 -0
- package/dist/module/lib/Components/MediaBanner/MediaBanner.test.js.map +1 -0
- package/dist/module/lib/Components/MediaBanner/index.js +5 -0
- package/dist/module/lib/Components/MediaBanner/index.js.map +1 -0
- package/dist/module/lib/Components/MediaBanner/types.js +4 -0
- package/dist/module/lib/Components/MediaBanner/types.js.map +1 -0
- package/dist/module/lib/Components/Tag/Tag.js +1 -0
- package/dist/module/lib/Components/Tag/Tag.js.map +1 -1
- package/dist/module/lib/Components/Tag/Tag.mdx +6 -0
- package/dist/module/lib/Components/Tag/Tag.stories.js +10 -0
- package/dist/module/lib/Components/Tag/Tag.stories.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/module/lib/Symbols/Icons/Csv.js +1 -1
- package/dist/module/lib/Symbols/Icons/Csv.js.map +1 -1
- package/dist/module/lib/Symbols/Icons/TriangleDown.js +47 -0
- package/dist/module/lib/Symbols/Icons/TriangleDown.js.map +1 -0
- package/dist/module/lib/Symbols/Icons/TriangleUp.js +47 -0
- package/dist/module/lib/Symbols/Icons/TriangleUp.js.map +1 -0
- package/dist/module/lib/Symbols/index.js +2 -0
- package/dist/module/lib/Symbols/index.js.map +1 -1
- package/dist/typescript/src/lib/Components/MediaBanner/MediaBanner.d.ts +16 -0
- package/dist/typescript/src/lib/Components/MediaBanner/MediaBanner.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/MediaBanner/index.d.ts +3 -0
- package/dist/typescript/src/lib/Components/MediaBanner/index.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/MediaBanner/types.d.ts +42 -0
- package/dist/typescript/src/lib/Components/MediaBanner/types.d.ts.map +1 -0
- package/dist/typescript/src/lib/Components/Tag/Tag.d.ts.map +1 -1
- package/dist/typescript/src/lib/Components/index.d.ts +1 -0
- package/dist/typescript/src/lib/Components/index.d.ts.map +1 -1
- package/dist/typescript/src/lib/Symbols/Icons/TriangleDown.d.ts +35 -0
- package/dist/typescript/src/lib/Symbols/Icons/TriangleDown.d.ts.map +1 -0
- package/dist/typescript/src/lib/Symbols/Icons/TriangleUp.d.ts +35 -0
- package/dist/typescript/src/lib/Symbols/Icons/TriangleUp.d.ts.map +1 -0
- package/dist/typescript/src/lib/Symbols/index.d.ts +2 -0
- package/dist/typescript/src/lib/Symbols/index.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/lib/Components/MediaBanner/MediaBanner.mdx +150 -0
- package/src/lib/Components/MediaBanner/MediaBanner.stories.tsx +143 -0
- package/src/lib/Components/MediaBanner/MediaBanner.test.tsx +77 -0
- package/src/lib/Components/MediaBanner/MediaBanner.tsx +172 -0
- package/src/lib/Components/MediaBanner/index.ts +2 -0
- package/src/lib/Components/MediaBanner/types.ts +44 -0
- package/src/lib/Components/Tag/Tag.mdx +6 -0
- package/src/lib/Components/Tag/Tag.stories.tsx +8 -0
- package/src/lib/Components/Tag/Tag.tsx +3 -1
- package/src/lib/Components/index.ts +1 -0
- package/src/lib/Symbols/Icons/Csv.tsx +1 -1
- package/src/lib/Symbols/Icons/TriangleDown.tsx +42 -0
- package/src/lib/Symbols/Icons/TriangleUp.tsx +42 -0
- package/src/lib/Symbols/index.ts +2 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-native-web-vite';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Button } from '../Button';
|
|
4
|
+
import { Box } from '../Utility';
|
|
5
|
+
import {
|
|
6
|
+
MediaBanner,
|
|
7
|
+
MediaBannerDescription,
|
|
8
|
+
MediaBannerTitle,
|
|
9
|
+
} from './MediaBanner';
|
|
10
|
+
|
|
11
|
+
const IMAGE_URL =
|
|
12
|
+
'https://images.unsplash.com/photo-1663741954108-d15d514529ef';
|
|
13
|
+
|
|
14
|
+
const meta: Meta<typeof MediaBanner> = {
|
|
15
|
+
component: MediaBanner,
|
|
16
|
+
title: 'Communication/MediaBanner',
|
|
17
|
+
subcomponents: {
|
|
18
|
+
MediaBannerTitle,
|
|
19
|
+
MediaBannerDescription,
|
|
20
|
+
},
|
|
21
|
+
parameters: {
|
|
22
|
+
docs: {
|
|
23
|
+
source: {
|
|
24
|
+
language: 'tsx',
|
|
25
|
+
format: true,
|
|
26
|
+
type: 'code',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
argTypes: {
|
|
31
|
+
imageUrl: {
|
|
32
|
+
control: 'text',
|
|
33
|
+
description: 'URL of the background image',
|
|
34
|
+
},
|
|
35
|
+
onClose: {
|
|
36
|
+
control: 'select',
|
|
37
|
+
description: 'Close action callback',
|
|
38
|
+
options: ['With Close', 'None'],
|
|
39
|
+
mapping: {
|
|
40
|
+
'With Close': () => {
|
|
41
|
+
console.log('Close clicked');
|
|
42
|
+
},
|
|
43
|
+
None: undefined,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export default meta;
|
|
50
|
+
type Story = StoryObj<typeof MediaBanner>;
|
|
51
|
+
|
|
52
|
+
export const Base: Story = {
|
|
53
|
+
args: {
|
|
54
|
+
imageUrl: IMAGE_URL,
|
|
55
|
+
},
|
|
56
|
+
render: (args) => (
|
|
57
|
+
<Box lx={{ width: 's400' }}>
|
|
58
|
+
<MediaBanner {...args}>
|
|
59
|
+
<MediaBannerTitle>Firmware Update</MediaBannerTitle>
|
|
60
|
+
<MediaBannerDescription>Keep your Nano updated!</MediaBannerDescription>
|
|
61
|
+
</MediaBanner>
|
|
62
|
+
</Box>
|
|
63
|
+
),
|
|
64
|
+
parameters: {
|
|
65
|
+
docs: {
|
|
66
|
+
source: {
|
|
67
|
+
code: `
|
|
68
|
+
<MediaBanner imageUrl="https://images.unsplash.com/photo-1663741954108-d15d514529ef">
|
|
69
|
+
<MediaBannerTitle>Firmware Update</MediaBannerTitle>
|
|
70
|
+
<MediaBannerDescription>
|
|
71
|
+
Keep your Nano updated!
|
|
72
|
+
</MediaBannerDescription>
|
|
73
|
+
</MediaBanner>
|
|
74
|
+
`,
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const Truncation: Story = {
|
|
81
|
+
render: () => (
|
|
82
|
+
<Box lx={{ width: 's400' }}>
|
|
83
|
+
<MediaBanner imageUrl={IMAGE_URL} onClose={() => console.log('close')}>
|
|
84
|
+
<MediaBannerTitle>
|
|
85
|
+
Earn Up to 12% APY With Staking Now And Much More Rewards Awaiting You
|
|
86
|
+
</MediaBannerTitle>
|
|
87
|
+
<MediaBannerDescription>
|
|
88
|
+
Put your idle crypto to work. Start staking SOL, ETH, ATOM and more
|
|
89
|
+
directly from Ledger Live. Maximize your returns with our secure
|
|
90
|
+
staking solutions.
|
|
91
|
+
</MediaBannerDescription>
|
|
92
|
+
</MediaBanner>
|
|
93
|
+
</Box>
|
|
94
|
+
),
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export const WithBrokenImage: Story = {
|
|
98
|
+
render: () => (
|
|
99
|
+
<Box lx={{ width: 's400' }}>
|
|
100
|
+
<MediaBanner
|
|
101
|
+
imageUrl='https://broken-url.invalid/image.jpg'
|
|
102
|
+
onClose={() => console.log('close')}
|
|
103
|
+
>
|
|
104
|
+
<MediaBannerTitle>Sorry!</MediaBannerTitle>
|
|
105
|
+
<MediaBannerDescription>
|
|
106
|
+
The image failed to load so the banner decided to gracefully hide it.
|
|
107
|
+
</MediaBannerDescription>
|
|
108
|
+
</MediaBanner>
|
|
109
|
+
</Box>
|
|
110
|
+
),
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export const WithClose: Story = {
|
|
114
|
+
render: () => {
|
|
115
|
+
const [visible, setVisible] = useState(true);
|
|
116
|
+
|
|
117
|
+
if (!visible) {
|
|
118
|
+
return (
|
|
119
|
+
<Button
|
|
120
|
+
appearance='transparent'
|
|
121
|
+
size='sm'
|
|
122
|
+
onPress={() => setVisible(true)}
|
|
123
|
+
>
|
|
124
|
+
Show banner
|
|
125
|
+
</Button>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<Box lx={{ width: 's400' }}>
|
|
131
|
+
<MediaBanner imageUrl={IMAGE_URL} onClose={() => setVisible(false)}>
|
|
132
|
+
<MediaBannerTitle>
|
|
133
|
+
Earn Up to 12% APY With Staking Now!
|
|
134
|
+
</MediaBannerTitle>
|
|
135
|
+
<MediaBannerDescription>
|
|
136
|
+
Put your idle crypto to work. Start staking SOL, ETH, ATOM and more
|
|
137
|
+
directly from Ledger Live
|
|
138
|
+
</MediaBannerDescription>
|
|
139
|
+
</MediaBanner>
|
|
140
|
+
</Box>
|
|
141
|
+
);
|
|
142
|
+
},
|
|
143
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { describe, it, expect, jest } from '@jest/globals';
|
|
2
|
+
import { ledgerLiveThemes } from '@ledgerhq/lumen-design-core';
|
|
3
|
+
import { fireEvent, render } from '@testing-library/react-native';
|
|
4
|
+
import { type ReactNode } from 'react';
|
|
5
|
+
import { ThemeProvider } from '../ThemeProvider/ThemeProvider';
|
|
6
|
+
import {
|
|
7
|
+
MediaBanner,
|
|
8
|
+
MediaBannerTitle,
|
|
9
|
+
MediaBannerDescription,
|
|
10
|
+
} from './MediaBanner';
|
|
11
|
+
|
|
12
|
+
const TestWrapper = ({ children }: { children: ReactNode }) => (
|
|
13
|
+
<ThemeProvider themes={ledgerLiveThemes} colorScheme='dark' locale='en'>
|
|
14
|
+
{children}
|
|
15
|
+
</ThemeProvider>
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
const IMAGE_URL = 'https://example.com/image.jpg';
|
|
19
|
+
|
|
20
|
+
describe('MediaBanner', () => {
|
|
21
|
+
it('should render title and description', () => {
|
|
22
|
+
const { getByText } = render(
|
|
23
|
+
<TestWrapper>
|
|
24
|
+
<MediaBanner imageUrl={IMAGE_URL}>
|
|
25
|
+
<MediaBannerTitle>Banner Title</MediaBannerTitle>
|
|
26
|
+
<MediaBannerDescription>Banner description</MediaBannerDescription>
|
|
27
|
+
</MediaBanner>
|
|
28
|
+
</TestWrapper>,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
getByText('Banner Title');
|
|
32
|
+
getByText('Banner description');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should call onClose when close button is pressed', () => {
|
|
36
|
+
const handleClose = jest.fn();
|
|
37
|
+
const { getByTestId } = render(
|
|
38
|
+
<TestWrapper>
|
|
39
|
+
<MediaBanner imageUrl={IMAGE_URL} onClose={handleClose}>
|
|
40
|
+
<MediaBannerTitle>Title</MediaBannerTitle>
|
|
41
|
+
</MediaBanner>
|
|
42
|
+
</TestWrapper>,
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const closeButton = getByTestId('media-banner-close-button');
|
|
46
|
+
expect(closeButton).toBeTruthy();
|
|
47
|
+
fireEvent.press(closeButton);
|
|
48
|
+
expect(handleClose).toHaveBeenCalledTimes(1);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should apply surface background color', () => {
|
|
52
|
+
const { getByTestId } = render(
|
|
53
|
+
<TestWrapper>
|
|
54
|
+
<MediaBanner testID='media-banner' imageUrl={IMAGE_URL}>
|
|
55
|
+
<MediaBannerTitle>Title</MediaBannerTitle>
|
|
56
|
+
</MediaBanner>
|
|
57
|
+
</TestWrapper>,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const banner = getByTestId('media-banner');
|
|
61
|
+
expect(banner.props.style.backgroundColor).toBe(
|
|
62
|
+
ledgerLiveThemes.dark.colors.bg.surface,
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should render with imageUrl prop', () => {
|
|
67
|
+
const { getByTestId } = render(
|
|
68
|
+
<TestWrapper>
|
|
69
|
+
<MediaBanner testID='media-banner' imageUrl={IMAGE_URL}>
|
|
70
|
+
<MediaBannerTitle>Title</MediaBannerTitle>
|
|
71
|
+
</MediaBanner>
|
|
72
|
+
</TestWrapper>,
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
expect(getByTestId('media-banner')).toBeTruthy();
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { Image, StyleSheet } from 'react-native';
|
|
3
|
+
import { useCommonTranslation } from '../../../i18n';
|
|
4
|
+
import { useStyleSheet, useTheme } from '../../../styles';
|
|
5
|
+
import { Close } from '../../Symbols';
|
|
6
|
+
import { InteractiveIcon } from '../InteractiveIcon';
|
|
7
|
+
import { Box, LinearGradient, Pressable, Text } from '../Utility';
|
|
8
|
+
import {
|
|
9
|
+
MediaBannerDescriptionProps,
|
|
10
|
+
MediaBannerProps,
|
|
11
|
+
MediaBannerTitleProps,
|
|
12
|
+
} from './types';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A promotional banner with a background image, title, description, and an optional close button.
|
|
16
|
+
*
|
|
17
|
+
* @see {@link https://ldls.vercel.app/?path=/docs/communication-mediabanner--docs Storybook}
|
|
18
|
+
*/
|
|
19
|
+
export function MediaBanner({
|
|
20
|
+
lx,
|
|
21
|
+
style,
|
|
22
|
+
imageUrl,
|
|
23
|
+
onClose,
|
|
24
|
+
closeAccessibilityLabel,
|
|
25
|
+
children,
|
|
26
|
+
...props
|
|
27
|
+
}: MediaBannerProps) {
|
|
28
|
+
const { t: translate } = useCommonTranslation();
|
|
29
|
+
const { theme: t } = useTheme();
|
|
30
|
+
const [imageLoadError, setImageLoadError] = useState(false);
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
setImageLoadError(false);
|
|
34
|
+
}, [imageUrl]);
|
|
35
|
+
|
|
36
|
+
const showImage = imageUrl && !imageLoadError;
|
|
37
|
+
|
|
38
|
+
const styles = useStyleSheet(
|
|
39
|
+
(t) => ({
|
|
40
|
+
container: {
|
|
41
|
+
backgroundColor: t.colors.bg.surface,
|
|
42
|
+
borderRadius: t.borderRadius.md,
|
|
43
|
+
overflow: 'hidden',
|
|
44
|
+
flexDirection: 'row',
|
|
45
|
+
height: t.sizes.s72,
|
|
46
|
+
},
|
|
47
|
+
contentWrapper: {
|
|
48
|
+
flex: 1,
|
|
49
|
+
overflow: 'hidden',
|
|
50
|
+
justifyContent: 'center',
|
|
51
|
+
paddingHorizontal: t.spacings.s12,
|
|
52
|
+
paddingVertical: t.spacings.s2,
|
|
53
|
+
},
|
|
54
|
+
contentContainer: {
|
|
55
|
+
paddingVertical: t.spacings.s12,
|
|
56
|
+
gap: 4,
|
|
57
|
+
},
|
|
58
|
+
closeButton: {
|
|
59
|
+
position: 'absolute',
|
|
60
|
+
top: 8.5,
|
|
61
|
+
right: 8.5,
|
|
62
|
+
},
|
|
63
|
+
}),
|
|
64
|
+
[],
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<Pressable lx={lx} style={[styles.container, style]} {...props}>
|
|
69
|
+
<Box style={styles.contentWrapper}>
|
|
70
|
+
<Box style={styles.contentContainer}>{children}</Box>
|
|
71
|
+
</Box>
|
|
72
|
+
<Box style={{ width: 120 }}>
|
|
73
|
+
{showImage && (
|
|
74
|
+
<Image
|
|
75
|
+
source={{ uri: imageUrl }}
|
|
76
|
+
style={StyleSheet.absoluteFill}
|
|
77
|
+
resizeMode='cover'
|
|
78
|
+
onError={() => setImageLoadError(true)}
|
|
79
|
+
accessible={false}
|
|
80
|
+
/>
|
|
81
|
+
)}
|
|
82
|
+
<LinearGradient
|
|
83
|
+
direction='to-topright'
|
|
84
|
+
stops={[
|
|
85
|
+
{ color: t.colors.bg.black, opacity: 0, offset: 0.67 },
|
|
86
|
+
{ color: t.colors.bg.black, opacity: 0.8 },
|
|
87
|
+
]}
|
|
88
|
+
style={StyleSheet.absoluteFill}
|
|
89
|
+
accessible={false}
|
|
90
|
+
pointerEvents='none'
|
|
91
|
+
/>
|
|
92
|
+
</Box>
|
|
93
|
+
{onClose && (
|
|
94
|
+
<Box style={styles.closeButton}>
|
|
95
|
+
<InteractiveIcon
|
|
96
|
+
testID='media-banner-close-button'
|
|
97
|
+
iconType='stroked'
|
|
98
|
+
appearance='white'
|
|
99
|
+
onPress={onClose}
|
|
100
|
+
accessibilityLabel={
|
|
101
|
+
closeAccessibilityLabel ||
|
|
102
|
+
translate('components.banner.closeAriaLabel')
|
|
103
|
+
}
|
|
104
|
+
>
|
|
105
|
+
<Close size={16} />
|
|
106
|
+
</InteractiveIcon>
|
|
107
|
+
</Box>
|
|
108
|
+
)}
|
|
109
|
+
</Pressable>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* The title of the MediaBanner. Clamps at 1 line.
|
|
115
|
+
*/
|
|
116
|
+
export function MediaBannerTitle({
|
|
117
|
+
lx,
|
|
118
|
+
style,
|
|
119
|
+
children,
|
|
120
|
+
...props
|
|
121
|
+
}: MediaBannerTitleProps) {
|
|
122
|
+
const styles = useStyleSheet(
|
|
123
|
+
(t) => ({
|
|
124
|
+
title: StyleSheet.flatten([
|
|
125
|
+
t.typographies.body2SemiBold,
|
|
126
|
+
{
|
|
127
|
+
color: t.colors.text.base,
|
|
128
|
+
},
|
|
129
|
+
]),
|
|
130
|
+
}),
|
|
131
|
+
[],
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
return (
|
|
135
|
+
<Text lx={lx} style={[styles.title, style]} numberOfLines={1} {...props}>
|
|
136
|
+
{children}
|
|
137
|
+
</Text>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* The description of the MediaBanner. Clamps at 2 lines.
|
|
143
|
+
*/
|
|
144
|
+
export function MediaBannerDescription({
|
|
145
|
+
lx,
|
|
146
|
+
style,
|
|
147
|
+
children,
|
|
148
|
+
...props
|
|
149
|
+
}: MediaBannerDescriptionProps) {
|
|
150
|
+
const styles = useStyleSheet(
|
|
151
|
+
(t) => ({
|
|
152
|
+
description: StyleSheet.flatten([
|
|
153
|
+
t.typographies.body3,
|
|
154
|
+
{
|
|
155
|
+
color: t.colors.text.muted,
|
|
156
|
+
},
|
|
157
|
+
]),
|
|
158
|
+
}),
|
|
159
|
+
[],
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
return (
|
|
163
|
+
<Text
|
|
164
|
+
lx={lx}
|
|
165
|
+
style={[styles.description, style]}
|
|
166
|
+
numberOfLines={2}
|
|
167
|
+
{...props}
|
|
168
|
+
>
|
|
169
|
+
{children}
|
|
170
|
+
</Text>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { StyledPressableProps, StyledTextProps } from '../../../styles';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Props for the MediaBanner root component.
|
|
6
|
+
*/
|
|
7
|
+
export type MediaBannerProps = {
|
|
8
|
+
/**
|
|
9
|
+
* URL of the background image displayed on the right side.
|
|
10
|
+
*/
|
|
11
|
+
imageUrl: string;
|
|
12
|
+
/**
|
|
13
|
+
* Optional close action callback.
|
|
14
|
+
*/
|
|
15
|
+
onClose?: () => void;
|
|
16
|
+
/**
|
|
17
|
+
* Optional accessibility label for the close button.
|
|
18
|
+
*/
|
|
19
|
+
closeAccessibilityLabel?: string;
|
|
20
|
+
/**
|
|
21
|
+
* The banner content (MediaBannerTitle, MediaBannerDescription).
|
|
22
|
+
*/
|
|
23
|
+
children: ReactNode;
|
|
24
|
+
} & Omit<StyledPressableProps, 'children'>;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Props for the MediaBannerTitle component.
|
|
28
|
+
*/
|
|
29
|
+
export type MediaBannerTitleProps = {
|
|
30
|
+
/**
|
|
31
|
+
* The title text content.
|
|
32
|
+
*/
|
|
33
|
+
children: ReactNode;
|
|
34
|
+
} & Omit<StyledTextProps, 'children'>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Props for the MediaBannerDescription component.
|
|
38
|
+
*/
|
|
39
|
+
export type MediaBannerDescriptionProps = {
|
|
40
|
+
/**
|
|
41
|
+
* The description text content.
|
|
42
|
+
*/
|
|
43
|
+
children: ReactNode;
|
|
44
|
+
} & Omit<StyledTextProps, 'children'>;
|
|
@@ -47,6 +47,12 @@ Tags can be displayed with or without an icon.
|
|
|
47
47
|
|
|
48
48
|
<Canvas of={TagStories.ContentTypeShowcase} />
|
|
49
49
|
|
|
50
|
+
### Truncation
|
|
51
|
+
|
|
52
|
+
When a tag's label exceeds the available space, the text is automatically truncated with an ellipsis.
|
|
53
|
+
|
|
54
|
+
<Canvas of={TagStories.TruncateShowcase} />
|
|
55
|
+
|
|
50
56
|
### Accessibility
|
|
51
57
|
|
|
52
58
|
To be implemented:
|
|
@@ -155,7 +155,9 @@ export const Tag = ({
|
|
|
155
155
|
{...props}
|
|
156
156
|
>
|
|
157
157
|
{IconComponent && <IconComponent size={iconSize} style={styles.icon} />}
|
|
158
|
-
<Text style={styles.text}
|
|
158
|
+
<Text style={styles.text} numberOfLines={1}>
|
|
159
|
+
{label}
|
|
160
|
+
</Text>
|
|
159
161
|
</Box>
|
|
160
162
|
);
|
|
161
163
|
};
|
|
@@ -43,7 +43,7 @@ export const Csv = createIcon(
|
|
|
43
43
|
/>
|
|
44
44
|
<Path
|
|
45
45
|
fill='currentColor'
|
|
46
|
-
d='
|
|
46
|
+
d='M4.483 13.656a.467.467 0 0 1 .641.156q.022.034.043.044.015.01.04.01h.426a.08.08 0 0 0 .079-.078.08.08 0 0 0-.062-.078l-.728-.183a1.013 1.013 0 0 1 .247-1.994h.426c.39 0 .704.217.878.502a.467.467 0 0 1-.797.486.13.13 0 0 0-.042-.044.1.1 0 0 0-.039-.01H5.17a.079.079 0 0 0-.02.155l.73.183a1.012 1.012 0 0 1-.246 1.995h-.427c-.39 0-.705-.217-.878-.503a.467.467 0 0 1 .155-.64m4.727-2.105c.248.07.392.327.323.575l-.656 2.334a.47.47 0 0 1-.45.34H7.99a.47.47 0 0 1-.45-.34l-.656-2.334a.467.467 0 0 1 .899-.252l.425 1.514.426-1.514a.467.467 0 0 1 .576-.323M1.538 12.667v1c0 .626.508 1.133 1.134 1.133h.666a.467.467 0 0 0 0-.934h-.666a.2.2 0 0 1-.2-.2v-1c0-.11.09-.2.2-.2h.666a.467.467 0 0 0 0-.933h-.666c-.626 0-1.134.508-1.134 1.134'
|
|
47
47
|
/>
|
|
48
48
|
</Svg>,
|
|
49
49
|
);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import Svg, { Path } from 'react-native-svg';
|
|
2
|
+
import createIcon from '../../Components/Icon/createIcon';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* TriangleDown icon component for React Native.
|
|
6
|
+
*
|
|
7
|
+
* This icon component is automatically generated from SVG files and uses the createIcon utility
|
|
8
|
+
* to create a consistent icon interface. It supports all standard SVG props (from react-native-svg)
|
|
9
|
+
* and additional size variants defined in the Icon component.
|
|
10
|
+
*
|
|
11
|
+
* @component
|
|
12
|
+
* @param {16 | 20 | 24 | 40 | 48 | 56} [size=24] - The size of the icon in pixels.
|
|
13
|
+
* @param {string} [color] - The color of the icon.
|
|
14
|
+
* @param {SVGProps} [...props] - All standard SVG element props (from react-native-svg).
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* // Basic usage with default size (24px)
|
|
18
|
+
* import { TriangleDown } from '@ledgerhq/lumen-ui-rnative/symbols';
|
|
19
|
+
*
|
|
20
|
+
* <TriangleDown />
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // With custom size and style
|
|
24
|
+
* <TriangleDown size={40} color="warning" lx={{ marginTop: 's4' }} />
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* // Used within a Button component
|
|
28
|
+
* import { Button } from '@ledgerhq/lumen-ui-rnative';
|
|
29
|
+
*
|
|
30
|
+
* <Button icon={TriangleDown} size="md">
|
|
31
|
+
* Click me
|
|
32
|
+
* </Button>
|
|
33
|
+
*/
|
|
34
|
+
export const TriangleDown = createIcon(
|
|
35
|
+
'TriangleDown',
|
|
36
|
+
<Svg width={24} height={24} fill='currentColor' viewBox='0 0 16 16'>
|
|
37
|
+
<Path
|
|
38
|
+
fill='currentColor'
|
|
39
|
+
d='M13.038 5.347 8.82 12.06a1 1 0 0 1-1.696-.004L2.95 5.343a1 1 0 0 1 .85-1.528h8.39a1 1 0 0 1 .848 1.532'
|
|
40
|
+
/>
|
|
41
|
+
</Svg>,
|
|
42
|
+
);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import Svg, { Path } from 'react-native-svg';
|
|
2
|
+
import createIcon from '../../Components/Icon/createIcon';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* TriangleUp icon component for React Native.
|
|
6
|
+
*
|
|
7
|
+
* This icon component is automatically generated from SVG files and uses the createIcon utility
|
|
8
|
+
* to create a consistent icon interface. It supports all standard SVG props (from react-native-svg)
|
|
9
|
+
* and additional size variants defined in the Icon component.
|
|
10
|
+
*
|
|
11
|
+
* @component
|
|
12
|
+
* @param {16 | 20 | 24 | 40 | 48 | 56} [size=24] - The size of the icon in pixels.
|
|
13
|
+
* @param {string} [color] - The color of the icon.
|
|
14
|
+
* @param {SVGProps} [...props] - All standard SVG element props (from react-native-svg).
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* // Basic usage with default size (24px)
|
|
18
|
+
* import { TriangleUp } from '@ledgerhq/lumen-ui-rnative/symbols';
|
|
19
|
+
*
|
|
20
|
+
* <TriangleUp />
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // With custom size and style
|
|
24
|
+
* <TriangleUp size={40} color="warning" lx={{ marginTop: 's4' }} />
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* // Used within a Button component
|
|
28
|
+
* import { Button } from '@ledgerhq/lumen-ui-rnative';
|
|
29
|
+
*
|
|
30
|
+
* <Button icon={TriangleUp} size="md">
|
|
31
|
+
* Click me
|
|
32
|
+
* </Button>
|
|
33
|
+
*/
|
|
34
|
+
export const TriangleUp = createIcon(
|
|
35
|
+
'TriangleUp',
|
|
36
|
+
<Svg width={24} height={24} fill='currentColor' viewBox='0 0 16 16'>
|
|
37
|
+
<Path
|
|
38
|
+
fill='currentColor'
|
|
39
|
+
d='M13.038 11.512 8.82 4.798a1 1 0 0 0-1.696.004L2.95 11.516a1 1 0 0 0 .85 1.528h8.39a1 1 0 0 0 .848-1.532'
|
|
40
|
+
/>
|
|
41
|
+
</Svg>,
|
|
42
|
+
);
|
package/src/lib/Symbols/index.ts
CHANGED
|
@@ -238,6 +238,8 @@ export { Tools } from './Icons/Tools';
|
|
|
238
238
|
export { TransferHorizontal } from './Icons/TransferHorizontal';
|
|
239
239
|
export { TransferVertical } from './Icons/TransferVertical';
|
|
240
240
|
export { Trash } from './Icons/Trash';
|
|
241
|
+
export { TriangleDown } from './Icons/TriangleDown';
|
|
242
|
+
export { TriangleUp } from './Icons/TriangleUp';
|
|
241
243
|
export { Truck } from './Icons/Truck';
|
|
242
244
|
export { Twitter } from './Icons/Twitter';
|
|
243
245
|
export { Unlink } from './Icons/Unlink';
|