@altinn/altinn-components 0.1.0 → 0.2.0

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 (162) hide show
  1. package/.storybook/StoryDecorator.tsx +27 -0
  2. package/.storybook/ThemeProvider.tsx +16 -0
  3. package/.storybook/main.ts +4 -5
  4. package/.storybook/preview.tsx +31 -29
  5. package/.storybook/storyDecorator.module.css +20 -0
  6. package/.storybook/theme.module.css +3 -0
  7. package/CHANGELOG.md +14 -0
  8. package/CONTRIBUTING.MD +59 -0
  9. package/README.md +33 -1
  10. package/lib/components/Attachment/AttachmentLink.stories.ts +21 -0
  11. package/lib/components/Attachment/AttachmentLink.tsx +20 -0
  12. package/lib/components/Attachment/AttachmentList.stories.ts +39 -0
  13. package/lib/components/Attachment/AttachmentList.tsx +26 -0
  14. package/lib/components/Attachment/attachmentLink.module.css +20 -0
  15. package/lib/components/Attachment/attachmentList.module.css +12 -0
  16. package/lib/components/Attachment/index.ts +2 -0
  17. package/lib/components/Avatar/avatar.module.css +2 -0
  18. package/lib/components/Badge/Badge.stories.ts +32 -0
  19. package/lib/components/Badge/Badge.tsx +13 -10
  20. package/lib/components/Badge/badge.module.css +18 -27
  21. package/lib/components/Button/Button.stories.ts +6 -0
  22. package/lib/components/Button/Button.tsx +19 -1
  23. package/lib/components/Button/ButtonBase.tsx +1 -1
  24. package/lib/components/Button/button.module.css +0 -19
  25. package/lib/components/Button/buttonBase.module.css +30 -12
  26. package/lib/components/Button/comboButton.module.css +4 -2
  27. package/lib/components/ContextMenu/ContextMenu.tsx +28 -0
  28. package/lib/components/ContextMenu/contextMenu.module.css +35 -0
  29. package/lib/components/Dialog/Dialog.stories.ts +320 -0
  30. package/lib/components/Dialog/Dialog.tsx +101 -0
  31. package/lib/components/Dialog/DialogAction.stories.ts +54 -0
  32. package/lib/components/Dialog/DialogAction.tsx +79 -0
  33. package/lib/components/Dialog/DialogActivityLog.tsx +18 -0
  34. package/lib/components/Dialog/DialogArticleBase.tsx +10 -0
  35. package/lib/components/Dialog/DialogAttachments.stories.ts +40 -0
  36. package/lib/components/Dialog/DialogAttachments.tsx +25 -0
  37. package/lib/components/Dialog/DialogBase.tsx +10 -0
  38. package/lib/components/Dialog/DialogBodyBase.tsx +17 -0
  39. package/lib/components/Dialog/DialogBorder.tsx +19 -0
  40. package/lib/components/Dialog/DialogContent.stories.ts +26 -0
  41. package/lib/components/Dialog/DialogContent.tsx +24 -0
  42. package/lib/components/Dialog/DialogFooter.tsx +14 -0
  43. package/lib/components/Dialog/DialogHeader.stories.ts +26 -0
  44. package/lib/components/Dialog/DialogHeader.tsx +23 -0
  45. package/lib/components/Dialog/DialogHeaderBase.tsx +10 -0
  46. package/lib/components/Dialog/DialogHeadings.stories.ts +35 -0
  47. package/lib/components/Dialog/DialogHeadings.tsx +77 -0
  48. package/lib/components/Dialog/DialogHistory.stories.ts +67 -0
  49. package/lib/components/Dialog/DialogHistory.tsx +19 -0
  50. package/lib/components/Dialog/DialogList.stories.ts +61 -0
  51. package/lib/components/Dialog/DialogList.tsx +20 -0
  52. package/lib/components/Dialog/DialogListItem.stories.tsx +238 -0
  53. package/lib/components/Dialog/DialogListItem.tsx +114 -0
  54. package/lib/components/Dialog/DialogListItemBase.tsx +50 -0
  55. package/lib/components/Dialog/DialogMetadata.stories.ts +77 -0
  56. package/lib/components/Dialog/DialogMetadata.tsx +56 -0
  57. package/lib/components/Dialog/DialogNav.stories.ts +90 -0
  58. package/lib/components/Dialog/DialogNav.tsx +60 -0
  59. package/lib/components/Dialog/DialogSectionBase.tsx +20 -0
  60. package/lib/components/Dialog/DialogSeenBy.stories.tsx +58 -0
  61. package/lib/components/Dialog/DialogSeenBy.tsx +36 -0
  62. package/lib/components/Dialog/DialogSelect.tsx +23 -0
  63. package/lib/components/Dialog/DialogStatus.stories.ts +57 -0
  64. package/lib/components/Dialog/DialogStatus.tsx +61 -0
  65. package/lib/components/Dialog/DialogTitle.stories.ts +33 -0
  66. package/lib/components/Dialog/DialogTitle.tsx +31 -0
  67. package/lib/components/Dialog/DialogTouchedBy.stories.tsx +27 -0
  68. package/lib/components/Dialog/DialogTouchedBy.tsx +19 -0
  69. package/lib/components/Dialog/dialog.module.css +21 -0
  70. package/lib/components/Dialog/dialogAction.module.css +26 -0
  71. package/lib/components/Dialog/dialogArticleBase.module.css +5 -0
  72. package/lib/components/Dialog/dialogBodyBase.module.css +13 -0
  73. package/lib/components/Dialog/dialogBorder.module.css +42 -0
  74. package/lib/components/Dialog/dialogHeaderBase.module.css +6 -0
  75. package/lib/components/Dialog/dialogHeadings.module.css +24 -0
  76. package/lib/components/Dialog/dialogHistory.module.css +12 -0
  77. package/lib/components/Dialog/dialogListItem.module.css +81 -0
  78. package/lib/components/Dialog/dialogListItemBase.module.css +28 -0
  79. package/lib/components/Dialog/dialogSectionBase.module.css +11 -0
  80. package/lib/components/Dialog/dialogSelect.module.css +34 -0
  81. package/lib/components/Dialog/dialogTitle.module.css +47 -0
  82. package/lib/components/Dialog/index.ts +2 -0
  83. package/lib/components/Header/GlobalMenu.tsx +1 -1
  84. package/lib/components/Header/Header.tsx +3 -3
  85. package/lib/components/Header/HeaderSearch.tsx +1 -1
  86. package/lib/components/History/HistoryBorder.tsx +17 -0
  87. package/lib/components/History/HistoryItem.stories.ts +47 -0
  88. package/lib/components/History/HistoryItem.tsx +64 -0
  89. package/lib/components/History/HistoryList.stories.ts +58 -0
  90. package/lib/components/History/HistoryList.tsx +26 -0
  91. package/lib/components/History/historyBorder.module.css +8 -0
  92. package/lib/components/History/historyItem.module.css +19 -0
  93. package/lib/components/History/historyList.module.css +12 -0
  94. package/lib/components/History/index.ts +2 -0
  95. package/lib/components/Icon/CheckboxCheckedIcon.tsx +28 -0
  96. package/lib/components/Icon/CheckboxIcon.stories.ts +7 -0
  97. package/lib/components/Icon/CheckboxIcon.tsx +6 -18
  98. package/lib/components/Icon/CheckboxUncheckedIcon.tsx +38 -0
  99. package/lib/components/Icon/ProgressIcon.stories.ts +43 -0
  100. package/lib/components/Icon/ProgressIcon.tsx +44 -0
  101. package/lib/components/Icon/RadioCheckedIcon.tsx +29 -0
  102. package/lib/components/Icon/RadioIcon.stories.ts +7 -0
  103. package/lib/components/Icon/RadioIcon.tsx +7 -19
  104. package/lib/components/Icon/RadioUncheckedIcon.tsx +30 -0
  105. package/lib/components/Icon/checkboxIcon.module.css +2 -0
  106. package/lib/components/Icon/index.ts +1 -0
  107. package/lib/components/Icon/progressIcon.module.css +29 -0
  108. package/lib/components/Layout/Layout.stories.ts +0 -3
  109. package/lib/components/List/List.tsx +20 -0
  110. package/lib/components/List/ListBase.tsx +19 -0
  111. package/lib/components/List/ListItem.stories.tsx +208 -0
  112. package/lib/components/List/ListItem.tsx +70 -0
  113. package/lib/components/List/ListItemBase.tsx +62 -0
  114. package/lib/components/List/ListItemLabel.tsx +29 -0
  115. package/lib/components/List/ListItemMedia.tsx +59 -0
  116. package/lib/components/List/index.ts +4 -0
  117. package/lib/components/List/listBase.module.css +16 -0
  118. package/lib/components/List/listItemBase.module.css +86 -0
  119. package/lib/components/List/listItemLabel.module.css +55 -0
  120. package/lib/components/List/listItemMedia.module.css +41 -0
  121. package/lib/components/Menu/Menu.stories.ts +46 -27
  122. package/lib/components/Menu/Menu.tsx +3 -3
  123. package/lib/components/Menu/MenuItem.stories.ts +12 -5
  124. package/lib/components/Menu/MenuItem.tsx +4 -3
  125. package/lib/components/Menu/MenuItemBase.tsx +7 -7
  126. package/lib/components/Menu/MenuItemLabel.tsx +4 -4
  127. package/lib/components/Menu/MenuItemMedia.tsx +2 -2
  128. package/lib/components/Menu/MenuOption.stories.ts +4 -2
  129. package/lib/components/Menu/MenuOption.tsx +4 -4
  130. package/lib/components/Menu/menuItemBase.module.css +72 -0
  131. package/lib/components/Menu/menuItemLabel.module.css +22 -0
  132. package/lib/components/Menu/menuItemMedia.module.css +36 -0
  133. package/lib/components/Menu/menuOption.module.css +6 -8
  134. package/lib/components/Meta/MetaBase.tsx +15 -0
  135. package/lib/components/Meta/MetaItem.stories.ts +25 -0
  136. package/lib/components/Meta/MetaItem.tsx +31 -0
  137. package/lib/components/Meta/MetaItemBase.tsx +46 -0
  138. package/lib/components/Meta/MetaItemLabel.tsx +20 -0
  139. package/lib/components/Meta/MetaItemMedia.tsx +22 -0
  140. package/lib/components/Meta/MetaList.stories.ts +29 -0
  141. package/lib/components/Meta/MetaList.tsx +43 -0
  142. package/lib/components/Meta/MetaProgress.stories.ts +29 -0
  143. package/lib/components/Meta/MetaProgress.tsx +26 -0
  144. package/lib/components/Meta/MetaTimestamp.stories.ts +33 -0
  145. package/lib/components/Meta/MetaTimestamp.tsx +29 -0
  146. package/lib/components/Meta/index.ts +6 -0
  147. package/lib/components/Meta/meta.module.css +6 -0
  148. package/lib/components/Meta/metaItem.module.css +107 -0
  149. package/lib/components/Meta/metaList.module.css +15 -0
  150. package/lib/components/Toolbar/ToolbarAdd.tsx +1 -1
  151. package/lib/components/Typography/Typography.tsx +21 -0
  152. package/lib/components/Typography/index.ts +1 -0
  153. package/lib/components/Typography/typography.module.css +56 -0
  154. package/lib/components/index.ts +9 -0
  155. package/lib/css/global.css +2 -0
  156. package/lib/css/shadows.css +7 -0
  157. package/lib/css/theme-article.css +15 -0
  158. package/lib/css/theme.css +5 -7
  159. package/package.json +4 -2
  160. package/renovate.json +1 -3
  161. package/.storybook/preview.css +0 -18
  162. /package/lib/components/Toolbar/{index.js → index.ts} +0 -0
