@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,101 @@
|
|
|
1
|
+
import { MetaBase } from '../Meta';
|
|
2
|
+
import { DialogActivityLog, type DialogActivityLogProps } from './DialogActivityLog';
|
|
3
|
+
import { DialogArticleBase } from './DialogArticleBase';
|
|
4
|
+
import { DialogAttachments, type DialogAttachmentsProps } from './DialogAttachments';
|
|
5
|
+
import { DialogBase } from './DialogBase';
|
|
6
|
+
import { DialogBodyBase } from './DialogBodyBase';
|
|
7
|
+
import { DialogContent } from './DialogContent';
|
|
8
|
+
import { DialogFooter } from './DialogFooter';
|
|
9
|
+
import { DialogHeader } from './DialogHeader';
|
|
10
|
+
import { DialogSeenBy, type DialogSeenByProps } from './DialogSeenBy';
|
|
11
|
+
|
|
12
|
+
import type { ReactNode } from 'react';
|
|
13
|
+
import { DialogAction, type DialogActionButtonProps } from './DialogAction';
|
|
14
|
+
import type { DialogRecipientProps, DialogSenderProps } from './DialogHeadings.tsx';
|
|
15
|
+
import { DialogHistory, type DialogHistoryProps } from './DialogHistory';
|
|
16
|
+
import { type DialogBackButtonProps, DialogNav } from './DialogNav';
|
|
17
|
+
import type { DialogStatusProps } from './DialogStatus';
|
|
18
|
+
|
|
19
|
+
export interface DialogProps {
|
|
20
|
+
/** Title */
|
|
21
|
+
title: string;
|
|
22
|
+
/** Back button */
|
|
23
|
+
backButton?: DialogBackButtonProps;
|
|
24
|
+
/** Dialog status */
|
|
25
|
+
status?: DialogStatusProps;
|
|
26
|
+
/** Updated date time */
|
|
27
|
+
updatedAt?: string;
|
|
28
|
+
/** Latest updated by name */
|
|
29
|
+
updatedByName?: string;
|
|
30
|
+
/** Due date */
|
|
31
|
+
dueAt?: string;
|
|
32
|
+
/** Sender */
|
|
33
|
+
sender?: DialogSenderProps;
|
|
34
|
+
/** Recipient */
|
|
35
|
+
recipient?: DialogRecipientProps;
|
|
36
|
+
/** Summary */
|
|
37
|
+
summary?: string;
|
|
38
|
+
/** Body (should be an output markdown/html rendered to React / HTML) */
|
|
39
|
+
body?: ReactNode;
|
|
40
|
+
/** List of action (buttons) */
|
|
41
|
+
actions?: DialogActionButtonProps[];
|
|
42
|
+
/** Dialog attachments */
|
|
43
|
+
attachments?: DialogAttachmentsProps;
|
|
44
|
+
/** Dialog is seen by the end user or others */
|
|
45
|
+
seenBy?: DialogSeenByProps;
|
|
46
|
+
/** Activity Log */
|
|
47
|
+
activityLog?: DialogActivityLogProps;
|
|
48
|
+
/** More information about the dialog, process, etc. */
|
|
49
|
+
additionalInfo?: string;
|
|
50
|
+
/** History */
|
|
51
|
+
history?: DialogHistoryProps;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Full representation of a dialog, including attachments, actions and history,
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
export const Dialog = ({
|
|
59
|
+
backButton,
|
|
60
|
+
updatedAt,
|
|
61
|
+
updatedByName,
|
|
62
|
+
dueAt,
|
|
63
|
+
status,
|
|
64
|
+
title,
|
|
65
|
+
sender,
|
|
66
|
+
recipient,
|
|
67
|
+
summary = 'Summary.',
|
|
68
|
+
body,
|
|
69
|
+
actions = [],
|
|
70
|
+
attachments,
|
|
71
|
+
history,
|
|
72
|
+
seenBy,
|
|
73
|
+
activityLog,
|
|
74
|
+
additionalInfo,
|
|
75
|
+
}: DialogProps) => {
|
|
76
|
+
return (
|
|
77
|
+
<DialogBase>
|
|
78
|
+
<DialogNav status={status} dueAt={dueAt} backButton={backButton} />
|
|
79
|
+
<DialogArticleBase>
|
|
80
|
+
<DialogHeader
|
|
81
|
+
title={title}
|
|
82
|
+
sender={sender}
|
|
83
|
+
recipient={recipient}
|
|
84
|
+
seen={seenBy?.seenByEndUser ?? false}
|
|
85
|
+
variant="neutral"
|
|
86
|
+
/>
|
|
87
|
+
<DialogBodyBase>
|
|
88
|
+
<DialogContent updatedAt={updatedAt} updatedByName={updatedByName} summary={summary} body={body} />
|
|
89
|
+
{attachments && <DialogAttachments {...attachments} />}
|
|
90
|
+
{actions?.length > 0 && <DialogAction items={actions} />}
|
|
91
|
+
<MetaBase>
|
|
92
|
+
{seenBy && <DialogSeenBy {...seenBy} />}
|
|
93
|
+
{activityLog && <DialogActivityLog {...activityLog} />}
|
|
94
|
+
</MetaBase>
|
|
95
|
+
</DialogBodyBase>
|
|
96
|
+
{additionalInfo && <DialogFooter additionalInfo={additionalInfo} />}
|
|
97
|
+
{history && <DialogHistory {...history} />}
|
|
98
|
+
</DialogArticleBase>
|
|
99
|
+
</DialogBase>
|
|
100
|
+
);
|
|
101
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { DialogAction } from './DialogAction';
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'Dialog/Sections/DialogAction',
|
|
6
|
+
component: DialogAction,
|
|
7
|
+
tags: ['autodocs'],
|
|
8
|
+
args: {
|
|
9
|
+
items: [
|
|
10
|
+
{
|
|
11
|
+
label: 'Primary',
|
|
12
|
+
priority: 'primary',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
label: 'Secondary',
|
|
16
|
+
priority: 'secondary',
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
} satisfies Meta<typeof DialogAction>;
|
|
21
|
+
|
|
22
|
+
export default meta;
|
|
23
|
+
type Story = StoryObj<typeof meta>;
|
|
24
|
+
|
|
25
|
+
export const Default: Story = {
|
|
26
|
+
args: {},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const Secondary: Story = {
|
|
30
|
+
args: {},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const MultipleButtons: Story = {
|
|
34
|
+
args: {
|
|
35
|
+
items: [
|
|
36
|
+
{
|
|
37
|
+
label: 'Primary',
|
|
38
|
+
priority: 'primary',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
label: 'Secondary',
|
|
42
|
+
priority: 'secondary',
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
label: 'Third action',
|
|
46
|
+
priority: 'tertiary',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
label: 'Fourth action',
|
|
50
|
+
priority: 'tertiary',
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { type MouseEventHandler, useMemo, useState } from 'react';
|
|
2
|
+
import { Button, ComboButton } from '../Button';
|
|
3
|
+
import { Menu, type MenuItemProps } from '../Menu';
|
|
4
|
+
import styles from './dialogAction.module.css';
|
|
5
|
+
|
|
6
|
+
export type DialogButtonPriority = 'primary' | 'secondary' | 'tertiary';
|
|
7
|
+
|
|
8
|
+
export interface DialogActionButtonProps {
|
|
9
|
+
id: string;
|
|
10
|
+
priority: DialogButtonPriority;
|
|
11
|
+
label?: string;
|
|
12
|
+
onClick?: MouseEventHandler;
|
|
13
|
+
loading?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface DialogActionProps {
|
|
17
|
+
/** List of actions */
|
|
18
|
+
items: DialogActionButtonProps[];
|
|
19
|
+
/** How many actions to display before turning into a ComboButton */
|
|
20
|
+
maxItems?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const DialogAction = ({ items, maxItems = 2 }: DialogActionProps) => {
|
|
24
|
+
const [expanded, setExpanded] = useState<boolean>(false);
|
|
25
|
+
const sortedItems = useMemo(() => {
|
|
26
|
+
return (items || []).sort((a, b) => {
|
|
27
|
+
const priorityOrder = ['primary', 'secondary', 'tertiary'];
|
|
28
|
+
return priorityOrder.indexOf(a?.priority) - priorityOrder.indexOf(b?.priority);
|
|
29
|
+
});
|
|
30
|
+
}, [items]);
|
|
31
|
+
|
|
32
|
+
if (!sortedItems.length || maxItems <= 0) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (sortedItems.length > maxItems) {
|
|
37
|
+
const remainingItems: MenuItemProps[] = sortedItems.slice(1).map((item) => ({
|
|
38
|
+
id: item.id,
|
|
39
|
+
title: item.label,
|
|
40
|
+
onClick: item.onClick,
|
|
41
|
+
group: item.priority,
|
|
42
|
+
}));
|
|
43
|
+
return (
|
|
44
|
+
<section className={styles.comboButton}>
|
|
45
|
+
<ComboButton
|
|
46
|
+
color="primary"
|
|
47
|
+
variant="solid"
|
|
48
|
+
icon={expanded ? 'chevron-up' : 'chevron-down'}
|
|
49
|
+
size="lg"
|
|
50
|
+
onIconClick={() => setExpanded((expanded) => !expanded)}
|
|
51
|
+
>
|
|
52
|
+
{sortedItems[0].label}
|
|
53
|
+
</ComboButton>
|
|
54
|
+
<div className={styles.dropdown} aria-expanded={expanded}>
|
|
55
|
+
<Menu items={remainingItems} theme="global" />
|
|
56
|
+
</div>
|
|
57
|
+
</section>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<section className={styles.action}>
|
|
63
|
+
{sortedItems.map((item, index) => {
|
|
64
|
+
return (
|
|
65
|
+
<Button
|
|
66
|
+
key={'button-' + index}
|
|
67
|
+
onClick={item.onClick}
|
|
68
|
+
color="primary"
|
|
69
|
+
variant={item.priority === 'primary' ? 'solid' : 'outline'}
|
|
70
|
+
size="lg"
|
|
71
|
+
loading={item.loading}
|
|
72
|
+
>
|
|
73
|
+
{item.label}
|
|
74
|
+
</Button>
|
|
75
|
+
);
|
|
76
|
+
})}
|
|
77
|
+
</section>
|
|
78
|
+
);
|
|
79
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ElementType, MouseEventHandler } from 'react';
|
|
2
|
+
import { MetaItem, type MetaItemSize } from '../Meta';
|
|
3
|
+
|
|
4
|
+
export interface DialogActivityLogProps {
|
|
5
|
+
size?: MetaItemSize;
|
|
6
|
+
label?: string;
|
|
7
|
+
as?: ElementType;
|
|
8
|
+
onClick?: MouseEventHandler;
|
|
9
|
+
href?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const DialogActivityLog = ({ size = 'xs', label = 'Activity log', ...rest }: DialogActivityLogProps) => {
|
|
13
|
+
return (
|
|
14
|
+
<MetaItem {...rest} size={size} icon={'clock-dashed'}>
|
|
15
|
+
{label}
|
|
16
|
+
</MetaItem>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import styles from './dialogArticleBase.module.css';
|
|
3
|
+
|
|
4
|
+
interface ArticleBaseProps {
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const DialogArticleBase = ({ children }: ArticleBaseProps) => {
|
|
9
|
+
return <article className={styles.article}>{children}</article>;
|
|
10
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { fn } from '@storybook/test';
|
|
3
|
+
|
|
4
|
+
import { DialogAttachments } from './DialogAttachments';
|
|
5
|
+
|
|
6
|
+
const meta = {
|
|
7
|
+
title: 'Dialog/Sections/DialogAttachments',
|
|
8
|
+
component: DialogAttachments,
|
|
9
|
+
tags: ['autodocs'],
|
|
10
|
+
args: {
|
|
11
|
+
title: '6 vedlegg',
|
|
12
|
+
items: [
|
|
13
|
+
{
|
|
14
|
+
label: 'A10-01 Situasjonsplan.pdf',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
label: 'A40-01 Fasade Nord Ny.pdf',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
label: 'A40-01 Fasade Øst.pdf',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
label: 'Tegning ny fasade.pdf',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
label: 'Tegning nytt snitt.pdf',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
label: 'Redegjørelse estetikk.pdf',
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
} satisfies Meta<typeof DialogAttachments>;
|
|
34
|
+
|
|
35
|
+
export default meta;
|
|
36
|
+
type Story = StoryObj<typeof meta>;
|
|
37
|
+
|
|
38
|
+
export const Default: Story = {
|
|
39
|
+
args: {},
|
|
40
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type AttachmentLinkProps, AttachmentList } from '../Attachment';
|
|
2
|
+
import { MetaItem } from '../Meta';
|
|
3
|
+
import { Typography } from '../Typography';
|
|
4
|
+
|
|
5
|
+
export interface DialogAttachmentsProps {
|
|
6
|
+
title?: string;
|
|
7
|
+
items?: AttachmentLinkProps[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const DialogAttachments = ({ title = 'Attachments', items }: DialogAttachmentsProps) => {
|
|
11
|
+
if (!items?.length) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<section>
|
|
17
|
+
<MetaItem as="h2" size="xs">
|
|
18
|
+
{title}
|
|
19
|
+
</MetaItem>
|
|
20
|
+
<Typography size="lg">
|
|
21
|
+
<AttachmentList size="lg" items={items} />
|
|
22
|
+
</Typography>
|
|
23
|
+
</section>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import styles from './dialog.module.css';
|
|
3
|
+
|
|
4
|
+
export interface DialogBaseProps {
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const DialogBase = ({ children }: DialogBaseProps) => {
|
|
9
|
+
return <div className={styles.dialog}>{children}</div>;
|
|
10
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { DialogBorder } from './DialogBorder';
|
|
3
|
+
import styles from './dialogBodyBase.module.css';
|
|
4
|
+
|
|
5
|
+
export interface DialogBodyProps {
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const DialogBodyBase = ({ children }: DialogBodyProps) => {
|
|
10
|
+
return (
|
|
11
|
+
<DialogBorder className={styles.border}>
|
|
12
|
+
<div className={styles.body} data-theme="article">
|
|
13
|
+
{children}
|
|
14
|
+
</div>
|
|
15
|
+
</DialogBorder>
|
|
16
|
+
);
|
|
17
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import cx from 'classnames';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
import type { DialogListItemSize } from './DialogListItemBase';
|
|
4
|
+
import styles from './dialogBorder.module.css';
|
|
5
|
+
|
|
6
|
+
export interface DialogBorderProps {
|
|
7
|
+
seen?: boolean;
|
|
8
|
+
size?: DialogListItemSize;
|
|
9
|
+
className?: string;
|
|
10
|
+
children?: ReactNode;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const DialogBorder = ({ seen = true, size = 'lg', className, children }: DialogBorderProps) => {
|
|
14
|
+
return (
|
|
15
|
+
<div className={cx(styles.border, className)} data-size={size} data-seen={seen}>
|
|
16
|
+
{children}
|
|
17
|
+
</div>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { DialogContent } from './DialogContent';
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'Dialog/DialogContent',
|
|
6
|
+
component: DialogContent,
|
|
7
|
+
tags: ['autodocs'],
|
|
8
|
+
args: {
|
|
9
|
+
updatedAt: '1999-05-26 22:59:00',
|
|
10
|
+
summary: 'Summary',
|
|
11
|
+
body: 'Body',
|
|
12
|
+
},
|
|
13
|
+
} satisfies Meta<typeof DialogContent>;
|
|
14
|
+
|
|
15
|
+
export default meta;
|
|
16
|
+
type Story = StoryObj<typeof meta>;
|
|
17
|
+
|
|
18
|
+
export const Default: Story = {
|
|
19
|
+
args: {},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const UpdatedByName: Story = {
|
|
23
|
+
args: {
|
|
24
|
+
updatedByName: 'Ole Gunnar Solskjær',
|
|
25
|
+
},
|
|
26
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { Typography } from '../Typography';
|
|
3
|
+
import { DialogMetadata } from './DialogMetadata';
|
|
4
|
+
|
|
5
|
+
export interface DialogContentProps {
|
|
6
|
+
updatedByName?: string;
|
|
7
|
+
updatedAt?: string;
|
|
8
|
+
updatedAtLabel?: string;
|
|
9
|
+
summary?: string;
|
|
10
|
+
body?: ReactNode;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Main textual content of a dialog, including summary, body and a timestamp */
|
|
14
|
+
export const DialogContent = ({ updatedAt, updatedAtLabel, summary, body }: DialogContentProps) => {
|
|
15
|
+
return (
|
|
16
|
+
<section>
|
|
17
|
+
<DialogMetadata updatedAt={updatedAt} updatedAtLabel={updatedAtLabel} />
|
|
18
|
+
<Typography size="lg">
|
|
19
|
+
<p>{summary}</p>
|
|
20
|
+
{body}
|
|
21
|
+
</Typography>
|
|
22
|
+
</section>
|
|
23
|
+
);
|
|
24
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Typography } from '../Typography';
|
|
2
|
+
import { DialogSectionBase } from './DialogSectionBase';
|
|
3
|
+
|
|
4
|
+
export interface DialogFooterProps {
|
|
5
|
+
additionalInfo?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const DialogFooter = ({ additionalInfo }: DialogFooterProps) => {
|
|
9
|
+
return (
|
|
10
|
+
<DialogSectionBase>
|
|
11
|
+
<Typography size="md">{additionalInfo}</Typography>
|
|
12
|
+
</DialogSectionBase>
|
|
13
|
+
);
|
|
14
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { fn } from '@storybook/test';
|
|
3
|
+
|
|
4
|
+
import { DialogHeader } from './DialogHeader';
|
|
5
|
+
|
|
6
|
+
const meta = {
|
|
7
|
+
title: 'Dialog/Sections/DialogHeader',
|
|
8
|
+
component: DialogHeader,
|
|
9
|
+
tags: ['autodocs'],
|
|
10
|
+
args: {
|
|
11
|
+
title: 'Title',
|
|
12
|
+
sender: {
|
|
13
|
+
name: 'Sender',
|
|
14
|
+
},
|
|
15
|
+
recipient: {
|
|
16
|
+
name: 'Recipient',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
} satisfies Meta<typeof DialogHeader>;
|
|
20
|
+
|
|
21
|
+
export default meta;
|
|
22
|
+
type Story = StoryObj<typeof meta>;
|
|
23
|
+
|
|
24
|
+
export const Default: Story = {
|
|
25
|
+
args: {},
|
|
26
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { DialogHeaderBase } from './DialogHeaderBase';
|
|
2
|
+
import { DialogHeadings, type DialogRecipientProps, type DialogSenderProps } from './DialogHeadings';
|
|
3
|
+
import type { DialogListItemVariant } from './DialogListItemBase.tsx';
|
|
4
|
+
import { DialogTitle } from './DialogTitle';
|
|
5
|
+
|
|
6
|
+
export interface DialogHeaderProps {
|
|
7
|
+
title: string;
|
|
8
|
+
seen: boolean;
|
|
9
|
+
variant: DialogListItemVariant;
|
|
10
|
+
sender?: DialogSenderProps;
|
|
11
|
+
recipient?: DialogRecipientProps;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const DialogHeader = ({ title, sender, recipient, seen, variant }: DialogHeaderProps) => {
|
|
15
|
+
return (
|
|
16
|
+
<DialogHeaderBase>
|
|
17
|
+
<DialogTitle seen={seen} size="xl" variant={variant}>
|
|
18
|
+
{title}
|
|
19
|
+
</DialogTitle>
|
|
20
|
+
<DialogHeadings size="xl" sender={sender} recipient={recipient} />
|
|
21
|
+
</DialogHeaderBase>
|
|
22
|
+
);
|
|
23
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import styles from './dialogHeaderBase.module.css';
|
|
3
|
+
|
|
4
|
+
export interface DialogHeaderProps {
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export const DialogHeaderBase = ({ children }: DialogHeaderProps) => {
|
|
9
|
+
return <header className={styles.header}>{children}</header>;
|
|
10
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { DialogHeadings } from './DialogHeadings';
|
|
3
|
+
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'Dialog/DialogHeadings',
|
|
6
|
+
component: DialogHeadings,
|
|
7
|
+
tags: ['autodocs'],
|
|
8
|
+
parameters: {},
|
|
9
|
+
args: {
|
|
10
|
+
sender: {
|
|
11
|
+
name: 'Sender',
|
|
12
|
+
},
|
|
13
|
+
recipient: {
|
|
14
|
+
type: 'person',
|
|
15
|
+
name: 'Recipient',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
} satisfies Meta<typeof DialogHeadings>;
|
|
19
|
+
|
|
20
|
+
export default meta;
|
|
21
|
+
type Story = StoryObj<typeof meta>;
|
|
22
|
+
|
|
23
|
+
export const Default: Story = {};
|
|
24
|
+
|
|
25
|
+
export const Company: Story = {
|
|
26
|
+
args: {
|
|
27
|
+
grouped: true,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const Grouped: Story = {
|
|
32
|
+
args: {
|
|
33
|
+
grouped: true,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Avatar, AvatarGroup, type AvatarSize } from '../Avatar';
|
|
2
|
+
import { MetaItem } from '../Meta';
|
|
3
|
+
import styles from './dialogHeadings.module.css';
|
|
4
|
+
|
|
5
|
+
export type DialogSenderType = 'company' | 'person';
|
|
6
|
+
export type DialogRecipientType = 'company' | 'person';
|
|
7
|
+
|
|
8
|
+
export interface DialogSenderProps {
|
|
9
|
+
type?: DialogSenderType;
|
|
10
|
+
name: string;
|
|
11
|
+
imageUrl?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface DialogRecipientProps {
|
|
15
|
+
type?: DialogRecipientType;
|
|
16
|
+
name: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
type DialogHeadingsSize = 'sm' | 'xs' | 'sm' | 'lg' | 'xl';
|
|
20
|
+
|
|
21
|
+
const sizeMap = {
|
|
22
|
+
avatar: {
|
|
23
|
+
xs: 'xs',
|
|
24
|
+
sm: 'xs',
|
|
25
|
+
md: 'xs',
|
|
26
|
+
lg: 'xs',
|
|
27
|
+
xl: 'lg',
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export interface DialogHeadingsProps {
|
|
32
|
+
size: DialogHeadingsSize;
|
|
33
|
+
/** Group sender and recipient avatars */
|
|
34
|
+
grouped?: boolean;
|
|
35
|
+
/** Sender */
|
|
36
|
+
sender?: DialogSenderProps;
|
|
37
|
+
/** Recipient */
|
|
38
|
+
recipient?: DialogRecipientProps;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Dialog headings for sender and recipient. Should present an avatar for the sender. */
|
|
42
|
+
|
|
43
|
+
export const DialogHeadings = ({
|
|
44
|
+
grouped,
|
|
45
|
+
size = 'lg',
|
|
46
|
+
sender = { type: 'company', name: 'Sender' },
|
|
47
|
+
recipient = { type: 'person', name: 'Recipient' },
|
|
48
|
+
}: DialogHeadingsProps) => {
|
|
49
|
+
return (
|
|
50
|
+
<div className={styles.headings} data-size={size}>
|
|
51
|
+
{grouped ? (
|
|
52
|
+
<AvatarGroup
|
|
53
|
+
items={[{ ...sender, type: 'company' }, recipient]}
|
|
54
|
+
size={sizeMap?.avatar[size] as AvatarSize}
|
|
55
|
+
className={styles.avatar}
|
|
56
|
+
/>
|
|
57
|
+
) : (
|
|
58
|
+
<Avatar
|
|
59
|
+
type="company"
|
|
60
|
+
imageUrl={sender?.imageUrl}
|
|
61
|
+
name={sender.name}
|
|
62
|
+
size={sizeMap?.avatar[size] as AvatarSize}
|
|
63
|
+
className={styles.avatar}
|
|
64
|
+
/>
|
|
65
|
+
)}
|
|
66
|
+
<MetaItem size="xs" className={styles.text}>
|
|
67
|
+
<span className={styles.sender}>{sender.name}</span>
|
|
68
|
+
{recipient?.name && (
|
|
69
|
+
<span>
|
|
70
|
+
{' til '}
|
|
71
|
+
<span>{recipient.name}</span>
|
|
72
|
+
</span>
|
|
73
|
+
)}
|
|
74
|
+
</MetaItem>
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
};
|