@transferwise/components 0.0.0-experimental-809f516 → 0.0.0-experimental-fd6654d

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 (50) hide show
  1. package/build/i18n/cs.json +9 -9
  2. package/build/i18n/cs.json.js +9 -9
  3. package/build/i18n/cs.json.mjs +9 -9
  4. package/build/index.js +1 -0
  5. package/build/index.js.map +1 -1
  6. package/build/index.mjs +1 -1
  7. package/build/main.css +185 -0
  8. package/build/styles/item/Item.css +185 -0
  9. package/build/styles/main.css +185 -0
  10. package/build/test-utils/assets/apple-pay-logo.svg +84 -0
  11. package/build/types/index.d.ts +2 -0
  12. package/build/types/index.d.ts.map +1 -1
  13. package/build/types/item/Item.d.ts +41 -0
  14. package/build/types/item/Item.d.ts.map +1 -0
  15. package/build/types/item/ItemAdditionalInfo.d.ts +9 -0
  16. package/build/types/item/ItemAdditionalInfo.d.ts.map +1 -0
  17. package/build/types/item/ItemCheckbox.d.ts +4 -0
  18. package/build/types/item/ItemCheckbox.d.ts.map +1 -0
  19. package/build/types/item/ItemIconButton.d.ts +6 -0
  20. package/build/types/item/ItemIconButton.d.ts.map +1 -0
  21. package/build/types/item/ItemMedia.d.ts +19 -0
  22. package/build/types/item/ItemMedia.d.ts.map +1 -0
  23. package/build/types/item/ItemNavigation.d.ts +4 -0
  24. package/build/types/item/ItemNavigation.d.ts.map +1 -0
  25. package/build/types/item/index.d.ts +6 -0
  26. package/build/types/item/index.d.ts.map +1 -0
  27. package/build/types/item/prompt/Prompt.d.ts +12 -0
  28. package/build/types/item/prompt/Prompt.d.ts.map +1 -0
  29. package/build/types/test-utils/fake-data.d.ts +2 -0
  30. package/build/types/test-utils/fake-data.d.ts.map +1 -1
  31. package/package.json +3 -3
  32. package/src/i18n/cs.json +9 -9
  33. package/src/index.ts +2 -0
  34. package/src/item/Item.css +185 -0
  35. package/src/item/Item.less +178 -0
  36. package/src/item/Item.story.tsx +124 -0
  37. package/src/item/Item.tsx +170 -0
  38. package/src/item/ItemAdditionalInfo.tsx +31 -0
  39. package/src/item/ItemCheckbox.tsx +16 -0
  40. package/src/item/ItemIconButton.tsx +17 -0
  41. package/src/item/ItemMedia.tsx +52 -0
  42. package/src/item/ItemNavigation.tsx +16 -0
  43. package/src/item/index.ts +6 -0
  44. package/src/item/prompt/Prompt.spec.tsx +77 -0
  45. package/src/item/prompt/Prompt.story.tsx +170 -0
  46. package/src/item/prompt/Prompt.tsx +44 -0
  47. package/src/main.css +185 -0
  48. package/src/main.less +1 -0
  49. package/src/test-utils/assets/apple-pay-logo.svg +84 -0
  50. package/src/test-utils/fake-data.ts +5 -0
