@altinn/altinn-components 0.4.1 → 0.5.1

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 (194) hide show
  1. package/.storybook/StoryDecorator.tsx +1 -1
  2. package/.storybook/main.ts +3 -4
  3. package/.storybook/preview.tsx +28 -0
  4. package/CHANGELOG.md +14 -0
  5. package/biome.jsonc +1 -1
  6. package/lib/components/Attachment/AttachmentLink.stories.ts +1 -1
  7. package/lib/components/Attachment/AttachmentList.stories.ts +1 -1
  8. package/lib/components/Button/Button.tsx +13 -10
  9. package/lib/components/Button/ButtonBase.tsx +1 -1
  10. package/lib/components/Button/ButtonIcon.tsx +16 -0
  11. package/lib/components/Button/ButtonLabel.tsx +18 -0
  12. package/lib/components/Button/Buttons.stories.tsx +64 -0
  13. package/lib/components/Button/ComboButton.tsx +9 -7
  14. package/lib/components/Button/IconButton.stories.tsx +47 -0
  15. package/lib/components/Button/IconButton.tsx +15 -5
  16. package/lib/components/Button/button.module.css +5 -46
  17. package/lib/components/Button/buttonBase.module.css +55 -23
  18. package/lib/components/Button/buttonIcon.module.css +17 -0
  19. package/lib/components/Button/buttonLabel.module.css +17 -0
  20. package/lib/components/Button/comboButton.module.css +15 -65
  21. package/lib/components/Button/iconButton.module.css +21 -4
  22. package/lib/components/Button/index.ts +2 -0
  23. package/lib/components/ContextMenu/ContextMenu.stories.ts +49 -0
  24. package/lib/components/ContextMenu/ContextMenu.tsx +12 -20
  25. package/lib/components/ContextMenu/ContextMenuBase.tsx +33 -0
  26. package/lib/components/Dialog/Dialog.stories.ts +12 -5
  27. package/lib/components/Dialog/Dialog.tsx +2 -0
  28. package/lib/components/Dialog/DialogGroup.tsx +24 -0
  29. package/lib/components/Dialog/DialogList.stories.ts +14 -10
  30. package/lib/components/Dialog/DialogList.tsx +26 -11
  31. package/lib/components/Dialog/DialogListItem.tsx +12 -2
  32. package/lib/components/Dialog/DialogListItemBase.tsx +4 -2
  33. package/lib/components/Dialog/DialogNav.stories.ts +5 -5
  34. package/lib/components/Dialog/DialogNav.tsx +2 -6
  35. package/lib/components/Dialog/DialogSelect.tsx +1 -1
  36. package/lib/components/Dialog/dialogGroup.module.css +35 -0
  37. package/lib/components/Dropdown/Backdrop.tsx +4 -3
  38. package/lib/components/Dropdown/DrawerBase.tsx +5 -2
  39. package/lib/components/Dropdown/DrawerBody.tsx +12 -0
  40. package/lib/components/Dropdown/DrawerButton.tsx +17 -0
  41. package/lib/components/Dropdown/DrawerFooter.tsx +12 -0
  42. package/lib/components/Dropdown/DrawerHeader.tsx +19 -0
  43. package/lib/components/Dropdown/DrawerOrDropdown.tsx +29 -0
  44. package/lib/components/Dropdown/DropdownBase.tsx +17 -2
  45. package/lib/components/Dropdown/backdrop.module.css +3 -0
  46. package/lib/components/Dropdown/drawerBase.module.css +9 -0
  47. package/lib/components/Dropdown/drawerBody.module.css +5 -0
  48. package/lib/components/Dropdown/drawerButton.module.css +6 -0
  49. package/lib/components/Dropdown/drawerFooter.module.css +13 -0
  50. package/lib/components/Dropdown/drawerHeader.module.css +17 -0
  51. package/lib/components/Dropdown/drawerOrDropdown.module.css +19 -0
  52. package/lib/components/Dropdown/dropdownBase.module.css +20 -4
  53. package/lib/components/Dropdown/index.ts +7 -1
  54. package/lib/components/Footer/footerMenu.module.css +5 -0
  55. package/lib/components/GlobalMenu/AccountButton.tsx +29 -0
  56. package/lib/components/GlobalMenu/AccountMenu.stories.tsx +65 -0
  57. package/lib/components/GlobalMenu/AccountMenu.tsx +73 -0
  58. package/lib/components/GlobalMenu/BackButton.tsx +10 -0
  59. package/lib/components/GlobalMenu/GlobalMenu.stories.tsx +112 -121
  60. package/lib/components/GlobalMenu/GlobalMenu.tsx +41 -89
  61. package/lib/components/GlobalMenu/GlobalMenuBase.tsx +22 -0
  62. package/lib/components/GlobalMenu/LogoutButton.tsx +19 -0
  63. package/lib/components/GlobalMenu/globalMenuBase.module.css +39 -0
  64. package/lib/components/GlobalMenu/index.tsx +1 -1
  65. package/lib/components/GlobalMenu/logoutButton.module.css +9 -0
  66. package/lib/components/Header/{Header.stories.ts → Header.stories.tsx} +79 -20
  67. package/lib/components/Header/Header.tsx +25 -38
  68. package/lib/components/Header/HeaderBase.tsx +7 -3
  69. package/lib/components/Header/header.module.css +10 -42
  70. package/lib/components/Header/headerBase.module.css +43 -0
  71. package/lib/components/Header/headerButton.module.css +1 -0
  72. package/lib/components/Layout/Layout.stories.tsx +77 -38
  73. package/lib/components/Layout/Layout.tsx +5 -3
  74. package/lib/components/Layout/LayoutBase.tsx +3 -2
  75. package/lib/components/Layout/layoutBase.module.css +11 -0
  76. package/lib/components/Layout/layoutBody.module.css +1 -0
  77. package/lib/components/LayoutAction/ActionHeader.tsx +1 -1
  78. package/lib/components/LayoutAction/ActionMenu.tsx +2 -4
  79. package/lib/components/LayoutAction/actionMenu.module.css +3 -0
  80. package/lib/components/List/List.stories.tsx +43 -0
  81. package/lib/components/List/List.tsx +6 -6
  82. package/lib/components/List/ListBase.tsx +6 -6
  83. package/lib/components/List/ListItem.tsx +4 -1
  84. package/lib/components/List/ListItemBase.tsx +20 -4
  85. package/lib/components/List/listBase.module.css +3 -3
  86. package/lib/components/List/listItemBase.module.css +4 -0
  87. package/lib/components/Menu/Menu.stories.ts +46 -46
  88. package/lib/components/Menu/Menu.tsx +3 -102
  89. package/lib/components/Menu/MenuBase.tsx +47 -3
  90. package/lib/components/Menu/MenuItem.tsx +8 -4
  91. package/lib/components/Menu/MenuItemBase.tsx +15 -2
  92. package/lib/components/Menu/MenuItems.stories.ts +438 -0
  93. package/lib/components/Menu/MenuItems.tsx +96 -0
  94. package/lib/components/Menu/MenuOption.tsx +4 -1
  95. package/lib/components/Menu/index.ts +1 -1
  96. package/lib/components/Menu/menu.module.css +2 -3
  97. package/lib/components/Menu/menuBase.module.css +25 -0
  98. package/lib/components/Menu/menuItemBase.module.css +11 -5
  99. package/lib/components/Menu/menuItemLabel.module.css +11 -1
  100. package/lib/components/Menu/menuSearch.module.css +1 -0
  101. package/lib/components/Meta/MetaItemBase.tsx +1 -1
  102. package/lib/components/Meta/MetaItemLabel.tsx +1 -1
  103. package/lib/components/Meta/MetaItemMedia.tsx +1 -1
  104. package/lib/components/Page/PageBase.tsx +14 -0
  105. package/lib/components/Page/PageHeader.tsx +21 -0
  106. package/lib/components/Page/PageHeaderMedia.tsx +25 -0
  107. package/lib/components/Page/SectionBase.tsx +52 -0
  108. package/lib/components/Page/SectionFooter.tsx +15 -0
  109. package/lib/components/Page/SectionHeader.tsx +16 -0
  110. package/lib/components/Page/index.ts +5 -0
  111. package/lib/components/Page/pageHeader.module.css +5 -0
  112. package/lib/components/Page/sectionBase.module.css +82 -0
  113. package/lib/components/Page/sectionFooter.module.css +8 -0
  114. package/lib/components/Page/sectionHeader.module.css +9 -0
  115. package/lib/components/RootProvider/RootProvider.tsx +43 -7
  116. package/lib/components/Searchbar/Autocomplete.stories.tsx +77 -0
  117. package/lib/components/Searchbar/Autocomplete.tsx +44 -0
  118. package/lib/components/Searchbar/AutocompleteBase.tsx +16 -0
  119. package/lib/components/Searchbar/AutocompleteGroup.tsx +17 -0
  120. package/lib/components/Searchbar/AutocompleteItem.tsx +23 -0
  121. package/lib/components/Searchbar/SearchField.tsx +78 -0
  122. package/lib/components/Searchbar/Searchbar.stories.tsx +151 -0
  123. package/lib/components/Searchbar/Searchbar.tsx +18 -0
  124. package/lib/components/Searchbar/SearchbarBase.tsx +23 -0
  125. package/lib/components/Searchbar/autocompleteBase.module.css +17 -0
  126. package/lib/components/Searchbar/autocompleteGroup.module.css +3 -0
  127. package/lib/components/Searchbar/autocompleteItem.module.css +19 -0
  128. package/lib/components/Searchbar/index.ts +1 -0
  129. package/lib/components/Searchbar/searchField.module.css +54 -0
  130. package/lib/components/Searchbar/searchbarBase.module.css +20 -0
  131. package/lib/components/Toolbar/Toolbar.stories.tsx +10 -10
  132. package/lib/components/Toolbar/Toolbar.tsx +28 -10
  133. package/lib/components/Toolbar/ToolbarAdd.tsx +6 -5
  134. package/lib/components/Toolbar/ToolbarBase.tsx +5 -20
  135. package/lib/components/Toolbar/ToolbarButton.tsx +1 -1
  136. package/lib/components/Toolbar/ToolbarFilter.tsx +11 -6
  137. package/lib/components/Toolbar/ToolbarMenu.tsx +8 -7
  138. package/lib/components/Toolbar/ToolbarOptions.stories.ts +5 -5
  139. package/lib/components/Toolbar/ToolbarOptions.tsx +34 -21
  140. package/lib/components/Toolbar/toolbarAdd.module.css +7 -0
  141. package/lib/components/Toolbar/toolbarBase.module.css +19 -0
  142. package/lib/components/Toolbar/toolbarButton.module.css +1 -1
  143. package/lib/components/Toolbar/toolbarFilter.module.css +25 -0
  144. package/lib/components/Toolbar/toolbarMenu.module.css +7 -0
  145. package/lib/components/Typography/Heading.tsx +23 -0
  146. package/lib/components/Typography/Typography.tsx +8 -5
  147. package/lib/components/Typography/heading.module.css +21 -0
  148. package/lib/components/Typography/index.ts +1 -0
  149. package/lib/components/Typography/typography.module.css +8 -0
  150. package/lib/components/index.ts +2 -0
  151. package/lib/hooks/index.ts +3 -0
  152. package/lib/{components/Menu → hooks}/useEscapeKey.ts +2 -2
  153. package/lib/hooks/useMenu.tsx +80 -0
  154. package/lib/index.ts +1 -0
  155. package/lib/stories/Color/MenuItem.stories.tsx +43 -0
  156. package/lib/stories/Color/Swatches.stories.tsx +19 -0
  157. package/lib/stories/Color/Swatches.tsx +42 -0
  158. package/lib/stories/Color/colors.json +62 -0
  159. package/lib/stories/Color/swatches.module.css +14 -0
  160. package/lib/stories/Inbox/BookmarksPage.tsx +52 -0
  161. package/lib/stories/Inbox/DialogPage.tsx +15 -0
  162. package/lib/stories/Inbox/Inbox.stories.tsx +55 -0
  163. package/lib/stories/Inbox/Inbox.tsx +12 -0
  164. package/lib/stories/Inbox/InboxLayout.tsx +50 -0
  165. package/lib/stories/Inbox/InboxPage.tsx +50 -0
  166. package/lib/stories/Inbox/InboxProvider.tsx +136 -0
  167. package/lib/stories/Inbox/InboxSection.tsx +39 -0
  168. package/lib/stories/Inbox/InboxToolbar.tsx +94 -0
  169. package/lib/stories/Inbox/ProfilePage.tsx +35 -0
  170. package/lib/stories/Inbox/SettingsPage.tsx +19 -0
  171. package/lib/stories/Inbox/accounts/accounts.ts +24 -0
  172. package/lib/stories/Inbox/accounts/index.ts +1 -0
  173. package/lib/stories/Inbox/actionMenu.ts +24 -0
  174. package/lib/stories/Inbox/dialogs/brreg-completed.json +35 -0
  175. package/lib/stories/Inbox/dialogs/brreg-draft.json +45 -0
  176. package/lib/stories/Inbox/dialogs/index.ts +10 -0
  177. package/lib/stories/Inbox/dialogs/skatt-2023.json +33 -0
  178. package/lib/stories/Inbox/groupBy.ts +19 -0
  179. package/lib/stories/Inbox/inboxSection.module.css +19 -0
  180. package/lib/stories/Inbox/index.ts +15 -0
  181. package/lib/stories/Inbox/layout/footer.ts +27 -0
  182. package/lib/stories/Inbox/layout/header.ts +11 -0
  183. package/lib/stories/Inbox/layout/index.ts +3 -0
  184. package/lib/stories/Inbox/layout/menu.ts +64 -0
  185. package/package.json +15 -13
  186. package/tsconfig.json +7 -2
  187. package/lib/components/Header/HeaderSearch.stories.ts +0 -20
  188. package/lib/components/Header/HeaderSearch.tsx +0 -44
  189. package/lib/components/Header/headerSearch.module.css +0 -30
  190. package/lib/components/Menu/MenuGroup.tsx +0 -18
  191. package/lib/components/Menu/__menuItem.module.css +0 -130
  192. package/lib/components/Toolbar/toolbar.module.css +0 -43
  193. /package/lib/components/ContextMenu/{contextMenu.module.css → contextMenuBase.module.css} +0 -0
  194. /package/lib/{components/Menu → hooks}/useClickOutside.ts +0 -0
