mirror of
https://github.com/navikt/aksel.git
synced 2026-10-13 09:12:03 +00:00
Compare commits
32
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe15b4d275 | ||
|
|
28e095d5a2 | ||
|
|
43377841ba | ||
|
|
2976ee9626 | ||
|
|
23c135b437 | ||
|
|
7f0498f250 | ||
|
|
5075c8d0a6 | ||
|
|
792eeaba42 | ||
|
|
0c7fc04935 | ||
|
|
0bb339e54a | ||
|
|
f5eb3adaea | ||
|
|
77cf71f814 | ||
|
|
f8c12b0757 | ||
|
|
be8265e13e | ||
|
|
0c7d6fb461 | ||
|
|
b97ac03c5a | ||
|
|
0ddb589138 | ||
|
|
1440c99b96 | ||
|
|
f8cf39c906 | ||
|
|
158c032436 | ||
|
|
6d6e6443dd | ||
|
|
e12ea8694e | ||
|
|
2d4cb67643 | ||
|
|
f5533766c8 | ||
|
|
3d1b0ac204 | ||
|
|
a1678d3b19 | ||
|
|
7007d3c58e | ||
|
|
8524346044 | ||
|
|
d5d8898659 | ||
|
|
1d635e1dbd | ||
|
|
6b3932b172 | ||
|
|
4d6ae1ae42 |
No files matched your search
@@ -1,5 +1,13 @@
|
||||
# @navikt/aksel-icons
|
||||
|
||||
## 5.8.0
|
||||
|
||||
## 5.7.6
|
||||
|
||||
## 5.7.5
|
||||
|
||||
## 5.7.4
|
||||
|
||||
## 5.7.3
|
||||
|
||||
## 5.7.2
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/aksel-icons",
|
||||
"version": "5.7.3",
|
||||
"version": "5.8.0",
|
||||
"author": "Aksel | NAV",
|
||||
"homepage": "https://aksel.nav.no/ikoner",
|
||||
"repository": {
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @navikt/aksel-stylelint
|
||||
|
||||
## 5.8.0
|
||||
|
||||
## 5.7.6
|
||||
|
||||
## 5.7.5
|
||||
|
||||
## 5.7.4
|
||||
|
||||
## 5.7.3
|
||||
|
||||
## 5.7.2
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/aksel-stylelint",
|
||||
"version": "5.7.3",
|
||||
"version": "5.8.0",
|
||||
"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.7.3",
|
||||
"@navikt/ds-tokens": "^5.7.3",
|
||||
"@navikt/ds-css": "^5.8.0",
|
||||
"@navikt/ds-tokens": "^5.8.0",
|
||||
"@types/jest": "^29.0.0",
|
||||
"concurrently": "7.2.1",
|
||||
"copyfiles": "2.4.1",
|
||||
|
||||
@@ -1,5 +1,33 @@
|
||||
# @navikt/aksel
|
||||
|
||||
## 5.8.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`0c7fc0493`](https://github.com/navikt/aksel/commit/0c7fc04935b96946b8ed1178c700077b6a1fcefd)]:
|
||||
- @navikt/ds-css@5.8.0
|
||||
|
||||
## 5.7.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`6d6e6443d`](https://github.com/navikt/aksel/commit/6d6e6443dd00464183b03fad6f822e5f3efab100)]:
|
||||
- @navikt/ds-css@5.7.6
|
||||
|
||||
## 5.7.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`3d1b0ac20`](https://github.com/navikt/aksel/commit/3d1b0ac2041bbc289536fa5a0dc65b2170dfc6fa)]:
|
||||
- @navikt/ds-css@5.7.5
|
||||
|
||||
## 5.7.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-css@5.7.4
|
||||
|
||||
## 5.7.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/aksel",
|
||||
"version": "5.7.3",
|
||||
"version": "5.8.0",
|
||||
"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.7.3",
|
||||
"@navikt/ds-css": "5.8.0",
|
||||
"axios": "1.3.6",
|
||||
"chalk": "4.1.0",
|
||||
"clipboardy": "^2.3.0",
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# @navikt/ds-css
|
||||
|
||||
## 5.8.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- :bug: Modal: Bedre støtte for Tooltip i Modal ([#2429](https://github.com/navikt/aksel/pull/2429))
|
||||
|
||||
## 5.7.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- :lipstick: Chips.Toggle: Ikon i uvalgt tilstand ([#2395](https://github.com/navikt/aksel/pull/2395))
|
||||
|
||||
## 5.7.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Checkbox, Radio: Transparent-border fungerer nå bedre på mørkere bakgrunner ([#2388](https://github.com/navikt/aksel/pull/2388))
|
||||
|
||||
## 5.7.4
|
||||
|
||||
## 5.7.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--a-spacing-1);
|
||||
gap: var(--a-spacing-05);
|
||||
margin: 0;
|
||||
padding: 0 var(--a-spacing-3);
|
||||
text-decoration: none;
|
||||
@@ -97,6 +97,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
.navds-chips--medium .navds-chips__toggle--with-checkmark {
|
||||
padding-left: var(--a-spacing-1-alt);
|
||||
}
|
||||
|
||||
.navds-chips--small .navds-chips__toggle--with-checkmark {
|
||||
padding-left: var(--a-spacing-1);
|
||||
}
|
||||
|
||||
.navds-chips--small .navds-chips__toggle-icon {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
.navds-chips__removable {
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
@@ -31,11 +31,13 @@
|
||||
.navds-radio__label::before {
|
||||
content: "";
|
||||
background-color: var(--ac-radio-checkbox-bg, var(--a-surface-default));
|
||||
box-shadow: inset 0 0 0 2px var(--ac-radio-checkbox-border, var(--a-border-default));
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
border-radius: var(--a-border-radius-medium);
|
||||
border-radius: var(--a-border-radius-small);
|
||||
flex-shrink: 0;
|
||||
box-shadow: 0 0 0 2px var(--ac-radio-checkbox-border, var(--a-border-default));
|
||||
width: calc(1.5rem - 0.25rem);
|
||||
height: calc(1.5rem - 0.25rem);
|
||||
margin-block: 2px;
|
||||
margin-inline: 2px;
|
||||
}
|
||||
|
||||
.navds-radio__label::before {
|
||||
@@ -64,36 +66,37 @@
|
||||
|
||||
.navds-checkbox--small > .navds-checkbox__label::before,
|
||||
.navds-radio--small > .navds-radio__label::before {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
width: calc(1.25rem - 0.25rem);
|
||||
height: calc(1.25rem - 0.25rem);
|
||||
}
|
||||
|
||||
.navds-checkbox__input:focus-visible + .navds-checkbox__label::before,
|
||||
.navds-radio__input:focus-visible + .navds-radio__label::before {
|
||||
box-shadow: inset 0 0 0 2px var(--ac-radio-checkbox-border, var(--a-border-default)), var(--a-shadow-focus);
|
||||
box-shadow: 0 0 0 2px var(--ac-radio-checkbox-border, var(--a-border-default)),
|
||||
0 0 0 2px var(--ac-radio-checkbox-bg, var(--a-surface-default)), 0 0 0 4px var(--a-border-focus);
|
||||
}
|
||||
|
||||
@supports not selector(:focus-visible) {
|
||||
.navds-checkbox__input:focus + .navds-checkbox__label::before,
|
||||
.navds-radio__input:focus + .navds-radio__label::before {
|
||||
box-shadow: inset 0 0 0 2px var(--ac-radio-checkbox-border, var(--a-border-default)), var(--a-shadow-focus);
|
||||
box-shadow: 0 0 0 2px var(--ac-radio-checkbox-border, var(--a-border-default)), 0 0 0 4px var(--a-border-focus);
|
||||
}
|
||||
}
|
||||
|
||||
.navds-checkbox__input:hover:focus-visible + .navds-checkbox__label::before,
|
||||
.navds-radio__input:hover:focus-visible + .navds-radio__label::before {
|
||||
box-shadow: inset 0 0 0 2px var(--ac-radio-checkbox-action, var(--a-surface-action)), var(--a-shadow-focus);
|
||||
box-shadow: 0 0 0 2px var(--ac-radio-checkbox-action, var(--a-surface-action)), 0 0 0 4px var(--a-border-focus);
|
||||
}
|
||||
|
||||
@supports not selector(:focus-visible) {
|
||||
.navds-checkbox__input:hover:focus + .navds-checkbox__label::before,
|
||||
.navds-radio__input:hover:focus + .navds-radio__label::before {
|
||||
box-shadow: inset 0 0 0 2px var(--ac-radio-checkbox-action, var(--a-surface-action)), var(--a-shadow-focus);
|
||||
box-shadow: 0 0 0 2px var(--ac-radio-checkbox-action, var(--a-surface-action)), 0 0 0 4px var(--a-border-focus);
|
||||
}
|
||||
}
|
||||
|
||||
.navds-checkbox__input:indeterminate + .navds-checkbox__label::before {
|
||||
box-shadow: none;
|
||||
box-shadow: 0 0 0 2px var(--ac-radio-checkbox-action, var(--a-surface-action));
|
||||
background-color: var(--ac-radio-checkbox-action, var(--a-surface-action));
|
||||
}
|
||||
|
||||
@@ -114,7 +117,7 @@
|
||||
}
|
||||
|
||||
.navds-checkbox__input:checked + .navds-checkbox__label::before {
|
||||
box-shadow: none;
|
||||
box-shadow: 0 0 0 2px var(--ac-radio-checkbox-action, var(--a-surface-action));
|
||||
background-color: var(--ac-radio-checkbox-action, var(--a-surface-action));
|
||||
}
|
||||
|
||||
@@ -146,31 +149,33 @@
|
||||
|
||||
.navds-checkbox__input:indeterminate:focus-visible + .navds-checkbox__label::before,
|
||||
.navds-checkbox__input:checked:focus-visible + .navds-checkbox__label::before {
|
||||
box-shadow: inset 0 0 0 1px var(--ac-radio-checkbox-bg, var(--a-surface-default)), var(--a-shadow-focus);
|
||||
box-shadow: 0 0 0 1px var(--ac-radio-checkbox-action, var(--a-surface-action)),
|
||||
0 0 0 2px var(--ac-radio-checkbox-bg, var(--a-surface-default)), 0 0 0 4px var(--a-border-focus);
|
||||
}
|
||||
|
||||
@supports not selector(:focus-visible) {
|
||||
.navds-checkbox__input:indeterminate:focus + .navds-checkbox__label::before,
|
||||
.navds-checkbox__input:checked:focus + .navds-checkbox__label::before {
|
||||
box-shadow: inset 0 0 0 1px var(--ac-radio-checkbox-bg, var(--a-surface-default)), var(--a-shadow-focus);
|
||||
box-shadow: 0 0 0 1px var(--ac-radio-checkbox-action, var(--a-surface-action)),
|
||||
0 0 0 2px var(--ac-radio-checkbox-bg, var(--a-surface-default)), 0 0 0 4px var(--a-border-focus);
|
||||
}
|
||||
}
|
||||
|
||||
.navds-radio__input:checked + .navds-radio__label::before {
|
||||
box-shadow: inset 0 0 0 2px var(--ac-radio-checkbox-action, var(--a-surface-action)),
|
||||
inset 0 0 0 4px var(--ac-radio-checkbox-bg, var(--a-surface-default));
|
||||
box-shadow: 0 0 0 2px var(--ac-radio-checkbox-action, var(--a-surface-action)),
|
||||
inset 0 0 0 2px var(--ac-radio-checkbox-bg, var(--a-surface-default));
|
||||
background-color: var(--ac-radio-checkbox-action, var(--a-surface-action));
|
||||
}
|
||||
|
||||
.navds-radio__input:checked:focus-visible + .navds-radio__label::before {
|
||||
box-shadow: inset 0 0 0 2px var(--ac-radio-checkbox-action, var(--a-surface-action)),
|
||||
inset 0 0 0 4px var(--ac-radio-checkbox-bg, var(--a-surface-default)), var(--a-shadow-focus);
|
||||
box-shadow: 0 0 0 2px var(--ac-radio-checkbox-action, var(--a-surface-action)),
|
||||
inset 0 0 0 2px var(--ac-radio-checkbox-bg, var(--a-surface-default)), 0 0 0 4px var(--a-border-focus);
|
||||
}
|
||||
|
||||
@supports not selector(:focus-visible) {
|
||||
.navds-radio__input:checked:focus + .navds-radio__label::before {
|
||||
box-shadow: inset 0 0 0 2px var(--ac-radio-checkbox-action, var(--a-surface-action)),
|
||||
inset 0 0 0 4px var(--ac-radio-checkbox-bg, var(--a-surface-default)), var(--a-shadow-focus);
|
||||
box-shadow: 0 0 0 2px var(--ac-radio-checkbox-action, var(--a-surface-action)),
|
||||
inset 0 0 0 2px var(--ac-radio-checkbox-bg, var(--a-surface-default)), 0 0 0 4px var(--a-border-focus);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,13 +187,13 @@
|
||||
.navds-checkbox__input:hover:not(:disabled):not(:checked):not(:indeterminate):not(:focus-visible)
|
||||
+ .navds-checkbox__label::before,
|
||||
.navds-radio__input:hover:not(:disabled):not(:checked):not(:focus-visible) + .navds-radio__label::before {
|
||||
box-shadow: inset 0 0 0 2px var(--ac-radio-checkbox-action, var(--a-surface-action));
|
||||
box-shadow: 0 0 0 2px var(--ac-radio-checkbox-action, var(--a-surface-action));
|
||||
}
|
||||
|
||||
@supports not selector(:focus-visible) {
|
||||
.navds-checkbox__input:hover:not(:disabled):not(:checked):not(:indeterminate):not(:focus) + .navds-checkbox__label::before,
|
||||
.navds-radio__input:hover:not(:disabled):not(:checked):not(:focus) + .navds-radio__label::before {
|
||||
box-shadow: inset 0 0 0 2px var(--ac-radio-checkbox-action, var(--a-surface-action));
|
||||
box-shadow: 0 0 0 2px var(--ac-radio-checkbox-action, var(--a-surface-action));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,14 +206,14 @@
|
||||
> .navds-checkbox__input:not(:hover):not(:disabled):not(:checked):not(:indeterminate)
|
||||
+ .navds-checkbox__label::before,
|
||||
.navds-radio--error > .navds-radio__input:not(:hover):not(:disabled):not(:checked) + .navds-radio__label::before {
|
||||
box-shadow: inset 0 0 0 2px var(--ac-radio-checkbox-error-border, var(--a-border-danger));
|
||||
box-shadow: 0 0 0 2px var(--ac-radio-checkbox-error-border, var(--a-border-danger));
|
||||
}
|
||||
|
||||
.navds-checkbox--error
|
||||
> .navds-checkbox__input:focus-visible:not(:hover):not(:disabled):not(:checked):not(:indeterminate)
|
||||
+ .navds-checkbox__label::before,
|
||||
.navds-radio--error > .navds-radio__input:focus-visible:not(:hover):not(:disabled):not(:checked) + .navds-radio__label::before {
|
||||
box-shadow: inset 0 0 0 2px var(--ac-radio-checkbox-error-border, var(--a-border-danger)), var(--a-shadow-focus);
|
||||
box-shadow: 0 0 0 2px var(--ac-radio-checkbox-error-border, var(--a-border-danger)), 0 0 0 4px var(--a-border-focus);
|
||||
}
|
||||
|
||||
@supports not selector(:focus-visible) {
|
||||
@@ -216,7 +221,7 @@
|
||||
> .navds-checkbox__input:focus:not(:hover):not(:disabled):not(:checked):not(:indeterminate)
|
||||
+ .navds-checkbox__label::before,
|
||||
.navds-radio--error > .navds-radio__input:focus:not(:hover):not(:disabled):not(:checked) + .navds-radio__label::before {
|
||||
box-shadow: inset 0 0 0 2px var(--ac-radio-checkbox-error-border, var(--a-border-danger)), var(--a-shadow-focus);
|
||||
box-shadow: 0 0 0 2px var(--ac-radio-checkbox-error-border, var(--a-border-danger)), 0 0 0 4px var(--a-border-focus);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +230,7 @@
|
||||
+ .navds-checkbox__label::before,
|
||||
.navds-radio--error > .navds-radio__input:hover:not(:disabled):not(:checked):not(:focus-visible) + .navds-radio__label::before {
|
||||
background-color: var(--ac-radio-checkbox-error-hover-bg, var(--a-surface-danger-subtle));
|
||||
box-shadow: inset 0 0 0 2px var(--ac-radio-checkbox-error-border, var(--a-border-danger));
|
||||
box-shadow: 0 0 0 2px var(--ac-radio-checkbox-error-border, var(--a-border-danger));
|
||||
}
|
||||
|
||||
.navds-checkbox--error
|
||||
@@ -233,7 +238,7 @@
|
||||
+ .navds-checkbox__label::before,
|
||||
.navds-radio--error > .navds-radio__input:focus-visible:hover:not(:disabled):not(:checked) + .navds-radio__label::before {
|
||||
background-color: var(--ac-radio-checkbox-error-hover-bg, var(--a-surface-danger-subtle));
|
||||
box-shadow: inset 0 0 0 2px var(--ac-radio-checkbox-error-border, var(--a-border-danger)), var(--a-shadow-focus);
|
||||
box-shadow: 0 0 0 2px var(--ac-radio-checkbox-error-border, var(--a-border-danger)), 0 0 0 4px var(--a-border-focus);
|
||||
}
|
||||
|
||||
@supports not selector(:focus-visible) {
|
||||
@@ -242,7 +247,7 @@
|
||||
+ .navds-checkbox__label::before,
|
||||
.navds-radio--error > .navds-radio__input:hover:not(:disabled):not(:checked):not(:focus) + .navds-radio__label::before {
|
||||
background-color: var(--ac-radio-checkbox-error-hover-bg, var(--a-surface-danger-subtle));
|
||||
box-shadow: inset 0 0 0 2px var(--ac-radio-checkbox-error-border, var(--a-border-danger));
|
||||
box-shadow: 0 0 0 2px var(--ac-radio-checkbox-error-border, var(--a-border-danger));
|
||||
}
|
||||
|
||||
.navds-checkbox--error
|
||||
@@ -250,7 +255,7 @@
|
||||
+ .navds-checkbox__label::before,
|
||||
.navds-radio--error > .navds-radio__input:focus:hover:not(:disabled):not(:checked) + .navds-radio__label::before {
|
||||
background-color: var(--ac-radio-checkbox-error-hover-bg, var(--a-surface-danger-subtle));
|
||||
box-shadow: inset 0 0 0 2px var(--ac-radio-checkbox-error-border, var(--a-border-danger)), var(--a-shadow-focus);
|
||||
box-shadow: 0 0 0 2px var(--ac-radio-checkbox-error-border, var(--a-border-danger)), 0 0 0 4px var(--a-border-focus);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,7 +295,7 @@
|
||||
.navds-radio--readonly > .navds-radio__input:not(:disabled):not(:checked) + .navds-radio__label::before,
|
||||
.navds-radio--readonly > .navds-radio__input:hover:not(:checked):not(:focus-visible) + .navds-radio__label::before {
|
||||
background-color: var(--__ac-radio-checkbox-readonly-bg);
|
||||
box-shadow: inset 0 0 0 2px var(--__ac-radio-checkbox-readonly-border);
|
||||
box-shadow: 0 0 0 2px var(--__ac-radio-checkbox-readonly-border);
|
||||
}
|
||||
|
||||
.navds-checkbox--readonly > .navds-checkbox__input:focus-visible + .navds-checkbox__label::before,
|
||||
@@ -299,8 +304,8 @@
|
||||
}
|
||||
|
||||
.navds-checkbox--readonly > .navds-checkbox__input:checked + .navds-checkbox__label::before {
|
||||
box-shadow: inset 0 0 0 2px var(--__ac-radio-checkbox-readonly-border);
|
||||
background-color: var(--__ac-radio-checkbox-readonly-bg);
|
||||
box-shadow: 0 0 0 2px var(--__ac-radio-checkbox-readonly-border);
|
||||
}
|
||||
|
||||
.navds-checkbox--readonly > .navds-checkbox__input:checked + .navds-checkbox__label > .navds-checkbox__icon {
|
||||
@@ -308,12 +313,12 @@
|
||||
}
|
||||
|
||||
.navds-radio--readonly > .navds-radio__input:checked + .navds-radio__label::before {
|
||||
box-shadow: inset 0 0 0 2px var(--__ac-radio-checkbox-readonly-border), inset 0 0 0 4px var(--__ac-radio-checkbox-readonly-bg);
|
||||
background-color: var(--a-icon-subtle);
|
||||
box-shadow: 0 0 0 2px var(--__ac-radio-checkbox-readonly-border), inset 0 0 0 2px var(--__ac-radio-checkbox-readonly-bg);
|
||||
}
|
||||
|
||||
.navds-checkbox--readonly > .navds-checkbox__input:indeterminate + .navds-checkbox__label::before {
|
||||
box-shadow: inset 0 0 0 2px var(--__ac-radio-checkbox-readonly-border);
|
||||
box-shadow: 0 0 0 2px var(--__ac-radio-checkbox-readonly-border);
|
||||
background-color: var(--__ac-radio-checkbox-readonly-bg);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
.navds-modal--polyfilled {
|
||||
top: 50%;
|
||||
transform: translate(0, -50%);
|
||||
overflow: auto;
|
||||
|
||||
/* From polyfill (dialog-polyfill/dist/dialog-polyfill.css): */
|
||||
left: 0;
|
||||
@@ -33,6 +32,10 @@
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.navds-modal--polyfilled .navds-modal--polyfilled {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.navds-modal--polyfilled:not([open]) {
|
||||
display: none; /* from polyfill */
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-css",
|
||||
"version": "5.7.3",
|
||||
"version": "5.8.0",
|
||||
"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.7.3",
|
||||
"@navikt/ds-tokens": "^5.8.0",
|
||||
"cssnano": "6.0.0",
|
||||
"fast-glob": "3.2.11",
|
||||
"lodash": "4.17.21",
|
||||
|
||||
@@ -1,5 +1,53 @@
|
||||
# @navikt/ds-react
|
||||
|
||||
## 5.8.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- :sparkles: Modal: Støtte for å lukke ved klikk utenfor ([#2386](https://github.com/navikt/aksel/pull/2386))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Autocomplete in combobox will not change formatting of the letters while being typed, but will use the casing of the autocompleted word when selecting the option. ([#2207](https://github.com/navikt/aksel/pull/2207))
|
||||
|
||||
- Accordion: Fikset dom-validering ved bruk av `div` i `button`. ([#2426](https://github.com/navikt/aksel/pull/2426))
|
||||
|
||||
- :bug: Modal: Bedre støtte for Tooltip i Modal ([#2429](https://github.com/navikt/aksel/pull/2429))
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.8.0
|
||||
- @navikt/aksel-icons@5.8.0
|
||||
|
||||
## 5.7.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- :lipstick: Chips.Toggle: Ikon i uvalgt tilstand ([#2395](https://github.com/navikt/aksel/pull/2395))
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.7.6
|
||||
- @navikt/aksel-icons@5.7.6
|
||||
|
||||
## 5.7.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Loader: Har nå riktig `ref`-type. ([#2391](https://github.com/navikt/aksel/pull/2391))
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.7.5
|
||||
- @navikt/aksel-icons@5.7.5
|
||||
|
||||
## 5.7.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Datepicker: Fungerer nå bedre i Modal ([#2400](https://github.com/navikt/aksel/pull/2400))
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.7.4
|
||||
- @navikt/aksel-icons@5.7.4
|
||||
|
||||
## 5.7.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-react",
|
||||
"version": "5.7.3",
|
||||
"version": "5.8.0",
|
||||
"description": "Aksel react-components for NAV designsystem",
|
||||
"author": "Aksel | NAV designsystem team",
|
||||
"license": "MIT",
|
||||
@@ -38,8 +38,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@floating-ui/react": "0.25.4",
|
||||
"@navikt/aksel-icons": "^5.7.3",
|
||||
"@navikt/ds-tokens": "^5.7.3",
|
||||
"@navikt/aksel-icons": "^5.8.0",
|
||||
"@navikt/ds-tokens": "^5.8.0",
|
||||
"@radix-ui/react-tabs": "1.0.0",
|
||||
"@radix-ui/react-toggle-group": "1.0.0",
|
||||
"clsx": "^1.2.1",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { ChevronDownIcon } from "@navikt/aksel-icons";
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef, useContext } from "react";
|
||||
import { Heading } from "../typography";
|
||||
import { AccordionContext } from "./AccordionContext";
|
||||
import { AccordionItemContext } from "./AccordionItem";
|
||||
import { ChevronDownIcon } from "@navikt/aksel-icons";
|
||||
|
||||
export interface AccordionHeaderProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
@@ -37,13 +37,13 @@ const AccordionHeader = forwardRef<HTMLButtonElement, AccordionHeaderProps>(
|
||||
aria-expanded={itemContext.open}
|
||||
type="button"
|
||||
>
|
||||
<div className="navds-accordion__icon-wrapper">
|
||||
<span className="navds-accordion__icon-wrapper">
|
||||
<ChevronDownIcon
|
||||
className="navds-accordion__header-chevron"
|
||||
title="Vis mer"
|
||||
aria-hidden
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
<Heading
|
||||
size={accordionContext?.headingSize ?? "small"}
|
||||
as="span"
|
||||
|
||||
@@ -6,7 +6,7 @@ export interface ToggleChipsProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
children: string;
|
||||
/**
|
||||
* Toggles aria-pressed and visual-changes
|
||||
* Toggles aria-pressed and visual changes
|
||||
*/
|
||||
selected?: boolean;
|
||||
/**
|
||||
@@ -44,28 +44,38 @@ export const ToggleChips: OverridableComponent<
|
||||
className={cl(
|
||||
"navds-chips__chip navds-chips__toggle",
|
||||
className,
|
||||
`navds-chips__toggle--${variant}`
|
||||
`navds-chips__toggle--${variant}`,
|
||||
{ "navds-chips__toggle--with-checkmark": checkmark }
|
||||
)}
|
||||
aria-pressed={selected}
|
||||
>
|
||||
{selected && checkmark && (
|
||||
{checkmark && (
|
||||
<svg
|
||||
aria-hidden
|
||||
className="navds-chips__toggle-icon"
|
||||
width="10"
|
||||
height="8"
|
||||
viewBox="0 0 10 8"
|
||||
width="1.25em"
|
||||
height="1.25em"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
focusable={false}
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M9.51894 0.45851C9.81799 0.745107 9.8281 1.21987 9.5415 1.51893L3.7915 7.51893C3.51247 7.81009 3.05315 7.82848 2.75174 7.56056L0.501735 5.56056C0.192148 5.28537 0.164263 4.81132 0.439451 4.50173C0.71464 4.19214 1.18869 4.16426 1.49828 4.43944L3.20835 5.95951L8.45852 0.481072C8.74511 0.182015 9.21988 0.171913 9.51894 0.45851Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
{selected ? (
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M10 18.125C14.4873 18.125 18.125 14.4873 18.125 10C18.125 5.51269 14.4873 1.875 10 1.875C5.51269 1.875 1.875 5.51269 1.875 10C1.875 14.4873 5.51269 18.125 10 18.125ZM14.128 7.72904C14.3695 7.44357 14.3339 7.01635 14.0485 6.7748C13.763 6.53326 13.3358 6.56886 13.0942 6.85432L8.60428 12.1606L6.41627 9.97263C6.15185 9.70822 5.72315 9.70822 5.45873 9.97263C5.19431 10.2371 5.19431 10.6658 5.45873 10.9302L8.16706 13.6385C8.30095 13.7724 8.48479 13.8441 8.67397 13.8362C8.86316 13.8284 9.0404 13.7416 9.16271 13.5971L14.128 7.72904Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
) : (
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M10 3.125C6.20304 3.125 3.125 6.20304 3.125 10C3.125 13.797 6.20304 16.875 10 16.875C13.797 16.875 16.875 13.797 16.875 10C16.875 6.20304 13.797 3.125 10 3.125ZM1.875 10C1.875 5.51269 5.51269 1.875 10 1.875C14.4873 1.875 18.125 5.51269 18.125 10C18.125 14.4873 14.4873 18.125 10 18.125C5.51269 18.125 1.875 14.4873 1.875 10Z"
|
||||
fill="var(--a-border-default)"
|
||||
/>
|
||||
)}
|
||||
</svg>
|
||||
)}
|
||||
<span className="navds-chips__chip-text">{children}</span>
|
||||
|
||||
@@ -60,11 +60,11 @@ Default.argTypes = {
|
||||
},
|
||||
};
|
||||
|
||||
export const Toggle = () => {
|
||||
export const Toggle = ({ size }) => {
|
||||
const [selected, setSelected] = useState<number[]>([2, 4]);
|
||||
return (
|
||||
<div className="colgap">
|
||||
<Chips>
|
||||
<Chips size={size}>
|
||||
{options.map((c, y) => (
|
||||
<Chips.Toggle
|
||||
selected={selected.includes(y)}
|
||||
@@ -81,7 +81,7 @@ export const Toggle = () => {
|
||||
</Chips.Toggle>
|
||||
))}
|
||||
</Chips>
|
||||
<Chips>
|
||||
<Chips size={size}>
|
||||
{options.map((c, y) => (
|
||||
<Chips.Toggle
|
||||
variant="neutral"
|
||||
@@ -102,6 +102,12 @@ export const Toggle = () => {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Toggle.argTypes = {
|
||||
size: {
|
||||
control: { type: "radio" },
|
||||
options: ["medium", "small"],
|
||||
},
|
||||
};
|
||||
|
||||
export const ToggleNoCheckmark = () => {
|
||||
const [selected, setSelected] = useState<number>(2);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* eslint-disable react-hooks/rules-of-hooks */
|
||||
import { Meta, StoryObj } from "@storybook/react";
|
||||
import isSameDay from "date-fns/isSameDay";
|
||||
import React, { useId, useState } from "react";
|
||||
import { useDatepicker, useRangeDatepicker } from "..";
|
||||
import { Button, HGrid, VStack } from "../..";
|
||||
import { BodyLong, Button, HGrid, HStack, Modal, VStack } from "../..";
|
||||
import DatePicker, { DatePickerProps } from "./DatePicker";
|
||||
import isSameDay from "date-fns/isSameDay";
|
||||
|
||||
const disabledDays = [
|
||||
new Date("Oct 10 2022"),
|
||||
@@ -432,3 +432,42 @@ export const WeekDayClick = () => {
|
||||
</VStack>
|
||||
);
|
||||
};
|
||||
|
||||
export const ModalDemo = () => {
|
||||
const { datepickerProps, inputProps } = useDatepicker({
|
||||
fromDate: new Date("Aug 23 2019"),
|
||||
toDate: new Date("Feb 23 2024"),
|
||||
onDateChange: console.log,
|
||||
});
|
||||
|
||||
return (
|
||||
<Modal open header={{ heading: "Modal-demo" }} width="1024px">
|
||||
<Modal.Body style={{ position: "relative" }}>
|
||||
<BodyLong>
|
||||
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Maiores nisi
|
||||
incidunt ipsum cupiditate nostrum nesciunt, corrupti nihil at atque
|
||||
animi ab aut. Quam iusto harum eligendi magnam nulla repudiandae
|
||||
molestias.
|
||||
</BodyLong>
|
||||
|
||||
<HGrid gap="6" columns={{ xs: 1, lg: 2 }}>
|
||||
<HStack justify="center" align="start">
|
||||
<DatePicker.Standalone
|
||||
fromDate={new Date("Aug 23 2019")}
|
||||
toDate={new Date("Feb 23 2024")}
|
||||
/>
|
||||
</HStack>
|
||||
<DatePicker {...datepickerProps} dropdownCaption>
|
||||
<DatePicker.Input {...inputProps} label="Velg dato" />
|
||||
</DatePicker>
|
||||
<HStack justify="center">
|
||||
<DatePicker.Standalone
|
||||
fromDate={new Date("Aug 23 2019")}
|
||||
toDate={new Date("Feb 23 2024")}
|
||||
/>
|
||||
</HStack>
|
||||
</HGrid>
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@@ -1,8 +1,10 @@
|
||||
import { Meta, StoryFn } from "@storybook/react";
|
||||
import setYear from "date-fns/setYear";
|
||||
import React, { useId, useState } from "react";
|
||||
import { Button, DateInputProps } from "../..";
|
||||
import { useMonthpicker } from "../hooks";
|
||||
import MonthPicker, { MonthPickerProps } from "./MonthPicker";
|
||||
import MonthPicker from "./MonthPicker";
|
||||
import { MonthPickerProps } from "./types";
|
||||
|
||||
export default {
|
||||
title: "ds-react/Monthpicker",
|
||||
@@ -147,3 +149,28 @@ export const UserControlled = () => {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const FollowYear = () => {
|
||||
const { monthpickerProps, inputProps, selectedMonth, setSelected } =
|
||||
useMonthpicker({
|
||||
fromDate: new Date("Aug 23 2019"),
|
||||
toDate: new Date("Aug 23 2025"),
|
||||
onMonthChange: console.log,
|
||||
});
|
||||
|
||||
const customYearChange = (yearDate?: Date) => {
|
||||
monthpickerProps.onYearChange?.(yearDate);
|
||||
if (selectedMonth && yearDate) {
|
||||
setSelected(setYear(selectedMonth, yearDate.getFullYear()));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-96">
|
||||
<MonthPicker {...monthpickerProps} onYearChange={customYearChange}>
|
||||
<MonthPicker.Input {...inputProps} label="Velg månede" />
|
||||
</MonthPicker>
|
||||
{selectedMonth && <div className="pt-4">{selectedMonth.getMonth()}</div>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -95,8 +95,7 @@ export const FilteredOptionsProvider = ({ children, value: props }) => {
|
||||
shouldAutocomplete &&
|
||||
normalizeText(searchTerm) !== "" &&
|
||||
(previousSearchTerm?.length || 0) < searchTerm.length &&
|
||||
filteredOptions.length > 0 &&
|
||||
!isValueInList(searchTerm, filteredOptions)
|
||||
filteredOptions.length > 0
|
||||
) {
|
||||
setValue(
|
||||
`${searchTerm}${filteredOptions[0].substring(searchTerm.length)}`
|
||||
|
||||
@@ -31,6 +31,7 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||
allowNewValues,
|
||||
currentOption,
|
||||
filteredOptions,
|
||||
isValueNew,
|
||||
toggleIsListOpen,
|
||||
isListOpen,
|
||||
filteredOptionsIndex,
|
||||
@@ -46,29 +47,43 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||
|
||||
const onEnter = useCallback(
|
||||
(event: React.KeyboardEvent) => {
|
||||
const isTextInSelectedOptions = (text: string) => {
|
||||
return selectedOptions.find(
|
||||
(item) => item.toLocaleLowerCase() === text.toLocaleLowerCase()
|
||||
);
|
||||
};
|
||||
|
||||
if (currentOption) {
|
||||
event.preventDefault();
|
||||
// Selecting a value from the dropdown / FilteredOptions
|
||||
toggleOption(currentOption, event);
|
||||
if (!isMultiSelect && !selectedOptions.includes(currentOption))
|
||||
if (!isMultiSelect && !isTextInSelectedOptions(currentOption))
|
||||
toggleIsListOpen(false);
|
||||
} else if (shouldAutocomplete && selectedOptions.includes(value)) {
|
||||
} else if (shouldAutocomplete && isTextInSelectedOptions(value)) {
|
||||
event.preventDefault();
|
||||
// Trying to set the same value that is already set, so just clearing the input
|
||||
clearInput(event);
|
||||
} else if ((allowNewValues || shouldAutocomplete) && value !== "") {
|
||||
event.preventDefault();
|
||||
// Autocompleting or adding a new value
|
||||
toggleOption(value, event);
|
||||
if (!isMultiSelect && !selectedOptions.includes(value))
|
||||
const selectedValue =
|
||||
allowNewValues && isValueNew ? value : filteredOptions[0];
|
||||
toggleOption(selectedValue, event);
|
||||
if (
|
||||
!isMultiSelect &&
|
||||
!isTextInSelectedOptions(filteredOptions[0] || selectedValue)
|
||||
) {
|
||||
toggleIsListOpen(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
[
|
||||
allowNewValues,
|
||||
clearInput,
|
||||
currentOption,
|
||||
filteredOptions,
|
||||
isMultiSelect,
|
||||
isValueNew,
|
||||
selectedOptions,
|
||||
shouldAutocomplete,
|
||||
toggleIsListOpen,
|
||||
|
||||
@@ -467,6 +467,50 @@ export const TestThatCallbacksOnlyFireWhenExpected: StoryObj<{
|
||||
},
|
||||
};
|
||||
|
||||
export const TestCasingWhenAutoCompleting = {
|
||||
args: {
|
||||
onChange: jest.fn(),
|
||||
onClear: jest.fn(),
|
||||
onToggleSelected: jest.fn(),
|
||||
},
|
||||
render: (props) => {
|
||||
return (
|
||||
<UNSAFE_Combobox
|
||||
options={["Camel Case", "lowercase", "UPPERCASE"]}
|
||||
label="Liker du best store eller små bokstaver?"
|
||||
shouldAutocomplete
|
||||
allowNewValues
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const input = canvas.getByRole<HTMLInputElement>("combobox");
|
||||
|
||||
// With exisiting option
|
||||
userEvent.click(input);
|
||||
await userEvent.type(input, "cAmEl CaSe", { delay: 250 });
|
||||
await sleep(250);
|
||||
expect(input.value).toBe("cAmEl CaSe");
|
||||
await userEvent.type(input, "{Enter}");
|
||||
await sleep(250);
|
||||
const chips = canvas.getAllByRole("list")[0];
|
||||
const selectedUpperCaseChip = within(chips).getAllByRole("listitem")[0];
|
||||
expect(selectedUpperCaseChip).toHaveTextContent("Camel Case"); // A weird issue is preventing the accessible name from being used in the test, even if it works in VoiceOver
|
||||
|
||||
// With custom option
|
||||
userEvent.click(input);
|
||||
await userEvent.type(input, "cAmEl{Backspace}", { delay: 250 });
|
||||
await sleep(250);
|
||||
expect(input.value).toBe("cAmEl");
|
||||
await userEvent.type(input, "{Enter}");
|
||||
await sleep(250);
|
||||
const selectedNewValueChip = within(chips).getAllByRole("listitem")[0];
|
||||
expect(selectedNewValueChip).toHaveTextContent("cAmEl"); // A weird issue is preventing the accessible name from being used in the test, even if it works in VoiceOver
|
||||
},
|
||||
};
|
||||
|
||||
export const TestHoverAndFocusSwitching: StoryObject = {
|
||||
render: () => {
|
||||
return (
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef } from "react";
|
||||
import {
|
||||
ResponsiveProp,
|
||||
SpacingScale,
|
||||
getResponsiveProps,
|
||||
} from "../utilities/css";
|
||||
import { getResponsiveProps } from "../utilities/css";
|
||||
import { ResponsiveProp, SpacingScale } from "../utilities/types";
|
||||
import { Slot } from "../../util/Slot";
|
||||
|
||||
export type BleedSpacingInline = "0" | "full" | "px" | SpacingScale;
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef } from "react";
|
||||
import { OverridableComponent } from "../../util/OverridableComponent";
|
||||
import { getResponsiveProps } from "../utilities/css";
|
||||
import {
|
||||
SpaceDelimitedAttribute,
|
||||
ResponsiveProp,
|
||||
SpacingScale,
|
||||
getResponsiveProps,
|
||||
} from "../utilities/css";
|
||||
import {
|
||||
BackgroundToken,
|
||||
BorderColorToken,
|
||||
ShadowToken,
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import React, { forwardRef, HTMLAttributes } from "react";
|
||||
import cl from "clsx";
|
||||
import {
|
||||
getResponsiveProps,
|
||||
getResponsiveValue,
|
||||
ResponsiveProp,
|
||||
SpacingScale,
|
||||
} from "../utilities/css";
|
||||
import { getResponsiveProps, getResponsiveValue } from "../utilities/css";
|
||||
import { ResponsiveProp, SpacingScale } from "../utilities/types";
|
||||
|
||||
export interface HGridProps extends HTMLAttributes<HTMLDivElement> {
|
||||
children: React.ReactNode;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef, HTMLAttributes } from "react";
|
||||
import { BreakpointsAlias } from "../utilities/css";
|
||||
import { BreakpointsAlias } from "../utilities/types";
|
||||
import { Slot } from "../../util/Slot";
|
||||
|
||||
export interface ResponsiveProps extends HTMLAttributes<HTMLDivElement> {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React from "react";
|
||||
import { Link } from "../../link";
|
||||
import { Heading, Label } from "../../typography";
|
||||
import { Box } from "../box";
|
||||
import { VStack } from "../stack";
|
||||
import { Link } from "../../link";
|
||||
|
||||
const LinkElement = ({ children }) => {
|
||||
return (
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef, HTMLAttributes } from "react";
|
||||
import { OverridableComponent } from "../../util/OverridableComponent";
|
||||
import {
|
||||
getResponsiveProps,
|
||||
getResponsiveValue,
|
||||
ResponsiveProp,
|
||||
SpacingScale,
|
||||
} from "../utilities/css";
|
||||
import { getResponsiveProps, getResponsiveValue } from "../utilities/css";
|
||||
import { ResponsiveProp, SpacingScale } from "../utilities/types";
|
||||
|
||||
export interface StackProps extends HTMLAttributes<HTMLDivElement> {
|
||||
children: React.ReactNode;
|
||||
|
||||
@@ -1,39 +1,4 @@
|
||||
export type BreakpointsAlias = "xs" | "sm" | "md" | "lg" | "xl";
|
||||
|
||||
export type SpacingScale =
|
||||
| "0"
|
||||
| "05"
|
||||
| "1"
|
||||
| "1-alt"
|
||||
| "2"
|
||||
| "3"
|
||||
| "4"
|
||||
| "5"
|
||||
| "6"
|
||||
| "7"
|
||||
| "8"
|
||||
| "9"
|
||||
| "10"
|
||||
| "11"
|
||||
| "12"
|
||||
| "14"
|
||||
| "16"
|
||||
| "18"
|
||||
| "20"
|
||||
| "24"
|
||||
| "32";
|
||||
|
||||
export type SpaceDelimitedAttribute<T extends string> =
|
||||
| T
|
||||
| `${T} ${T}`
|
||||
| `${T} ${T} ${T}`
|
||||
| `${T} ${T} ${T} ${T}`;
|
||||
|
||||
type FixedResponsiveT<T> = {
|
||||
[Breakpoint in BreakpointsAlias]?: T;
|
||||
};
|
||||
|
||||
export type ResponsiveProp<T> = T | FixedResponsiveT<T>;
|
||||
import { ResponsiveProp } from "./types";
|
||||
|
||||
export function getResponsiveValue<T = string>(
|
||||
componentName: string,
|
||||
|
||||
@@ -3,6 +3,7 @@ import surfaceColors from "@navikt/ds-tokens/src/colors-surface.json";
|
||||
import borderColors from "@navikt/ds-tokens/src/colors-border.json";
|
||||
import borderRadii from "@navikt/ds-tokens/src/border.json";
|
||||
import shadows from "@navikt/ds-tokens/src/shadow.json";
|
||||
import Spacing from "@navikt/ds-tokens/src/spacing.json";
|
||||
|
||||
export type BackgroundToken =
|
||||
| keyof typeof bgColors.a
|
||||
@@ -12,3 +13,18 @@ export type BorderRadiiToken =
|
||||
| keyof (typeof borderRadii.a)["border-radius"]
|
||||
| "0";
|
||||
export type ShadowToken = keyof typeof shadows.a.shadow;
|
||||
|
||||
export type BreakpointsAlias = "xs" | "sm" | "md" | "lg" | "xl";
|
||||
|
||||
export type SpacingScale = keyof (typeof Spacing)["a"]["spacing"];
|
||||
|
||||
export type SpaceDelimitedAttribute<T extends string> =
|
||||
| T
|
||||
| `${T} ${T}`
|
||||
| `${T} ${T} ${T}`
|
||||
| `${T} ${T} ${T} ${T}`;
|
||||
type FixedResponsiveT<T> = {
|
||||
[Breakpoint in BreakpointsAlias]?: T;
|
||||
};
|
||||
|
||||
export type ResponsiveProp<T> = T | FixedResponsiveT<T>;
|
||||
@@ -2,7 +2,7 @@ import cl from "clsx";
|
||||
import React, { forwardRef, SVGProps } from "react";
|
||||
import { omit, useId } from "../util";
|
||||
|
||||
export interface LoaderProps extends SVGProps<SVGSVGElement> {
|
||||
export interface LoaderProps extends Omit<SVGProps<SVGSVGElement>, "ref"> {
|
||||
/**
|
||||
* Changes Loader width/height
|
||||
* 88px | 64px | 40px | 32px | 24px | 20px | 16px
|
||||
@@ -31,6 +31,12 @@ export interface LoaderProps extends SVGProps<SVGSVGElement> {
|
||||
* @default "neutral"
|
||||
*/
|
||||
variant?: "neutral" | "interaction" | "inverted";
|
||||
/**
|
||||
* Allows getting a ref to the component instance.
|
||||
* Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
|
||||
* @see https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom
|
||||
*/
|
||||
ref?: React.Ref<SVGSVGElement>;
|
||||
}
|
||||
|
||||
/* Workaround for @types/react v17/v18 feil */
|
||||
@@ -46,7 +52,7 @@ export type LoaderType = React.ForwardRefExoticComponent<
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* <Loader size="3xlarge" title="venter..." />
|
||||
* <Loader size="3xlarge" title="Venter..." />
|
||||
* ```
|
||||
*/
|
||||
export const Loader: LoaderType = forwardRef<SVGSVGElement, LoaderProps>(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import { Loader } from "..";
|
||||
import { Meta } from "@storybook/react";
|
||||
import React from "react";
|
||||
import { Loader, LoaderProps } from "..";
|
||||
export default {
|
||||
title: "ds-react/Loader",
|
||||
component: Loader,
|
||||
@@ -29,7 +29,7 @@ export default {
|
||||
} as Meta;
|
||||
|
||||
export const Default = {
|
||||
render: (props: any) => {
|
||||
render: (props: LoaderProps) => {
|
||||
return <Loader {...props} />;
|
||||
},
|
||||
|
||||
|
||||
@@ -82,11 +82,13 @@ export const Modal = forwardRef<HTMLDialogElement, ModalProps>(
|
||||
open,
|
||||
onBeforeClose,
|
||||
onCancel,
|
||||
closeOnBackdropClick,
|
||||
width,
|
||||
portal,
|
||||
className,
|
||||
"aria-labelledby": ariaLabelledby,
|
||||
style,
|
||||
onClick,
|
||||
...rest
|
||||
}: ModalProps,
|
||||
ref
|
||||
@@ -108,6 +110,11 @@ export const Modal = forwardRef<HTMLDialogElement, ModalProps>(
|
||||
if (needPolyfill && modalRef.current && portalNode) {
|
||||
dialogPolyfill.registerDialog(modalRef.current);
|
||||
}
|
||||
// We set autofocus on the dialog element to prevent the default behavior where first focusable element gets focus when modal is opened.
|
||||
// This is mainly to fix an edge case where having a Tooltip as the first focusable element would make it activate when you open the modal.
|
||||
// We have to use JS because it doesn't work to set it with a prop (React bug?)
|
||||
// Currently doesn't seem to work in Chrome. See also Tooltip.tsx
|
||||
if (modalRef.current && portalNode) modalRef.current.autofocus = true;
|
||||
}, [modalRef, portalNode]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -128,34 +135,57 @@ export const Modal = forwardRef<HTMLDialogElement, ModalProps>(
|
||||
const isWidthPreset =
|
||||
typeof width === "string" && ["small", "medium"].includes(width);
|
||||
|
||||
const mergedClassName = cl("navds-modal", className, {
|
||||
"navds-modal--polyfilled": needPolyfill,
|
||||
"navds-modal--autowidth": !width,
|
||||
[`navds-modal--${width}`]: isWidthPreset,
|
||||
});
|
||||
|
||||
const mergedStyle = {
|
||||
...style,
|
||||
...(!isWidthPreset ? { width } : {}),
|
||||
};
|
||||
|
||||
const mergedOnCancel: React.DialogHTMLAttributes<HTMLDialogElement>["onCancel"] =
|
||||
(event) => {
|
||||
if (onBeforeClose && onBeforeClose() === false) {
|
||||
event.preventDefault();
|
||||
} else if (onCancel) onCancel(event);
|
||||
};
|
||||
|
||||
const mergedOnClick =
|
||||
closeOnBackdropClick && !needPolyfill // closeOnBackdropClick has issues on polyfill when nesting modals (DatePicker)
|
||||
? (event: React.MouseEvent<HTMLDialogElement>) => {
|
||||
onClick && onClick(event);
|
||||
if (
|
||||
event.target === modalRef.current &&
|
||||
(!onBeforeClose || onBeforeClose() !== false)
|
||||
) {
|
||||
modalRef.current.close();
|
||||
}
|
||||
}
|
||||
: onClick;
|
||||
|
||||
const mergedAriaLabelledBy =
|
||||
!ariaLabelledby && !rest["aria-label"] && header
|
||||
? ariaLabelId
|
||||
: ariaLabelledby;
|
||||
|
||||
const component = (
|
||||
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions
|
||||
<dialog
|
||||
{...rest}
|
||||
ref={mergedRef}
|
||||
className={cl("navds-modal", className, {
|
||||
"navds-modal--polyfilled": needPolyfill,
|
||||
"navds-modal--autowidth": !width,
|
||||
[`navds-modal--${width}`]: isWidthPreset,
|
||||
})}
|
||||
style={{
|
||||
...style,
|
||||
...(!isWidthPreset ? { width } : {}),
|
||||
}}
|
||||
onCancel={(event) => {
|
||||
// FYI: onCancel fires when you press Esc
|
||||
if (onBeforeClose && onBeforeClose() === false) {
|
||||
event.preventDefault();
|
||||
} else if (onCancel) onCancel(event);
|
||||
}}
|
||||
aria-labelledby={
|
||||
!ariaLabelledby && !rest["aria-label"] && header
|
||||
? ariaLabelId
|
||||
: ariaLabelledby
|
||||
}
|
||||
className={mergedClassName}
|
||||
style={mergedStyle}
|
||||
onCancel={mergedOnCancel} // FYI: onCancel fires when you press Esc
|
||||
onClick={mergedOnClick}
|
||||
aria-labelledby={mergedAriaLabelledBy}
|
||||
>
|
||||
<ModalContext.Provider
|
||||
value={{
|
||||
closeHandler: getCloseHandler(modalRef, header, onBeforeClose),
|
||||
ref: modalRef,
|
||||
}}
|
||||
>
|
||||
{header && (
|
||||
|
||||
@@ -2,5 +2,6 @@ import React from "react";
|
||||
|
||||
interface ModalContextProps {
|
||||
closeHandler?: React.MouseEventHandler<HTMLButtonElement>;
|
||||
ref: React.RefObject<HTMLDialogElement>;
|
||||
}
|
||||
export const ModalContext = React.createContext<ModalContextProps | null>(null);
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useRef, useState } from "react";
|
||||
import { FileIcon } from "@navikt/aksel-icons";
|
||||
import { BodyLong, Button, Heading } from "..";
|
||||
import React, { useRef, useState } from "react";
|
||||
import { BodyLong, Button, Heading, Tooltip } from "..";
|
||||
import Modal from "./Modal";
|
||||
|
||||
export default {
|
||||
@@ -27,6 +27,7 @@ export const WithUseRef = () => {
|
||||
heading: "Title",
|
||||
size: "small",
|
||||
}}
|
||||
closeOnBackdropClick
|
||||
>
|
||||
<Modal.Body>
|
||||
<BodyLong spacing>
|
||||
@@ -45,6 +46,7 @@ export const WithUseRef = () => {
|
||||
onBeforeClose={() =>
|
||||
window.confirm("Are you sure you want to close the modal?")
|
||||
}
|
||||
closeOnBackdropClick
|
||||
aria-labelledby="heading123"
|
||||
>
|
||||
<Modal.Header>
|
||||
@@ -111,6 +113,7 @@ export const WithUseState = () => {
|
||||
e.stopPropagation(); // onClose wil propagate to parent modal if not stopped
|
||||
setOpen2(false);
|
||||
}}
|
||||
closeOnBackdropClick
|
||||
aria-label="Nested modal"
|
||||
width={800}
|
||||
>
|
||||
@@ -165,3 +168,28 @@ export const MediumWithPortal = () => (
|
||||
<Modal.Body>Lorem ipsum dolor sit amet.</Modal.Body>
|
||||
</Modal>
|
||||
);
|
||||
|
||||
export const WithTooltip = () => {
|
||||
const ref = useRef<HTMLDialogElement>(null);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Button onClick={() => ref.current?.showModal()}>Open Modal</Button>
|
||||
<Modal
|
||||
open={ref.current ? undefined : true /* initially open */}
|
||||
ref={ref}
|
||||
>
|
||||
<Modal.Body>
|
||||
<div style={{ marginBottom: "1rem" }}>
|
||||
<Tooltip content="This_is_the_first_tooltip">
|
||||
<Button>Test 1</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Tooltip content="This is the second tooltip">
|
||||
<Button>Test 2</Button>
|
||||
</Tooltip>
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -42,6 +42,13 @@ export interface ModalProps
|
||||
* Called when the user presses the Esc key, unless `onBeforeClose()` returns `false`.
|
||||
*/
|
||||
onCancel?: React.ReactEventHandler<HTMLDialogElement>;
|
||||
/**
|
||||
* Whether to close when clicking on the backdrop.
|
||||
*
|
||||
* **WARNING:** Users may click outside by accident. Don't use if closing can cause data loss, or the modal contains important info.
|
||||
* @default false
|
||||
*/
|
||||
closeOnBackdropClick?: boolean;
|
||||
/**
|
||||
* @default fit-content (up to 700px)
|
||||
* */
|
||||
|
||||
@@ -133,6 +133,7 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
|
||||
const arrowRef = useRef<HTMLDivElement | null>(null);
|
||||
const isInModal = useContext(ModalContext) !== null;
|
||||
const chosenStrategy = userStrategy ?? (isInModal ? "fixed" : "absolute");
|
||||
const chosenFlip = isInModal ? true : _flip;
|
||||
|
||||
const {
|
||||
x,
|
||||
@@ -150,7 +151,8 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
|
||||
onOpenChange: () => onClose(),
|
||||
middleware: [
|
||||
flOffset(offset ?? (arrow ? 16 : 4)),
|
||||
_flip && flip({ padding: 5, fallbackPlacements: ["bottom", "top"] }),
|
||||
chosenFlip &&
|
||||
flip({ padding: 5, fallbackPlacements: ["bottom", "top"] }),
|
||||
shift({ padding: 12 }),
|
||||
flArrow({ element: arrowRef, padding: 8 }),
|
||||
],
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {
|
||||
arrow as flArrow,
|
||||
autoUpdate,
|
||||
flip,
|
||||
FloatingPortal,
|
||||
autoUpdate,
|
||||
arrow as flArrow,
|
||||
flip,
|
||||
offset,
|
||||
safePolygon,
|
||||
shift,
|
||||
@@ -14,16 +14,18 @@ import {
|
||||
} from "@floating-ui/react";
|
||||
import cl from "clsx";
|
||||
import React, {
|
||||
HTMLAttributes,
|
||||
cloneElement,
|
||||
forwardRef,
|
||||
HTMLAttributes,
|
||||
useContext,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { ModalContext } from "../modal/ModalContext";
|
||||
import { useProvider } from "../provider";
|
||||
import { Detail } from "../typography";
|
||||
import { mergeRefs, useId } from "../util";
|
||||
import { useProvider } from "../provider";
|
||||
|
||||
export interface TooltipProps extends HTMLAttributes<HTMLDivElement> {
|
||||
/**
|
||||
@@ -110,7 +112,11 @@ export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
|
||||
) => {
|
||||
const [open, setOpen] = useState(defaultOpen);
|
||||
const arrowRef = useRef<HTMLDivElement | null>(null);
|
||||
const rootElement = useProvider()?.rootElement;
|
||||
const modalContext = useContext(ModalContext);
|
||||
const providerRootElement = useProvider()?.rootElement;
|
||||
const rootElement = modalContext
|
||||
? modalContext.ref.current
|
||||
: providerRootElement;
|
||||
|
||||
const {
|
||||
x,
|
||||
@@ -133,7 +139,13 @@ export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
|
||||
flip({ padding: 5, fallbackPlacements: ["bottom", "top"] }),
|
||||
flArrow({ element: arrowRef, padding: 5 }),
|
||||
],
|
||||
whileElementsMounted: autoUpdate,
|
||||
whileElementsMounted: modalContext
|
||||
? (reference, floating, update) =>
|
||||
// Reduces jumping in Chrome when used in a Modal and it's the first focusable element.
|
||||
// Can be removed when autofocus starts working on <dialog> in Chrome. See also Modal.tsx
|
||||
autoUpdate(reference, floating, update, { animationFrame: true })
|
||||
: autoUpdate,
|
||||
strategy: modalContext ? "fixed" : undefined,
|
||||
});
|
||||
|
||||
const { getReferenceProps, getFloatingProps } = useInteractions([
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @navikt/ds-tailwind
|
||||
|
||||
## 5.8.0
|
||||
|
||||
## 5.7.6
|
||||
|
||||
## 5.7.5
|
||||
|
||||
## 5.7.4
|
||||
|
||||
## 5.7.3
|
||||
|
||||
## 5.7.2
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-tailwind",
|
||||
"version": "5.7.3",
|
||||
"version": "5.8.0",
|
||||
"description": "Tailwind config based on @navikt/ds-tokens",
|
||||
"author": "Aksel | NAV designsystem team",
|
||||
"keywords": [
|
||||
@@ -22,7 +22,7 @@
|
||||
"directory": "@navikt/core/tailwind"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@navikt/ds-tokens": "^5.7.3",
|
||||
"@navikt/ds-tokens": "^5.8.0",
|
||||
"@types/jest": "^29.0.0",
|
||||
"color": "4.2.3",
|
||||
"jest": "^29.0.0",
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @navikt/ds-tokens
|
||||
|
||||
## 5.8.0
|
||||
|
||||
## 5.7.6
|
||||
|
||||
## 5.7.5
|
||||
|
||||
## 5.7.4
|
||||
|
||||
## 5.7.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-tokens",
|
||||
"version": "5.7.3",
|
||||
"version": "5.8.0",
|
||||
"description": "Design-tokens for NAV designsystem",
|
||||
"author": "Aksel | NAV designsystem team",
|
||||
"keywords": [
|
||||
|
||||
+284
-242
File diff suppressed because it is too large.
Load diff
@@ -15,11 +15,11 @@
|
||||
"website"
|
||||
],
|
||||
"dependencies": {
|
||||
"@navikt/aksel-icons": "^5.7.3",
|
||||
"@navikt/ds-css": "^5.7.3",
|
||||
"@navikt/ds-react": "^5.7.3",
|
||||
"@navikt/ds-tailwind": "^5.7.3",
|
||||
"@navikt/ds-tokens": "^5.7.3"
|
||||
"@navikt/aksel-icons": "^5.8.0",
|
||||
"@navikt/ds-css": "^5.8.0",
|
||||
"@navikt/ds-react": "^5.8.0",
|
||||
"@navikt/ds-tailwind": "^5.8.0",
|
||||
"@navikt/ds-tokens": "^5.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier-plugin-tailwindcss": "^0.2.3"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { BodyLong, Detail, Heading, Link } from "@navikt/ds-react";
|
||||
import {
|
||||
PortableText,
|
||||
@@ -27,7 +28,6 @@ import {
|
||||
TokenTable,
|
||||
UuFeedback,
|
||||
Video,
|
||||
logNav,
|
||||
} from ".";
|
||||
|
||||
const serializers: Partial<PortableTextReactComponents> = {
|
||||
@@ -130,14 +130,11 @@ const serializers: Partial<PortableTextReactComponents> = {
|
||||
|
||||
return (
|
||||
<Link
|
||||
as={NextLink}
|
||||
href={href}
|
||||
inlineText
|
||||
onClick={(e) =>
|
||||
logNav(
|
||||
"link",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
amplitudeLogNavigation("link", e.currentTarget.getAttribute("href"))
|
||||
}
|
||||
{...(href.startsWith("http") &&
|
||||
!href.startsWith("https://aksel.nav.no/")
|
||||
@@ -160,11 +157,7 @@ const serializers: Partial<PortableTextReactComponents> = {
|
||||
href={href}
|
||||
inlineText
|
||||
onClick={(e) =>
|
||||
logNav(
|
||||
"link",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
amplitudeLogNavigation("link", e.currentTarget.getAttribute("href"))
|
||||
}
|
||||
>
|
||||
{text}
|
||||
|
||||
@@ -111,9 +111,7 @@ export const WithSidebar = ({
|
||||
</div>
|
||||
|
||||
<div className={cl("sm:px-6 md:px-10", { flex: variant === "page" })}>
|
||||
{variant === "page" && (
|
||||
<TableOfContentsv2 changedState={pageProps["content"]} />
|
||||
)}
|
||||
{variant === "page" && <TableOfContentsv2 />}
|
||||
<div className="w-full">
|
||||
{children}
|
||||
<Feedback docId={pageProps?._id} docType={pageProps?._type} />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { BodyShort, Heading, Link } from "@navikt/ds-react";
|
||||
import { FigmaIcon, GithubIcon, SlackIcon } from "components/assets";
|
||||
import Logo from "components/assets/Logo";
|
||||
import { logNav } from "components/website-modules/utils/amplitude";
|
||||
import dynamic from "next/dynamic";
|
||||
/* import FooterForm from "./FooterForm"; */
|
||||
|
||||
@@ -119,11 +119,7 @@ function FooterLink({ children, href }) {
|
||||
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) =>
|
||||
logNav(
|
||||
"footer",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
amplitudeLogNavigation("footer", e.currentTarget.getAttribute("href"))
|
||||
}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
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";
|
||||
import { logNav } from "../..";
|
||||
|
||||
const LinkElement = ({ name, href, onClick }) => {
|
||||
const { asPath } = useRouter();
|
||||
@@ -23,9 +23,8 @@ const LinkElement = ({ name, href, onClick }) => {
|
||||
}
|
||||
)}
|
||||
onClick={(e) => {
|
||||
logNav(
|
||||
amplitudeLogNavigation(
|
||||
"header",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
);
|
||||
onClick();
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { MagnifyingGlassIcon } from "@navikt/aksel-icons";
|
||||
import { Button } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import Logo from "components/assets/Logo";
|
||||
import { Hamburger } from "components/layout/header/Hamburger";
|
||||
import dynamic from "next/dynamic";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { logNav } from "../..";
|
||||
import { Button } from "@navikt/ds-react";
|
||||
import dynamic from "next/dynamic";
|
||||
import { MagnifyingGlassIcon } from "@navikt/aksel-icons";
|
||||
|
||||
export const GlobalSearch = dynamic(() => import("./search"), {
|
||||
loading: () => (
|
||||
@@ -46,11 +46,7 @@ const LinkElement = ({ name, href, prefetch = undefined }) => {
|
||||
}
|
||||
)}
|
||||
onClick={(e) =>
|
||||
logNav(
|
||||
"header",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
amplitudeLogNavigation("header", e.currentTarget.getAttribute("href"))
|
||||
}
|
||||
>
|
||||
{name}
|
||||
@@ -87,9 +83,8 @@ export const Header = ({
|
||||
href="/"
|
||||
passHref
|
||||
onClick={(e) =>
|
||||
logNav(
|
||||
amplitudeLogNavigation(
|
||||
"header",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { amplitude, AmplitudeEvents } from "@/logging";
|
||||
import { allArticleDocuments } from "@/sanity/config";
|
||||
import { SearchResultsT } from "@/types";
|
||||
import { debounce } from "@navikt/ds-react";
|
||||
import { useMemo, useState } from "react";
|
||||
import useSWRImmutable from "swr/immutable";
|
||||
import { createSearchResult, formatResults, fuseSearch } from "../utils";
|
||||
import { debounce } from "@navikt/ds-react";
|
||||
import { logSearch } from "@/utils";
|
||||
|
||||
export const useSearch = () => {
|
||||
const [fuseResults, setFuseResults] = useState<SearchResultsT>(null);
|
||||
@@ -35,7 +35,7 @@ export const useSearch = () => {
|
||||
...createSearchResult(formatedResults, rawResults),
|
||||
query: value,
|
||||
});
|
||||
logSearch({
|
||||
amplitude.track(AmplitudeEvents.søk, {
|
||||
type: "standard",
|
||||
searchedFromUrl: window.location.pathname,
|
||||
query: value,
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import { logSearch } from "@/utils";
|
||||
import { AmplitudeEvents, amplitude } from "@/logging";
|
||||
import { createContext, useCallback, useContext } from "react";
|
||||
import { useSearch } from "../hooks";
|
||||
import { SearchContext } from "./SearchProvider";
|
||||
@@ -32,7 +32,7 @@ export const SearchLoggingProvider = ({
|
||||
accuracy: (100 - index / context?.results?.totalHits).toFixed(0),
|
||||
topResult: index <= context?.results?.topResults?.length,
|
||||
};
|
||||
logSearch(data);
|
||||
amplitude.track(AmplitudeEvents.søk, data);
|
||||
},
|
||||
[
|
||||
query,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { AkselSidebarT } from "@/types";
|
||||
import { logNav } from "@/utils";
|
||||
import {
|
||||
ChevronDownIcon,
|
||||
SparklesIcon,
|
||||
@@ -15,22 +15,19 @@ import { useSection } from "./useSection";
|
||||
|
||||
const NavItem = ({
|
||||
link,
|
||||
asPath,
|
||||
}: {
|
||||
link: { heading: string; slug: string; kategori: string; tag?: string };
|
||||
asPath: string;
|
||||
}) => {
|
||||
const isActive = asPath === `/${link.slug}`;
|
||||
const { asPath } = useRouter();
|
||||
const isActive = asPath.split("#")[0] === `/${link.slug}`;
|
||||
|
||||
return (
|
||||
<li>
|
||||
<Link
|
||||
aria-current={isActive ? "page" : undefined}
|
||||
href={`/${link.slug}`}
|
||||
onClick={(e) => {
|
||||
logNav(
|
||||
"meny",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
);
|
||||
amplitudeLogNavigation("meny", e.currentTarget.getAttribute("href"));
|
||||
}}
|
||||
className={cl(
|
||||
"hover:text-deepblue-800 focus-visible:shadow-focus text-medium pr-05 relative flex overflow-hidden py-1 pl-4 leading-snug before:rounded-full hover:before:transition-colors focus:outline-none focus-visible:z-10 focus-visible:rounded-sm",
|
||||
@@ -81,7 +78,6 @@ const Dropdown = ({
|
||||
links: AkselSidebarT;
|
||||
}) => {
|
||||
const [open, setOpen] = useState(true);
|
||||
const { asPath } = useRouter();
|
||||
|
||||
return (
|
||||
<li className="peer w-full peer-data-[open=true]:mt-6" data-open={open}>
|
||||
@@ -107,7 +103,7 @@ const Dropdown = ({
|
||||
|
||||
<ul hidden={!open} className="pl-2">
|
||||
{links.map((z) => (
|
||||
<NavItem link={z} key={z?.heading} asPath={asPath} />
|
||||
<NavItem link={z} key={z?.heading} />
|
||||
))}
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Heading } from "@navikt/ds-react";
|
||||
import Nextlink from "next/link";
|
||||
import cl from "clsx";
|
||||
import Image from "next/legacy/image";
|
||||
import { StatusTag } from "components/website-modules/StatusTag";
|
||||
import { ArticleListT } from "@/types";
|
||||
import { urlFor } from "@/sanity/interface";
|
||||
import { ArticleListT } from "@/types";
|
||||
import { Heading } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import { StatusTag } from "components/website-modules/StatusTag";
|
||||
import Image from "next/legacy/image";
|
||||
import Nextlink from "next/link";
|
||||
|
||||
const ComponentOverview = ({ node }: { node: ArticleListT }) => {
|
||||
if (!node || node.length === 0) {
|
||||
@@ -26,6 +26,16 @@ const ComponentOverview = ({ node }: { node: ArticleListT }) => {
|
||||
} else if (b?.status?.tag === "deprecated") {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (a.sidebarindex !== null || b.sidebarindex !== null) {
|
||||
if (a.sidebarindex !== null && b.sidebarindex !== null) {
|
||||
return a.sidebarindex - b.sidebarindex;
|
||||
} else if (a.sidebarindex !== null) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return a?.heading?.localeCompare(b?.heading);
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import { AkselTheme, getKey } from "@/sb-util";
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import Tabell from "./Tabell";
|
||||
|
||||
const meta = {
|
||||
title: "Sanity-modules/Tabell",
|
||||
component: Tabell,
|
||||
tags: ["autodocs"],
|
||||
} satisfies Meta<typeof Tabell>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
const args = {
|
||||
node: {
|
||||
rows: [
|
||||
{
|
||||
_key: getKey(),
|
||||
cells: ["Tablehead 1", "Tablehead 2", "Tablehead 3"],
|
||||
},
|
||||
{
|
||||
_key: getKey(),
|
||||
cells: ["Cell 1", "Cell 2", "Cell 3"],
|
||||
},
|
||||
{
|
||||
_key: getKey(),
|
||||
cells: ["Cell 1", "Cell 2", "Cell 3"],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
export const Aksel: Story = {
|
||||
args,
|
||||
decorators: [AkselTheme],
|
||||
};
|
||||
|
||||
export const Designsystem: Story = {
|
||||
args,
|
||||
};
|
||||
@@ -1,5 +1,6 @@
|
||||
import { withErrorBoundary } from "@/error-boundary";
|
||||
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import {
|
||||
AkselGodPraksisDocT,
|
||||
ResolveContributorsSingleT,
|
||||
@@ -9,7 +10,7 @@ import {
|
||||
import { BodyShort, Detail, Heading } from "@navikt/ds-react";
|
||||
import { useFormatedDate } from "components/website-modules/utils/getDate";
|
||||
import NextLink from "next/link";
|
||||
import { abbrName, logNav } from "../..";
|
||||
import { abbrName } from "../..";
|
||||
|
||||
const ArtikkelCard = ({
|
||||
slug,
|
||||
@@ -42,9 +43,8 @@ const ArtikkelCard = ({
|
||||
passHref
|
||||
className="after:absolute after:inset-0 after:z-10 after:rounded-lg focus:outline-none"
|
||||
onClick={(e) =>
|
||||
logNav(
|
||||
amplitudeLogNavigation(
|
||||
"artikkel-kort",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { withErrorBoundary } from "@/error-boundary";
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { AkselBloggDocT, ResolveContributorsT, ResolveSlugT } from "@/types";
|
||||
import { getAuthors } from "@/utils";
|
||||
import { BodyLong, BodyShort, Heading, Link } from "@navikt/ds-react";
|
||||
import { useFormatedDate } from "components/website-modules/utils/getDate";
|
||||
import NextLink from "next/link";
|
||||
import { getAuthors, logNav } from "@/utils";
|
||||
|
||||
const BloggCard = ({
|
||||
blog,
|
||||
@@ -21,9 +22,8 @@ const BloggCard = ({
|
||||
<Link
|
||||
className="text-deepblue-500 underline hover:no-underline"
|
||||
onClick={(e) =>
|
||||
logNav(
|
||||
amplitudeLogNavigation(
|
||||
"blogg-card",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { withErrorBoundary } from "@/error-boundary";
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { urlFor } from "@/sanity/interface";
|
||||
import { AkselTemaT } from "@/types";
|
||||
import { logNav } from "@/utils";
|
||||
import { BodyShort } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import Image from "next/legacy/image";
|
||||
@@ -33,11 +33,7 @@ const GodPraksisCard = ({ node }: { node: AkselTemaT }) => {
|
||||
href={`/god-praksis/${node.slug.current}`}
|
||||
passHref
|
||||
onClick={(e) =>
|
||||
logNav(
|
||||
"card",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
amplitudeLogNavigation("card", e.currentTarget.getAttribute("href"))
|
||||
}
|
||||
className="navds-heading--medium text-deepblue-700 navds-heading mb-4 underline after:absolute after:inset-0 after:rounded-lg focus:outline-none group-hover:no-underline"
|
||||
>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { withErrorBoundary } from "@/error-boundary";
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { urlFor } from "@/sanity/interface";
|
||||
import { AkselTemaT } from "@/types";
|
||||
import { logNav } from "@/utils";
|
||||
import Image from "next/legacy/image";
|
||||
import NextLink from "next/link";
|
||||
|
||||
@@ -26,11 +26,7 @@ const GodPraksisCardSimple = ({ node }: { node: Partial<AkselTemaT> }) => {
|
||||
href={`/god-praksis/${node.slug.current}`}
|
||||
passHref
|
||||
onClick={(e) =>
|
||||
logNav(
|
||||
"card",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
amplitudeLogNavigation("card", e.currentTarget.getAttribute("href"))
|
||||
}
|
||||
className="navds-heading--small navds-link text-deepblue-700 navds-heading flex-wrap break-all no-underline hover:underline focus:outline-none"
|
||||
>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { withErrorBoundary } from "@/error-boundary";
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { SanityBlockContent } from "@/sanity-block";
|
||||
import { InnholdsKortPrinsipperT } from "@/types";
|
||||
import { logNav } from "@/utils";
|
||||
import { Heading } from "@navikt/ds-react";
|
||||
import NextLink from "next/link";
|
||||
|
||||
@@ -23,9 +23,9 @@ const InnholdsKort = ({ node }: { node: InnholdsKortPrinsipperT }) => {
|
||||
href={`/${node?.lenke}`}
|
||||
passHref
|
||||
onClick={(e) =>
|
||||
logNav(
|
||||
amplitudeLogNavigation(
|
||||
"prinsipp-kort",
|
||||
window.location.pathname,
|
||||
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { logNav } from "@/components";
|
||||
import { withErrorBoundary } from "@/error-boundary";
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { RelatertInnholdT } from "@/types";
|
||||
import { NewspaperIcon } from "@navikt/aksel-icons";
|
||||
import { Heading, Link } from "@navikt/ds-react";
|
||||
@@ -21,8 +21,8 @@ const RelatertInnhold = ({ node }: { node: RelatertInnholdT }) => {
|
||||
as="p"
|
||||
spacing
|
||||
>
|
||||
<NewspaperIcon fontSize="1.5rem" title="Nyheter" aria-hidden />
|
||||
Relevante lenker
|
||||
<NewspaperIcon fontSize="1.5rem" title="Lenker" aria-hidden />
|
||||
{node.title || "Relevante lenker"}
|
||||
</Heading>
|
||||
<ul className="grid gap-3 pl-8">
|
||||
{node.lenker.map((x) => (
|
||||
@@ -31,9 +31,8 @@ const RelatertInnhold = ({ node }: { node: RelatertInnholdT }) => {
|
||||
as={NextLink}
|
||||
href={getHref(x)}
|
||||
onClick={(e) =>
|
||||
logNav(
|
||||
amplitudeLogNavigation(
|
||||
"relatert-innhold",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ export const CodeSandbox = ({ code }: { code: string }) => {
|
||||
} as any,
|
||||
isBinary: false,
|
||||
},
|
||||
"App.js": {
|
||||
"App.tsx": {
|
||||
content: getCode(code),
|
||||
isBinary: false,
|
||||
},
|
||||
@@ -54,7 +54,7 @@ export const CodeSandbox = ({ code }: { code: string }) => {
|
||||
className="h-8"
|
||||
>
|
||||
<input type="hidden" name="parameters" value={parameters} />
|
||||
<input type="hidden" name="query" value="module=App.js" />
|
||||
<input type="hidden" name="query" value="module=App.tsx" />
|
||||
<Button
|
||||
variant="tertiary-neutral"
|
||||
size="small"
|
||||
|
||||
@@ -30,7 +30,7 @@ const ComponentExamples = ({ node }: { node: CodeExamplesT }) => {
|
||||
) as HTMLIFrameElement;
|
||||
const exampleIframeDOM = exampleIframe?.contentDocument;
|
||||
const exampleWrapper = exampleIframeDOM?.getElementById("ds-example");
|
||||
if (exampleWrapper) {
|
||||
if (exampleWrapper && exampleWrapper.offsetHeight) {
|
||||
const newHeight = iframePadding + exampleWrapper.offsetHeight;
|
||||
clearInterval(waitForExampleContentToRender);
|
||||
setFrameState(newHeight < 300 ? 300 : newHeight);
|
||||
@@ -93,15 +93,12 @@ const ComponentExamples = ({ node }: { node: CodeExamplesT }) => {
|
||||
value={fil.navn}
|
||||
selected={active === fil.navn}
|
||||
id={`${node.dir.title.toLowerCase()}demo-${fil.navn}`}
|
||||
onClick={() => {
|
||||
setActiveExample(fil.navn);
|
||||
onClick={async () => {
|
||||
setUnloaded(true);
|
||||
router.replace(
|
||||
`#${node.dir.title.toLowerCase()}demo-${fil.navn}`,
|
||||
undefined,
|
||||
{
|
||||
shallow: true,
|
||||
}
|
||||
await router.replace(
|
||||
`${
|
||||
router.asPath.split("#")[0]
|
||||
}#${node.dir.title.toLowerCase()}demo-${fil.navn}`
|
||||
);
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { withErrorBoundary } from "@/error-boundary";
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { urlFor } from "@/sanity/interface";
|
||||
import { abbrName } from "@/utils";
|
||||
import { BodyShort, Detail, Heading } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import { logNav } from "components/website-modules/utils/amplitude";
|
||||
import { getImage } from "components/website-modules/utils/get-image";
|
||||
import { useFormatedDate } from "components/website-modules/utils/getDate";
|
||||
import NextImage from "next/legacy/image";
|
||||
@@ -112,9 +112,8 @@ const Card = ({
|
||||
passHref
|
||||
className="after:absolute after:inset-0 after:z-10 after:rounded-lg focus:outline-none"
|
||||
onClick={(e) =>
|
||||
logNav(
|
||||
amplitudeLogNavigation(
|
||||
"forside-masonary",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { urlFor } from "@/sanity/interface";
|
||||
import { getAuthors, logNav } from "@/utils";
|
||||
import { getAuthors } from "@/utils";
|
||||
import { BodyLong, BodyShort, Heading, Link } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import { getImage } from "components/website-modules/utils/get-image";
|
||||
@@ -79,9 +80,8 @@ export const Highlight = ({
|
||||
<Link
|
||||
as={NextLink}
|
||||
onClick={(e) =>
|
||||
logNav(
|
||||
amplitudeLogNavigation(
|
||||
"artikkel-kort",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { withErrorBoundary } from "@/error-boundary";
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import cl from "clsx";
|
||||
import Link from "next/link";
|
||||
import React from "react";
|
||||
import cl from "clsx";
|
||||
import { logNav } from "@/utils";
|
||||
|
||||
const AkselLink = ({
|
||||
href,
|
||||
@@ -26,11 +26,7 @@ const AkselLink = ({
|
||||
!inverted,
|
||||
})}
|
||||
onClick={(e) =>
|
||||
logNav(
|
||||
"link",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
amplitudeLogNavigation("link", e.currentTarget.getAttribute("href"))
|
||||
}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { logNav } from "components/website-modules/utils/amplitude";
|
||||
import Link from "next/link";
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import cl from "clsx";
|
||||
import Link from "next/link";
|
||||
|
||||
export const IntroCards = ({
|
||||
links,
|
||||
@@ -31,9 +31,8 @@ export const IntroCards = ({
|
||||
)}
|
||||
prefetch={false}
|
||||
onClick={(e) =>
|
||||
logNav(
|
||||
amplitudeLogNavigation(
|
||||
"intro-kort",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { AmplitudeEvents, amplitude } from "@/logging";
|
||||
import { FeedbackT, HelpfulArticleEnum } from "@/types";
|
||||
import { Button, Heading, Label, Textarea } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import { useRouter } from "next/router";
|
||||
import { useCallback, useContext, useEffect, useRef, useState } from "react";
|
||||
import { AmplitudeEvents, IdContext, logAmplitudeEvent } from "../utils";
|
||||
import { IdContext } from "../utils";
|
||||
import styles from "./feedback.module.css";
|
||||
|
||||
const Feedback = ({
|
||||
@@ -55,7 +56,7 @@ const Feedback = ({
|
||||
(completed: boolean) => {
|
||||
!hasLoggedFeedback &&
|
||||
activeState &&
|
||||
logAmplitudeEvent(AmplitudeEvents.feedbackinteraksjon, {
|
||||
amplitude.track(AmplitudeEvents.feedbackinteraksjon, {
|
||||
fra: asPath,
|
||||
vamd: activeState,
|
||||
completed,
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import { AmplitudeEvents, amplitude } from "@/logging";
|
||||
import * as Icons from "@navikt/aksel-icons";
|
||||
import meta from "@navikt/aksel-icons/metadata";
|
||||
import { Button, Heading } from "@navikt/ds-react";
|
||||
import Snippet from "components/sanity-modules/code/Snippet";
|
||||
import { SuggestionBlock } from "components/website-modules/suggestionblock";
|
||||
import {
|
||||
AmplitudeEvents,
|
||||
logAmplitudeEvent,
|
||||
} from "components/website-modules/utils/amplitude";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
@@ -52,7 +49,7 @@ export const IconSidebar = ({
|
||||
}, [name]);
|
||||
|
||||
const logDownload = (icon, format) => {
|
||||
logAmplitudeEvent(AmplitudeEvents.ikonnedlastning, {
|
||||
amplitude.track(AmplitudeEvents.ikonnedlastning, {
|
||||
icon,
|
||||
format,
|
||||
});
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { AmplitudeEvents, logAmplitudeEvent, logNav } from "@/utils";
|
||||
import { AmplitudeEvents, amplitude, amplitudeLogNavigation } from "@/logging";
|
||||
import { BrailleIcon, DownloadIcon, PackageIcon } from "@navikt/aksel-icons";
|
||||
import { Link as DsLink } from "@navikt/ds-react";
|
||||
|
||||
import { FigmaIcon, GithubIcon } from "components/assets";
|
||||
import NextLink from "next/link";
|
||||
|
||||
@@ -23,11 +22,7 @@ export const TitleLinks = () => (
|
||||
<DsLink
|
||||
className="text-text-default no-underline hover:underline"
|
||||
onClick={(e) =>
|
||||
logNav(
|
||||
"link",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
amplitudeLogNavigation("link", e.currentTarget.getAttribute("href"))
|
||||
}
|
||||
>
|
||||
<FigmaIcon className="ml-1" /> <span className="">Figma</span>
|
||||
@@ -41,7 +36,7 @@ export const TitleLinks = () => (
|
||||
href="https://cdn.nav.no/aksel/icons/zip/aksel-icons.zip"
|
||||
download="Ikonpakke"
|
||||
onClick={() => {
|
||||
logAmplitudeEvent(AmplitudeEvents.ikonnedlastning, {
|
||||
amplitude.track(AmplitudeEvents.ikonnedlastning, {
|
||||
icon: "Ikonpakke",
|
||||
format: "zip",
|
||||
});
|
||||
@@ -60,11 +55,7 @@ export const TitleLinks = () => (
|
||||
<DsLink
|
||||
className="text-text-default no-underline hover:underline"
|
||||
onClick={(e) =>
|
||||
logNav(
|
||||
"link",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
amplitudeLogNavigation("link", e.currentTarget.getAttribute("href"))
|
||||
}
|
||||
>
|
||||
<PackageIcon className="text-2xl" aria-hidden /> Installer med NPM
|
||||
@@ -81,11 +72,7 @@ export const TitleLinks = () => (
|
||||
<DsLink
|
||||
className="text-text-default no-underline hover:underline"
|
||||
onClick={(e) =>
|
||||
logNav(
|
||||
"link",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
amplitudeLogNavigation("link", e.currentTarget.getAttribute("href"))
|
||||
}
|
||||
>
|
||||
<GithubIcon className="ml-[3px] h-[18px] w-[18px]" />{" "}
|
||||
@@ -103,11 +90,7 @@ export const TitleLinks = () => (
|
||||
<DsLink
|
||||
className="text-text-default no-underline hover:underline"
|
||||
onClick={(e) =>
|
||||
logNav(
|
||||
"link",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
amplitudeLogNavigation("link", e.currentTarget.getAttribute("href"))
|
||||
}
|
||||
>
|
||||
<BrailleIcon aria-hidden className="text-2xl" />{" "}
|
||||
|
||||
@@ -5,15 +5,13 @@ import { useToc } from "components/website-modules/toc/useToc";
|
||||
import * as React from "react";
|
||||
|
||||
export function TableOfContents({
|
||||
changedState,
|
||||
hideToc = true,
|
||||
aksel = false,
|
||||
}: {
|
||||
changedState: any;
|
||||
hideToc?: boolean;
|
||||
aksel?: boolean;
|
||||
}) {
|
||||
const { toc, activeId, activeSubId } = useToc(changedState);
|
||||
const { toc, activeId, activeSubId } = useToc();
|
||||
|
||||
const handleFocus = (id: string) => {
|
||||
const element = document.getElementById(id);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/* eslint-disable react-hooks/rules-of-hooks */
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import TOC from "./TOCv2";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
const meta = {
|
||||
title: "Website-modules/TOCv2",
|
||||
@@ -14,11 +12,6 @@ type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Designsystemet: Story = {
|
||||
render: () => {
|
||||
const [render, setRender] = useState<boolean>(false);
|
||||
useEffect(() => {
|
||||
setRender(true);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex justify-between">
|
||||
<main className="grid gap-32 last-of-type:mb-[90vh]">
|
||||
@@ -35,7 +28,7 @@ export const Designsystemet: Story = {
|
||||
<h3 id="Z3">Heading Z3</h3>
|
||||
<h3 id="Z4">Heading Z4</h3>
|
||||
</main>
|
||||
<TOC changedState={render} />
|
||||
<TOC />
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -4,8 +4,8 @@ import cl from "clsx";
|
||||
import { useToc } from "components/website-modules/toc/useToc";
|
||||
import * as React from "react";
|
||||
|
||||
export function TableOfContentsv2({ changedState }: { changedState: any }) {
|
||||
const { toc, activeId, activeSubId } = useToc(changedState);
|
||||
export function TableOfContentsv2() {
|
||||
const { toc, activeId, activeSubId } = useToc();
|
||||
|
||||
const handleFocus = (id: string) => {
|
||||
const element = document.getElementById(id);
|
||||
@@ -47,7 +47,7 @@ export function TableOfContentsv2({ changedState }: { changedState: any }) {
|
||||
as="li"
|
||||
truncate
|
||||
size="small"
|
||||
className={cl("animate-fadeIn relative py-1 ", {
|
||||
className={cl("animate-toc relative py-1 ", {
|
||||
"font-semibold": link.id === activeId,
|
||||
})}
|
||||
>
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { useClientLayoutEffect } from "@navikt/ds-react";
|
||||
import throttle from "lodash/throttle";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export const useToc = ({ changedState }: { changedState: any }) => {
|
||||
export const useToc = () => {
|
||||
const [toc, setToc] = useState<
|
||||
{ heading: string; id: string; lvl3: { heading: string; id: string }[] }[]
|
||||
>([]);
|
||||
const router = useRouter();
|
||||
|
||||
const [activeId, setActiveId] = useState(null);
|
||||
const [activeSubId, setActiveSubId] = useState(null);
|
||||
@@ -57,7 +59,7 @@ export const useToc = ({ changedState }: { changedState: any }) => {
|
||||
}, 150);
|
||||
|
||||
return () => clearTimeout(time);
|
||||
}, [changedState]);
|
||||
}, [router.asPath]);
|
||||
|
||||
useEffect(() => {
|
||||
const validPick = (el: HTMLElement) => {
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
import { SearchLogT } from "@/types";
|
||||
import getConfig from "next/config";
|
||||
import { Router } from "next/router";
|
||||
import { useCallback, useEffect } from "react";
|
||||
import { track, init } from "@amplitude/analytics-browser";
|
||||
const { publicRuntimeConfig } = getConfig();
|
||||
|
||||
export enum AmplitudeEvents {
|
||||
"sidevisning" = "sidevisning",
|
||||
"navigasjon" = "navigasjon",
|
||||
"notfound" = "notfound",
|
||||
"error" = "error",
|
||||
"ikonklikk" = "ikonklikk",
|
||||
"ikonsok" = "ikonsok",
|
||||
"fargeklikk" = "fargeklikk",
|
||||
"ikonnedlastning" = "ikonnedlastning",
|
||||
"feedbackinteraksjon" = "feedbackinteraksjon",
|
||||
"scroll" = "scroll",
|
||||
"søk" = "søk",
|
||||
}
|
||||
|
||||
export const initAmplitude = () => {
|
||||
if (!(typeof window === "undefined")) {
|
||||
init("1a9a84a5e557ac9635a250bc27d75030", undefined, {
|
||||
useBatch: true,
|
||||
serverUrl: "https://amplitude.nav.no/collect",
|
||||
defaultTracking: {
|
||||
attribution: false,
|
||||
},
|
||||
ingestionMetadata: { sourceName: window.location.toString() },
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const logSearch = (data: SearchLogT) => {
|
||||
logAmplitudeEvent(AmplitudeEvents.søk, {
|
||||
...data,
|
||||
});
|
||||
};
|
||||
|
||||
const logPageView = (s: string, data: any = {}, firstLoad?: boolean) => {
|
||||
logAmplitudeEvent(AmplitudeEvents.sidevisning, {
|
||||
side: s,
|
||||
firstLoad: !!firstLoad,
|
||||
...data,
|
||||
});
|
||||
};
|
||||
|
||||
export const logNav = (kilde: string, fra: string, til: string) => {
|
||||
logAmplitudeEvent(AmplitudeEvents.navigasjon, {
|
||||
kilde,
|
||||
fra,
|
||||
til,
|
||||
});
|
||||
};
|
||||
|
||||
const isPreview = () => !!document.getElementById("exit-preview-id");
|
||||
const isProdUrl = () => window.location.host === "aksel.nav.no";
|
||||
|
||||
const isDevelopment = process.env.NODE_ENV === "development";
|
||||
const isTest = publicRuntimeConfig?.NEXT_PUBLIC_TEST !== undefined;
|
||||
|
||||
const isProduction = () => {
|
||||
return !(isDevelopment || isTest || isPreview()) && isProdUrl();
|
||||
};
|
||||
|
||||
export function logAmplitudeEvent(eventName: string, data?: any): Promise<any> {
|
||||
return new Promise(function (resolve: any) {
|
||||
const eventData = data ? { ...data } : {};
|
||||
if (isProduction()) {
|
||||
track(eventName, eventData, resolve);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export const usePageView = (router: Router, pageProps: any) => {
|
||||
const logView = useCallback(
|
||||
(e, first = false) => {
|
||||
const data = {};
|
||||
try {
|
||||
if (pageProps?.page && pageProps.page?._type === "aksel_artikkel") {
|
||||
const tema = pageProps.page.tema.map((x) => x?.slug?.current) ?? null;
|
||||
if (tema && tema.length > 0) {
|
||||
data["tema"] = tema;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
isDevelopment && console.error(error);
|
||||
}
|
||||
/* first-prop might be an object */
|
||||
logPageView(
|
||||
e,
|
||||
{
|
||||
...data,
|
||||
...(pageProps?.title && pageProps?.title.length > 0
|
||||
? { sidetittel: pageProps.title }
|
||||
: {}),
|
||||
},
|
||||
first === true
|
||||
);
|
||||
},
|
||||
[pageProps]
|
||||
);
|
||||
|
||||
const logScroll = useCallback((highestPercent: number) => {
|
||||
highestPercent > 100 && (highestPercent = 100);
|
||||
if (
|
||||
document === undefined ||
|
||||
window?.location?.pathname?.startsWith?.("/eksempler")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNaN(highestPercent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
logAmplitudeEvent(AmplitudeEvents.scroll, {
|
||||
side: window.location.pathname,
|
||||
prosent: highestPercent,
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
let highestPercent = 0;
|
||||
let timeoutId = null;
|
||||
const footer = document.querySelector("#aksel-footer") as HTMLElement;
|
||||
|
||||
//get highest scroll percent
|
||||
function scrollListener() {
|
||||
timeoutId = setTimeout(() => {
|
||||
const currentPercent = Math.round(
|
||||
(window.scrollY /
|
||||
(document.body.scrollHeight -
|
||||
window.innerHeight -
|
||||
(footer ? footer.offsetHeight : 0))) *
|
||||
100
|
||||
);
|
||||
if (currentPercent > highestPercent) {
|
||||
highestPercent = currentPercent;
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
window.addEventListener("scroll", scrollListener);
|
||||
|
||||
router.events.on("routeChangeComplete", logView);
|
||||
router.events.on("routeChangeStart", logScroll);
|
||||
window.onload = () => logView(window.location.pathname, true);
|
||||
|
||||
return () => {
|
||||
router.events.off("routeChangeComplete", logView);
|
||||
router.events.off("routeChangeStart", logScroll);
|
||||
window.removeEventListener("scroll", scrollListener);
|
||||
};
|
||||
}, [router.events, logView, logScroll]);
|
||||
};
|
||||
@@ -1,10 +1,9 @@
|
||||
import { AkselBloggDocT, ResolveContributorsT, ResolveSlugT } from "@/types";
|
||||
|
||||
export * from "./util";
|
||||
export * from "./amplitude";
|
||||
export * from "./hooks";
|
||||
export * from "./contexts";
|
||||
export * from "./date-string";
|
||||
export * from "./hooks";
|
||||
export * from "./util";
|
||||
|
||||
export const isNew = (date: string) => {
|
||||
const date1 = new Date(date);
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { AmplitudeEvents } from "./events";
|
||||
import { amplitude } from "./useAmplitude";
|
||||
|
||||
/**
|
||||
* Preset for logging navigation-events
|
||||
* @param src Component/Elements to keep track of
|
||||
* @param to Destination URL
|
||||
*/
|
||||
export const amplitudeLogNavigation = (src: string, to: string) =>
|
||||
amplitude.track(AmplitudeEvents.navigasjon, {
|
||||
src,
|
||||
to,
|
||||
from: window.location.pathname,
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
export enum AmplitudeEvents {
|
||||
"navigasjon" = "navigasjon",
|
||||
"notfound" = "notfound",
|
||||
"error" = "error",
|
||||
"ikonnedlastning" = "ikonnedlastning",
|
||||
"feedbackinteraksjon" = "feedbackinteraksjon",
|
||||
"søk" = "søk",
|
||||
"link" = "link",
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export { amplitudeLogNavigation } from "./event-tracking";
|
||||
export { AmplitudeEvents } from "./events";
|
||||
export { amplitude } from "./useAmplitude";
|
||||
@@ -0,0 +1,95 @@
|
||||
import type { Types } from "@amplitude/analytics-browser";
|
||||
|
||||
import { useEffect } from "react";
|
||||
|
||||
const batchedEvents = [];
|
||||
|
||||
export let amplitude: Partial<Pick<Types.BrowserClient, "init" | "track">> = {
|
||||
track: (...eventsData) => {
|
||||
batchedEvents.push(eventsData);
|
||||
return {
|
||||
promise: new Promise<Types.Result>((resolve) =>
|
||||
resolve({
|
||||
event: { event_type: "MockEvent" },
|
||||
code: 200,
|
||||
message: "Success: pre-batched amplitude-tracking",
|
||||
})
|
||||
),
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
const AMPLITUDE_PUBLIC_API_KEY = "1a9a84a5e557ac9635a250bc27d75030";
|
||||
|
||||
/**
|
||||
* https://www.docs.developers.amplitude.com/data/sdks/browser-2/#tracking-default-events
|
||||
* https://javascript.plainenglish.io/how-to-implement-amplitude-in-next-js-a-3-step-guide-6803c44ca862
|
||||
*/
|
||||
const useAmplitudeInit = () => {
|
||||
useEffect(() => {
|
||||
const isProdUrl = () => window.location.host === "aksel.nav.no";
|
||||
const isExample = () => window.location.pathname.includes("eksempler/");
|
||||
const isPreview = () => !!document.getElementById("exit-preview-id");
|
||||
|
||||
const initAmplitude = async () => {
|
||||
if (isExample()) {
|
||||
return;
|
||||
} else if (!isProdUrl()) {
|
||||
mockAmplitude();
|
||||
return;
|
||||
}
|
||||
|
||||
amplitude = await import("@amplitude/analytics-browser");
|
||||
amplitude
|
||||
.init(AMPLITUDE_PUBLIC_API_KEY, undefined, {
|
||||
useBatch: true,
|
||||
serverUrl: "https://amplitude.nav.no/collect",
|
||||
defaultTracking: {
|
||||
pageViews: {
|
||||
trackHistoryChanges: "pathOnly",
|
||||
trackOn: () => {
|
||||
return !isPreview();
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
.promise.then(() =>
|
||||
batchedEvents
|
||||
.splice(0, batchedEvents.length)
|
||||
.forEach(([event, eventData]) => amplitude.track(event, eventData))
|
||||
)
|
||||
.catch(async () => {
|
||||
const { logger } = await import("logger");
|
||||
logger.error("Failed logging batched events");
|
||||
});
|
||||
};
|
||||
initAmplitude();
|
||||
}, []);
|
||||
};
|
||||
|
||||
/**
|
||||
* Allows logging events to console in dev
|
||||
*/
|
||||
function mockAmplitude() {
|
||||
amplitude = {
|
||||
track: (
|
||||
eventInput: Types.BaseEvent | string,
|
||||
eventProperties?: Record<string, any>
|
||||
) => {
|
||||
console.group("Mocked amplitude-event");
|
||||
console.table({ eventInput, ...eventProperties });
|
||||
console.groupEnd();
|
||||
return {
|
||||
promise: new Promise<Types.Result>((resolve) =>
|
||||
resolve({
|
||||
event: { event_type: "MockEvent" },
|
||||
code: 200,
|
||||
message: "Success: mocked amplitude-tracking",
|
||||
})
|
||||
),
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default useAmplitudeInit;
|
||||
@@ -1,19 +1,5 @@
|
||||
import { useEffect } from "react";
|
||||
|
||||
const environment = process.env.NODE_ENV;
|
||||
|
||||
export const isProduction = (): boolean => {
|
||||
if (typeof window !== "undefined") {
|
||||
const url =
|
||||
window && window.location && window.location.href
|
||||
? window.location.href
|
||||
: "";
|
||||
return environment === "production" && /aksel.nav.no/.test(url);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// https://stackoverflow.com/questions/38588346/anchor-a-tags-not-working-in-chrome-when-using/38588927#38588927
|
||||
// https://github.com/vercel/next.js/discussions/13134
|
||||
export function useScrollToHashOnPageLoad(): void {
|
||||
|
||||
@@ -13,7 +13,7 @@ const ContentSecurityPolicy = `
|
||||
img-src 'self' cdn.sanity.io https://avatars.githubusercontent.com data: ${cdnUrl} ${hotjarUrl};
|
||||
script-src 'self' ${cdnUrl} ${hotjarUrl} https://in2.taskanalytics.com/tm.js 'nonce-4e1aa203a32e' 'unsafe-eval';
|
||||
style-src 'self' ${cdnUrl} ${hotjarUrl} 'unsafe-inline';
|
||||
connect-src 'self' ${cdnUrl} ${hotjarUrl} https://raw.githubusercontent.com/navikt/ https://hnbe3yhs.apicdn.sanity.io wss://hnbe3yhs.api.sanity.io cdn.sanity.io *.api.sanity.io https://amplitude.nav.no https://in2.taskanalytics.com/03346;
|
||||
connect-src 'self' ${cdnUrl} ${hotjarUrl} https://*.hotjar.io wss://*.hotjar.com https://raw.githubusercontent.com/navikt/ https://hnbe3yhs.apicdn.sanity.io wss://hnbe3yhs.api.sanity.io cdn.sanity.io *.api.sanity.io https://amplitude.nav.no https://in2.taskanalytics.com/03346;
|
||||
frame-ancestors 'self' localhost:3000;
|
||||
media-src 'self' ${cdnUrl} cdn.sanity.io;
|
||||
frame-src 'self' https://web.microsoftstream.com localhost:3000 https://aksel.ekstern.dev.nav.no;
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
"start": "cd .next/standalone/aksel.nav.no/website && PORT=3000 HOSTNAME=0.0.0.0 node server.js",
|
||||
"cp:assets": "cross-env cp -R public .next/standalone/aksel.nav.no/website/ && cross-env cp -R .next/static .next/standalone/aksel.nav.no/website/.next/static",
|
||||
"update:searchindex": "ts-node --project tsconfig.json ./scripts/create-index",
|
||||
"e2e": "yarn build && NEXT_PUBLIC_TEST=true yarn start-server-and-test start http://localhost:3000 playwright",
|
||||
"e2e:full": "yarn build && ts-node ./e2e/genUrls.ts && NEXT_PUBLIC_TEST=true FULL_TEST=true yarn start-server-and-test start http://localhost:3000 playwright",
|
||||
"e2e:ci": "NEXT_PUBLIC_TEST=true yarn start-server-and-test start http://localhost:3000 playwright",
|
||||
"e2e:ci-full": "ts-node ./e2e/genUrls.ts && NEXT_PUBLIC_TEST=true FULL_TEST=true yarn start-server-and-test start http://localhost:3000 playwright",
|
||||
"e2e": "yarn build && yarn start-server-and-test start http://localhost:3000 playwright",
|
||||
"e2e:full": "yarn build && ts-node ./e2e/genUrls.ts && FULL_TEST=true yarn start-server-and-test start http://localhost:3000 playwright",
|
||||
"e2e:ci": " yarn start-server-and-test start http://localhost:3000 playwright",
|
||||
"e2e:ci-full": "ts-node ./e2e/genUrls.ts && FULL_TEST=true yarn start-server-and-test start http://localhost:3000 playwright",
|
||||
"update:props": "ts-node --project tsconfig.tsnode.json ./scripts/update-props",
|
||||
"update:tokens": "ts-node --project tsconfig.tsnode.json ./scripts/update-tokens",
|
||||
"update:eksempler": "ts-node --project tsconfig.tsnode.json ./scripts/examples/update-sanity",
|
||||
@@ -29,7 +29,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@amplitude/analytics-browser": "^2.2.3",
|
||||
"@portabletext/react": "^3.0.7",
|
||||
"@portabletext/react": "^3.0.11",
|
||||
"@sanity/client": "^6.6.0",
|
||||
"@sanity/code-input": "4.1.1",
|
||||
"@sanity/color-input": "^3.1.0",
|
||||
@@ -42,9 +42,9 @@
|
||||
"date-fns": "2.29.3",
|
||||
"fuse.js": "^6.6.2",
|
||||
"lodash": "^4.17.21",
|
||||
"next": "^13.5.0",
|
||||
"next-logger": "^3.0.2",
|
||||
"next-sanity": "^5.5.8",
|
||||
"next": "13.2.1",
|
||||
"next-logger": "3.0.2",
|
||||
"next-sanity": "5.5.8",
|
||||
"pino": "^8.14.1",
|
||||
"prism-react-renderer": "^2.0.0",
|
||||
"react": "^18.0.0",
|
||||
@@ -63,8 +63,8 @@
|
||||
"devDependencies": {
|
||||
"@axe-core/playwright": "^4.5.2",
|
||||
"@babel/core": "^7.19.0",
|
||||
"@next/bundle-analyzer": "^13.5.0",
|
||||
"@next/eslint-plugin-next": "^12.2.0",
|
||||
"@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",
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { AmplitudeEvents, logAmplitudeEvent } from "@/components";
|
||||
import { AmplitudeEvents, amplitude } from "@/logging";
|
||||
import { BodyLong, Heading, Link } from "@navikt/ds-react";
|
||||
import NextLink from "next/link";
|
||||
import { AkselCubeStatic } from "components/website-modules/cube";
|
||||
import NextLink from "next/link";
|
||||
import { useEffect } from "react";
|
||||
|
||||
function Page() {
|
||||
useEffect(() => {
|
||||
logAmplitudeEvent(AmplitudeEvents.notfound, {
|
||||
amplitude.track(AmplitudeEvents.notfound, {
|
||||
side: window.location.pathname,
|
||||
});
|
||||
}, []);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { AmplitudeEvents, logAmplitudeEvent } from "@/components";
|
||||
import { AmplitudeEvents, amplitude } from "@/logging";
|
||||
import { BodyLong, Heading } from "@navikt/ds-react";
|
||||
import { AkselCubeStatic } from "components/website-modules/cube";
|
||||
import { useEffect } from "react";
|
||||
|
||||
function Page() {
|
||||
useEffect(() => {
|
||||
logAmplitudeEvent(AmplitudeEvents.error, {
|
||||
amplitude.track(AmplitudeEvents.error, {
|
||||
side: window.location.pathname,
|
||||
});
|
||||
}, []);
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import { BaseSEO } from "components/website-modules/seo/BaseSEO";
|
||||
import {
|
||||
initAmplitude,
|
||||
usePageView,
|
||||
} from "components/website-modules/utils/amplitude";
|
||||
import useAmplitudeInit from "components/website-modules/utils/logging/useAmplitude";
|
||||
import { useScrollToHashOnPageLoad } from "components/website-modules/utils/util";
|
||||
import { AppProps } from "next/app";
|
||||
import { useEffect } from "react";
|
||||
@@ -10,11 +7,9 @@ import { hotjar } from "react-hotjar";
|
||||
import { IdContext } from "../components/website-modules/utils/contexts/id-context";
|
||||
import "../styles/index.css";
|
||||
|
||||
initAmplitude();
|
||||
|
||||
function App({ Component, pageProps, router }: AppProps) {
|
||||
useScrollToHashOnPageLoad();
|
||||
usePageView(router, pageProps);
|
||||
useAmplitudeInit();
|
||||
|
||||
useEffect(() => {
|
||||
window.location.host === "design.nav.no" &&
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This is imported to allow the Output File Tracing feature of Next.js to work correctly with the log patcher
|
||||
import "next-logger";
|
||||
|
||||
import { Html, Head, Main, NextScript } from "next/document";
|
||||
import { Head, Html, Main, NextScript } from "next/document";
|
||||
|
||||
export default function Document() {
|
||||
return (
|
||||
@@ -15,12 +15,6 @@ export default function Document() {
|
||||
type="font/woff2"
|
||||
crossOrigin="anonymous"
|
||||
/>
|
||||
<link
|
||||
rel="preload"
|
||||
href="/searchindex.json"
|
||||
as="fetch"
|
||||
crossOrigin="anonymous"
|
||||
/>
|
||||
</Head>
|
||||
<body data-theme="light" className="aksel antialiased">
|
||||
<Main />
|
||||
|
||||
@@ -1,35 +1,27 @@
|
||||
import { DatePicker, useDatepicker, Button, Modal } from "@navikt/ds-react";
|
||||
import { DatePicker, Modal } from "@navikt/ds-react";
|
||||
import { withDsExample } from "components/website-modules/examples/withDsExample";
|
||||
import { useRef } from "react";
|
||||
import format from "date-fns/format";
|
||||
import nbLocale from "date-fns/locale/nb";
|
||||
import { useState } from "react";
|
||||
|
||||
const Example = () => {
|
||||
const ref = useRef<HTMLDialogElement>(null);
|
||||
|
||||
const { datepickerProps, inputProps, selectedDay } = useDatepicker({
|
||||
fromDate: new Date("Aug 23 2019"),
|
||||
onDateChange: console.log,
|
||||
});
|
||||
const [date, setDate] = useState(null);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button onClick={() => ref.current?.showModal()}>Åpne modal</Button>
|
||||
|
||||
<Modal ref={ref} header={{ heading: "Heading" }}>
|
||||
<Modal.Body>
|
||||
<div className="min-h-96 min-w-96 max-w-full">
|
||||
<DatePicker {...datepickerProps}>
|
||||
<DatePicker.Input {...inputProps} label="Velg dato" />
|
||||
</DatePicker>
|
||||
<div className="pt-4">
|
||||
{selectedDay &&
|
||||
format(selectedDay, "dd.MM.yyyy", { locale: nbLocale })}
|
||||
</div>
|
||||
<Modal open header={{ heading: "Heading" }}>
|
||||
<Modal.Body>
|
||||
<div className="min-h-96 min-w-96 max-w-full">
|
||||
<DatePicker.Standalone
|
||||
onSelect={setDate}
|
||||
fromDate={new Date("Aug 23 2019")}
|
||||
fixedWeeks
|
||||
/>
|
||||
<div className="pt-4">
|
||||
{date && format(date, "dd.MM.yyyy", { locale: nbLocale })}
|
||||
</div>
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
</>
|
||||
</div>
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -23,5 +23,5 @@ export const Demo = {
|
||||
};
|
||||
|
||||
export const args = {
|
||||
index: 1,
|
||||
index: 3,
|
||||
};
|
||||
@@ -26,5 +26,5 @@ export const Demo = {
|
||||
};
|
||||
|
||||
export const args = {
|
||||
index: 0,
|
||||
index: 1,
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Link } from "@navikt/ds-react";
|
||||
import { withDsExample } from "components/website-modules/examples/withDsExample";
|
||||
import NextLink from "next/link";
|
||||
|
||||
const Example = () => {
|
||||
return (
|
||||
<Link href="#" as={NextLink}>
|
||||
Lenke til ny side
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
export default withDsExample(Example);
|
||||
|
||||
/* Storybook story */
|
||||
export const Demo = {
|
||||
render: Example,
|
||||
};
|
||||
|
||||
export const args = {
|
||||
index: 5,
|
||||
};
|
||||
@@ -21,5 +21,5 @@ export const Demo = {
|
||||
};
|
||||
|
||||
export const args = {
|
||||
index: 0,
|
||||
index: 4,
|
||||
};
|
||||
@@ -25,5 +25,5 @@ export const Demo = {
|
||||
};
|
||||
|
||||
export const args = {
|
||||
index: 0,
|
||||
index: 2,
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
import { LinkPanel } from "@navikt/ds-react";
|
||||
import { withDsExample } from "components/website-modules/examples/withDsExample";
|
||||
import NextLink from "next/link";
|
||||
|
||||
const Example = () => {
|
||||
return (
|
||||
<LinkPanel href="#" border as={NextLink}>
|
||||
<LinkPanel.Title>Arbeidssøker eller permittert</LinkPanel.Title>
|
||||
</LinkPanel>
|
||||
);
|
||||
};
|
||||
|
||||
export default withDsExample(Example);
|
||||
|
||||
/* Storybook story */
|
||||
export const Demo = {
|
||||
render: Example,
|
||||
};
|
||||
|
||||
export const args = {
|
||||
index: 3,
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Button } from "@navikt/ds-react";
|
||||
import { withDsExample } from "components/website-modules/examples/withDsExample";
|
||||
|
||||
const Example = () => {
|
||||
return <Button loading>Lagre</Button>;
|
||||
};
|
||||
|
||||
export default withDsExample(Example);
|
||||
|
||||
export const args = {
|
||||
index: 5,
|
||||
};
|
||||
@@ -2,7 +2,7 @@ import { Loader } from "@navikt/ds-react";
|
||||
import { withDsExample } from "components/website-modules/examples/withDsExample";
|
||||
|
||||
const Example = () => {
|
||||
return <Loader size="3xlarge" title="venter..." variant="interaction" />;
|
||||
return <Loader size="3xlarge" title="Venter..." variant="interaction" />;
|
||||
};
|
||||
|
||||
export default withDsExample(Example);
|
||||
|
||||
@@ -2,10 +2,10 @@ import { Loader } from "@navikt/ds-react";
|
||||
import { withDsExample } from "components/website-modules/examples/withDsExample";
|
||||
|
||||
const Example = () => {
|
||||
return <Loader size="3xlarge" title="venter..." variant="inverted" />;
|
||||
return <Loader size="3xlarge" title="Venter..." variant="inverted" />;
|
||||
};
|
||||
|
||||
export default withDsExample(Example, { variant: "full" });
|
||||
export default withDsExample(Example, { variant: "inverted" });
|
||||
|
||||
export const args = {
|
||||
index: 2,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Loader } from "@navikt/ds-react";
|
||||
import { withDsExample } from "components/website-modules/examples/withDsExample";
|
||||
|
||||
const Example = () => {
|
||||
return <Loader size="3xlarge" title="venter..." />;
|
||||
return <Loader size="3xlarge" title="Venter..." />;
|
||||
};
|
||||
|
||||
export default withDsExample(Example);
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { Loader } from "@navikt/ds-react";
|
||||
import { HStack, Loader } from "@navikt/ds-react";
|
||||
import { withDsExample } from "components/website-modules/examples/withDsExample";
|
||||
|
||||
const Example = () => {
|
||||
return (
|
||||
<div className="grid place-items-center gap-4">
|
||||
<Loader size="3xlarge" title="venter..." />
|
||||
<Loader size="2xlarge" title="venter..." />
|
||||
<Loader size="xlarge" title="venter..." />
|
||||
<Loader size="large" title="venter..." />
|
||||
<Loader size="medium" title="venter..." />
|
||||
<Loader size="small" title="venter..." />
|
||||
<Loader size="xsmall" title="venter..." />
|
||||
</div>
|
||||
<HStack gap="18">
|
||||
<Loader size="3xlarge" title="Venter..." />
|
||||
<Loader size="2xlarge" title="Venter..." />
|
||||
<Loader size="xlarge" title="Venter..." />
|
||||
<Loader size="large" title="Venter..." />
|
||||
<Loader size="medium" title="Venter..." />
|
||||
<Loader size="small" title="Venter..." />
|
||||
<Loader size="xsmall" title="Venter..." />
|
||||
</HStack>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -2,13 +2,12 @@ import { Loader } from "@navikt/ds-react";
|
||||
import { withDsExample } from "components/website-modules/examples/withDsExample";
|
||||
|
||||
const Example = () => {
|
||||
return (
|
||||
<Loader size="3xlarge" title="venter..." variant="inverted" transparent />
|
||||
);
|
||||
return <Loader size="3xlarge" title="Venter..." transparent />;
|
||||
};
|
||||
|
||||
export default withDsExample(Example, { variant: "full" });
|
||||
export default withDsExample(Example);
|
||||
|
||||
export const args = {
|
||||
index: 3,
|
||||
desc: "Prop-en 'transparent' fjerner bakgrunnselementet på Loader.",
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
import { BodyLong, Button, Modal } from "@navikt/ds-react";
|
||||
import { withDsExample } from "components/website-modules/examples/withDsExample";
|
||||
import { useRef } from "react";
|
||||
|
||||
const Example = () => {
|
||||
const ref = useRef<HTMLDialogElement>(null);
|
||||
|
||||
return (
|
||||
<div className="py-16">
|
||||
<Button onClick={() => ref.current?.showModal()}>Åpne modal</Button>
|
||||
|
||||
<Modal ref={ref} header={{ heading: "Overskrift" }} closeOnBackdropClick>
|
||||
<Modal.Body>
|
||||
<BodyLong>
|
||||
Culpa aliquip ut cupidatat laborum minim quis ex in aliqua. Qui
|
||||
incididunt dolor do ad ut. Incididunt eiusmod nostrud deserunt duis
|
||||
laborum. Proident aute culpa qui nostrud velit adipisicing minim.
|
||||
Consequat aliqua aute dolor do sit Lorem nisi mollit velit. Aliqua
|
||||
exercitation non minim minim pariatur sunt laborum ipsum.
|
||||
Exercitation nostrud est laborum magna non non aliqua qui esse.
|
||||
</BodyLong>
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default withDsExample(Example);
|
||||
|
||||
/* Storybook story */
|
||||
export const Demo = {
|
||||
render: Example,
|
||||
};
|
||||
|
||||
export const args = {
|
||||
index: 5,
|
||||
desc: "Husk at det er lett å klikke utenfor ved et uhell. Ikke bruk 'closeOnBackdropClick' hvis det kan føre til at brukeren mister data eller går glipp av viktig informasjon.",
|
||||
};
|
||||
@@ -5,11 +5,17 @@ import { useRef, useState } from "react";
|
||||
const Example = () => {
|
||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||
const [openState, setOpenState] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button ref={buttonRef} onClick={() => setOpenState(true)}>
|
||||
<Button
|
||||
ref={buttonRef}
|
||||
onClick={() => setOpenState(!openState)}
|
||||
aria-expanded={openState}
|
||||
>
|
||||
Åpne popover
|
||||
</Button>
|
||||
|
||||
<Popover
|
||||
open={openState}
|
||||
onClose={() => setOpenState(false)}
|
||||
|
||||
Loaded 100 of 133 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user