@altinn/altinn-components 0.2.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/.github/workflows/ci-cd-main.yml +5 -2
  2. package/.github/workflows/workflow-deploy-storybook.yml +35 -0
  3. package/.storybook/StoryDecorator.tsx +10 -8
  4. package/CHANGELOG.md +14 -0
  5. package/README.md +20 -2
  6. package/lib/components/Attachment/AttachmentLink.stories.ts +0 -2
  7. package/lib/components/Avatar/avatar.stories.tsx +1 -0
  8. package/lib/components/Button/IconButton.tsx +21 -0
  9. package/lib/components/Button/buttonBase.module.css +17 -2
  10. package/lib/components/Button/iconButton.module.css +14 -0
  11. package/lib/components/Button/index.ts +1 -0
  12. package/lib/components/Dialog/Dialog.stories.ts +0 -2
  13. package/lib/components/Dialog/DialogAttachments.stories.ts +0 -2
  14. package/lib/components/Dialog/DialogHeader.stories.ts +0 -2
  15. package/lib/components/Dialog/DialogListItem.tsx +3 -0
  16. package/lib/components/Dialog/DialogMetadata.stories.ts +0 -2
  17. package/lib/components/Dialog/DialogNav.stories.ts +0 -2
  18. package/lib/components/Dialog/DialogSeenBy.stories.tsx +5 -7
  19. package/lib/components/Dialog/DialogTitle.stories.ts +0 -2
  20. package/lib/components/Dialog/dialogListItemBase.module.css +1 -1
  21. package/lib/components/Dropdown/Backdrop.tsx +11 -0
  22. package/lib/components/Dropdown/DrawerBase.tsx +17 -0
  23. package/lib/components/Dropdown/DropdownBase.tsx +17 -0
  24. package/lib/components/Dropdown/backdrop.module.css +8 -0
  25. package/lib/components/Dropdown/drawerBase.module.css +8 -0
  26. package/lib/components/Dropdown/dropdownBase.module.css +18 -0
  27. package/lib/components/Dropdown/index.ts +3 -0
  28. package/lib/components/Footer/Footer.stories.ts +37 -0
  29. package/lib/components/Footer/Footer.tsx +21 -0
  30. package/lib/components/Footer/FooterAddress.tsx +12 -0
  31. package/lib/components/Footer/FooterBase.tsx +16 -0
  32. package/lib/components/Footer/FooterLogo.tsx +17 -0
  33. package/lib/components/Footer/FooterMenu.tsx +43 -0
  34. package/lib/components/Footer/footerAddress.module.css +8 -0
  35. package/lib/components/Footer/footerBase.module.css +28 -0
  36. package/lib/components/Footer/footerLogo.module.css +12 -0
  37. package/lib/components/Footer/footerMenu.module.css +30 -0
  38. package/lib/components/Footer/index.ts +1 -0
  39. package/lib/components/{Header → GlobalMenu}/GlobalMenu.stories.tsx +1 -13
  40. package/lib/components/{Header → GlobalMenu}/GlobalMenu.tsx +14 -23
  41. package/lib/components/GlobalMenu/index.tsx +1 -0
  42. package/lib/components/Header/Header.stories.ts +61 -33
  43. package/lib/components/Header/Header.tsx +43 -17
  44. package/lib/components/Header/HeaderBase.tsx +10 -3
  45. package/lib/components/Header/HeaderButton.stories.ts +16 -0
  46. package/lib/components/Header/HeaderButton.tsx +12 -0
  47. package/lib/components/Header/HeaderMenu.tsx +17 -0
  48. package/lib/components/Header/header.module.css +51 -13
  49. package/lib/components/Header/headerBase.module.css +8 -0
  50. package/lib/components/Header/headerButton.module.css +1 -0
  51. package/lib/components/Header/headerMenu.module.css +3 -0
  52. package/lib/components/Header/index.tsx +0 -1
  53. package/lib/components/Layout/Layout.stories.tsx +264 -0
  54. package/lib/components/Layout/Layout.tsx +11 -7
  55. package/lib/components/Layout/LayoutBase.tsx +1 -1
  56. package/lib/components/Layout/LayoutBody.tsx +1 -1
  57. package/lib/components/Layout/LayoutContent.tsx +1 -1
  58. package/lib/components/Layout/LayoutSidebar.tsx +11 -4
  59. package/lib/components/Layout/layoutBase.module.css +23 -0
  60. package/lib/components/Layout/layoutBody.module.css +14 -0
  61. package/lib/components/Layout/layoutContent.module.css +8 -0
  62. package/lib/components/Layout/layoutSidebar.module.css +19 -0
  63. package/lib/components/LayoutAction/ActionFooter.stories.tsx +70 -0
  64. package/lib/components/LayoutAction/ActionFooter.tsx +15 -0
  65. package/lib/components/LayoutAction/ActionHeader.stories.ts +20 -0
  66. package/lib/components/LayoutAction/ActionHeader.tsx +19 -0
  67. package/lib/components/LayoutAction/ActionMenu.stories.tsx +39 -0
  68. package/lib/components/LayoutAction/ActionMenu.tsx +22 -0
  69. package/lib/components/LayoutAction/actionFooter.module.css +28 -0
  70. package/lib/components/LayoutAction/actionHeader.module.css +55 -0
  71. package/lib/components/LayoutAction/actionMenu.module.css +25 -0
  72. package/lib/components/LayoutAction/index.ts +3 -0
  73. package/lib/components/Menu/MenuBase.tsx +4 -2
  74. package/lib/components/Menu/MenuItemBase.tsx +5 -3
  75. package/lib/components/RootProvider/RootProvider.tsx +19 -0
  76. package/lib/components/RootProvider/index.ts +1 -0
  77. package/lib/components/Snackbar/Snackbar.stories.tsx +21 -0
  78. package/lib/components/Snackbar/Snackbar.tsx +32 -0
  79. package/lib/components/Snackbar/SnackbarBase.tsx +39 -0
  80. package/lib/components/Snackbar/SnackbarLabel.tsx +10 -0
  81. package/lib/components/Snackbar/SnackbarMedia.tsx +14 -0
  82. package/lib/components/Snackbar/index.ts +4 -0
  83. package/lib/components/Snackbar/snackbarBase.module.css +55 -0
  84. package/lib/components/Snackbar/snackbarLabel.module.css +6 -0
  85. package/lib/components/Snackbar/snackbarMedia.module.css +10 -0
  86. package/lib/components/Toolbar/ToolbarAdd.stories.ts +0 -2
  87. package/lib/components/Toolbar/ToolbarFilter.stories.ts +0 -2
  88. package/lib/components/index.ts +5 -0
  89. package/package.json +1 -1
  90. package/lib/components/Layout/Layout.stories.ts +0 -124
  91. package/lib/components/Layout/layout.module.css +0 -63
  92. /package/lib/components/Header/{globalMenu.module.css → mobileMenu.module.css} +0 -0
