@altinn/altinn-components 0.0.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 (126) hide show
  1. package/.github/workflows/ci-cd-main.yml +44 -0
  2. package/.github/workflows/ci-cd-pull-request.yml +39 -0
  3. package/.node-version +1 -0
  4. package/.storybook/main.ts +22 -0
  5. package/.storybook/preview.ts +15 -0
  6. package/CHANGELOG.md +13 -0
  7. package/README.md +2 -0
  8. package/biome.jsonc +65 -0
  9. package/lib/components/Avatar/Avatar.tsx +91 -0
  10. package/lib/components/Avatar/AvatarGroup.stories.ts +67 -0
  11. package/lib/components/Avatar/AvatarGroup.tsx +42 -0
  12. package/lib/components/Avatar/avatar.module.css +59 -0
  13. package/lib/components/Avatar/avatar.stories.tsx +44 -0
  14. package/lib/components/Avatar/avatarGroup.module.css +78 -0
  15. package/lib/components/Avatar/color.ts +71 -0
  16. package/lib/components/Avatar/index.ts +2 -0
  17. package/lib/components/Badge/Badge.tsx +19 -0
  18. package/lib/components/Badge/badge.module.css +36 -0
  19. package/lib/components/Badge/index.tsx +1 -0
  20. package/lib/components/Button/Button.stories.ts +44 -0
  21. package/lib/components/Button/Button.tsx +39 -0
  22. package/lib/components/Button/ButtonBase.tsx +53 -0
  23. package/lib/components/Button/ComboButton.stories.ts +45 -0
  24. package/lib/components/Button/ComboButton.tsx +44 -0
  25. package/lib/components/Button/button.module.css +82 -0
  26. package/lib/components/Button/buttonBase.module.css +77 -0
  27. package/lib/components/Button/comboButton.module.css +83 -0
  28. package/lib/components/Button/index.ts +3 -0
  29. package/lib/components/Header/DigdirLogomark.tsx +23 -0
  30. package/lib/components/Header/GlobalMenu.stories.tsx +202 -0
  31. package/lib/components/Header/GlobalMenu.tsx +131 -0
  32. package/lib/components/Header/Header.stories.ts +85 -0
  33. package/lib/components/Header/Header.tsx +64 -0
  34. package/lib/components/Header/HeaderBase.tsx +10 -0
  35. package/lib/components/Header/HeaderButton.stories.ts +54 -0
  36. package/lib/components/Header/HeaderButton.tsx +55 -0
  37. package/lib/components/Header/HeaderLogo.stories.ts +17 -0
  38. package/lib/components/Header/HeaderLogo.tsx +22 -0
  39. package/lib/components/Header/HeaderSearch.stories.ts +20 -0
  40. package/lib/components/Header/HeaderSearch.tsx +44 -0
  41. package/lib/components/Header/globalMenu.module.css +28 -0
  42. package/lib/components/Header/header.module.css +39 -0
  43. package/lib/components/Header/headerButton.module.css +35 -0
  44. package/lib/components/Header/headerLogo.module.css +24 -0
  45. package/lib/components/Header/headerSearch.module.css +30 -0
  46. package/lib/components/Header/index.tsx +5 -0
  47. package/lib/components/Icon/CheckboxIcon.stories.ts +25 -0
  48. package/lib/components/Icon/CheckboxIcon.tsx +29 -0
  49. package/lib/components/Icon/Icon.stories.ts +24 -0
  50. package/lib/components/Icon/Icon.tsx +23 -0
  51. package/lib/components/Icon/RadioIcon.stories.ts +25 -0
  52. package/lib/components/Icon/RadioIcon.tsx +29 -0
  53. package/lib/components/Icon/SvgIcon.tsx +18 -0
  54. package/lib/components/Icon/__AkselIcon.tsx +37 -0
  55. package/lib/components/Icon/checkboxIcon.module.css +21 -0
  56. package/lib/components/Icon/icon.module.css +4 -0
  57. package/lib/components/Icon/iconsMap.tsx +2078 -0
  58. package/lib/components/Icon/index.ts +5 -0
  59. package/lib/components/Icon/radioIcon.module.css +21 -0
  60. package/lib/components/Layout/Layout.stories.ts +127 -0
  61. package/lib/components/Layout/Layout.tsx +40 -0
  62. package/lib/components/Layout/LayoutBase.stories.ts +17 -0
  63. package/lib/components/Layout/LayoutBase.tsx +30 -0
  64. package/lib/components/Layout/LayoutBody.stories.ts +17 -0
  65. package/lib/components/Layout/LayoutBody.tsx +16 -0
  66. package/lib/components/Layout/LayoutContent.stories.ts +17 -0
  67. package/lib/components/Layout/LayoutContent.tsx +15 -0
  68. package/lib/components/Layout/LayoutSidebar.stories.ts +17 -0
  69. package/lib/components/Layout/LayoutSidebar.tsx +16 -0
  70. package/lib/components/Layout/index.tsx +4 -0
  71. package/lib/components/Layout/layout.module.css +63 -0
  72. package/lib/components/Menu/Menu.stories.ts +495 -0
  73. package/lib/components/Menu/Menu.tsx +123 -0
  74. package/lib/components/Menu/MenuBase.tsx +17 -0
  75. package/lib/components/Menu/MenuGroup.tsx +18 -0
  76. package/lib/components/Menu/MenuHeader.tsx +13 -0
  77. package/lib/components/Menu/MenuItem.stories.ts +127 -0
  78. package/lib/components/Menu/MenuItem.tsx +58 -0
  79. package/lib/components/Menu/MenuItemBase.tsx +62 -0
  80. package/lib/components/Menu/MenuItemLabel.tsx +30 -0
  81. package/lib/components/Menu/MenuItemMedia.tsx +42 -0
  82. package/lib/components/Menu/MenuOption.stories.ts +50 -0
  83. package/lib/components/Menu/MenuOption.tsx +45 -0
  84. package/lib/components/Menu/MenuSearch.stories.ts +18 -0
  85. package/lib/components/Menu/MenuSearch.tsx +25 -0
  86. package/lib/components/Menu/index.ts +10 -0
  87. package/lib/components/Menu/menu.module.css +26 -0
  88. package/lib/components/Menu/menuHeader.module.css +12 -0
  89. package/lib/components/Menu/menuItem.module.css +136 -0
  90. package/lib/components/Menu/menuOption.module.css +29 -0
  91. package/lib/components/Menu/menuSearch.module.css +29 -0
  92. package/lib/components/Menu/useClickOutside.ts +21 -0
  93. package/lib/components/Menu/useEscapeKey.ts +16 -0
  94. package/lib/components/Toolbar/Toolbar.stories.tsx +188 -0
  95. package/lib/components/Toolbar/Toolbar.tsx +138 -0
  96. package/lib/components/Toolbar/ToolbarAdd.stories.ts +25 -0
  97. package/lib/components/Toolbar/ToolbarAdd.tsx +25 -0
  98. package/lib/components/Toolbar/ToolbarBase.tsx +27 -0
  99. package/lib/components/Toolbar/ToolbarButton.stories.ts +32 -0
  100. package/lib/components/Toolbar/ToolbarButton.tsx +65 -0
  101. package/lib/components/Toolbar/ToolbarFilter.stories.ts +66 -0
  102. package/lib/components/Toolbar/ToolbarFilter.tsx +70 -0
  103. package/lib/components/Toolbar/ToolbarMenu.stories.ts +37 -0
  104. package/lib/components/Toolbar/ToolbarMenu.tsx +28 -0
  105. package/lib/components/Toolbar/ToolbarOptions.stories.ts +108 -0
  106. package/lib/components/Toolbar/ToolbarOptions.tsx +61 -0
  107. package/lib/components/Toolbar/ToolbarSearch.stories.ts +19 -0
  108. package/lib/components/Toolbar/ToolbarSearch.tsx +24 -0
  109. package/lib/components/Toolbar/index.js +3 -0
  110. package/lib/components/Toolbar/toolbar.module.css +43 -0
  111. package/lib/components/Toolbar/toolbarButton.module.css +3 -0
  112. package/lib/components/Toolbar/toolbarSearch.module.css +28 -0
  113. package/lib/components/index.ts +1 -0
  114. package/lib/css/colors.css +113 -0
  115. package/lib/css/global.css +12 -0
  116. package/lib/css/theme-company.css +15 -0
  117. package/lib/css/theme-global.css +15 -0
  118. package/lib/css/theme-neutral.css +15 -0
  119. package/lib/css/theme-person.css +15 -0
  120. package/lib/css/theme.css +24 -0
  121. package/lib/index.ts +1 -0
  122. package/package.json +52 -0
  123. package/tsconfig.json +23 -0
  124. package/tsconfig.node.json +11 -0
  125. package/typings.d.ts +1 -0
  126. package/vite.config.ts +20 -0
