@transferwise/components 0.0.0-experimental-6a6c19f → 0.0.0-experimental-e72bc9f

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 (166) hide show
  1. package/build/i18n/cs.json +1 -0
  2. package/build/i18n/cs.json.js +1 -0
  3. package/build/i18n/cs.json.js.map +1 -1
  4. package/build/i18n/cs.json.mjs +1 -0
  5. package/build/i18n/cs.json.mjs.map +1 -1
  6. package/build/i18n/de.json +1 -0
  7. package/build/i18n/de.json.js +1 -0
  8. package/build/i18n/de.json.js.map +1 -1
  9. package/build/i18n/de.json.mjs +1 -0
  10. package/build/i18n/de.json.mjs.map +1 -1
  11. package/build/i18n/es.json +1 -0
  12. package/build/i18n/es.json.js +1 -0
  13. package/build/i18n/es.json.js.map +1 -1
  14. package/build/i18n/es.json.mjs +1 -0
  15. package/build/i18n/es.json.mjs.map +1 -1
  16. package/build/i18n/fr.json +1 -0
  17. package/build/i18n/fr.json.js +1 -0
  18. package/build/i18n/fr.json.js.map +1 -1
  19. package/build/i18n/fr.json.mjs +1 -0
  20. package/build/i18n/fr.json.mjs.map +1 -1
  21. package/build/i18n/hu.json +1 -0
  22. package/build/i18n/hu.json.js +1 -0
  23. package/build/i18n/hu.json.js.map +1 -1
  24. package/build/i18n/hu.json.mjs +1 -0
  25. package/build/i18n/hu.json.mjs.map +1 -1
  26. package/build/i18n/id.json +1 -0
  27. package/build/i18n/id.json.js +1 -0
  28. package/build/i18n/id.json.js.map +1 -1
  29. package/build/i18n/id.json.mjs +1 -0
  30. package/build/i18n/id.json.mjs.map +1 -1
  31. package/build/i18n/it.json +1 -0
  32. package/build/i18n/it.json.js +1 -0
  33. package/build/i18n/it.json.js.map +1 -1
  34. package/build/i18n/it.json.mjs +1 -0
  35. package/build/i18n/it.json.mjs.map +1 -1
  36. package/build/i18n/ja.json +1 -0
  37. package/build/i18n/ja.json.js +1 -0
  38. package/build/i18n/ja.json.js.map +1 -1
  39. package/build/i18n/ja.json.mjs +1 -0
  40. package/build/i18n/ja.json.mjs.map +1 -1
  41. package/build/i18n/nl.json +4 -3
  42. package/build/i18n/pl.json +1 -0
  43. package/build/i18n/pl.json.js +1 -0
  44. package/build/i18n/pl.json.js.map +1 -1
  45. package/build/i18n/pl.json.mjs +1 -0
  46. package/build/i18n/pl.json.mjs.map +1 -1
  47. package/build/i18n/pt.json +1 -0
  48. package/build/i18n/pt.json.js +1 -0
  49. package/build/i18n/pt.json.js.map +1 -1
  50. package/build/i18n/pt.json.mjs +1 -0
  51. package/build/i18n/pt.json.mjs.map +1 -1
  52. package/build/i18n/ro.json +1 -0
  53. package/build/i18n/ro.json.js +1 -0
  54. package/build/i18n/ro.json.js.map +1 -1
  55. package/build/i18n/ro.json.mjs +1 -0
  56. package/build/i18n/ro.json.mjs.map +1 -1
  57. package/build/i18n/ru.json +1 -0
  58. package/build/i18n/ru.json.js +1 -0
  59. package/build/i18n/ru.json.js.map +1 -1
  60. package/build/i18n/ru.json.mjs +1 -0
  61. package/build/i18n/ru.json.mjs.map +1 -1
  62. package/build/i18n/th.json +1 -0
  63. package/build/i18n/th.json.js +1 -0
  64. package/build/i18n/th.json.js.map +1 -1
  65. package/build/i18n/th.json.mjs +1 -0
  66. package/build/i18n/th.json.mjs.map +1 -1
  67. package/build/i18n/tr.json +1 -0
  68. package/build/i18n/tr.json.js +1 -0
  69. package/build/i18n/tr.json.js.map +1 -1
  70. package/build/i18n/tr.json.mjs +1 -0
  71. package/build/i18n/tr.json.mjs.map +1 -1
  72. package/build/i18n/zh-CN.json +1 -0
  73. package/build/i18n/zh-CN.json.js +1 -0
  74. package/build/i18n/zh-CN.json.js.map +1 -1
  75. package/build/i18n/zh-CN.json.mjs +1 -0
  76. package/build/i18n/zh-CN.json.mjs.map +1 -1
  77. package/build/i18n/zh-HK.json +1 -0
  78. package/build/i18n/zh-HK.json.js +1 -0
  79. package/build/i18n/zh-HK.json.js.map +1 -1
  80. package/build/i18n/zh-HK.json.mjs +1 -0
  81. package/build/i18n/zh-HK.json.mjs.map +1 -1
  82. package/build/image/Image.js +10 -9
  83. package/build/image/Image.js.map +1 -1
  84. package/build/image/Image.mjs +11 -11
  85. package/build/image/Image.mjs.map +1 -1
  86. package/build/index.js +1 -0
  87. package/build/index.js.map +1 -1
  88. package/build/index.mjs +1 -1
  89. package/build/main.css +188 -0
  90. package/build/styles/listItem/ListItem.css +188 -0
  91. package/build/styles/main.css +188 -0
  92. package/build/test-utils/assets/apple-pay-logo.svg +84 -0
  93. package/build/types/image/Image.d.ts +1 -0
  94. package/build/types/image/Image.d.ts.map +1 -1
  95. package/build/types/index.d.ts +2 -0
  96. package/build/types/index.d.ts.map +1 -1
  97. package/build/types/listItem/ListItem.d.ts +43 -0
  98. package/build/types/listItem/ListItem.d.ts.map +1 -0
  99. package/build/types/listItem/ListItemAdditionalInfo.d.ts +9 -0
  100. package/build/types/listItem/ListItemAdditionalInfo.d.ts.map +1 -0
  101. package/build/types/listItem/ListItemButton.d.ts +4 -0
  102. package/build/types/listItem/ListItemButton.d.ts.map +1 -0
  103. package/build/types/listItem/ListItemCheckbox.d.ts +4 -0
  104. package/build/types/listItem/ListItemCheckbox.d.ts.map +1 -0
  105. package/build/types/listItem/ListItemIconButton.d.ts +7 -0
  106. package/build/types/listItem/ListItemIconButton.d.ts.map +1 -0
  107. package/build/types/listItem/ListItemMedia.d.ts +19 -0
  108. package/build/types/listItem/ListItemMedia.d.ts.map +1 -0
  109. package/build/types/listItem/ListItemNavigation.d.ts +4 -0
  110. package/build/types/listItem/ListItemNavigation.d.ts.map +1 -0
  111. package/build/types/listItem/ListItemSwitch.d.ts +3 -0
  112. package/build/types/listItem/ListItemSwitch.d.ts.map +1 -0
  113. package/build/types/listItem/index.d.ts +6 -0
  114. package/build/types/listItem/index.d.ts.map +1 -0
  115. package/build/types/listItem/prompt/Prompt.d.ts +12 -0
  116. package/build/types/listItem/prompt/Prompt.d.ts.map +1 -0
  117. package/build/types/listItem/useItemControl.d.ts +5 -0
  118. package/build/types/listItem/useItemControl.d.ts.map +1 -0
  119. package/build/types/test-utils/fake-data.d.ts +2 -0
  120. package/build/types/test-utils/fake-data.d.ts.map +1 -1
  121. package/package.json +3 -3
  122. package/src/i18n/cs.json +1 -0
  123. package/src/i18n/de.json +1 -0
  124. package/src/i18n/es.json +1 -0
  125. package/src/i18n/fr.json +1 -0
  126. package/src/i18n/hu.json +1 -0
  127. package/src/i18n/id.json +1 -0
  128. package/src/i18n/it.json +1 -0
  129. package/src/i18n/ja.json +1 -0
  130. package/src/i18n/nl.json +4 -3
  131. package/src/i18n/pl.json +1 -0
  132. package/src/i18n/pt.json +1 -0
  133. package/src/i18n/ro.json +1 -0
  134. package/src/i18n/ru.json +1 -0
  135. package/src/i18n/th.json +1 -0
  136. package/src/i18n/tr.json +1 -0
  137. package/src/i18n/zh-CN.json +1 -0
  138. package/src/i18n/zh-HK.json +1 -0
  139. package/src/image/Image.spec.tsx +3 -3
  140. package/src/image/Image.tsx +12 -10
  141. package/src/index.ts +2 -0
  142. package/src/legacylistItem/LegacyListItem.story.tsx +5 -5
  143. package/src/legacylistItem/LegacyListItem.tests.story.tsx +6 -6
  144. package/src/listItem/ListItem.css +188 -0
  145. package/src/listItem/ListItem.less +182 -0
  146. package/src/listItem/ListItem.story.tsx +273 -0
  147. package/src/listItem/ListItem.tsx +183 -0
  148. package/src/listItem/ListItemAdditionalInfo.tsx +31 -0
  149. package/src/listItem/ListItemButton.spec.tsx +90 -0
  150. package/src/listItem/ListItemButton.tsx +18 -0
  151. package/src/listItem/ListItemCheckbox.tsx +14 -0
  152. package/src/listItem/ListItemIconButton.tsx +13 -0
  153. package/src/listItem/ListItemMedia.tsx +52 -0
  154. package/src/listItem/ListItemNavigation.tsx +11 -0
  155. package/src/listItem/ListItemSwitch.tsx +8 -0
  156. package/src/listItem/index.ts +10 -0
  157. package/src/listItem/prompt/Prompt.spec.tsx +77 -0
  158. package/src/listItem/prompt/Prompt.story.tsx +170 -0
  159. package/src/listItem/prompt/Prompt.tsx +44 -0
  160. package/src/listItem/useItemControl.tsx +12 -0
  161. package/src/main.css +188 -0
  162. package/src/main.less +1 -0
  163. package/src/promoCard/__snapshots__/PromoCard.spec.tsx.snap +0 -1
  164. package/src/promoCard/__snapshots__/PromoCardGroup.spec.tsx.snap +0 -2
  165. package/src/test-utils/assets/apple-pay-logo.svg +84 -0
  166. package/src/test-utils/fake-data.ts +5 -0