@@ -0,0 +1,55 @@
1
+ .header {
2
+ position: fixed;
3
+ z-index: 10;
4
+ top: 0;
5
+ right: 0;
6
+ bottom: auto;
7
+ left: 0;
8
+ }
9
+
10
+ .header {
11
+ background-color: var(--global-base-default);
12
+ color: white;
13
+ height: 76px;
14
+ }
15
+
16
+ .header {
17
+ display: flex;
18
+ align-items: center;
19
+ justify-content: space-between;
20
+ padding: 1rem;
21
+ }
22
+
23
+ .header {
24
+ transition-property: all;
25
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
26
+ transition-duration: .15s;
27
+ transform: translateY(0);
28
+ }
29
+
30
+ .header[aria-hidden="true"] {
31
+ transform: translateY(-100%);
32
+ }
33
+
34
+ .title {
35
+ font-size: 1rem;
36
+ font-weight: normal;
37
+ }
38
+
39
+ .button {
40
+ border: 1px solid #fff;
41
+ width: 2.75rem;
42
+ height: 2.75rem;
43
+ display: flex;
44
+ align-items: center;
45
+ justify-content: center;
46
+ border-radius: 2px;
47
+ }
48
+
49
+ .button:hover {
50
+ background-color: var(--global-base-hover);
51
+ }
52
+
53
+ .icon {
54
+ font-size: 1.5rem;
55
+ }
@@ -0,0 +1,25 @@
1
+ .menu {
2
+ background-color: var(--global-base-default);
3
+ color: white;
4
+ padding: 0 .5rem;
5
+ border-radius: 0.375rem;
6
+ }
7
+
8
+ .list {
9
+ display: flex;
10
+ flex-direction: column;
11
+ }
12
+
13
+ @media (min-width: 1024px) {
14
+ .list {
15
+ flex-direction: row;
16
+ align-items: center;
17
+ justify-content: start;
18
+ column-gap: .5rem;
19
+ width: auto;
20
+ }
21
+ }
22
+
23
+ .list .item:hover {
24
+ background-color: var(--global-base-hover);
25
+ }
@@ -0,0 +1,3 @@
1
+ export * from './ActionHeader.tsx';
2
+ export * from './ActionFooter.tsx';
3
+ export * from './ActionMenu.tsx';
@@ -1,16 +1,18 @@
1
+ import cx from 'classnames';
1
2
  import type { ElementType, ReactNode } from 'react';