@@ -0,0 +1,28 @@
1
+ .button {
2
+ position: relative;
3
+ display: inline-block;
4
+ }
5
+
6
+ .dropdown {
7
+ display: none;
8
+ }
9
+
10
+ .header {
11
+ margin: 0.5rem 0;
12
+ }
13
+
14
+ .dropdown[aria-expanded="true"] {
15
+ display: block;
16
+ position: absolute;
17
+ min-width: 256px;
18
+ right: 0;
19
+ z-index: 2;
20
+ }
21
+
22
+ .dropdown {
23
+ margin-top: 0.5rem;
24
+ padding: 0 0.5rem;
25
+ background-color: var(--neutral-background-default);
26
+ border-radius: 2px;
27
+ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.15), 0 1px 2px 0 rgba(0, 0, 0, 0.12), 0 2px 4px 0 rgba(0, 0, 0, 0.1);
28
+ }
@@ -0,0 +1,39 @@
1
+ .header {
2
+ display: flex;
3
+ align-items: center;
4
+ justify-content: space-between;
5
+ flex-wrap: wrap;
6
+ gap: 1rem;
7
+ padding: 1rem;
8
+ }
9
+
10
+ /* color */
11
+
12
+ .header[data-color="light"] {
13
+ background-color: var(--global-background-default);
14
+ }
15
+
16
+ .header[data-color="dark"] {
17
+ background-color: var(--global-base-default);
18
+ color: #fff;
19
+ }
20
+
21
+ /* search */
22
+
23
+ .search {
24
+ width: 100%;
25
+ }
26
+
27
+ @media (min-width: 1024px) {
28
+ .search {
29
+ position: absolute;
30
+ left: 0;
31
+ right: 0;
32
+ margin: 0 auto;
33
+ max-width: 320px;
34
+ }
35
+
36
+ .search[aria-expanded="true"] {
37
+ max-width: 640px;
38
+ }
39
+ }
@@ -0,0 +1,35 @@
1
+ .button {
2
+ position: relative;
3
+ display: inline-flex;
4
+ align-items: center;
5
+ column-gap: 0.625rem;
6
+ background-color: var(--global-base-default);
7
+ color: white;
8
+ padding: 0.625rem;
9
+ border-radius: 4px;
10
+ }
11
+
12
+ .label {
13
+ font-size: 1.125rem;
14
+ font-weight: 500;
15
+ padding: 0.25rem;
16
+ }
17
+
18
+ .icon {
19
+ width: 2.25rem;
20
+ height: 2.25rem;
21
+ display: flex;
22
+ align-items: center;
23
+ justify-content: center;
24
+ border-radius: 2px;
25
+ font-size: 1.5rem;
26
+ }
27
+
28
+ .loginIcon {
29
+ background-color: white;
30
+ color: black;
31
+ }
32
+
33
+ .closeIcon {
34
+ border: 1px solid white;
35
+ }
@@ -0,0 +1,24 @@
1
+ .logo {
2
+ display: flex;
3
+ align-items: center;
4
+ color: currentColor;
5
+ text-decoration: none;
6
+ }
7
+
8
+ .symbol {
9
+ width: 2rem;
10
+ height: 2rem;
11
+ margin: 6px;
12
+ }
13
+
14
+ .riksSymbol {
15
+ width: 2.5rem;
16
+ height: 2.5rem;
17
+ margin: 0;
18
+ }
19
+
20
+ .text {
21
+ font-size: 1.5rem;
22
+ font-weight: 500;
23
+ padding: 4px;
24
+ }
@@ -0,0 +1,30 @@
1
+ .field {
2
+ position: relative;
3
+ display: flex;
4
+ align-items: center;
5
+ font-size: 1.125rem;
6
+ color: currentColor;
7
+ }
8
+
9
+ .input {
10
+ font-size: inherit;
11
+ flex-grow: 1;
12
+ padding-left: 2.5rem;
13
+ padding-right: 1rem;
14
+ padding-top: 1rem;
15
+ padding-bottom: 1rem;
16
+ border-radius: 4px;
17
+ border: 2px solid;
18
+ background-color: transparent;
19
+ }
20
+
21
+ .input[value] {
22
+ background-color: white;
23
+ }
24
+
25
+ .icon {
26
+ position: absolute;
27
+ left: 0;
28
+ font-size: 1.25rem;
29
+ margin: 0 1rem;
30
+ }
@@ -0,0 +1,5 @@
1
+ export * from './Header';
2
+ export * from './HeaderBase';
3
+ export * from './HeaderLogo';
4
+ export * from './HeaderButton';
5
+ export * from './GlobalMenu.tsx';
@@ -0,0 +1,25 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { CheckboxIcon } from './CheckboxIcon';
3
+
4
+ const meta = {
5
+ title: 'Atoms/Icon/CheckboxIcon',
6
+ component: CheckboxIcon,
7
+ tags: ['autodocs'],
8
+ parameters: {},
9
+ args: {},
10
+ } satisfies Meta<typeof CheckboxIcon>;
11
+
12
+ export default meta;
13
+ type Story = StoryObj<typeof meta>;
14
+
15
+ export const Default: Story = {
16
+ args: {
17
+ checked: false,
18
+ },
19
+ };
20
+
21
+ export const Checked: Story = {
22
+ args: {
23
+ checked: true,
24
+ },
25
+ };
@@ -0,0 +1,29 @@
1
+ import cx from 'classnames';
2
+ import styles from './checkboxIcon.module.css';
3
+
4
+ export type CheckboxIconProps = {
5
+ checked: boolean;
6
+ title?: string;
7
+ className?: string;
8
+ };
9
+
10
+ /**
11
+ * Checkbox for lists and list items
12
+ */
13
+ export const CheckboxIcon = ({ checked, title, className }: CheckboxIconProps) => {
14
+ return (
15
+ <div data-checked={checked} className={cx(styles.checkbox, className)}>
16
+ <svg
17
+ xmlns="http://www.w3.org/2000/svg"
18
+ fill="none"
19
+ viewBox="0 0 24 24"
20
+ strokeWidth={2.5}
21
+ stroke="currentColor"
22
+ className={styles.icon}
23
+ >
24
+ <title>{title}</title>
25
+ <path strokeLinecap="round" strokeLinejoin="round" d="M4.5 12.75l6 6 9-13.5" />
26
+ </svg>
27
+ </div>
28
+ );
29
+ };
@@ -0,0 +1,24 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { Icon } from './Icon';
3
+ import { iconsMap } from './iconsMap';
4
+
5
+ const meta = {
6
+ title: 'Atoms/Icon/Icon',
7
+ component: Icon,
8
+ tags: ['autodocs'],
9
+ parameters: {},
10
+ argTypes: {
11
+ name: Object.keys(iconsMap),
12
+ },
13
+ args: {
14
+ name: 'inbox',
15
+ variant: 'outline',
16
+ },
17
+ } satisfies Meta<typeof Icon>;
18
+
19
+ export default meta;
20
+ type Story = StoryObj<typeof meta>;
21
+
22
+ export const Default: Story = {
23
+ args: {},
24
+ };
@@ -0,0 +1,23 @@
1
+ import cx from 'classnames';
2
+ import { type IconName, iconsMap } from './';
3
+ import { SvgIcon } from './SvgIcon';
4
+ import styles from './icon.module.css';
5
+
6
+ export type IconVariant = 'solid' | 'outline';
7
+
8
+ interface IconProps {
9
+ name: IconName;
10
+ variant?: IconVariant;
11
+ className?: string;
12
+ }
13
+
14
+ export const Icon = ({ name, variant = 'outline', className }: IconProps) => {
15
+ const svgIcon: JSX.Element | undefined =
16
+ (iconsMap[name] as { [key in IconVariant]: JSX.Element })?.[variant] ?? iconsMap[name]?.outline;
17
+
18
+ if (!svgIcon) {
19
+ return <span className={cx([styles.icon], className)} />;
20
+ }
21
+
22
+ return <SvgIcon svgIconComponent={svgIcon} className={cx([styles.icon], className)} />;
23
+ };
@@ -0,0 +1,25 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { RadioIcon } from './RadioIcon';
3
+
4
+ const meta = {
5
+ title: 'Atoms/Icon/RadioIcon',
6
+ component: RadioIcon,
7
+ tags: ['autodocs'],
8
+ parameters: {},
9
+ args: {},
10
+ } satisfies Meta<typeof RadioIcon>;
11
+
12
+ export default meta;
13
+ type Story = StoryObj<typeof meta>;
14
+
15
+ export const Default: Story = {
16
+ args: {
17
+ checked: false,
18
+ },
19
+ };
20
+
21
+ export const Checked: Story = {
22
+ args: {
23
+ checked: true,
24
+ },
25
+ };
@@ -0,0 +1,29 @@
1
+ import cx from 'classnames';
2
+ import styles from './radioIcon.module.css';
3
+
4
+ export type RadioIconProps = {
5
+ checked: boolean;
6
+ title?: string;
7
+ className?: string;
8
+ };
9
+
10
+ /**
11
+ * Radio icon for lists and list items
12
+ */
13
+ export const RadioIcon = ({ checked, title, className }: RadioIconProps) => {
14
+ return (
15
+ <div data-checked={checked} className={cx(styles.radio, className)}>
16
+ <svg
17
+ xmlns="http://www.w3.org/2000/svg"
18
+ fill="none"
19
+ viewBox="0 0 24 24"
20
+ strokeWidth={2.5}
21
+ stroke="currentColor"
22
+ className={styles.icon}
23
+ >
24
+ <title>{title}</title>
25
+ <circle cx="12" cy="12" r="6" fill="currentColor" />
26
+ </svg>
27
+ </div>
28
+ );
29
+ };
@@ -0,0 +1,18 @@
1
+ import type { SVGAttributes } from 'react';
2
+ import { cloneElement, isValidElement } from 'react';
3
+ import type React from 'react';
4
+
5
+ export type IconComponentProps = {
6
+ svgIconComponent: React.ReactNode;
7
+ };
8
+
9
+ export type SvgIconProps = IconComponentProps & SVGAttributes<SVGElement>;
10
+
11
+ export const SvgIcon = ({ svgIconComponent, ...rest }: SvgIconProps) => {
12
+ if (isValidElement(svgIconComponent)) {
13
+ return cloneElement(svgIconComponent, { ...rest });
14
+ }
15
+ return null;
16
+ };
17
+
18
+ SvgIcon.displayName = 'SvgIcon';
@@ -0,0 +1,37 @@
1
+ import * as AkselIcons from '@navikt/aksel-icons';
2
+
3
+ const convertName = (str: string) => str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
4
+
5
+ export const Icon = ({ name = 'inbox' }: { name: string; variant: 'solid' | 'outline' }) => {
6
+ const byIcon = [];
7
+ const byName = {};
8
+
9
+ const addRef = ({ name, type, key: string }: { name: string; type: 'solid' | 'outline'; key: string }) => {
10
+ const icon = `<${string} />`;
11
+ if (!byName[name]) {
12
+ byName[name] = {};
13
+ }
14
+
15
+ byName[name] = {
16
+ ...byName[name],
17
+ [type]: icon,
18
+ };
19
+ };
20
+
21
+ Object.entries(AkselIcons).map(([key]) => {
22
+ const iconName = convertName(key).substring(1);
23
+ let name: string;
24
+
25
+ if (iconName.includes('-fill-icon')) {
26
+ name = iconName.replace('-fill-icon', '');
27
+ addRef({ name, type: 'solid', key });
28
+ } else if (iconName.includes('-icon')) {
29
+ name = iconName.replace('-icon', '');
30
+ addRef({ name, type: 'outline', key });
31
+ }
32
+
33
+ byIcon.push(key);
34
+ });
35
+
36
+ return JSON.stringify(byName);
37
+ };
@@ -0,0 +1,21 @@
1
+ .checkbox {
2
+ font-size: 1rem;
3
+ border: 2px solid;
4
+ border-radius: 2px;
5
+ display: inline-flex;
6
+ align-items: center;
7
+ justify-content: center;
8
+ color: var(--theme-base-default);
9
+ height: 1em;
10
+ width: 1em;
11
+ }
12
+
13
+ .checkbox[data-checked="true"] {
14
+ border-color: var(--theme-base-default);
15
+ background-color: var(--theme-base-default);
16
+ color: var(--theme-background-subtle);
17
+ }
18
+
19
+ .checkbox > svg {
20
+ stroke: currentColor;
21
+ }
@@ -0,0 +1,4 @@
1
+ .icon {
2
+ height: 1em;
3
+ width: 1em;
4
+ }