@@ -1,3 +1,4 @@
1
+ /*
1
2
  .checkbox {
2
3
  font-size: 1rem;
3
4
  border: 2px solid;
@@ -19,3 +20,4 @@
19
20
  .checkbox > svg {
20
21
  stroke: currentColor;
21
22
  }
23
+ */
@@ -2,4 +2,5 @@ export * from './Icon';
2
2
  export * from './SvgIcon';
3
3
  export * from './CheckboxIcon';
4
4
  export * from './RadioIcon';
5
+ export * from './ProgressIcon';
5
6
  export * from './iconsMap';
@@ -0,0 +1,29 @@
1
+ .progress {
2
+ --size: 16px;
3
+ width: var(--size);
4
+ height: var(--size);
5
+ aspect-ratio: 1;
6
+ border-radius: 50%;
7
+ background: conic-gradient(var(--theme-border-strong) var(--progress, 0), var(--theme-surface-default) 0);
8
+ display: grid;
9
+ place-content: center;
10
+ transform: scaleX(-1);
11
+ }
12
+
13
+ .progress:after {
14
+ width: calc(var(--size) * 0.5);
15
+ height: calc(var(--size) * 0.5);
16
+ aspect-ratio: 1;
17
+ content: attr(data-value);
18
+ display: grid;
19
+ background: #fff;
20
+ border-radius: 50%;
21
+ font-size: 0;
22
+ place-content: center;
23
+ }
24
+
25
+ .complete {
26
+ width: var(--size);
27
+ height: var(--size);
28
+ color: var(--theme-border-strong);
29
+ }
@@ -11,7 +11,6 @@ const menu: MenuProps = {
11
11
  size: 'lg',
12
12
  icon: 'inbox',
13
13
  title: 'Innboks',
14
- badge: '4',
15
14
  },