2
3
  import styles from './menu.module.css';
3
4
 
4
5
  export interface MenuBaseProps {
5
6
  as?: ElementType;
6
7
  theme?: string;
8
+ className?: string;
7
9
  children?: ReactNode;
8
10
  }
9
11
 
10
- export const MenuBase = ({ as = 'nav', theme, children }: MenuBaseProps) => {
12
+ export const MenuBase = ({ as = 'nav', theme, className, children }: MenuBaseProps) => {
11
13
  const Component = as;
12
14
  return (
13
- <Component className={styles.menu} data-theme={theme}>
15
+ <Component className={cx(styles.menu, className)} data-theme={theme}>
14
16
  {children}
15
17
  </Component>
16
18
  );
@@ -54,9 +54,11 @@ export const MenuItemBase = ({
54
54
  {children}
55
55
  {badge && <Badge {...badge} />}
56
56
  </div>
57
- <div className={styles.action}>
58
- {applicableIcon && <Icon name={applicableIcon} className={styles.actionIcon} />}
59
- </div>
57
+ {applicableIcon && (
58
+ <div className={styles.action}>
59
+ {applicableIcon && <Icon name={applicableIcon} className={styles.actionIcon} />}
60
+ </div>
61
+ )}
60
62
  </Component>
61
63
  );
62
64
  };
@@ -0,0 +1,19 @@
1
+ import { type ReactNode, createContext } from 'react';
2
+
3
+ interface RootContextProvider {
4
+ showBackdrop: boolean;
5
+ }
6
+
7
+ const initialValue = {
8
+ showBackdrop: false,
9
+ };
10
+ const RootContext = createContext<RootContextProvider>(initialValue);
11
+
12
+ interface ProviderProps {
13
+ children: ReactNode;
14
+ value?: RootContextProvider;
15
+ }
16
+
17
+ export const RootProvider = ({ children, value }: ProviderProps) => {
18
+ return <RootContext.Provider value={value ?? initialValue}>{children}</RootContext.Provider>;
19
+ };
@@ -0,0 +1 @@
1
+ export * from './RootProvider.tsx';
@@ -0,0 +1,21 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { Snackbar } from './Snackbar';
3
+
4
+ const meta = {
5
+ title: 'Snackbar/Snackbar',
6
+ component: Snackbar,
7
+ tags: ['autodocs'],
8
+ parameters: {},
9
+ args: {
10
+ id: 'id',
11
+ icon: 'bell',
12
+ message: 'Message',
13
+ },
14
+ } satisfies Meta<typeof Snackbar>;
15
+
16
+ export default meta;
17
+ type Story = StoryObj<typeof meta>;
18
+
19
+ export const Default: Story = {
20
+ args: {},
21
+ };
@@ -0,0 +1,32 @@
1
+ import type { ElementType } from 'react';
2
+ import type { IconName } from '../Icon';
3
+ import { SnackbarBase, type SnackbarColor } from './SnackbarBase';
4
+ import { SnackbarLabel } from './SnackbarLabel';
5
+ import { SnackbarMedia } from './SnackbarMedia';
6
+
7
+ export interface SnackbarProps {
8
+ id: string;
9
+ /** Element type to render */
10
+ as?: ElementType;
11
+ /** Color */
12
+ color?: SnackbarColor;
13
+ /** Message */
14
+ message?: string;
15
+ /** Icon */
16
+ icon?: IconName;
17
+ /** Dismissable */
18
+ dismissable?: boolean;
19
+ /** onDismiss */
20
+ onDismiss?: () => void;
21
+ /** Optional classname */
22
+ className?: string;
23
+ }
24
+
25
+ export const Snackbar = ({ as = 'a', color, message, icon, ...rest }: SnackbarProps) => {
26
+ return (
27
+ <SnackbarBase as={as} color={color} {...rest}>
28
+ <SnackbarMedia icon={icon} />
29
+ <SnackbarLabel>{message}</SnackbarLabel>
30
+ </SnackbarBase>
31
+ );
32
+ };
@@ -0,0 +1,39 @@
1
+ import cx from 'classnames';
2
+ import type { ElementType, ReactNode } from 'react';
3
+ import { IconButton } from '../Button';
4
+ import styles from './snackbarBase.module.css';
5
+
6
+ export type SnackbarColor = 'default' | 'accent';
7
+
8
+ interface SnackbarBaseProps {
9
+ as?: ElementType;
10
+ color?: SnackbarColor;
11
+ href?: string;
12
+ className?: string;
13
+ dismissable?: boolean;
14
+ onDismiss?: () => void;
15
+ children?: ReactNode;
16
+ }
17
+
18
+ export const SnackbarBase = ({
19
+ as,
20
+ children,
21
+ className,
22
+ color,
23
+ dismissable = true,
24
+ onDismiss,
25
+ ...rest
26
+ }: SnackbarBaseProps) => {
27
+ const Component = as || 'div';
28
+
29
+ return (
30
+ <Component className={cx(styles.item, className)} data-color={color} {...rest}>
31
+ <div className={styles.content}>{children}</div>
32
+ {dismissable && (
33
+ <div className={styles.action}>
34
+ <IconButton icon="x-mark" variant="text" onClick={onDismiss} className={styles.dismiss} />
35
+ </div>
36
+ )}
37
+ </Component>
38
+ );
39
+ };
@@ -0,0 +1,10 @@
1
+ import type { ReactNode } from 'react';
2
+ import styles from './snackbarLabel.module.css';
3
+
4
+ export interface SnackbarLabelProps {
5
+ children?: ReactNode;
6
+ }
7
+
8
+ export const SnackbarLabel = ({ children }: SnackbarLabelProps) => {
9
+ return <span className={styles.label}>{children}</span>;
10
+ };
@@ -0,0 +1,14 @@
1
+ import { Icon, type IconName } from '../Icon';
2
+ import styles from './snackbarMedia.module.css';
3
+
4
+ interface SnackbarMediaProps {
5
+ icon?: IconName;
6
+ }
7
+
8
+ export const SnackbarMedia = ({ icon = 'bell' }: SnackbarMediaProps) => {
9
+ return (
10
+ <div className={styles.media}>
11
+ <Icon name={icon} variant="solid" className={styles.icon} />
12
+ </div>
13
+ );
14
+ };
@@ -0,0 +1,4 @@
1
+ export * from './Snackbar';
2
+ export * from './SnackbarBase';
3
+ export * from './SnackbarMedia';
4
+ export * from './SnackbarLabel';
@@ -0,0 +1,55 @@
1
+ .item {
2
+ border: none;
3
+
4
+ color: inherit;
5
+ font: inherit;
6
+ text-align: inherit;
7
+
8
+ line-height: normal;
9
+
10
+ -webkit-font-smoothing: inherit;
11
+ -moz-osx-font-smoothing: inherit;
12
+
13
+ user-select: none;
14
+
15
+ border-radius: 0.5rem;
16
+ }
17
+
18
+ .item {
19
+ position: relative;
20
+ display: flex;
21
+ align-items: center;
22
+ text-decoration: none;
23
+ color: inherit;
24
+ }
25
+
26
+ .content {
27
+ flex-grow: 1;
28
+ display: flex;
29
+ align-items: center;
30
+ gap: 0.625rem;
31
+ margin: 0.625rem;
32
+ }
33
+
34
+ .action {
35
+ flex-shrink: 0;
36
+ display: flex;
37
+ align-items: center;
38
+ margin: 0.625rem;
39
+ }
40
+
41
+ /* colors */
42
+
43
+ .item {
44
+ background-color: var(--global-base-default);
45
+ color: #fff;
46
+ box-shadow: var(--ds-shadow-xs);
47
+ }
48
+
49
+ .item[data-color="accent"] {
50
+ background-color: var(--theme-surface-default);
51
+ }
52
+
53
+ .item[data-color="accent"]:hover {
54
+ background-color: var(--theme-surface-hover);
55
+ }
@@ -0,0 +1,6 @@
1
+ /* label */
2
+
3
+ .label {
4
+ display: flex;
5
+ justify-content: center;
6
+ }
@@ -0,0 +1,10 @@
1
+ .media {
2
+ display: flex;
3
+ align-items: center;
4
+ justify-content: center;
5
+ }
6
+
7
+ .icon {
8
+ font-size: 1.5rem;
9
+ margin: 0.625rem;
10
+ }
@@ -1,6 +1,4 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react';
2
- import { fn } from '@storybook/test';
3
-
4
2
  import { ToolbarAdd } from './ToolbarAdd';
5
3
 
6
4
  const meta = {
@@ -1,6 +1,4 @@
1
1
  import type { Meta, StoryObj } from '@storybook/react';
2
- import { fn } from '@storybook/test';
3
-
4
2
  import { ToolbarFilter } from './ToolbarFilter';
5
3
 
6
4
  const meta = {
@@ -1,9 +1,13 @@
1
1
  export * from './Attachment';
2
2
  export * from './Avatar';
3
3
  export * from './Badge';
4
+ export * from './LayoutAction';
4
5
  export * from './Button';
5
6
  export * from './ContextMenu';
6
7
  export * from './Dialog';
8
+ export * from './Dropdown';
9
+ export * from './Footer';
10
+ export * from './GlobalMenu';
7
11
  export * from './Header';
8
12
  export * from './History';
9
13
  export * from './Icon';
@@ -11,5 +15,6 @@ export * from './Layout';
11
15
  export * from './List';
12
16
  export * from './Menu';
13
17
  export * from './Meta';
18
+ export * from './Snackbar';
14
19
  export * from './Toolbar';
15
20
  export * from './Typography';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@altinn/altinn-components",
3
- "version": "0.2.2",
3
+ "version": "0.4.0",
4
4
  "main": "lib/index.ts",
5
5
  "description": "Reusable react components",
6
6
  "publishConfig": {
@@ -1,124 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/react';
2
- import type { MenuProps } from '../Menu';
3
- import { Layout } from './Layout';
4
-
5
- const menu: MenuProps = {
6
- groups: {},
7
- items: [
8
- {
9
- id: '1',
10
- group: 1,
11
- size: 'lg',
12
- icon: 'inbox',
13
- title: 'Innboks',
14
- },
15
- {
16
- id: '2',
17
- group: 2,
18
- icon: 'doc-pencil',
19
- title: 'Utkast',
20
- },
21
- {
22
- id: '3',
23
- group: 2,
24
- icon: 'file-checkmark',
25
- selected: true,
26
- title: 'Sendt',
27
- },
28
- {
29
- id: '4',
30
- group: 3,
31
- icon: 'bookmark',
32
- title: 'Lagrede søk',
33
- },
34
- {
35
- id: '5',
36
- group: 4,
37
- icon: 'archive',
38
- title: 'Arkivert',
39
- },
40
- {
41
- id: '6',
42
- group: 4,
43
- disabled: true,
44
- icon: 'trash',
45
- title: 'Papirkurv',
46
- },
47
- ],
48
- };
49
-
50
- const meta = {
51
- title: 'Layout/Layout',
52
- component: Layout,
53
- tags: ['autodocs'],
54
- parameters: {
55
- layout: 'fullscreen',
56
- },
57
- args: {
58
- header: {
59
- menu: {
60
- search: {
61
- name: 'search',
62
- placeholder: 'Søk i Altinn',
63
- },
64
- accounts: [
65
- {
66
- type: 'person',
67
- name: 'Aurora Mikalsen',
68
- selected: true,
69
- },
70
- ],
71
- },
72
- },
73
- sidebar: {
74
- menu,
75
- },
76
- },
77
- } satisfies Meta<typeof Layout>;
78
-
79
- export default meta;
80
- type Story = StoryObj<typeof meta>;
81
-
82
- export const Default: Story = {
83
- args: {},
84
- };
85
-
86
- export const GlobalCompany: Story = {
87
- args: {
88
- sidebar: {
89
- menu: {
90
- ...menu,
91
- defaultItemColor: 'company',
92
- },
93
- },
94
- },
95
- };
96
-
97
- export const GlobalPerson: Story = {
98
- args: {
99
- sidebar: {
100
- menu: {
101
- ...menu,
102
- defaultItemColor: 'person',
103
- },
104
- },
105
- },
106
- };
107
-
108
- export const Neutral: Story = {
109
- args: {
110
- theme: 'neutral',
111
- },
112
- };
113
-
114
- export const Company: Story = {
115
- args: {
116
- theme: 'company',
117
- },
118
- };
119
-
120
- export const Person: Story = {
121
- args: {
122
- theme: 'person',
123
- },
124
- };
@@ -1,63 +0,0 @@
1
- .base {
2
- display: flex;
3
- flex-direction: column;
4
- min-height: 100vh;
5
- }
6
-
7
- /* theme */
8
-
9
- .base[data-theme="global"] {
10
- background-color: var(--neutral-background-default);
11
- }
12
-
13
- .base[data-theme="neutral"] {
14
- background-color: var(--neutral-background-subtle);
15
- }
16
-
17
- .base[data-theme="person"] {
18
- background-color: var(--person-background-subtle);
19
- }
20
-
21
- .base[data-theme="company"] {
22
- background-color: var(--company-background-subtle);
23
- }
24
-
25
- /* body (sidebar + content ) */
26
-
27
- .body {
28
- flex-grow: 1;
29
- width: 100%;
30
- max-width: 1280px;
31
- margin: 0 auto;
32
- display: flex;
33
- column-gap: 2em;
34
- }
35
-
36
- @media (min-width: 1024px) {
37
- .body {
38
- padding: 0 1rem;
39
- }
40
- }
41
-
42
- .content {
43
- flex-grow: 1;
44
- position: relative;
45
- display: flex;
46
- flex-direction: column;
47
- }
48
-
49
- .sidebar {
50
- display: none;
51
- }
52
-
53
- @media (min-width: 1024px) {
54
- .sidebar {
55
- display: none;
56
- width: 224px;
57
- }
58
-
59
- .sidebar[aria-expanded="true"] {
60
- display: flex;
61
- flex-direction: column;
62
- }
63
- }