@ledgerhq/lumen-ui-rnative 0.1.11 → 0.1.13

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 (140) hide show
  1. package/dist/module/i18n/locales/de.json +3 -0
  2. package/dist/module/i18n/locales/en.json +3 -0
  3. package/dist/module/i18n/locales/es.json +3 -0
  4. package/dist/module/i18n/locales/fr.json +3 -0
  5. package/dist/module/i18n/locales/ja.json +3 -0
  6. package/dist/module/i18n/locales/ko.json +3 -0
  7. package/dist/module/i18n/locales/pt.json +3 -0
  8. package/dist/module/i18n/locales/ru.json +3 -0
  9. package/dist/module/i18n/locales/th.json +3 -0
  10. package/dist/module/i18n/locales/tr.json +3 -0
  11. package/dist/module/i18n/locales/zh.json +3 -0
  12. package/dist/module/lib/Animations/Pulse/Pulse.js +1 -1
  13. package/dist/module/lib/Animations/Spin/Spin.js +1 -1
  14. package/dist/module/lib/Components/AmountDisplay/AmountDisplay.js +21 -21
  15. package/dist/module/lib/Components/AmountDisplay/AmountDisplay.js.map +1 -1
  16. package/dist/module/lib/Components/AmountInput/AmountInput.js +3 -3
  17. package/dist/module/lib/Components/BaseInput/BaseInput.js +1 -1
  18. package/dist/module/lib/Components/BottomSheet/BottomSheet.stories.js.map +1 -1
  19. package/dist/module/lib/Components/Card/Card.js +39 -29
  20. package/dist/module/lib/Components/Card/Card.js.map +1 -1
  21. package/dist/module/lib/Components/InteractiveIcon/InteractiveIcon.js +22 -2
  22. package/dist/module/lib/Components/InteractiveIcon/InteractiveIcon.js.map +1 -1
  23. package/dist/module/lib/Components/Link/Link.mdx +1 -0
  24. package/dist/module/lib/Components/MediaBanner/MediaBanner.js +158 -0
  25. package/dist/module/lib/Components/MediaBanner/MediaBanner.js.map +1 -0
  26. package/dist/module/lib/Components/MediaBanner/MediaBanner.mdx +150 -0
  27. package/dist/module/lib/Components/MediaBanner/MediaBanner.stories.js +135 -0
  28. package/dist/module/lib/Components/MediaBanner/MediaBanner.stories.js.map +1 -0
  29. package/dist/module/lib/Components/MediaBanner/MediaBanner.test.js +83 -0
  30. package/dist/module/lib/Components/MediaBanner/MediaBanner.test.js.map +1 -0
  31. package/dist/module/lib/Components/MediaBanner/index.js +5 -0
  32. package/dist/module/lib/Components/MediaBanner/index.js.map +1 -0
  33. package/dist/module/lib/Components/MediaBanner/types.js +4 -0
  34. package/dist/module/lib/Components/MediaBanner/types.js.map +1 -0
  35. package/dist/module/lib/Components/MediaCard/MediaCard.js +183 -0
  36. package/dist/module/lib/Components/MediaCard/MediaCard.js.map +1 -0
  37. package/dist/module/lib/Components/MediaCard/MediaCard.mdx +111 -0
  38. package/dist/module/lib/Components/MediaCard/MediaCard.stories.js +199 -0
  39. package/dist/module/lib/Components/MediaCard/MediaCard.stories.js.map +1 -0
  40. package/dist/module/lib/Components/MediaCard/MediaCard.test.js +140 -0
  41. package/dist/module/lib/Components/MediaCard/MediaCard.test.js.map +1 -0
  42. package/dist/module/lib/Components/MediaCard/index.js +5 -0
  43. package/dist/module/lib/Components/MediaCard/index.js.map +1 -0
  44. package/dist/module/lib/Components/MediaCard/types.js +4 -0
  45. package/dist/module/lib/Components/MediaCard/types.js.map +1 -0
  46. package/dist/module/lib/Components/PageIndicator/PageIndicator.js +2 -2
  47. package/dist/module/lib/Components/SegmentedControl/usePillLayout.js +1 -1
  48. package/dist/module/lib/Components/Stepper/Stepper.js +1 -1
  49. package/dist/module/lib/Components/Switch/BaseSwitch.js +1 -1
  50. package/dist/module/lib/Components/TabBar/TabBar.js +4 -4
  51. package/dist/module/lib/Components/ThemeProvider/ThemeProvider.test.js +22 -20
  52. package/dist/module/lib/Components/ThemeProvider/ThemeProvider.test.js.map +1 -1
  53. package/dist/module/lib/Components/TriggerButton/TriggerButton.js +197 -0
  54. package/dist/module/lib/Components/TriggerButton/TriggerButton.js.map +1 -0
  55. package/dist/module/lib/Components/TriggerButton/TriggerButton.mdx +44 -0
  56. package/dist/module/lib/Components/TriggerButton/TriggerButton.stories.js +170 -0
  57. package/dist/module/lib/Components/TriggerButton/TriggerButton.stories.js.map +1 -0
  58. package/dist/module/lib/Components/TriggerButton/TriggerButton.test.js +146 -0
  59. package/dist/module/lib/Components/TriggerButton/TriggerButton.test.js.map +1 -0
  60. package/dist/module/lib/Components/TriggerButton/index.js +5 -0
  61. package/dist/module/lib/Components/TriggerButton/index.js.map +1 -0
  62. package/dist/module/lib/Components/TriggerButton/types.js +4 -0
  63. package/dist/module/lib/Components/TriggerButton/types.js.map +1 -0
  64. package/dist/module/lib/Components/Utility/Gradient/RadialGradient/RadialGradient.stories.js.map +1 -1
  65. package/dist/module/lib/Components/index.js +3 -0
  66. package/dist/module/lib/Components/index.js.map +1 -1
  67. package/dist/module/lib/Symbols/Icons/NanoGen5.js +49 -0
  68. package/dist/module/lib/Symbols/Icons/NanoGen5.js.map +1 -0
  69. package/dist/module/lib/Symbols/index.js +1 -0
  70. package/dist/module/lib/Symbols/index.js.map +1 -1
  71. package/dist/typescript/src/lib/Components/Card/Card.d.ts.map +1 -1
  72. package/dist/typescript/src/lib/Components/InteractiveIcon/InteractiveIcon.d.ts +1 -1
  73. package/dist/typescript/src/lib/Components/InteractiveIcon/InteractiveIcon.d.ts.map +1 -1
  74. package/dist/typescript/src/lib/Components/InteractiveIcon/types.d.ts +8 -0
  75. package/dist/typescript/src/lib/Components/InteractiveIcon/types.d.ts.map +1 -1
  76. package/dist/typescript/src/lib/Components/MediaBanner/MediaBanner.d.ts +16 -0
  77. package/dist/typescript/src/lib/Components/MediaBanner/MediaBanner.d.ts.map +1 -0
  78. package/dist/typescript/src/lib/Components/MediaBanner/index.d.ts +3 -0
  79. package/dist/typescript/src/lib/Components/MediaBanner/index.d.ts.map +1 -0
  80. package/dist/typescript/src/lib/Components/MediaBanner/types.d.ts +42 -0
  81. package/dist/typescript/src/lib/Components/MediaBanner/types.d.ts.map +1 -0
  82. package/dist/typescript/src/lib/Components/MediaCard/MediaCard.d.ts +32 -0
  83. package/dist/typescript/src/lib/Components/MediaCard/MediaCard.d.ts.map +1 -0
  84. package/dist/typescript/src/lib/Components/MediaCard/index.d.ts +3 -0
  85. package/dist/typescript/src/lib/Components/MediaCard/index.d.ts.map +1 -0
  86. package/dist/typescript/src/lib/Components/MediaCard/types.d.ts +38 -0
  87. package/dist/typescript/src/lib/Components/MediaCard/types.d.ts.map +1 -0
  88. package/dist/typescript/src/lib/Components/TriggerButton/TriggerButton.d.ts +26 -0
  89. package/dist/typescript/src/lib/Components/TriggerButton/TriggerButton.d.ts.map +1 -0
  90. package/dist/typescript/src/lib/Components/TriggerButton/index.d.ts +3 -0
  91. package/dist/typescript/src/lib/Components/TriggerButton/index.d.ts.map +1 -0
  92. package/dist/typescript/src/lib/Components/TriggerButton/types.d.ts +38 -0
  93. package/dist/typescript/src/lib/Components/TriggerButton/types.d.ts.map +1 -0
  94. package/dist/typescript/src/lib/Components/index.d.ts +3 -0
  95. package/dist/typescript/src/lib/Components/index.d.ts.map +1 -1
  96. package/dist/typescript/src/lib/Symbols/Icons/NanoGen5.d.ts +35 -0
  97. package/dist/typescript/src/lib/Symbols/Icons/NanoGen5.d.ts.map +1 -0
  98. package/dist/typescript/src/lib/Symbols/index.d.ts +1 -0
  99. package/dist/typescript/src/lib/Symbols/index.d.ts.map +1 -1
  100. package/package.json +3 -3
  101. package/src/i18n/locales/de.json +3 -0
  102. package/src/i18n/locales/en.json +3 -0
  103. package/src/i18n/locales/es.json +3 -0
  104. package/src/i18n/locales/fr.json +3 -0
  105. package/src/i18n/locales/ja.json +3 -0
  106. package/src/i18n/locales/ko.json +3 -0
  107. package/src/i18n/locales/pt.json +3 -0
  108. package/src/i18n/locales/ru.json +3 -0
  109. package/src/i18n/locales/th.json +3 -0
  110. package/src/i18n/locales/tr.json +3 -0
  111. package/src/i18n/locales/zh.json +3 -0
  112. package/src/lib/Components/AmountDisplay/AmountDisplay.tsx +20 -20
  113. package/src/lib/Components/BottomSheet/BottomSheet.stories.tsx +9 -9
  114. package/src/lib/Components/Card/Card.tsx +38 -33
  115. package/src/lib/Components/InteractiveIcon/InteractiveIcon.tsx +26 -4
  116. package/src/lib/Components/InteractiveIcon/types.ts +8 -0
  117. package/src/lib/Components/Link/Link.mdx +1 -0
  118. package/src/lib/Components/MediaBanner/MediaBanner.mdx +150 -0
  119. package/src/lib/Components/MediaBanner/MediaBanner.stories.tsx +143 -0
  120. package/src/lib/Components/MediaBanner/MediaBanner.test.tsx +77 -0
  121. package/src/lib/Components/MediaBanner/MediaBanner.tsx +172 -0
  122. package/src/lib/Components/MediaBanner/index.ts +2 -0
  123. package/src/lib/Components/MediaBanner/types.ts +44 -0
  124. package/src/lib/Components/MediaCard/MediaCard.mdx +111 -0
  125. package/src/lib/Components/MediaCard/MediaCard.stories.tsx +190 -0
  126. package/src/lib/Components/MediaCard/MediaCard.test.tsx +125 -0
  127. package/src/lib/Components/MediaCard/MediaCard.tsx +203 -0
  128. package/src/lib/Components/MediaCard/index.ts +2 -0
  129. package/src/lib/Components/MediaCard/types.ts +39 -0
  130. package/src/lib/Components/ThemeProvider/ThemeProvider.test.tsx +16 -18
  131. package/src/lib/Components/TriggerButton/TriggerButton.mdx +44 -0
  132. package/src/lib/Components/TriggerButton/TriggerButton.stories.tsx +132 -0
  133. package/src/lib/Components/TriggerButton/TriggerButton.test.tsx +157 -0
  134. package/src/lib/Components/TriggerButton/TriggerButton.tsx +228 -0
  135. package/src/lib/Components/TriggerButton/index.ts +2 -0
  136. package/src/lib/Components/TriggerButton/types.ts +38 -0
  137. package/src/lib/Components/Utility/Gradient/RadialGradient/RadialGradient.stories.tsx +1 -1
  138. package/src/lib/Components/index.ts +3 -0
  139. package/src/lib/Symbols/Icons/NanoGen5.tsx +44 -0
  140. package/src/lib/Symbols/index.ts +1 -0
