mirror of
https://github.com/navikt/aksel.git
synced 2026-10-13 01:02:02 +00:00
Compare commits
41
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c855ee0da | ||
|
|
ade35e9fba | ||
|
|
b9d2a65c3f | ||
|
|
5cd1a6d86a | ||
|
|
1bdebfd134 | ||
|
|
138c4523ee | ||
|
|
363d51e2c4 | ||
|
|
1079e8465a | ||
|
|
8dda59082d | ||
|
|
21d5ddd433 | ||
|
|
1b7bc53294 | ||
|
|
4dc5a90c72 | ||
|
|
c7694f8ddd | ||
|
|
10bbdb730b | ||
|
|
f4458f3bb8 | ||
|
|
9dafbeb4eb | ||
|
|
4b4e190c20 | ||
|
|
b7d03bfc89 | ||
|
|
bc259f5b30 | ||
|
|
16cad26378 | ||
|
|
6ee4aa3e82 | ||
|
|
bb5466178a | ||
|
|
efb92be344 | ||
|
|
e3f75f542f | ||
|
|
96610bb543 | ||
|
|
eee7143cf6 | ||
|
|
a1b8cc0364 | ||
|
|
e5d2f7eb8c | ||
|
|
67b8b6626e | ||
|
|
8783f1821d | ||
|
|
d52085f256 | ||
|
|
67e8565da3 | ||
|
|
bb4ff1afc3 | ||
|
|
16c0c15c67 | ||
|
|
f506dca7e1 | ||
|
|
a44b2e2e7c | ||
|
|
d96d368e7b | ||
|
|
d3c0052c33 | ||
|
|
f848bea71a | ||
|
|
1585106c55 | ||
|
|
5ed06e19fe |
No files matched your search
@@ -20,7 +20,11 @@
|
||||
"access": "public",
|
||||
"baseBranch": "main",
|
||||
"updateInternalDependencies": "patch",
|
||||
"ignore": ["aksel.nav.no", "aksel-icons-figma-plugin"],
|
||||
"ignore": [
|
||||
"aksel.nav.no",
|
||||
"aksel-icons-figma-plugin",
|
||||
"eslint-plugin-aksel-local"
|
||||
],
|
||||
|
||||
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
|
||||
"updateInternalDependents": "always"
|
||||
|
||||
@@ -47,6 +47,7 @@ module.exports = {
|
||||
files: ["**/*.test.*", "**/__tests__/*"],
|
||||
extends: ["plugin:jest/recommended", "plugin:testing-library/react"],
|
||||
},
|
||||
|
||||
{
|
||||
files: ["aksel.nav.no/website/**"],
|
||||
env: {
|
||||
@@ -78,6 +79,16 @@ module.exports = {
|
||||
"jsx-a11y/anchor-is-valid": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: [
|
||||
"aksel.nav.no/website/pages/eksempler/**/*.tsx",
|
||||
"aksel.nav.no/website/pages/templates/**/*.tsx",
|
||||
],
|
||||
plugins: ["aksel-local"],
|
||||
rules: {
|
||||
"aksel-local/comment-check": ["error"],
|
||||
},
|
||||
},
|
||||
],
|
||||
globals: {
|
||||
Locale: "readonly",
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
# @navikt/aksel-icons
|
||||
|
||||
## 5.11.3
|
||||
|
||||
## 5.11.2
|
||||
|
||||
## 5.11.1
|
||||
|
||||
## 5.11.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Ikoner: Nytt ikon `PushPin` ([#2503](https://github.com/navikt/aksel/pull/2503))
|
||||
|
||||
## 5.10.4
|
||||
|
||||
## 5.10.3
|
||||
|
||||
## 5.10.2
|
||||
|
||||
## 5.10.1
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.3117 3.25101C15.5796 2.51892 14.3754 2.57898 13.7198 3.38029L10.1358 7.76072C10.1008 7.80356 10.0525 7.83356 9.99854 7.84601L5.5894 8.8635C4.25008 9.17258 3.77354 10.8342 4.74547 11.8061L7.93934 15L3.46967 19.4697C3.17678 19.7626 3.17678 20.2374 3.46967 20.5303C3.76256 20.8232 4.23744 20.8232 4.53033 20.5303L9 16.0607L12.1939 19.2545C13.1658 20.2265 14.8274 19.7499 15.1365 18.4106L16.154 14.0015C16.1664 13.9475 16.1964 13.8992 16.2393 13.8642L20.6197 10.2802C21.421 9.62457 21.4811 8.42042 20.749 7.68833L16.3117 3.25101ZM9.53033 14.4697L13.2545 18.1939C13.3934 18.3327 13.6308 18.2646 13.6749 18.0733L14.6924 13.6642C14.7795 13.2866 14.9895 12.9486 15.2894 12.7032L19.6699 9.11925C19.7843 9.02559 19.7929 8.85357 19.6883 8.74899L15.251 4.31167C15.1464 4.20709 14.9744 4.21567 14.8807 4.33014L11.2968 8.71058C11.0514 9.01048 10.7134 9.22046 10.3358 9.3076L5.92669 10.3251C5.73536 10.3692 5.66728 10.6066 5.80613 10.7455L9.53033 14.4697Z" fill="#23262A"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,9 @@
|
||||
name: PushPin
|
||||
category: Home
|
||||
sub_category: Hosehold items
|
||||
keywords:
|
||||
- pinn
|
||||
- tegnestift
|
||||
variant: Stroke
|
||||
updated_at: 23.11.2023
|
||||
created_at: 23.11.2023
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.3117 3.25101C15.5796 2.51892 14.3754 2.57898 13.7198 3.38029L10.1358 7.76072C10.1008 7.80356 10.0525 7.83356 9.99856 7.84601L5.58942 8.8635C4.2501 9.17258 3.77356 10.8342 4.74548 11.8061L12.1939 19.2545C13.1658 20.2265 14.8274 19.7499 15.1365 18.4106L16.154 14.0015C16.1665 13.9475 16.1965 13.8992 16.2393 13.8642L20.6197 10.2802C21.421 9.62457 21.4811 8.42042 20.749 7.68833L16.3117 3.25101ZM4.53033 20.5303L8.06066 17L7 15.9393L3.46967 19.4697C3.17678 19.7626 3.17678 20.2374 3.46967 20.5303C3.76256 20.8232 4.23744 20.8232 4.53033 20.5303Z" fill="#23262A"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 718 B |
@@ -0,0 +1,9 @@
|
||||
name: PushPinFill
|
||||
category: Home
|
||||
sub_category: Hosehold items
|
||||
keywords:
|
||||
- pinn
|
||||
- tegnestift
|
||||
variant: Fill
|
||||
updated_at: 23.11.2023
|
||||
created_at: 23.11.2023
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/aksel-icons",
|
||||
"version": "5.10.2",
|
||||
"version": "5.11.3",
|
||||
"author": "Aksel | NAV",
|
||||
"homepage": "https://aksel.nav.no/ikoner",
|
||||
"repository": {
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @navikt/aksel-stylelint
|
||||
|
||||
## 5.11.3
|
||||
|
||||
## 5.11.2
|
||||
|
||||
## 5.11.1
|
||||
|
||||
## 5.11.0
|
||||
|
||||
## 5.10.4
|
||||
|
||||
## 5.10.3
|
||||
|
||||
## 5.10.2
|
||||
|
||||
## 5.10.1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/aksel-stylelint",
|
||||
"version": "5.10.2",
|
||||
"version": "5.11.3",
|
||||
"author": "Aksel | NAV",
|
||||
"homepage": "https://aksel.nav.no/grunnleggende/kode/stylelint",
|
||||
"repository": {
|
||||
@@ -35,8 +35,8 @@
|
||||
"dev": "yarn watch:lint"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@navikt/ds-css": "^5.10.2",
|
||||
"@navikt/ds-tokens": "^5.10.2",
|
||||
"@navikt/ds-css": "^5.11.3",
|
||||
"@navikt/ds-tokens": "^5.11.3",
|
||||
"@types/jest": "^29.0.0",
|
||||
"concurrently": "7.2.1",
|
||||
"copyfiles": "2.4.1",
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
# @navikt/aksel
|
||||
|
||||
## 5.11.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`8dda59082`](https://github.com/navikt/aksel/commit/8dda59082d9e64a81751805e6be5c30e3fb9cfaa), [`363d51e2c`](https://github.com/navikt/aksel/commit/363d51e2c414f619026084698911a99ac6b5e0bf)]:
|
||||
- @navikt/ds-css@5.11.3
|
||||
|
||||
## 5.11.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-css@5.11.2
|
||||
|
||||
## 5.11.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`10bbdb730`](https://github.com/navikt/aksel/commit/10bbdb730ba79544fa65e1aacebd865be8672a05)]:
|
||||
- @navikt/ds-css@5.11.1
|
||||
|
||||
## 5.11.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`b7d03bfc8`](https://github.com/navikt/aksel/commit/b7d03bfc89dddb679c49a075bd45d675aacc7a71), [`9dafbeb4e`](https://github.com/navikt/aksel/commit/9dafbeb4eb802532cb9c6ad50ab5bf502e1bd5b4), [`16cad2637`](https://github.com/navikt/aksel/commit/16cad263787ad12978c191e2fb45816d2015ef0c)]:
|
||||
- @navikt/ds-css@5.11.0
|
||||
|
||||
## 5.10.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-css@5.10.4
|
||||
|
||||
## 5.10.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`d3c0052c3`](https://github.com/navikt/aksel/commit/d3c0052c3300189798d04f17c2c2892f7c304277)]:
|
||||
- @navikt/ds-css@5.10.3
|
||||
|
||||
## 5.10.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/aksel",
|
||||
"version": "5.10.2",
|
||||
"version": "5.11.3",
|
||||
"description": "Aksel command line interface. Handles css-imports, codemods and more",
|
||||
"author": "Aksel | NAV designsystem team",
|
||||
"license": "MIT",
|
||||
@@ -29,7 +29,7 @@
|
||||
},
|
||||
"homepage": "https://aksel.nav.no/grunnleggende/kode/kommandolinje",
|
||||
"dependencies": {
|
||||
"@navikt/ds-css": "5.10.2",
|
||||
"@navikt/ds-css": "5.11.3",
|
||||
"axios": "1.6.0",
|
||||
"chalk": "4.1.0",
|
||||
"clipboardy": "^2.3.0",
|
||||
|
||||
@@ -1,5 +1,41 @@
|
||||
# @navikt/ds-css
|
||||
|
||||
## 5.11.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- :bug: Textarea: Skru av autosize ved manuell resize ([#2518](https://github.com/navikt/aksel/pull/2518))
|
||||
|
||||
- Page: La til `md`-bredde (768px) ([#2510](https://github.com/navikt/aksel/pull/2510))
|
||||
|
||||
## 5.11.2
|
||||
|
||||
## 5.11.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Switch: Byttet success-farger med action npr checked ([#2511](https://github.com/navikt/aksel/pull/2511))
|
||||
|
||||
## 5.11.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- :sparkles: Textarea: Mulighet for å sette resize-retning ([#2494](https://github.com/navikt/aksel/pull/2494))
|
||||
|
||||
- :sparkles: Textarea: Eksperimentell støtte for automatisk scrollbar ([#2457](https://github.com/navikt/aksel/pull/2457))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- :wheelchair: Textarea: Forsinkelse ved live-opplesning av gjenstående tegn ([#2502](https://github.com/navikt/aksel/pull/2502))
|
||||
|
||||
## 5.10.4
|
||||
|
||||
## 5.10.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- :bug: Textarea: Teller flyttet ut av tekstfeltet for å unngå overlapp og misforståelser ([#2483](https://github.com/navikt/aksel/pull/2483))
|
||||
|
||||
## 5.10.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
|
||||
.navds-switch__input:hover ~ .navds-switch__label-wrapper,
|
||||
.navds-switch__label-wrapper:hover {
|
||||
color: var(--ac-switch-action, var(--a-surface-action));
|
||||
color: var(--ac-switch-action, var(--a-surface-action-selected));
|
||||
}
|
||||
|
||||
.navds-switch__input:disabled:hover ~ .navds-switch__label-wrapper {
|
||||
@@ -91,7 +91,7 @@
|
||||
}
|
||||
|
||||
.navds-switch__input:checked ~ .navds-switch__track {
|
||||
background-color: var(--ac-switch-checked-bg, var(--a-surface-success));
|
||||
background-color: var(--ac-switch-checked-bg, var(--a-surface-action-selected));
|
||||
}
|
||||
|
||||
.navds-switch__input:hover ~ .navds-switch__track {
|
||||
@@ -99,7 +99,7 @@
|
||||
}
|
||||
|
||||
.navds-switch__input:hover:checked ~ .navds-switch__track {
|
||||
background-color: var(--ac-switch-checked-hover-bg, var(--a-surface-success-hover));
|
||||
background-color: var(--ac-switch-checked-hover-bg, var(--a-surface-action-selected-hover));
|
||||
}
|
||||
|
||||
.navds-switch__input:disabled ~ .navds-switch__track {
|
||||
@@ -107,7 +107,7 @@
|
||||
}
|
||||
|
||||
.navds-switch__input:checked:disabled ~ .navds-switch__track {
|
||||
background-color: var(--ac-switch-checked-bg, var(--a-border-success));
|
||||
background-color: var(--ac-switch-checked-bg, var(--a-border-action-selected));
|
||||
}
|
||||
|
||||
.navds-switch__input:focus-visible ~ .navds-switch__track {
|
||||
@@ -139,7 +139,7 @@
|
||||
|
||||
.navds-switch__input:checked ~ .navds-switch__track > .navds-switch__thumb {
|
||||
transform: translateX(1.25rem);
|
||||
color: var(--ac-switch-thumb-icon-checked, var(--a-icon-success));
|
||||
color: var(--ac-switch-thumb-icon-checked, var(--a-icon-action-selected));
|
||||
}
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
@@ -160,11 +160,6 @@
|
||||
transform: translateX(1.25rem);
|
||||
}
|
||||
|
||||
/* Loader */
|
||||
.navds-switch__input:checked ~ .navds-switch__track > .navds-switch__thumb .navds-loader__foreground {
|
||||
stroke: var(--ac-switch-thumb-icon-checked, var(--a-icon-success));
|
||||
}
|
||||
|
||||
/* Disabled */
|
||||
.navds-switch__input:disabled {
|
||||
appearance: none;
|
||||
|
||||
@@ -21,8 +21,14 @@
|
||||
}
|
||||
|
||||
.navds-textarea__wrapper {
|
||||
--__ac-textarea-height: initial;
|
||||
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
.navds-textarea__input:first-child {
|
||||
height: var(--__ac-textarea-height);
|
||||
}
|
||||
|
||||
.navds-textarea__input {
|
||||
@@ -37,10 +43,6 @@
|
||||
color: var(--ac-textarea-text, var(--__ac-textarea-text, var(--a-text-default)));
|
||||
}
|
||||
|
||||
.navds-textarea--counter {
|
||||
padding-bottom: var(--a-spacing-8);
|
||||
}
|
||||
|
||||
.navds-textarea__input::placeholder {
|
||||
color: var(--ac-textarea-placeholder, var(--__ac-textarea-placeholder, var(--a-text-subtle)));
|
||||
}
|
||||
@@ -65,27 +67,51 @@
|
||||
padding: var(--a-spacing-1-alt);
|
||||
}
|
||||
|
||||
.navds-form-field--small .navds-textarea--counter.navds-textarea__input {
|
||||
padding-bottom: var(--a-spacing-7);
|
||||
}
|
||||
|
||||
.navds-textarea__counter {
|
||||
pointer-events: none;
|
||||
margin-top: var(--a-spacing-05);
|
||||
color: var(--ac-textarea-counter-text, var(--__ac-textarea-counter-text, var(--a-text-subtle)));
|
||||
font-style: italic;
|
||||
position: absolute;
|
||||
text-align: left;
|
||||
left: 0.0625rem;
|
||||
bottom: 0.0625rem;
|
||||
padding: var(--a-spacing-1) var(--a-spacing-2);
|
||||
}
|
||||
|
||||
.navds-textarea__counter--error {
|
||||
color: var(--ac-textarea-counter-error-text, var(--__ac-textarea-counter-error-text, var(--a-text-danger)));
|
||||
}
|
||||
|
||||
.navds-textarea--resize .navds-textarea__input {
|
||||
.navds-textarea__sr-counter {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navds-textarea__wrapper:focus-within .navds-textarea__sr-counter {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
.navds-textarea--resize-both .navds-textarea__input {
|
||||
resize: both;
|
||||
border-end-end-radius: 0;
|
||||
}
|
||||
|
||||
.navds-textarea--resize-horizontal .navds-textarea__input {
|
||||
resize: horizontal;
|
||||
border-end-end-radius: 0;
|
||||
}
|
||||
|
||||
.navds-textarea--resize-vertical .navds-textarea__input {
|
||||
resize: vertical;
|
||||
border-end-end-radius: 0;
|
||||
}
|
||||
|
||||
.navds-textarea--autoscrollbar,
|
||||
.navds-textarea--autoscrollbar .navds-textarea__wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
|
||||
/* Makes the box-shadow visible even though overflow is hidden: */
|
||||
padding: 3px;
|
||||
margin: -3px;
|
||||
}
|
||||
|
||||
.navds-textarea--autoscrollbar .navds-textarea__input {
|
||||
scrollbar-gutter: stable; /* Needed to prevent scrollbar from appearing too early */
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-css",
|
||||
"version": "5.10.2",
|
||||
"version": "5.11.3",
|
||||
"description": "CSS for NAV Designsystem",
|
||||
"author": "Aksel | NAV designsystem team",
|
||||
"keywords": [
|
||||
@@ -27,7 +27,7 @@
|
||||
"css:get-version": "node config/get-version.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@navikt/ds-tokens": "^5.10.2",
|
||||
"@navikt/ds-tokens": "^5.11.3",
|
||||
"cssnano": "6.0.0",
|
||||
"fast-glob": "3.2.11",
|
||||
"lodash": "4.17.21",
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
padding-block-end: var(--a-spacing-8);
|
||||
}
|
||||
|
||||
.navds-pageblock--md {
|
||||
max-width: 768px;
|
||||
}
|
||||
|
||||
.navds-pageblock--lg {
|
||||
max-width: 1024px;
|
||||
}
|
||||
|
||||
@@ -401,14 +401,14 @@
|
||||
"--ac-select-error-border": "--a-surface-danger"
|
||||
},
|
||||
"switch": {
|
||||
"--ac-switch-action": "--a-surface-action",
|
||||
"--ac-switch-action": "--a-surface-action-selected",
|
||||
"--ac-switch-bg": "--a-surface-neutral",
|
||||
"--ac-switch-checked-bg": "--a-surface-success",
|
||||
"--ac-switch-checked-bg": "--a-surface-action-selected",
|
||||
"--ac-switch-hover-bg": "--a-surface-neutral-hover",
|
||||
"--ac-switch-checked-hover-bg": "--a-surface-success-hover",
|
||||
"--ac-switch-checked-hover-bg": "--a-surface-action-selected-hover",
|
||||
"--ac-switch-thumb-bg": "--a-surface-default",
|
||||
"--ac-switch-thumb-icon": "--a-icon-subtle",
|
||||
"--ac-switch-thumb-icon-checked": "--a-icon-success"
|
||||
"--ac-switch-thumb-icon-checked": "--a-icon-action-selected"
|
||||
},
|
||||
"textfield": {
|
||||
"--ac-textfield-bg": "--a-surface-default",
|
||||
|
||||
@@ -1,5 +1,79 @@
|
||||
# @navikt/ds-react
|
||||
|
||||
## 5.11.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- :bug: Textarea: Skru av autosize ved manuell resize ([#2518](https://github.com/navikt/aksel/pull/2518))
|
||||
|
||||
- :bug: Popover: Ikke lukk ved klikk inni når parent er fokuserbar ([#2521](https://github.com/navikt/aksel/pull/2521))
|
||||
|
||||
- Page: La til `md`-bredde (768px) ([#2510](https://github.com/navikt/aksel/pull/2510))
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.11.3
|
||||
- @navikt/aksel-icons@5.11.3
|
||||
|
||||
## 5.11.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ⬆️ upgrade date-fns version & make it minor-version agnostic ([#2514](https://github.com/navikt/aksel/pull/2514))
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.11.2
|
||||
- @navikt/aksel-icons@5.11.2
|
||||
|
||||
## 5.11.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Switch: Byttet success-farger med action npr checked ([#2511](https://github.com/navikt/aksel/pull/2511))
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.11.1
|
||||
- @navikt/aksel-icons@5.11.1
|
||||
|
||||
## 5.11.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- :sparkles: Textarea: Mulighet for å sette resize-retning ([#2494](https://github.com/navikt/aksel/pull/2494))
|
||||
|
||||
- :sparkles: Textarea: Eksperimentell støtte for automatisk scrollbar ([#2457](https://github.com/navikt/aksel/pull/2457))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- :wheelchair: Textarea: Forsinkelse ved live-opplesning av gjenstående tegn ([#2502](https://github.com/navikt/aksel/pull/2502))
|
||||
|
||||
- Updated dependencies [[`bc259f5b3`](https://github.com/navikt/aksel/commit/bc259f5b306319c0e08397d5300596fc1d43353e)]:
|
||||
- @navikt/aksel-icons@5.11.0
|
||||
- @navikt/ds-tokens@5.11.0
|
||||
|
||||
## 5.10.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Gjør lukknapp i Alert til type button ([#2497](https://github.com/navikt/aksel/pull/2497))
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.10.4
|
||||
- @navikt/aksel-icons@5.10.4
|
||||
|
||||
## 5.10.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- :wheelchair: Textarea: Byttet fra `aria-live` til `role=status` på telleren for bedre semantikk ([#2483](https://github.com/navikt/aksel/pull/2483))
|
||||
|
||||
- :bug: Textarea: Teller flyttet ut av tekstfeltet for å unngå overlapp og misforståelser ([#2483](https://github.com/navikt/aksel/pull/2483))
|
||||
|
||||
- ErrorSummary: Gjør det mulig å rendre ErrorSummary.Item conditionally ([#2484](https://github.com/navikt/aksel/pull/2484))
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.10.3
|
||||
- @navikt/aksel-icons@5.10.3
|
||||
|
||||
## 5.10.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-react",
|
||||
"version": "5.10.2",
|
||||
"version": "5.11.3",
|
||||
"description": "Aksel react-components for NAV designsystem",
|
||||
"author": "Aksel | NAV designsystem team",
|
||||
"license": "MIT",
|
||||
@@ -38,12 +38,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@floating-ui/react": "0.25.4",
|
||||
"@navikt/aksel-icons": "^5.10.2",
|
||||
"@navikt/ds-tokens": "^5.10.2",
|
||||
"@navikt/aksel-icons": "^5.11.3",
|
||||
"@navikt/ds-tokens": "^5.11.3",
|
||||
"@radix-ui/react-tabs": "1.0.0",
|
||||
"@radix-ui/react-toggle-group": "1.0.0",
|
||||
"clsx": "^1.2.1",
|
||||
"date-fns": "2.29.3",
|
||||
"date-fns": "^2.30.0",
|
||||
"react-day-picker": "8.3.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -117,6 +117,7 @@ export const Alert = forwardRef<HTMLDivElement, AlertProps>(
|
||||
size="small"
|
||||
variant="tertiary-neutral"
|
||||
onClick={onClose}
|
||||
type="button"
|
||||
icon={<XMarkIcon title="Lukk Alert" />}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -5,11 +5,11 @@ import React, {
|
||||
useEffect,
|
||||
useState,
|
||||
} from "react";
|
||||
import { FormFieldProps, useFormField } from "./useFormField";
|
||||
import { ReadOnlyIcon } from "./ReadOnlyIcon";
|
||||
import { Loader } from "../loader";
|
||||
import { BodyShort } from "../typography";
|
||||
import { omit } from "../util";
|
||||
import { ReadOnlyIcon } from "./ReadOnlyIcon";
|
||||
import { FormFieldProps, useFormField } from "./useFormField";
|
||||
|
||||
const SelectedIcon = () => (
|
||||
<svg
|
||||
@@ -134,7 +134,11 @@ export const Switch = forwardRef<HTMLInputElement, SwitchProps>(
|
||||
<span className="navds-switch__track">
|
||||
<span className="navds-switch__thumb">
|
||||
{loading ? (
|
||||
<Loader size="xsmall" aria-live="polite" />
|
||||
<Loader
|
||||
size="xsmall"
|
||||
aria-live="polite"
|
||||
variant={checked ? "interaction" : "neutral"}
|
||||
/>
|
||||
) : checked ? (
|
||||
<SelectedIcon />
|
||||
) : null}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef, useState } from "react";
|
||||
import { BodyShort, ErrorMessage, Label } from "../typography";
|
||||
import TextareaAutosize from "../util/TextareaAutoSize";
|
||||
import { FormFieldProps, useFormField } from "./useFormField";
|
||||
import { ReadOnlyIcon } from "./ReadOnlyIcon";
|
||||
import { omit, useId } from "../util";
|
||||
import TextareaAutosize from "../util/TextareaAutoSize";
|
||||
import { ReadOnlyIcon } from "./ReadOnlyIcon";
|
||||
import Counter from "./TextareaCounter";
|
||||
import { FormFieldProps, useFormField } from "./useFormField";
|
||||
|
||||
/**
|
||||
* TODO: Mulighet for lokalisering av sr-only/counter text
|
||||
@@ -27,7 +28,6 @@ export interface TextareaProps
|
||||
defaultValue?: string;
|
||||
/**
|
||||
* Maximum number of character rows to display.
|
||||
* @bug Internal scrolling with `maxLength` scrolls over maxLength-text
|
||||
*/
|
||||
maxRows?: number;
|
||||
/**
|
||||
@@ -45,12 +45,18 @@ export interface TextareaProps
|
||||
/**
|
||||
* Enables resizing of field
|
||||
*/
|
||||
resize?: boolean;
|
||||
resize?: boolean | "vertical" | "horizontal";
|
||||
/**
|
||||
* Textarea will stop growing and get a scrollbar when there's no more room to grow.
|
||||
* Requires `display:flex` on the parent.
|
||||
* Experimental feature that may be removed or get breaking changes in a minor version.
|
||||
*/
|
||||
UNSAFE_autoScrollbar?: boolean;
|
||||
/**
|
||||
* i18n-translations for counter-text
|
||||
*/
|
||||
i18n?: {
|
||||
/** @default Antall tegn igjen */
|
||||
/** @default tegn igjen */
|
||||
counterLeft?: string;
|
||||
/** @default tegn for mye */
|
||||
counterTooMuch?: string;
|
||||
@@ -86,6 +92,7 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
maxLength,
|
||||
hideLabel = false,
|
||||
resize,
|
||||
UNSAFE_autoScrollbar,
|
||||
i18n,
|
||||
readOnly,
|
||||
...rest
|
||||
@@ -121,7 +128,9 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
"navds-form-field--readonly": readOnly,
|
||||
"navds-textarea--readonly": readOnly,
|
||||
"navds-textarea--error": hasError,
|
||||
"navds-textarea--resize": resize,
|
||||
"navds-textarea--autoscrollbar": UNSAFE_autoScrollbar,
|
||||
[`navds-textarea--resize-${resize === true ? "both" : resize}`]:
|
||||
resize,
|
||||
}
|
||||
)}
|
||||
>
|
||||
@@ -157,19 +166,17 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
: setControlledValue(e.target.value)
|
||||
}
|
||||
minRows={getMinRows()}
|
||||
autoScrollbar={UNSAFE_autoScrollbar}
|
||||
ref={ref}
|
||||
readOnly={readOnly}
|
||||
className={cl(
|
||||
"navds-textarea__input",
|
||||
"navds-body-short",
|
||||
`navds-body-short--${size ?? "medium"}`,
|
||||
{
|
||||
"navds-textarea--counter": hasMaxLength,
|
||||
}
|
||||
`navds-body-short--${size ?? "medium"}`
|
||||
)}
|
||||
{...(describedBy ? { "aria-describedby": describedBy } : {})}
|
||||
/>
|
||||
{hasMaxLength && (
|
||||
{hasMaxLength && !readOnly && !inputProps.disabled && (
|
||||
<>
|
||||
<span id={maxLengthId} className="navds-sr-only">
|
||||
{`Tekstområde med plass til ${maxLength} tegn.`}
|
||||
@@ -198,22 +205,4 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
}
|
||||
);
|
||||
|
||||
export const Counter = ({ maxLength, currentLength, size, i18n }) => {
|
||||
const difference = maxLength - currentLength;
|
||||
|
||||
return (
|
||||
<BodyShort
|
||||
className={cl("navds-textarea__counter", {
|
||||
"navds-textarea__counter--error": difference < 0,
|
||||
})}
|
||||
aria-live={difference < 20 ? "polite" : "off"}
|
||||
size={size}
|
||||
>
|
||||
{difference < 0
|
||||
? `${Math.abs(difference)} ${i18n?.counterTooMuch ?? "tegn for mye"}`
|
||||
: `${difference} ${i18n?.counterLeft ?? "tegn igjen"}`}
|
||||
</BodyShort>
|
||||
);
|
||||
};
|
||||
|
||||
export default Textarea;
|
||||
@@ -0,0 +1,58 @@
|
||||
import cl from "clsx";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { BodyShort } from "../typography";
|
||||
import debounce from "../util/debounce";
|
||||
import type { TextareaProps } from "./Textarea";
|
||||
|
||||
interface Props {
|
||||
maxLength: number;
|
||||
currentLength: number;
|
||||
size: TextareaProps["size"];
|
||||
i18n: TextareaProps["i18n"];
|
||||
}
|
||||
|
||||
const TextareaCounter = ({ maxLength, currentLength, size, i18n }: Props) => {
|
||||
const difference = maxLength - currentLength;
|
||||
|
||||
const [debouncedDiff, setDebouncedDiff] = useState(difference);
|
||||
|
||||
useEffect(() => {
|
||||
const debounceFunc = debounce(() => {
|
||||
setDebouncedDiff(difference);
|
||||
}, 2000);
|
||||
debounceFunc();
|
||||
|
||||
return () => {
|
||||
debounceFunc.clear();
|
||||
};
|
||||
}, [difference]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{difference < 20 && (
|
||||
<span
|
||||
role="status"
|
||||
className="navds-textarea__sr-counter navds-sr-only"
|
||||
>
|
||||
{getCounterText(debouncedDiff, i18n)}
|
||||
</span>
|
||||
)}
|
||||
|
||||
<BodyShort
|
||||
className={cl("navds-textarea__counter", {
|
||||
"navds-textarea__counter--error": difference < 0,
|
||||
})}
|
||||
size={size}
|
||||
>
|
||||
{getCounterText(difference, i18n)}
|
||||
</BodyShort>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getCounterText = (difference: number, i18n: TextareaProps["i18n"]) =>
|
||||
difference < 0
|
||||
? `${Math.abs(difference)} ${i18n?.counterTooMuch ?? "tegn for mye"}`
|
||||
: `${difference} ${i18n?.counterLeft ?? "tegn igjen"}`;
|
||||
|
||||
export default TextareaCounter;
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { forwardRef, HTMLAttributes } from "react";
|
||||
import React, { forwardRef, HTMLAttributes, isValidElement } from "react";
|
||||
import cl from "clsx";
|
||||
import { Heading, BodyShort } from "../../typography";
|
||||
import ErrorSummaryItem, { ErrorSummaryItemType } from "./ErrorSummaryItem";
|
||||
@@ -100,7 +100,10 @@ export const ErrorSummary = forwardRef<HTMLDivElement, ErrorSummaryProps>(
|
||||
</Heading>
|
||||
<BodyShort as="ul" size={size} className="navds-error-summary__list">
|
||||
{React.Children.map(children, (child) => {
|
||||
return <li key={child?.toString()}>{child}</li>;
|
||||
if (!isValidElement(child)) {
|
||||
return null;
|
||||
}
|
||||
return <li key={child.toString()}>{child}</li>;
|
||||
})}
|
||||
</BodyShort>
|
||||
</section>
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
export {
|
||||
default as ConfirmationPanel,
|
||||
type ConfirmationPanelProps,
|
||||
} from "./ConfirmationPanel";
|
||||
export { Fieldset, FieldsetContext, type FieldsetProps } from "./Fieldset";
|
||||
export { default as Select, type SelectProps } from "./Select";
|
||||
export { default as Switch, type SwitchProps } from "./Switch";
|
||||
export { default as TextField, type TextFieldProps } from "./TextField";
|
||||
export { default as Textarea, type TextareaProps } from "./Textarea";
|
||||
export {
|
||||
Checkbox,
|
||||
CheckboxGroup,
|
||||
type CheckboxGroupProps,
|
||||
type CheckboxProps,
|
||||
} from "./checkbox";
|
||||
export {
|
||||
type ConfirmationPanelProps,
|
||||
default as ConfirmationPanel,
|
||||
} from "./ConfirmationPanel";
|
||||
export { Combobox as UNSAFE_Combobox, type ComboboxProps } from "./combobox";
|
||||
export { ErrorSummary, type ErrorSummaryProps } from "./error-summary";
|
||||
export { Fieldset, FieldsetContext, type FieldsetProps } from "./Fieldset";
|
||||
export {
|
||||
Radio,
|
||||
RadioGroup,
|
||||
@@ -17,8 +22,3 @@ export {
|
||||
type RadioProps,
|
||||
} from "./radio";
|
||||
export { Search, type SearchClearEvent, type SearchProps } from "./search";
|
||||
export { Combobox as UNSAFE_Combobox, type ComboboxProps } from "./combobox";
|
||||
export { default as Select, type SelectProps } from "./Select";
|
||||
export { default as Switch, type SwitchProps } from "./Switch";
|
||||
export { Counter, default as Textarea, type TextareaProps } from "./Textarea";
|
||||
export { default as TextField, type TextFieldProps } from "./TextField";
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Meta, StoryObj } from "@storybook/react";
|
||||
import React from "react";
|
||||
import { Meta, StoryFn, StoryObj } from "@storybook/react";
|
||||
import React, { useState } from "react";
|
||||
import { Button } from "../../button";
|
||||
import { Textarea } from "../index";
|
||||
|
||||
const meta: Meta<typeof Textarea> = {
|
||||
@@ -14,12 +15,15 @@ export const Default: StoryObj<typeof Textarea> = {
|
||||
},
|
||||
|
||||
args: {
|
||||
maxLength: 100,
|
||||
maxLength: 0,
|
||||
label: "Ipsum enim quis culpa",
|
||||
resize: false,
|
||||
},
|
||||
|
||||
argTypes: {
|
||||
resize: {
|
||||
control: { type: "radio" },
|
||||
options: [true, "vertical", "horizontal"],
|
||||
},
|
||||
size: {
|
||||
control: { type: "radio" },
|
||||
options: ["medium", "small"],
|
||||
@@ -28,16 +32,17 @@ export const Default: StoryObj<typeof Textarea> = {
|
||||
error: { type: "string" },
|
||||
hideLabel: { type: "boolean" },
|
||||
disabled: { type: "boolean" },
|
||||
readOnly: { type: "boolean" },
|
||||
maxRows: { type: "number" },
|
||||
minRows: { type: "number" },
|
||||
},
|
||||
};
|
||||
|
||||
export const Small = () => {
|
||||
export const Small: StoryFn = () => {
|
||||
return <Textarea size="small" label="Ipsum enim quis culpa" />;
|
||||
};
|
||||
|
||||
export const Description = () => {
|
||||
export const Description: StoryFn = () => {
|
||||
return (
|
||||
<div className="colgap">
|
||||
<Textarea
|
||||
@@ -53,7 +58,7 @@ export const Description = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export const Error = () => {
|
||||
export const Error: StoryFn = () => {
|
||||
return (
|
||||
<div className="colgap">
|
||||
<Textarea
|
||||
@@ -66,11 +71,25 @@ export const Error = () => {
|
||||
error="Consectetur labore velit eiusmod Lorem ut nostrud mollit labore ullamco laboris laboris in."
|
||||
size="small"
|
||||
/>
|
||||
|
||||
<Textarea
|
||||
label="Ipsum enim quis culpa"
|
||||
error="Consectetur labore velit eiusmod Lorem ut nostrud mollit labore ullamco laboris laboris in."
|
||||
maxLength={20}
|
||||
/>
|
||||
|
||||
<Textarea
|
||||
label="Ipsum enim quis culpa"
|
||||
error="Consectetur labore velit eiusmod Lorem ut nostrud mollit labore ullamco laboris laboris in."
|
||||
value="Sed dignissim sollicitudin porta."
|
||||
maxLength={20}
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Disabled = () => {
|
||||
export const Disabled: StoryFn = () => {
|
||||
return (
|
||||
<div className="colgap">
|
||||
<Textarea label="Ipsum enim quis culpa" disabled />
|
||||
@@ -79,19 +98,19 @@ export const Disabled = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export const HideLabel = () => {
|
||||
export const HideLabel: StoryFn = () => {
|
||||
return <Textarea label="Ipsum enim quis culpa" hideLabel />;
|
||||
};
|
||||
|
||||
export const MaxLength = () => {
|
||||
return <Textarea maxLength={200} label="Ipsum enim quis culpa" />;
|
||||
export const MaxLength: StoryFn = () => {
|
||||
return <Textarea maxLength={50} label="Ipsum enim quis culpa" />;
|
||||
};
|
||||
|
||||
export const MinRows = () => {
|
||||
export const MinRows: StoryFn = () => {
|
||||
return <Textarea minRows={5} label="Ipsum enim quis culpa" />;
|
||||
};
|
||||
|
||||
export const MaxRows = () => {
|
||||
export const MaxRows: StoryFn = () => {
|
||||
return (
|
||||
<Textarea
|
||||
maxRows={3}
|
||||
@@ -101,11 +120,23 @@ export const MaxRows = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export const Resize = () => {
|
||||
export const Resize: StoryFn = () => {
|
||||
return <Textarea resize label="Ipsum enim quis culpa" />;
|
||||
};
|
||||
|
||||
export const Readonly = () => {
|
||||
export const Controlled: StoryFn = () => {
|
||||
const [value, setValue] = useState("");
|
||||
return (
|
||||
<Textarea
|
||||
resize
|
||||
label="Ipsum enim quis culpa"
|
||||
value={value}
|
||||
onChange={(event) => setValue(event.currentTarget.value)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const Readonly: StoryFn = () => {
|
||||
return (
|
||||
<div className="colgap">
|
||||
<Textarea
|
||||
@@ -123,3 +154,35 @@ export const Readonly = () => {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const AutoScrollbar: StoryFn<typeof Textarea> = (props) => (
|
||||
<div
|
||||
style={{
|
||||
border: "1px solid lightGreen",
|
||||
height: "90vh",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<div style={{ border: "1px dashed gray" }}>
|
||||
<h1>Header</h1>
|
||||
</div>
|
||||
<Textarea
|
||||
{...props}
|
||||
resize
|
||||
label="Textarea with autoScrollbar"
|
||||
description="Description"
|
||||
maxLength={30}
|
||||
UNSAFE_autoScrollbar
|
||||
/>
|
||||
<div style={{ border: "1px dashed gray" }}>
|
||||
<Button>Send</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
AutoScrollbar.argTypes = {
|
||||
error: { type: "string" },
|
||||
hideLabel: { type: "boolean" },
|
||||
maxRows: { type: "number" },
|
||||
minRows: { type: "number" },
|
||||
};
|
||||
@@ -2,12 +2,13 @@ import cl from "clsx";
|
||||
import React, { forwardRef } from "react";
|
||||
import { OverridableComponent } from "../../../util/OverridableComponent";
|
||||
|
||||
export const widths = ["lg", "xl", "2xl"] as const;
|
||||
export const widths = ["md", "lg", "xl", "2xl"] as const;
|
||||
|
||||
export interface PageBlockProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
/**
|
||||
* Predefined max-width
|
||||
* @example
|
||||
* md: 768px
|
||||
* lg: 1024px
|
||||
* xl: 1280px
|
||||
* 2xl: 1440px
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import React, { forwardRef } from "react";
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef } from "react";
|
||||
import { OverridableComponent } from "../util/OverridableComponent";
|
||||
|
||||
export interface LinkProps
|
||||
extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
|
||||
/**
|
||||
* Inverts when the underline appears. If this is false,
|
||||
* the underline does not appear by default, but does appear when the link is hovered.
|
||||
* This makes it more suitable for use when inlined in text.
|
||||
* the underline only appears on hover.
|
||||
*
|
||||
* **NB: Underline can only be removed in menus etc. where it's obvious that it's a link.**
|
||||
* @default true
|
||||
*/
|
||||
underline?: boolean;
|
||||
|
||||
@@ -184,9 +184,10 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
|
||||
(e: FocusEvent) => {
|
||||
if (
|
||||
e.target instanceof HTMLElement &&
|
||||
![anchorEl, refs?.floating?.current].some((element) =>
|
||||
![anchorEl, refs.floating.current].some((element) =>
|
||||
element?.contains(e.target as Node)
|
||||
)
|
||||
) &&
|
||||
!e.target.contains(refs.floating.current)
|
||||
) {
|
||||
open && onClose();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
import { Popover } from "../index";
|
||||
import { Button } from "../button";
|
||||
import { Popover } from "../index";
|
||||
|
||||
const placements = [
|
||||
"top",
|
||||
@@ -47,9 +47,9 @@ export default {
|
||||
|
||||
export const Default = (props: any) => {
|
||||
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>();
|
||||
const [open, setOpen] = useState<boolean>(false);
|
||||
const [open, setOpen] = useState(false);
|
||||
return (
|
||||
<div>
|
||||
<div tabIndex={-1}>
|
||||
<Button ref={(el) => setAnchorEl(el)} onClick={() => setOpen((x) => !x)}>
|
||||
Open
|
||||
</Button>
|
||||
@@ -57,10 +57,12 @@ export const Default = (props: any) => {
|
||||
{...props}
|
||||
open={props.open ?? open}
|
||||
anchorEl={anchorEl}
|
||||
onClose={(e) => setOpen(e)}
|
||||
onClose={() => setOpen(false)}
|
||||
>
|
||||
<Popover.Content>Velit in consequat</Popover.Content>
|
||||
</Popover>
|
||||
|
||||
<Button variant="secondary">Another button</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ import "react";
|
||||
|
||||
declare module "react" {
|
||||
interface CSSProperties {
|
||||
[key: `--ac-${string}`]: string | undefined;
|
||||
[key: `--__ac-${string}`]: string | undefined;
|
||||
[key: `--ac-${string}`]: string | number | undefined;
|
||||
[key: `--__ac-${string}`]: string | number | undefined;
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,7 @@ export interface TableType
|
||||
* <Table.Header>
|
||||
* <Table.Row>
|
||||
* <Table.HeaderCell scope="col">Navn</Table.HeaderCell>
|
||||
* <Table.HeaderCell scope="col">Fødseslnr.</Table.HeaderCell>
|
||||
* <Table.HeaderCell scope="col">Fødselsnr.</Table.HeaderCell>
|
||||
* <Table.HeaderCell scope="col">Start</Table.HeaderCell>
|
||||
* </Table.Row>
|
||||
* </Table.Header>
|
||||
|
||||
@@ -1,19 +1,57 @@
|
||||
/* https://github.com/mui/material-ui/blob/master/packages/mui-base/src/TextareaAutosize/TextareaAutosize.js */
|
||||
/* https://github.com/mui/material-ui/blob/master/packages/mui-base/src/TextareaAutosize/TextareaAutosize.tsx */
|
||||
import React, { forwardRef, useEffect, useMemo, useRef, useState } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { debounce, mergeRefs, useClientLayoutEffect } from "../util";
|
||||
|
||||
type State = {
|
||||
outerHeightStyle: number;
|
||||
overflow?: boolean | undefined;
|
||||
};
|
||||
|
||||
const updateState = (
|
||||
prevState: State,
|
||||
newState: State,
|
||||
renders: React.MutableRefObject<number>
|
||||
) => {
|
||||
const { outerHeightStyle, overflow } = newState;
|
||||
// Need a large enough difference to update the height.
|
||||
// This prevents infinite rendering loop.
|
||||
if (
|
||||
renders.current < 20 &&
|
||||
((outerHeightStyle > 0 &&
|
||||
Math.abs((prevState.outerHeightStyle || 0) - outerHeightStyle) > 1) ||
|
||||
prevState.overflow !== overflow)
|
||||
) {
|
||||
renders.current += 1;
|
||||
return {
|
||||
overflow,
|
||||
outerHeightStyle,
|
||||
};
|
||||
}
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
if (renders.current === 20) {
|
||||
console.error(
|
||||
[
|
||||
"Textarea: Too many re-renders. The layout is unstable.",
|
||||
"TextareaAutosize limits the number of renders to prevent an infinite loop.",
|
||||
].join("\n")
|
||||
);
|
||||
}
|
||||
}
|
||||
return prevState;
|
||||
};
|
||||
|
||||
/**
|
||||
* https://github.com/mui/material-ui/blob/master/packages/mui-utils/src/ownerDocument.ts
|
||||
* https://github.com/mui/material-ui/blob/master/packages/mui-utils/src/ownerWindow.ts
|
||||
* https://github.com/mui/material-ui/blob/master/packages/mui-utils/src/ownerDocument/ownerDocument.ts
|
||||
* https://github.com/mui/material-ui/blob/master/packages/mui-utils/src/ownerWindow/ownerWindow.ts
|
||||
*/
|
||||
const ownerWindow = (node: Node | null): Window => {
|
||||
const ownerWindow = (node: Node | undefined): Window => {
|
||||
const doc = (node && node.ownerDocument) || document;
|
||||
return doc.defaultView || window;
|
||||
};
|
||||
|
||||
function getStyleValue(computedStyle, property) {
|
||||
return parseInt(computedStyle[property], 10) || 0;
|
||||
function getStyleValue(value: string) {
|
||||
return parseInt(value, 10) || 0;
|
||||
}
|
||||
|
||||
interface TextareaAutosizeProps
|
||||
@@ -30,34 +68,46 @@ interface TextareaAutosizeProps
|
||||
* @default 1
|
||||
*/
|
||||
minRows?: number;
|
||||
/**
|
||||
* If true, textarea will never get `overflow:hidden`
|
||||
*/
|
||||
autoScrollbar?: boolean;
|
||||
}
|
||||
|
||||
const TextareaAutosize = forwardRef<HTMLTextAreaElement, TextareaAutosizeProps>(
|
||||
(
|
||||
{ className, onChange, maxRows, minRows = 1, style, value, ...other },
|
||||
{
|
||||
className,
|
||||
onChange,
|
||||
maxRows,
|
||||
minRows = 1,
|
||||
autoScrollbar,
|
||||
style,
|
||||
value,
|
||||
...other
|
||||
}: TextareaAutosizeProps,
|
||||
ref
|
||||
) => {
|
||||
const { current: isControlled } = useRef(value != null);
|
||||
const inputRef = useRef<HTMLTextAreaElement | null>(null);
|
||||
const inputRef = useRef<HTMLTextAreaElement>(null);
|
||||
const handleRef = useMemo(() => mergeRefs([inputRef, ref]), [ref]);
|
||||
const shadowRef = useRef<HTMLTextAreaElement | null>(null);
|
||||
const shadowRef = useRef<HTMLTextAreaElement>(null);
|
||||
const renders = useRef(0);
|
||||
const [state, setState] = useState<any>({});
|
||||
const [state, setState] = useState<State>({ outerHeightStyle: 0 });
|
||||
|
||||
const getUpdatedState = React.useCallback(() => {
|
||||
if (!inputRef.current || !shadowRef.current) return;
|
||||
const input = inputRef.current;
|
||||
const input = inputRef.current!;
|
||||
const containerWindow = ownerWindow(input);
|
||||
const computedStyle = containerWindow.getComputedStyle(input);
|
||||
|
||||
// If input's width is shrunk and it's not visible, don't sync height.
|
||||
if (computedStyle.width === "0px") {
|
||||
return;
|
||||
return { outerHeightStyle: 0 };
|
||||
}
|
||||
|
||||
const inputShallow = shadowRef.current;
|
||||
const inputShallow = shadowRef.current!;
|
||||
inputShallow.style.width = computedStyle.width;
|
||||
inputShallow.value = input.value || other?.placeholder || "x";
|
||||
inputShallow.value = input.value || other.placeholder || "x";
|
||||
if (inputShallow.value.slice(-1) === "\n") {
|
||||
// Certain fonts which overflow the line height will cause the textarea
|
||||
// to report a different scrollHeight depending on whether the last line
|
||||
@@ -65,13 +115,13 @@ const TextareaAutosize = forwardRef<HTMLTextAreaElement, TextareaAutosizeProps>(
|
||||
inputShallow.value += " ";
|
||||
}
|
||||
|
||||
const boxSizing = computedStyle["box-sizing"];
|
||||
const boxSizing = computedStyle.boxSizing;
|
||||
const padding =
|
||||
getStyleValue(computedStyle, "padding-bottom") +
|
||||
getStyleValue(computedStyle, "padding-top");
|
||||
getStyleValue(computedStyle.paddingBottom) +
|
||||
getStyleValue(computedStyle.paddingTop);
|
||||
const border =
|
||||
getStyleValue(computedStyle, "border-bottom-width") +
|
||||
getStyleValue(computedStyle, "border-top-width");
|
||||
getStyleValue(computedStyle.borderBottomWidth) +
|
||||
getStyleValue(computedStyle.borderTopWidth);
|
||||
|
||||
// The height of the inner content
|
||||
const innerHeight = inputShallow.scrollHeight - padding;
|
||||
@@ -97,7 +147,7 @@ const TextareaAutosize = forwardRef<HTMLTextAreaElement, TextareaAutosizeProps>(
|
||||
const overflow = Math.abs(outerHeight - innerHeight) <= 1;
|
||||
|
||||
return { outerHeightStyle, overflow };
|
||||
}, [maxRows, minRows, other?.placeholder]);
|
||||
}, [maxRows, minRows, other.placeholder]);
|
||||
|
||||
const syncHeight = React.useCallback(() => {
|
||||
const newState = getUpdatedState();
|
||||
@@ -106,85 +156,61 @@ const TextareaAutosize = forwardRef<HTMLTextAreaElement, TextareaAutosizeProps>(
|
||||
return;
|
||||
}
|
||||
|
||||
setState((prevState) => {
|
||||
return updateState(prevState, newState);
|
||||
});
|
||||
setState((prevState) => updateState(prevState, newState, renders));
|
||||
}, [getUpdatedState]);
|
||||
|
||||
const updateState = (prevState, newState) => {
|
||||
const { outerHeightStyle, overflow } = newState;
|
||||
// Need a large enough difference to update the height.
|
||||
// This prevents infinite rendering loop.
|
||||
if (
|
||||
renders.current < 20 &&
|
||||
((outerHeightStyle > 0 &&
|
||||
Math.abs((prevState.outerHeightStyle || 0) - outerHeightStyle) > 1) ||
|
||||
prevState.overflow !== overflow)
|
||||
) {
|
||||
renders.current += 1;
|
||||
return {
|
||||
overflow,
|
||||
outerHeightStyle,
|
||||
};
|
||||
}
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
if (renders.current === 20) {
|
||||
console.error(
|
||||
[
|
||||
"Textarea: Too many re-renders. The layout is unstable.",
|
||||
"TextareaAutosize limits the number of renders to prevent an infinite loop.",
|
||||
].join("\n")
|
||||
);
|
||||
useClientLayoutEffect(() => {
|
||||
const syncHeightWithFlushSync = () => {
|
||||
const newState = getUpdatedState();
|
||||
|
||||
if (isEmpty(newState)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return prevState;
|
||||
};
|
||||
|
||||
const withFlushSync = () => {
|
||||
const newState = getUpdatedState();
|
||||
|
||||
if (isEmpty(newState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// In React 18, state updates in a ResizeObserver's callback are happening after the paint which causes flickering
|
||||
// when doing some visual updates in it. Using flushSync ensures that the dom will be painted after the states updates happen
|
||||
// Related issue - https://github.com/facebook/react/issues/24331
|
||||
ReactDOM.flushSync(() => {
|
||||
setState((prevState) => {
|
||||
return updateState(prevState, newState);
|
||||
// In React 18, state updates in a ResizeObserver's callback are happening after
|
||||
// the paint, this leads to an infinite rendering.
|
||||
//
|
||||
// Using flushSync ensures that the states is updated before the next pain.
|
||||
// Related issue - https://github.com/facebook/react/issues/24331
|
||||
ReactDOM.flushSync(() => {
|
||||
setState((prevState) => updateState(prevState, newState, renders));
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
const handleResize = debounce(() => {
|
||||
const handleResize = () => {
|
||||
renders.current = 0;
|
||||
|
||||
if (inputRef.current) {
|
||||
withFlushSync();
|
||||
if (inputRef.current?.style.height || inputRef.current?.style.width) {
|
||||
// User has resized manually
|
||||
if (inputRef.current?.style.overflow === "hidden") {
|
||||
setState((oldState) => ({ ...oldState, overflow: false })); // The state update isn't important, we just need to trigger a rerender
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
let resizeObserver: ResizeObserver;
|
||||
|
||||
syncHeightWithFlushSync();
|
||||
};
|
||||
|
||||
const debounceHandleResize = debounce(handleResize);
|
||||
const input = inputRef.current!;
|
||||
const containerWindow = ownerWindow(input);
|
||||
|
||||
containerWindow.addEventListener("resize", handleResize);
|
||||
containerWindow.addEventListener("resize", debounceHandleResize);
|
||||
|
||||
let resizeObserver: ResizeObserver;
|
||||
if (typeof ResizeObserver !== "undefined") {
|
||||
resizeObserver = new ResizeObserver(handleResize);
|
||||
resizeObserver.observe(input);
|
||||
}
|
||||
|
||||
return () => {
|
||||
handleResize.clear();
|
||||
containerWindow.removeEventListener("resize", handleResize);
|
||||
debounceHandleResize.clear();
|
||||
containerWindow.removeEventListener("resize", debounceHandleResize);
|
||||
if (resizeObserver) {
|
||||
resizeObserver.disconnect();
|
||||
}
|
||||
};
|
||||
});
|
||||
}, [getUpdatedState]);
|
||||
|
||||
useClientLayoutEffect(() => {
|
||||
syncHeight();
|
||||
@@ -194,7 +220,7 @@ const TextareaAutosize = forwardRef<HTMLTextAreaElement, TextareaAutosizeProps>(
|
||||
renders.current = 0;
|
||||
}, [value]);
|
||||
|
||||
const handleChange = (event) => {
|
||||
const handleChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
renders.current = 0;
|
||||
|
||||
if (!isControlled) {
|
||||
@@ -206,6 +232,20 @@ const TextareaAutosize = forwardRef<HTMLTextAreaElement, TextareaAutosizeProps>(
|
||||
}
|
||||
};
|
||||
|
||||
const mainStyle: React.CSSProperties = {
|
||||
["--__ac-textarea-height"]: state.outerHeightStyle + "px",
|
||||
// Need a large enough difference to allow scrolling.
|
||||
// This prevents infinite rendering loop.
|
||||
overflow:
|
||||
state.overflow &&
|
||||
!autoScrollbar &&
|
||||
!inputRef.current?.style.height &&
|
||||
!inputRef.current?.style.width
|
||||
? "hidden"
|
||||
: undefined,
|
||||
...style,
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<textarea
|
||||
@@ -214,13 +254,7 @@ const TextareaAutosize = forwardRef<HTMLTextAreaElement, TextareaAutosizeProps>(
|
||||
ref={handleRef}
|
||||
// Apply the rows prop to get a "correct" first SSR paint
|
||||
rows={minRows}
|
||||
style={{
|
||||
height: state.outerHeightStyle,
|
||||
// Need a large enough difference to allow scrolling.
|
||||
// This prevents infinite rendering loop.
|
||||
...(state.overflow ? { overflow: "hidden" } : {}),
|
||||
...style,
|
||||
}}
|
||||
style={mainStyle}
|
||||
{...other}
|
||||
className={className}
|
||||
/>
|
||||
@@ -250,12 +284,12 @@ const TextareaAutosize = forwardRef<HTMLTextAreaElement, TextareaAutosizeProps>(
|
||||
}
|
||||
);
|
||||
|
||||
function isEmpty(obj: any) {
|
||||
function isEmpty(obj: State) {
|
||||
return (
|
||||
obj === undefined ||
|
||||
obj === null ||
|
||||
Object.keys(obj).length === 0 ||
|
||||
(obj?.outerHeightStyle === 0 && !obj?.overflow)
|
||||
(obj.outerHeightStyle === 0 && !obj.overflow)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
src/tokens.ts
|
||||
tailwind.config.js
|
||||
tailwind.config.js
|
||||
!tailwind.config.d.ts
|
||||
@@ -1,5 +1,21 @@
|
||||
# @navikt/ds-tailwind
|
||||
|
||||
## 5.11.3
|
||||
|
||||
## 5.11.2
|
||||
|
||||
## 5.11.1
|
||||
|
||||
## 5.11.0
|
||||
|
||||
## 5.10.4
|
||||
|
||||
## 5.10.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- typescript types for tailwind preset ([#2486](https://github.com/navikt/aksel/pull/2486))
|
||||
|
||||
## 5.10.2
|
||||
|
||||
## 5.10.1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-tailwind",
|
||||
"version": "5.10.2",
|
||||
"version": "5.11.3",
|
||||
"description": "Tailwind config based on @navikt/ds-tokens",
|
||||
"author": "Aksel | NAV designsystem team",
|
||||
"keywords": [
|
||||
@@ -8,9 +8,11 @@
|
||||
"design-tokens"
|
||||
],
|
||||
"main": "tailwind.config.js",
|
||||
"types": "tailwind.config.d.ts",
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
"tailwind.config.js"
|
||||
"tailwind.config.js",
|
||||
"tailwind.config.d.ts"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "ts-node ./src",
|
||||
@@ -22,11 +24,12 @@
|
||||
"directory": "@navikt/core/tailwind"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@navikt/ds-tokens": "^5.10.2",
|
||||
"@navikt/ds-tokens": "^5.11.3",
|
||||
"@types/jest": "^29.0.0",
|
||||
"color": "4.2.3",
|
||||
"jest": "^29.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"ts-jest": "^29.0.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.1.6"
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import type { Config } from "tailwindcss";
|
||||
|
||||
declare const preset: Partial<Config>;
|
||||
|
||||
export default preset;
|
||||
@@ -1,5 +1,17 @@
|
||||
# @navikt/ds-tokens
|
||||
|
||||
## 5.11.3
|
||||
|
||||
## 5.11.2
|
||||
|
||||
## 5.11.1
|
||||
|
||||
## 5.11.0
|
||||
|
||||
## 5.10.4
|
||||
|
||||
## 5.10.3
|
||||
|
||||
## 5.10.2
|
||||
|
||||
## 5.10.1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-tokens",
|
||||
"version": "5.10.2",
|
||||
"version": "5.11.3",
|
||||
"description": "Design-tokens for NAV designsystem",
|
||||
"author": "Aksel | NAV designsystem team",
|
||||
"keywords": [
|
||||
|
||||
+116
-64
@@ -1,9 +1,55 @@
|
||||
# Changelog
|
||||
|
||||
## 5.11
|
||||
|
||||
### @navikt/ds-react
|
||||
|
||||
- :bug: Textarea: Skru av autosize ved manuell resize ([#2518](https://github.com/navikt/aksel/pull/2518))
|
||||
|
||||
- :bug: Popover: Ikke lukk ved klikk inni når parent er fokuserbar ([#2521](https://github.com/navikt/aksel/pull/2521))
|
||||
|
||||
- Page: La til `md`-bredde (768px) ([#2510](https://github.com/navikt/aksel/pull/2510))
|
||||
|
||||
* ⬆️ upgrade date-fns version & make it minor-version agnostic ([#2514](https://github.com/navikt/aksel/pull/2514))
|
||||
|
||||
- Switch: Byttet success-farger med action npr checked ([#2511](https://github.com/navikt/aksel/pull/2511))
|
||||
|
||||
* :sparkles: Textarea: Mulighet for å sette resize-retning ([#2494](https://github.com/navikt/aksel/pull/2494))
|
||||
|
||||
* :sparkles: Textarea: Eksperimentell støtte for automatisk scrollbar ([#2457](https://github.com/navikt/aksel/pull/2457))
|
||||
|
||||
- :wheelchair: Textarea: Forsinkelse ved live-opplesning av gjenstående tegn ([#2502](https://github.com/navikt/aksel/pull/2502))
|
||||
|
||||
### @navikt/ds-css
|
||||
|
||||
- :bug: Textarea: Skru av autosize ved manuell resize ([#2518](https://github.com/navikt/aksel/pull/2518))
|
||||
|
||||
- Page: La til `md`-bredde (768px) ([#2510](https://github.com/navikt/aksel/pull/2510))
|
||||
|
||||
* Switch: Byttet success-farger med action npr checked ([#2511](https://github.com/navikt/aksel/pull/2511))
|
||||
|
||||
- :sparkles: Textarea: Mulighet for å sette resize-retning ([#2494](https://github.com/navikt/aksel/pull/2494))
|
||||
|
||||
- :sparkles: Textarea: Eksperimentell støtte for automatisk scrollbar ([#2457](https://github.com/navikt/aksel/pull/2457))
|
||||
|
||||
* :wheelchair: Textarea: Forsinkelse ved live-opplesning av gjenstående tegn ([#2502](https://github.com/navikt/aksel/pull/2502))
|
||||
|
||||
### @navikt/aksel-icons
|
||||
|
||||
- Ikoner: Nytt ikon `PushPin` ([#2503](https://github.com/navikt/aksel/pull/2503))
|
||||
|
||||
## 5.10
|
||||
|
||||
### @navikt/ds-react
|
||||
|
||||
- Gjør lukknapp i Alert til type button ([#2497](https://github.com/navikt/aksel/pull/2497))
|
||||
|
||||
* :wheelchair: Textarea: Byttet fra `aria-live` til `role=status` på telleren for bedre semantikk ([#2483](https://github.com/navikt/aksel/pull/2483))
|
||||
|
||||
* :bug: Textarea: Teller flyttet ut av tekstfeltet for å unngå overlapp og misforståelser ([#2483](https://github.com/navikt/aksel/pull/2483))
|
||||
|
||||
* ErrorSummary: Gjør det mulig å rendre ErrorSummary.Item conditionally ([#2484](https://github.com/navikt/aksel/pull/2484))
|
||||
|
||||
- OverridableComponent: Fungerer nå bedre ved bruk av typeof <komponent> ([#2474](https://github.com/navikt/aksel/pull/2474))
|
||||
|
||||
* Table: Håndterer nå sjekk for interaktive elementer i ExpandableRow bedre ([#2461](https://github.com/navikt/aksel/pull/2461))
|
||||
@@ -12,9 +58,15 @@
|
||||
|
||||
### @navikt/ds-css
|
||||
|
||||
- Primtives: CSS-import for primitives er nå mer spesifikk ([#2469](https://github.com/navikt/aksel/pull/2469))
|
||||
- :bug: Textarea: Teller flyttet ut av tekstfeltet for å unngå overlapp og misforståelser ([#2483](https://github.com/navikt/aksel/pull/2483))
|
||||
|
||||
* Primitives: Ny komponent `Page` og `Page.Block` ([#2456](https://github.com/navikt/aksel/pull/2456))
|
||||
* Primtives: CSS-import for primitives er nå mer spesifikk ([#2469](https://github.com/navikt/aksel/pull/2469))
|
||||
|
||||
- Primitives: Ny komponent `Page` og `Page.Block` ([#2456](https://github.com/navikt/aksel/pull/2456))
|
||||
|
||||
### @navikt/ds-tailwind
|
||||
|
||||
- typescript types for tailwind preset ([#2486](https://github.com/navikt/aksel/pull/2486))
|
||||
|
||||
## 5.9
|
||||
|
||||
@@ -62,10 +114,6 @@
|
||||
|
||||
## 5.7
|
||||
|
||||
### @navikt/aksel-icons
|
||||
|
||||
- Ikoner: Nye ikoner `ChevronLeftFirstCircle` og `ChevronRightLastCircle` ([#2365](https://github.com/navikt/aksel/pull/2365))
|
||||
|
||||
### @navikt/ds-react
|
||||
|
||||
- :lipstick: Chips.Toggle: Ikon i uvalgt tilstand ([#2395](https://github.com/navikt/aksel/pull/2395))
|
||||
@@ -106,15 +154,11 @@
|
||||
|
||||
- Ny spacing token på 0.375rem ([#2370](https://github.com/navikt/aksel/pull/2370))
|
||||
|
||||
## 5.6
|
||||
|
||||
### @navikt/aksel-icons
|
||||
|
||||
- Ikoner: SVG export setter nå `height="1em"`, `width="1em"` og `fill="currentColor"`. ([#2300](https://github.com/navikt/aksel/pull/2300))
|
||||
- Ikoner: Nye ikoner `ChevronLeftFirstCircle` og `ChevronRightLastCircle` ([#2365](https://github.com/navikt/aksel/pull/2365))
|
||||
|
||||
- Ikoner: Nye ikoner `book` og `books` ([#2313](https://github.com/navikt/aksel/pull/2313))
|
||||
|
||||
* Ikoner: Nye ikoner `ClipboardCheckmark` og `ClipboardLink` ([#2307](https://github.com/navikt/aksel/pull/2307))
|
||||
## 5.6
|
||||
|
||||
### @navikt/ds-react
|
||||
|
||||
@@ -166,6 +210,14 @@
|
||||
|
||||
- Tokens: Tilbyr nå token literals for typer, tidligere string literals ([#2342](https://github.com/navikt/aksel/pull/2342))
|
||||
|
||||
### @navikt/aksel-icons
|
||||
|
||||
- Ikoner: SVG export setter nå `height="1em"`, `width="1em"` og `fill="currentColor"`. ([#2300](https://github.com/navikt/aksel/pull/2300))
|
||||
|
||||
- Ikoner: Nye ikoner `book` og `books` ([#2313](https://github.com/navikt/aksel/pull/2313))
|
||||
|
||||
* Ikoner: Nye ikoner `ClipboardCheckmark` og `ClipboardLink` ([#2307](https://github.com/navikt/aksel/pull/2307))
|
||||
|
||||
## 5.5
|
||||
|
||||
### @navikt/ds-react
|
||||
@@ -206,10 +258,6 @@
|
||||
|
||||
## 5.3
|
||||
|
||||
### @navikt/aksel-icons
|
||||
|
||||
- :bug: SVG import map er nå riktig path ([#2250](https://github.com/navikt/aksel/pull/2250))
|
||||
|
||||
### @navikt/ds-react
|
||||
|
||||
- :bug: Popover: sjekk at det er et HTML-element som får fokus ([#2258](https://github.com/navikt/aksel/pull/2258))
|
||||
@@ -246,11 +294,11 @@
|
||||
|
||||
- Typography: Oppdatert med typo-klasser for `textColor`, `weight`, `align`, `visuallyHidden` og `truncated`. ([#2211](https://github.com/navikt/aksel/pull/2211))
|
||||
|
||||
## 5.2
|
||||
|
||||
### @navikt/aksel-icons
|
||||
|
||||
- Ikoner: Oppdatert ikonpakke ([#2197](https://github.com/navikt/aksel/pull/2197))
|
||||
- :bug: SVG import map er nå riktig path ([#2250](https://github.com/navikt/aksel/pull/2250))
|
||||
|
||||
## 5.2
|
||||
|
||||
### @navikt/ds-react
|
||||
|
||||
@@ -268,6 +316,10 @@
|
||||
|
||||
* Hovering over combobox dropdown will move selection/focus in the list, so we don't end up with a split focus, and reversely when moving focus while hovering ([#2193](https://github.com/navikt/aksel/pull/2193))
|
||||
|
||||
### @navikt/aksel-icons
|
||||
|
||||
- Ikoner: Oppdatert ikonpakke ([#2197](https://github.com/navikt/aksel/pull/2197))
|
||||
|
||||
## 5.1
|
||||
|
||||
### @navikt/ds-react
|
||||
@@ -483,18 +535,18 @@
|
||||
|
||||
* Fikset klassenavn brukt for popover i Datepicker og Monthpicker ([PR](https://github.com/navikt/aksel/pull/2041))
|
||||
|
||||
### @navikt/ds-tailwind
|
||||
|
||||
- Shadow-tokens er oppdatert ([PR](https://github.com/navikt/aksel/pull/2041))
|
||||
|
||||
- Oppdatert text-subtle og icon-subtle tokens til 700-skala (tidligere 600). ([PR](https://github.com/navikt/aksel/pull/2036))
|
||||
|
||||
### @navikt/ds-css
|
||||
|
||||
- :lipstick: Chat: fjernet border, satt avatar svg til 24x24px, byttet om "subtle" og "neutral" ([#2077](https://github.com/navikt/aksel/pull/2077))
|
||||
|
||||
* Shadow-tokens er oppdatert: Datepicker har nå ikke border, Modal bruker shadow-xlarge, LinkCard bruker shadow-xsmall ([PR](https://github.com/navikt/aksel/pull/2041))
|
||||
|
||||
### @navikt/ds-tailwind
|
||||
|
||||
- Shadow-tokens er oppdatert ([PR](https://github.com/navikt/aksel/pull/2041))
|
||||
|
||||
- Oppdatert text-subtle og icon-subtle tokens til 700-skala (tidligere 600). ([PR](https://github.com/navikt/aksel/pull/2036))
|
||||
|
||||
### @navikt/ds-tokens
|
||||
|
||||
- Shadow-tokens er oppdatert til mer tydeligere varianter ([PR](https://github.com/navikt/aksel/pull/2041))
|
||||
@@ -527,10 +579,6 @@
|
||||
|
||||
- Deprecated klassenavn `navds-chips--icon-left` ([PR](https://github.com/navikt/aksel/pull/2035))
|
||||
|
||||
### @navikt/aksel-icons
|
||||
|
||||
- Nye ikoner `ChevronRightLast` og `ChevronLeftLast` ([PR](https://github.com/navikt/aksel/pull/2054))
|
||||
|
||||
### @navikt/ds-react
|
||||
|
||||
- Fikset JSDom-problemer ved testing av Timeline
|
||||
@@ -555,10 +603,6 @@
|
||||
|
||||
- Accordion: La til `indent`-prop ([PR](https://github.com/navikt/aksel/pull/2027))
|
||||
|
||||
### @navikt/ds-tailwind
|
||||
|
||||
- :tada: Fargetokens for datavisualisering. ([PR](https://github.com/navikt/aksel/pull/2032))
|
||||
|
||||
### @navikt/ds-css
|
||||
|
||||
- Readmore: setter nå eksplisitt color for å ikke arve text-subtle fra parent. ([PR](https://github.com/navikt/aksel/pull/2049))
|
||||
@@ -569,12 +613,20 @@
|
||||
|
||||
- Alle description-felter på fieldsets har nå `text-subtle` som farge. ([PR](https://github.com/navikt/aksel/pull/2036))
|
||||
|
||||
### @navikt/ds-tailwind
|
||||
|
||||
- :tada: Fargetokens for datavisualisering. ([PR](https://github.com/navikt/aksel/pull/2032))
|
||||
|
||||
### @navikt/ds-tokens
|
||||
|
||||
- :tada: Fargetokens for datavisualisering. ([PR](https://github.com/navikt/aksel/pull/2032))
|
||||
|
||||
- Oppdatert text-subtle og icon-subtle tokens til 700-skala (tidligere 600). ([PR](https://github.com/navikt/aksel/pull/2036))
|
||||
|
||||
### @navikt/aksel-icons
|
||||
|
||||
- Nye ikoner `ChevronRightLast` og `ChevronLeftLast` ([PR](https://github.com/navikt/aksel/pull/2054))
|
||||
|
||||
## 4.0
|
||||
|
||||
### @navikt/aksel
|
||||
@@ -627,10 +679,6 @@
|
||||
|
||||
## 3.2
|
||||
|
||||
### @navikt/aksel-icons
|
||||
|
||||
- Nye ikoner `FileParagraph` og `FilePlus` ([PR](https://github.com/navikt/aksel/pull/1998))
|
||||
|
||||
### @navikt/ds-react
|
||||
|
||||
- Search: Støtter nå htmlSize-prop ([PR](https://github.com/navikt/aksel/pull/2000))
|
||||
@@ -649,6 +697,10 @@
|
||||
|
||||
- CopyButton: `xsmall`-size for bruk i tabeller ([PR](https://github.com/navikt/aksel/pull/1994))
|
||||
|
||||
### @navikt/aksel-icons
|
||||
|
||||
- Nye ikoner `FileParagraph` og `FilePlus` ([PR](https://github.com/navikt/aksel/pull/1998))
|
||||
|
||||
## 3.1
|
||||
|
||||
### @navikt/ds-react
|
||||
@@ -681,16 +733,6 @@
|
||||
|
||||
## 2.9
|
||||
|
||||
### @navikt/aksel-icons
|
||||
|
||||
- Oppdatert Statusikoner til å være tydeligere og mer konsistente. ([PR](https://github.com/navikt/aksel/pull/1959))
|
||||
|
||||
* Fikset `CheckmarkIcon`-bug
|
||||
|
||||
- Fikset `CheckmarkCircleIcon`-bug ([PR](https://github.com/navikt/aksel/pull/1956))
|
||||
|
||||
* Nye ikoner `BulletList` og `NumberList` ([PR](https://github.com/navikt/aksel/pull/1950))
|
||||
|
||||
### @navikt/aksel
|
||||
|
||||
- :truck: Flyttet Codemods fra `@navikt/ds-codemods` -> `@navikt/aksel`. `@navikt/ds-codemods` regnes nå som deprecated ([PR](https://github.com/navikt/aksel/pull/1952))
|
||||
@@ -703,19 +745,17 @@
|
||||
|
||||
- CSS nå tilgjengelig som separate filer: Kan lastest fra CDN, minified-versjoner tilgjengelig ([PR](https://github.com/navikt/aksel/pull/1941))
|
||||
|
||||
## 2.8
|
||||
|
||||
### @navikt/aksel-icons
|
||||
|
||||
- :tada: Nye ikoner `HandKnot` og `HandKnotFilled` ([PR](https://github.com/navikt/aksel/pull/1928))
|
||||
- Oppdatert Statusikoner til å være tydeligere og mer konsistente. ([PR](https://github.com/navikt/aksel/pull/1959))
|
||||
|
||||
* Oppdatert `InformationSquare`-ikon ([PR](https://github.com/navikt/aksel/pull/1921))
|
||||
* Fikset `CheckmarkIcon`-bug
|
||||
|
||||
- Oppdatert `VideoSlack`, `Questionmark` og `Information`-ikoner ([PR](https://github.com/navikt/aksel/pull/1909))
|
||||
- Fikset `CheckmarkCircleIcon`-bug ([PR](https://github.com/navikt/aksel/pull/1956))
|
||||
|
||||
* Nye ikoner `VideoSlash` og `VideoSlashFill`
|
||||
* Nye ikoner `BulletList` og `NumberList` ([PR](https://github.com/navikt/aksel/pull/1950))
|
||||
|
||||
- Fikset Sourcemap-bug
|
||||
## 2.8
|
||||
|
||||
### @navikt/ds-react
|
||||
|
||||
@@ -751,8 +791,26 @@
|
||||
|
||||
- ExpansioCard: Oppdatert typografi ([PR](https://github.com/navikt/aksel/pull/1870))
|
||||
|
||||
### @navikt/aksel-icons
|
||||
|
||||
- :tada: Nye ikoner `HandKnot` og `HandKnotFilled` ([PR](https://github.com/navikt/aksel/pull/1928))
|
||||
|
||||
* Oppdatert `InformationSquare`-ikon ([PR](https://github.com/navikt/aksel/pull/1921))
|
||||
|
||||
- Oppdatert `VideoSlack`, `Questionmark` og `Information`-ikoner ([PR](https://github.com/navikt/aksel/pull/1909))
|
||||
|
||||
* Nye ikoner `VideoSlash` og `VideoSlashFill`
|
||||
|
||||
- Fikset Sourcemap-bug
|
||||
|
||||
## 2.7
|
||||
|
||||
### @navikt/ds-css
|
||||
|
||||
- Tabs: La til focus-markering for Tabs.Panel ([PR](https://github.com/navikt/aksel/pull/1863))
|
||||
|
||||
* ToggleGroup: Fikset token-bug
|
||||
|
||||
### @navikt/aksel-icons
|
||||
|
||||
- Nye ikoner `CaretUpDownFilledDown`, `CaretUpDownFilledUp`, `CloudDown`, `CloudDownFill`, `CloudUp`, `CloudUpFill`, `HddDown`, `HddDownFill`, `HddUp`, `HddUpFill`, `Inbox`, `InboxDown`, `InboxDownFill`, `InboxFill`, `InboxUp`, `InboxUpFill`, `ShoppingBasket`, `ShoppingBasketFill`
|
||||
@@ -761,12 +819,6 @@
|
||||
|
||||
- Ny ikonpakke med for core icons 3! `@navikt/aksel-icons` ([PR](https://github.com/navikt/aksel/pull/1847))
|
||||
|
||||
### @navikt/ds-css
|
||||
|
||||
- Tabs: La til focus-markering for Tabs.Panel ([PR](https://github.com/navikt/aksel/pull/1863))
|
||||
|
||||
* ToggleGroup: Fikset token-bug
|
||||
|
||||
## 2.6
|
||||
|
||||
### @navikt/ds-react
|
||||
@@ -881,10 +933,6 @@
|
||||
|
||||
* Fonter blir bruk i all typografi blir nå lastet fra CDN
|
||||
|
||||
### @navikt/ds-tailwind
|
||||
|
||||
- Alle token er oppdatert til nytt format. ([Guide](https://aksel.nav.no/grunnleggende/kode/migrering#h76f47744d112))
|
||||
|
||||
### @navikt/ds-css
|
||||
|
||||
- Radio: Fikset default visuell error-state ([PR](https://github.com/navikt/aksel/pull/1737))
|
||||
@@ -897,6 +945,10 @@
|
||||
|
||||
* Tokens: Alle komponenter bruker nå semantiske tokens for som standard, med innebygd støtte for komponent-spesifikke tokens.
|
||||
|
||||
### @navikt/ds-tailwind
|
||||
|
||||
- Alle token er oppdatert til nytt format. ([Guide](https://aksel.nav.no/grunnleggende/kode/migrering#h76f47744d112))
|
||||
|
||||
### @navikt/ds-tokens
|
||||
|
||||
- Alle token er oppdatert til nytt format. ([Guide](https://aksel.nav.no/grunnleggende/kode/migrering#h76f47744d112))
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
"playroom"
|
||||
],
|
||||
"dependencies": {
|
||||
"@navikt/aksel-icons": "^5.10.2",
|
||||
"@navikt/ds-css": "^5.10.2",
|
||||
"@navikt/ds-react": "^5.10.2",
|
||||
"@navikt/ds-tailwind": "^5.10.2",
|
||||
"@navikt/ds-tokens": "^5.10.2"
|
||||
"@navikt/aksel-icons": "^5.11.3",
|
||||
"@navikt/ds-css": "^5.11.3",
|
||||
"@navikt/ds-react": "^5.11.3",
|
||||
"@navikt/ds-tailwind": "^5.11.3",
|
||||
"@navikt/ds-tokens": "^5.11.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier-plugin-tailwindcss": "^0.2.3"
|
||||
|
||||
@@ -12,7 +12,8 @@ module.exports = {
|
||||
// Optional:
|
||||
title: "Aksel Sandbox",
|
||||
snippets: path.resolve("./src/snippets.ts"),
|
||||
widths: [480, 768, 1024, 1280],
|
||||
widths: [320, 480, 768, 1024, 1280, 1440],
|
||||
defaultWidths: [320, 1280], // will be supported if this PR is merged: https://github.com/seek-oss/playroom/pull/302
|
||||
port: 9000,
|
||||
frameComponent: path.resolve("./src/FrameComponent.tsx"),
|
||||
useScope: path.resolve("./src/useScope.tsx"),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { loadCsf } from "@storybook/csf-tools";
|
||||
import type { StorybookConfig } from "@storybook/nextjs";
|
||||
import { readFileSync } from "fs";
|
||||
import { dirname, join } from "path";
|
||||
import { dirname, join, resolve } from "path";
|
||||
|
||||
/**
|
||||
* This function is used to resolve the absolute path of a package.
|
||||
@@ -65,5 +65,74 @@ const config: StorybookConfig = {
|
||||
docs: {
|
||||
autodocs: "tag",
|
||||
},
|
||||
webpackFinal: async (sbConfig: any) => {
|
||||
if (!sbConfig.resolve.alias) {
|
||||
return sbConfig;
|
||||
}
|
||||
// Add path aliases
|
||||
sbConfig.resolve.alias["@/sb-util"] = resolve(__dirname, "./utils.tsx");
|
||||
sbConfig.resolve.alias["@/types"] = resolve(
|
||||
__dirname,
|
||||
"../components/types/index.ts"
|
||||
);
|
||||
sbConfig.resolve.alias["@/sanity-block"] = resolve(
|
||||
__dirname,
|
||||
"../components/website-modules/SanityBlockContent.tsx"
|
||||
);
|
||||
sbConfig.resolve.alias["@/hooks"] = resolve(
|
||||
__dirname,
|
||||
"../components/hooks/"
|
||||
);
|
||||
sbConfig.resolve.alias["@/logging"] = resolve(
|
||||
__dirname,
|
||||
"../components/logging/index.ts"
|
||||
);
|
||||
sbConfig.resolve.alias["@/utils"] = resolve(
|
||||
__dirname,
|
||||
"../components/utils/index.ts"
|
||||
);
|
||||
sbConfig.resolve.alias["@/utils"] = resolve(
|
||||
__dirname,
|
||||
"../components/utils/index.ts"
|
||||
);
|
||||
sbConfig.resolve.alias["@/layout"] = resolve(
|
||||
__dirname,
|
||||
"../components/layout/"
|
||||
);
|
||||
sbConfig.resolve.alias["@/assets"] = resolve(
|
||||
__dirname,
|
||||
"../components/assets/"
|
||||
);
|
||||
sbConfig.resolve.alias["@/web"] = resolve(
|
||||
__dirname,
|
||||
"../components/website-modules/"
|
||||
);
|
||||
sbConfig.resolve.alias["@/cms"] = resolve(
|
||||
__dirname,
|
||||
"../components/sanity-modules/"
|
||||
);
|
||||
sbConfig.resolve.alias["@/error-boundary"] = resolve(
|
||||
__dirname,
|
||||
"../components/website-modules/ErrorBoundary.tsx"
|
||||
);
|
||||
sbConfig.resolve.alias["@/sanity/config"] = resolve(
|
||||
__dirname,
|
||||
"../sanity/config.ts"
|
||||
);
|
||||
sbConfig.resolve.alias["@/sanity/client.server"] = resolve(
|
||||
__dirname,
|
||||
"../sanity/interface/client.server.js"
|
||||
);
|
||||
sbConfig.resolve.alias["@/sanity/interface"] = resolve(
|
||||
__dirname,
|
||||
"../sanity/interface/interface.ts"
|
||||
);
|
||||
sbConfig.resolve.alias["@/sanity/queries"] = resolve(
|
||||
__dirname,
|
||||
"../sanity/interface/queries.js"
|
||||
);
|
||||
|
||||
return sbConfig;
|
||||
},
|
||||
};
|
||||
export default config;
|
||||
@@ -1,8 +1,8 @@
|
||||
import { FigmaIcon, GithubIcon, SlackIcon } from "@/assets/Icons";
|
||||
import AkselLogo from "@/assets/Logo";
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { BodyShort, Heading, Link } from "@navikt/ds-react";
|
||||
import { Box, HGrid, Page, VStack } from "@navikt/ds-react";
|
||||
import dynamic from "next/dynamic";
|
||||
import LinkBlock from "./parts/LinkBlock";
|
||||
|
||||
export const EditButton = dynamic(() => import("@/web/EditButton"), {
|
||||
ssr: false,
|
||||
@@ -10,116 +10,83 @@ export const EditButton = dynamic(() => import("@/web/EditButton"), {
|
||||
|
||||
const Footer = () => {
|
||||
return (
|
||||
<footer
|
||||
id="aksel-footer"
|
||||
data-hj-suppress
|
||||
<Box
|
||||
as="footer"
|
||||
data-theme="dark"
|
||||
className="toc-ignore text-text-on-inverted bg-deepblue-800 relative flex w-full justify-center"
|
||||
id="aksel-footer"
|
||||
className="relative"
|
||||
background="surface-alt-3-strong"
|
||||
paddingBlock="12 16"
|
||||
>
|
||||
<div className="relative z-10 mx-auto grid w-full max-w-screen-2xl gap-12 px-4 pb-16 pt-12 md:grid-cols-2 md:px-6 lg:grid-cols-4 xl:grid-cols-4 xl:gap-6">
|
||||
<LogoBlock />
|
||||
<Snarveier />
|
||||
<SideLenker />
|
||||
<Kontakt />
|
||||
</div>
|
||||
<EditButton />
|
||||
</footer>
|
||||
<Page.Block width="2xl" gutters>
|
||||
<HGrid columns={{ xs: 1, md: 2, lg: 4 }} gap={{ xs: "12", xl: "6" }}>
|
||||
<VStack gap="4">
|
||||
<AkselLogo className="fill-white" />
|
||||
<div>
|
||||
<p>© {new Date().getFullYear()} NAV</p>
|
||||
<p>Arbeids- og velferdsetaten</p>
|
||||
</div>
|
||||
</VStack>
|
||||
<LinkBlock
|
||||
heading="Snarveier"
|
||||
links={[
|
||||
{
|
||||
url: "/god-praksis/artikler/skriv-for-aksel",
|
||||
text: "Skriv for Aksel",
|
||||
},
|
||||
{
|
||||
url: "/prinsipper/brukeropplevelse",
|
||||
text: "Prinsipper for brukeropplevelse",
|
||||
},
|
||||
{ url: "https://sikkerhet.nav.no/", text: "Security Playbook" },
|
||||
{
|
||||
url: "https://etterlevelse.intern.nav.no/",
|
||||
text: "Etterlevelse",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<LinkBlock
|
||||
heading="Om nettstedet"
|
||||
links={[
|
||||
{
|
||||
url: "/god-praksis/artikler/om-aksel",
|
||||
text: "Hva er Aksel?",
|
||||
},
|
||||
{
|
||||
url: "/side/personvernerklaering",
|
||||
text: "Personvernerklæring",
|
||||
},
|
||||
{
|
||||
url: "/side/tilgjengelighetserklaring-for-aksel",
|
||||
text: "Tilgjengelighetserklæring",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<LinkBlock
|
||||
heading="Finn oss"
|
||||
links={[
|
||||
{
|
||||
url: "https://www.figma.com/@nav_aksel",
|
||||
text: "Figma",
|
||||
icon: <FigmaIcon />,
|
||||
},
|
||||
{
|
||||
url: "https://github.com/navikt/aksel",
|
||||
text: "Github",
|
||||
icon: <GithubIcon />,
|
||||
},
|
||||
{
|
||||
url: "https://nav-it.slack.com/archives/C7NE7A8UF",
|
||||
text: "Slack",
|
||||
icon: <SlackIcon />,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</HGrid>
|
||||
</Page.Block>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
function LogoBlock() {
|
||||
return (
|
||||
<div>
|
||||
<AkselLogo className="fill-white" />
|
||||
<p className="mt-4">© {new Date().getFullYear()} NAV</p>
|
||||
<p>Arbeids- og velferdsetaten</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Snarveier() {
|
||||
return (
|
||||
<div>
|
||||
<Heading level="2" size="xsmall">
|
||||
Snarveier
|
||||
</Heading>
|
||||
<BodyShort as="ul" className="mt-3 grid gap-3">
|
||||
<FooterLink href="/god-praksis/artikler/skriv-for-aksel">
|
||||
Skriv for Aksel
|
||||
</FooterLink>
|
||||
<FooterLink href="/prinsipper/brukeropplevelse">
|
||||
Prinsipper for brukeropplevelse
|
||||
</FooterLink>
|
||||
{/* <FooterLink href="https://identitet.nav.no/">Identitet</FooterLink> */}
|
||||
<FooterLink href="https://sikkerhet.nav.no/">
|
||||
Security Playbook
|
||||
</FooterLink>
|
||||
<FooterLink href="https://etterlevelse.intern.nav.no/">
|
||||
Etterlevelse
|
||||
</FooterLink>
|
||||
</BodyShort>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Kontakt() {
|
||||
return (
|
||||
<div>
|
||||
<Heading level="2" size="xsmall">
|
||||
Finn oss
|
||||
</Heading>
|
||||
<BodyShort as="ul" className="mt-3 grid gap-3">
|
||||
<FooterLink href="https://www.figma.com/@nav_aksel">
|
||||
<FigmaIcon />
|
||||
Figma
|
||||
</FooterLink>
|
||||
<FooterLink href="https://github.com/navikt/aksel">
|
||||
<GithubIcon />
|
||||
Github
|
||||
</FooterLink>
|
||||
<FooterLink href="https://nav-it.slack.com/archives/C7NE7A8UF">
|
||||
<SlackIcon />
|
||||
Slack
|
||||
</FooterLink>
|
||||
</BodyShort>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
function SideLenker() {
|
||||
return (
|
||||
<div>
|
||||
<Heading level="2" size="xsmall">
|
||||
Om nettstedet
|
||||
</Heading>
|
||||
<BodyShort as="ul" className="mt-3 grid gap-3">
|
||||
<FooterLink href="/god-praksis/artikler/om-aksel">
|
||||
Hva er Aksel?
|
||||
</FooterLink>
|
||||
<FooterLink href="/side/personvernerklaering">
|
||||
Personvernerklæring
|
||||
</FooterLink>
|
||||
<FooterLink href="/side/tilgjengelighetserklaring-for-aksel">
|
||||
Tilgjengelighetserklæring
|
||||
</FooterLink>
|
||||
</BodyShort>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function FooterLink({ children, href }) {
|
||||
return (
|
||||
<li>
|
||||
<Link
|
||||
className="text-text-on-inverted focus:shadow-focus focus:text-text-default flex w-fit items-center gap-1 underline hover:no-underline focus:bg-blue-200 focus:shadow-blue-200"
|
||||
href={href}
|
||||
onClick={(e) =>
|
||||
amplitudeLogNavigation("footer", e.currentTarget.getAttribute("href"))
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
export default Footer;
|
||||
@@ -0,0 +1,19 @@
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { Link } from "@navikt/ds-react";
|
||||
|
||||
function FooterLink({ children, href }) {
|
||||
return (
|
||||
<li>
|
||||
<Link
|
||||
className="text-text-on-inverted focus:shadow-focus focus:text-text-default flex w-fit items-center gap-1 underline hover:no-underline focus:bg-blue-200 focus:shadow-blue-200"
|
||||
href={href}
|
||||
onClick={(e) =>
|
||||
amplitudeLogNavigation("footer", e.currentTarget.getAttribute("href"))
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
export default FooterLink;
|
||||
@@ -0,0 +1,27 @@
|
||||
import { BodyShort, Heading } from "@navikt/ds-react";
|
||||
import FooterLink from "./FooterLink";
|
||||
|
||||
type LinkBlockPropsT = {
|
||||
heading: string;
|
||||
links: { url: string; text: string; icon?: React.ReactNode }[];
|
||||
};
|
||||
|
||||
function LinkBlock({ heading, links }: LinkBlockPropsT) {
|
||||
return (
|
||||
<div>
|
||||
<Heading level="2" size="xsmall">
|
||||
{heading}
|
||||
</Heading>
|
||||
<BodyShort as="ul" className="mt-3 grid gap-3">
|
||||
{links.map((link) => (
|
||||
<FooterLink key={link.url} href={link.url}>
|
||||
{link.icon}
|
||||
{link.text}
|
||||
</FooterLink>
|
||||
))}
|
||||
</BodyShort>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default LinkBlock;
|
||||
@@ -1,102 +0,0 @@
|
||||
import { MenuHamburgerIcon } from "@navikt/aksel-icons";
|
||||
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { Modal } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { useState } from "react";
|
||||
|
||||
const LinkElement = ({ name, href, onClick }) => {
|
||||
const { asPath } = useRouter();
|
||||
return (
|
||||
<li className="my-2 flex h-11 items-center">
|
||||
<Link
|
||||
href={href}
|
||||
passHref
|
||||
className={cl(
|
||||
"hover:bg-surface-action-subtle-hover focus-visible:shadow-focus relative flex h-full w-full items-center rounded px-2 focus:outline-none",
|
||||
{
|
||||
"before:bg-surface-action-selected pl-4 font-semibold before:absolute before:left-0 before:h-6 before:w-1 before:rounded-full":
|
||||
asPath.startsWith(href),
|
||||
"": !asPath.startsWith(href),
|
||||
}
|
||||
)}
|
||||
onClick={(e) => {
|
||||
amplitudeLogNavigation(
|
||||
"header",
|
||||
e.currentTarget.getAttribute("href")
|
||||
);
|
||||
onClick();
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
export const Hamburger = () => {
|
||||
const [open, setOpen] = useState(false);
|
||||
return (
|
||||
<>
|
||||
<div className="mr-2 grid h-full place-content-center lg:hidden">
|
||||
<button
|
||||
onClick={() => setOpen(!open)}
|
||||
aria-expanded={open}
|
||||
className="focus-visible:shadow-focus hover:bg-surface-neutral-subtle-hover ml-2 flex aspect-square items-center justify-center rounded px-3 py-3 focus:outline-none"
|
||||
>
|
||||
<MenuHamburgerIcon
|
||||
fontSize="2rem"
|
||||
className="pointer-events-none"
|
||||
aria-label="Åpne meny"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<Modal
|
||||
open={open}
|
||||
onClose={() => setOpen(false)}
|
||||
header={{ heading: "Meny" }}
|
||||
width="small"
|
||||
closeOnBackdropClick
|
||||
>
|
||||
<Modal.Body>
|
||||
<nav aria-label="hovedmeny">
|
||||
<ul>
|
||||
<LinkElement
|
||||
onClick={() => setOpen(false)}
|
||||
name="God praksis"
|
||||
href="/god-praksis"
|
||||
/>
|
||||
<LinkElement
|
||||
onClick={() => setOpen(false)}
|
||||
name="Grunnleggende"
|
||||
href="/grunnleggende"
|
||||
/>
|
||||
<LinkElement
|
||||
onClick={() => setOpen(false)}
|
||||
name="Ikoner"
|
||||
href="/ikoner"
|
||||
/>
|
||||
<LinkElement
|
||||
onClick={() => setOpen(false)}
|
||||
name="Komponenter"
|
||||
href="/komponenter"
|
||||
/>
|
||||
<LinkElement
|
||||
onClick={() => setOpen(false)}
|
||||
name="Mønster & Maler"
|
||||
href="/monster-maler"
|
||||
/>
|
||||
<LinkElement
|
||||
onClick={() => setOpen(false)}
|
||||
name="Blogg"
|
||||
href="/produktbloggen"
|
||||
/>
|
||||
</ul>
|
||||
</nav>
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,12 +1,12 @@
|
||||
import AkselLogo from "@/assets/Logo";
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { MagnifyingGlassIcon } from "@navikt/aksel-icons";
|
||||
import { Button } from "@navikt/ds-react";
|
||||
import { Box, Button, HStack, Page, Show, Spacer } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import dynamic from "next/dynamic";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { Hamburger } from "./Hamburger";
|
||||
import { Hamburger } from "./parts/Hamburger";
|
||||
import HeaderLink from "./parts/HeaderLink";
|
||||
|
||||
export const GlobalSearch = dynamic(
|
||||
() => import("../../website-modules/search/Search"),
|
||||
@@ -32,92 +32,64 @@ export const GlobalSearch = dynamic(
|
||||
}
|
||||
);
|
||||
|
||||
const LinkElement = ({ name, href, prefetch = undefined }) => {
|
||||
const { asPath } = useRouter();
|
||||
return (
|
||||
<li>
|
||||
<Link
|
||||
href={href}
|
||||
prefetch={prefetch}
|
||||
className={cl(
|
||||
"text-deepblue-800 focus-visible:shadow-focus relative grid h-11 place-items-center rounded px-2 focus:outline-none",
|
||||
{
|
||||
"before:bg-deepblue-600 font-semibold before:absolute before:bottom-[1px] before:z-10 before:h-1 before:w-[calc(100%_-_16px)] before:rounded-full":
|
||||
asPath.startsWith(href),
|
||||
"hover:before:bg-border-subtle-hover before:absolute before:bottom-[1px] before:z-10 before:h-1 before:w-[calc(100%_-_16px)] before:rounded-full":
|
||||
!asPath.startsWith(href),
|
||||
}
|
||||
)}
|
||||
onClick={(e) =>
|
||||
amplitudeLogNavigation("header", e.currentTarget.getAttribute("href"))
|
||||
}
|
||||
>
|
||||
{name}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
const Header = ({
|
||||
variant = "default",
|
||||
}: {
|
||||
variant?: "blogg" | "subtle" | "default" | "transparent";
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<header
|
||||
className={cl("z-20", {
|
||||
"bg-amber-50": variant === "blogg",
|
||||
"bg-surface-default": variant === "default",
|
||||
"bg-surface-subtle": variant === "subtle",
|
||||
"bg-surface-transparent": variant === "transparent",
|
||||
})}
|
||||
>
|
||||
<a className="skiplink" href="#hovedinnhold">
|
||||
Hopp til innhold
|
||||
</a>
|
||||
<header
|
||||
className={cl("h-header z-20", {
|
||||
"bg-[#FEFCE9]": variant === "blogg",
|
||||
"bg-surface-default": variant === "default",
|
||||
"bg-surface-subtle": variant === "subtle",
|
||||
"bg-surface-transparent": variant === "transparent",
|
||||
})}
|
||||
>
|
||||
<div
|
||||
className={cl(
|
||||
"mx-auto flex h-full max-w-screen-2xl items-center pr-4 lg:pr-6"
|
||||
)}
|
||||
>
|
||||
<div className="flex h-11 items-center pl-4 pr-4 sm:pl-4 sm:pr-6">
|
||||
<Link
|
||||
href="/"
|
||||
passHref
|
||||
onClick={(e) =>
|
||||
amplitudeLogNavigation(
|
||||
"header",
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
}
|
||||
className="focus-visible:shadow-focus grid h-full place-items-center rounded px-2 focus:outline-none"
|
||||
>
|
||||
<AkselLogo className="text-deepblue-800" />
|
||||
<span className="sr-only">Aksel</span>
|
||||
</Link>
|
||||
</div>
|
||||
<nav
|
||||
className="ml-auto hidden h-full pr-2 lg:block lg:pr-8"
|
||||
aria-label="Hovedmeny"
|
||||
<Page.Block width="2xl">
|
||||
<div className="h-header flex items-center pr-4 lg:pr-6">
|
||||
<Link
|
||||
href="/"
|
||||
passHref
|
||||
onClick={(e) =>
|
||||
amplitudeLogNavigation(
|
||||
"header",
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
}
|
||||
className="focus-visible:shadow-focus mx-4 grid h-11 place-items-center rounded px-2 focus:outline-none sm:mr-6"
|
||||
>
|
||||
<ul className="hidden h-full items-center gap-2 md:flex">
|
||||
<LinkElement name="God praksis" href="/god-praksis" />
|
||||
<LinkElement name="Grunnleggende" href="/grunnleggende" />
|
||||
<LinkElement name="Ikoner" href="/ikoner" prefetch={false} />
|
||||
<LinkElement name="Komponenter" href="/komponenter" />
|
||||
<LinkElement name="Mønster & Maler" href="/monster-maler" />
|
||||
<LinkElement name="Bloggen" href="/produktbloggen" />
|
||||
</ul>
|
||||
</nav>
|
||||
<div className="z-[1050] ml-auto mr-4 flex justify-center lg:ml-0 lg:mr-0">
|
||||
<GlobalSearch />
|
||||
</div>
|
||||
<AkselLogo className="text-deepblue-800" />
|
||||
<span className="sr-only">Aksel</span>
|
||||
</Link>
|
||||
|
||||
<Hamburger />
|
||||
<Spacer />
|
||||
<Show above="lg" asChild>
|
||||
<Box
|
||||
as="nav"
|
||||
paddingInline={{ xs: "0 2", lg: "0 8" }}
|
||||
aria-label="Hovedmeny"
|
||||
>
|
||||
<HStack as="ul" gap="2" align="center">
|
||||
<HeaderLink name="God praksis" href="/god-praksis" />
|
||||
<HeaderLink name="Grunnleggende" href="/grunnleggende" />
|
||||
<HeaderLink name="Ikoner" href="/ikoner" prefetch={false} />
|
||||
<HeaderLink name="Komponenter" href="/komponenter" />
|
||||
<HeaderLink name="Mønster & Maler" href="/monster-maler" />
|
||||
<HeaderLink name="Bloggen" href="/produktbloggen" />
|
||||
</HStack>
|
||||
</Box>
|
||||
</Show>
|
||||
<HStack align="center" gap="2">
|
||||
<GlobalSearch />
|
||||
<Hamburger />
|
||||
</HStack>
|
||||
</div>
|
||||
</header>
|
||||
</>
|
||||
</Page.Block>
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import { MenuHamburgerIcon } from "@navikt/aksel-icons";
|
||||
import { Button, Modal, Show } from "@navikt/ds-react";
|
||||
import { useState } from "react";
|
||||
import HamburgerLink from "./HamburgerLink";
|
||||
|
||||
export const Hamburger = () => {
|
||||
const [open, setOpen] = useState(false);
|
||||
return (
|
||||
<Show below="lg">
|
||||
<Button
|
||||
variant="tertiary-neutral"
|
||||
onClick={() => setOpen(!open)}
|
||||
aria-expanded={open}
|
||||
icon={
|
||||
<MenuHamburgerIcon
|
||||
fontSize="2rem"
|
||||
className="pointer-events-none"
|
||||
title="Åpne meny"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<Modal
|
||||
open={open}
|
||||
onClose={() => setOpen(false)}
|
||||
header={{ heading: "Meny" }}
|
||||
width="small"
|
||||
closeOnBackdropClick
|
||||
>
|
||||
<Modal.Body>
|
||||
<nav aria-label="hovedmeny">
|
||||
<ul>
|
||||
<HamburgerLink
|
||||
onClick={() => setOpen(false)}
|
||||
name="God praksis"
|
||||
href="/god-praksis"
|
||||
/>
|
||||
<HamburgerLink
|
||||
onClick={() => setOpen(false)}
|
||||
name="Grunnleggende"
|
||||
href="/grunnleggende"
|
||||
/>
|
||||
<HamburgerLink
|
||||
onClick={() => setOpen(false)}
|
||||
name="Ikoner"
|
||||
href="/ikoner"
|
||||
/>
|
||||
<HamburgerLink
|
||||
onClick={() => setOpen(false)}
|
||||
name="Komponenter"
|
||||
href="/komponenter"
|
||||
/>
|
||||
<HamburgerLink
|
||||
onClick={() => setOpen(false)}
|
||||
name="Mønster & Maler"
|
||||
href="/monster-maler"
|
||||
/>
|
||||
<HamburgerLink
|
||||
onClick={() => setOpen(false)}
|
||||
name="Blogg"
|
||||
href="/produktbloggen"
|
||||
/>
|
||||
</ul>
|
||||
</nav>
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import cl from "clsx";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
function HamburgerLink({ name, href, onClick }) {
|
||||
const { asPath } = useRouter();
|
||||
return (
|
||||
<li className="my-2 flex h-11 items-center">
|
||||
<Link
|
||||
href={href}
|
||||
passHref
|
||||
className={cl(
|
||||
"hover:bg-surface-action-subtle-hover focus-visible:shadow-focus relative flex h-full w-full items-center rounded px-2 focus:outline-none",
|
||||
{
|
||||
"before:bg-surface-action-selected pl-4 font-semibold before:absolute before:left-0 before:h-6 before:w-1 before:rounded-full":
|
||||
asPath.startsWith(href),
|
||||
"": !asPath.startsWith(href),
|
||||
}
|
||||
)}
|
||||
onClick={(e) => {
|
||||
amplitudeLogNavigation(
|
||||
"header",
|
||||
e.currentTarget.getAttribute("href")
|
||||
);
|
||||
onClick();
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
export default HamburgerLink;
|
||||
@@ -0,0 +1,32 @@
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import cl from "clsx";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
function HeaderLink({ name, href, prefetch = undefined }) {
|
||||
const { asPath } = useRouter();
|
||||
return (
|
||||
<li>
|
||||
<Link
|
||||
href={href}
|
||||
prefetch={prefetch}
|
||||
className={cl(
|
||||
"text-deepblue-800 focus-visible:shadow-focus relative grid h-11 place-items-center rounded px-2 focus:outline-none",
|
||||
{
|
||||
"before:bg-deepblue-600 font-semibold before:absolute before:bottom-[1px] before:z-10 before:h-1 before:w-[calc(100%_-_16px)] before:rounded-full":
|
||||
asPath.startsWith(href),
|
||||
"hover:before:bg-border-subtle-hover before:absolute before:bottom-[1px] before:z-10 before:h-1 before:w-[calc(100%_-_16px)] before:rounded-full":
|
||||
!asPath.startsWith(href),
|
||||
}
|
||||
)}
|
||||
onClick={(e) =>
|
||||
amplitudeLogNavigation("header", e.currentTarget.getAttribute("href"))
|
||||
}
|
||||
>
|
||||
{name}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
export default HeaderLink;
|
||||
@@ -11,8 +11,8 @@ import { BodyLong, Button, Chips, HStack } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { Sandbox } from "./parts/Sandbox";
|
||||
import { CodeSandbox } from "./parts/CodeSandbox";
|
||||
import { Sandbox } from "./parts/Sandbox";
|
||||
|
||||
const iframePadding = 192;
|
||||
const iframeId = "example-iframe";
|
||||
@@ -98,10 +98,10 @@ const ComponentExamples = ({ node }: CodeExamplesProps) => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-5 max-w-xl">
|
||||
<Chips>
|
||||
{node.dir.filer.map((fil) => {
|
||||
return (
|
||||
{node.dir.filer.length > 1 && (
|
||||
<div className="mb-5 max-w-xl">
|
||||
<Chips>
|
||||
{node.dir.filer.map((fil) => (
|
||||
<Chips.Toggle
|
||||
checkmark={false}
|
||||
key={fil._key}
|
||||
@@ -119,119 +119,117 @@ const ComponentExamples = ({ node }: CodeExamplesProps) => {
|
||||
>
|
||||
{fixName(fil.title)}
|
||||
</Chips.Toggle>
|
||||
);
|
||||
))}
|
||||
</Chips>
|
||||
</div>
|
||||
)}
|
||||
{node.dir.filer.map((fil) => (
|
||||
<div
|
||||
key={fil._key}
|
||||
className={cl({
|
||||
visible: active === fil.navn,
|
||||
hidden: active !== fil.navn,
|
||||
})}
|
||||
</Chips>
|
||||
</div>
|
||||
{node.dir.filer.map((fil) => {
|
||||
return (
|
||||
<div
|
||||
key={fil._key}
|
||||
className={cl({
|
||||
visible: active === fil.navn,
|
||||
hidden: active !== fil.navn,
|
||||
})}
|
||||
>
|
||||
{fil?.description && (
|
||||
<BodyLong className="mb-2">{fil.description}</BodyLong>
|
||||
)}
|
||||
>
|
||||
{fil?.description && (
|
||||
<BodyLong className="mb-2">{fil.description}</BodyLong>
|
||||
)}
|
||||
|
||||
{active === fil.navn && (
|
||||
<>
|
||||
<div
|
||||
{active === fil.navn && (
|
||||
<>
|
||||
<div
|
||||
className={cl(
|
||||
"overflow-hidden rounded-t-lg border border-b-0 border-gray-300 ",
|
||||
{
|
||||
"relative animate-pulse": unloaded,
|
||||
"bg-gray-50": !unloaded,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<iframe
|
||||
src={`/${demoVariant}/${node.dir.title}/${fil.navn.replace(
|
||||
".tsx",
|
||||
""
|
||||
)}`}
|
||||
height={frameState}
|
||||
onLoad={() => handleExampleLoad()}
|
||||
id={iframeId}
|
||||
aria-label={`${node?.dir?.title} ${fil.navn} eksempel`}
|
||||
className={cl(
|
||||
"overflow-hidden rounded-t-lg border border-b-0 border-gray-300 ",
|
||||
"min-w-80 block w-full max-w-full resize-x bg-white shadow-[20px_0_20px_-20px_rgba(0,0,0,0.22)]",
|
||||
{
|
||||
"relative animate-pulse": unloaded,
|
||||
"bg-gray-50": !unloaded,
|
||||
invisible: unloaded,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<iframe
|
||||
src={`/${demoVariant}/${node.dir.title}/${fil.navn.replace(
|
||||
".tsx",
|
||||
""
|
||||
)}`}
|
||||
height={frameState}
|
||||
onLoad={() => handleExampleLoad()}
|
||||
id={iframeId}
|
||||
aria-label={`${node?.dir?.title} ${fil.navn} eksempel`}
|
||||
className={cl(
|
||||
"min-w-80 block w-full max-w-full resize-x bg-white shadow-[20px_0_20px_-20px_rgba(0,0,0,0.22)]",
|
||||
{
|
||||
invisible: unloaded,
|
||||
}
|
||||
)}
|
||||
title="Kode-eksempler"
|
||||
ref={iframeRef}
|
||||
/>
|
||||
{unloaded && (
|
||||
<div className="absolute inset-0 mx-auto flex flex-col items-center justify-center gap-2">
|
||||
<div className="grid w-3/5 gap-2">
|
||||
<div className="bg-surface-neutral-subtle h-6 w-2/3 rounded-xl" />
|
||||
<div className="bg-surface-neutral-subtle h-16 w-full rounded-xl" />
|
||||
</div>
|
||||
title="Kode-eksempler"
|
||||
ref={iframeRef}
|
||||
/>
|
||||
{unloaded && (
|
||||
<div className="absolute inset-0 mx-auto flex flex-col items-center justify-center gap-2">
|
||||
<div className="grid w-3/5 gap-2">
|
||||
<div className="bg-surface-neutral-subtle h-6 w-2/3 rounded-xl" />
|
||||
<div className="bg-surface-neutral-subtle h-16 w-full rounded-xl" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="mb-2 rounded-b-lg border border-gray-300 p-1">
|
||||
<HStack gap="4" justify="space-between">
|
||||
<div className="hidden sm:block">
|
||||
<HStack gap="2">
|
||||
<Button
|
||||
variant="tertiary-neutral"
|
||||
size="small"
|
||||
icon={
|
||||
<MobileSmallIcon title="Sett eksempel til mobilbredde" />
|
||||
}
|
||||
onClick={() =>
|
||||
(iframeRef.current.style.width = "360px")
|
||||
}
|
||||
/>
|
||||
|
||||
<Button
|
||||
variant="tertiary-neutral"
|
||||
size="small"
|
||||
icon={
|
||||
<LaptopIcon title="Sett eksempel til desktopbredde" />
|
||||
}
|
||||
onClick={() => (iframeRef.current.style.width = "")}
|
||||
/>
|
||||
</HStack>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="mb-2 rounded-b-lg border border-gray-300 p-1">
|
||||
<HStack gap="4" justify="space-between">
|
||||
<div className="hidden sm:block">
|
||||
<HStack gap="2">
|
||||
{fil?.sandboxEnabled && (
|
||||
<Sandbox code={fil?.sandboxBase64} />
|
||||
)}
|
||||
<CodeSandbox code={fil.innhold.trim()} />
|
||||
<Button
|
||||
variant="tertiary-neutral"
|
||||
size="small"
|
||||
icon={
|
||||
<ExternalLinkIcon title="Åpne eksempel i nytt vindu" />
|
||||
<MobileSmallIcon title="Sett eksempel til mobilbredde" />
|
||||
}
|
||||
target="_blank"
|
||||
className="si-ignore"
|
||||
as="a"
|
||||
href={`/${demoVariant}/${
|
||||
node.dir.title
|
||||
}/${fil.navn.replace(".tsx", "")}`}
|
||||
onClick={() =>
|
||||
(iframeRef.current.style.width = "360px")
|
||||
}
|
||||
/>
|
||||
|
||||
<Button
|
||||
variant="tertiary-neutral"
|
||||
size="small"
|
||||
icon={
|
||||
<LaptopIcon title="Sett eksempel til desktopbredde" />
|
||||
}
|
||||
onClick={() => (iframeRef.current.style.width = "")}
|
||||
/>
|
||||
</HStack>
|
||||
</HStack>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SnippetLazy
|
||||
node={{
|
||||
code: { code: fil.innhold.trim(), language: "tsx" },
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<HStack gap="2">
|
||||
{fil?.sandboxEnabled && (
|
||||
<Sandbox code={fil?.sandboxBase64} />
|
||||
)}
|
||||
<CodeSandbox code={fil.innhold.trim()} />
|
||||
<Button
|
||||
variant="tertiary-neutral"
|
||||
size="small"
|
||||
icon={
|
||||
<ExternalLinkIcon title="Åpne eksempel i nytt vindu" />
|
||||
}
|
||||
target="_blank"
|
||||
className="si-ignore"
|
||||
as="a"
|
||||
href={`/${demoVariant}/${
|
||||
node.dir.title
|
||||
}/${fil.navn.replace(".tsx", "")}`}
|
||||
/>
|
||||
</HStack>
|
||||
</HStack>
|
||||
</div>
|
||||
|
||||
<SnippetLazy
|
||||
node={{
|
||||
code: { code: fil.innhold.trim(), language: "tsx" },
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -27,7 +27,7 @@ const Element = ({ block }: { block: DoDontT["blokker"][number] }) => {
|
||||
<BodyShort
|
||||
as="span"
|
||||
className={cl(
|
||||
"relative z-[-1] flex items-center gap-1 rounded-t-lg px-4 py-2",
|
||||
"text-text-default relative z-[-1] flex items-center gap-1 rounded-t-lg px-4 py-2",
|
||||
{
|
||||
"bg-surface-success-moderate": block.variant === "do",
|
||||
"bg-surface-danger-moderate": block.variant === "dont",
|
||||
|
||||
@@ -10,8 +10,9 @@ export const FrontpageBlock = ({ blocks }: FrontpageBlockProps) => {
|
||||
if (!blocks || !blocks.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="lg:px-18 px-2">
|
||||
<>
|
||||
{blocks.map((x) => {
|
||||
switch (x._type) {
|
||||
case "nytt_fra_aksel":
|
||||
@@ -20,7 +21,7 @@ export const FrontpageBlock = ({ blocks }: FrontpageBlockProps) => {
|
||||
return null;
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
+14
-2
@@ -1,4 +1,5 @@
|
||||
import ErrorBoundary from "@/error-boundary";
|
||||
import { useFormatedDate } from "@/hooks/useFormatedDate";
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { urlFor } from "@/sanity/interface";
|
||||
import { abbrName, getImage } from "@/utils";
|
||||
@@ -7,7 +8,6 @@ import cl from "clsx";
|
||||
import NextImage from "next/legacy/image";
|
||||
import NextLink from "next/link";
|
||||
import { Tag } from "./Tag";
|
||||
import { useFormatedDate } from "@/hooks/useFormatedDate";
|
||||
|
||||
export type ArticleT = {
|
||||
_key: string;
|
||||
@@ -71,7 +71,13 @@ const Card = ({ article, visible, index }: CardProps) => {
|
||||
{article.status?.bilde ?? article.seo?.image ? (
|
||||
article.status?.bilde ? (
|
||||
<NextImage
|
||||
src={urlFor(article.status?.bilde).auto("format").url()}
|
||||
src={urlFor(article.status.bilde).auto("format").url()}
|
||||
blurDataURL={urlFor(article.status.bilde)
|
||||
.width(24)
|
||||
.height(24)
|
||||
.blur(10)
|
||||
.url()}
|
||||
placeholder="blur"
|
||||
width="200"
|
||||
height="200"
|
||||
alt={article.heading + " thumbnail"}
|
||||
@@ -81,6 +87,12 @@ const Card = ({ article, visible, index }: CardProps) => {
|
||||
<div className="relative h-[200px] w-full">
|
||||
<NextImage
|
||||
src={urlFor(article.seo?.image).auto("format").url()}
|
||||
blurDataURL={urlFor(article.seo?.image)
|
||||
.width(24)
|
||||
.height(24)
|
||||
.blur(10)
|
||||
.url()}
|
||||
placeholder="blur"
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
alt={article.heading + " thumbnail"}
|
||||
|
||||
+13
-1
@@ -1,3 +1,4 @@
|
||||
import { useFormatedDate } from "@/hooks/useFormatedDate";
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { urlFor } from "@/sanity/interface";
|
||||
import { getAuthors, getImage } from "@/utils";
|
||||
@@ -7,7 +8,6 @@ import Image from "next/legacy/image";
|
||||
import NextLink from "next/link";
|
||||
import { ArticleT } from "./Card";
|
||||
import { Tag } from "./Tag";
|
||||
import { useFormatedDate } from "@/hooks/useFormatedDate";
|
||||
|
||||
export const Highlight = ({
|
||||
article,
|
||||
@@ -35,6 +35,12 @@ export const Highlight = ({
|
||||
{useStatusImage ? (
|
||||
<Image
|
||||
src={urlFor(article.status.bilde).quality(100).auto("format").url()}
|
||||
blurDataURL={urlFor(article.status.bilde)
|
||||
.width(24)
|
||||
.height(24)
|
||||
.blur(10)
|
||||
.url()}
|
||||
placeholder="blur"
|
||||
quality={100}
|
||||
layout="fill"
|
||||
aria-hidden
|
||||
@@ -49,6 +55,12 @@ export const Highlight = ({
|
||||
) : article?.seo?.image ? (
|
||||
<Image
|
||||
src={urlFor(article.seo.image).quality(100).auto("format").url()}
|
||||
blurDataURL={urlFor(article.seo.image)
|
||||
.width(24)
|
||||
.height(24)
|
||||
.blur(10)
|
||||
.url()}
|
||||
placeholder="blur"
|
||||
quality={100}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
|
||||
@@ -18,9 +18,9 @@ const RelatertInnhold = ({ node }: RelatertInnholdProps) => {
|
||||
x?.intern ? `/${x.intern_lenke}` : x.ekstern_link;
|
||||
|
||||
return (
|
||||
<div className="ring-border-subtle toc-ignore bg-surface-neutral-subtle my-7 max-w-2xl rounded-lg p-4 ring-1 ring-inset sm:p-6">
|
||||
<div className="ring-border-subtle toc-ignore bg-surface-neutral-subtle my-7 max-w-2xl rounded-lg p-4 ring-1 ring-inset dark:bg-gray-800 sm:p-6">
|
||||
<Heading
|
||||
className="override-text-no-max text-text-subtle flex items-center gap-2"
|
||||
className="override-text-no-max text-text-subtle dark:text-text-on-inverted flex items-center gap-2"
|
||||
size="small"
|
||||
as="p"
|
||||
spacing
|
||||
@@ -40,7 +40,7 @@ const RelatertInnhold = ({ node }: RelatertInnholdProps) => {
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
}
|
||||
className="text-xl font-semibold text-gray-800"
|
||||
className="dark:text-text-on-inverted text-xl font-semibold text-gray-800"
|
||||
>
|
||||
{x.title}
|
||||
</Link>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { SANITY_PROJECT_ID } from "@/sanity/config";
|
||||
import { AkselTheme, getKey } from "@/sb-util";
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { getKey, AkselTheme } from "@/sb-util";
|
||||
import Video from "./Video";
|
||||
|
||||
const meta = {
|
||||
@@ -18,7 +19,7 @@ const args = {
|
||||
caption: "caption-tekst",
|
||||
transkripsjon: "Transkripsjonstekst",
|
||||
webm: {
|
||||
url: "https://cdn.sanity.io/files/hnbe3yhs/production/274a2ceb69b056e1a7048ad1a5a2f8deff53a2f4.webm",
|
||||
url: `https://cdn.sanity.io/files/${SANITY_PROJECT_ID}/production/274a2ceb69b056e1a7048ad1a5a2f8deff53a2f4.webm`,
|
||||
extension: "WEBM",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,31 +1,20 @@
|
||||
import { useCheckAuth } from "@/hooks/useCheckAuth";
|
||||
import { useSanityDocId } from "@/hooks/useSanityDocId";
|
||||
import { PencilIcon } from "@navikt/aksel-icons";
|
||||
import { Tooltip } from "@navikt/ds-react";
|
||||
|
||||
function EditButton() {
|
||||
const idCtx = useSanityDocId();
|
||||
const validUser = useCheckAuth();
|
||||
|
||||
return validUser && idCtx?.id ? (
|
||||
<div className="overflow-hidden">
|
||||
<Tooltip
|
||||
content="Vises bare for innloggede redaktører"
|
||||
placement="left"
|
||||
delay={500}
|
||||
>
|
||||
<a
|
||||
href={`https://aksel.nav.no/admin/prod/intent/edit/id=${idCtx?.id}`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="editbutton bg-deepblue-800 hover:bg-deepblue-700 absolute right-0 top-0 flex -translate-y-[99%] items-center gap-2 overflow-hidden rounded-tl px-2 py-1 text-white transition-transform hover:translate-x-0"
|
||||
aria-hidden
|
||||
tabIndex={-1}
|
||||
>
|
||||
<PencilIcon aria-hidden className="shrink-0 text-xl" /> Rediger side
|
||||
</a>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<a
|
||||
href={`https://aksel.nav.no/admin/prod/intent/edit/id=${idCtx?.id}`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="bg-deepblue-800 hover:bg-deepblue-700 absolute right-0 top-0 flex -translate-y-[99%] items-center gap-2 overflow-hidden rounded-tl px-2 py-1 text-white transition-transform hover:translate-x-0"
|
||||
>
|
||||
<PencilIcon aria-hidden className="shrink-0 text-xl" /> Rediger side
|
||||
</a>
|
||||
) : null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const InlineCode = (
|
||||
props: React.HTMLAttributes<HTMLElement> & { noAmps?: boolean }
|
||||
) => (
|
||||
<code className="text-deepblue-800 font-mono text-sm font-semibold leading-normal before:contents">
|
||||
<code className="text-deepblue-800 dark:text-deepblue-300 font-mono text-sm font-semibold leading-normal before:contents">
|
||||
{!props?.noAmps && (
|
||||
<span aria-hidden className="inline-code-amp">
|
||||
`
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
import { useCheckAuth } from "@/hooks/useCheckAuth";
|
||||
import { BodyShort, Button } from "@navikt/ds-react";
|
||||
import Link from "next/link";
|
||||
|
||||
function PreviewBanner({
|
||||
loading = true,
|
||||
validUser,
|
||||
}: {
|
||||
loading: boolean;
|
||||
validUser: boolean;
|
||||
}) {
|
||||
function PreviewBanner({ loading = true }: { loading: boolean }) {
|
||||
const validUser = useCheckAuth();
|
||||
|
||||
if (!validUser) {
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
import { useCheckAuth } from "@/hooks/useCheckAuth";
|
||||
import { getClient } from "@/sanity/client.server";
|
||||
import { LiveQueryProvider, useLiveQuery } from "next-sanity/preview";
|
||||
import dynamic from "next/dynamic";
|
||||
import { ComponentType, useMemo } from "react";
|
||||
|
||||
const PreviewBanner = dynamic(() => import("@/web/PreviewBanner"), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
function PreviewProvider({ children }: { children: React.ReactNode }) {
|
||||
const client = useMemo(() => {
|
||||
return getClient().withConfig({
|
||||
useCdn: false,
|
||||
ignoreBrowserTokenWarning: true,
|
||||
perspective: "previewDrafts",
|
||||
});
|
||||
}, []);
|
||||
return <LiveQueryProvider client={client}>{children}</LiveQueryProvider>;
|
||||
}
|
||||
|
||||
function LiveQuery({
|
||||
comp: Comp,
|
||||
query,
|
||||
params,
|
||||
props,
|
||||
validUser,
|
||||
}: {
|
||||
comp: ComponentType;
|
||||
query: string;
|
||||
props: any;
|
||||
params?: any;
|
||||
validUser: boolean;
|
||||
}) {
|
||||
const [data, loading] = useLiveQuery(props, query, params);
|
||||
|
||||
return (
|
||||
<>
|
||||
<PreviewBanner loading={loading} validUser={validUser} />
|
||||
<Comp {...props} {...data} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const WithPreview = ({
|
||||
comp,
|
||||
query,
|
||||
params,
|
||||
props,
|
||||
}: {
|
||||
comp;
|
||||
query: string;
|
||||
props: any;
|
||||
params?: any;
|
||||
}) => {
|
||||
const validUser = useCheckAuth();
|
||||
return (
|
||||
<PreviewProvider>
|
||||
<LiveQuery
|
||||
props={props}
|
||||
query={query}
|
||||
params={params}
|
||||
comp={comp}
|
||||
validUser={validUser}
|
||||
/>
|
||||
</PreviewProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default WithPreview;
|
||||
@@ -19,6 +19,12 @@ export const HighlightedBlogg = ({
|
||||
{blogg?.seo?.image ? (
|
||||
<Image
|
||||
src={urlFor(blogg.seo.image).quality(100).auto("format").url()}
|
||||
blurDataURL={urlFor(blogg.seo.image)
|
||||
.width(24)
|
||||
.height(24)
|
||||
.blur(10)
|
||||
.url()}
|
||||
placeholder="blur"
|
||||
quality={100}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
@@ -62,6 +68,12 @@ export const HighlightedBlogg = ({
|
||||
{blogg?.seo?.image ? (
|
||||
<Image
|
||||
src={urlFor(blogg.seo.image).quality(100).auto("format").url()}
|
||||
blurDataURL={urlFor(blogg.seo.image)
|
||||
.width(24)
|
||||
.height(24)
|
||||
.blur(10)
|
||||
.url()}
|
||||
placeholder="blur"
|
||||
quality={100}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
|
||||
@@ -10,18 +10,17 @@ import cl from "clsx";
|
||||
import { ComponentType, useEffect, useState } from "react";
|
||||
import styles from "./examples.module.css";
|
||||
|
||||
type withDsT = {
|
||||
variant?: "full" | "inverted" | "static" | "subtle";
|
||||
showBreakpoints?: boolean;
|
||||
};
|
||||
|
||||
export const withDsExample = (
|
||||
Component: ComponentType,
|
||||
/**
|
||||
* Static: Used for dynamic-height examples like ExpansionCard
|
||||
*/
|
||||
{
|
||||
variant,
|
||||
showBreakpoints,
|
||||
}: {
|
||||
variant?: "full" | "inverted" | "static" | "subtle";
|
||||
showBreakpoints?: boolean;
|
||||
} = {}
|
||||
{ variant, showBreakpoints }: withDsT = {}
|
||||
) => {
|
||||
const DsHOC = (props: any) => {
|
||||
const [width, setWidth] = useState<number>();
|
||||
@@ -57,7 +56,12 @@ export const withDsExample = (
|
||||
breakpoint = "xl";
|
||||
}
|
||||
return (
|
||||
<HStack gap="1" className="absolute left-2 top-1" align="center">
|
||||
<HStack
|
||||
gap="05"
|
||||
className="rounded-br-medium absolute left-0 top-0 p-1"
|
||||
align="center"
|
||||
style={{ background: getBg(variant) }}
|
||||
>
|
||||
<Icon aria-hidden fontSize="1.5rem" /> {`${breakpoint}`}
|
||||
</HStack>
|
||||
);
|
||||
@@ -66,12 +70,12 @@ export const withDsExample = (
|
||||
return (
|
||||
<div
|
||||
className={cl(styles.examples, {
|
||||
"bg-gray-900": variant === "inverted",
|
||||
"bg-bg-subtle": variant === "subtle",
|
||||
[styles.containerStatic]: variant === "static",
|
||||
[styles.container]: variant !== "static",
|
||||
})}
|
||||
style={{ background: getBg(variant) }}
|
||||
>
|
||||
<style global>{`html {scrollbar-gutter: unset;}`}</style>
|
||||
{showBreakpoints && <BreakpointText />}
|
||||
<div
|
||||
id="ds-example"
|
||||
@@ -91,3 +95,15 @@ export const withDsExample = (
|
||||
|
||||
return DsHOC;
|
||||
};
|
||||
|
||||
function getBg(variant: withDsT["variant"]): string {
|
||||
switch (variant) {
|
||||
case "inverted":
|
||||
return "var(--a-surface-inverted)";
|
||||
case "subtle":
|
||||
return "var(--a-bg-subtle)";
|
||||
|
||||
default:
|
||||
return "var(--a-bg-default)";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { getClient } from "@/sanity/client.server";
|
||||
import { LiveQueryProvider } from "next-sanity/preview";
|
||||
import { useMemo } from "react";
|
||||
import LiveQuery from "./parts/LiveQuery";
|
||||
import { PreviewProps } from "./parts/types";
|
||||
|
||||
const WithPreview = ({
|
||||
comp,
|
||||
query,
|
||||
params,
|
||||
props,
|
||||
resolvers,
|
||||
}: PreviewProps) => {
|
||||
const client = useMemo(() => {
|
||||
return getClient().withConfig({
|
||||
useCdn: false,
|
||||
ignoreBrowserTokenWarning: true,
|
||||
perspective: "previewDrafts",
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<LiveQueryProvider client={client}>
|
||||
<LiveQuery
|
||||
props={props}
|
||||
query={query}
|
||||
params={params}
|
||||
comp={comp}
|
||||
resolvers={resolvers}
|
||||
/>
|
||||
</LiveQueryProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default WithPreview;
|
||||
@@ -0,0 +1,29 @@
|
||||
import { useLiveQuery } from "next-sanity/preview";
|
||||
import dynamic from "next/dynamic";
|
||||
import { runResolvers } from "./resolvers";
|
||||
import { PreviewProps } from "./types";
|
||||
|
||||
const PreviewBanner = dynamic(() => import("@/web/PreviewBanner"), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
function LiveQuery({
|
||||
comp: Comp,
|
||||
query,
|
||||
params,
|
||||
props,
|
||||
resolvers,
|
||||
}: PreviewProps) {
|
||||
const [data, loading] = useLiveQuery(props, query, params);
|
||||
|
||||
const _data = loading ? props : runResolvers({ resolvers, data });
|
||||
|
||||
return (
|
||||
<>
|
||||
<PreviewBanner loading={loading} />
|
||||
<Comp {..._data} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default LiveQuery;
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
import { runResolvers } from "../resolvers";
|
||||
|
||||
describe("runResolvers", () => {
|
||||
test("should return original data when resolvers is null", () => {
|
||||
const data = { key: "value" };
|
||||
expect(runResolvers({ resolvers: null, data })).toEqual(data);
|
||||
});
|
||||
|
||||
test("should return original data when resolvers is an empty array", () => {
|
||||
const data = { key: "value" };
|
||||
expect(runResolvers({ resolvers: [], data })).toEqual(data);
|
||||
});
|
||||
|
||||
test("should run resolver callback with data from specified keys", () => {
|
||||
const data = { key1: "value1", key2: "value2" };
|
||||
const resolvers = [
|
||||
{
|
||||
key: "result",
|
||||
dataKeys: ["key1", "key2"],
|
||||
cb: ([value1, value2]) => value1 + value2,
|
||||
},
|
||||
];
|
||||
expect(runResolvers({ resolvers, data })).toEqual({
|
||||
...data,
|
||||
result: "value1value2",
|
||||
});
|
||||
});
|
||||
|
||||
test("should run multiple resolver callbacks", () => {
|
||||
const data = { key1: "value1", key2: "value2" };
|
||||
const resolvers = [
|
||||
{
|
||||
key: "result1",
|
||||
dataKeys: ["key1"],
|
||||
cb: ([value1]) => value1 + "suffix",
|
||||
},
|
||||
{
|
||||
key: "result2",
|
||||
dataKeys: ["key2"],
|
||||
cb: ([value2]) => "prefix" + value2,
|
||||
},
|
||||
];
|
||||
expect(runResolvers({ resolvers, data })).toEqual({
|
||||
...data,
|
||||
result1: "value1suffix",
|
||||
result2: "prefixvalue2",
|
||||
});
|
||||
});
|
||||
|
||||
test("should handle nested keys", () => {
|
||||
const data = { key1: { key2: "value2" } };
|
||||
const resolvers = [
|
||||
{
|
||||
key: "result",
|
||||
dataKeys: ["key1.key2"],
|
||||
cb: ([value2]) => "prefix" + value2,
|
||||
},
|
||||
];
|
||||
expect(runResolvers({ resolvers, data })).toEqual({
|
||||
...data,
|
||||
result: "prefixvalue2",
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
import { ResolverT } from "./types";
|
||||
|
||||
/**
|
||||
* `runResolvers` is responsible for executing a set of resolvers for streamed data from sanity.
|
||||
* This allows running functions and parse data both at initial load `getStaticProps` and when streamed `useLiveQuery`
|
||||
* @param {Array<Resolvers>}
|
||||
* @returns any
|
||||
*/
|
||||
export function runResolvers({
|
||||
resolvers,
|
||||
data,
|
||||
}: {
|
||||
resolvers: ResolverT;
|
||||
data: any;
|
||||
}) {
|
||||
if (!resolvers) {
|
||||
return data;
|
||||
}
|
||||
|
||||
return resolvers.reduce((acc, resolver) => {
|
||||
/* Not allowed to edit accumulators directly as its readonly*/
|
||||
const _acc = { ...acc };
|
||||
const dataFromKeys = resolver.dataKeys.map((key) =>
|
||||
getNestedProperty(_acc, key)
|
||||
);
|
||||
|
||||
_acc[resolver.key] = resolver.cb(dataFromKeys);
|
||||
return _acc;
|
||||
}, data);
|
||||
}
|
||||
|
||||
function getNestedProperty(obj: any, path: string) {
|
||||
return path
|
||||
.split(".")
|
||||
.reduce((acc, key) => (acc ? acc[key] : undefined), obj);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { ComponentType } from "react";
|
||||
|
||||
export type ResolverT = {
|
||||
key: string;
|
||||
dataKeys: string[];
|
||||
cb: (v: any[]) => any;
|
||||
}[];
|
||||
|
||||
export type PreviewProps = {
|
||||
/**
|
||||
* Component to call with live data.
|
||||
* This would normally be the page-component
|
||||
*/
|
||||
comp: ComponentType;
|
||||
/**
|
||||
* Sanity(groq)-query to run live data on
|
||||
*/
|
||||
query: string;
|
||||
/**
|
||||
* sanity(groq)-params
|
||||
*/
|
||||
params?: any;
|
||||
/**
|
||||
* Default/fallback-data if preview fails and for initial load
|
||||
*/
|
||||
props: any;
|
||||
/**
|
||||
* Array of functions we want to run on live data when fetched
|
||||
* @example Supports getting data from nested objects like `page.content`
|
||||
* @example
|
||||
* Here we run `generateSidebar` function on `sidebar` key every time the data is reloaded
|
||||
* resolvers={[
|
||||
* { key: "sidebar", dataKeys: ["page.content", "page.intro"], cb: (v) => generateSidebar(v[0], "komponenter") },
|
||||
* ]}
|
||||
*/
|
||||
resolvers?: ResolverT;
|
||||
};
|
||||
@@ -1,10 +1,10 @@
|
||||
import { MagnifyingGlassIcon } from "@navikt/aksel-icons";
|
||||
import { Button, Modal } from "@navikt/ds-react";
|
||||
import { useContext } from "react";
|
||||
import { SearchContext, SearchNavigationContext } from "../providers";
|
||||
import { Error } from "./Error";
|
||||
import { SearchForm } from "./Form";
|
||||
import { Results } from "./Results";
|
||||
import { SearchContext, SearchNavigationContext } from "../providers";
|
||||
|
||||
export const Search = () => {
|
||||
const { open, setOpen } = useContext(SearchContext);
|
||||
|
||||
@@ -52,7 +52,7 @@ function UlList({
|
||||
className="whitespace-break-spaces"
|
||||
weight={isActive(node.id) ? "semibold" : "regular"}
|
||||
>
|
||||
{removeEmojies(node.title)}
|
||||
{removeEmojies(node.title).trim()}
|
||||
</BodyShort>
|
||||
</a>
|
||||
{!nested && node.children.length > 0 && (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { getDirectories } from "../scripts/update-examples/parts/get-directories";
|
||||
import { parseCodeFiles } from "../scripts/update-examples/parts/parse-code-files";
|
||||
|
||||
@@ -26,7 +26,7 @@ test.describe("sandbox examples (all)", () => {
|
||||
}
|
||||
});
|
||||
|
||||
test.describe("templates", () => {
|
||||
/* test.describe("templates", () => {
|
||||
const subdirs = getDirectories("templates");
|
||||
|
||||
for (const subdir of subdirs) {
|
||||
@@ -47,5 +47,5 @@ test.describe("sandbox examples (all)", () => {
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}); */
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import urls from "./test-urls.json";
|
||||
import { expect, test } from "@playwright/test";
|
||||
import { getDirectories } from "../scripts/update-examples/parts/get-directories";
|
||||
import { parseCodeFiles } from "../scripts/update-examples/parts/parse-code-files";
|
||||
import urls from "./test-urls.json";
|
||||
|
||||
test.describe("Smoketest all pages", () => {
|
||||
for (const url of urls) {
|
||||
@@ -28,9 +28,8 @@ test.describe("Smoketest all pages", () => {
|
||||
|
||||
test.describe("sandbox examples (just a few)", () => {
|
||||
const examples = getDirectories("eksempler");
|
||||
const templates = getDirectories("templates");
|
||||
|
||||
const folders = [...examples, ...templates];
|
||||
const folders = [...examples];
|
||||
|
||||
const randomFolders = [folders[0], folders[20], folders[50]];
|
||||
|
||||
|
||||
@@ -19,6 +19,16 @@ export async function middleware(req: NextRequest) {
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
||||
const url = req.nextUrl.clone();
|
||||
if (
|
||||
url.pathname.startsWith("/sandbox") &&
|
||||
!url.pathname.includes("index.html") &&
|
||||
!url.pathname.match(/(\..*)$/)
|
||||
) {
|
||||
url.pathname = url.pathname + "/index.html";
|
||||
return NextResponse.redirect(url);
|
||||
}
|
||||
|
||||
try {
|
||||
const redirect = await sanityClient.fetch(
|
||||
`
|
||||
|
||||
@@ -29,21 +29,21 @@
|
||||
"playwright": "playwright test",
|
||||
"test:watch": "jest --watch --config ./config/jest.config.js",
|
||||
"backup": "ts-node scripts/backup.js",
|
||||
"watch:tw": "yarn tailwindcss -i ./styles/index.css -o ./dist/tw.css --watch"
|
||||
"watch:tw": "yarn tailwindcss -i ./components/styles/index.css -o ./dist/tw.css --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@amplitude/analytics-browser": "^2.2.3",
|
||||
"@portabletext/react": "^3.0.11",
|
||||
"@sanity/client": "^6.6.0",
|
||||
"@sanity/client": "^6.8.6",
|
||||
"@sanity/code-input": "4.1.1",
|
||||
"@sanity/color-input": "^3.1.0",
|
||||
"@sanity/image-url": "1.0.2",
|
||||
"@sanity/table": "1.0.1",
|
||||
"@sanity/vision": "3.18.0",
|
||||
"@sanity/vision": "3.20.0",
|
||||
"boring-avatars": "1.10.1",
|
||||
"clsx": "^1.2.1",
|
||||
"codesandbox": "^2.2.3",
|
||||
"date-fns": "2.29.3",
|
||||
"date-fns": "^2.30.0",
|
||||
"fuse.js": "^6.6.2",
|
||||
"jscodeshift": "^0.15.1",
|
||||
"lodash": "^4.17.21",
|
||||
@@ -57,10 +57,10 @@
|
||||
"react-dom": "^18.0.0",
|
||||
"react-hotjar": "^6.1.0",
|
||||
"react-responsive-masonry": "^2.1.7",
|
||||
"sanity": "3.18.0",
|
||||
"sanity-plugin-asset-source-unsplash": "^1.1.1",
|
||||
"sanity-plugin-media": "^2.2.2",
|
||||
"sharp": "0.32.5",
|
||||
"sanity": "3.20.0",
|
||||
"sanity-plugin-asset-source-unsplash": "^1.1.2",
|
||||
"sanity-plugin-media": "^2.2.4",
|
||||
"sharp": "0.32.6",
|
||||
"styled-components": "^6.0.0",
|
||||
"swr": "^1.1.2",
|
||||
"tailwindcss": "^3.3.3",
|
||||
@@ -72,8 +72,8 @@
|
||||
"@next/bundle-analyzer": "13.2.1",
|
||||
"@next/eslint-plugin-next": "13.2.1",
|
||||
"@playwright/test": "1.35.1",
|
||||
"@sanity/block-tools": "^3.18.0",
|
||||
"@sanity/schema": "^3.18.0",
|
||||
"@sanity/block-tools": "^3.20.0",
|
||||
"@sanity/schema": "^3.20.0",
|
||||
"@testing-library/jest-dom": "^5.16.0",
|
||||
"@testing-library/react": "^13.3.0",
|
||||
"@types/jest": "^29.0.0",
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
import Footer from "@/layout/footer/Footer";
|
||||
import Header from "@/layout/header/Header";
|
||||
import { AmplitudeEvents, amplitude } from "@/logging";
|
||||
import { AkselCubeStatic } from "@/web/aksel-cube/AkselCube";
|
||||
import { BodyLong, Heading } from "@navikt/ds-react";
|
||||
import {
|
||||
BodyShort,
|
||||
Box,
|
||||
Heading,
|
||||
Link,
|
||||
List,
|
||||
Page,
|
||||
VStack,
|
||||
} from "@navikt/ds-react";
|
||||
import { useEffect } from "react";
|
||||
|
||||
function Page() {
|
||||
function ErrorPage({ statusCode }) {
|
||||
useEffect(() => {
|
||||
amplitude.track(AmplitudeEvents.error, {
|
||||
side: window.location.pathname,
|
||||
@@ -11,21 +20,66 @@ function Page() {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
id="vk-notFoundId"
|
||||
className="relative flex h-screen w-screen items-center justify-center gap-8 overflow-hidden"
|
||||
>
|
||||
<AkselCubeStatic className="text-deepblue-300 opacity-10" />
|
||||
<div>
|
||||
<Heading spacing level="1" size="large">
|
||||
500 - Internal Server Error
|
||||
</Heading>
|
||||
<BodyLong className="mb-2">
|
||||
Det oppstod en feil ved lasting av side. Prøv å laste side på nytt.
|
||||
</BodyLong>
|
||||
</div>
|
||||
</div>
|
||||
<Page data-aksel-template="500-v1" footer={<Footer />} id="vk-notFoundId">
|
||||
<Header />
|
||||
<Page.Block as="main" width="xl" gutters>
|
||||
<Box paddingBlock="20 8">
|
||||
<VStack gap="16">
|
||||
<VStack gap="12" align="start">
|
||||
<div>
|
||||
{statusCode && (
|
||||
<BodyShort textColor="subtle" size="small">
|
||||
Statuskode {statusCode}
|
||||
</BodyShort>
|
||||
)}
|
||||
<Heading level="1" size="large" spacing>
|
||||
Beklager, noe gikk galt.
|
||||
</Heading>
|
||||
<BodyShort spacing>
|
||||
En teknisk feil på våre servere gjør at siden er
|
||||
utilgjengelig. Dette skyldes ikke noe du gjorde.
|
||||
</BodyShort>
|
||||
<BodyShort>Du kan prøve å</BodyShort>
|
||||
<List>
|
||||
<List.Item>
|
||||
vente noen minutter og laste siden på nytt
|
||||
</List.Item>
|
||||
<List.Item>gå tilbake til forrige side</List.Item>
|
||||
</List>
|
||||
<BodyShort>
|
||||
Hvis problemet vedvarer, kan du{" "}
|
||||
<Link
|
||||
href="https://github.com/navikt/aksel/issues/new?assignees=&labels=bug+%F0%9F%90%9B&projects=&template=bug-report.md&title=[Aksel.nav.no%20-%20500]"
|
||||
target="_blank"
|
||||
>
|
||||
kontakte oss (åpnes i ny fane)
|
||||
</Link>
|
||||
.
|
||||
</BodyShort>
|
||||
</div>
|
||||
</VStack>
|
||||
<div>
|
||||
<Heading level="1" size="large" spacing>
|
||||
Something went wrong
|
||||
</Heading>
|
||||
<BodyShort spacing>
|
||||
This was caused by a technical fault on our servers. Please
|
||||
refresh this page or try again in a few minutes.{" "}
|
||||
</BodyShort>
|
||||
<BodyShort>
|
||||
<Link
|
||||
target="_blank"
|
||||
href="https://github.com/navikt/aksel/issues/new?assignees=&labels=bug+%F0%9F%90%9B&projects=&template=bug-report.md&title=[Aksel.nav.no%20-%20500]"
|
||||
>
|
||||
Contact us (opens in new tab)
|
||||
</Link>{" "}
|
||||
if the problem persists.
|
||||
</BodyShort>
|
||||
</div>
|
||||
</VStack>
|
||||
</Box>
|
||||
</Page.Block>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
export default ErrorPage;
|
||||
@@ -1,24 +1,85 @@
|
||||
import { AkselCubeStatic } from "@/web/aksel-cube/AkselCube";
|
||||
import { BodyLong, Heading } from "@navikt/ds-react";
|
||||
import React from "react";
|
||||
import Footer from "@/layout/footer/Footer";
|
||||
import Header from "@/layout/header/Header";
|
||||
import { AmplitudeEvents, amplitude } from "@/logging";
|
||||
import {
|
||||
BodyShort,
|
||||
Box,
|
||||
Heading,
|
||||
Link,
|
||||
List,
|
||||
Page,
|
||||
VStack,
|
||||
} from "@navikt/ds-react";
|
||||
import { useEffect } from "react";
|
||||
|
||||
function ErrorPage({ statusCode }) {
|
||||
useEffect(() => {
|
||||
amplitude.track(AmplitudeEvents.error, {
|
||||
side: window.location.pathname,
|
||||
});
|
||||
}, []);
|
||||
|
||||
const MyError = ({ statusCode }) => {
|
||||
return (
|
||||
<div
|
||||
id="vk-notFoundId"
|
||||
className="relative flex h-screen w-screen items-center justify-center gap-8 overflow-hidden"
|
||||
>
|
||||
<AkselCubeStatic className="text-deepblue-300 opacity-10" />
|
||||
<div>
|
||||
<Heading spacing level="1" size="large">
|
||||
{statusCode} - Det oppstod en feil!
|
||||
</Heading>
|
||||
<BodyLong className="mb-2">
|
||||
Det oppstod en feil ved lasting av side. Prøv å laste side på nytt.
|
||||
</BodyLong>
|
||||
</div>
|
||||
</div>
|
||||
<Page data-aksel-template="500-v1" footer={<Footer />} id="vk-notFoundId">
|
||||
<Header />
|
||||
<Page.Block as="main" width="xl" gutters>
|
||||
<Box paddingBlock="20 8">
|
||||
<VStack gap="16">
|
||||
<VStack gap="12" align="start">
|
||||
<div>
|
||||
{statusCode && (
|
||||
<BodyShort textColor="subtle" size="small">
|
||||
Statuskode {statusCode}
|
||||
</BodyShort>
|
||||
)}
|
||||
<Heading level="1" size="large" spacing>
|
||||
Beklager, noe gikk galt.
|
||||
</Heading>
|
||||
<BodyShort spacing>
|
||||
En teknisk feil på våre servere gjør at siden er
|
||||
utilgjengelig. Dette skyldes ikke noe du gjorde.
|
||||
</BodyShort>
|
||||
<BodyShort>Du kan prøve å</BodyShort>
|
||||
<List>
|
||||
<List.Item>
|
||||
vente noen minutter og laste siden på nytt
|
||||
</List.Item>
|
||||
<List.Item>gå tilbake til forrige side</List.Item>
|
||||
</List>
|
||||
<BodyShort>
|
||||
Hvis problemet vedvarer, kan du{" "}
|
||||
<Link
|
||||
href="https://github.com/navikt/aksel/issues/new?assignees=&labels=bug+%F0%9F%90%9B&projects=&template=bug-report.md&title=[Aksel.nav.no%20-%20500]"
|
||||
target="_blank"
|
||||
>
|
||||
kontakte oss (åpnes i ny fane)
|
||||
</Link>
|
||||
.
|
||||
</BodyShort>
|
||||
</div>
|
||||
</VStack>
|
||||
<div>
|
||||
<Heading level="1" size="large" spacing>
|
||||
Something went wrong
|
||||
</Heading>
|
||||
<BodyShort spacing>
|
||||
This was caused by a technical fault on our servers. Please
|
||||
refresh this page or try again in a few minutes.{" "}
|
||||
</BodyShort>
|
||||
<BodyShort>
|
||||
<Link
|
||||
target="_blank"
|
||||
href="https://github.com/navikt/aksel/issues/new?assignees=&labels=bug+%F0%9F%90%9B&projects=&template=bug-report.md&title=[Aksel.nav.no%20-%20500]"
|
||||
>
|
||||
Contact us (opens in new tab)
|
||||
</Link>{" "}
|
||||
if the problem persists.
|
||||
</BodyShort>
|
||||
</div>
|
||||
</VStack>
|
||||
</Box>
|
||||
</Page.Block>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
export default MyError;
|
||||
}
|
||||
export default ErrorPage;
|
||||
@@ -1,3 +1,4 @@
|
||||
import cl from "clsx";
|
||||
import { NextStudio } from "next-sanity/studio";
|
||||
import { useEffect, useState } from "react";
|
||||
import { workspaceConfig } from "../../sanity/sanity.config";
|
||||
@@ -20,7 +21,9 @@ const StudioPage = () => {
|
||||
return (
|
||||
<div
|
||||
data-theme={scheme}
|
||||
className="aksel-admin h-full min-h-screen"
|
||||
className={cl("aksel-admin h-full min-h-screen", {
|
||||
dark: scheme === "dark",
|
||||
})}
|
||||
id="sanity-wrapper"
|
||||
>
|
||||
<NextStudio
|
||||
|
||||
@@ -10,7 +10,7 @@ Eksempler må ligge under `eksempler/[gruppe]/[eksempel].tsx`
|
||||
|
||||
### Kode
|
||||
|
||||
Alle linjer som inneholder `withDsExample` + alt under `export default withDsExample(Example);` blir automatisk fjernet fra kode-snippet.
|
||||
Alle linjer som inneholder `examples/withDsExample` + alt under `// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE` blir automatisk fjernet fra kode-snippet.
|
||||
|
||||
Demo-komponent må ha navn `Example` for at CodeSandbox-knapp skal fungere riktig.
|
||||
|
||||
@@ -28,10 +28,11 @@ const Example = () => {
|
||||
return <Button>Primary</Button>;
|
||||
};
|
||||
|
||||
export default withDsExample(Example); <- Alt under denne linjen fjernes fra vist kode
|
||||
// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
|
||||
export default withDsExample(Example);
|
||||
|
||||
export const args = {
|
||||
index: 0,
|
||||
desc: "Primærknapp brukes til xyz"
|
||||
desc: "Primærknapp brukes til xyz",
|
||||
};
|
||||
```
|
||||
@@ -33,6 +33,7 @@ const Example = () => {
|
||||
);
|
||||
};
|
||||
|
||||
// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
|
||||
export default withDsExample(Example, { variant: "static" });
|
||||
|
||||
/* Storybook story */
|
||||
|
||||
@@ -32,6 +32,7 @@ const Example = () => {
|
||||
);
|
||||
};
|
||||
|
||||
// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
|
||||
export default withDsExample(Example, { variant: "static" });
|
||||
|
||||
/* Storybook story */
|
||||
|
||||
@@ -32,6 +32,7 @@ const Example = () => {
|
||||
);
|
||||
};
|
||||
|
||||
// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
|
||||
export default withDsExample(Example, { variant: "static" });
|
||||
|
||||
/* Storybook story */
|
||||
|
||||
@@ -51,6 +51,7 @@ const Example = () => {
|
||||
);
|
||||
};
|
||||
|
||||
// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
|
||||
export default withDsExample(Example, { variant: "static" });
|
||||
|
||||
/* Storybook story */
|
||||
|
||||
@@ -32,6 +32,7 @@ const Example = () => {
|
||||
);
|
||||
};
|
||||
|
||||
// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
|
||||
export default withDsExample(Example, { variant: "static" });
|
||||
|
||||
/* Storybook story */
|
||||
|
||||
@@ -18,6 +18,7 @@ const Example = () => {
|
||||
);
|
||||
};
|
||||
|
||||
// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
|
||||
export default withDsExample(Example);
|
||||
|
||||
/* Storybook story */
|
||||
|
||||
@@ -7,6 +7,7 @@ const Example = () => {
|
||||
);
|
||||
};
|
||||
|
||||
// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
|
||||
export default withDsExample(Example);
|
||||
|
||||
/* Storybook story */
|
||||
@@ -15,5 +16,6 @@ export const Demo = {
|
||||
};
|
||||
|
||||
export const args = {
|
||||
index: 0,
|
||||
index: 4,
|
||||
desc: "Brukes til å informere brukere om at noe kritisk har skjedd og vil kreve umiddelbar oppmerksomhet.",
|
||||
};
|
||||
@@ -22,6 +22,7 @@ const Example = () => {
|
||||
);
|
||||
};
|
||||
|
||||
// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
|
||||
export default withDsExample(Example);
|
||||
|
||||
/* Storybook story */
|
||||
@@ -30,5 +31,5 @@ export const Demo = {
|
||||
};
|
||||
|
||||
export const args = {
|
||||
index: 2,
|
||||
index: 8,
|
||||
};
|
||||
@@ -11,6 +11,7 @@ const Example = () => {
|
||||
);
|
||||
};
|
||||
|
||||
// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
|
||||
export default withDsExample(Example);
|
||||
|
||||
/* Storybook story */
|
||||
@@ -19,5 +20,6 @@ export const Demo = {
|
||||
};
|
||||
|
||||
export const args = {
|
||||
index: 0,
|
||||
index: 2,
|
||||
desc: "Skal formidle ren informasjon",
|
||||
};
|
||||
@@ -22,6 +22,7 @@ const Example = () => {
|
||||
);
|
||||
};
|
||||
|
||||
// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
|
||||
export default withDsExample(Example);
|
||||
|
||||
/* Storybook story */
|
||||
@@ -30,5 +31,6 @@ export const Demo = {
|
||||
};
|
||||
|
||||
export const args = {
|
||||
index: 3,
|
||||
index: 9,
|
||||
desc: "Bruk inline om varselet er en del av annet innhold eller når panelet og bakgrunnsfarge blir støy for brukeren.",
|
||||
};
|
||||
@@ -24,6 +24,7 @@ const Example = () => {
|
||||
);
|
||||
};
|
||||
|
||||
// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
|
||||
export default withDsExample(Example);
|
||||
|
||||
/* Storybook story */
|
||||
@@ -32,5 +33,5 @@ export const Demo = {
|
||||
};
|
||||
|
||||
export const args = {
|
||||
index: 0,
|
||||
index: 10,
|
||||
};
|
||||
@@ -14,6 +14,7 @@ const Example = () => {
|
||||
);
|
||||
};
|
||||
|
||||
// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
|
||||
export default withDsExample(Example);
|
||||
|
||||
/* Storybook story */
|
||||
@@ -22,5 +23,6 @@ export const Demo = {
|
||||
};
|
||||
|
||||
export const args = {
|
||||
index: 4,
|
||||
index: 7,
|
||||
desc: "Husk riktig h-tag ved bruk av heading i Alert",
|
||||
};
|
||||
@@ -41,6 +41,7 @@ const AlertWithCloseButton = ({
|
||||
);
|
||||
};
|
||||
|
||||
// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
|
||||
export default withDsExample(Example);
|
||||
|
||||
/* Storybook story */
|
||||
@@ -49,5 +50,5 @@ export const Demo = {
|
||||
};
|
||||
|
||||
export const args = {
|
||||
index: 1,
|
||||
index: 6,
|
||||
};
|
||||
@@ -1,27 +1,20 @@
|
||||
import { withDsExample } from "@/web/examples/withDsExample";
|
||||
import { Alert } from "@navikt/ds-react";
|
||||
import { Alert, VStack } from "@navikt/ds-react";
|
||||
|
||||
const Example = () => {
|
||||
return (
|
||||
<div className="grid gap-4">
|
||||
<Alert size="small" variant="info">
|
||||
Hvis du er mellom 62 og 67 år når du søker, må du som hovedregel ha hatt
|
||||
en pensjonsgivende inntekt som tilsvarer x G, året før du fikk nedsatt
|
||||
arbeidsevnen.
|
||||
</Alert>
|
||||
<VStack gap="4" align="center">
|
||||
<Alert size="small" variant="success">
|
||||
Søknad er sendt inn!
|
||||
</Alert>
|
||||
<Alert size="small" variant="warning">
|
||||
Du må være registrert hos NAV for å bruke aktivitetsplanen.
|
||||
<Alert size="small" variant="success" inline>
|
||||
Søknad er sendt inn!
|
||||
</Alert>
|
||||
<Alert size="small" variant="error">
|
||||
Noe gikk galt! Prøv igjen om noen minutter.
|
||||
</Alert>
|
||||
</div>
|
||||
</VStack>
|
||||
);
|
||||
};
|
||||
|
||||
// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
|
||||
export default withDsExample(Example);
|
||||
|
||||
/* Storybook story */
|
||||
@@ -30,5 +23,5 @@ export const Demo = {
|
||||
};
|
||||
|
||||
export const args = {
|
||||
index: 1,
|
||||
index: 5,
|
||||
};
|
||||
@@ -5,6 +5,7 @@ const Example = () => {
|
||||
return <Alert variant="success">Søknad er sendt inn!</Alert>;
|
||||
};
|
||||
|
||||
// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
|
||||
export default withDsExample(Example);
|
||||
|
||||
/* Storybook story */
|
||||
@@ -13,5 +14,6 @@ export const Demo = {
|
||||
};
|
||||
|
||||
export const args = {
|
||||
index: 0,
|
||||
index: 1,
|
||||
desc: "Bekrefter at en oppgave er fullført som forventet.",
|
||||
};
|
||||
@@ -9,6 +9,7 @@ const Example = () => {
|
||||
);
|
||||
};
|
||||
|
||||
// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
|
||||
export default withDsExample(Example);
|
||||
|
||||
/* Storybook story */
|
||||
@@ -17,5 +18,6 @@ export const Demo = {
|
||||
};
|
||||
|
||||
export const args = {
|
||||
index: 0,
|
||||
index: 3,
|
||||
desc: "Bruk denne når du vil at brukeren skal foreta en bestemt handling eller for å advare dem om noe viktig.",
|
||||
};
|
||||
@@ -33,6 +33,7 @@ function Divider() {
|
||||
return <hr className="border-border-subtle" />;
|
||||
}
|
||||
|
||||
// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
|
||||
export default withDsExample(Example, { variant: "full" });
|
||||
|
||||
/* Storybook story */
|
||||
|
||||
@@ -28,6 +28,7 @@ function Divider() {
|
||||
return <hr className="border-border-subtle" />;
|
||||
}
|
||||
|
||||
// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
|
||||
export default withDsExample(Example, { variant: "full" });
|
||||
|
||||
/* Storybook story */
|
||||
|
||||
@@ -34,6 +34,7 @@ function Divider() {
|
||||
return <hr className="border-border-subtle" />;
|
||||
}
|
||||
|
||||
// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
|
||||
export default withDsExample(Example, { variant: "full" });
|
||||
|
||||
/* Storybook story */
|
||||
|
||||
@@ -30,6 +30,7 @@ function Divider() {
|
||||
return <hr className="border-border-subtle" />;
|
||||
}
|
||||
|
||||
// EXAMPLES DO NOT INCLUDE CONTENT BELOW THIS LINE
|
||||
export default withDsExample(Example, { variant: "full" });
|
||||
|
||||
/* Storybook story */
|
||||
|
||||
Loaded 100 of 497 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user