16
15
  {
17
16
  id: '2',
@@ -25,14 +24,12 @@ const menu: MenuProps = {
25
24
  icon: 'file-checkmark',
26
25
  selected: true,
27
26
  title: 'Sendt',
28
- badge: '2',
29
27
  },
30
28
  {
31
29
  id: '4',
32
30
  group: 3,
33
31
  icon: 'bookmark',
34
32
  title: 'Lagrede søk',
35
- badge: '11',
36
33
  },
37
34
  {
38
35
  id: '5',
@@ -0,0 +1,20 @@
1
+ import type { LayoutTheme } from '../Layout';
2
+ import { ListBase } from '../List';
3
+ import { ListItem, type ListItemProps } from './ListItem';
4
+ import type { ListItemSize } from './ListItemBase';
5
+
6
+ export interface ListProps {
7
+ size?: ListItemSize;
8
+ theme?: LayoutTheme;
9
+ items?: ListItemProps[];
10
+ }
11
+
12
+ export const List = ({ theme, size = 'md', items }: ListProps) => {
13
+ return (
14
+ <ListBase theme={theme} size={size}>
15
+ {items?.map((item, index) => {
16
+ return <ListItem {...item} size={size} key={'item' + index} />;
17
+ })}
18
+ </ListBase>
19
+ );
20
+ };
@@ -0,0 +1,19 @@
1
+ import type { ReactNode } from 'react';
2
+ import styles from './listBase.module.css';
3
+
4
+ import type { LayoutTheme } from '../Layout';
5
+ import type { ListItemSize } from './ListItemBase';
6
+
7
+ export interface ListBaseProps {
8
+ size?: ListItemSize;
9
+ theme?: LayoutTheme;
10
+ children?: ReactNode;
11
+ }
12
+
13
+ export const ListBase = ({ size = 'md', theme, children }: ListBaseProps) => {
14
+ return (
15
+ <div className={styles.list} data-theme={theme} data-size={size}>
16
+ {children}
17
+ </div>
18
+ );
19
+ };
@@ -0,0 +1,208 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { Fragment, useState } from 'react';
3
+
4
+ import { MetaItem } from '../Meta';
5
+ import { List, ListBase, ListItem } from './';
6
+
7
+ const sizes = ['lg', 'md', 'sm', 'xs'];
8
+
9
+ const meta = {
10
+ title: 'List/ListItem',
11
+ component: ListItem,
12
+ tags: ['autodocs'],
13
+ parameters: {},
14
+ args: {
15
+ id: 'id',
16
+ title: 'Title',
17
+ description: 'Description',
18
+ size: 'md',
19
+ href: '#',
20
+ },
21
+ } satisfies Meta<typeof ListItem>;
22
+
23
+ export default meta;
24
+ type Story = StoryObj<typeof meta>;
25
+
26
+ export const Default: Story = {
27
+ args: {},
28
+ };
29
+
30
+ export const Icon: Story = {
31
+ args: {
32
+ icon: 'teddy-bear',
33
+ },
34
+ };
35
+
36
+ export const IconAccent: Story = {
37
+ args: {
38
+ color: 'accent',
39
+ icon: 'teddy-bear',
40
+ },
41
+ };
42
+
43
+ export const Person: Story = {
44
+ args: {
45
+ avatar: {
46
+ type: 'person',
47
+ name: 'Erik Huseklepp',
48
+ },
49
+ },
50
+ };
51
+
52
+ export const Company: Story = {
53
+ args: {
54
+ avatar: {
55
+ type: 'company',
56
+ name: 'Sportsklubben Brann',
57
+ },
58
+ },
59
+ };
60
+
61
+ export const Logo: Story = {
62
+ args: {
63
+ avatar: {
64
+ type: 'company',
65
+ name: 'Politiets sikkerhetstjeneste',
66
+ imageUrl:
67
+ 'https://media.licdn.com/dms/image/v2/D4D0BAQH7Yv86kmHN5g/company-logo_200_200/company-logo_200_200/0/1688735908848?e=1738195200&v=beta&t=f-Mkzd03bqzdQN4IT0h89VQ9_Jri1iJ6XphYYnjsgEo',
68
+ },
69
+ },
70
+ };
71
+
72
+ export const PeopleGroup: Story = {
73
+ args: {
74
+ avatarGroup: {
75
+ items: [
76
+ {
77
+ type: 'person',
78
+ name: 'Albert Åberg',
79
+ },
80
+ {
81
+ type: 'person',
82
+ name: 'Birger Meling',
83
+ },
84
+ {
85
+ type: 'person',
86
+ name: 'Celine Dion',
87
+ },
88
+ ],
89
+ },
90
+ },
91
+ };
92
+
93
+ export const CompanyGroup: Story = {
94
+ args: {
95
+ avatarGroup: {
96
+ items: [
97
+ {
98
+ type: 'company',
99
+ name: 'Albert Åberg',
100
+ },
101
+ {
102
+ type: 'company',
103
+ name: 'Birger Meling',
104
+ },
105
+ {
106
+ type: 'company',
107
+ name: 'Celine Dion',
108
+ },
109
+ ],
110
+ },
111
+ },
112
+ };
113
+
114
+ export const LongTitle: Story = {
115
+ args: {
116
+ avatar: {
117
+ type: 'company',
118
+ name: 'Direktoratet for samfunnssikkerhet og beredskap',
119
+ imageUrl:
120
+ 'https://media.licdn.com/dms/image/v2/C510BAQHlQiOWI4f45w/company-logo_200_200/company-logo_200_200/0/1631389121726?e=1738195200&v=beta&t=Q1P8kOwpgLvoqHBxyrHCaYd2upNkPQVi2zSSxJzbdCA',
121
+ },
122
+ title:
123
+ 'Samtykke for å reparere elektrisk utstyr hvis bruk er forbundet med særlig risiko, herunder elektromedisinsk utstyr',
124
+ description: 'Direktoratet for samfunnssikkerhet og beredskap',
125
+ },
126
+ };
127
+
128
+ export const Sizes = (args) => {
129
+ return (
130
+ <ListBase>
131
+ {sizes?.map((size) => {
132
+ return (
133
+ <Fragment key={size}>
134
+ <ListItem {...args} size={size} selected={size === args?.size} />
135
+ <MetaItem>{size}</MetaItem>
136
+ </Fragment>
137
+ );
138
+ })}
139
+ </ListBase>
140
+ );
141
+ };
142
+
143
+ export const Collapsible = (args) => {
144
+ const [expanded, setExpanded] = useState(false);
145
+
146
+ const onToggle = () => {
147
+ setExpanded((prevState) => !prevState);
148
+ };
149
+
150
+ const people = [
151
+ {
152
+ name: 'Per Ove Ludvigsen',
153
+ role: 'Sportlig leder',
154
+ rights: 'Admin',
155
+ },
156
+ {
157
+ name: 'Eirik Horneland',
158
+ role: 'Trener',
159
+ rights: 'Admin',
160
+ },
161
+ {
162
+ name: 'Erik Huseklepp',
163
+ role: 'Assistenttrener',
164
+ rights: 'Lese og skrive',
165
+ },
166
+ {
167
+ name: 'Hassan El Fakiri',
168
+ role: 'Toppspillerutvikler',
169
+ rights: 'Ingen rettigheter',
170
+ },
171
+ ];
172
+
173
+ const items = people?.map((item) => {
174
+ return {
175
+ avatar: {
176
+ ...item,
177
+ type: 'person',
178
+ },
179
+ title: item?.name,
180
+ description: item?.role,
181
+ badge: { label: item?.rights },
182
+ linkIcon: 'menu-elipsis-horizontal',
183
+ };
184
+ });
185
+
186
+ const avatarGroup = {
187
+ items: people?.map((item) => {
188
+ return {
189
+ name: item?.name,
190
+ type: 'person',
191
+ };
192
+ }),
193
+ };
194
+
195
+ return (
196
+ <Fragment>
197
+ <ListItem
198
+ {...args}
199
+ avatarGroup={avatarGroup}
200
+ collapsible={true}
201
+ expanded={expanded}
202
+ onClick={onToggle}
203
+ as="button"
204
+ />
205
+ {expanded && <List size="xs" items={items} />}
206
+ </Fragment>
207
+ );
208
+ };
@@ -0,0 +1,70 @@
1
+ import type { ElementType, ReactNode } from 'react';
2
+ import type { AvatarGroupProps, AvatarProps } from '../Avatar';
3
+ import type { BadgeProps } from '../Badge';
4
+ import type { IconName } from '../Icon';
5
+ import { ListItemBase, type ListItemColor, type ListItemSize } from './ListItemBase';
6
+ import { ListItemLabel } from './ListItemLabel';
7
+ import { ListItemMedia } from './ListItemMedia';
8
+
9
+ export interface ListItemProps {
10
+ id: string;
11
+ type?: string;
12
+ /** Element type to render */
13
+ as?: ElementType;
14
+ color?: ListItemColor;
15
+ href?: string;
16
+ onClick?: () => void;
17
+ hidden?: boolean;
18
+ /** Collapsible item, sets linkIcon to "chevron down" */
19
+ collapsible?: boolean;
20
+ /** Item is expanded, sets linkIcon to "chevron up" */
21
+ expanded?: boolean;
22
+ /** Item is selected */
23
+ selected?: boolean;
24
+ /** Item is disabled, should disable mouse events */
25
+ disabled?: boolean;
26
+ /** Display an icon indicating behaviour */
27
+ linkIcon?: IconName;
28
+ /** Size of list item */
29
+ size?: ListItemSize;
30
+ /** Title */
31
+ title?: string;
32
+ /** Optional description */
33
+ description?: string;
34
+ /** Optional badge */
35
+ badge?: BadgeProps;
36
+ /** List item icon */
37
+ icon?: IconName;
38
+ /** List item avatar */
39
+ avatar?: AvatarProps;
40
+ /** List item avatarGroup */
41
+ avatarGroup?: AvatarGroupProps;
42
+ children?: ReactNode;
43
+ items?: ListItemProps[];
44
+ className?: string;
45
+ }
46
+
47
+ export const ListItem = ({
48
+ as = 'a',
49
+ color,
50
+ children,
51
+ selected,
52
+ disabled,
53
+ size = 'sm',
54
+ icon,
55
+ avatar,
56
+ avatarGroup,
57
+ badge,
58
+ title,
59
+ description,
60
+ ...rest
61
+ }: ListItemProps) => {
62
+ return (
63
+ <ListItemBase as={as} size={size} badge={badge} color={color} selected={selected} {...rest}>
64
+ <ListItemMedia color={color} size={size} icon={icon} avatar={avatar} avatarGroup={avatarGroup} />
65
+ <ListItemLabel title={title} description={description} size={size}>
66
+ {children}
67
+ </ListItemLabel>
68
+ </ListItemBase>
69
+ );
70
+ };
@@ -0,0 +1,62 @@
1
+ import cx from 'classnames';
2
+ import type { ElementType, ReactNode } from 'react';
3
+ import { Badge, type BadgeProps } from '../Badge';
4
+ import { Icon, type IconName } from '../Icon';
5
+ import styles from './listItemBase.module.css';
6
+
7
+ export type ListItemColor = 'default' | 'accent';
8
+ export type ListItemSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
9
+
10
+ interface ListItemBaseProps {
11
+ as?: ElementType;
12
+ size?: ListItemSize;
13
+ linkIcon?: IconName;
14
+ color?: ListItemColor;
15
+ badge?: BadgeProps;
16
+ href?: string;
17
+ className?: string;
18
+ collapsible?: boolean;
19
+ selected?: boolean;
20
+ expanded?: boolean;
21
+ children?: ReactNode;
22
+ }
23
+
24
+ export const ListItemBase = ({
25
+ as,
26
+ children,
27
+ className,
28
+ href,
29
+ size,
30
+ color,
31
+ collapsible,
32
+ selected,
33
+ expanded,
34
+ linkIcon,
35
+ badge,
36
+ ...rest
37
+ }: ListItemBaseProps) => {
38
+ const Component = as || 'a';
39
+
40
+ const applicableIcon =
41
+ collapsible && expanded ? 'chevron-up' : collapsible ? 'chevron-down' : href ? 'chevron-right' : linkIcon;
42
+
43
+ return (
44
+ <Component
45
+ className={cx(styles.item, className)}
46
+ data-color={color}
47
+ data-size={size}
48
+ aria-selected={selected}
49
+ aria-expanded={expanded}
50
+ href={href}
51
+ {...rest}
52
+ >
53
+ <div className={styles.content} data-size={size}>
54
+ {children}
55
+ </div>
56
+ <div className={styles.action}>
57
+ {badge && <Badge {...badge} />}
58
+ {applicableIcon && <Icon name={applicableIcon} className={styles.linkIcon} />}
59
+ </div>
60
+ </Component>
61
+ );
62
+ };
@@ -0,0 +1,29 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { ListItemSize } from './ListItemBase';
3
+ import styles from './listItemLabel.module.css';
4
+
5
+ export interface ListItemLabelProps {
6
+ size?: ListItemSize;
7
+ title?: string;
8
+ description?: string;
9
+ children?: ReactNode;
10
+ }
11
+
12
+ export const ListItemLabel = ({ size = 'sm', title, description, children }: ListItemLabelProps) => {
13
+ return (
14
+ <span className={styles.label} data-size={size}>
15
+ {children ? (
16
+ children
17
+ ) : (
18
+ <>
19
+ <strong className={styles.title} data-size={size}>
20
+ {title}
21
+ </strong>
22
+ <span className={styles.description} data-size={size}>
23
+ {description}
24
+ </span>
25
+ </>
26
+ )}
27
+ </span>
28
+ );
29
+ };
@@ -0,0 +1,59 @@
1
+ import type { ReactNode } from 'react';
2
+ import { Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, type AvatarSize } from '../Avatar';
3
+ import { Icon, type IconName } from '../Icon';
4
+ import type { ListItemColor, ListItemSize } from './ListItemBase';
5
+ import styles from './listItemMedia.module.css';
6
+
7
+ interface ListItemMediaProps {
8
+ color?: ListItemColor;
9
+ size?: ListItemSize;
10
+ icon?: IconName;
11
+ avatar?: AvatarProps;
12
+ avatarGroup?: AvatarGroupProps;
13
+ children?: ReactNode;
14
+ }
15
+
16
+ const sizeMap = {
17
+ avatar: {
18
+ xs: 'xs',
19
+ sm: 'sm',
20
+ md: 'md',
21
+ lg: 'lg',
22
+ xl: 'xl',
23
+ },
24
+ avatarGroup: {
25
+ xs: 'xs',
26
+ sm: 'xs',
27
+ md: 'sm',
28
+ lg: 'md',
29
+ xl: 'lg',
30
+ },
31
+ };
32
+
33
+ export const ListItemMedia = ({
34
+ size = 'sm',
35
+ color = 'default',
36
+ icon,
37
+ avatar,
38
+ avatarGroup,
39
+ children,
40
+ }: ListItemMediaProps) => {
41
+ if (!icon && !avatar && !avatarGroup && !children) {
42
+ return false;
43
+ }
44
+
45
+ return (
46
+ <div className={styles.media} data-size={size} data-color={!icon ? null : color}>
47
+ {(icon && <Icon name={icon} variant="outline" className={styles.icon} />) ||
48
+ (avatar && <Avatar {...avatar} size={sizeMap?.avatar[size] as AvatarSize} className={styles.avatar} />) ||
49
+ (avatarGroup && (
50
+ <AvatarGroup
51
+ {...avatarGroup}
52
+ size={sizeMap?.avatarGroup[size] as AvatarSize}
53
+ className={styles.avatarGroup}
54
+ />
55
+ ))}
56
+ {children}
57
+ </div>
58
+ );
59
+ };
@@ -0,0 +1,4 @@
1
+ export * from './ListItemBase';
2
+ export * from './ListItem';
3
+ export * from './ListBase';
4
+ export * from './List';
@@ -0,0 +1,16 @@
1
+ .list {
2
+ display: flex;
3
+ flex-direction: column;
4
+ }
5
+
6
+ .list[data-size="sm"] {
7
+ row-gap: 4px;
8
+ }
9
+
10
+ .list[data-size="md"] {
11
+ row-gap: 8px;
12
+ }
13
+
14
+ .list[data-size="lg"] {
15
+ row-gap: 16px;
16
+ }
@@ -0,0 +1,86 @@
1
+ /* reset */
2
+
3
+ .item {
4
+ border: none;
5
+
6
+ color: inherit;
7
+ font: inherit;
8
+ text-align: inherit;
9
+
10
+ line-height: normal;
11
+
12
+ -webkit-font-smoothing: inherit;
13
+ -moz-osx-font-smoothing: inherit;
14
+
15
+ user-select: none;
16
+ cursor: pointer;
17
+ }
18
+
19
+ .item {
20
+ width: 100%;
21
+ position: relative;
22
+ display: flex;
23
+ align-items: center;
24
+ text-decoration: none;
25
+ color: inherit;
26
+ }
27
+
28
+ /* sizes */
29
+
30
+ .item[data-size="xs"] {
31
+ min-height: 36px;
32
+ }
33
+
34
+ .item[data-size="sm"] {
35
+ min-height: 44px;
36
+ }
37
+
38
+ .item[data-size="md"] {
39
+ min-height: 56px;
40
+ }
41
+
42
+ .item[data-size="lg"] {
43
+ min-height: 64px;
44
+ }
45
+
46
+ .item[data-size="xl"] {
47
+ min-height: 72px;
48
+ }
49
+
50
+ /* content (icon + header) */
51
+
52
+ .content {
53
+ flex-grow: 1;
54
+ display: flex;
55
+ align-items: center;
56
+ gap: 0.625rem;
57
+ padding: 0.5rem 0.625rem;
58
+ }
59
+
60
+ /* action */
61
+
62
+ .action {
63
+ display: flex;
64
+ align-items: center;
65
+ gap: 0.625rem;
66
+ padding: 0.625rem;
67
+ }
68
+
69
+ .linkIcon {
70
+ font-size: 1.5rem;
71
+ }
72
+
73
+ /* colors */
74
+
75
+ .item {
76
+ background-color: var(--theme-background-default);
77
+ box-shadow: var(--ds-shadow-xs);
78
+ }
79
+
80
+ .item[data-color="accent"] {
81
+ background-color: var(--theme-surface-default);
82
+ }
83
+
84
+ .item[data-color="accent"]:hover {
85
+ background-color: var(--theme-surface-hover);
86
+ }
@@ -0,0 +1,55 @@
1
+ /* label */
2
+
3
+ .label {
4
+ display: flex;
5
+ justify-content: center;
6
+ }
7
+
8
+ .label[data-size="xs"] {
9
+ align-items: center;
10
+ column-gap: 0.25em;
11
+ font-size: 0.875rem;
12
+ }
13
+
14
+ .label[data-size="sm"] {
15
+ align-items: center;
16
+ column-gap: 0.25rem;
17
+ }
18
+
19
+ .label[data-size="md"] {
20
+ flex-direction: column;
21
+ }
22
+
23
+ .label[data-size="lg"] {
24
+ flex-direction: column;
25
+ }
26
+
27
+ .label[data-size="xl"] {
28
+ flex-direction: column;
29
+ }
30
+
31
+ /* title + descr */
32
+
33
+ .title {
34
+ font-weight: 600;
35
+ margin: 0;
36
+ }
37
+
38
+ .title[data-size="lg"] {
39
+ font-size: 1.125rem;
40
+ }
41
+
42
+ .title[data-size="xl"] {
43
+ font-size: 1.25rem;
44
+ }
45
+
46
+ .description {
47
+ color: var(--theme-text-subtle);
48
+ margin: 0;
49
+ }
50
+
51
+ .description[data-size="md"],
52
+ .description[data-size="lg"],
53
+ .description[data-size="xl"] {
54
+ font-size: 0.875em;
55
+ }