@@ -0,0 +1,182 @@
1
+ .wds-list-item {
2
+ padding: var(--size-16);
3
+ border-radius: var(--radius-large);
4
+ background-color: var(--color-background-screen);
5
+ gap: var(--size-16);
6
+
7
+ &-interactive {
8
+ cursor: pointer;
9
+ &:hover {
10
+ background-color: var(--color-background-screen-hover);
11
+ }
12
+ &:active {
13
+ background-color: var(--color-background-screen-active);
14
+ }
15
+ }
16
+
17
+ &-media {
18
+
19
+ &-image {
20
+ width: var(--item-media-image-size);
21
+ height: var(--item-media-image-size);
22
+ }
23
+ }
24
+
25
+ &-body {
26
+ width: 100%;
27
+ }
28
+
29
+ &-title {
30
+ color: var(--color-content-primary);
31
+ }
32
+
33
+ &-additional-info {
34
+ color: var(--color-content-tertiary);
35
+ }
36
+
37
+ &-value {
38
+ flex: 0 0 auto;
39
+ }
40
+
41
+ &-control {
42
+ flex: 0 0 auto;
43
+ }
44
+
45
+ &-spotlight {
46
+ &-active {
47
+ background-color: var(--color-background-neutral);
48
+
49
+ &:hover {
50
+ background-color: var(--color-background-neutral-hover);
51
+ }
52
+ &:active {
53
+ background-color: var(--color-background-neutral-active);
54
+ }
55
+ }
56
+
57
+ &-inactive {
58
+ background-color: color-mix(in srgb, var(--color-background-neutral) 25%, transparent);
59
+ border: 1px dashed var(--color-border-neutral);
60
+
61
+ &:hover {
62
+ background-color: color-mix(in srgb, var(--color-background-neutral-hover) 25%, transparent);
63
+ }
64
+ &:active {
65
+ background-color: color-mix(in srgb, var(--color-background-neutral-active) 25%, transparent);
66
+ }
67
+ }
68
+ }
69
+
70
+ &-prompt {
71
+ display: inline-flex;
72
+ padding-top: calc(var(--padding-x-small) / 2);
73
+ padding-bottom: calc(var(--padding-x-small) / 2);
74
+ padding-left: calc(var(--padding-x-small) - 1px);
75
+ padding-right: var(--padding-x-small);
76
+ border-radius: var(--radius-small);
77
+ word-break: break-word;
78
+ overflow-wrap: break-word;
79
+
80
+ .np-prompt-icon {
81
+ padding-right: calc(var(--size-12) / 2);
82
+ padding-top: calc(var(--size-4) - 1px);
83
+ padding-bottom: calc(var(--size-4) - 1px);
84
+
85
+ .tw-icon-tags,
86
+ .tw-icon-confetti {
87
+ color: var(--color-sentiment-positive-primary);
88
+ }
89
+ }
90
+
91
+ a {
92
+ text-underline-offset: calc(var(--size-4) / 2);
93
+ }
94
+
95
+ &.np-prompt-interactive {
96
+ text-decoration: none;
97
+ cursor: pointer;
98
+ border: none;
99
+ }
100
+
101
+ &.negative {
102
+ background-color: var(--color-sentiment-negative-secondary);
103
+ color: var(--color-sentiment-negative-primary);
104
+ a {
105
+ color: var(--color-sentiment-negative-primary);
106
+ &:hover {
107
+ color: var(--color-sentiment-negative-primary-hover);
108
+ }
109
+ &:active {
110
+ color: var(--color-sentiment-negative-primary-active);
111
+ }
112
+ }
113
+ .np-prompt-interactive& {
114
+ &:hover {
115
+ background-color: color-mix(in srgb, var(--color-sentiment-negative-secondary) 95%, var(--color-sentiment-negative-primary));
116
+ }
117
+ &:active {
118
+ background-color: color-mix(in srgb, var(--color-sentiment-negative-secondary) 90%, var(--color-sentiment-negative-primary));
119
+ }
120
+ }
121
+ }
122
+ &.positive,
123
+ &.discount,
124
+ &.savings {
125
+ background-color: var(--color-sentiment-positive-secondary);
126
+ color: var(--color-sentiment-positive-primary);
127
+ a {
128
+ color: var(--color-sentiment-positive-primary);
129
+ &:hover {
130
+ color: var(--color-sentiment-positive-primary-hover);
131
+ }
132
+ &:active {
133
+ color: var(--color-sentiment-positive-primary-active);
134
+ }
135
+ }
136
+ .np-prompt-interactive& {
137
+ &:hover {
138
+ background-color: color-mix(in srgb, var(--color-sentiment-positive-secondary) 95%, var(--color-sentiment-positive-primary));
139
+ }
140
+ &:active {
141
+ background-color: color-mix(in srgb, var(--color-sentiment-positive-secondary) 90%, var(--color-sentiment-positive-primary));
142
+ }
143
+ }
144
+ }
145
+ &.neutral {
146
+ background-color: var(--color-background-neutral);
147
+ color: var(--color-content-primary);
148
+ a {
149
+ color: var(--color-content-primary);
150
+ }
151
+ .np-prompt-interactive& {
152
+ &:hover {
153
+ background-color: var(--color-background-neutral-hover);
154
+ }
155
+ &:active {
156
+ background-color: var(--color-background-neutral-active);
157
+ }
158
+ }
159
+ }
160
+ &.warning {
161
+ background-color: var(--color-sentiment-warning-secondary);
162
+ color: var(--color-sentiment-warning-content);
163
+ a {
164
+ color: var(--color-sentiment-warning-content);
165
+ &:hover {
166
+ color: var(--color-sentiment-warning-content-hover);
167
+ }
168
+ &:active {
169
+ color: var(--color-sentiment-warning-content-active);
170
+ }
171
+ }
172
+ .np-prompt-interactive& {
173
+ &:hover {
174
+ background-color: color-mix(in srgb, var(--color-sentiment-warning-secondary) 90%, var(--color-sentiment-warning-primary));
175
+ }
176
+ &:active {
177
+ background-color: color-mix(in srgb, var(--color-sentiment-warning-secondary) 80%, var(--color-sentiment-warning-primary));
178
+ }
179
+ }
180
+ }
181
+ }
182
+ }
@@ -0,0 +1,273 @@
1
+ import ListItem, { Props as ItemProps } from './ListItem';
2
+ import { Meta, StoryObj } from '@storybook/react';
3
+ import React, { useState } from 'react';
4
+ import { FastFlag, MultiCurrency, Plus, Receipt, Savings } from '@transferwise/icons';
5
+
6
+ import { lorem10, lorem20, lorem40, lorem5 } from '../test-utils';
7
+ import { Flag } from '@wise/art';
8
+ import { List } from '../legacylistItem/List';
9
+ import Money from '../money';
10
+ import Section from '../section';
11
+ import Header from '../header';
12
+
13
+ export default {
14
+ component: ListItem,
15
+ title: 'Content/ListItem',
16
+ } satisfies Meta<ItemProps>;
17
+
18
+ type Story = StoryObj<ItemProps>;
19
+
20
+ // TODO: delete this story later when we have more peace of the List Item puzzle
21
+ export const TempPlayground: Story = {
22
+ render: () => {
23
+ const [checked, setChecked] = useState(false);
24
+
25
+ return (
26
+ <div>
27
+ <ListItem
28
+ media={
29
+ <ListItem.AvatarView badge={{ type: 'action' }}>
30
+ <Flag code="BBD" />
31
+ </ListItem.AvatarView>
32
+ }
33
+ title="Test title"
34
+ subtitle="Test subtitle"
35
+ additionalInfo={<ListItem.AdditionalInfo>{lorem10}</ListItem.AdditionalInfo>}
36
+ />
37
+ <ListItem
38
+ media={
39
+ <ListItem.AvatarLayout
40
+ avatars={[{ asset: <Flag code="BBD" /> }, { asset: <Flag code="MXN" /> }]}
41
+ />
42
+ }
43
+ title="Test title"
44
+ subtitle={lorem10}
45
+ additionalInfo={<ListItem.AdditionalInfo>{lorem20}</ListItem.AdditionalInfo>}
46
+ />
47
+ <ListItem
48
+ media={
49
+ <ListItem.AvatarLayout
50
+ size={72}
51
+ orientation="diagonal"
52
+ avatars={[{ asset: <Flag code="BBD" /> }, { asset: <Flag code="MXN" /> }]}
53
+ />
54
+ }
55
+ title="Test title"
56
+ subtitle={lorem10}
57
+ valueTitle="100 GBP"
58
+ valueSubtitle="100 USD"
59
+ additionalInfo={<ListItem.AdditionalInfo>{lorem20}</ListItem.AdditionalInfo>}
60
+ />
61
+ <ListItem
62
+ media={<ListItem.AvatarView profileType="BUSINESS" notification />}
63
+ title="Test title"
64
+ subtitle="Test subtitle"
65
+ additionalInfo={
66
+ <ListItem.AdditionalInfo
67
+ action={{ label: 'Learn more', href: 'https://wise.com', target: '_blank' }}
68
+ >
69
+ {lorem10}
70
+ </ListItem.AdditionalInfo>
71
+ }
72
+ prompt={<ListItem.Prompt type="negative">You have done something wrong</ListItem.Prompt>}
73
+ />
74
+ <ListItem
75
+ media={<ListItem.AvatarView imgSrc="../avatar-square-dude.webp" selected />}
76
+ title="Test title"
77
+ additionalInfo={<ListItem.AdditionalInfo>{lorem10}</ListItem.AdditionalInfo>}
78
+ prompt={
79
+ <ListItem.Prompt
80
+ type="discount"
81
+ action={{
82
+ href: 'https://wise.com',
83
+ target: '_blank',
84
+ 'aria-label': 'clickable prompt',
85
+ }}
86
+ >
87
+ The whole prompt is secretly clickable
88
+ </ListItem.Prompt>
89
+ }
90
+ />
91
+
92
+ <ListItem
93
+ media={<ListItem.Image src="../apple-pay-logo.svg" />}
94
+ title="Accepting Apple Pay"
95
+ subtitle={lorem10}
96
+ />
97
+
98
+ <ListItem
99
+ media={<ListItem.Image src="../wise-card.svg" />}
100
+ title="Wise Business Card"
101
+ subtitle={lorem5}
102
+ />
103
+
104
+ <ListItem
105
+ title="Test title"
106
+ disabled
107
+ subtitle={lorem10}
108
+ additionalInfo={<ListItem.AdditionalInfo>{lorem20}</ListItem.AdditionalInfo>}
109
+ control={<ListItem.Button priority="secondary-neutral">as Button</ListItem.Button>}
110
+ />
111
+ <ListItem
112
+ title="Test title"
113
+ disabled
114
+ subtitle={lorem10}
115
+ additionalInfo={<ListItem.AdditionalInfo>{lorem20}</ListItem.AdditionalInfo>}
116
+ control={
117
+ <ListItem.IconButton>
118
+ <Plus />
119
+ </ListItem.IconButton>
120
+ }
121
+ />
122
+
123
+ <ListItem
124
+ title="Test title"
125
+ subtitle={lorem10}
126
+ additionalInfo={<ListItem.AdditionalInfo>{lorem20}</ListItem.AdditionalInfo>}
127
+ control={
128
+ <ListItem.Button
129
+ priority="secondary-neutral"
130
+ as="a"
131
+ target="dfdf"
132
+ aria-label="adsfasfd"
133
+ href="wise.com"
134
+ >
135
+ as Link
136
+ </ListItem.Button>
137
+ }
138
+ />
139
+
140
+ <ListItem
141
+ title="Test title"
142
+ subtitle={lorem10}
143
+ additionalInfo={<ListItem.AdditionalInfo>{lorem20}</ListItem.AdditionalInfo>}
144
+ control={<ListItem.Checkbox indeterminate />}
145
+ />
146
+
147
+ <ListItem
148
+ title="Test title"
149
+ subtitle={lorem10}
150
+ additionalInfo={<ListItem.AdditionalInfo>{lorem20}</ListItem.AdditionalInfo>}
151
+ control={
152
+ <ListItem.Switch
153
+ checked={checked}
154
+ onClick={() => {
155
+ setChecked(!checked);
156
+ }}
157
+ />
158
+ }
159
+ />
160
+ </div>
161
+ );
162
+ },
163
+ };
164
+
165
+ export const Radio: Story = {
166
+ render: () => (
167
+ <div>
168
+ {/* Basic */}
169
+ {/* with additional info */}
170
+ {/* with prompt */}
171
+ {/* Disabled */}
172
+ {/* Spotlight */}
173
+ {/* Active */}
174
+ </div>
175
+ ),
176
+ };
177
+
178
+ export const Button: Story = {
179
+ render: () => (
180
+ <div>
181
+ {/* Basic */}
182
+ {/* with additional info */}
183
+ {/* with prompt */}
184
+ {/* partially interactive */}
185
+ {/* Disabled */}
186
+ {/* Spotlight */}
187
+ {/* Active */}
188
+ </div>
189
+ ),
190
+ };
191
+
192
+ export const NonInteractive: Story = {
193
+ render: () => (
194
+ <div>
195
+ <Section>
196
+ <Header title="Transcation Details" />
197
+ <List>
198
+ <ListItem
199
+ media={
200
+ <ListItem.AvatarView>
201
+ <MultiCurrency />
202
+ </ListItem.AvatarView>
203
+ }
204
+ title="Estimated costs"
205
+ subtitle="Other providers"
206
+ valueTitle={<Money amount={100} currency="GBP" />}
207
+ />
208
+ <ListItem
209
+ media={
210
+ <ListItem.AvatarView>
211
+ <FastFlag />
212
+ </ListItem.AvatarView>
213
+ }
214
+ title="Total paid"
215
+ subtitle="Wise"
216
+ valueTitle={<Money amount={12.15} currency="GBP" />}
217
+ valueSubtitle={<Money amount={100.9} currency="GBP" />}
218
+ />
219
+ <ListItem
220
+ media={
221
+ <ListItem.AvatarView>
222
+ <Receipt />
223
+ </ListItem.AvatarView>
224
+ }
225
+ title="Total fees"
226
+ subtitle={lorem5}
227
+ valueSubtitle={<Money amount={5.5} currency="GBP" />}
228
+ />
229
+ <ListItem
230
+ media={
231
+ <ListItem.AvatarView>
232
+ <Savings />
233
+ </ListItem.AvatarView>
234
+ }
235
+ title="You saved"
236
+ valueSubtitle={<Money amount={1000} currency="GBP" />}
237
+ />
238
+ </List>
239
+ </Section>
240
+
241
+ <ListItem
242
+ as="div"
243
+ title="Bank name and address"
244
+ subtitle="Bank Ltd, 2 Street Boulevard, Singapore, 1213423"
245
+ additionalInfo={
246
+ <ListItem.AdditionalInfo
247
+ action={{ label: 'Learn more', href: 'https://wise.com', target: '_blank' }}
248
+ >
249
+ This is our partner bank in Singapore.
250
+ </ListItem.AdditionalInfo>
251
+ }
252
+ />
253
+ <ListItem
254
+ as="div"
255
+ title="Bank name and address"
256
+ subtitle="Capital Ltd, 2 Canal Street, London, E14 111"
257
+ additionalInfo={
258
+ <ListItem.AdditionalInfo
259
+ action={{ label: 'Learn more', href: 'https://wise.com', target: '_blank' }}
260
+ />
261
+ }
262
+ />
263
+ {/* Basic */}
264
+ {/* with additional info */}
265
+ {/* with prompt */}
266
+ {/* Disabled */}
267
+ {/* Spotlight */}
268
+ {/* Active */}
269
+ </div>
270
+ ),
271
+ };
272
+
273
+ // add intaces with dark mode
@@ -0,0 +1,183 @@
1
+ import { createContext, ReactNode, useId, useMemo, useState } from 'react';
2
+ import { Typography } from '../common';
3
+ import Body from '../body';
4
+ import { AdditionalInfo } from './ListItemAdditionalInfo';
5
+ import { IconButton } from './ListItemIconButton';
6
+ import { Checkbox } from './ListItemCheckbox';
7
+ import { Navigation } from './ListItemNavigation';
8
+ import { clsx } from 'clsx';
9
+ import { Button } from './ListItemButton';
10
+ import { Switch } from './ListItemSwitch';
11
+ import { AvatarLayout, AvatarView, Image } from './ListItemMedia';
12
+ import Prompt from './prompt/Prompt';
13
+
14
+ export type ListItemTypes =
15
+ | 'non-interactive'
16
+ | 'navigation'
17
+ | 'radio'
18
+ | 'checkbox'
19
+ | 'switch'
20
+ | 'button'
21
+ | 'icon-button';
22
+
23
+ export type Props = {
24
+ as?: 'li' | 'div' | 'span';
25
+ inverted?: boolean;
26
+ disabled?: boolean;
27
+ spotlight?: 'active' | 'inactive';
28
+ title: ReactNode;
29
+ subtitle?: ReactNode;
30
+ additionalInfo?: ReactNode;
31
+ valueTitle?: ReactNode;
32
+ valueSubtitle?: ReactNode;
33
+ media?: ReactNode;
34
+ control?: ReactNode;
35
+ prompt?: ReactNode;
36
+ };
37
+
38
+ export type ListItemContextData = {
39
+ setControlType: (type: ListItemTypes) => void;
40
+ ids: {
41
+ label: string;
42
+ additionalInfo: string;
43
+ value: string;
44
+ control: string;
45
+ prompt: string;
46
+ };
47
+ props: Pick<Props, 'as' | 'disabled' | 'inverted'>;
48
+ };
49
+
50
+ // @ts-expect-error for now let's mock it with `null` value
51
+ // but actually by default we should specify `setControlType('none')`
52
+ export const ListItemContext = createContext<ListItemContextData>(null);
53
+
54
+ export const ListItem = ({
55
+ as: View = 'li',
56
+ title,
57
+ subtitle,
58
+ additionalInfo,
59
+ prompt,
60
+ inverted,
61
+ media,
62
+ spotlight = undefined,
63
+ valueTitle,
64
+ valueSubtitle,
65
+ control = null,
66
+ disabled,
67
+ }: Props) => {
68
+ /*
69
+ const returnType = (): ReactNode => {
70
+ switch (type) {
71
+ case 'Navigation':
72
+ return <Chevron orientation={Position.RIGHT} disabled />;
73
+ case 'Radio':
74
+ return <RadioButton name="Hello" checked />;
75
+ case 'Checkbox':
76
+ return <CheckboxButton name="Hello" checked />;
77
+ case 'Switch':
78
+ return <Switch onClick={() => console.log('clicked')} />;
79
+ case 'Button':
80
+ return <Button v2>Hello</Button>;
81
+ case 'IconButton':
82
+ return (
83
+ <IconButton size={40} priority="minimal">
84
+ <InfoCircle />
85
+ </IconButton>
86
+ );
87
+ }
88
+ };
89
+ */
90
+ const idPrefix = useId();
91
+
92
+ const [controlType, setControlType] = useState<ListItemTypes>('non-interactive');
93
+ const ids = {
94
+ label: `${idPrefix}_label`,
95
+ value: `${idPrefix}_value`,
96
+ control: `${idPrefix}_control`,
97
+ prompt: `${idPrefix}_prompt`,
98
+ additionalInfo: `${idPrefix}_additional-info`,
99
+ };
100
+
101
+ const listItemContext = useMemo(
102
+ () => ({ setControlType, ids, props: { as: View, disabled, inverted } }),
103
+ [],
104
+ );
105
+
106
+ return (
107
+ <ListItemContext.Provider value={listItemContext}>
108
+ <View
109
+ className={clsx(
110
+ 'wds-list-item',
111
+ { 'wds-list-item-interactive': controlType !== 'non-interactive' },
112
+ `wds-list-item-${controlType}`,
113
+ 'd-flex flex-row',
114
+ { 'align-items-center': !subtitle },
115
+ {
116
+ [`wds-list-item-spotlight-${spotlight}`]: !!spotlight,
117
+ },
118
+ )}
119
+ aria-describedby={[ids.additionalInfo].join(' ')}
120
+ >
121
+ {media && <div className="wds-list-item-media">{media}</div>}
122
+
123
+ {/* Title + Subtitle + Values + Additional Info - Group */}
124
+ <div className="wds-list-item-body">
125
+ {/* Title + Subtitle + Values - Group */}
126
+ <div className="d-flex justify-content-between">
127
+ <span>
128
+ {/* @ts-expect-error div can have role and aria-lavel props */}
129
+ <Body
130
+ type={Typography.BODY_LARGE_BOLD}
131
+ className="wds-list-item-title"
132
+ // for a11y this needs to be a header but for SEO it shouldn't be `h*` tag
133
+ // so we enable header semantics via `role` and `aria-level` attrs
134
+ role="heading"
135
+ aria-level="4"
136
+ >
137
+ {title}
138
+ </Body>
139
+ <Body className="wds-list-item-subtitle">{subtitle}</Body>
140
+ </span>
141
+ {(valueTitle || valueSubtitle) && (
142
+ <span
143
+ id={ids.value}
144
+ className={clsx('wds-list-item-value', 'd-flex align-items-center', {
145
+ 'flex-column': valueTitle !== undefined && valueSubtitle !== undefined,
146
+ })}
147
+ >
148
+ {valueTitle && (
149
+ <Body type={Typography.BODY_LARGE_BOLD} className="wds-list-item-title-value">
150
+ {valueTitle}
151
+ </Body>
152
+ )}
153
+ {valueSubtitle && (
154
+ <Body className="wds-list-item-subtitle-value">{valueSubtitle}</Body>
155
+ )}
156
+ </span>
157
+ )}
158
+ </div>
159
+
160
+ {/* Additional Info and Prompt here */}
161
+ {Boolean(subtitle) && additionalInfo}
162
+ </div>
163
+ {control === null ? null : <Body className="wds-list-item-control">{control}</Body>}
164
+ {prompt}
165
+ </View>
166
+ </ListItemContext.Provider>
167
+ );
168
+ };
169
+
170
+ /* eslint-disable functional/immutable-data */
171
+ ListItem.Image = Image;
172
+ ListItem.AvatarView = AvatarView;
173
+ ListItem.AvatarLayout = AvatarLayout;
174
+ ListItem.AdditionalInfo = AdditionalInfo;
175
+ ListItem.Checkbox = Checkbox;
176
+ ListItem.IconButton = IconButton;
177
+ ListItem.Navigation = Navigation;
178
+ ListItem.Button = Button;
179
+ ListItem.Switch = Switch;
180
+ ListItem.Prompt = Prompt;
181
+ /* eslint-enable functional/immutable-data */
182
+
183
+ export default ListItem;
@@ -0,0 +1,31 @@
1
+ import { PropsWithChildren, useContext } from 'react';
2
+ import { ListItemContext, ListItemContextData } from './ListItem';
3
+ import Body from '../body';
4
+ import Link, { LinkProps } from '../link';
5
+ import { Typography } from '../common';
6
+
7
+ export type ListItemAdditionalInfoProps = PropsWithChildren<{
8
+ action?: Pick<LinkProps, 'href' | 'onClick' | 'target'> & { label?: string };
9
+ }>;
10
+
11
+ export const AdditionalInfo = function ({ children, action }: ListItemAdditionalInfoProps) {
12
+ const { ids } = useContext<ListItemContextData>(ListItemContext);
13
+
14
+ return (
15
+ <Body
16
+ type={Typography.BODY_DEFAULT}
17
+ id={ids.additionalInfo}
18
+ className="wds-list-item-additional-info"
19
+ >
20
+ {children}
21
+ {action ? (
22
+ <>
23
+ {' '}
24
+ <Link href={action.href} target={action.target} onClick={action.onClick}>
25
+ {action.label}
26
+ </Link>
27
+ </>
28
+ ) : null}
29
+ </Body>
30
+ );
31
+ };