@@ -0,0 +1,132 @@
1
+ import { CryptoIcon } from '@ledgerhq/crypto-icons';
2
+ import type { Meta, StoryObj } from '@storybook/react-native-web-vite';
3
+ import { Settings, Star } from '../../Symbols';
4
+ import { Box } from '../Utility';
5
+ import { TriggerButton } from './TriggerButton';
6
+
7
+ const meta: Meta<typeof TriggerButton> = {
8
+ component: TriggerButton,
9
+ title: 'Action/TriggerButton',
10
+ parameters: {
11
+ layout: 'centered',
12
+ docs: {
13
+ source: {
14
+ language: 'tsx',
15
+ format: true,
16
+ type: 'code',
17
+ },
18
+ },
19
+ },
20
+ };
21
+
22
+ export default meta;
23
+ type Story = StoryObj<typeof TriggerButton>;
24
+
25
+ export const Base: Story = {
26
+ args: {
27
+ children: 'All accounts',
28
+ appearance: 'gray',
29
+ },
30
+ render: (args) => <TriggerButton {...args} />,
31
+ parameters: {
32
+ docs: {
33
+ source: {
34
+ code: `
35
+ <TriggerButton appearance="gray">
36
+ All accounts
37
+ </TriggerButton>
38
+ `,
39
+ },
40
+ },
41
+ },
42
+ };
43
+
44
+ export const SizeShowcase: Story = {
45
+ render: () => (
46
+ <Box lx={{ flexDirection: 'row', alignItems: 'center', gap: 's16' }}>
47
+ <TriggerButton size='sm' icon={<Star size={20} />} iconType='flat'>
48
+ Small
49
+ </TriggerButton>
50
+ <TriggerButton size='md' icon={<Star size={20} />} iconType='flat'>
51
+ Medium
52
+ </TriggerButton>
53
+ </Box>
54
+ ),
55
+ };
56
+
57
+ export const IconTypeShowcase: Story = {
58
+ render: () => (
59
+ <Box lx={{ flexDirection: 'column', gap: 's16' }}>
60
+ <Box lx={{ flexDirection: 'row', alignItems: 'center', gap: 's16' }}>
61
+ <TriggerButton
62
+ icon={<Settings size={20} />}
63
+ iconType='flat'
64
+ appearance='gray'
65
+ >
66
+ Flat icon (md)
67
+ </TriggerButton>
68
+ <TriggerButton
69
+ icon={<CryptoIcon ledgerId='bitcoin' ticker='BTC' size='32px' />}
70
+ iconType='rounded'
71
+ appearance='gray'
72
+ >
73
+ Rounded icon (md)
74
+ </TriggerButton>
75
+ <TriggerButton appearance='gray'>No icon (md)</TriggerButton>
76
+ </Box>
77
+ <Box lx={{ flexDirection: 'row', alignItems: 'center', gap: 's16' }}>
78
+ <TriggerButton
79
+ icon={<Settings size={20} />}
80
+ iconType='flat'
81
+ appearance='gray'
82
+ size='sm'
83
+ >
84
+ Flat icon (sm)
85
+ </TriggerButton>
86
+ <TriggerButton
87
+ icon={<CryptoIcon ledgerId='bitcoin' ticker='BTC' size='24px' />}
88
+ iconType='rounded'
89
+ appearance='gray'
90
+ size='sm'
91
+ >
92
+ Rounded icon (sm)
93
+ </TriggerButton>
94
+ <TriggerButton appearance='gray' size='sm'>
95
+ No icon (sm)
96
+ </TriggerButton>
97
+ </Box>
98
+ </Box>
99
+ ),
100
+ };
101
+
102
+ export const AppearanceShowcase: Story = {
103
+ render: () => {
104
+ const appearances = ['gray', 'transparent', 'no-background'] as const;
105
+ return (
106
+ <Box lx={{ flexDirection: 'column', gap: 's16', padding: 's16' }}>
107
+ {appearances.map((appearance) => (
108
+ <Box
109
+ key={appearance}
110
+ lx={{ flexDirection: 'row', alignItems: 'center', gap: 's16' }}
111
+ >
112
+ <TriggerButton appearance={appearance}>{appearance}</TriggerButton>
113
+ <TriggerButton
114
+ appearance={appearance}
115
+ icon={<Settings size={20} />}
116
+ iconType='flat'
117
+ >
118
+ {appearance}
119
+ </TriggerButton>
120
+ <TriggerButton
121
+ appearance={appearance}
122
+ icon={<CryptoIcon ledgerId='bitcoin' ticker='BTC' size='32px' />}
123
+ iconType='rounded'
124
+ >
125
+ {appearance}
126
+ </TriggerButton>
127
+ </Box>
128
+ ))}
129
+ </Box>
130
+ );
131
+ },
132
+ };
@@ -0,0 +1,157 @@
1
+ import { describe, it, expect, jest } from '@jest/globals';
2
+ import { ledgerLiveThemes } from '@ledgerhq/lumen-design-core';
3
+ import { render, screen, fireEvent } from '@testing-library/react-native';
4
+ import React, { createRef } from 'react';
5
+ import { View, ViewStyle } from 'react-native';
6
+
7
+ import { Settings } from '../../Symbols';
8
+ import { ThemeProvider } from '../ThemeProvider/ThemeProvider';
9
+ import { TriggerButton } from './TriggerButton';
10
+
11
+ const renderWithProvider = (component: React.ReactElement) => {
12
+ return render(
13
+ <ThemeProvider themes={ledgerLiveThemes} colorScheme='dark' locale='en'>
14
+ {component}
15
+ </ThemeProvider>,
16
+ );
17
+ };
18
+
19
+ describe('TriggerButton', () => {
20
+ describe('Rendering', () => {
21
+ it('should render with label text and correct accessibility role', () => {
22
+ renderWithProvider(
23
+ <TriggerButton testID='trigger'>All accounts</TriggerButton>,
24
+ );
25
+ const trigger = screen.getByTestId('trigger');
26
+ expect(trigger).toBeTruthy();
27
+ expect(screen.getByText('All accounts')).toBeTruthy();
28
+ expect(trigger.props.accessibilityRole).toBe('button');
29
+ });
30
+
31
+ it('should always render a chevron icon', () => {
32
+ renderWithProvider(<TriggerButton testID='trigger'>Label</TriggerButton>);
33
+ expect(screen.getByTestId('button-trigger-chevron')).toBeTruthy();
34
+ });
35
+
36
+ it.each(['gray', 'transparent', 'no-background'] as const)(
37
+ 'should render without errors for appearance "%s"',
38
+ (appearance) => {
39
+ renderWithProvider(
40
+ <TriggerButton testID='trigger' appearance={appearance}>
41
+ Label
42
+ </TriggerButton>,
43
+ );
44
+ expect(screen.getByTestId('trigger')).toBeTruthy();
45
+ },
46
+ );
47
+
48
+ it.each(['sm', 'md'] as const)(
49
+ 'should render without errors for size "%s"',
50
+ (size) => {
51
+ renderWithProvider(
52
+ <TriggerButton testID='trigger' size={size}>
53
+ Label
54
+ </TriggerButton>,
55
+ );
56
+ expect(screen.getByTestId('trigger')).toBeTruthy();
57
+ },
58
+ );
59
+ });
60
+
61
+ describe('Icons', () => {
62
+ it('should render with a flat interface icon', () => {
63
+ renderWithProvider(
64
+ <TriggerButton
65
+ testID='trigger'
66
+ icon={<Settings size={20} testID='icon' />}
67
+ iconType='flat'
68
+ >
69
+ Network
70
+ </TriggerButton>,
71
+ );
72
+ expect(screen.getByTestId('icon')).toBeTruthy();
73
+ expect(screen.getByText('Network')).toBeTruthy();
74
+ });
75
+
76
+ it('should render with a rounded icon', () => {
77
+ renderWithProvider(
78
+ <TriggerButton
79
+ testID='trigger'
80
+ icon={<View testID='crypto-icon' />}
81
+ iconType='rounded'
82
+ >
83
+ Bitcoin
84
+ </TriggerButton>,
85
+ );
86
+ expect(screen.getByTestId('crypto-icon')).toBeTruthy();
87
+ expect(screen.getByText('Bitcoin')).toBeTruthy();
88
+ });
89
+ });
90
+
91
+ describe('States', () => {
92
+ it('should be disabled when disabled prop is true', () => {
93
+ renderWithProvider(
94
+ <TriggerButton testID='trigger' disabled>
95
+ Label
96
+ </TriggerButton>,
97
+ );
98
+ const trigger = screen.getByTestId('trigger');
99
+ expect(trigger.props.accessibilityState.disabled).toBe(true);
100
+ });
101
+ });
102
+
103
+ describe('Interactions', () => {
104
+ it('should call onPress when pressed', () => {
105
+ const handlePress = jest.fn();
106
+ renderWithProvider(
107
+ <TriggerButton testID='trigger' onPress={handlePress}>
108
+ Press me
109
+ </TriggerButton>,
110
+ );
111
+
112
+ fireEvent.press(screen.getByTestId('trigger'));
113
+ expect(handlePress).toHaveBeenCalledTimes(1);
114
+ });
115
+
116
+ it('should not call onPress when disabled', () => {
117
+ const handlePress = jest.fn();
118
+ renderWithProvider(
119
+ <TriggerButton testID='trigger' onPress={handlePress} disabled>
120
+ Disabled
121
+ </TriggerButton>,
122
+ );
123
+
124
+ fireEvent.press(screen.getByTestId('trigger'));
125
+ expect(handlePress).not.toHaveBeenCalled();
126
+ });
127
+ });
128
+
129
+ describe('Ref Forwarding', () => {
130
+ it('should forward ref', () => {
131
+ const ref = createRef<View>();
132
+ renderWithProvider(
133
+ <TriggerButton ref={ref} testID='trigger'>
134
+ Label
135
+ </TriggerButton>,
136
+ );
137
+ expect(ref.current).toBeTruthy();
138
+ });
139
+ });
140
+
141
+ describe('Styling', () => {
142
+ it('should apply custom style and lx props', () => {
143
+ const customStyle: ViewStyle = { marginTop: 16 };
144
+ renderWithProvider(
145
+ <TriggerButton
146
+ testID='trigger'
147
+ style={customStyle}
148
+ lx={{ padding: 's8' }}
149
+ >
150
+ Styled
151
+ </TriggerButton>,
152
+ );
153
+ const trigger = screen.getByTestId('trigger');
154
+ expect(trigger.props.style).toBeDefined();
155
+ });
156
+ });
157
+ });
@@ -0,0 +1,228 @@
1
+ import { PropsWithChildren } from 'react';
2
+ import { StyleSheet, Text, View } from 'react-native';
3
+ import { useStyleSheet } from '../../../styles';
4
+ import { ChevronDown } from '../../Symbols';
5
+ import { Pressable } from '../Utility';
6
+ import type { TriggerButtonProps } from './types';
7
+
8
+ type Appearance = NonNullable<TriggerButtonProps['appearance']>;
9
+ type Size = NonNullable<TriggerButtonProps['size']>;
10
+ type IconType = 'flat' | 'rounded' | 'none';
11
+
12
+ const useStyles = ({
13
+ appearance,
14
+ size,
15
+ disabled,
16
+ pressed,
17
+ iconType,
18
+ }: {
19
+ appearance: Appearance;
20
+ size: Size;
21
+ disabled: boolean;
22
+ pressed: boolean;
23
+ iconType: IconType;
24
+ }) => {
25
+ return useStyleSheet(
26
+ (t) => {
27
+ const bgColors: Record<Appearance, string> = {
28
+ gray: t.colors.bg.muted,
29
+ transparent: t.colors.bg.mutedTransparent,
30
+ 'no-background': 'transparent',
31
+ };
32
+
33
+ const pressedBgColors: Record<Appearance, string> = {
34
+ gray: t.colors.bg.mutedPressed,
35
+ transparent: t.colors.bg.mutedTransparentPressed,
36
+ 'no-background': t.colors.bg.baseTransparentPressed,
37
+ };
38
+
39
+ const textColor = disabled ? t.colors.text.disabled : t.colors.text.base;
40
+
41
+ type PaddingStyle = {
42
+ paddingTop: number;
43
+ paddingBottom: number;
44
+ paddingLeft: number;
45
+ paddingRight: number;
46
+ };
47
+
48
+ const paddingMap: Record<Size, Record<IconType, PaddingStyle>> = {
49
+ md: {
50
+ flat: {
51
+ paddingTop: t.spacings.s12,
52
+ paddingBottom: t.spacings.s12,
53
+ paddingLeft: t.spacings.s16,
54
+ paddingRight: t.spacings.s16,
55
+ },
56
+ rounded: {
57
+ paddingTop: t.spacings.s8,
58
+ paddingBottom: t.spacings.s8,
59
+ paddingLeft: t.spacings.s8,
60
+ paddingRight: t.spacings.s16,
61
+ },
62
+ none: {
63
+ paddingTop: t.spacings.s14,
64
+ paddingBottom: t.spacings.s14,
65
+ paddingLeft: t.spacings.s16,
66
+ paddingRight: t.spacings.s16,
67
+ },
68
+ },
69
+ sm: {
70
+ flat: {
71
+ paddingTop: t.spacings.s10,
72
+ paddingBottom: t.spacings.s10,
73
+ paddingLeft: t.spacings.s12,
74
+ paddingRight: t.spacings.s12,
75
+ },
76
+ rounded: {
77
+ paddingTop: t.spacings.s8,
78
+ paddingBottom: t.spacings.s8,
79
+ paddingLeft: t.spacings.s8,
80
+ paddingRight: t.spacings.s10,
81
+ },
82
+ none: {
83
+ paddingTop: t.spacings.s10,
84
+ paddingBottom: t.spacings.s10,
85
+ paddingLeft: t.spacings.s12,
86
+ paddingRight: t.spacings.s12,
87
+ },
88
+ },
89
+ };
90
+
91
+ return {
92
+ container: StyleSheet.flatten([
93
+ {
94
+ flexDirection: 'row',
95
+ alignItems: 'center',
96
+ borderRadius: t.borderRadius.full,
97
+ backgroundColor: bgColors[appearance],
98
+ gap: t.spacings.s8,
99
+ },
100
+ paddingMap[size][iconType],
101
+ pressed && { backgroundColor: pressedBgColors[appearance] },
102
+ disabled && { backgroundColor: t.colors.bg.disabled },
103
+ appearance === 'no-background' &&
104
+ disabled && { backgroundColor: 'transparent' },
105
+ ]),
106
+ label: StyleSheet.flatten([
107
+ t.typographies.body2SemiBold,
108
+ {
109
+ color: textColor,
110
+ textAlign: 'left',
111
+ },
112
+ ]),
113
+ labelWrapper: {
114
+ flexDirection: 'row',
115
+ alignItems: 'center',
116
+ gap: t.spacings.s2,
117
+ },
118
+ icon: {
119
+ flexShrink: 0,
120
+ },
121
+ chevron: {
122
+ flexShrink: 0,
123
+ color: textColor,
124
+ },
125
+ };
126
+ },
127
+ [appearance, size, disabled, pressed, iconType],
128
+ );
129
+ };
130
+
131
+ /**
132
+ * Trigger button for select/dropdown components. Displays a label with an optional
133
+ * leading icon and a trailing chevron indicator.
134
+ *
135
+ * This component is intended to be used exclusively as the trigger inside a Select or
136
+ * dropdown pattern. It should not be used as a standalone action button — use `Button`
137
+ * or `IconButton` instead.
138
+ *
139
+ * @see {@link https://www.figma.com/design/JxaLVMTWirCpU0rsbZ30k7/2.-Components-Library?node-id=6389-45680 Figma}
140
+ *
141
+ * @example
142
+ * import { TriggerButton } from '@ledgerhq/lumen-ui-rnative';
143
+ * import { Settings } from '@ledgerhq/lumen-ui-rnative/symbols';
144
+ *
145
+ * <TriggerButton icon={<Settings size={20} />} iconType="flat">
146
+ * Network
147
+ * </TriggerButton>
148
+ *
149
+ * <TriggerButton>All accounts</TriggerButton>
150
+ */
151
+ export const TriggerButton = ({
152
+ lx,
153
+ style,
154
+ appearance = 'gray',
155
+ size = 'md',
156
+ disabled = false,
157
+ icon,
158
+ iconType = 'flat',
159
+ children: label,
160
+ ref,
161
+ ...props
162
+ }: TriggerButtonProps) => {
163
+ const effectiveIconType: IconType = icon ? iconType : 'none';
164
+
165
+ return (
166
+ <Pressable
167
+ ref={ref}
168
+ lx={lx}
169
+ style={style}
170
+ disabled={disabled}
171
+ accessibilityRole='button'
172
+ accessibilityState={{ disabled }}
173
+ {...props}
174
+ >
175
+ {({ pressed }) => (
176
+ <TriggerButtonContent
177
+ appearance={appearance}
178
+ size={size}
179
+ disabled={disabled}
180
+ pressed={pressed}
181
+ iconType={effectiveIconType}
182
+ icon={icon}
183
+ >
184
+ {label}
185
+ </TriggerButtonContent>
186
+ )}
187
+ </Pressable>
188
+ );
189
+ };
190
+
191
+ type TriggerButtonContentProps = PropsWithChildren<{
192
+ appearance: Appearance;
193
+ size: Size;
194
+ disabled: boolean;
195
+ pressed: boolean;
196
+ iconType: IconType;
197
+ icon?: TriggerButtonProps['icon'];
198
+ }>;
199
+
200
+ const TriggerButtonContent = ({
201
+ appearance,
202
+ size,
203
+ disabled,
204
+ pressed,
205
+ iconType,
206
+ icon,
207
+ children,
208
+ }: TriggerButtonContentProps) => {
209
+ const styles = useStyles({ appearance, size, disabled, pressed, iconType });
210
+
211
+ return (
212
+ <View style={styles.container} testID='button-trigger-content'>
213
+ {icon && <View style={styles.icon}>{icon}</View>}
214
+ <View style={styles.labelWrapper}>
215
+ <Text style={styles.label} numberOfLines={1} ellipsizeMode='tail'>
216
+ {children}
217
+ </Text>
218
+ <ChevronDown
219
+ size={20}
220
+ style={styles.chevron}
221
+ testID='button-trigger-chevron'
222
+ />
223
+ </View>
224
+ </View>
225
+ );
226
+ };
227
+
228
+ TriggerButton.displayName = 'TriggerButton';
@@ -0,0 +1,2 @@
1
+ export { TriggerButton } from './TriggerButton';
2
+ export * from './types';
@@ -0,0 +1,38 @@
1
+ import { ReactNode } from 'react';
2
+ import { StyledPressableProps } from '../../../styles';
3
+
4
+ export type TriggerButtonProps = {
5
+ /**
6
+ * The visual style of the trigger button.
7
+ * @default 'gray'
8
+ */
9
+ appearance?: 'gray' | 'transparent' | 'no-background';
10
+ /**
11
+ * The size variant of the trigger button.
12
+ * @default 'md'
13
+ */
14
+ size?: 'sm' | 'md';
15
+ /**
16
+ * An optional pre-rendered icon element to display as leading content.
17
+ * Consumer is responsible for sizing the icon.
18
+ */
19
+ icon?: ReactNode;
20
+ /**
21
+ * Determines the padding scheme when an icon is present.
22
+ * - `'flat'`: Standard padding for line/interface icons.
23
+ * - `'rounded'`: Tighter left padding for circular icons with their own background (e.g., crypto icons).
24
+ *
25
+ * Only relevant when `icon` is provided.
26
+ * @default 'flat'
27
+ */
28
+ iconType?: 'flat' | 'rounded';
29
+ /**
30
+ * Whether the trigger button is disabled.
31
+ * @default false
32
+ */
33
+ disabled?: boolean;
34
+ /**
35
+ * The label content of the trigger button.
36
+ */
37
+ children: ReactNode;
38
+ } & Omit<StyledPressableProps, 'children'>;
@@ -64,7 +64,7 @@ export const CenterPositionShowcase: Story = {
64
64
  { center: { x: 0.8, y: 0.2 }, label: '{x: 0.8, y: 0.2}' },
65
65
  ],