@@ -0,0 +1,185 @@
1
+ .np-item {
2
+ padding: 16px;
3
+ padding: var(--size-16);
4
+ border-radius: 24px;
5
+ border-radius: var(--radius-large);
6
+ background-color: #ffffff;
7
+ background-color: var(--color-background-screen);
8
+ gap: 16px;
9
+ gap: var(--size-16);
10
+ }
11
+ .np-item-interactive {
12
+ cursor: pointer;
13
+ }
14
+ .np-item-interactive:hover {
15
+ background-color: var(--color-background-screen-hover);
16
+ }
17
+ .np-item-interactive:active {
18
+ background-color: var(--color-background-screen-active);
19
+ }
20
+ .np-item-media-image {
21
+ width: var(--item-media-image-size);
22
+ height: var(--item-media-image-size);
23
+ }
24
+ .np-item-title {
25
+ color: #37517e;
26
+ color: var(--color-content-primary);
27
+ }
28
+ .np-item-additional-info {
29
+ color: #768e9c;
30
+ color: var(--color-content-tertiary);
31
+ }
32
+ .np-item-value {
33
+ flex: 0 0 auto;
34
+ }
35
+ .np-item-control {
36
+ flex: 0 0 auto;
37
+ }
38
+ .np-item-spotlight-active {
39
+ background-color: rgba(134,167,189,0.10196);
40
+ background-color: var(--color-background-neutral);
41
+ }
42
+ .np-item-spotlight-active:hover {
43
+ background-color: var(--color-background-neutral-hover);
44
+ }
45
+ .np-item-spotlight-active:active {
46
+ background-color: var(--color-background-neutral-active);
47
+ }
48
+ .np-item-spotlight-inactive {
49
+ background-color: rgba(134, 167, 189, 0.025);
50
+ border: 1px dashed rgba(0,0,0,0.10196);
51
+ border: 1px dashed var(--color-border-neutral);
52
+ }
53
+ @supports (color: color-mix(in lch, red, blue)) {
54
+ .np-item-spotlight-inactive {
55
+ background-color: color-mix(in srgb, var(--color-background-neutral) 25%, transparent);
56
+ }
57
+ }
58
+ .np-item-spotlight-inactive:hover {
59
+ background-color: color-mix(in srgb, var(--color-background-neutral-hover) 25%, transparent);
60
+ }
61
+ .np-item-spotlight-inactive:active {
62
+ background-color: color-mix(in srgb, var(--color-background-neutral-active) 25%, transparent);
63
+ }
64
+ .np-item-prompt {
65
+ display: inline-flex;
66
+ padding-top: calc(8px / 2);
67
+ padding-top: calc(var(--padding-x-small) / 2);
68
+ padding-bottom: calc(8px / 2);
69
+ padding-bottom: calc(var(--padding-x-small) / 2);
70
+ padding-left: calc(8px - 1px);
71
+ padding-left: calc(var(--padding-x-small) - 1px);
72
+ padding-right: 8px;
73
+ padding-right: var(--padding-x-small);
74
+ border-radius: 10px;
75
+ border-radius: var(--radius-small);
76
+ word-break: break-word;
77
+ word-wrap: break-word;
78
+ }
79
+ .np-item-prompt .np-prompt-icon {
80
+ padding-right: calc(12px / 2);
81
+ padding-right: calc(var(--size-12) / 2);
82
+ padding-top: calc(4px - 1px);
83
+ padding-top: calc(var(--size-4) - 1px);
84
+ padding-bottom: calc(4px - 1px);
85
+ padding-bottom: calc(var(--size-4) - 1px);
86
+ }
87
+ .np-item-prompt .np-prompt-icon .tw-icon-tags,
88
+ .np-item-prompt .np-prompt-icon .tw-icon-confetti {
89
+ color: var(--color-sentiment-positive-primary);
90
+ }
91
+ .np-item-prompt a {
92
+ text-underline-offset: calc(4px / 2);
93
+ text-underline-offset: calc(var(--size-4) / 2);
94
+ }
95
+ .np-item-prompt.np-prompt-interactive {
96
+ -webkit-text-decoration: none;
97
+ text-decoration: none;
98
+ cursor: pointer;
99
+ border: none;
100
+ }
101
+ .np-item-prompt.negative {
102
+ background-color: var(--color-sentiment-negative-secondary);
103
+ color: var(--color-sentiment-negative-primary);
104
+ }
105
+ .np-item-prompt.negative a {
106
+ color: var(--color-sentiment-negative-primary);
107
+ }
108
+ .np-item-prompt.negative a:hover {
109
+ color: var(--color-sentiment-negative-primary-hover);
110
+ }
111
+ .np-item-prompt.negative a:active {
112
+ color: var(--color-sentiment-negative-primary-active);
113
+ }
114
+ .np-prompt-interactive.np-item-prompt.negative:hover {
115
+ background-color: color-mix(in srgb, var(--color-sentiment-negative-secondary) 95%, var(--color-sentiment-negative-primary));
116
+ }
117
+ .np-prompt-interactive.np-item-prompt.negative:active {
118
+ background-color: color-mix(in srgb, var(--color-sentiment-negative-secondary) 90%, var(--color-sentiment-negative-primary));
119
+ }
120
+ .np-item-prompt.positive,
121
+ .np-item-prompt.discount,
122
+ .np-item-prompt.savings {
123
+ background-color: var(--color-sentiment-positive-secondary);
124
+ color: var(--color-sentiment-positive-primary);
125
+ }
126
+ .np-item-prompt.positive a,
127
+ .np-item-prompt.discount a,
128
+ .np-item-prompt.savings a {
129
+ color: var(--color-sentiment-positive-primary);
130
+ }
131
+ .np-item-prompt.positive a:hover,
132
+ .np-item-prompt.discount a:hover,
133
+ .np-item-prompt.savings a:hover {
134
+ color: var(--color-sentiment-positive-primary-hover);
135
+ }
136
+ .np-item-prompt.positive a:active,
137
+ .np-item-prompt.discount a:active,
138
+ .np-item-prompt.savings a:active {
139
+ color: var(--color-sentiment-positive-primary-active);
140
+ }
141
+ .np-prompt-interactive.np-item-prompt.positive:hover,
142
+ .np-prompt-interactive.np-item-prompt.discount:hover,
143
+ .np-prompt-interactive.np-item-prompt.savings:hover {
144
+ background-color: color-mix(in srgb, var(--color-sentiment-positive-secondary) 95%, var(--color-sentiment-positive-primary));
145
+ }
146
+ .np-prompt-interactive.np-item-prompt.positive:active,
147
+ .np-prompt-interactive.np-item-prompt.discount:active,
148
+ .np-prompt-interactive.np-item-prompt.savings:active {
149
+ background-color: color-mix(in srgb, var(--color-sentiment-positive-secondary) 90%, var(--color-sentiment-positive-primary));
150
+ }
151
+ .np-item-prompt.neutral {
152
+ background-color: rgba(134,167,189,0.10196);
153
+ background-color: var(--color-background-neutral);
154
+ color: #37517e;
155
+ color: var(--color-content-primary);
156
+ }
157
+ .np-item-prompt.neutral a {
158
+ color: #37517e;
159
+ color: var(--color-content-primary);
160
+ }
161
+ .np-prompt-interactive.np-item-prompt.neutral:hover {
162
+ background-color: var(--color-background-neutral-hover);
163
+ }
164
+ .np-prompt-interactive.np-item-prompt.neutral:active {
165
+ background-color: var(--color-background-neutral-active);
166
+ }
167
+ .np-item-prompt.warning {
168
+ background-color: var(--color-sentiment-warning-secondary);
169
+ color: var(--color-sentiment-warning-content);
170
+ }
171
+ .np-item-prompt.warning a {
172
+ color: var(--color-sentiment-warning-content);
173
+ }
174
+ .np-item-prompt.warning a:hover {
175
+ color: var(--color-sentiment-warning-content-hover);
176
+ }
177
+ .np-item-prompt.warning a:active {
178
+ color: var(--color-sentiment-warning-content-active);
179
+ }
180
+ .np-prompt-interactive.np-item-prompt.warning:hover {
181
+ background-color: color-mix(in srgb, var(--color-sentiment-warning-secondary) 90%, var(--color-sentiment-warning-primary));
182
+ }
183
+ .np-prompt-interactive.np-item-prompt.warning:active {
184
+ background-color: color-mix(in srgb, var(--color-sentiment-warning-secondary) 80%, var(--color-sentiment-warning-primary));
185
+ }
@@ -0,0 +1,178 @@
1
+ .np-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
+ &-title {
26
+ color: var(--color-content-primary);
27
+ }
28
+
29
+ &-additional-info {
30
+ color: var(--color-content-tertiary);
31
+ }
32
+
33
+ &-value {
34
+ flex: 0 0 auto;
35
+ }
36
+
37
+ &-control {
38
+ flex: 0 0 auto;
39
+ }
40
+
41
+ &-spotlight {
42
+ &-active {
43
+ background-color: var(--color-background-neutral);
44
+
45
+ &:hover {
46
+ background-color: var(--color-background-neutral-hover);
47
+ }
48
+ &:active {
49
+ background-color: var(--color-background-neutral-active);
50
+ }
51
+ }
52
+
53
+ &-inactive {
54
+ background-color: color-mix(in srgb, var(--color-background-neutral) 25%, transparent);
55
+ border: 1px dashed var(--color-border-neutral);
56
+
57
+ &:hover {
58
+ background-color: color-mix(in srgb, var(--color-background-neutral-hover) 25%, transparent);
59
+ }
60
+ &:active {
61
+ background-color: color-mix(in srgb, var(--color-background-neutral-active) 25%, transparent);
62
+ }
63
+ }
64
+ }
65
+
66
+ &-prompt {
67
+ display: inline-flex;
68
+ padding-top: calc(var(--padding-x-small) / 2);
69
+ padding-bottom: calc(var(--padding-x-small) / 2);
70
+ padding-left: calc(var(--padding-x-small) - 1px);
71
+ padding-right: var(--padding-x-small);
72
+ border-radius: var(--radius-small);
73
+ word-break: break-word;
74
+ overflow-wrap: break-word;
75
+
76
+ .np-prompt-icon {
77
+ padding-right: calc(var(--size-12) / 2);
78
+ padding-top: calc(var(--size-4) - 1px);
79
+ padding-bottom: calc(var(--size-4) - 1px);
80
+
81
+ .tw-icon-tags,
82
+ .tw-icon-confetti {
83
+ color: var(--color-sentiment-positive-primary);
84
+ }
85
+ }
86
+
87
+ a {
88
+ text-underline-offset: calc(var(--size-4) / 2);
89
+ }
90
+
91
+ &.np-prompt-interactive {
92
+ text-decoration: none;
93
+ cursor: pointer;
94
+ border: none;
95
+ }
96
+
97
+ &.negative {
98
+ background-color: var(--color-sentiment-negative-secondary);
99
+ color: var(--color-sentiment-negative-primary);
100
+ a {
101
+ color: var(--color-sentiment-negative-primary);
102
+ &:hover {
103
+ color: var(--color-sentiment-negative-primary-hover);
104
+ }
105
+ &:active {
106
+ color: var(--color-sentiment-negative-primary-active);
107
+ }
108
+ }
109
+ .np-prompt-interactive& {
110
+ &:hover {
111
+ background-color: color-mix(in srgb, var(--color-sentiment-negative-secondary) 95%, var(--color-sentiment-negative-primary));
112
+ }
113
+ &:active {
114
+ background-color: color-mix(in srgb, var(--color-sentiment-negative-secondary) 90%, var(--color-sentiment-negative-primary));
115
+ }
116
+ }
117
+ }
118
+ &.positive,
119
+ &.discount,
120
+ &.savings {
121
+ background-color: var(--color-sentiment-positive-secondary);
122
+ color: var(--color-sentiment-positive-primary);
123
+ a {
124
+ color: var(--color-sentiment-positive-primary);
125
+ &:hover {
126
+ color: var(--color-sentiment-positive-primary-hover);
127
+ }
128
+ &:active {
129
+ color: var(--color-sentiment-positive-primary-active);
130
+ }
131
+ }
132
+ .np-prompt-interactive& {
133
+ &:hover {
134
+ background-color: color-mix(in srgb, var(--color-sentiment-positive-secondary) 95%, var(--color-sentiment-positive-primary));
135
+ }
136
+ &:active {
137
+ background-color: color-mix(in srgb, var(--color-sentiment-positive-secondary) 90%, var(--color-sentiment-positive-primary));
138
+ }
139
+ }
140
+ }
141
+ &.neutral {
142
+ background-color: var(--color-background-neutral);
143
+ color: var(--color-content-primary);
144
+ a {
145
+ color: var(--color-content-primary);
146
+ }
147
+ .np-prompt-interactive& {
148
+ &:hover {
149
+ background-color: var(--color-background-neutral-hover);
150
+ }
151
+ &:active {
152
+ background-color: var(--color-background-neutral-active);
153
+ }
154
+ }
155
+ }
156
+ &.warning {
157
+ background-color: var(--color-sentiment-warning-secondary);
158
+ color: var(--color-sentiment-warning-content);
159
+ a {
160
+ color: var(--color-sentiment-warning-content);
161
+ &:hover {
162
+ color: var(--color-sentiment-warning-content-hover);
163
+ }
164
+ &:active {
165
+ color: var(--color-sentiment-warning-content-active);
166
+ }
167
+ }
168
+ .np-prompt-interactive& {
169
+ &:hover {
170
+ background-color: color-mix(in srgb, var(--color-sentiment-warning-secondary) 90%, var(--color-sentiment-warning-primary));
171
+ }
172
+ &:active {
173
+ background-color: color-mix(in srgb, var(--color-sentiment-warning-secondary) 80%, var(--color-sentiment-warning-primary));
174
+ }
175
+ }
176
+ }
177
+ }
178
+ }
@@ -0,0 +1,124 @@
1
+ import Item, { Props as ItemProps } from './Item';
2
+ import { Meta, StoryObj } from '@storybook/react';
3
+ import { lorem10, lorem20, lorem40, lorem5 } from '../test-utils';
4
+ import { Flag } from '@wise/art';
5
+
6
+ export default {
7
+ component: Item,
8
+ title: 'Content/Item',
9
+ } satisfies Meta<ItemProps>;
10
+
11
+ type Story = StoryObj<ItemProps>;
12
+
13
+ // TODO: delete this story later when we have more peace of the List Item puzzle
14
+ export const TempPlayground: Story = {
15
+ render: () => (
16
+ <div>
17
+ <Item
18
+ media={
19
+ <Item.AvatarView badge={{ type: 'action' }}>
20
+ <Flag code="BBD" />
21
+ </Item.AvatarView>
22
+ }
23
+ title="Test title"
24
+ subtitle="Test subtitle"
25
+ additionalInfo={<Item.AdditionalInfo>{lorem10}</Item.AdditionalInfo>}
26
+ />
27
+ <Item
28
+ media={
29
+ <Item.AvatarLayout
30
+ avatars={[{ asset: <Flag code="BBD" /> }, { asset: <Flag code="MXN" /> }]}
31
+ />
32
+ }
33
+ title="Test title"
34
+ subtitle={lorem10}
35
+ additionalInfo={<Item.AdditionalInfo>{lorem20}</Item.AdditionalInfo>}
36
+ />
37
+ <Item
38
+ media={
39
+ <Item.AvatarLayout
40
+ size={72}
41
+ orientation="diagonal"
42
+ avatars={[{ asset: <Flag code="BBD" /> }, { asset: <Flag code="MXN" /> }]}
43
+ />
44
+ }
45
+ title="Test title"
46
+ subtitle={lorem10}
47
+ valueTitle="100 GBP"
48
+ valueSubtitle="100 USD"
49
+ additionalInfo={<Item.AdditionalInfo>{lorem20}</Item.AdditionalInfo>}
50
+ />
51
+ <Item
52
+ media={<Item.AvatarView profileType="BUSINESS" notification />}
53
+ title="Test title"
54
+ subtitle="Test subtitle"
55
+ additionalInfo={
56
+ <Item.AdditionalInfo
57
+ action={{ label: 'Learn more', href: 'https://wise.com', target: '_blank' }}
58
+ >
59
+ {lorem10}
60
+ </Item.AdditionalInfo>
61
+ }
62
+ prompt={<Item.Prompt type="negative">You have done something wrong</Item.Prompt>}
63
+ />
64
+ <Item
65
+ media={<Item.AvatarView imgSrc="../avatar-square-dude.webp" selected />}
66
+ title="Test title"
67
+ additionalInfo={<Item.AdditionalInfo>{lorem10}</Item.AdditionalInfo>}
68
+ prompt={
69
+ <Item.Prompt
70
+ type="discount"
71
+ action={{
72
+ href: 'https://wise.com',
73
+ target: '_blank',
74
+ 'aria-label': 'clickable prompt',
75
+ }}
76
+ >
77
+ The whole prompt is secretly clickable
78
+ </Item.Prompt>
79
+ }
80
+ />
81
+
82
+ <Item
83
+ media={<Item.Image src="../apple-pay-logo.svg" />}
84
+ title="Accepting Apple Pay"
85
+ subtitle={lorem10}
86
+ />
87
+
88
+ <Item
89
+ media={<Item.Image src="../wise-card.svg" />}
90
+ title="Wise Business Card"
91
+ subtitle={lorem5}
92
+ />
93
+ </div>
94
+ ),
95
+ };
96
+
97
+ export const ItemRadio: Story = {
98
+ render: () => (
99
+ <div>
100
+ {/* Basic */}
101
+ {/* with additional info */}
102
+ {/* with prompt */}
103
+ {/* Disabled */}
104
+ {/* Spotlight */}
105
+ {/* Active */}
106
+ </div>
107
+ ),
108
+ };
109
+
110
+ export const ItemButton: Story = {
111
+ render: () => (
112
+ <div>
113
+ {/* Basic */}
114
+ {/* with additional info */}
115
+ {/* with prompt */}
116
+ {/* partially interactive */}
117
+ {/* Disabled */}
118
+ {/* Spotlight */}
119
+ {/* Active */}
120
+ </div>
121
+ ),
122
+ };
123
+
124
+ // add intaces with dark mode
@@ -0,0 +1,170 @@
1
+ import { createContext, ReactNode, useId, useMemo, useState } from 'react';
2
+ import { Typography } from '../common';
3
+ import Body from '../body';
4
+ import { AdditionalInfo } from './ItemAdditionalInfo';
5
+ import { IconButton } from './ItemIconButton';
6
+ import { Checkbox } from './ItemCheckbox';
7
+ import { Navigation } from './ItemNavigation';
8
+ import { clsx } from 'clsx';
9
+ import { AvatarLayout, AvatarView, Image } from './ItemMedia';
10
+ import Prompt from './prompt/Prompt';
11
+
12
+ export type ItemTypes =
13
+ | 'non-interactive'
14
+ | 'navigation'
15
+ | 'radio'
16
+ | 'checkbox'
17
+ | 'switch'
18
+ | 'button'
19
+ | 'icon-button';
20
+
21
+ export type Props = {
22
+ as?: 'li' | 'div' | 'span';
23
+ inverted?: boolean;
24
+ disabled?: boolean;
25
+ spotlight?: 'active' | 'inactive';
26
+ title: ReactNode;
27
+ subtitle?: ReactNode;
28
+ additionalInfo?: ReactNode;
29
+ valueTitle?: ReactNode;
30
+ valueSubtitle?: ReactNode;
31
+ media?: ReactNode;
32
+ control?: ReactNode;
33
+ prompt?: ReactNode;
34
+ };
35
+
36
+ export type ItemContextData = {
37
+ setControlType: (type: ItemTypes) => void;
38
+ ids: {
39
+ label: string;
40
+ additionalInfo: string;
41
+ value: string;
42
+ control: string;
43
+ prompt: string;
44
+ };
45
+ props: Pick<Props, 'as' | 'disabled' | 'inverted'>;
46
+ };
47
+
48
+ // @ts-expect-error for now let's mock it with `null` value
49
+ // but actually by default we should specify `setControlType('none')`
50
+ export const ItemContext = createContext<ItemContextData>(null);
51
+
52
+ export const Item = ({
53
+ as: View = 'li',
54
+ title,
55
+ subtitle,
56
+ additionalInfo,
57
+ prompt,
58
+ inverted,
59
+ media,
60
+ spotlight = undefined,
61
+ valueTitle,
62
+ valueSubtitle,
63
+ control = null,
64
+ disabled,
65
+ }: Props) => {
66
+ /*
67
+ const returnType = (): ReactNode => {
68
+ switch (type) {
69
+ case 'Navigation':
70
+ return <Chevron orientation={Position.RIGHT} disabled />;
71
+ case 'Radio':
72
+ return <RadioButton name="Hello" checked />;
73
+ case 'Checkbox':
74
+ return <CheckboxButton name="Hello" checked />;
75
+ case 'Switch':
76
+ return <Switch onClick={() => console.log('clicked')} />;
77
+ case 'Button':
78
+ return <Button v2>Hello</Button>;
79
+ case 'IconButton':
80
+ return (
81
+ <IconButton size={40} priority="minimal">
82
+ <InfoCircle />
83
+ </IconButton>
84
+ );
85
+ }
86
+ };
87
+ */
88
+ const idPrefix = useId();
89
+
90
+ const [controlType, setControlType] = useState<ItemTypes>('non-interactive');
91
+ const ids = {
92
+ label: `${idPrefix}_label`,
93
+ value: `${idPrefix}_value`,
94
+ control: `${idPrefix}_control`,
95
+ prompt: `${idPrefix}_prompt`,
96
+ additionalInfo: `${idPrefix}_additional-info`,
97
+ };
98
+
99
+ const itemCtx = useMemo(
100
+ () => ({ setControlType, ids, props: { as: View, disabled, inverted } }),
101
+ [],
102
+ );
103
+
104
+ return (
105
+ <ItemContext.Provider value={itemCtx}>
106
+ <View
107
+ className={clsx(
108
+ 'np-item',
109
+ { 'np-item-interactive': controlType !== 'non-interactive' },
110
+ `np-item-${controlType}`,
111
+ 'd-flex flex-row',
112
+ { 'align-items-center': !subtitle },
113
+ {
114
+ [`np-item-spotlight-${spotlight}`]: !!spotlight,
115
+ },
116
+ )}
117
+ aria-describedby={[ids.additionalInfo].join(' ')}
118
+ >
119
+ {media && <div className="np-item-media">{media}</div>}
120
+
121
+ {/* Title + Subtitle + Values + Additional Info - Group */}
122
+ <div>
123
+ {/* Title + Subtitle + Values - Group */}
124
+ <div className="d-flex justify-content-between">
125
+ <span>
126
+ {/* @ts-expect-error div can have role and aria-lavel props */}
127
+ <Body
128
+ type={Typography.BODY_LARGE_BOLD}
129
+ className="np-item-title"
130
+ // for a11y this needs to be a header but for SEO it shouldn't be `h*` tag
131
+ // so we enable header semantics via `role` and `aria-level` attrs
132
+ role="heading"
133
+ aria-level="4"
134
+ >
135
+ {title}
136
+ </Body>
137
+ <Body className="np-item-subtitle">{subtitle}</Body>
138
+ </span>
139
+ {(valueTitle || valueSubtitle) && (
140
+ <span id={ids.value} className="np-item-value">
141
+ <Body type={Typography.BODY_LARGE_BOLD} className="np-item-title-value">
142
+ {valueTitle}
143
+ </Body>
144
+ <Body className="np-item-subtitle-value">{valueSubtitle}</Body>
145
+ </span>
146
+ )}
147
+ </div>
148
+
149
+ {/* Additional Info and Prompt here */}
150
+ {Boolean(subtitle) && additionalInfo}
151
+ </div>
152
+ {control === null ? null : <Body className="np-item-control">{control}</Body>}
153
+ {prompt}
154
+ </View>
155
+ </ItemContext.Provider>
156
+ );
157
+ };
158
+
159
+ /* eslint-disable functional/immutable-data */
160
+ Item.Image = Image;
161
+ Item.AvatarView = AvatarView;
162
+ Item.AvatarLayout = AvatarLayout;
163
+ Item.AdditionalInfo = AdditionalInfo;
164
+ Item.Checkbox = Checkbox;
165
+ Item.IconButton = IconButton;
166
+ Item.Navigation = Navigation;
167
+ Item.Prompt = Prompt;
168
+ /* eslint-enable functional/immutable-data */
169
+
170
+ export default Item;
@@ -0,0 +1,31 @@
1
+ import { PropsWithChildren, useContext } from 'react';
2
+ import { ItemContext, ItemContextData } from './Item';
3
+ import Body from '../body';
4
+ import Link, { LinkProps } from '../link';
5
+ import { Typography } from '../common';
6
+
7
+ export type ItemAdditionalInfoProps = PropsWithChildren<{
8
+ action?: Pick<LinkProps, 'href' | 'onClick' | 'target'> & { label?: string };
9
+ }>;
10
+
11
+ export const AdditionalInfo = function ({ children, action }: ItemAdditionalInfoProps) {
12
+ const { ids } = useContext<ItemContextData>(ItemContext);
13
+
14
+ return (
15
+ <Body
16
+ type={Typography.BODY_DEFAULT}
17
+ id={ids.additionalInfo}
18
+ className="np-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
+ };
@@ -0,0 +1,16 @@
1
+ import { useContext, useEffect } from 'react';
2
+ import CheckboxButton from '../checkboxButton';
3
+ import { CheckboxButtonProps } from '../checkboxButton/CheckboxButton';
4
+ import { ItemContext, ItemContextData } from './Item';
5
+
6
+ export type ItemCheckboxProps = Pick<CheckboxButtonProps, 'checked' | 'indeterminate' | 'onChange'>;
7
+
8
+ export const Checkbox = function (props: ItemCheckboxProps) {
9
+ const { setControlType, props: baseItemProps } = useContext<ItemContextData>(ItemContext);
10
+
11
+ useEffect(() => {
12
+ setControlType('checkbox');
13
+ }, []);
14
+
15
+ return <CheckboxButton disabled={baseItemProps.disabled} {...props} />;
16
+ };