@@ -2,84 +2,34 @@
2
2
  display: inline-flex;
3
3
  flex-direction: row-reverse;
4
4
  align-items: center;
5
- border: 1px solid;
6
5
  border-radius: 2px;
7
6
  }
8
7
 
9
- /*
10
- .button[aria-selected="true"] {
11
- background-color: var(--theme-background-subtle);
12
- color: var(--theme-text-default);
13
- }
14
- */
15
-
16
- .label {
17
- line-height: 1rem;
18
- font-weight: 600;
19
- }
20
-
21
8
  .divider {
9
+ align-self: stretch;
22
10
  border-left: 1px solid currentColor;
23
11
  width: 1px;
24
- height: 1em;
12
+ margin: 0.375rem 0;
25
13
  }
26
14
 
27
- .icon {
28
- display: flex;
15
+ .primary,
16
+ .secondary {
17
+ display: inline-flex;
29
18
  align-items: center;
30
- justify-content: center;
31
- }
32
-
33
- /* variant */
34
-
35
- .button[data-variant="solid"] {
36
- border-color: var(--theme-base-hover);
37
- background-color: var(--theme-base-hover);
38
- color: white;
39
- }
40
-
41
- /* sm 36px */
42
-
43
- .label[data-size="sm"] {
44
- font-size: 0.875rem;
45
- padding: 8px 10px;
19
+ border: none;
46
20
  }
47
21
 
48
- .divider[data-size="sm"] {
49
- height: 20px;
50
- }
51
-
52
- .icon[data-size="sm"] {
53
- font-size: 1.25rem;
54
- padding: 6px 5px;
55
- }
56
-
57
- /* md 44px */
58
-
59
- .button[data-size="md"] {
60
- font-size: 1rem;
61
- }
62
-
63
- .label[data-size="md"] {
64
- padding: 10px;
65
- }
66
-
67
- .icon[data-size="md"] {
68
- font-size: 1.25rem;
69
- padding: 12px 8px;
70
- }
71
-
72
- /* lg 56 */
73
-
74
- .button[data-size="lg"] {
75
- font-size: 1.125rem;
22
+ .primary[data-size="sm"],
23
+ .secondary[data-size="sm"] {
24
+ padding: 0 0.375rem;
76
25
  }
77
26
 
78
- .label[data-size="lg"] {
79
- padding: 1rem;
27
+ .primary[data-size="md"],
28
+ .secondary[data-size="md"] {
29
+ padding: 0 0.5rem;
80
30
  }
81
31
 
82
- .icon[data-size="lg"] {
83
- font-size: 1.5rem;
84
- padding: 16px 10px;
32
+ .primary[data-size="lg"],
33
+ .secondary[data-size="lg"] {
34
+ padding: 0 0.625rem;
85
35
  }
@@ -1,7 +1,4 @@
1
1
  .button {
2
- border: 1px solid;
3
- width: 2.75rem;
4
- height: 2.75rem;
5
2
  display: flex;
6
3
  align-items: center;
7
4
  justify-content: center;
@@ -10,5 +7,25 @@
10
7
 
11
8
  .icon {
12
9
  font-size: 1.5rem;
13
- margin: 0.625rem;
10
+ }
11
+
12
+ /* sm 36 */
13
+
14
+ .button[data-size="sm"] {
15
+ width: 2.25rem;
16
+ height: 2.25rem;
17
+ }
18
+
19
+ /* md 44 */
20
+
21
+ .button[data-size="md"] {
22
+ width: 2.75rem;
23
+ height: 2.75rem;
24
+ }
25
+
26
+ /* lg 56 */
27
+
28
+ .button[data-size="lg"] {
29
+ width: 3.5rem;
30
+ height: 3.5rem;
14
31
  }
@@ -1,4 +1,6 @@
1
1
  export * from './ButtonBase';
2
+ export * from './ButtonLabel';
3
+ export * from './ButtonIcon';
2
4
  export * from './Button';
3
5
  export * from './ComboButton';
4
6
  export * from './IconButton';
@@ -0,0 +1,49 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { ContextMenu } from './ContextMenu';
3
+
4
+ const meta = {
5
+ title: 'ContextMenu/ContextMenu',
6
+ component: ContextMenu,
7
+ tags: ['autodocs'],
8
+ parameters: {},
9
+ args: {
10
+ placement: 'left',
11
+ items: [
12
+ {
13
+ id: '1',
14
+ groupId: '1',
15
+ icon: 'arrow-redo',
16
+ label: 'Del og gi tilgang',
17
+ },
18
+ {
19
+ id: '2',
20
+ groupId: '1',
21
+ icon: 'eye-closed',
22
+ label: 'Marker som ny',
23
+ },
24
+ {
25
+ id: '3',
26
+ groupId: '2',
27
+ icon: 'archive',
28
+ label: 'Flytt til arkiv',
29
+ },
30
+ {
31
+ id: '4',
32
+ groupId: '2',
33
+ icon: 'trash',
34
+ label: 'Flytt til papirkurv',
35
+ },
36
+ {
37
+ id: '5',
38
+ groupId: '3',
39
+ icon: 'clock-dashed',
40
+ label: 'Aktivitetslogg',
41
+ },
42
+ ],
43
+ },
44
+ } satisfies Meta<typeof ContextMenu>;
45
+
46
+ export default meta;
47
+ type Story = StoryObj<typeof meta>;
48
+
49
+ export const Default: Story = {};
@@ -1,28 +1,20 @@
1
- import type { MouseEventHandler } from 'react';
2
- import { ButtonBase } from '../Button';
3
- import { Icon } from '../Icon';
4
- import { Menu, type MenuGroups, type MenuItemProps } from '../Menu';
5
- import styles from './contextMenu.module.css';
1
+ import type { DropdownPlacement, MenuItemProps } from '../';
2
+ import { type MenuItemGroups, MenuItems } from '../';
3
+ import { useRootContext } from '../RootProvider';
4
+ import { ContextMenuBase } from './ContextMenuBase';
6
5
 
7
6
  export interface ContextMenuProps {
8
- onToggle?: MouseEventHandler;
9
- label: string;
10
- value: string | number;
7
+ id: string;
11
8
  items: MenuItemProps[];
12
- groups?: MenuGroups;
13
- expanded?: boolean;
14
- className?: string;
9
+ placement?: DropdownPlacement;
10
+ groups?: MenuItemGroups;
15
11
  }
16
12
 
17
- export const ContextMenu = ({ expanded = true, onToggle, groups = {}, items }: ContextMenuProps) => {
13
+ export const ContextMenu = ({ id = 'context-menu', placement = 'right', groups = {}, items }: ContextMenuProps) => {
14
+ const { currentId, toggleId } = useRootContext();
18
15
  return (
19
- <div className={styles.toggle}>
20
- <ButtonBase className={styles.button} as="button" color="secondary" onClick={onToggle}>
21
- <Icon className={styles.icon} name="menu-elipsis-horizontal" />
22
- </ButtonBase>
23
- <div className={styles.dropdown} aria-expanded={expanded}>
24
- <Menu theme="global" defaultItemColor="subtle" groups={groups} items={items} />
25
- </div>
26
- </div>
16
+ <ContextMenuBase placement={placement} expanded={currentId === id} onToggle={() => toggleId(id)}>
17
+ <MenuItems groups={groups} items={items} />
18
+ </ContextMenuBase>
27
19
  );
28
20
  };
@@ -0,0 +1,33 @@
1
+ import type { ReactNode } from 'react';
2
+ import { DropdownBase, IconButton } from '../';
3
+ import type { DropdownPlacement } from '../';
4
+ import styles from './contextMenuBase.module.css';
5
+
6
+ export interface ContextMenuBaseProps {
7
+ placement: DropdownPlacement;
8
+ expanded: boolean;
9
+ onToggle?: () => void;
10
+ children?: ReactNode;
11
+ }
12
+
13
+ export const ContextMenuBase = ({
14
+ placement = 'right',
15
+ expanded = false,
16
+ onToggle,
17
+ children,
18
+ }: ContextMenuBaseProps) => {
19
+ return (
20
+ <div className={styles.toggle}>
21
+ <IconButton
22
+ className={styles.button}
23
+ icon="menu-elipsis-horizontal"
24
+ variant="text"
25
+ color="secondary"
26
+ onClick={onToggle}
27
+ />
28
+ <DropdownBase className={styles.dropdown} placement={placement} expanded={expanded}>
29
+ {children}
30
+ </DropdownBase>
31
+ </div>
32
+ );
33
+ };
@@ -8,11 +8,15 @@ const meta = {
8
8
  parameters: {},
9
9
  argTypes: { body: { control: 'text' } },
10
10
  args: {
11
- menu: [
12
- {
13
- items: [{ label: 'Menu 1' }],
14
- },
15
- ],
11
+ menu: {
12
+ id: 'context-menu',
13
+ items: [
14
+ {
15
+ label: 'Fjern',
16
+ id: 'remove',
17
+ },
18
+ ],
19
+ },
16
20
  updatedAt: '1999-05-26',
17
21
  updatedAtLabel: '26. mai 1999',
18
22
  title: 'Title',
@@ -42,9 +46,11 @@ export const Attachments: Story = {
42
46
  items: [
43
47
  {
44
48
  label: 'Dokument 1.pdf',
49
+ href: '',
45
50
  },
46
51
  {
47
52
  label: 'Dokument 2.pdf',
53
+ href: '',
48
54
  },
49
55
  ],
50
56
  },
@@ -106,6 +112,7 @@ export const Example: Story = {
106
112
  items: [
107
113
  {
108
114
  label: 'Vedtak om innlevering av bedriftsdata.pdf',
115
+ href: '',
109
116
  },
110
117
  ],
111
118
  },
@@ -19,6 +19,8 @@ import { type DialogBackButtonProps, DialogNav } from './DialogNav';
19
19
  import type { DialogStatusProps } from './DialogStatus';
20
20
 
21
21
  export interface DialogProps {
22
+ /** Dialog id */
23
+ id: string;
22
24
  /** Title */
23
25
  title: string;
24
26
  /** Back button */
@@ -0,0 +1,24 @@
1
+ import type { ReactNode } from 'react';
2
+ import { Heading, ListBase, SectionBase, SectionHeader } from '../';
3
+ import { Button } from '../Button';
4
+
5
+ export interface DialogGroupProps {
6
+ title?: string;
7
+ children?: ReactNode;
8
+ }
9
+
10
+ export const DialogGroup = ({ title, children }: DialogGroupProps) => {
11
+ return (
12
+ <SectionBase spacing="md">
13
+ {title && (
14
+ <SectionHeader padding margin>
15
+ <Heading>{title}</Heading>
16
+ <Button variant="text" icon="checkmark" size="sm" reverse>
17
+ Velg alle
18
+ </Button>
19
+ </SectionHeader>
20
+ )}
21
+ <ListBase spacing="md">{children}</ListBase>
22
+ </SectionBase>
23
+ );
24
+ };
@@ -1,6 +1,4 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react';
2
- import { fn } from '@storybook/test';
3
-
4
2
  import { DialogList } from './DialogList';
5
3
 
6
4
  const meta = {
@@ -16,26 +14,31 @@ const meta = {
16
14
  title: 'Støtte til utbygging av solceller',
17
15
  summary: 'Din støtte er innvilget',
18
16
  status: { value: 'draft' },
17
+ groupId: '2024-01',
19
18
  },
20
19
  {
21
20
  title: 'Støtte til utbygging av solceller',
22
21
  summary: 'Din støtte er innvilget',
23
22
  status: { value: 'sent' },
23
+ groupId: '2024-02',
24
24
  },
25
25
  {
26
26
  title: 'Støtte til utbygging av solceller',
27
27
  summary: 'Din støtte er innvilget',
28
28
  status: { value: 'requires-attention' },
29
+ groupId: '2024-01',
29
30
  },
30
31
  {
31
32
  title: 'Støtte til utbygging av solceller',
32
33
  summary: 'Din støtte er innvilget',
33
34
  status: { value: 'in-progress' },
35
+ groupId: '2024-02',
34
36
  },
35
37
  {
36
38
  title: 'Støtte til utbygging av solceller',
37
39
  summary: 'Din støtte er innvilget.',
38
40
  status: { value: 'completed' },
41
+ groupId: '2024-01',
39
42
  },
40
43
  ],
41
44
  },
@@ -48,14 +51,15 @@ export const Default: Story = {
48
51
  args: {},
49
52
  };
50
53
 
51
- export const Company: Story = {
54
+ export const Grouped: Story = {
52
55
  args: {
53
- theme: 'company',
54
- },
55
- };
56
-
57
- export const Person: Story = {
58
- args: {
59
- theme: 'person',
56
+ groups: {
57
+ '2024-01': {
58
+ title: 'Januar 2024',
59
+ },
60
+ '2024-02': {
61
+ title: 'Februar 2024',
62
+ },
63
+ },
60
64
  },
61
65
  };
@@ -1,20 +1,35 @@
1
- import type { LayoutTheme } from '../Layout';
2
- import { ListBase } from '../List';
1
+ import { SectionBase } from '../';
2
+ import { useMenu } from '../../hooks';
3
+ import { DialogGroup, type DialogGroupProps } from './DialogGroup';
3
4
  import { DialogListItem, type DialogListItemProps } from './DialogListItem';
4
- import type { DialogListItemSize } from './DialogListItemBase';
5
5
 
6
6
  export interface DialogListProps {
7
- size?: DialogListItemSize;
8
- theme?: LayoutTheme;
9
- items?: DialogListItemProps[];
7
+ items: DialogListItemProps[];
8
+ groups?: Record<string, DialogGroupProps>;
10
9
  }
11
10
 
12
- export const DialogList = ({ theme, size = 'md', items }: DialogListProps) => {
11
+ export const DialogList = ({ items, groups = {} }: DialogListProps) => {
12
+ const { menu } = useMenu<DialogListItemProps, DialogGroupProps>({
13
+ items,
14
+ groups,
15
+ groupByKey: 'groupId',
16
+ keyboardEvents: false,
17
+ });
18
+
13
19
  return (
14
- <ListBase theme={theme} size={size}>
15
- {items?.map((item, index) => {
16
- return <DialogListItem {...item} size={size} key={'item' + index} />;
20
+ <SectionBase spacing="none" margin="md">
21
+ {menu?.map((group, groupIndex) => {
22
+ const groupProps = group.props || {};
23
+
24
+ return (
25
+ <DialogGroup {...groupProps} key={groupIndex}>
26
+ {group?.items.map((item, index) => {
27
+ const itemProps = item.props || {};
28
+ return <DialogListItem {...itemProps} key={index} />;
29
+ })}
30
+ </DialogGroup>
31
+ );
17
32
  })}
18
- </ListBase>
33
+ </SectionBase>
19
34
  );
20
35
  };
@@ -55,6 +55,8 @@ export type DialogListItemProps = {
55
55
  attachmentsCount?: number;
56
56
  /** OnClick handler */
57
57
  onClick?: () => void;
58
+ /** Group id */
59
+ groupId?: string;
58
60
  };
59
61
 
60
62
  /**
@@ -68,6 +70,7 @@ export const DialogListItem = ({
68
70
  size = 'lg',
69
71
  variant = 'neutral',
70
72
  href,
73
+ onClick,
71
74
  select,
72
75
  selected,
73
76
  status,
@@ -84,10 +87,17 @@ export const DialogListItem = ({
84
87
  attachmentsCount,
85
88
  title,
86
89
  summary,
87
- ...rest
88
90
  }: DialogListItemProps) => {
89
91
  return (
90
- <DialogListItemBase as={as} size={size} href={href} select={select} selected={selected} variant={variant} {...rest}>
92
+ <DialogListItemBase
93
+ as={as}
94
+ size={size}
95
+ href={href}
96
+ select={select}
97
+ selected={selected}
98
+ variant={variant}
99
+ onClick={onClick}
100
+ >
91
101
  <DialogBorder className={styles.border} size={size} seen={seen}>
92
102
  <header data-size={size} className={styles.header}>
93
103
  <DialogTitle size={size} seen={seen} variant={variant}>
@@ -20,6 +20,8 @@ export type DialogListItemBaseProps = {
20
20
  children?: ReactNode;
21
21
  /** Variant */
22
22
  variant?: DialogListItemVariant;
23
+ /** OnClick handler */
24
+ onClick?: () => void;
23
25
  };
24
26
 
25
27
  /**
@@ -35,13 +37,13 @@ export const DialogListItemBase = ({
35
37
  select,
36
38
  selected,
37
39
  children,
38
- ...rest
40
+ onClick,
39
41
  }: DialogListItemBaseProps) => {
40
42
  const Component = as || 'button';
41
43
 
42
44
  return (
43
45
  <article className={styles.item} data-size={size} aria-selected={selected}>
44
- <Component className={styles.link} data-size={size} href={href} {...rest}>
46
+ <Component className={styles.link} data-size={size} href={href} onClick={onClick} tabIndex={0}>
45
47
  {children}
46
48
  </Component>
47
49
  {select && <DialogSelect className={styles.select} {...select} />}
@@ -54,31 +54,31 @@ export const ContextMenu: Story = {
54
54
  items: [
55
55
  {
56
56
  id: '1',
57
- group: '1',
57
+ groupId: '1',
58
58
  icon: 'arrow-redo',
59
59
  label: 'Del og gi tilgang',
60
60
  },
61
61
  {
62
62
  id: '2',
63
- group: '1',
63
+ groupId: '1',
64
64
  icon: 'eye-closed',
65
65
  label: 'Marker som ny',
66
66
  },
67
67
  {
68
68
  id: '3',
69
- group: '2',
69
+ groupId: '2',
70
70
  icon: 'archive',
71
71
  label: 'Flytt til arkiv',
72
72
  },
73
73
  {
74
74
  id: '4',
75
- group: '2',
75
+ groupId: '2',
76
76
  icon: 'trash',
77
77
  label: 'Flytt til papirkurv',
78
78
  },
79
79
  {
80
80
  id: '5',
81
- group: '3',
81
+ groupId: '3',
82
82
  icon: 'clock-dashed',
83
83
  label: 'Aktivitetslogg',
84
84
  },
@@ -1,8 +1,7 @@
1
1
  'use client';
2
- import { useState } from 'react';
3
2
  import type { ElementType } from 'react';
4
3
  import { Button } from '../Button';
5
- import { ContextMenu, type ContextMenuProps } from '../ContextMenu/ContextMenu.tsx';
4
+ import { ContextMenu, type ContextMenuProps } from '../ContextMenu';
6
5
  import { MetaTimestamp } from '../Meta';
7
6
  import { DialogStatus, type DialogStatusProps } from './DialogStatus';
8
7
  import { DialogTouchedBy, type DialogTouchedByActor } from './DialogTouchedBy';
@@ -37,9 +36,6 @@ export const DialogNav = ({
37
36
  touchedBy,
38
37
  menu,
39
38
  }: DialogNavProps) => {
40
- const [expandedItem, setexpandedItem] = useState<boolean>(false);
41
- const onToggle = () => setexpandedItem((expanded) => !expanded);
42
-
43
39
  return (
44
40
  <nav className={styles.nav}>
45
41
  <Button {...backButton} variant="text" color="secondary" icon="arrow-left" reverse>
@@ -53,7 +49,7 @@ export const DialogNav = ({
53
49
  )}
54
50
  {status && <DialogStatus {...status} />}
55
51
  {touchedBy && <DialogTouchedBy touchedBy={touchedBy} />}
56
- {menu && <ContextMenu {...menu} expanded={expandedItem} onToggle={onToggle} />}
52
+ {menu && <ContextMenu {...menu} />}
57
53
  </div>
58
54
  </nav>
59
55
  );
@@ -16,7 +16,7 @@ export type DialogSelectProps = {
16
16
  export const DialogSelect = ({ checked = false, onChange, className }: DialogSelectProps) => {
17
17
  return (
18
18
  <label className={cx(styles.label, className)}>
19
- <input type="checkbox" checked={checked} onChange={onChange} className={styles.input} />
19
+ <input type="checkbox" checked={checked} onChange={onChange} className={styles.input} tabIndex={-1} />
20
20
  <CheckboxIcon hover={true} checked={checked} className={styles.icon} />
21
21
  </label>
22
22
  );
@@ -0,0 +1,35 @@
1
+ .section {
2
+ display: flex;
3
+ flex-direction: column;
4
+ row-gap: 0.5rem;
5
+ margin: 0.5rem 0;
6
+ }
7
+
8
+ .header {
9
+ display: flex;
10
+ justify-content: space-between;
11
+ margin: 0.5rem 0;
12
+ }
13
+
14
+ .title {
15
+ font-size: 1.25rem;
16
+ font-weight: 500;
17
+ line-height: 1.5rem;
18
+ margin: 0.375rem 0;
19
+ }
20
+
21
+ .title {
22
+ padding: 0 1rem;
23
+ }
24
+
25
+ @media (min-width: 1024px) {
26
+ .title {
27
+ padding: 0;
28
+ }
29
+ }
30
+
31
+ .list {
32
+ display: flex;
33
+ flex-direction: column;
34
+ row-gap: 0.5rem;
35
+ }
@@ -1,11 +1,12 @@
1
1
  import cx from 'classnames';
2
+ import type { MouseEventHandler } from 'react';
2
3
  import styles from './backdrop.module.css';
3
4
 
4
5
  export interface BackdropProps {
5
- expanded?: boolean;
6
6
  className?: string;
7
+ onClick?: MouseEventHandler;
7
8
  }
8
9
 
9
- export const Backdrop = ({ expanded = false, className }: BackdropProps) => {
10
- return <div className={cx(styles.backdrop, className)} aria-expanded={expanded} />;
10
+ export const Backdrop = ({ className, onClick }: BackdropProps) => {
11
+ return <div className={cx(styles.backdrop, className)} onMouseDown={onClick} />;
11
12
  };
@@ -2,15 +2,18 @@ import cx from 'classnames';
2
2
  import type { ReactNode } from 'react';
3
3
  import styles from './drawerBase.module.css';
4
4
 
5
+ export type DrawerPlacement = 'inline' | 'bottom';
6
+
5
7
  export interface DrawerBaseProps {
8
+ placement?: DrawerPlacement;
6
9
  expanded?: boolean;
7
10
  className?: string;
8
11
  children?: ReactNode;
9
12
  }
10
13
 
11
- export const DrawerBase = ({ expanded = false, className, children }: DrawerBaseProps) => {
14
+ export const DrawerBase = ({ placement = 'inline', expanded = false, className, children }: DrawerBaseProps) => {
12
15
  return (
13
- <div className={cx(styles.drawer, className)} aria-expanded={expanded}>
16
+ <div className={cx(styles.drawer, className)} data-placement={placement} aria-expanded={expanded}>
14
17
  {children}
15
18
  </div>
16
19
  );
@@ -0,0 +1,12 @@
1
+ import cx from 'classnames';
2
+ import type { ReactNode } from 'react';
3
+ import styles from './drawerBody.module.css';
4
+
5
+ export interface DrawerBodyProps {
6
+ className?: string;
7
+ children?: ReactNode;
8
+ }
9
+
10
+ export const DrawerBody = ({ className, children }: DrawerBodyProps) => {
11
+ return <div className={cx(styles.body, className)}>{children}</div>;
12
+ };