66
66
  },
67
- ] as const;
67
+ ];
68
68
 
69
69
  return (
70
70
  <Box lx={{ flexDirection: 'column', gap: 's40' }}>
@@ -5,6 +5,7 @@ export * from './Avatar';
5
5
  export * from './Banner';
6
6
  export * from './BottomSheet';
7
7
  export * from './Button';
8
+ export * from './TriggerButton';
8
9
  export * from './Card';
9
10
  export * from './CardButton';
10
11
  export * from './ContentBanner';
@@ -15,6 +16,8 @@ export * from './IconButton';
15
16
  export * from './InteractiveIcon';
16
17
  export * from './Link';
17
18
  export * from './ListItem';
19
+ export * from './MediaBanner';
20
+ export * from './MediaCard';
18
21
  export * from './NavBar';
19
22
  export * from './PageIndicator';
20
23
  export * from './SearchInput';
@@ -0,0 +1,44 @@
1
+ import Svg, { Path } from 'react-native-svg';
2
+ import createIcon from '../../Components/Icon/createIcon';
3
+
4
+ /**
5
+ * NanoGen5 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 { NanoGen5 } from '@ledgerhq/lumen-ui-rnative/symbols';
19
+ *
20
+ * <NanoGen5 />
21
+ *
22
+ * @example
23
+ * // With custom size and style
24
+ * <NanoGen5 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={NanoGen5} size="md">
31
+ * Click me
32
+ * </Button>
33
+ */
34
+ export const NanoGen5 = createIcon(
35
+ 'NanoGen5',
36
+ <Svg width={24} height={24} fill='currentColor' viewBox='0 0 16 16'>
37
+ <Path
38
+ fill='currentColor'
39
+ fillRule='evenodd'
40
+ d='M11 1.333c.92 0 1.667.747 1.667 1.667v.333c.184 0 .333.15.333.334v1.666a.334.334 0 0 1-.266.327l-.067.007V13c0 .92-.746 1.667-1.667 1.667H5c-.92 0-1.667-.746-1.667-1.667V3c0-.92.747-1.667 1.667-1.667zM9.667 12.667a.667.667 0 0 0 0 1.333H11a.667.667 0 0 0 0-1.333zM5 2.333A.667.667 0 0 0 4.333 3v8c0 .368.299.667.667.667h6a.667.667 0 0 0 .667-.667V3A.667.667 0 0 0 11 2.333z'
41
+ clipRule='evenodd'
42
+ />
43
+ </Svg>,
44
+ );
@@ -164,6 +164,7 @@ export { Moon } from './Icons/Moon';
164
164
  export { MoreHorizontal } from './Icons/MoreHorizontal';
165
165
  export { MoreVertical } from './Icons/MoreVertical';
166
166
  export { Nano } from './Icons/Nano';
167
+ export { NanoGen5 } from './Icons/NanoGen5';
167
168
  export { NetworkWarning } from './Icons/NetworkWarning';
168
169
  export { Nfc } from './Icons/Nfc';
169
170
  export { Nft } from './Icons/Nft';