@altinn/altinn-components 0.0.1 → 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.
- package/.storybook/StoryDecorator.tsx +27 -0
- package/.storybook/ThemeProvider.tsx +16 -0
- package/.storybook/main.ts +4 -5
- package/.storybook/preview.tsx +35 -0
- package/.storybook/storyDecorator.module.css +20 -0
- package/.storybook/theme.module.css +3 -0
- package/CHANGELOG.md +21 -0
- package/CONTRIBUTING.MD +59 -0
- package/README.md +33 -1
- package/lib/components/Attachment/AttachmentLink.stories.ts +21 -0
- package/lib/components/Attachment/AttachmentLink.tsx +20 -0
- package/lib/components/Attachment/AttachmentList.stories.ts +39 -0
- package/lib/components/Attachment/AttachmentList.tsx +26 -0
- package/lib/components/Attachment/attachmentLink.module.css +20 -0
- package/lib/components/Attachment/attachmentList.module.css +12 -0
- package/lib/components/Attachment/index.ts +2 -0
- package/lib/components/Avatar/Avatar.tsx +8 -16
- package/lib/components/Avatar/AvatarGroup.stories.ts +3 -4
- package/lib/components/Avatar/AvatarGroup.tsx +20 -3
- package/lib/components/Avatar/avatar.module.css +2 -0
- package/lib/components/Avatar/avatar.stories.tsx +1 -6
- package/lib/components/Badge/Badge.stories.ts +32 -0
- package/lib/components/Badge/Badge.tsx +13 -10
- package/lib/components/Badge/badge.module.css +18 -27
- package/lib/components/Button/Button.stories.ts +6 -0
- package/lib/components/Button/Button.tsx +19 -1
- package/lib/components/Button/ButtonBase.tsx +1 -1
- package/lib/components/Button/button.module.css +0 -19
- package/lib/components/Button/buttonBase.module.css +30 -12
- package/lib/components/Button/comboButton.module.css +4 -2
- package/lib/components/ContextMenu/ContextMenu.tsx +28 -0
- package/lib/components/ContextMenu/contextMenu.module.css +35 -0
- package/lib/components/Dialog/Dialog.stories.ts +320 -0
- package/lib/components/Dialog/Dialog.tsx +101 -0
- package/lib/components/Dialog/DialogAction.stories.ts +54 -0
- package/lib/components/Dialog/DialogAction.tsx +79 -0
- package/lib/components/Dialog/DialogActivityLog.tsx +18 -0
- package/lib/components/Dialog/DialogArticleBase.tsx +10 -0
- package/lib/components/Dialog/DialogAttachments.stories.ts +40 -0
- package/lib/components/Dialog/DialogAttachments.tsx +25 -0
- package/lib/components/Dialog/DialogBase.tsx +10 -0
- package/lib/components/Dialog/DialogBodyBase.tsx +17 -0
- package/lib/components/Dialog/DialogBorder.tsx +19 -0
- package/lib/components/Dialog/DialogContent.stories.ts +26 -0
- package/lib/components/Dialog/DialogContent.tsx +24 -0
- package/lib/components/Dialog/DialogFooter.tsx +14 -0
- package/lib/components/Dialog/DialogHeader.stories.ts +26 -0
- package/lib/components/Dialog/DialogHeader.tsx +23 -0
- package/lib/components/Dialog/DialogHeaderBase.tsx +10 -0
- package/lib/components/Dialog/DialogHeadings.stories.ts +35 -0
- package/lib/components/Dialog/DialogHeadings.tsx +77 -0
- package/lib/components/Dialog/DialogHistory.stories.ts +67 -0
- package/lib/components/Dialog/DialogHistory.tsx +19 -0
- package/lib/components/Dialog/DialogList.stories.ts +61 -0
- package/lib/components/Dialog/DialogList.tsx +20 -0
- package/lib/components/Dialog/DialogListItem.stories.tsx +238 -0
- package/lib/components/Dialog/DialogListItem.tsx +114 -0
- package/lib/components/Dialog/DialogListItemBase.tsx +50 -0
- package/lib/components/Dialog/DialogMetadata.stories.ts +77 -0
- package/lib/components/Dialog/DialogMetadata.tsx +56 -0
- package/lib/components/Dialog/DialogNav.stories.ts +90 -0
- package/lib/components/Dialog/DialogNav.tsx +60 -0
- package/lib/components/Dialog/DialogSectionBase.tsx +20 -0
- package/lib/components/Dialog/DialogSeenBy.stories.tsx +58 -0
- package/lib/components/Dialog/DialogSeenBy.tsx +36 -0
- package/lib/components/Dialog/DialogSelect.tsx +23 -0
- package/lib/components/Dialog/DialogStatus.stories.ts +57 -0
- package/lib/components/Dialog/DialogStatus.tsx +61 -0
- package/lib/components/Dialog/DialogTitle.stories.ts +33 -0
- package/lib/components/Dialog/DialogTitle.tsx +31 -0
- package/lib/components/Dialog/DialogTouchedBy.stories.tsx +27 -0
- package/lib/components/Dialog/DialogTouchedBy.tsx +19 -0
- package/lib/components/Dialog/dialog.module.css +21 -0
- package/lib/components/Dialog/dialogAction.module.css +26 -0
- package/lib/components/Dialog/dialogArticleBase.module.css +5 -0
- package/lib/components/Dialog/dialogBodyBase.module.css +13 -0
- package/lib/components/Dialog/dialogBorder.module.css +42 -0
- package/lib/components/Dialog/dialogHeaderBase.module.css +6 -0
- package/lib/components/Dialog/dialogHeadings.module.css +24 -0
- package/lib/components/Dialog/dialogHistory.module.css +12 -0
- package/lib/components/Dialog/dialogListItem.module.css +81 -0
- package/lib/components/Dialog/dialogListItemBase.module.css +28 -0
- package/lib/components/Dialog/dialogSectionBase.module.css +11 -0
- package/lib/components/Dialog/dialogSelect.module.css +34 -0
- package/lib/components/Dialog/dialogTitle.module.css +47 -0
- package/lib/components/Dialog/index.ts +2 -0
- package/lib/components/Header/GlobalMenu.tsx +1 -1
- package/lib/components/Header/Header.tsx +3 -3
- package/lib/components/Header/HeaderSearch.tsx +1 -1
- package/lib/components/History/HistoryBorder.tsx +17 -0
- package/lib/components/History/HistoryItem.stories.ts +47 -0
- package/lib/components/History/HistoryItem.tsx +64 -0
- package/lib/components/History/HistoryList.stories.ts +58 -0
- package/lib/components/History/HistoryList.tsx +26 -0
- package/lib/components/History/historyBorder.module.css +8 -0
- package/lib/components/History/historyItem.module.css +19 -0
- package/lib/components/History/historyList.module.css +12 -0
- package/lib/components/History/index.ts +2 -0
- package/lib/components/Icon/CheckboxCheckedIcon.tsx +28 -0
- package/lib/components/Icon/CheckboxIcon.stories.ts +7 -0
- package/lib/components/Icon/CheckboxIcon.tsx +6 -18
- package/lib/components/Icon/CheckboxUncheckedIcon.tsx +38 -0
- package/lib/components/Icon/ProgressIcon.stories.ts +43 -0
- package/lib/components/Icon/ProgressIcon.tsx +44 -0
- package/lib/components/Icon/RadioCheckedIcon.tsx +29 -0
- package/lib/components/Icon/RadioIcon.stories.ts +7 -0
- package/lib/components/Icon/RadioIcon.tsx +7 -19
- package/lib/components/Icon/RadioUncheckedIcon.tsx +30 -0
- package/lib/components/Icon/checkboxIcon.module.css +2 -0
- package/lib/components/Icon/index.ts +1 -0
- package/lib/components/Icon/progressIcon.module.css +29 -0
- package/lib/components/Layout/Layout.stories.ts +0 -3
- package/lib/components/List/List.tsx +20 -0
- package/lib/components/List/ListBase.tsx +19 -0
- package/lib/components/List/ListItem.stories.tsx +208 -0
- package/lib/components/List/ListItem.tsx +70 -0
- package/lib/components/List/ListItemBase.tsx +62 -0
- package/lib/components/List/ListItemLabel.tsx +29 -0
- package/lib/components/List/ListItemMedia.tsx +59 -0
- package/lib/components/List/index.ts +4 -0
- package/lib/components/List/listBase.module.css +16 -0
- package/lib/components/List/listItemBase.module.css +86 -0
- package/lib/components/List/listItemLabel.module.css +55 -0
- package/lib/components/List/listItemMedia.module.css +41 -0
- package/lib/components/Menu/Menu.stories.ts +46 -27
- package/lib/components/Menu/Menu.tsx +3 -3
- package/lib/components/Menu/MenuItem.stories.ts +12 -7
- package/lib/components/Menu/MenuItem.tsx +4 -3
- package/lib/components/Menu/MenuItemBase.tsx +7 -7
- package/lib/components/Menu/MenuItemLabel.tsx +4 -4
- package/lib/components/Menu/MenuItemMedia.tsx +2 -2
- package/lib/components/Menu/MenuOption.stories.ts +4 -2
- package/lib/components/Menu/MenuOption.tsx +4 -4
- package/lib/components/Menu/menuItemBase.module.css +72 -0
- package/lib/components/Menu/menuItemLabel.module.css +22 -0
- package/lib/components/Menu/menuItemMedia.module.css +36 -0
- package/lib/components/Menu/menuOption.module.css +6 -8
- package/lib/components/Meta/MetaBase.tsx +15 -0
- package/lib/components/Meta/MetaItem.stories.ts +25 -0
- package/lib/components/Meta/MetaItem.tsx +31 -0
- package/lib/components/Meta/MetaItemBase.tsx +46 -0
- package/lib/components/Meta/MetaItemLabel.tsx +20 -0
- package/lib/components/Meta/MetaItemMedia.tsx +22 -0
- package/lib/components/Meta/MetaList.stories.ts +29 -0
- package/lib/components/Meta/MetaList.tsx +43 -0
- package/lib/components/Meta/MetaProgress.stories.ts +29 -0
- package/lib/components/Meta/MetaProgress.tsx +26 -0
- package/lib/components/Meta/MetaTimestamp.stories.ts +33 -0
- package/lib/components/Meta/MetaTimestamp.tsx +29 -0
- package/lib/components/Meta/index.ts +6 -0
- package/lib/components/Meta/meta.module.css +6 -0
- package/lib/components/Meta/metaItem.module.css +107 -0
- package/lib/components/Meta/metaList.module.css +15 -0
- package/lib/components/Toolbar/ToolbarAdd.tsx +1 -1
- package/lib/components/Typography/Typography.tsx +21 -0
- package/lib/components/Typography/index.ts +1 -0
- package/lib/components/Typography/typography.module.css +56 -0
- package/lib/components/index.ts +9 -0
- package/lib/css/global.css +2 -0
- package/lib/css/shadows.css +7 -0
- package/lib/css/theme-article.css +15 -0
- package/lib/css/theme.css +5 -7
- package/package.json +4 -2
- package/renovate.json +4 -0
- package/.storybook/preview.ts +0 -15
- /package/lib/components/Toolbar/{index.js → index.ts} +0 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import cx from 'classnames';
|
|
2
|
+
import type { CSSProperties } from 'react';
|
|
3
|
+
import styles from './progressIcon.module.css';
|
|
4
|
+
export interface ProgressIconProps {
|
|
5
|
+
value?: number;
|
|
6
|
+
total?: number;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface CustomCSSProperties extends CSSProperties {
|
|
11
|
+
'--progress'?: string;
|
|
12
|
+
}
|
|
13
|
+
export const ProgressIcon = ({ value = 0, total = 100, className }: ProgressIconProps) => {
|
|
14
|
+
const percentage = Math.round((value / total) * 100);
|
|
15
|
+
|
|
16
|
+
if (value === total) {
|
|
17
|
+
return (
|
|
18
|
+
<svg
|
|
19
|
+
width="16"
|
|
20
|
+
height="16"
|
|
21
|
+
viewBox="0 0 16 16"
|
|
22
|
+
fill="none"
|
|
23
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
24
|
+
className={styles.complete}
|
|
25
|
+
>
|
|
26
|
+
<title>
|
|
27
|
+
Progress {value} of {total}
|
|
28
|
+
</title>
|
|
29
|
+
<path
|
|
30
|
+
fill="currentColor"
|
|
31
|
+
fillRule="evenodd"
|
|
32
|
+
clipRule="evenodd"
|
|
33
|
+
d="M8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16ZM11.1751 5.11246C11.3892 4.87167 11.7579 4.84998 11.9987 5.06402C12.2395 5.27805 12.2612 5.64676 12.0471 5.88755L7.60268 10.8876C7.49595 11.0076 7.34442 11.0784 7.18383 11.0831C7.02324 11.0878 6.86782 11.0261 6.75421 10.9125L3.97644 8.13471C3.74863 7.9069 3.74863 7.53756 3.97644 7.30975C4.20424 7.08194 4.57359 7.08194 4.80139 7.30975L7.14172 9.65007L11.1751 5.11246Z"
|
|
34
|
+
/>
|
|
35
|
+
</svg>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const progressStyle: CustomCSSProperties = {
|
|
40
|
+
'--progress': `${percentage}%`,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return <div className={cx(styles.progress, className)} style={progressStyle} data-value={`${percentage}%`} />;
|
|
44
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type RadioCheckedIconProps = {
|
|
2
|
+
title?: string;
|
|
3
|
+
className?: string;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Radio for lists and list items
|
|
8
|
+
*/
|
|
9
|
+
export const RadioCheckedIcon = ({ title = 'Radio', className }: RadioCheckedIconProps) => {
|
|
10
|
+
return (
|
|
11
|
+
<svg
|
|
12
|
+
width="1em"
|
|
13
|
+
height="1em"
|
|
14
|
+
viewBox="0 0 24 24"
|
|
15
|
+
fill="none"
|
|
16
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
17
|
+
className={className}
|
|
18
|
+
>
|
|
19
|
+
<title>{title}</title>
|
|
20
|
+
|
|
21
|
+
<path
|
|
22
|
+
fillRule="evenodd"
|
|
23
|
+
clipRule="evenodd"
|
|
24
|
+
d="M12 24C18.6274 24 24 18.6274 24 12C24 5.37258 18.6274 0 12 0C5.37258 0 0 5.37258 0 12C0 18.6274 5.37258 24 12 24ZM12 17C14.7614 17 17 14.7614 17 12C17 9.23858 14.7614 7 12 7C9.23858 7 7 9.23858 7 12C7 14.7614 9.23858 17 12 17Z"
|
|
25
|
+
fill="black"
|
|
26
|
+
/>
|
|
27
|
+
</svg>
|
|
28
|
+
);
|
|
29
|
+
};
|
|
@@ -1,29 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { RadioCheckedIcon } from './RadioCheckedIcon';
|
|
2
|
+
import { RadioUncheckedIcon } from './RadioUncheckedIcon';
|
|
3
3
|
|
|
4
4
|
export type RadioIconProps = {
|
|
5
5
|
checked: boolean;
|
|
6
|
+
hover?: boolean;
|
|
6
7
|
title?: string;
|
|
7
8
|
className?: string;
|
|
8
9
|
};
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
|
-
* Radio
|
|
12
|
+
* Radio for lists and list items
|
|
12
13
|
*/
|
|
13
|
-
export const RadioIcon = ({ checked, title, className }: RadioIconProps) => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
<svg
|
|
17
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
18
|
-
fill="none"
|
|
19
|
-
viewBox="0 0 24 24"
|
|
20
|
-
strokeWidth={2.5}
|
|
21
|
-
stroke="currentColor"
|
|
22
|
-
className={styles.icon}
|
|
23
|
-
>
|
|
24
|
-
<title>{title}</title>
|
|
25
|
-
<circle cx="12" cy="12" r="6" fill="currentColor" />
|
|
26
|
-
</svg>
|
|
27
|
-
</div>
|
|
28
|
-
);
|
|
14
|
+
export const RadioIcon = ({ checked, title = 'Radio', hover = false, className }: RadioIconProps) => {
|
|
15
|
+
const iconProps = { title, className };
|
|
16
|
+
return checked ? <RadioCheckedIcon {...iconProps} /> : <RadioUncheckedIcon {...iconProps} hover={hover} />;
|
|
29
17
|
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type RadioUncheckedIconProps = {
|
|
2
|
+
title?: string;
|
|
3
|
+
className?: string;
|
|
4
|
+
hover?: boolean;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Radio for lists and list items
|
|
9
|
+
*/
|
|
10
|
+
export const RadioUncheckedIcon = ({ title = 'Radio', className, hover = false }: RadioUncheckedIconProps) => {
|
|
11
|
+
return (
|
|
12
|
+
<svg
|
|
13
|
+
width="1em"
|
|
14
|
+
height="1em"
|
|
15
|
+
viewBox="0 0 24 24"
|
|
16
|
+
fill="none"
|
|
17
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
18
|
+
className={className}
|
|
19
|
+
>
|
|
20
|
+
<title>{title}</title>
|
|
21
|
+
<path
|
|
22
|
+
fillRule="evenodd"
|
|
23
|
+
clipRule="evenodd"
|
|
24
|
+
d="M12 21.5C17.2467 21.5 21.5 17.2467 21.5 12C21.5 6.75329 17.2467 2.5 12 2.5C6.75329 2.5 2.5 6.75329 2.5 12C2.5 17.2467 6.75329 21.5 12 21.5ZM12 24C18.6274 24 24 18.6274 24 12C24 5.37258 18.6274 0 12 0C5.37258 0 0 5.37258 0 12C0 18.6274 5.37258 24 12 24Z"
|
|
25
|
+
fill="black"
|
|
26
|
+
/>
|
|
27
|
+
{hover && <circle data-hover={true} cx="12" cy="12" r="5" fill="black" />}
|
|
28
|
+
</svg>
|
|
29
|
+
);
|
|
30
|
+
};
|
|
@@ -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
|
+
};
|