@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
@@ -1,83 +1,70 @@
1
1
  'use client';
2
- import cx from 'classnames';
3
- import { useState } from 'react';
4
- import { Backdrop, DrawerBase, DropdownBase } from '../Dropdown';
2
+ import { useEscapeKey } from '../../hooks';
3
+ import { DrawerBase, DropdownBase } from '../Dropdown';
5
4
  import { GlobalMenu, type GlobalMenuProps } from '../GlobalMenu';
5
+ import { useRootContext } from '../RootProvider';
6
+ import { Searchbar, type SearchbarProps } from '../Searchbar';
6
7
  import { HeaderBase } from './HeaderBase';
7
8
  import { HeaderButton } from './HeaderButton';
8
9
  import { HeaderLogo } from './HeaderLogo';
9
10
  import { HeaderMenu } from './HeaderMenu';
10
- import { HeaderSearch, type HeaderSearchProps } from './HeaderSearch';
11
11
  import styles from './header.module.css';
12
12
 
13
- export type HeaderExpandedType = 'search' | 'menu' | null;
14
-
15
13
  export interface HeaderProps {
16
14
  menu: GlobalMenuProps;
17
- search?: HeaderSearchProps;
15
+ search?: SearchbarProps;
18
16
  }
19
17
 
20
18
  export const Header = ({ search, menu }: HeaderProps) => {
21
- const [expandedType, setExpandedType] = useState<HeaderExpandedType | null>(null);
22
- const selectedAccount = menu?.accounts?.find((account) => account.selected);
19
+ const { currentId, toggleId, openId, closeAll } = useRootContext();
20
+ const selectedAccount = menu.accounts?.find((account) => account.selected);
23
21
  const selectedAvatar = selectedAccount && {
24
22
  type: selectedAccount.type,
25
23
  name: selectedAccount.name,
26
24
  };
27
25
 
28
- const onToggle = (type: HeaderExpandedType) => {
29
- if (expandedType === type) {
30
- setExpandedType(null);
31
- } else {
32
- setExpandedType(type);
33
- }
34
- };
26
+ useEscapeKey(closeAll);
35
27
 
36
28
  const onSearchFocus = () => {
37
- setExpandedType('search');
29
+ openId('search');
30
+ };
31
+
32
+ const onSearchClose = () => {
33
+ toggleId('search');
38
34
  };
39
35
 
40
- const onSearchBlur = () => {
41
- setExpandedType(null);
36
+ const onToggleMenu = () => {
37
+ toggleId('menu');
42
38
  };
43
39
 
44
40
  return (
45
- <HeaderBase
46
- className={cx(
47
- styles.header,
48
- expandedType === 'menu' && styles.menuExpanded,
49
- expandedType === 'search' && styles.searchExpanded,
50
- )}
51
- expanded={(expandedType && true) || false}
52
- >
53
- <Backdrop className={styles.backdrop} />
41
+ <HeaderBase currentId={currentId} open={currentId === 'search' || currentId === 'menu'} onClose={closeAll}>
54
42
  <HeaderLogo className={styles.logo} />
55
43
  <HeaderMenu className={styles.menu}>
56
44
  <HeaderButton
57
45
  avatar={selectedAvatar}
58
- onClick={() => onToggle('menu')}
59
- expanded={expandedType === 'menu'}
46
+ onClick={onToggleMenu}
47
+ expanded={currentId === 'menu'}
60
48
  label={menu?.menuLabel}
61
49
  />
62
50
  {menu && (
63
- <DropdownBase expanded={expandedType === 'menu'} className={styles.dropdown}>
64
- <GlobalMenu {...menu} variant="dropdown" />
51
+ <DropdownBase padding={false} placement="right" expanded={currentId === 'menu'} className={styles.dropdown}>
52
+ <GlobalMenu {...menu} currentEndUser={selectedAccount} />
65
53
  </DropdownBase>
66
54
  )}
67
55
  </HeaderMenu>
68
-
69
56
  {search && (
70
- <HeaderSearch
57
+ <Searchbar
71
58
  {...search}
72
59
  className={styles.search}
73
- expanded={expandedType === 'search'}
74
- onBlur={onSearchBlur}
60
+ expanded={currentId === 'search'}
61
+ onClose={onSearchClose}
75
62
  onFocus={onSearchFocus}
76
63
  />
77
64
  )}
78
65
  {menu && (
79
- <DrawerBase expanded={expandedType === 'menu'} className={styles.drawer}>
80
- <GlobalMenu {...menu} variant="drawer" expanded={expandedType === 'menu'} />
66
+ <DrawerBase expanded={currentId === 'menu'} className={styles.drawer}>
67
+ <GlobalMenu {...menu} currentEndUser={selectedAccount} expanded={currentId === 'menu'} />
81
68
  </DrawerBase>
82
69
  )}
83
70
  </HeaderBase>
@@ -1,16 +1,20 @@
1
1
  import cx from 'classnames';
2
2
  import type { ReactNode } from 'react';
3
+ import { Backdrop } from '../';
3
4
  import styles from './headerBase.module.css';
4
5
 
5
6
  export interface HeaderBaseProps {
6
- expanded?: boolean;
7
+ currentId?: string;
7
8
  className?: string;
8
9
  children?: ReactNode;
10
+ open?: boolean;
11
+ onClose?: () => void;
9
12
  }
10
13
 
11
- export const HeaderBase = ({ expanded, className, children }: HeaderBaseProps) => {
14
+ export const HeaderBase = ({ currentId, className, children, open, onClose }: HeaderBaseProps) => {
12
15
  return (
13
- <header className={cx(styles.header, className)} aria-expanded={expanded}>
16
+ <header className={cx(styles.header, className)} data-current-id={currentId}>
17
+ {open && <Backdrop className={styles.backdrop} onClick={onClose} />}
14
18
  {children}
15
19
  </header>
16
20
  );
@@ -1,35 +1,26 @@
1
- .backdrop {
2
- display: none;
3
- z-index: 2;
4
- }
5
-
6
- .header .drawer[aria-expanded="true"] {
1
+ .drawer[aria-expanded="true"] {
7
2
  display: block;
8
3
  }
9
4
 
10
- .header .dropdown[aria-expanded="true"] {
5
+ .dropdown[aria-expanded="true"] {
11
6
  width: 320px;
12
7
  display: none;
13
8
  }
14
9
 
15
- /* menu */
16
-
17
- .header.menuExpanded {
18
- background-color: white;
10
+ @media (min-width: 1024px) {
11
+ .dropdown[aria-expanded="true"] {
12
+ display: block;
13
+ }
19
14
  }
20
15
 
21
16
  @media (min-width: 1024px) {
22
- .header.menuExpanded {
23
- background-color: transparent;
17
+ .drawer[aria-expanded="true"] {
18
+ display: none;
24
19
  }
25
20
 
26
- .header.menuExpanded .backdrop {
21
+ .dropdown[aria-expanded="true"] {
27
22
  display: block;
28
23
  }
29
-
30
- .header.menuExpanded .menu {
31
- z-index: 2;
32
- }
33
24
  }
34
25
 
35
26
  /* search */
@@ -38,31 +29,7 @@
38
29
  width: 100%;
39
30
  }
40
31
 
41
- .header.searchExpanded {
42
- margin-top: -72px;
43
- }
44
-
45
- .header.searchExpanded .search {
46
- z-index: 2;
47
- }
48
-
49
- .header.searchExpanded .backdrop {
50
- display: block;
51
- }
52
-
53
32
  @media (min-width: 1024px) {
54
- .header.searchExpanded {
55
- margin-top: 0;
56
- }
57
-
58
- .header .drawer[aria-expanded="true"] {
59
- display: none;
60
- }
61
-
62
- .header .dropdown[aria-expanded="true"] {
63
- display: block;
64
- }
65
-
66
33
  .search {
67
34
  position: absolute;
68
35
  left: 0;
@@ -72,6 +39,7 @@
72
39
  }
73
40
 
74
41
  .search[aria-expanded="true"] {
42
+ z-index: 2;
75
43
  max-width: 640px;
76
44
  }
77
45
  }
@@ -1,4 +1,5 @@
1
1
  .header {
2
+ z-index: 1;
2
3
  display: flex;
3
4
  align-items: center;
4
5
  justify-content: space-between;
@@ -6,3 +7,45 @@
6
7
  gap: 1rem;
7
8
  padding: 1rem;
8
9
  }
10
+
11
+ .backdrop {
12
+ display: none;
13
+ }
14
+
15
+ /* menu */
16
+
17
+ .header[data-current-id="menu"] {
18
+ background-color: white;
19
+ }
20
+
21
+ @media (min-width: 1024px) {
22
+ .header[data-current-id="menu"] {
23
+ background-color: transparent;
24
+ }
25
+
26
+ .header[data-current-id="menu"] .backdrop {
27
+ display: block;
28
+ }
29
+ }
30
+
31
+ /* search */
32
+
33
+ .header {
34
+ transition-property: all;
35
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
36
+ transition-duration: .15s;
37
+ }
38
+
39
+ .header[data-current-id="search"] {
40
+ margin-top: -72px;
41
+ }
42
+
43
+ .header[data-current-id="search"] .backdrop {
44
+ display: block;
45
+ }
46
+
47
+ @media (min-width: 1024px) {
48
+ .header[data-current-id="search"] {
49
+ margin-top: 0;
50
+ }
51
+ }
@@ -1,5 +1,6 @@
1
1
  .button {
2
2
  position: relative;
3
+ z-index: 2;
3
4
  display: inline-flex;
4
5
  align-items: center;
5
6
  column-gap: 0.625rem;
@@ -53,7 +53,7 @@ const menu: MenuProps = {
53
53
  items: [
54
54
  {
55
55
  id: '1',
56
- group: 1,
56
+ groupId: 1,
57
57
  size: 'lg',
58
58
  icon: 'inbox',
59
59
  title: 'Innboks',
@@ -61,7 +61,7 @@ const menu: MenuProps = {
61
61
  },
62
62
  {
63
63
  id: '2',
64
- group: 2,
64
+ groupId: 2,
65
65
  icon: 'doc-pencil',
66
66
  title: 'Utkast',
67
67
  },
@@ -74,19 +74,19 @@ const menu: MenuProps = {
74
74
  },
75
75
  {
76
76
  id: '4',
77
- group: 3,
77
+ groupId: 3,
78
78
  icon: 'bookmark',
79
79
  title: 'Lagrede søk',
80
80
  },
81
81
  {
82
82
  id: '5',
83
- group: 4,
83
+ groupId: 4,
84
84
  icon: 'archive',
85
85
  title: 'Arkivert',
86
86
  },
87
87
  {
88
88
  id: '6',
89
- group: 4,
89
+ groupId: 4,
90
90
  disabled: true,
91
91
  icon: 'trash',
92
92
  title: 'Papirkurv',
@@ -102,6 +102,7 @@ const meta = {
102
102
  layout: 'fullscreen',
103
103
  },
104
104
  args: {
105
+ theme: 'person',
105
106
  header,
106
107
  footer,
107
108
  sidebar: {
@@ -117,44 +118,82 @@ export const Default: Story = {
117
118
  args: {},
118
119
  };
119
120
 
120
- export const GlobalCompany: Story = {
121
- args: {
122
- sidebar: {
123
- menu: {
124
- ...menu,
125
- defaultItemColor: 'company',
126
- },
127
- },
128
- },
129
- };
121
+ export const ControlledStateSearch = (args) => {
122
+ const [q, setQ] = useState<string>('');
123
+ const onChange = (event) => {
124
+ setQ(event.target.value);
125
+ };
130
126
 
131
- export const GlobalPerson: Story = {
132
- args: {
133
- sidebar: {
134
- menu: {
135
- ...menu,
136
- defaultItemColor: 'person',
137
- },
127
+ const scopes = [
128
+ {
129
+ groupId: '1',
130
+ id: 'inbox',
131
+ href: '#',
132
+ label: q
133
+ ? () => {
134
+ return (
135
+ <span>
136
+ <mark>{q}</mark> i innboksen
137
+ </span>
138
+ );
139
+ }
140
+ : 'Alt i innboksen',
138
141
  },
139
- },
140
- };
142
+ {
143
+ groupId: '1',
144
+ id: 'global',
145
+ href: '#',
146
+ label: q
147
+ ? () => {
148
+ return (
149
+ <span>
150
+ <mark>{q}</mark> i hele Altinn
151
+ </span>
152
+ );
153
+ }
154
+ : 'Alt i hele Altinn',
155
+ },
156
+ ];
141
157
 
142
- export const Neutral: Story = {
143
- args: {
144
- theme: 'neutral',
145
- },
146
- };
158
+ const suggestions = q
159
+ ? [
160
+ {
161
+ groupId: '2',
162
+ href: 'http://www.altinn.no',
163
+ label: 'Skattemelding 2024',
164
+ },
165
+ {
166
+ groupId: '2',
167
+ href: 'http://www.altinn.no',
168
+ label: 'Skattemelding 2025',
169
+ },
170
+ ].filter((item) => item.label.toLowerCase().includes((q ?? '').toLowerCase()))
171
+ : [];
147
172
 
148
- export const Company: Story = {
149
- args: {
150
- theme: 'company',
151
- },
152
- };
173
+ const autocomplete = {
174
+ groups: {
175
+ 2: {
176
+ title: `${suggestions.length} treff i innboksen`,
177
+ },
178
+ },
179
+ items: [...scopes, ...suggestions],
180
+ };
153
181
 
154
- export const Person: Story = {
155
- args: {
156
- theme: 'person',
157
- },
182
+ return (
183
+ <Layout
184
+ {...args}
185
+ header={{
186
+ ...args.header,
187
+ search: {
188
+ ...args.header.search,
189
+ value: q,
190
+ onChange,
191
+ onClear: () => setQ(''),
192
+ autocomplete,
193
+ },
194
+ }}
195
+ />
196
+ );
158
197
  };
159
198
 
160
199
  export const InboxBulkMode = (args) => {
@@ -3,6 +3,7 @@ import { LayoutBase, LayoutBody, LayoutContent, LayoutSidebar, type LayoutTheme
3
3
  import { Footer, type FooterProps } from '../Footer';
4
4
  import { Header, type HeaderProps } from '../Header';
5
5
  import { Menu, type MenuProps } from '../Menu';
6
+ import { useRootContext } from '../RootProvider';
6
7
 
7
8
  interface SidebarProps {
8
9
  theme?: LayoutTheme;
@@ -19,15 +20,16 @@ export interface LayoutProps {
19
20
  theme?: LayoutTheme;
20
21
  header?: HeaderProps;
21
22
  footer?: FooterProps;
22
- sidebar: SidebarProps;
23
- content: ContentProps;
23
+ sidebar?: SidebarProps;
24
+ content?: ContentProps;
24
25
  children: ReactNode;
25
26
  }
26
27
 
27
28
  export const Layout = ({ theme = 'global', header, footer, sidebar = {}, content = {}, children }: LayoutProps) => {
29
+ const { currentId } = useRootContext();
28
30
  const { menu, ...sideRestProps } = sidebar;
29
31
  return (
30
- <LayoutBase theme={theme}>
32
+ <LayoutBase theme={theme} currentId={currentId}>
31
33
  {header && <Header {...header} />}
32
34
  <LayoutBody>
33
35
  {sidebar && (
@@ -5,6 +5,7 @@ export type LayoutTheme = 'global' | 'global-dark' | 'neutral' | 'company' | 'pe
5
5
 
6
6
  export interface LayoutBaseProps {
7
7
  theme?: LayoutTheme;
8
+ currentId?: string;
8
9
  children?: ReactNode;
9
10
  }
10
11
 
@@ -21,9 +22,9 @@ export interface LayoutBaseProps {
21
22
  * - Footer
22
23
  *
23
24
  */
24
- export const LayoutBase = ({ theme, children }: LayoutBaseProps) => {
25
+ export const LayoutBase = ({ currentId, theme, children }: LayoutBaseProps) => {
25
26
  return (
26
- <div className={styles.base} data-theme={theme}>
27
+ <div className={styles.base} data-theme={theme} data-current-id={currentId}>
27
28
  {children}
28
29
  </div>
29
30
  );
@@ -9,3 +9,14 @@
9
9
  .base[data-theme] {
10
10
  background-color: var(--theme-background-subtle);
11
11
  }
12
+
13
+ .base[data-current-id="menu"] {
14
+ background-color: var(--theme-background-default);
15
+ }
16
+
17
+ @media (max-width: 1024px) {
18
+ .base[data-current-id="menu"] header + *,
19
+ .base[data-current-id="menu"] footer {
20
+ display: none;
21
+ }
22
+ }
@@ -3,6 +3,7 @@
3
3
  width: 100%;
4
4
  max-width: 1280px;
5
5
  margin: 0 auto;
6
+ padding: 0 1rem;
6
7
  display: flex;
7
8
  column-gap: 2em;
8
9
  }
@@ -13,7 +13,7 @@ export const ActionHeader = ({ hidden = false, title, dismissable = true, onDism
13
13
  return (
14
14
  <header className={styles.header} aria-hidden={hidden} data-theme="global-dark">
15
15
  <h2 className={styles.title}>{title}</h2>
16
- {dismissable && <IconButton icon="x-mark" onClick={onDismiss} className={styles.dismiss} />}
16
+ {dismissable && <IconButton icon="x-mark" variant="outline" onClick={onDismiss} className={styles.dismiss} />}
17
17
  </header>
18
18
  );
19
19
  };
@@ -1,10 +1,8 @@
1
- import { MenuBase, MenuItem, type MenuItemProps } from '../Menu';
1
+ import { MenuBase, MenuItem, type MenuItemProps, type MenuTheme } from '../Menu';
2
2
  import styles from './actionMenu.module.css';
3
3
 
4
- type ActionMenuTheme = 'inherit' | 'global-dark';
5
-
6
4
  export interface ActionMenuProps {
7
- theme?: ActionMenuTheme;
5
+ theme?: MenuTheme;
8
6
  items?: MenuItemProps[];
9
7
  }
10
8
 
@@ -14,6 +14,9 @@
14
14
  .list {
15
15
  display: flex;
16
16
  flex-direction: column;
17
+ list-style: none;
18
+ padding: 0;
19
+ margin: 0;
17
20
  }
18
21
 
19
22
  @media (min-width: 1024px) {
@@ -0,0 +1,43 @@
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/List',
11
+ component: List,
12
+ tags: ['autodocs'],
13
+ parameters: {},
14
+ args: {
15
+ items: [
16
+ {
17
+ id: '1',
18
+ title: 'Title',
19
+ description: 'Description',
20
+ href: '#',
21
+ },
22
+ {
23
+ id: '2',
24
+ title: 'Title',
25
+ description: 'Description',
26
+ href: '#',
27
+ },
28
+ {
29
+ id: '3',
30
+ title: 'Title',
31
+ description: 'Description',
32
+ href: '#',
33
+ },
34
+ ],
35
+ },
36
+ } satisfies Meta<typeof List>;
37
+
38
+ export default meta;
39
+ type Story = StoryObj<typeof meta>;
40
+
41
+ export const Default: Story = {
42
+ args: {},
43
+ };
@@ -1,18 +1,18 @@
1
- import type { LayoutTheme } from '../Layout';
2
- import { ListBase } from '../List';
1
+ import { ListBase, type ListSpacing, type ListTheme } from '../List';
3
2
  import { ListItem, type ListItemProps } from './ListItem';
4
3
  import type { ListItemSize } from './ListItemBase';
5
4
 
6
5
  export interface ListProps {
7
6
  size?: ListItemSize;
8
- theme?: LayoutTheme;
7
+ spacing?: ListSpacing;
8
+ theme?: ListTheme;
9
9
  items?: ListItemProps[];
10
10
  }
11
11
 
12
- export const List = ({ theme, size = 'md', items }: ListProps) => {
12
+ export const List = ({ theme, size = 'md', spacing = 'md', items = [] }: ListProps) => {
13
13
  return (
14
- <ListBase theme={theme} size={size}>
15
- {items?.map((item, index) => {
14
+ <ListBase theme={theme} spacing={spacing}>
15
+ {items.map((item, index) => {
16
16
  return <ListItem {...item} size={size} key={'item' + index} />;
17
17
  })}
18
18
  </ListBase>
@@ -1,18 +1,18 @@
1
1
  import type { ReactNode } from 'react';
2
2
  import styles from './listBase.module.css';
3
3
 
4
- import type { LayoutTheme } from '../Layout';
5
- import type { ListItemSize } from './ListItemBase';
4
+ export type ListTheme = 'inherit' | 'global' | 'neutral' | 'person' | 'company';
5
+ export type ListSpacing = 'none' | 'sm' | 'md' | 'lg';
6
6
 
7
7
  export interface ListBaseProps {
8
- size?: ListItemSize;
9
- theme?: LayoutTheme;
8
+ theme?: ListTheme;
9
+ spacing?: ListSpacing;
10
10
  children?: ReactNode;
11
11
  }
12
12
 
13
- export const ListBase = ({ size = 'md', theme, children }: ListBaseProps) => {
13
+ export const ListBase = ({ theme = 'inherit', spacing = 'md', children }: ListBaseProps) => {
14
14
  return (
15
- <div className={styles.list} data-theme={theme} data-size={size}>
15
+ <div className={styles.list} data-theme={theme} data-spacing={spacing}>
16
16
  {children}
17
17
  </div>
18
18
  );
@@ -13,7 +13,10 @@ export interface ListItemProps {
13
13
  as?: ElementType;
14
14
  color?: ListItemColor;
15
15
  href?: string;
16
- onClick?: () => void;
16
+ onClick?(): void;
17
+ /** Item is active */
18
+ active?: boolean;
19
+ /** Item should be hidden from view */
17
20
  hidden?: boolean;
18
21
  /** Collapsible item, sets linkIcon to "chevron down" */
19
22
  collapsible?: boolean;