mirror of
https://github.com/navikt/aksel.git
synced 2026-10-13 09:12:03 +00:00
Compare commits
73
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12cca3e352 | ||
|
|
396bcfbb8a | ||
|
|
0a364b989a | ||
|
|
233cf0cb31 | ||
|
|
b3d1c8429a | ||
|
|
1b66630b08 | ||
|
|
a3640b4ad1 | ||
|
|
c9092c951e | ||
|
|
5761ee7213 | ||
|
|
6239d40d9c | ||
|
|
4081131e1a | ||
|
|
a0797cbf70 | ||
|
|
8f0c6948c3 | ||
|
|
9dd22c2201 | ||
|
|
47f174edee | ||
|
|
00ccebf826 | ||
|
|
ca3d011b54 | ||
|
|
da11faf790 | ||
|
|
41022fb3ab | ||
|
|
81a79de789 | ||
|
|
1d6e33799f | ||
|
|
3c9187ce50 | ||
|
|
87b4d45583 | ||
|
|
154eab1ec6 | ||
|
|
0ee4fc5a6d | ||
|
|
1bfb3acbdf | ||
|
|
8c0e121d66 | ||
|
|
0c86b6e6b3 | ||
|
|
23f077d0d9 | ||
|
|
2be6c7b629 | ||
|
|
dc63423efb | ||
|
|
223a328382 | ||
|
|
6450782d49 | ||
|
|
1c05a87aa0 | ||
|
|
286e8e7265 | ||
|
|
fea8356538 | ||
|
|
3017843435 | ||
|
|
5a8807cf30 | ||
|
|
ca7c15118f | ||
|
|
564df74c79 | ||
|
|
50bfca15e8 | ||
|
|
8d0c782903 | ||
|
|
b50c5c5b20 | ||
|
|
c13ae0ba42 | ||
|
|
db3598b763 | ||
|
|
bfb3d2fd04 | ||
|
|
9c9d69dc4a | ||
|
|
8fcc763ee0 | ||
|
|
70a202737f | ||
|
|
e91c4b5853 | ||
|
|
c4588ba1d2 | ||
|
|
759cf51851 | ||
|
|
4c5f810fdc | ||
|
|
ae142178ad | ||
|
|
74aefe9329 | ||
|
|
d774cda10f | ||
|
|
145489756d | ||
|
|
8df7514055 | ||
|
|
614767d5a2 | ||
|
|
fb23dbac85 | ||
|
|
51acc59fde | ||
|
|
a18e62ec95 | ||
|
|
9dc465dc76 | ||
|
|
ffd5023dd9 | ||
|
|
6ae42fccef | ||
|
|
3692c588af | ||
|
|
e2be70da9b | ||
|
|
dd4c90c24f | ||
|
|
c1615a5acd | ||
|
|
c6aef457de | ||
|
|
6f36724570 | ||
|
|
91b956d8c2 | ||
|
|
c9d70ebd1c |
No files matched your search
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"repository": "@nav/designsystem",
|
||||
"head": "updated-specify-tokens",
|
||||
"base": "master",
|
||||
"rules": [
|
||||
{
|
||||
"name": "Specify / Icons",
|
||||
"path": "@navikt/ds-icons/svg",
|
||||
"filter": {
|
||||
"types": ["vector"]
|
||||
},
|
||||
"parsers": [
|
||||
{
|
||||
"name": "pascalcasify",
|
||||
"options": {
|
||||
"keys": ["name"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "name-assets-files-by-pattern",
|
||||
"options": {
|
||||
"pattern": "{{name}}.{{format}}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Specify / Icons - metadata",
|
||||
"path": "@navikt/ds-icons/figma-api/metadata-specify.json",
|
||||
"filter": {
|
||||
"types": ["vector"]
|
||||
},
|
||||
"parsers": [
|
||||
{
|
||||
"name": "pascalcasify",
|
||||
"options": {
|
||||
"keys": ["name"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pick",
|
||||
"options": {
|
||||
"keys": [
|
||||
"name",
|
||||
"createdAt",
|
||||
"updatedAt",
|
||||
"meta.description",
|
||||
"meta.parentFrame",
|
||||
"meta.frame",
|
||||
"page"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Meta } from "@storybook/addon-docs/blocks";
|
||||
import { Meta } from "@storybook/addon-docs";
|
||||
|
||||
<Meta title="ds-react/Kom i gang" />
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import { Meta } from "@storybook/addon-docs";
|
||||
|
||||
<Meta title="ds-react/Roadmap" />
|
||||
|
||||
# Plan videre
|
||||
|
||||
Arbeidet med det nye pakke-oppsettet har nå foregått en stund og skulle egentlig vært
|
||||
lengre på vei en det er nå. Men arbeidet har på ingen måte stoppet opp! Vi jobber kontinuerlig med
|
||||
å finne bedre løsninger for å kunne bygge systemet opp fra bunnen av. Dette innegår da
|
||||
ny dokumentasjons-side bygd med Sanity, nye byggeblokker helt fra token-nivå og bedre sizing for eksterne/interne sider. Dette vil da forhåpentligvis la oss
|
||||
bygge mer robuste og fleksible løsninger for fremtiden.
|
||||
|
||||
(Rekkefølgen representer ikke faktisk tidsline eller prioritet)
|
||||
|
||||
## Tokens
|
||||
|
||||
Vi bygger opp `@navikt/ds-tokens` pakken som inneholder alle design-tokensene til designsystemet fra bunnen av.
|
||||
Dette vil gjøre styling og overriding av komponenter enklere da man kan bruke css-variabler.
|
||||
|
||||
## Intern / Ekstern sizing
|
||||
|
||||
Komponenter tilpasses og standariseres bedre for skillet mellom interne/eksterne flater.
|
||||
Løsning er ikke fast bestemt, men eksempel på dette er `size="s" -> 32px, size="m"-> 48px`.
|
||||
Dette vil da eksempelvis kunne være en standard som er gjennomgående for de fleste komponentene.
|
||||
|
||||
## Ny dokumentasjon-side
|
||||
|
||||
Vi bygger en ny side for å dokumentere systemet, og mer rundt utvikling/design i nav med "Verktøykassen"
|
||||
|
||||
## Migrere komponenter/styling fra nav-frontend-\* -> `@navikt/ds-css / @navikt/ds-react`
|
||||
|
||||
Dette arbeidet kommer sakte men sikkert på plass, men tar litt tid da mye må på plass først, da eksempelvis sizing og tokens.
|
||||
Noen komponenter vil ha oppdatert funksjonalitet, noen bare stilendringer, mens noen kan nesten brukes 1-1 fra nav-frontend-.
|
||||
|
||||
Note: Noen pakker vil ikke flyttes over fra nav-frontend og `deprecates` i praksis da. De pakkene som ikka tas over vil ikke bli deprecated på `npm`, slik at man kan fortsette å ta dem i bruk uten en sint terminal hver gang man kjører `yarn install`.
|
||||
|
||||
## Theming
|
||||
|
||||
Etterhvert når vi har nye react, css og token pakke på plass har vi et ønske om å kunne se på theming for
|
||||
eks darkmode.
|
||||
|
||||
## Vue, svelte, web-components etc...
|
||||
|
||||
Dette er noe vi ikke har på planene for tiden, men etterhvert som ting faller på plass så vil dette være
|
||||
noe vi kunne ta en titt på hvis vi ser at det trengs.
|
||||
|
||||
## Feature-flagging
|
||||
|
||||
Ideen om å ta i bruk feature-flagging er noe som virker veldig interessant og vil da se på muligheten for å kunne levere
|
||||
større endringe i feature-flags for testing, og da publisere under eks major-bump i faste intervaller. Dette vil da kunne
|
||||
gjøre det enklere for deg som consumer av pakkene å ha oversikt over endringer og hva som må migreres.
|
||||
|
||||
## Versjonering
|
||||
|
||||
To av de nye pakkene under `@navikt`, da `ds-css` og `ds-react` er nå versjonert under to store pakker med alle komponentene. I fremtiden vil vi se på å
|
||||
ha både samversjonering (alle pakker under en eks ds-react versjon) og induvduell verjsonering da eks ds-react/button har en egen versjon
|
||||
slik at man kan ha mer finkontroll over komponentbruk på siden sin.
|
||||
@@ -22,18 +22,11 @@
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.navds-accordion-menu-collapsable .navds-accordion-menu__list,
|
||||
.navds-accordion-menu-collapsable
|
||||
.navds-accordion-menu-collapsable
|
||||
.navds-accordion-menu-collapsable__button {
|
||||
font-weight: var(--navds-font-weight-regular);
|
||||
}
|
||||
|
||||
.navds-accordion-menu-item,
|
||||
.navds-accordion-menu-collapsable__button {
|
||||
display: flex;
|
||||
padding: var(--navds-spacing-3) var(--navds-spacing-4);
|
||||
line-height: 1.5rem; /* TODO: fix typography. */
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.navds-accordion-menu-collapsable__expand-icon {
|
||||
@@ -82,16 +75,16 @@
|
||||
.navds-accordion-menu-collapsable__button:focus {
|
||||
outline: 3px solid var(--navds-text-focus);
|
||||
outline-offset: -3px;
|
||||
color: var(--navds-color-darkgray);
|
||||
}
|
||||
|
||||
.navds-accordion-menu-item:hover,
|
||||
.navds-accordion-menu-collapsable__button:hover {
|
||||
background-color: var(--navds-color-gray-20);
|
||||
background-color: var(--navds-color-blue-10);
|
||||
}
|
||||
|
||||
.navds-accordion-menu-item--active {
|
||||
box-shadow: inset 0.5rem 0 var(--navds-color-text-link);
|
||||
color: var(--navds-color-text);
|
||||
text-decoration: none;
|
||||
font-weight: var(--navds-font-weight-bold);
|
||||
}
|
||||
@@ -5,14 +5,12 @@
|
||||
.navds-accordion {
|
||||
position: relative;
|
||||
background: var(--navds-color-background);
|
||||
border: var(--navds-border-default);
|
||||
border-radius: 4px;
|
||||
border-bottom: 2px solid #c9c9c9;
|
||||
}
|
||||
|
||||
.navds-accordion:hover {
|
||||
box-shadow: var(--navds-color-hover);
|
||||
border: var(--navds-panel-hover);
|
||||
color: black;
|
||||
/* color: black; */
|
||||
border-bottom: 2px solid var(--navds-color-blue-50);
|
||||
}
|
||||
|
||||
.navds-accordion:focus,
|
||||
@@ -39,16 +37,16 @@
|
||||
|
||||
.navds-accordion__button {
|
||||
padding: var(--navds-spacing-4);
|
||||
border-radius: 4px;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
text-align: left;
|
||||
border: none;
|
||||
width: 100%;
|
||||
margin-bottom: 0;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
color: var(--navds-color-text-link);
|
||||
}
|
||||
|
||||
.navds-accordion__button:hover .navds-accordion__heading {
|
||||
@@ -69,3 +67,16 @@
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.navds-accordion__chevron--filled {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navds-accordion__button:hover
|
||||
> .navds-accordion__chevron.navds-accordion__chevron--filled {
|
||||
display: inherit;
|
||||
}
|
||||
|
||||
.navds-accordion__button:hover > .navds-accordion__chevron {
|
||||
display: none;
|
||||
}
|
||||
+23
-11
@@ -2,21 +2,24 @@
|
||||
border-radius: 4px;
|
||||
border: var(--navds-border-default);
|
||||
|
||||
/* Padding calculated based on 16px font for 64px tall alert */
|
||||
padding: 1.1875rem var(--navds-spacing-4);
|
||||
/* Padding calculated based on 18px font for 64px tall alert */
|
||||
padding: var(--navds-spacing-4) var(--navds-spacing-4);
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
column-gap: 0.75rem;
|
||||
justify-content: start;
|
||||
min-height: 64px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.navds-alert--s {
|
||||
border-radius: 0;
|
||||
padding: var(--navds-spacing-2) var(--navds-spacing-4);
|
||||
padding: var(--navds-spacing-1) var(--navds-spacing-4);
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.navds-alert > svg {
|
||||
.navds-alert > span > svg {
|
||||
margin-right: var(--navds-spacing-3);
|
||||
font-size: 1.5rem;
|
||||
flex-shrink: 0;
|
||||
background: radial-gradient(
|
||||
circle,
|
||||
var(--navds-color-background) 50%,
|
||||
@@ -25,8 +28,17 @@
|
||||
);
|
||||
}
|
||||
|
||||
.navds-alert > div {
|
||||
display: block;
|
||||
margin: auto 0;
|
||||
max-width: 43.5rem;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.navds-alert > span {
|
||||
margin-top: 1px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-height: calc(var(--navds-spacing-8) - 2px);
|
||||
}
|
||||
|
||||
.navds-alert--error {
|
||||
@@ -34,7 +46,7 @@
|
||||
background-color: var(--navds-color-error-background);
|
||||
}
|
||||
|
||||
.navds-alert--error > svg {
|
||||
.navds-alert--error > span > svg {
|
||||
color: var(--navds-color-red-60);
|
||||
}
|
||||
|
||||
@@ -43,7 +55,7 @@
|
||||
background-color: var(--navds-color-warning-background);
|
||||
}
|
||||
|
||||
.navds-alert--warning > svg {
|
||||
.navds-alert--warning > span > svg {
|
||||
color: var(--navds-color-orange-40);
|
||||
background: radial-gradient(
|
||||
circle,
|
||||
@@ -58,7 +70,7 @@
|
||||
background-color: var(--navds-color-info-background);
|
||||
}
|
||||
|
||||
.navds-alert--info > svg {
|
||||
.navds-alert--info > span > svg {
|
||||
color: var(--navds-color-lightblue-70);
|
||||
}
|
||||
|
||||
@@ -67,6 +79,6 @@
|
||||
background-color: var(--navds-color-success-background);
|
||||
}
|
||||
|
||||
.navds-alert--success > svg {
|
||||
.navds-alert--success > span > svg {
|
||||
color: var(--navds-color-green-70);
|
||||
}
|
||||
@@ -9,6 +9,16 @@
|
||||
/* Disabled because of UU concerns */
|
||||
/* @import "smooth-scroll.css"; */
|
||||
|
||||
html {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: var(--navds-font-family);
|
||||
line-height: 1.375;
|
||||
|
||||
+34
-172
@@ -1,5 +1,5 @@
|
||||
.navds-button {
|
||||
display: inline-block;
|
||||
display: inline-flex;
|
||||
cursor: pointer;
|
||||
background-color: var(--navds-color-background);
|
||||
color: var(--navds-color-action-default);
|
||||
@@ -10,14 +10,38 @@
|
||||
border-radius: 2px;
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
min-height: 48px;
|
||||
align-items: center;
|
||||
|
||||
/* Padding calculated based on 18px font for 44px tall button */
|
||||
padding: calc(0.625rem - 2px) calc(var(--navds-spacing-8) - 2px);
|
||||
padding: calc(var(--navds-spacing-3) - 2px) var(--navds-spacing-3);
|
||||
}
|
||||
|
||||
.navds-button > svg {
|
||||
font-size: 1.5rem;
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
}
|
||||
|
||||
.navds-button--s > svg {
|
||||
font-size: 1.25rem;
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
}
|
||||
|
||||
.navds-button > svg + *:not(.sr-only),
|
||||
.navds-button > *:not(.sr-only) + svg {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
/* .navds-button:last-child {
|
||||
margin-left: 0.5rem;
|
||||
} */
|
||||
|
||||
.navds-button--s {
|
||||
/* Padding calculated based on 16px font for 32px tall button */
|
||||
padding: calc(0.3125rem - 2px) calc(var(--navds-spacing-4) - 2px);
|
||||
padding: 0.25rem calc(var(--navds-spacing-4) - 2px);
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.navds-button:focus {
|
||||
@@ -33,16 +57,7 @@
|
||||
.navds-button--primary:active {
|
||||
color: var(--navds-color-text-inverse);
|
||||
background-color: var(--navds-color-action-hover);
|
||||
border-width: 0;
|
||||
|
||||
/* Padding calculated based on 18px font for 44px tall button */
|
||||
padding: 0.625rem var(--navds-spacing-8);
|
||||
}
|
||||
|
||||
.navds-button--primary:hover.navds-button--s,
|
||||
.navds-button--primary:active.navds-button--s {
|
||||
/* Padding calculated based on 16px font for 32px tall button */
|
||||
padding: 0.3125rem var(--navds-spacing-4);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.navds-button--primary:active {
|
||||
@@ -86,42 +101,18 @@
|
||||
|
||||
.navds-button--action,
|
||||
.navds-button--danger {
|
||||
/* Padding calculated based on 18px font for 44px tall button */
|
||||
padding: 0.625rem var(--navds-spacing-8);
|
||||
border-width: 0;
|
||||
transform: translateY(calc(-1 * 2px));
|
||||
position: relative;
|
||||
color: var(--navds-color-text-inverse);
|
||||
}
|
||||
|
||||
.navds-button--action.navds-button--s,
|
||||
.navds-button--danger.navds-button--s {
|
||||
/* Padding calculated based on 16px font for 32px tall button */
|
||||
padding: 0.3125rem var(--navds-spacing-4);
|
||||
}
|
||||
|
||||
.navds-button--action:not(:focus),
|
||||
.navds-button--danger:not(:focus) {
|
||||
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25), 0 2px 0 rgba(0, 0, 0, 0.25);
|
||||
color: white;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.navds-button--action:hover {
|
||||
background-color: var(--navds-color-action-hover);
|
||||
border-color: var(--navds-color-action-hover);
|
||||
}
|
||||
|
||||
.navds-button--danger:hover {
|
||||
background-color: var(--navds-color-danger-hover);
|
||||
}
|
||||
|
||||
.navds-button--danger:hover,
|
||||
.navds-button--action:hover {
|
||||
transform: translateY(calc(-1 * 3px));
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.navds-button--action:hover:not(:focus),
|
||||
.navds-button--danger:hover:not(:focus) {
|
||||
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25), 0 3px 0 rgba(0, 0, 0, 0.25);
|
||||
border-color: var(--navds-color-danger-hover);
|
||||
}
|
||||
|
||||
.navds-button--action:active {
|
||||
@@ -132,131 +123,9 @@
|
||||
background-color: var(--navds-color-danger-active);
|
||||
}
|
||||
|
||||
.navds-button--action:active,
|
||||
.navds-button--danger:active {
|
||||
transform: translateY(0);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.navds-button--action:active:not(:focus),
|
||||
.navds-button--danger:active:not(:focus) {
|
||||
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25), 0 0 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.navds-button--action:focus {
|
||||
color: var(--navds-color-action-default);
|
||||
background-color: var(--navds-color-background);
|
||||
}
|
||||
|
||||
.navds-button--action:focus,
|
||||
.navds-button--danger:focus {
|
||||
color: var(--navds-color-danger-default);
|
||||
background-color: var(--navds-color-background);
|
||||
}
|
||||
|
||||
.navds-button--danger:focus,
|
||||
.navds-button--action:focus {
|
||||
/* Padding calculated based on 18px font for 44px tall button */
|
||||
padding: calc(0.625rem - 2px) calc(var(--navds-spacing-8) - 2px);
|
||||
transform: translateY(calc(-1 * 2px));
|
||||
position: relative;
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.navds-button--action:focus.navds-button--s,
|
||||
.navds-button--danger:focus.navds-button--s {
|
||||
/* Padding calculated based on 16px font for 32px tall button */
|
||||
padding: calc(0.3125rem - 2px) calc(var(--navds-spacing-4) - 2px);
|
||||
}
|
||||
|
||||
.navds-button--action:hover:focus {
|
||||
background-color: var(--navds-color-action-hover);
|
||||
}
|
||||
|
||||
.navds-button--danger:hover:focus {
|
||||
background-color: var(--navds-color-danger-hover);
|
||||
}
|
||||
|
||||
.navds-button--action:hover:focus,
|
||||
.navds-button--danger:hover:focus {
|
||||
/* Padding calculated based on 18px font for 44px tall button */
|
||||
padding: 0.625rem var(--navds-spacing-8);
|
||||
border-width: 0;
|
||||
color: var(--navds-color-text-inverse);
|
||||
}
|
||||
|
||||
.navds-button--action:hover:focus.navds-button--s,
|
||||
.navds-button--danger:hover:focus.navds-button--s {
|
||||
/* Padding calculated based on 16px font for 32px tall button */
|
||||
padding: 0.3125rem var(--navds-spacing-4);
|
||||
}
|
||||
|
||||
.navds-button--action:active:focus {
|
||||
color: var(--navds-color-action-active);
|
||||
border-color: var(--navds-color-action-active);
|
||||
}
|
||||
|
||||
.navds-button--danger:active:focus {
|
||||
color: var(--navds-color-danger-active);
|
||||
border-color: var(--navds-color-danger-active);
|
||||
}
|
||||
|
||||
.navds-button--action:active:focus,
|
||||
.navds-button--danger:active:focus {
|
||||
/* Padding calculated based on 18px font for 44px tall button */
|
||||
padding: calc(0.625rem - 2px) calc(var(--navds-spacing-8) - 2px);
|
||||
transform: translateY(0);
|
||||
position: relative;
|
||||
border-width: 2px;
|
||||
background-color: var(--navds-color-background);
|
||||
}
|
||||
|
||||
.navds-button--action:active:focus.navds-button--s,
|
||||
.navds-button--danger:active:focus.navds-button--s {
|
||||
/* Padding calculated based on 16px font for 32px tall button */
|
||||
padding: calc(0.3125rem - 2px) calc(var(--navds-spacing-4) - 2px);
|
||||
}
|
||||
|
||||
.navds-button--action:hover:focus:active {
|
||||
color: var(--navds-color-text-inverse);
|
||||
background-color: var(--navds-color-action-active);
|
||||
}
|
||||
|
||||
.navds-button--danger:hover:focus:active {
|
||||
color: var(--navds-color-text-inverse);
|
||||
background-color: var(--navds-color-danger-active);
|
||||
}
|
||||
|
||||
/**************************
|
||||
* ::before *
|
||||
**************************/
|
||||
|
||||
.navds-button--action::before,
|
||||
.navds-button--danger::before {
|
||||
bottom: calc(-1 * 2px);
|
||||
height: 2px;
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.navds-button--action:hover::before,
|
||||
.navds-button--danger:hover::before {
|
||||
bottom: calc(-1 * 3px);
|
||||
height: 3px;
|
||||
}
|
||||
|
||||
.navds-button--action:focus::before,
|
||||
.navds-button--danger:focus::before {
|
||||
bottom: calc(-1 * 2px);
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
.navds-button--action:active::before,
|
||||
.navds-button--danger:active::before {
|
||||
bottom: 0;
|
||||
height: 0;
|
||||
border-color: white;
|
||||
}
|
||||
|
||||
/**************************
|
||||
@@ -264,8 +133,6 @@
|
||||
**************************/
|
||||
|
||||
.navds-button:disabled:disabled {
|
||||
/* Padding calculated based on 18px font for 44px tall button */
|
||||
padding: 0.625rem var(--navds-spacing-8);
|
||||
background-color: var(--navds-color-disabled);
|
||||
color: var(--navds-color-text-inverse);
|
||||
cursor: not-allowed;
|
||||
@@ -273,8 +140,3 @@
|
||||
box-shadow: none;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.navds-button:disabled:disabled.navds-button--s {
|
||||
/* Padding calculated based on 16px font for 32px tall button */
|
||||
padding: 0.3125rem var(--navds-spacing-4);
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
align-items: center;
|
||||
column-gap: 0.5em;
|
||||
padding: var(--navds-spacing-1);
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.navds-copy-to-clipboard__popover {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
.navds-checkbox-group--s > .navds-checkboxes {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.navds-fieldset.navds-checkbox-group--m > .navds-checkboxes {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.navds-fieldset.navds-checkbox-group--m > .navds-fieldset__error {
|
||||
margin-top: 0;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
.navds-checkbox {
|
||||
position: relative;
|
||||
padding: var(--navds-spacing-3) 0;
|
||||
}
|
||||
|
||||
.navds-checkbox__input {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
left: -12px;
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.navds-checkbox__label {
|
||||
display: flex;
|
||||
width: fit-content;
|
||||
gap: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.navds-checkbox__description {
|
||||
padding-left: calc(48px - 12px);
|
||||
color: var(--navds-color-gray-80);
|
||||
}
|
||||
|
||||
.navds-checkbox--with-description {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.navds-checkbox .navds-error-message {
|
||||
margin-top: var(--navds-spacing-3);
|
||||
}
|
||||
|
||||
.navds-checkbox--with-description .navds-error-message {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.navds-checkbox--with-error-message {
|
||||
padding-bottom: var(--navds-spacing-2);
|
||||
}
|
||||
|
||||
.navds-checkbox__label::before {
|
||||
content: "";
|
||||
background-color: white;
|
||||
border: 1px solid var(--navds-color-border);
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
border-radius: 4px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.navds-checkbox--s {
|
||||
padding: var(--navds-spacing-1) 0;
|
||||
}
|
||||
|
||||
.navds-checkbox--s > .navds-checkbox__input {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
top: 2px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.navds-checkbox--s > .navds-checkbox__label::before {
|
||||
margin-top: -2px;
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
|
||||
.navds-checkbox__input:hover + .navds-checkbox__label {
|
||||
color: var(--navds-color-blue-50);
|
||||
}
|
||||
|
||||
.navds-checkbox__input:hover + .navds-checkbox__label::before {
|
||||
border-color: var(--navds-color-blue-50);
|
||||
background-color: var(--navds-color-blue-10);
|
||||
}
|
||||
|
||||
.navds-checkbox__input:focus + .navds-checkbox__label::before {
|
||||
box-shadow: var(--navds-shadow-focus);
|
||||
}
|
||||
|
||||
.navds-checkbox__input:checked + .navds-checkbox__label::before {
|
||||
background-image: var(--navds-checkmark-image-white);
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 75%;
|
||||
border: 2px solid var(--navds-color-blue-50);
|
||||
background-color: var(--navds-color-blue-50);
|
||||
}
|
||||
|
||||
.navds-checkbox__input:checked:focus + .navds-checkbox__label::before {
|
||||
background-color: white;
|
||||
background-image: var(--navds-checkmark-image-blue);
|
||||
}
|
||||
|
||||
.navds-checkbox--error
|
||||
> .navds-checkbox__input:not(:hover):not(:focus):not(:disabled):not(:checked)
|
||||
+ .navds-checkbox__label::before {
|
||||
box-shadow: 0 0 0 1px var(--navds-color-red-50);
|
||||
border-color: var(--navds-color-red-50);
|
||||
}
|
||||
|
||||
.navds-checkbox--s .navds-error-message {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.navds-checkbox__input:disabled,
|
||||
.navds-checkbox__input:disabled + .navds-checkbox__label {
|
||||
color: var(--navds-color-gray-40);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.navds-checkbox__input:disabled + .navds-checkbox__label::before {
|
||||
background-color: var(--navds-color-gray-10);
|
||||
border-color: var(--navds-color-gray-60);
|
||||
}
|
||||
|
||||
.navds-checkbox__input:disabled:checked + .navds-checkbox__label::before {
|
||||
background-color: var(--navds-color-gray-40);
|
||||
border-color: var(--navds-color-gray-40);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
.navds-confirmation-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--navds-spacing-4);
|
||||
padding: var(--navds-spacing-4);
|
||||
border-radius: 4px;
|
||||
background-color: #ffeccc;
|
||||
transition: background-color linear 100ms;
|
||||
}
|
||||
|
||||
.navds-confirmation-panel__content {
|
||||
max-width: 80ch;
|
||||
}
|
||||
|
||||
.navds-confirmation-panel--s {
|
||||
padding: var(--navds-spacing-3);
|
||||
gap: var(--navds-spacing-2);
|
||||
}
|
||||
|
||||
.navds-confirmation-panel--checked {
|
||||
background-color: #ccf1d6;
|
||||
border-color: #ccf1d6;
|
||||
}
|
||||
|
||||
.navds-confirmation-panel--error {
|
||||
background-color: #f3e3e3;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.navds-confirmation-panel--checked
|
||||
> .navds-confirmation-panel__content
|
||||
.navds-link:not(:focus) {
|
||||
color: var(--navds-color-darkgray);
|
||||
}
|
||||
|
||||
.navds-confirmation-panel
|
||||
.navds-checkbox__input:hover
|
||||
+ .navds-checkbox__label {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.navds-confirmation-panel--checked
|
||||
.navds-checkbox__input:hover
|
||||
+ .navds-checkbox__label {
|
||||
color: var(--navds-color-darkgray);
|
||||
}
|
||||
|
||||
.navds-confirmation-panel--checked
|
||||
.navds-checkbox__input
|
||||
+ .navds-checkbox__label::before {
|
||||
transition: none;
|
||||
background-color: var(--navds-color-green-50);
|
||||
border-color: var(--navds-color-green-50);
|
||||
background-image: var(--navds-checkmark-image-white);
|
||||
}
|
||||
|
||||
.navds-confirmation-panel--checked
|
||||
.navds-checkbox__input:hover
|
||||
+ .navds-checkbox__label::before {
|
||||
background-color: var(--navds-color-green-70);
|
||||
border-color: var(--navds-color-green-70);
|
||||
}
|
||||
|
||||
.navds-confirmation-panel--checked
|
||||
.navds-checkbox__input:focus:hover
|
||||
+ .navds-checkbox__label::before {
|
||||
background-image: var(--navds-checkmark-image-white);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
.navds-error-message {
|
||||
display: block;
|
||||
color: var(--navds-color-red-50);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
.navds-error-summary {
|
||||
background-color: #fff;
|
||||
padding: var(--navds-spacing-4);
|
||||
border: 4px solid #ba3a26;
|
||||
}
|
||||
|
||||
.navds-error-summary--s {
|
||||
padding: var(--navds-spacing-2);
|
||||
}
|
||||
|
||||
.navds-error-summary:focus {
|
||||
box-shadow: var(--navds-shadow-focus);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.navds-error-summary__list {
|
||||
margin: 1rem 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.navds-error-summary--s > .navds-error-summary__list {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
.navds-fieldset {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.navds-fieldset > :not(:first-child):not(:empty) {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.navds-fieldset--s > :not(:first-child):not(:empty) {
|
||||
margin-top: 4px;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
.navds-form-field > :not(:first-child):not(:empty),
|
||||
.navds-form-field > input:not(:first-child) {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.navds-form-field--s > :not(:first-child):not(:empty),
|
||||
.navds-form-field--s > input:not(:first-child) {
|
||||
margin-top: 4px;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
Order matters; rearrange with care
|
||||
*/
|
||||
@import "fieldset.css";
|
||||
@import "form.css";
|
||||
@import "error-summary.css";
|
||||
@import "checkbox.css";
|
||||
@import "checkbox-group.css";
|
||||
@import "confirmation-panel.css";
|
||||
@import "error-message.css";
|
||||
@import "radio.css";
|
||||
@import "radio-group.css";
|
||||
@import "select.css";
|
||||
@import "text-field.css";
|
||||
@import "textarea.css";
|
||||
@@ -0,0 +1,13 @@
|
||||
.navds-radio-group--s > .navds-radio-buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.navds-fieldset.navds-radio-group--m > .navds-radio-buttons {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.navds-fieldset.navds-radio-group--m > .navds-fieldset__error {
|
||||
margin-top: 0;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
.navds-radio {
|
||||
position: relative;
|
||||
padding: var(--navds-spacing-3) 0;
|
||||
}
|
||||
|
||||
.navds-radio--with-description .navds-error-message {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.navds-radio .navds-error-message {
|
||||
margin-top: var(--navds-spacing-3);
|
||||
}
|
||||
|
||||
.navds-radio__input {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
left: -12px;
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.navds-radio__label {
|
||||
display: flex;
|
||||
width: fit-content;
|
||||
gap: 12px;
|
||||
min-width: 48px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.navds-radio__description {
|
||||
padding-left: calc(48px - 12px);
|
||||
color: var(--navds-color-gray-80);
|
||||
}
|
||||
|
||||
.navds-radio--with-description {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.navds-radio--with-error-message {
|
||||
padding-bottom: var(--navds-spacing-2);
|
||||
}
|
||||
|
||||
.navds-radio__label::before {
|
||||
content: "";
|
||||
background-color: white;
|
||||
border: 1px solid var(--navds-color-border);
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
border-radius: 4px;
|
||||
flex-shrink: 0;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.navds-radio--s {
|
||||
padding: var(--navds-spacing-1) 0;
|
||||
}
|
||||
|
||||
.navds-radio--s > .navds-radio__input {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
top: 2px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.navds-radio--s > .navds-radio__label::before {
|
||||
margin-top: -2px;
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
|
||||
.navds-radio__input:hover + .navds-radio__label {
|
||||
color: var(--navds-color-blue-50);
|
||||
}
|
||||
|
||||
.navds-radio__input:hover + .navds-radio__label::before {
|
||||
border-color: var(--navds-color-blue-50);
|
||||
background-color: var(--navds-color-blue-10);
|
||||
}
|
||||
|
||||
.navds-radio__input:focus + .navds-radio__label::before {
|
||||
box-shadow: var(--navds-shadow-focus);
|
||||
}
|
||||
|
||||
.navds-radio__input:checked + .navds-radio__label::before {
|
||||
border: 2px solid var(--navds-color-blue-50);
|
||||
box-shadow: 0 0 0 3px #fff inset, 0 0 0 2rem var(--navds-color-blue-50) inset;
|
||||
}
|
||||
|
||||
.navds-radio__input:checked:focus + .navds-radio__label::before {
|
||||
transition: box-shadow 200ms cubic-bezier(0.465, 0.183, 0.153, 0.946);
|
||||
box-shadow: 0 0 0 3px var(--navds-color-blue-80), 0 0 0 3px #fff inset,
|
||||
0 0 0 2rem var(--navds-color-blue-50) inset;
|
||||
}
|
||||
|
||||
.navds-radio--error
|
||||
> .navds-radio__input:not(:hover):not(:focus):not(:disabled):not(:checked)
|
||||
+ .navds-radio__label::before {
|
||||
box-shadow: 0 0 0 1px var(--navds-color-red-50);
|
||||
border-color: var(--navds-color-red-50);
|
||||
}
|
||||
|
||||
.navds-radio--s .navds-error-message {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.navds-radio__input:disabled,
|
||||
.navds-radio__input:disabled + .navds-radio__label {
|
||||
color: var(--navds-color-gray-40);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.navds-radio__input:disabled + .navds-radio__label::before {
|
||||
background-color: var(--navds-color-gray-10);
|
||||
border-color: var(--navds-color-gray-60);
|
||||
}
|
||||
|
||||
.navds-radio__input:disabled:checked + .navds-radio__label::before {
|
||||
background-color: var(--navds-color-gray-40);
|
||||
border-color: var(--navds-color-gray-40);
|
||||
box-shadow: 0 0 0 3px #fff inset, 0 0 0 2rem var(--navds-color-gray-40) inset;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
.navds-select__input {
|
||||
appearance: none;
|
||||
padding: 0.5rem;
|
||||
background-color: white;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--navds-color-gray-40);
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
min-height: 48px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
padding-right: 2.5rem;
|
||||
}
|
||||
|
||||
.navds-select__input:hover {
|
||||
border-color: var(--navds-color-blue-50);
|
||||
}
|
||||
|
||||
.navds-select__input:focus {
|
||||
outline: none;
|
||||
box-shadow: var(--navds-shadow-focus);
|
||||
}
|
||||
|
||||
.navds-select__container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.navds-select__chevron {
|
||||
position: absolute;
|
||||
font-size: 1rem;
|
||||
right: 0.5rem;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.navds-form-field--s .navds-select__input {
|
||||
min-height: 32px;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
|
||||
/**
|
||||
Error handling
|
||||
*/
|
||||
.navds-select--error > * select:not(:hover):not(:focus):not(:disabled) {
|
||||
box-shadow: 0 0 0 1px var(--navds-color-red-50);
|
||||
border-color: var(--navds-color-red-50);
|
||||
}
|
||||
|
||||
/*
|
||||
Disabled handling
|
||||
TODO: Oppdatere farger her
|
||||
*/
|
||||
.navds-select__input:disabled,
|
||||
.navds-select__input[read-only] {
|
||||
background-color: var(--navds-color-gray-10);
|
||||
border-color: var(--navds-color-gray-40);
|
||||
box-shadow: none;
|
||||
color: var(--navds-color-darkgray);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
.navds-text-field__input {
|
||||
appearance: none;
|
||||
padding: 0.5rem;
|
||||
background-color: white;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--navds-color-border);
|
||||
min-height: 48px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.navds-form-field--s > .navds-text-field__input {
|
||||
padding: 0.25rem;
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.navds-text-field__input:hover {
|
||||
border-color: var(--navds-color-blue-50);
|
||||
}
|
||||
|
||||
.navds-text-field__input:focus {
|
||||
outline: none;
|
||||
box-shadow: var(--navds-shadow-focus);
|
||||
}
|
||||
|
||||
/**
|
||||
Error handling
|
||||
*/
|
||||
.navds-text-field--error
|
||||
> .navds-text-field__input:not(:hover):not(:focus):not(:disabled) {
|
||||
box-shadow: 0 0 0 1px var(--navds-color-red-50);
|
||||
border-color: var(--navds-color-red-50);
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: Oppdater denne til riktige farger
|
||||
Disabled handling
|
||||
*/
|
||||
.navds-text-field__input:disabled,
|
||||
.navds-text-field__input[readonly] {
|
||||
background-color: #f1f1f1;
|
||||
border-color: #6a6a6a;
|
||||
box-shadow: none;
|
||||
color: #262626;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
.navds-textarea__wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.navds-textarea__input {
|
||||
appearance: none;
|
||||
padding: var(--navds-spacing-2);
|
||||
background-color: white;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--navds-color-border);
|
||||
resize: none;
|
||||
width: 100%;
|
||||
transition: height 0.1s ease-out;
|
||||
display: block;
|
||||
min-height: 48px;
|
||||
}
|
||||
|
||||
.navds-textarea--counter {
|
||||
padding-bottom: var(--navds-spacing-8);
|
||||
}
|
||||
|
||||
.navds-textarea__input:hover {
|
||||
border-color: var(--navds-color-blue-50);
|
||||
}
|
||||
|
||||
.navds-textarea__input:focus {
|
||||
outline: none;
|
||||
box-shadow: var(--navds-shadow-focus);
|
||||
}
|
||||
|
||||
.navds-form-field--s .navds-textarea__input {
|
||||
padding: var(--navds-spacing-1);
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.navds-form-field--s .navds-textarea--counter.navds-textarea__input {
|
||||
padding-bottom: var(--navds-spacing-7);
|
||||
}
|
||||
|
||||
.navds-textarea__counter {
|
||||
pointer-events: none;
|
||||
color: var(--navds-color-gray-40);
|
||||
font-style: italic;
|
||||
position: absolute;
|
||||
text-align: right;
|
||||
left: var(--navds-spacing-3);
|
||||
right: var(--navds-spacing-3);
|
||||
bottom: var(--navds-spacing-2);
|
||||
}
|
||||
|
||||
.navds-textarea__counter--error {
|
||||
color: var(--navds-color-red-50);
|
||||
}
|
||||
|
||||
/**
|
||||
Error handling
|
||||
*/
|
||||
.navds-textarea--error
|
||||
.navds-textarea__input:not(:hover):not(:focus):not(:disabled) {
|
||||
box-shadow: 0 0 0 1px var(--navds-color-red-50);
|
||||
border-color: var(--navds-color-red-50);
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: Oppdater denne til riktige farger
|
||||
Disabled handling
|
||||
*/
|
||||
.navds-textarea__input:disabled,
|
||||
.navds-textarea__input[readonly] {
|
||||
background-color: #f1f1f1;
|
||||
border-color: #6a6a6a;
|
||||
box-shadow: none;
|
||||
color: #262626;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
@@ -13,9 +13,12 @@
|
||||
@import "copy-to-clipboard.css";
|
||||
@import "header.css";
|
||||
@import "internal-header.css";
|
||||
@import "form/index.css";
|
||||
@import "link.css";
|
||||
@import "loader.css";
|
||||
@import "modal.css";
|
||||
@import "popover.css";
|
||||
@import "tag.css";
|
||||
@import "panel.css";
|
||||
@import "link-panel.css";
|
||||
@import "speech-bubble.css";
|
||||
@@ -0,0 +1,105 @@
|
||||
.navds-loader {
|
||||
width: 1.5rem;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
animation: loader-rotate 1.4s linear infinite;
|
||||
}
|
||||
|
||||
.navds-loader__foreground {
|
||||
animation: loader-dasharray 1.4s ease-in-out infinite;
|
||||
stroke-dasharray: 80px, 200px;
|
||||
stroke-dashoffset: 0;
|
||||
stroke: var(--navds-color-gray-40);
|
||||
}
|
||||
|
||||
.navds-loader__background {
|
||||
stroke: var(--navds-color-gray-10);
|
||||
}
|
||||
|
||||
.navds-loader--neutral .navds-loader__foreground {
|
||||
stroke: var(--navds-color-gray-40);
|
||||
}
|
||||
|
||||
.navds-loader--interaction .navds-loader__foreground {
|
||||
stroke: var(--navds-color-blue-50);
|
||||
}
|
||||
|
||||
.navds-loader--inverted .navds-loader__foreground {
|
||||
stroke: white;
|
||||
}
|
||||
|
||||
.navds-loader--inverted .navds-loader__background {
|
||||
stroke: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.navds-loader--transparent .navds-loader__background {
|
||||
stroke: transparent;
|
||||
}
|
||||
|
||||
.navds-loader--2xl {
|
||||
width: 4rem;
|
||||
}
|
||||
|
||||
.navds-loader--xl {
|
||||
width: 2.5rem;
|
||||
}
|
||||
|
||||
.navds-loader--l {
|
||||
width: 2rem;
|
||||
}
|
||||
|
||||
.navds-loader--m {
|
||||
width: 1.5rem;
|
||||
}
|
||||
|
||||
.navds-loader--s {
|
||||
width: 1.25rem;
|
||||
}
|
||||
|
||||
.navds-loader--xs {
|
||||
width: 1rem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Button spesific styling
|
||||
*/
|
||||
|
||||
.navds-button .navds-loader .navds-loader__foreground {
|
||||
stroke: currentColor;
|
||||
}
|
||||
|
||||
.navds-button:hover .navds-loader .navds-loader__background {
|
||||
stroke: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.navds-button:active .navds-loader .navds-loader__background {
|
||||
stroke: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.navds-button--action .navds-loader .navds-loader__background,
|
||||
.navds-button--danger .navds-loader .navds-loader__background {
|
||||
stroke: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
@keyframes loader-rotate {
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes loader-dasharray {
|
||||
0% {
|
||||
stroke-dasharray: 1px, 200px;
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
|
||||
50% {
|
||||
stroke-dasharray: 100px, 200px;
|
||||
stroke-dashoffset: -15px;
|
||||
}
|
||||
|
||||
100% {
|
||||
stroke-dasharray: 100px, 200px;
|
||||
stroke-dashoffset: -120px;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-css",
|
||||
"version": "0.6.2",
|
||||
"version": "0.6.18",
|
||||
"private": false,
|
||||
"description": "Css for NAV Designsystem components",
|
||||
"author": "NAV Designsystem team",
|
||||
@@ -21,7 +21,7 @@
|
||||
"watch-css": "postcss -w --use postcss-import -o dist/index.css index.css"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@navikt/ds-tokens": "^0.4.2",
|
||||
"@navikt/ds-tokens": "^0.4.4",
|
||||
"normalize.css": "^8.0.1",
|
||||
"postcss": "^8.2.7",
|
||||
"postcss-cli": "^8.3.1",
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
.navds-speechbubble {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: var(--navds-spacing-4);
|
||||
}
|
||||
|
||||
.navds-speechbubble--right {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.navds-speechbubble__bubble-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--navds-spacing-3);
|
||||
}
|
||||
|
||||
.navds-speechbubble--right .navds-speechbubble__bubble-list {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.navds-speechbubble__illustration {
|
||||
align-items: center;
|
||||
background: var(--navds-color-gray-20);
|
||||
color: var(--navds-color-darkgray);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
height: 3rem;
|
||||
width: 3rem;
|
||||
}
|
||||
|
||||
.navds-speechbubble__illustration svg {
|
||||
align-self: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.navds-speechbubble__bubble {
|
||||
padding: 1rem;
|
||||
box-shadow: 0 2px 4px 0 var(--navds-color-gray-20);
|
||||
width: fit-content;
|
||||
max-width: 37.5rem;
|
||||
background-color: var(--navds-color-gray-10);
|
||||
border-radius: 12px;
|
||||
border-bottom-left-radius: 2px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--navds-spacing-2);
|
||||
}
|
||||
|
||||
.navds-speechbubble__bubble:focus {
|
||||
box-shadow: var(--navds-shadow-focus);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.navds-speechbubble--right .navds-speechbubble__bubble {
|
||||
border-radius: 12px;
|
||||
border-bottom-right-radius: 2px;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.navds-speechbubble__top-text {
|
||||
color: var(--navds-color-gray-60);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"type": "commonjs",
|
||||
"main": "index.js",
|
||||
"typings": "../esm/index.d.ts",
|
||||
"sideEffects": false
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
@@ -11,7 +11,7 @@
|
||||
"name": "AddCircle",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.784Z",
|
||||
"updated_at": "2021-04-09T13:32:16.308Z",
|
||||
"updated_at": "2021-08-12T11:15:52.168Z",
|
||||
"pageName": "Interface",
|
||||
"visible": true
|
||||
},
|
||||
@@ -32,18 +32,18 @@
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"name": "AddPeople",
|
||||
"name": "AddPerson",
|
||||
"description": "",
|
||||
"created_at": "2021-06-15T15:06:55.651Z",
|
||||
"updated_at": "2021-06-15T15:06:55.651Z",
|
||||
"updated_at": "2021-08-13T06:33:04.695Z",
|
||||
"pageName": "People",
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"name": "AddPeopleFilled",
|
||||
"name": "AddPersonFilled",
|
||||
"description": "",
|
||||
"created_at": "2021-06-15T15:06:55.654Z",
|
||||
"updated_at": "2021-06-15T15:06:55.654Z",
|
||||
"updated_at": "2021-08-13T06:33:04.683Z",
|
||||
"pageName": "People",
|
||||
"visible": true
|
||||
},
|
||||
@@ -107,7 +107,7 @@
|
||||
"name": "Back",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.840Z",
|
||||
"updated_at": "2021-04-09T13:32:23.607Z",
|
||||
"updated_at": "2021-08-12T14:51:21.441Z",
|
||||
"pageName": "Chevron",
|
||||
"visible": true
|
||||
},
|
||||
@@ -123,7 +123,7 @@
|
||||
"name": "Bag",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.673Z",
|
||||
"updated_at": "2021-06-14T07:21:59.055Z",
|
||||
"updated_at": "2021-08-13T09:47:23.613Z",
|
||||
"pageName": "Jobs",
|
||||
"visible": true
|
||||
},
|
||||
@@ -203,7 +203,7 @@
|
||||
"name": "Bookmark",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.877Z",
|
||||
"updated_at": "2021-04-09T13:32:23.611Z",
|
||||
"updated_at": "2021-08-12T12:32:34.047Z",
|
||||
"pageName": "File",
|
||||
"visible": true
|
||||
},
|
||||
@@ -251,7 +251,7 @@
|
||||
"name": "Calculator",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.917Z",
|
||||
"updated_at": "2021-06-14T07:21:59.043Z",
|
||||
"updated_at": "2021-08-12T12:31:15.652Z",
|
||||
"pageName": "Money",
|
||||
"visible": true
|
||||
},
|
||||
@@ -395,7 +395,7 @@
|
||||
"name": "Clock",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.647Z",
|
||||
"updated_at": "2021-04-09T13:32:23.334Z",
|
||||
"updated_at": "2021-08-13T07:30:12.128Z",
|
||||
"pageName": "Time",
|
||||
"visible": true
|
||||
},
|
||||
@@ -411,7 +411,7 @@
|
||||
"name": "Close",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.827Z",
|
||||
"updated_at": "2021-04-09T13:32:16.911Z",
|
||||
"updated_at": "2021-08-12T13:19:34.922Z",
|
||||
"pageName": "Interface",
|
||||
"visible": true
|
||||
},
|
||||
@@ -419,7 +419,7 @@
|
||||
"name": "CloseFilled",
|
||||
"description": "",
|
||||
"created_at": "2021-01-11T13:37:55.364Z",
|
||||
"updated_at": "2021-04-09T13:32:16.624Z",
|
||||
"updated_at": "2021-08-12T10:54:40.891Z",
|
||||
"pageName": "Interface",
|
||||
"visible": true
|
||||
},
|
||||
@@ -427,7 +427,7 @@
|
||||
"name": "CoApplicant",
|
||||
"description": "",
|
||||
"created_at": "2021-04-30T10:55:32.823Z",
|
||||
"updated_at": "2021-04-30T10:55:32.823Z",
|
||||
"updated_at": "2021-08-13T09:47:48.809Z",
|
||||
"pageName": "People",
|
||||
"visible": true
|
||||
},
|
||||
@@ -507,7 +507,7 @@
|
||||
"name": "Copy",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.619Z",
|
||||
"updated_at": "2021-05-05T12:44:31.388Z",
|
||||
"updated_at": "2021-08-12T12:36:11.164Z",
|
||||
"pageName": "File",
|
||||
"visible": true
|
||||
},
|
||||
@@ -567,6 +567,14 @@
|
||||
"pageName": "File",
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"name": "Decision",
|
||||
"description": "",
|
||||
"created_at": "2021-08-13T06:33:04.661Z",
|
||||
"updated_at": "2021-08-13T06:33:04.661Z",
|
||||
"pageName": "People",
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"name": "DecisionCheck",
|
||||
"description": "",
|
||||
@@ -591,6 +599,14 @@
|
||||
"pageName": "People",
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"name": "DecisionFilled",
|
||||
"description": "",
|
||||
"created_at": "2021-08-13T06:33:04.665Z",
|
||||
"updated_at": "2021-08-13T06:33:04.665Z",
|
||||
"pageName": "People",
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"name": "Delete",
|
||||
"description": "",
|
||||
@@ -619,7 +635,7 @@
|
||||
"name": "DialogDots",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:43.133Z",
|
||||
"updated_at": "2021-04-09T13:32:23.486Z",
|
||||
"updated_at": "2021-08-12T11:19:13.127Z",
|
||||
"pageName": "Communication",
|
||||
"visible": true
|
||||
},
|
||||
@@ -875,7 +891,7 @@
|
||||
"name": "EmployerFilled",
|
||||
"description": "",
|
||||
"created_at": "2021-01-22T13:40:32.293Z",
|
||||
"updated_at": "2021-04-22T08:46:31.424Z",
|
||||
"updated_at": "2021-08-13T06:33:04.692Z",
|
||||
"pageName": "People",
|
||||
"visible": true
|
||||
},
|
||||
@@ -931,7 +947,7 @@
|
||||
"name": "Eye",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.895Z",
|
||||
"updated_at": "2021-04-09T13:32:23.514Z",
|
||||
"updated_at": "2021-08-12T09:55:24.102Z",
|
||||
"pageName": "Privacy",
|
||||
"visible": true
|
||||
},
|
||||
@@ -939,7 +955,7 @@
|
||||
"name": "EyeFilled",
|
||||
"description": "",
|
||||
"created_at": "2021-01-11T13:37:55.321Z",
|
||||
"updated_at": "2021-04-09T13:32:16.996Z",
|
||||
"updated_at": "2021-08-12T09:55:25.386Z",
|
||||
"pageName": "Privacy",
|
||||
"visible": true
|
||||
},
|
||||
@@ -947,7 +963,7 @@
|
||||
"name": "EyeScreened",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.956Z",
|
||||
"updated_at": "2021-04-09T13:32:23.351Z",
|
||||
"updated_at": "2021-08-12T09:56:29.536Z",
|
||||
"pageName": "Privacy",
|
||||
"visible": true
|
||||
},
|
||||
@@ -955,7 +971,7 @@
|
||||
"name": "EyeScreenedFilled",
|
||||
"description": "",
|
||||
"created_at": "2021-01-11T13:37:55.578Z",
|
||||
"updated_at": "2021-04-09T13:32:23.419Z",
|
||||
"updated_at": "2021-08-12T09:55:47.137Z",
|
||||
"pageName": "Privacy",
|
||||
"visible": true
|
||||
},
|
||||
@@ -1107,7 +1123,7 @@
|
||||
"name": "Findout",
|
||||
"description": "",
|
||||
"created_at": "2021-05-05T13:04:25.502Z",
|
||||
"updated_at": "2021-05-05T13:04:25.502Z",
|
||||
"updated_at": "2021-08-12T12:32:46.082Z",
|
||||
"pageName": "File",
|
||||
"visible": true
|
||||
},
|
||||
@@ -1139,7 +1155,7 @@
|
||||
"name": "Folder",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.682Z",
|
||||
"updated_at": "2021-04-09T13:32:23.439Z",
|
||||
"updated_at": "2021-08-13T07:30:12.108Z",
|
||||
"pageName": "File",
|
||||
"visible": true
|
||||
},
|
||||
@@ -1267,7 +1283,7 @@
|
||||
"name": "HandBandage",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.711Z",
|
||||
"updated_at": "2021-04-09T13:32:16.442Z",
|
||||
"updated_at": "2021-08-13T09:48:45.392Z",
|
||||
"pageName": "Health",
|
||||
"visible": true
|
||||
},
|
||||
@@ -1379,7 +1395,7 @@
|
||||
"name": "Helmet",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.793Z",
|
||||
"updated_at": "2021-04-09T13:32:23.412Z",
|
||||
"updated_at": "2021-08-13T09:49:01.868Z",
|
||||
"pageName": "Jobs",
|
||||
"visible": true
|
||||
},
|
||||
@@ -1491,7 +1507,7 @@
|
||||
"name": "Information",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:43.005Z",
|
||||
"updated_at": "2021-04-09T13:32:16.578Z",
|
||||
"updated_at": "2021-08-12T12:35:33.631Z",
|
||||
"pageName": "Status",
|
||||
"visible": true
|
||||
},
|
||||
@@ -1499,7 +1515,7 @@
|
||||
"name": "InformationFilled",
|
||||
"description": "",
|
||||
"created_at": "2021-01-11T13:37:55.736Z",
|
||||
"updated_at": "2021-04-09T13:32:16.132Z",
|
||||
"updated_at": "2021-08-12T11:36:44.756Z",
|
||||
"pageName": "Status",
|
||||
"visible": true
|
||||
},
|
||||
@@ -1531,7 +1547,7 @@
|
||||
"name": "LawFilled",
|
||||
"description": "",
|
||||
"created_at": "2021-01-11T13:37:55.330Z",
|
||||
"updated_at": "2021-04-09T13:32:16.725Z",
|
||||
"updated_at": "2021-08-13T09:50:59.913Z",
|
||||
"pageName": "Privacy",
|
||||
"visible": true
|
||||
},
|
||||
@@ -1539,7 +1555,7 @@
|
||||
"name": "Left",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.797Z",
|
||||
"updated_at": "2021-04-09T13:32:23.354Z",
|
||||
"updated_at": "2021-08-13T06:33:04.688Z",
|
||||
"pageName": "Arrow",
|
||||
"visible": true
|
||||
},
|
||||
@@ -1619,7 +1635,7 @@
|
||||
"name": "Locked",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:43.027Z",
|
||||
"updated_at": "2021-04-09T13:32:23.385Z",
|
||||
"updated_at": "2021-08-12T09:56:54.295Z",
|
||||
"pageName": "Privacy",
|
||||
"visible": true
|
||||
},
|
||||
@@ -1715,7 +1731,7 @@
|
||||
"name": "MinusCircleFilled",
|
||||
"description": "",
|
||||
"created_at": "2021-01-11T13:37:55.721Z",
|
||||
"updated_at": "2021-04-09T13:32:16.246Z",
|
||||
"updated_at": "2021-08-12T10:26:25.789Z",
|
||||
"pageName": "Interface",
|
||||
"visible": true
|
||||
},
|
||||
@@ -1731,7 +1747,7 @@
|
||||
"name": "Mobile",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:43.010Z",
|
||||
"updated_at": "2021-04-09T13:32:16.508Z",
|
||||
"updated_at": "2021-08-12T11:19:05.339Z",
|
||||
"pageName": "Device",
|
||||
"visible": true
|
||||
},
|
||||
@@ -1747,7 +1763,7 @@
|
||||
"name": "Money",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.741Z",
|
||||
"updated_at": "2021-04-09T13:32:23.388Z",
|
||||
"updated_at": "2021-08-12T12:31:01.092Z",
|
||||
"pageName": "Money",
|
||||
"visible": true
|
||||
},
|
||||
@@ -1891,7 +1907,7 @@
|
||||
"name": "Office1",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.720Z",
|
||||
"updated_at": "2021-04-09T13:32:23.456Z",
|
||||
"updated_at": "2021-08-12T12:56:17.625Z",
|
||||
"pageName": "Building",
|
||||
"visible": true
|
||||
},
|
||||
@@ -1987,7 +2003,7 @@
|
||||
"name": "People",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.850Z",
|
||||
"updated_at": "2021-04-09T13:32:23.661Z",
|
||||
"updated_at": "2021-08-12T11:17:04.979Z",
|
||||
"pageName": "People",
|
||||
"visible": true
|
||||
},
|
||||
@@ -2115,7 +2131,7 @@
|
||||
"name": "Profile",
|
||||
"description": "",
|
||||
"created_at": "2021-04-26T09:24:38.029Z",
|
||||
"updated_at": "2021-04-30T10:55:32.846Z",
|
||||
"updated_at": "2021-08-12T12:32:56.285Z",
|
||||
"pageName": "File",
|
||||
"visible": true
|
||||
},
|
||||
@@ -2147,7 +2163,7 @@
|
||||
"name": "Receipt",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.904Z",
|
||||
"updated_at": "2021-04-09T13:32:23.649Z",
|
||||
"updated_at": "2021-08-12T12:29:47.091Z",
|
||||
"pageName": "Money",
|
||||
"visible": true
|
||||
},
|
||||
@@ -2227,7 +2243,7 @@
|
||||
"name": "Right",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.642Z",
|
||||
"updated_at": "2021-04-09T13:32:23.409Z",
|
||||
"updated_at": "2021-08-12T07:14:26.093Z",
|
||||
"pageName": "Arrow",
|
||||
"visible": true
|
||||
},
|
||||
@@ -2259,7 +2275,7 @@
|
||||
"name": "Sandglass",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:43.117Z",
|
||||
"updated_at": "2021-04-09T13:32:23.313Z",
|
||||
"updated_at": "2021-08-12T08:18:12.598Z",
|
||||
"pageName": "Time",
|
||||
"visible": true
|
||||
},
|
||||
@@ -2323,7 +2339,7 @@
|
||||
"name": "Search",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.983Z",
|
||||
"updated_at": "2021-04-09T13:32:16.382Z",
|
||||
"updated_at": "2021-08-12T12:37:22.919Z",
|
||||
"pageName": "Interface",
|
||||
"visible": true
|
||||
},
|
||||
@@ -2387,7 +2403,7 @@
|
||||
"name": "Send",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:43.101Z",
|
||||
"updated_at": "2021-04-09T13:32:23.596Z",
|
||||
"updated_at": "2021-08-13T07:30:12.151Z",
|
||||
"pageName": "Communication",
|
||||
"visible": true
|
||||
},
|
||||
@@ -2403,7 +2419,7 @@
|
||||
"name": "Service",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.707Z",
|
||||
"updated_at": "2021-06-14T07:21:59.047Z",
|
||||
"updated_at": "2021-08-12T11:15:52.145Z",
|
||||
"pageName": "People",
|
||||
"visible": true
|
||||
},
|
||||
@@ -2675,7 +2691,7 @@
|
||||
"name": "SuccessStroke",
|
||||
"description": "",
|
||||
"created_at": "2021-04-15T07:12:49.753Z",
|
||||
"updated_at": "2021-04-15T07:12:49.753Z",
|
||||
"updated_at": "2021-08-12T11:30:36.177Z",
|
||||
"pageName": "Status",
|
||||
"visible": true
|
||||
},
|
||||
@@ -2755,7 +2771,7 @@
|
||||
"name": "ThermometerStroke",
|
||||
"description": "",
|
||||
"created_at": "2021-04-07T12:13:28.179Z",
|
||||
"updated_at": "2021-04-09T13:32:16.814Z",
|
||||
"updated_at": "2021-08-12T12:34:12.825Z",
|
||||
"pageName": "Health",
|
||||
"visible": true
|
||||
},
|
||||
@@ -2811,7 +2827,7 @@
|
||||
"name": "Unlocked",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:42.823Z",
|
||||
"updated_at": "2021-04-09T13:32:16.901Z",
|
||||
"updated_at": "2021-08-12T09:56:56.564Z",
|
||||
"pageName": "Privacy",
|
||||
"visible": true
|
||||
},
|
||||
@@ -2843,7 +2859,7 @@
|
||||
"name": "Upload",
|
||||
"description": "",
|
||||
"created_at": "2020-07-01T10:37:43.046Z",
|
||||
"updated_at": "2021-04-09T13:32:23.685Z",
|
||||
"updated_at": "2021-08-13T07:41:40.719Z",
|
||||
"pageName": "Attachment",
|
||||
"visible": true
|
||||
},
|
||||
|
||||
File renamed without changes.
File renamed without changes.
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-icons",
|
||||
"version": "0.3.3",
|
||||
"version": "0.5.1",
|
||||
"private": false,
|
||||
"description": "NAVs egne ikoner i SVG og React format",
|
||||
"repository": {
|
||||
@@ -14,11 +14,10 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"author": "NAV",
|
||||
"main": "esm/index.js",
|
||||
"module": "esm/index.js",
|
||||
"typings": "esm/index.d.ts",
|
||||
"sideEffects": false,
|
||||
"type": "module",
|
||||
"main": "./cjs/index.js",
|
||||
"module": "./esm/index.js",
|
||||
"typings": "./esm/index.d.ts",
|
||||
"files": [
|
||||
"/cjs",
|
||||
"/esm",
|
||||
@@ -26,12 +25,13 @@
|
||||
"/svg"
|
||||
],
|
||||
"scripts": {
|
||||
"cjs-package": "copyfiles -f config/package.json cjs",
|
||||
"dl-icons": "FILE_KEY=UmEVH3pZ71uJPsSz9ilP3Y node --experimental-modules --es-module-specifier-resolution=node -r dotenv/config figma-api/index.js dotenv_config_path=figma-api/.env",
|
||||
"create-package-json-pointers-to-esm": "node ../../utilities/scripts/createPackageJsonsWithESMPointers.js",
|
||||
"dl-icons": "FILE_KEY=UmEVH3pZ71uJPsSz9ilP3Y node --experimental-modules --es-module-specifier-resolution=node -r dotenv/config figma-api/index.mjs dotenv_config_path=figma-api/.env",
|
||||
"create-icons": "svgr --silent --typescript --ref --icon --title-prop --replace-attr-values \"#262626=currentColor\" -d src svg",
|
||||
"convert-icons": "node figma-api/pngConverter.js",
|
||||
"convert-icons": "node figma-api/pngConverter.mjs",
|
||||
"clean": "rm -rf src && rm -rf esm && rm -rf cjs && rm -rf png && rm -rf NAV-ikonpakke-png.zip && rm -rf NAV-ikonpakke-svg.zip",
|
||||
"build": "npm run clean && npm run create-icons && tsc && tsc -p tsconfig-esm.json && yarn cjs-package && npm run convert-icons && node figma-api/zipIcons.js"
|
||||
"zip-icons": "node figma-api/zipIcons.mjs",
|
||||
"build": "npm run clean && npm run create-icons && tsc && tsc -p tsconfig-esm.json && yarn create-package-json-pointers-to-esm && npm run convert-icons && yarn zip-icons"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Meta } from "@storybook/addon-docs/blocks";
|
||||
import { Meta } from "@storybook/addon-docs";
|
||||
|
||||
<Meta title="ds-icons/Kom i gang" />
|
||||
|
||||
|
||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,5 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.9565 8C12.6134 8 13.9565 6.65685 13.9565 5C13.9565 3.34315 12.6134 2 10.9565 2C9.29969 2 7.95654 3.34315 7.95654 5C7.95654 6.65685 9.29969 8 10.9565 8ZM10.9565 10C13.718 10 15.9565 7.76142 15.9565 5C15.9565 2.23858 13.718 0 10.9565 0C8.19512 0 5.95654 2.23858 5.95654 5C5.95654 7.76142 8.19512 10 10.9565 10Z" fill="#262626"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.0569 11.5858C19.2758 10.8047 18.0095 10.8047 17.2285 11.5858L15.8143 13C15.0332 13.781 15.0332 15.0474 15.8143 15.8284L16.6856 16.6997L12.1071 21.2782L11.4 21.9853L12.8142 23.3995L13.5213 22.6924L18.0998 18.114L19.0496 19.0637C19.8306 19.8448 21.0969 19.8448 21.878 19.0637L23.2922 17.6495C24.0733 16.8685 24.0733 15.6021 23.2922 14.8211L20.0569 11.5858ZM18.6427 13L21.878 16.2353L20.4638 17.6495L17.2285 14.4142L18.6427 13Z" fill="#262626"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.1594 11.7521C13.2095 11.2709 12.1352 11 11 11C7.13401 11 4 14.134 4 18H6C6 15.2386 8.23858 13 11 13C11.5609 13 12.0993 13.092 12.6014 13.2617L14.1594 11.7521Z" fill="#262626"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 5C16 7.76142 13.7614 10 11 10C8.23858 10 6 7.76142 6 5C6 2.23858 8.23858 0 11 0C13.7614 0 16 2.23858 16 5ZM4 18C4 14.134 7.13401 11 11 11C12.3956 11 13.6959 11.4084 14.7877 12.1123L8.7108 18H4Z" fill="#262626"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M19.2782 12.2854C18.8876 11.9049 18.2545 11.9049 17.8639 12.2854L15.3891 14.6973C14.9985 15.0778 14.9985 15.6949 15.3891 16.0754L16.8033 17.4536L11.5 22.6218L12.9142 24L18.2175 18.8318L19.8085 20.3823C20.199 20.7628 20.8322 20.7628 21.2227 20.3823L23.6976 17.9704C24.0881 17.5899 24.0881 16.9728 23.6976 16.5923L19.2782 12.2854Z" fill="#262626"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 764 B |
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"type": "commonjs",
|
||||
"main": "index.js",
|
||||
"typings": "../esm/index.d.ts",
|
||||
"sideEffects": false
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-react",
|
||||
"version": "0.6.2",
|
||||
"version": "0.7.1",
|
||||
"private": false,
|
||||
"description": "NAV designsystem react components",
|
||||
"author": "NAV Designsystem team",
|
||||
@@ -14,11 +14,10 @@
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/navikt/nav-frontend-moduler/tree/master/%40navikt/ds-react"
|
||||
},
|
||||
"main": "esm/index.js",
|
||||
"module": "esm/index.js",
|
||||
"typings": "esm/index.d.ts",
|
||||
"sideEffects": false,
|
||||
"type": "module",
|
||||
"main": "./cjs/index.js",
|
||||
"module": "./esm/index.js",
|
||||
"typings": "./esm/index.d.ts",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
@@ -28,13 +27,14 @@
|
||||
"/src"
|
||||
],
|
||||
"scripts": {
|
||||
"cjs-package": "copyfiles -f config/package.json cjs",
|
||||
"create-package-json-pointers-to-esm": "node ../../utilities/scripts/createPackageJsonsWithESMPointers.js",
|
||||
"clean": "rm -rf cjs esm",
|
||||
"build": "yarn run clean && tsc && tsc -p tsconfig-esm.json && yarn cjs-package",
|
||||
"build": "yarn run clean && tsc && tsc -p tsconfig-esm.json && yarn create-package-json-pointers-to-esm",
|
||||
"watch": "tsc --watch -p tsconfig-esm.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@navikt/ds-icons": "^0.3.3",
|
||||
"@material-ui/core": "^4.12.2",
|
||||
"@navikt/ds-icons": "^0.5.1",
|
||||
"@popperjs/core": "^2.5.4",
|
||||
"classnames": "^2.2.6",
|
||||
"copy-to-clipboard": "^3.3.1",
|
||||
@@ -42,7 +42,7 @@
|
||||
"react-merge-refs": "^1.1.0",
|
||||
"react-modal": "3.12.1",
|
||||
"react-popper": "^2.2.4",
|
||||
"uuid": "^8.3.2"
|
||||
"short-uuid": "^4.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"copyfiles": "^2.4.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { forwardRef, HTMLAttributes } from "react";
|
||||
import { AccordionMenu as BaseAccordionMenu } from "../accordion-menu";
|
||||
import { Title } from "../index";
|
||||
import { Title } from "..";
|
||||
import { ActiveAnchorProvider } from "./ActiveAnchorStore";
|
||||
import cl from "classnames";
|
||||
|
||||
@@ -8,7 +8,6 @@ export interface AccordionAnchorMenuProps
|
||||
extends HTMLAttributes<HTMLDivElement> {
|
||||
title?: string;
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const AccordionAnchorMenu = forwardRef<
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Meta, Canvas } from "@storybook/addon-docs";
|
||||
import { AccordionAnchorMenu } from "../../index";
|
||||
import { Success } from "@navikt/ds-react";
|
||||
|
||||
<Meta title="ds-react/accordion-anchor-menu/intro" />
|
||||
|
||||
# AccordionAnchorMenu
|
||||
|
||||
NOTE: Komponenten er ikke oppdatert og er veldig buggy. Ville ungått bruk av denne om mulig og bare brukt
|
||||
vanlig `AccordionMenu`. Hvorvidt vi kommer til å oppdatere denne og ta den med i 1.0 er usikkert.
|
||||
|
||||
`AccordionAnchorMenu` er en meny-komponent som implementerer `AccordionMenu` med context
|
||||
for lytting på aktiv anchor/heading. Dette vil si at active-state settes automatisk.
|
||||
når man scroller forbi den relevante linken på siden.
|
||||
@@ -4,7 +4,6 @@ import MenuItems from "./MenuItems";
|
||||
|
||||
export interface AccordionMenuProps extends HTMLAttributes<HTMLElement> {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const AccordionMenu = forwardRef<HTMLElement, AccordionMenuProps>(
|
||||
|
||||
@@ -8,7 +8,6 @@ export interface AccordionMenuCollapsableProps
|
||||
title: string;
|
||||
defaultOpen?: boolean;
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const AccordionMenuCollapsable = forwardRef<
|
||||
@@ -32,6 +31,7 @@ const AccordionMenuCollapsable = forwardRef<
|
||||
{title}
|
||||
<Expand
|
||||
role="img"
|
||||
focusable="false"
|
||||
aria-label={isOpen ? "Pil peker opp" : "Pil peker ned"}
|
||||
className="navds-accordion-menu-collapsable__expand-icon"
|
||||
/>
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import React from "react";
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
const MenuItems = ({ children }: { children: React.ReactNode }) => (
|
||||
<ul className="navds-accordion-menu__list">
|
||||
{React.Children.toArray(children).map((child, i) => (
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
import { Meta, Canvas } from "@storybook/addon-docs";
|
||||
import {
|
||||
AccordionMenu,
|
||||
AccordionMenuItem,
|
||||
AccordionMenuCollapsable,
|
||||
} from "../../index";
|
||||
|
||||
<Meta title="ds-react/accordion-menu/intro" />
|
||||
|
||||
# Hvordan ta i bruk Accordion-menu
|
||||
|
||||
```jsx
|
||||
<AccordionMenu>
|
||||
<AccordionMenuItem href="#leo">Leo</AccordionMenuItem>
|
||||
<AccordionMenuCollapsable title="Proin">
|
||||
<AccordionMenuItem href="#nulla" active>
|
||||
Nulla
|
||||
</AccordionMenuItem>
|
||||
<AccordionMenuItem href="#luctus">Luctus</AccordionMenuItem>
|
||||
</AccordionMenuCollapsable>
|
||||
<AccordionMenuCollapsable title="Accumsan">
|
||||
<AccordionMenuItem href="#justo" aria-current="page">
|
||||
Justo
|
||||
</AccordionMenuItem>
|
||||
<AccordionMenuCollapsable title="Proin">
|
||||
<AccordionMenuItem href="#nulla">Nulla</AccordionMenuItem>
|
||||
<AccordionMenuItem href="#luctus">Luctus</AccordionMenuItem>
|
||||
</AccordionMenuCollapsable>
|
||||
</AccordionMenuCollapsable>
|
||||
</AccordionMenu>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<AccordionMenu>
|
||||
<AccordionMenuItem href="#leo">Leo</AccordionMenuItem>
|
||||
<AccordionMenuCollapsable title="Proin">
|
||||
<AccordionMenuItem href="#nulla" active>
|
||||
Nulla
|
||||
</AccordionMenuItem>
|
||||
<AccordionMenuItem href="#luctus">Luctus</AccordionMenuItem>
|
||||
</AccordionMenuCollapsable>
|
||||
<AccordionMenuCollapsable title="Accumsan">
|
||||
<AccordionMenuItem href="#justo" aria-current="page">
|
||||
Justo
|
||||
</AccordionMenuItem>
|
||||
<AccordionMenuCollapsable title="Proin">
|
||||
<AccordionMenuItem href="#nulla">Nulla</AccordionMenuItem>
|
||||
<AccordionMenuItem href="#luctus">Luctus</AccordionMenuItem>
|
||||
</AccordionMenuCollapsable>
|
||||
</AccordionMenuCollapsable>
|
||||
</AccordionMenu>
|
||||
</Canvas>
|
||||
|
||||
Accordion-menu støtter opp til maks to-nivårer av `AccordionMenuCollapsable` akkurat nå.
|
||||
|
||||
`AccordionMenuItem` er implementert med `OverridableComponent`, noe som
|
||||
gjør at man kan ta i bruk eks react-router slik:
|
||||
|
||||
```jsx
|
||||
<Item
|
||||
component={NavLink}
|
||||
activeClassName="navds-accordion-menu-item--active"
|
||||
to="/1"
|
||||
>
|
||||
Lenketekst
|
||||
</Item>
|
||||
```
|
||||
|
||||
Her er `NavLink` fra `react-router-dom` brukt, og man får da
|
||||
samtidig bruke alle propsene til denne komponenten som da er `activeClassName` her.
|
||||
@@ -42,10 +42,10 @@ export const All = () => (
|
||||
<Item href="#luctus">Luctus</Item>
|
||||
</Collapsable>
|
||||
<Collapsable title="Accumsan">
|
||||
<Item href="#justo" ariaCurrent="page">
|
||||
<Item href="#justo" aria-current="page">
|
||||
Justo
|
||||
</Item>
|
||||
<Item href="#pariatur" active ariaCurrent="page">
|
||||
<Item href="#pariatur" active aria-current="page">
|
||||
Pariatur
|
||||
</Item>
|
||||
<Collapsable title="Proin">
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React, { forwardRef, useEffect, useState } from "react";
|
||||
import cl from "classnames";
|
||||
import { UnmountClosed, Collapse } from "react-collapse";
|
||||
import { Expand } from "@navikt/ds-icons";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { Expand, ExpandFilled } from "@navikt/ds-icons";
|
||||
import { useId } from "..";
|
||||
|
||||
export interface AccordionProps
|
||||
extends React.HTMLAttributes<HTMLButtonElement> {
|
||||
@@ -10,10 +10,6 @@ export interface AccordionProps
|
||||
* Component content
|
||||
*/
|
||||
children: React.ReactNode;
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
className?: string;
|
||||
/**
|
||||
* Content on interactive surface of component
|
||||
*/
|
||||
@@ -26,8 +22,6 @@ export interface AccordionProps
|
||||
open?: boolean;
|
||||
/**
|
||||
* Callback for when user interacts with component
|
||||
*
|
||||
* @param {object} event
|
||||
*/
|
||||
onClick?: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
|
||||
/**
|
||||
@@ -46,19 +40,15 @@ const Accordion = forwardRef<HTMLButtonElement, AccordionProps>(
|
||||
className,
|
||||
renderContentWhenClosed = false,
|
||||
onClick,
|
||||
id,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const [contentId, setContentId] = useState("");
|
||||
const [buttonId, setButtonId] = useState("");
|
||||
const [internalOpen, setInternalOpen] = useState<boolean>(open);
|
||||
|
||||
// Forsøk på å fikse Nextjs SSR server/client clock problem
|
||||
useEffect(() => {
|
||||
setContentId(() => uuidv4());
|
||||
setButtonId(() => uuidv4());
|
||||
}, []);
|
||||
const buttonId = useId(id);
|
||||
const contentId = useId();
|
||||
|
||||
useEffect(() => {
|
||||
setInternalOpen(open);
|
||||
@@ -88,11 +78,22 @@ const Accordion = forwardRef<HTMLButtonElement, AccordionProps>(
|
||||
{heading}
|
||||
</span>
|
||||
<Expand
|
||||
focusable="false"
|
||||
role="img"
|
||||
className={cl(
|
||||
"navds-accordion__chevron",
|
||||
`navds-accordion__chevron--${internalOpen ? "up" : "down"}`
|
||||
)}
|
||||
/>
|
||||
<ExpandFilled
|
||||
focusable="false"
|
||||
role="img"
|
||||
className={cl(
|
||||
"navds-accordion__chevron",
|
||||
"navds-accordion__chevron--filled",
|
||||
`navds-accordion__chevron--${internalOpen ? "up" : "down"}`
|
||||
)}
|
||||
/>
|
||||
</button>
|
||||
<div id={contentId} role="region" aria-labelledby={buttonId}>
|
||||
<CollapseComponent isOpened={internalOpen}>
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { Meta, Canvas } from "@storybook/addon-docs";
|
||||
import { Accordion } from "../../index";
|
||||
|
||||
<Meta title="ds-react/accordion/intro" />
|
||||
|
||||
# Hvordan ta i bruk Accordion
|
||||
|
||||
```jsx
|
||||
<Accordion heading="Qui id id ad cupidatat ullamco.">
|
||||
Et anim nostrud reprehenderit duis eu tempor et irure proident. Eu ea occaecat
|
||||
aliqua commodo sunt. Sit cupidatat ad id occaecat exercitation ipsum laboris
|
||||
duis velit consequat adipisicing do amet aute. Aliquip culpa minim commodo
|
||||
laborum eiusmod eu magna elit veniam ullamco ullamco minim.
|
||||
</Accordion>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Accordion heading="Qui id id ad cupidatat ullamco.">
|
||||
Et anim nostrud reprehenderit duis eu tempor et irure proident. Eu ea
|
||||
occaecat aliqua commodo sunt. Sit cupidatat ad id occaecat exercitation
|
||||
ipsum laboris duis velit consequat adipisicing do amet aute. Aliquip culpa
|
||||
minim commodo laborum eiusmod eu magna elit veniam ullamco ullamco minim.
|
||||
</Accordion>
|
||||
</Canvas>
|
||||
|
||||
Accordion-komponeten styrer selv open/closed state, men om man ønsker kan man selv overskrive denne med
|
||||
`open`-prop + `onClick`-prop.
|
||||
|
||||
Note: Hvis man tar i bruk `onClick`, så tolker komponeten det slik at du ønsker å styre state selv, så
|
||||
man må da også bruke `open`-prop
|
||||
|
||||
`renderContentWhenClosed`-prop bestemmer om innholdet (children) skal beholdes i dom-strukturen mens
|
||||
Accordion er lukket. Defaulter til `false`.
|
||||
@@ -12,17 +12,10 @@ export interface AlertProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
* Decides what design the alert will have
|
||||
*/
|
||||
variant: "error" | "warning" | "info" | "success";
|
||||
/**
|
||||
* Component content
|
||||
*/
|
||||
children: React.ReactNode;
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
className?: string;
|
||||
/**
|
||||
* Reduces padding on component
|
||||
* @default "medium"
|
||||
* Changes padding and font-sizes
|
||||
* @default "m"
|
||||
*/
|
||||
size?: "m" | "s";
|
||||
}
|
||||
@@ -30,13 +23,37 @@ export interface AlertProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
const Icon = ({ variant }) => {
|
||||
switch (variant) {
|
||||
case "error":
|
||||
return <ErrorFilled />;
|
||||
return (
|
||||
<ErrorFilled
|
||||
aria-label={`${variant}-ikon`}
|
||||
focusable="false"
|
||||
role="img"
|
||||
/>
|
||||
);
|
||||
case "warning":
|
||||
return <WarningFilled />;
|
||||
return (
|
||||
<WarningFilled
|
||||
aria-label={`${variant}-ikon`}
|
||||
focusable="false"
|
||||
role="img"
|
||||
/>
|
||||
);
|
||||
case "info":
|
||||
return <InformationFilled />;
|
||||
return (
|
||||
<InformationFilled
|
||||
aria-label={`${variant}-ikon`}
|
||||
focusable="false"
|
||||
role="img"
|
||||
/>
|
||||
);
|
||||
case "success":
|
||||
return <SuccessFilled />;
|
||||
return (
|
||||
<SuccessFilled
|
||||
aria-label={`${variant}-ikon`}
|
||||
focusable="false"
|
||||
role="img"
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -52,12 +69,15 @@ const Alert = forwardRef<HTMLDivElement, AlertProps>(
|
||||
`navds-alert--${variant}`,
|
||||
`navds-alert--${size}`,
|
||||
"navds-body-long",
|
||||
"navds-body--s"
|
||||
{ "navds-body--s": size === "s" }
|
||||
)}
|
||||
{...rest}
|
||||
>
|
||||
<Icon variant={variant} />
|
||||
<span>{children}</span>
|
||||
<span>
|
||||
<span className="sr-only">{`${variant}-ikon`}</span>
|
||||
<Icon variant={variant} />
|
||||
</span>
|
||||
<div>{children}</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import { Meta, Canvas } from "@storybook/addon-docs";
|
||||
import { Alert } from "../../index";
|
||||
|
||||
<Meta title="ds-react/alert/intro" />
|
||||
|
||||
# Hvordan ta i bruk Alert
|
||||
|
||||
```jsx
|
||||
<Alert variant="info">
|
||||
Id elit esse enim reprehenderit.Tempor tempor ex exercitation id aute
|
||||
eu.Laborum nulla nisi irure voluptate mollit fugiat.Est quis culpa nostrud et
|
||||
reprehenderit ea sint.Eu veniam labore enim labore qui eiusmod Lorem amet ad
|
||||
esse.
|
||||
</Alert>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Alert variant="info">
|
||||
Id elit esse enim reprehenderit.Tempor tempor ex exercitation id aute
|
||||
eu.Laborum nulla nisi irure voluptate mollit fugiat.Est quis culpa nostrud
|
||||
et reprehenderit ea sint.Eu veniam labore enim labore qui eiusmod Lorem amet
|
||||
ad esse.
|
||||
</Alert>
|
||||
</Canvas>
|
||||
|
||||
## Varianter
|
||||
|
||||
`variants`-prop kan brukes for å endre utseende mellom
|
||||
`info`, `success`, `warning` og `error`
|
||||
|
||||
<Canvas>
|
||||
<Alert variant="info">Id elit esse enim reprehenderit.</Alert>
|
||||
<Alert variant="success">Id elit esse enim reprehenderit.</Alert>
|
||||
<Alert variant="warning">Id elit esse enim reprehenderit.</Alert>
|
||||
<Alert variant="error">Id elit esse enim reprehenderit.</Alert>
|
||||
</Canvas>
|
||||
|
||||
## Sizing
|
||||
|
||||
Alert har to størrelser: Default 64px min-height og small 32px min-height
|
||||
|
||||
<Canvas>
|
||||
<Alert size="s" variant="info">
|
||||
Id elit esse enim reprehenderit.
|
||||
</Alert>
|
||||
<Alert size="s" variant="success">
|
||||
Id elit esse enim reprehenderit.
|
||||
</Alert>
|
||||
<Alert size="s" variant="warning">
|
||||
Id elit esse enim reprehenderit.
|
||||
</Alert>
|
||||
<Alert size="s" variant="error">
|
||||
Id elit esse enim reprehenderit.
|
||||
</Alert>
|
||||
</Canvas>
|
||||
@@ -19,14 +19,19 @@ export const All = () => {
|
||||
<h1>Alert</h1>
|
||||
{variants.map((variant) => (
|
||||
<Alert key={variant} variant={variant}>
|
||||
{Array(8).fill(`${variant} content`).join(" ")}
|
||||
Id elit esse enim reprehenderit.Tempor tempor ex exercitation id aute
|
||||
eu.Laborum nulla nisi irure voluptate mollit fugiat.Est quis culpa
|
||||
nostrud et reprehenderit ea sint.Eu veniam labore enim labore qui
|
||||
eiusmod Lorem amet ad esse.
|
||||
</Alert>
|
||||
))}
|
||||
<h2>Small</h2>
|
||||
<div>
|
||||
{variants.map((variant) => (
|
||||
<Alert key={variant} variant={variant} size="s">
|
||||
{Array(8).fill(`${variant} content`).join(" ")}
|
||||
Exercitation enim nisi veniam nostrud Lorem ipsum ea fugiat. Aute
|
||||
exercitation voluptate proident sit ex reprehenderit quis ex ut
|
||||
mollit.
|
||||
</Alert>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -7,21 +7,18 @@ export interface ButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
|
||||
*/
|
||||
children: React.ReactNode;
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
className?: string;
|
||||
/**
|
||||
* Decides component design and interactions
|
||||
* Changes design and interactions
|
||||
* @default "primary"
|
||||
*/
|
||||
variant?: "primary" | "secondary" | "action" | "danger";
|
||||
/**
|
||||
* Reduces internal padding for component
|
||||
* @default "medium"
|
||||
* Changes padding, height and font-size
|
||||
* @default "m"
|
||||
*/
|
||||
size?: "m" | "s";
|
||||
/**
|
||||
* Prevent the user from interacting with the button: it cannot be pressed or focused.
|
||||
* @note Avoid using if possible for accessibility purposes
|
||||
* @default false
|
||||
*/
|
||||
disabled?: boolean;
|
||||
@@ -36,7 +33,8 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
"navds-button",
|
||||
`navds-button--${variant}`,
|
||||
`navds-button--${size}`,
|
||||
"navds-body-short"
|
||||
"navds-body-short",
|
||||
{ "navds-body--s": size === "s" }
|
||||
)}
|
||||
{...rest}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import { Meta, Canvas } from "@storybook/addon-docs";
|
||||
import { Button, Loader } from "../../index";
|
||||
import { Success } from "@navikt/ds-react";
|
||||
|
||||
<Meta title="ds-react/button/intro" />
|
||||
|
||||
# Hvordan ta i bruk Button
|
||||
|
||||
```jsx
|
||||
<Button>Buttontekst</Button>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Button>Buttontekst</Button>
|
||||
</Canvas>
|
||||
|
||||
## Varianter
|
||||
|
||||
`variants`-prop kan brukes for å endre utseende mellom
|
||||
`primary`, `secondary`, `action` og `danger`
|
||||
|
||||
<Canvas>
|
||||
<Button variant="primary">Buttontekst</Button>
|
||||
<Button variant="secondary">Buttontekst</Button>
|
||||
<Button variant="action">Buttontekst</Button>
|
||||
<Button variant="danger">Buttontekst</Button>
|
||||
</Canvas>
|
||||
|
||||
## Sizing
|
||||
|
||||
Button har to størrelser: Default 48px min-height og small 32px min-height
|
||||
|
||||
<Canvas>
|
||||
<Button size="s" variant="primary">
|
||||
Buttontekst
|
||||
</Button>
|
||||
<Button size="s" variant="secondary">
|
||||
Buttontekst
|
||||
</Button>
|
||||
<Button size="s" variant="action">
|
||||
Buttontekst
|
||||
</Button>
|
||||
<Button size="s" variant="danger">
|
||||
Buttontekst
|
||||
</Button>
|
||||
</Canvas>
|
||||
|
||||
## Med ikon eller `<Loader />`
|
||||
|
||||
Hvis man setter ikoner (svg) eller `<Loader />` rett på button vil størrelsen
|
||||
bli justert automatisk. For å få riktige marginer rundt ikonet må man da wrappe innholdet
|
||||
i et element
|
||||
|
||||
<Canvas>
|
||||
<Button>
|
||||
<span>Buttontekst</span> <Loader />
|
||||
</Button>
|
||||
<Button size="s">
|
||||
<span>Buttontekst</span>
|
||||
<Loader />
|
||||
</Button>
|
||||
<Button>
|
||||
<Loader /> <span>Buttontekst</span>
|
||||
</Button>
|
||||
</Canvas>
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from "react";
|
||||
import { Button } from "../index";
|
||||
import { Success } from "@navikt/ds-icons";
|
||||
|
||||
export default {
|
||||
title: "ds-react/button",
|
||||
@@ -52,7 +53,7 @@ export const All = () => {
|
||||
{variants.map((variant) => (
|
||||
<a
|
||||
key={variant}
|
||||
className={`navds-button navds-button--${variant}`}
|
||||
className={`navds-button navds-button--${variant} navds-body-short`}
|
||||
href="the-link"
|
||||
>
|
||||
{variant}
|
||||
@@ -67,6 +68,30 @@ export const All = () => {
|
||||
</Button>
|
||||
))}
|
||||
</Section>
|
||||
<h2>Button w/icon</h2>
|
||||
<Section>
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant}>
|
||||
<span>{variant}</span> <Success />
|
||||
</Button>
|
||||
))}
|
||||
</Section>
|
||||
<h2>Small w/icon</h2>
|
||||
<Section>
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} size="s">
|
||||
<Success /> <span>{variant}</span>
|
||||
</Button>
|
||||
))}
|
||||
</Section>
|
||||
<Section>
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} size="s">
|
||||
<span className="sr-only">Success ikon</span>
|
||||
<Success />
|
||||
</Button>
|
||||
))}
|
||||
</Section>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -5,10 +5,6 @@ import { OverridableComponent } from "../util";
|
||||
export interface MicroCardProps {
|
||||
props: {
|
||||
children: string;
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
className?: string;
|
||||
} & React.HTMLAttributes<HTMLAnchorElement>;
|
||||
defaultComponent: "a";
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Meta } from "@storybook/addon-docs/blocks";
|
||||
import { Meta, Canvas } from "@storybook/addon-docs";
|
||||
import { MicroCard } from "../index.ts";
|
||||
|
||||
<Meta title="ds-react/card/intro" />
|
||||
|
||||
@@ -12,9 +13,13 @@ Kan brukes som en vanlig lenke direkte:
|
||||
<MicroCard href="/lenke/til/side">Lenketekst</MicroCard>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<MicroCard href="/lenke/til/side">Lenketekst</MicroCard>
|
||||
</Canvas>
|
||||
|
||||
Hvis man ønsker å ta i bruk nextjs sin `Link`-komponent:
|
||||
|
||||
```
|
||||
```jsx
|
||||
<Link href="/lenke/til/side" passHref>
|
||||
<MicroCard>Lenketekst</MicroCard>
|
||||
</Link>
|
||||
|
||||
@@ -2,10 +2,6 @@ import React, { forwardRef, HTMLAttributes } from "react";
|
||||
import cl from "classnames";
|
||||
|
||||
export interface ContentContainerProps extends HTMLAttributes<HTMLDivElement> {
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
classNames?: string;
|
||||
/**
|
||||
* Component content
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { Meta, Canvas } from "@storybook/addon-docs";
|
||||
|
||||
<Meta title="ds-react/content-container/intro" />
|
||||
|
||||
# Hvordan ta i bruk ContentContainer
|
||||
|
||||
```jsx
|
||||
<ContentContainer>
|
||||
<div>innhold...</div>
|
||||
</ContentContainer>
|
||||
```
|
||||
|
||||
## Bruk
|
||||
|
||||
Komponenten fungerer som en wrapper rundt innholdet ditt på siden for å
|
||||
justere padding og max-width. Dette er all stylingen som blir applied
|
||||
|
||||
```css
|
||||
.navds-content-container {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: var(--navds-content-container-max-width);
|
||||
padding: var(--navds-content-container-padding-small);
|
||||
}
|
||||
|
||||
@media (min-width: 448px) {
|
||||
.navds-content-container {
|
||||
padding: var(--navds-content-container-padding-medium-and-larger);
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -9,10 +9,14 @@ import React, {
|
||||
useState,
|
||||
} from "react";
|
||||
import mergeRefs from "react-merge-refs";
|
||||
import { Popover, Button } from "../index";
|
||||
import { Popover, Button } from "..";
|
||||
|
||||
export interface CopyToClipboardProps
|
||||
extends HTMLAttributes<HTMLButtonElement> {
|
||||
/**
|
||||
* Button text
|
||||
*/
|
||||
children?: React.ReactNode;
|
||||
/**
|
||||
* Text to be copied to clipboard
|
||||
*/
|
||||
@@ -61,7 +65,15 @@ const CopyToClipboard = forwardRef<HTMLButtonElement, CopyToClipboardProps>(
|
||||
onClick={handleClick}
|
||||
{...rest}
|
||||
>
|
||||
{icon ? <>{icon}</> : <Copy aria-label="Fil ikon for kopiering" />}
|
||||
{icon ? (
|
||||
<>{icon}</>
|
||||
) : (
|
||||
<Copy
|
||||
focusable="false"
|
||||
role="img"
|
||||
aria-label="Fil ikon for kopiering"
|
||||
/>
|
||||
)}
|
||||
{children ? children : <span className="sr-only">{title}</span>}
|
||||
</Button>
|
||||
<Popover
|
||||
|
||||
@@ -9,7 +9,7 @@ export default {
|
||||
};
|
||||
|
||||
export const All = () => {
|
||||
const label = "pi";
|
||||
const label = "Kopierte PI til clipboard";
|
||||
|
||||
const text = "3.14159265359";
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { Meta, Canvas } from "@storybook/addon-docs";
|
||||
import { CopyToClipboard } from "../../index";
|
||||
import { Success } from "@navikt/ds-react";
|
||||
|
||||
<Meta title="ds-react/copy-to-clipboard/intro" />
|
||||
|
||||
# Hvordan ta i bruk CopyToClipboard
|
||||
|
||||
Innholdet i `text` vil da bli kopiert til clipboard, mens innholdet i `label`
|
||||
brukes i popovertekst og `sr-only` span som rendres hvis knappen ikke har noe tekstinnhold
|
||||
`sr-only` tekst blir da `Kopier ${label} (${text})`
|
||||
|
||||
```jsx
|
||||
<CopyToClipboard label={"Kopierte PI til clipboard"} text={"3.14"}>
|
||||
Kopier Pi{" "}
|
||||
</CopyToClipboard>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<CopyToClipboard label={"Kopierte PI til clipboard"} text={"3.14"}>
|
||||
Kopier Pi{" "}
|
||||
</CopyToClipboard>
|
||||
</Canvas>
|
||||
|
||||
## Custom ikon
|
||||
|
||||
Man kan sette andre ikoner en `Copy` ved `icon`-proppen
|
||||
|
||||
```jsx
|
||||
<CopyToClipboard
|
||||
icon={<Link />}
|
||||
label={"Kopierte PI til clipboard"}
|
||||
text={"3.14"}
|
||||
/>
|
||||
```
|
||||
@@ -0,0 +1,45 @@
|
||||
import React, { forwardRef } from "react";
|
||||
import cl from "classnames";
|
||||
import { BodyLong, Checkbox, CheckboxProps } from "..";
|
||||
|
||||
export interface ConfirmationPanelProps extends Partial<CheckboxProps> {
|
||||
/**
|
||||
* Additional information on panel
|
||||
*/
|
||||
children?: React.ReactNode;
|
||||
/**
|
||||
* Checkbox label
|
||||
*/
|
||||
label: string;
|
||||
/**
|
||||
* Checked state for checkbox
|
||||
*/
|
||||
checked: boolean;
|
||||
}
|
||||
|
||||
const ConfirmationPanel = forwardRef<HTMLDivElement, ConfirmationPanelProps>(
|
||||
({ className, children, label, ...props }, ref) => {
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cl("navds-confirmation-panel", className, {
|
||||
"navds-confirmation-panel--s": props.size === "s",
|
||||
"navds-confirmation-panel--error": !!props.error,
|
||||
"navds-confirmation-panel--checked": !!props.checked,
|
||||
})}
|
||||
>
|
||||
{children && (
|
||||
<BodyLong
|
||||
size={props.size}
|
||||
className="navds-confirmation-panel__content"
|
||||
>
|
||||
{children}
|
||||
</BodyLong>
|
||||
)}
|
||||
<Checkbox {...props}>{label}</Checkbox>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default ConfirmationPanel;
|
||||
@@ -0,0 +1,17 @@
|
||||
import React from "react";
|
||||
import cl from "classnames";
|
||||
import { Label } from "..";
|
||||
|
||||
const ErrorMessage = (props) => (
|
||||
<Label
|
||||
{...props}
|
||||
component="div"
|
||||
className={cl(
|
||||
"navds-error-message",
|
||||
props.className,
|
||||
`navds-error-message--${props.size ?? "m"}`
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
||||
export default ErrorMessage;
|
||||
@@ -0,0 +1,132 @@
|
||||
import cl from "classnames";
|
||||
import React, { FieldsetHTMLAttributes, forwardRef, useContext } from "react";
|
||||
import { BodyShort, Label, omit } from "../..";
|
||||
import ErrorMessage from "../ErrorMessage";
|
||||
import { FormFieldProps } from "../useFormField";
|
||||
import { useFieldset } from "./useFieldset";
|
||||
|
||||
export type FieldsetContextProps = {
|
||||
/**
|
||||
* Error message applied to element
|
||||
*/
|
||||
error?: React.ReactNode;
|
||||
/**
|
||||
* Overrides internal errorId
|
||||
*/
|
||||
errorId: string;
|
||||
/**
|
||||
* Changes paddings, margins and font-sizes
|
||||
*/
|
||||
size: "m" | "s";
|
||||
disabled: boolean;
|
||||
};
|
||||
|
||||
export const FieldsetContext = React.createContext<FieldsetContextProps | null>(
|
||||
null
|
||||
);
|
||||
export interface FieldsetProps
|
||||
extends FormFieldProps,
|
||||
FieldsetHTMLAttributes<HTMLFieldSetElement> {
|
||||
/**
|
||||
* FormFields in Fieldset
|
||||
*/
|
||||
children: React.ReactNode;
|
||||
/**
|
||||
* Fieldset legend
|
||||
*/
|
||||
legend: React.ReactNode;
|
||||
/**
|
||||
* If enabled shows the legend and description for screenreaders only
|
||||
*/
|
||||
hideLegend?: boolean;
|
||||
/**
|
||||
* Toggles error propagation to child-elements
|
||||
* @default true
|
||||
*/
|
||||
errorPropagation?: boolean;
|
||||
}
|
||||
|
||||
const Fieldset = forwardRef<HTMLFieldSetElement, FieldsetProps>(
|
||||
(props, ref) => {
|
||||
const {
|
||||
inputProps,
|
||||
errorId,
|
||||
showErrorMsg,
|
||||
hasError,
|
||||
size,
|
||||
inputDescriptionId,
|
||||
} = useFieldset(props);
|
||||
|
||||
const fieldset = useContext(FieldsetContext);
|
||||
|
||||
const {
|
||||
children,
|
||||
className,
|
||||
errorPropagation = true,
|
||||
legend,
|
||||
description,
|
||||
hideLegend,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<FieldsetContext.Provider
|
||||
value={{
|
||||
error: errorPropagation ? props.error ?? fieldset?.error : undefined,
|
||||
errorId: cl({
|
||||
[errorId]: showErrorMsg,
|
||||
[fieldset?.errorId ?? ""]: !!fieldset?.error,
|
||||
}),
|
||||
size,
|
||||
disabled: props.disabled ?? false,
|
||||
}}
|
||||
>
|
||||
<fieldset
|
||||
{...omit(rest, ["errorId"])}
|
||||
{...inputProps}
|
||||
ref={ref}
|
||||
className={cl(
|
||||
className,
|
||||
"navds-fieldset",
|
||||
`navds-fieldset--${size}`,
|
||||
{ "navds-fieldset--error": hasError }
|
||||
)}
|
||||
>
|
||||
<Label
|
||||
size={size}
|
||||
component="legend"
|
||||
className={cl("navds-fieldset__legend", {
|
||||
"sr-only": !!hideLegend,
|
||||
})}
|
||||
>
|
||||
{legend}
|
||||
</Label>
|
||||
{!!description && (
|
||||
<BodyShort
|
||||
className={cl("navds-fieldset__description", {
|
||||
"sr-only": !!hideLegend,
|
||||
})}
|
||||
id={inputDescriptionId}
|
||||
size={size}
|
||||
>
|
||||
{description}
|
||||
</BodyShort>
|
||||
)}
|
||||
{children}
|
||||
<div
|
||||
id={errorId}
|
||||
aria-relevant="additions removals"
|
||||
aria-live="polite"
|
||||
className="navds-fieldset__error"
|
||||
>
|
||||
{showErrorMsg && (
|
||||
<ErrorMessage size={size}>{props.error}</ErrorMessage>
|
||||
)}
|
||||
</div>
|
||||
</fieldset>
|
||||
</FieldsetContext.Provider>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default Fieldset;
|
||||
@@ -0,0 +1 @@
|
||||
export { default, FieldsetProps, FieldsetContext } from "./Fieldset";
|
||||
@@ -0,0 +1,17 @@
|
||||
import { useFormField } from "../useFormField";
|
||||
|
||||
/**
|
||||
* Handles props for Fieldset in context with parent Fieldset.
|
||||
*/
|
||||
export const useFieldset = (props) => {
|
||||
const formField = useFormField(props, "fieldset");
|
||||
const { inputProps } = formField;
|
||||
|
||||
return {
|
||||
...formField,
|
||||
inputProps: {
|
||||
"aria-invalid": inputProps["aria-invalid"],
|
||||
"aria-describedby": inputProps["aria-describedby"],
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,103 @@
|
||||
import React, { forwardRef, SelectHTMLAttributes } from "react";
|
||||
import cl from "classnames";
|
||||
import { Expand } from "@navikt/ds-icons";
|
||||
import { BodyShort, Label } from "..";
|
||||
import ErrorMessage from "./ErrorMessage";
|
||||
import { FormFieldProps, useFormField } from "./useFormField";
|
||||
|
||||
export interface SelectProps
|
||||
extends FormFieldProps,
|
||||
Omit<SelectHTMLAttributes<HTMLSelectElement>, "size"> {
|
||||
/**
|
||||
* Collection of <option>-elements
|
||||
*/
|
||||
children: React.ReactNode;
|
||||
/**
|
||||
* Expose the HTML size attribute
|
||||
*/
|
||||
htmlSize?: number;
|
||||
/**
|
||||
* Label for select
|
||||
*/
|
||||
label: string;
|
||||
/**
|
||||
* If enabled shows the label and description for screenreaders only
|
||||
*/
|
||||
hideLabel?: boolean;
|
||||
}
|
||||
|
||||
const Select = forwardRef<HTMLSelectElement, SelectProps>((props, ref) => {
|
||||
const {
|
||||
inputProps,
|
||||
errorId,
|
||||
showErrorMsg,
|
||||
hasError,
|
||||
size,
|
||||
inputDescriptionId,
|
||||
} = useFormField(props, "textField");
|
||||
|
||||
const {
|
||||
children,
|
||||
label,
|
||||
className,
|
||||
description,
|
||||
htmlSize,
|
||||
hideLabel = false,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cl(
|
||||
props.className,
|
||||
"navds-form-field",
|
||||
`navds-form-field--${size}`,
|
||||
{ "navds-select--error": hasError }
|
||||
)}
|
||||
>
|
||||
<Label
|
||||
htmlFor={inputProps.id}
|
||||
size={size}
|
||||
component="label"
|
||||
className={cl("navds-select__label", {
|
||||
"sr-only": hideLabel,
|
||||
})}
|
||||
>
|
||||
{label}
|
||||
</Label>
|
||||
{!!description && (
|
||||
<BodyShort
|
||||
className={cl("navds-select__description", {
|
||||
"sr-only": hideLabel,
|
||||
})}
|
||||
id={inputDescriptionId}
|
||||
size={size}
|
||||
>
|
||||
{description}
|
||||
</BodyShort>
|
||||
)}
|
||||
<div className="navds-select__container">
|
||||
<select
|
||||
{...rest}
|
||||
{...inputProps}
|
||||
ref={ref}
|
||||
className={cl(
|
||||
className,
|
||||
"navds-select__input",
|
||||
"navds-body-short",
|
||||
`navds-body--${size ?? "m"}`
|
||||
)}
|
||||
size={props.htmlSize}
|
||||
>
|
||||
{children}
|
||||
</select>
|
||||
<Expand className="navds-select__chevron" />
|
||||
</div>
|
||||
<div id={errorId} aria-relevant="additions removals" aria-live="polite">
|
||||
{showErrorMsg && <ErrorMessage size={size}>{props.error}</ErrorMessage>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default Select;
|
||||
@@ -0,0 +1,92 @@
|
||||
import React, { forwardRef, InputHTMLAttributes } from "react";
|
||||
import cl from "classnames";
|
||||
import { BodyShort, Label } from "..";
|
||||
import ErrorMessage from "./ErrorMessage";
|
||||
import { FormFieldProps, useFormField } from "./useFormField";
|
||||
|
||||
export interface TextFieldProps
|
||||
extends FormFieldProps,
|
||||
Omit<InputHTMLAttributes<HTMLInputElement>, "size"> {
|
||||
/**
|
||||
* Expose the HTML size attribute
|
||||
*/
|
||||
htmlSize?: number;
|
||||
/**
|
||||
* If enabled shows the label and description for screenreaders only
|
||||
*/
|
||||
hideLabel?: boolean;
|
||||
/**
|
||||
* TextField label
|
||||
*/
|
||||
label: React.ReactNode;
|
||||
}
|
||||
|
||||
const TextField = forwardRef<HTMLInputElement, TextFieldProps>((props, ref) => {
|
||||
const {
|
||||
inputProps,
|
||||
errorId,
|
||||
showErrorMsg,
|
||||
hasError,
|
||||
size,
|
||||
inputDescriptionId,
|
||||
} = useFormField(props, "textField");
|
||||
|
||||
const {
|
||||
label,
|
||||
className,
|
||||
description,
|
||||
htmlSize,
|
||||
hideLabel = false,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cl(
|
||||
props.className,
|
||||
"navds-form-field",
|
||||
`navds-form-field--${size}`,
|
||||
{ "navds-text-field--error": hasError }
|
||||
)}
|
||||
>
|
||||
<Label
|
||||
htmlFor={inputProps.id}
|
||||
size={size}
|
||||
component="label"
|
||||
className={cl("navds-text-field__label", { "sr-only": hideLabel })}
|
||||
>
|
||||
{label}
|
||||
</Label>
|
||||
|
||||
{!!description && (
|
||||
<BodyShort
|
||||
className={cl("navds-text-field__description", {
|
||||
"sr-only": hideLabel,
|
||||
})}
|
||||
id={inputDescriptionId}
|
||||
size={size}
|
||||
>
|
||||
{description}
|
||||
</BodyShort>
|
||||
)}
|
||||
<input
|
||||
{...rest}
|
||||
{...inputProps}
|
||||
ref={ref}
|
||||
type="text"
|
||||
className={cl(
|
||||
className,
|
||||
"navds-text-field__input",
|
||||
"navds-body-short",
|
||||
`navds-body-${size ?? "m"}`
|
||||
)}
|
||||
size={htmlSize}
|
||||
/>
|
||||
<div id={errorId} aria-relevant="additions removals" aria-live="polite">
|
||||
{showErrorMsg && <ErrorMessage size={size}>{props.error}</ErrorMessage>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default TextField;
|
||||
@@ -0,0 +1,153 @@
|
||||
import React, { forwardRef } from "react";
|
||||
import cl from "classnames";
|
||||
import TextareaAutosize from "@material-ui/core/TextareaAutosize";
|
||||
import { BodyShort, Label } from "..";
|
||||
import ErrorMessage from "./ErrorMessage";
|
||||
import { FormFieldProps, useFormField } from "./useFormField";
|
||||
import { useId } from "..";
|
||||
|
||||
/**
|
||||
* TODO: Mulighet for lokalisering av sr-only/counter text
|
||||
*/
|
||||
export interface TextareaProps
|
||||
extends FormFieldProps,
|
||||
React.TextareaHTMLAttributes<HTMLTextAreaElement> {
|
||||
/**
|
||||
* Visually allowed length of content
|
||||
*/
|
||||
maxLength?: number;
|
||||
value: string;
|
||||
onChange: React.ChangeEventHandler<HTMLTextAreaElement>;
|
||||
/**
|
||||
* Maximum number of rows to display.
|
||||
* @bug Internal scrolling with `maxLength` scrolls over maxLength-text
|
||||
*/
|
||||
maxRows?: number;
|
||||
/**
|
||||
* Minimum number of rows to display.
|
||||
*/
|
||||
minRows?: number;
|
||||
/**
|
||||
* Textarea label
|
||||
*/
|
||||
label: React.ReactNode;
|
||||
/**
|
||||
* If enabled shows the label and description for screenreaders only
|
||||
*/
|
||||
hideLabel?: boolean;
|
||||
}
|
||||
|
||||
const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
(props, ref) => {
|
||||
const {
|
||||
inputProps,
|
||||
errorId,
|
||||
showErrorMsg,
|
||||
hasError,
|
||||
size,
|
||||
inputDescriptionId,
|
||||
} = useFormField(props, "textarea");
|
||||
|
||||
const {
|
||||
label,
|
||||
className,
|
||||
description,
|
||||
maxLength,
|
||||
hideLabel = false,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
const maxLengthId = `TextareaMaxLength-${useId()}`;
|
||||
const hasMaxLength = maxLength !== undefined && maxLength > 0;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cl(
|
||||
props.className,
|
||||
"navds-form-field",
|
||||
`navds-form-field--${size}`,
|
||||
{ "navds-textarea--error": hasError }
|
||||
)}
|
||||
>
|
||||
<Label
|
||||
htmlFor={inputProps.id}
|
||||
size={size}
|
||||
component="label"
|
||||
className={cl("navds-textarea__label", {
|
||||
"sr-only": hideLabel,
|
||||
})}
|
||||
>
|
||||
{label}
|
||||
</Label>
|
||||
{!!description && (
|
||||
<BodyShort
|
||||
className={cl("navds-textarea__description", {
|
||||
"sr-only": hideLabel,
|
||||
})}
|
||||
id={inputDescriptionId}
|
||||
size={size}
|
||||
>
|
||||
{description}
|
||||
</BodyShort>
|
||||
)}
|
||||
<div className="navds-textarea__wrapper">
|
||||
<TextareaAutosize
|
||||
{...rest}
|
||||
{...inputProps}
|
||||
ref={ref}
|
||||
className={cl(
|
||||
className,
|
||||
"navds-textarea__input",
|
||||
"navds-body-short",
|
||||
`navds-body-${size ?? "m"}`,
|
||||
{
|
||||
"navds-textarea--counter": hasMaxLength,
|
||||
}
|
||||
)}
|
||||
aria-describedby={cl(inputProps["aria-describedby"], {
|
||||
[maxLengthId]: hasMaxLength,
|
||||
})}
|
||||
/>
|
||||
{hasMaxLength && (
|
||||
<>
|
||||
<span id={maxLengthId} className="sr-only">
|
||||
Tekstområde med plass til {maxLength} tegn., Textarea can have{" "}
|
||||
{maxLength} signs.
|
||||
</span>
|
||||
<Counter
|
||||
maxLength={maxLength}
|
||||
currentLength={props.value.length}
|
||||
size={size}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div id={errorId} aria-relevant="additions removals" aria-live="polite">
|
||||
{showErrorMsg && (
|
||||
<ErrorMessage size={size}>{props.error}</ErrorMessage>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export const Counter = ({ maxLength, currentLength, size }) => {
|
||||
const difference = maxLength - currentLength;
|
||||
|
||||
return (
|
||||
<BodyShort
|
||||
className={cl("navds-textarea__counter", {
|
||||
"navds-textarea__counter--error": difference < 0,
|
||||
})}
|
||||
aria-live="polite"
|
||||
size={size}
|
||||
>
|
||||
{difference < 0
|
||||
? `Du har ${Math.abs(difference)} tegn for mye`
|
||||
: `Du har ${difference} tegn igjen`}
|
||||
</BodyShort>
|
||||
);
|
||||
};
|
||||
|
||||
export default Textarea;
|
||||
@@ -0,0 +1,85 @@
|
||||
import React, { forwardRef, InputHTMLAttributes } from "react";
|
||||
import cl from "classnames";
|
||||
import useCheckbox from "./useCheckbox";
|
||||
import ErrorMessage from "../ErrorMessage";
|
||||
import { FormFieldProps } from "../useFormField";
|
||||
import { BodyShort, omit } from "../..";
|
||||
|
||||
export interface CheckboxProps
|
||||
extends FormFieldProps,
|
||||
Omit<InputHTMLAttributes<HTMLInputElement>, "size"> {
|
||||
/**
|
||||
* Label for checkbox
|
||||
*/
|
||||
children: React.ReactNode;
|
||||
/**
|
||||
* Hides label and makes it viewable for screen-readers only.
|
||||
*/
|
||||
hideLabel?: boolean;
|
||||
}
|
||||
|
||||
const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>((props, ref) => {
|
||||
const {
|
||||
inputProps,
|
||||
errorId,
|
||||
showErrorMsg,
|
||||
hasError,
|
||||
size,
|
||||
inputDescriptionId,
|
||||
} = useCheckbox(props);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cl(
|
||||
props.className,
|
||||
"navds-checkbox",
|
||||
`navds-checkbox--${size}`,
|
||||
{
|
||||
"navds-checkbox--error": hasError,
|
||||
"navds-checkbox--with-error-message": showErrorMsg,
|
||||
"navds-checkbox--with-description": !!props.description,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<input
|
||||
{...omit(props, [
|
||||
"children",
|
||||
"size",
|
||||
"error",
|
||||
"errorId",
|
||||
"description",
|
||||
"hideLabel",
|
||||
])}
|
||||
{...inputProps}
|
||||
className="navds-checkbox__input"
|
||||
ref={ref}
|
||||
/>
|
||||
<BodyShort
|
||||
component="label"
|
||||
htmlFor={inputProps.id}
|
||||
size={size}
|
||||
className="navds-checkbox__label"
|
||||
>
|
||||
{props.hideLabel ? (
|
||||
<span className="sr-only">{props.children}</span>
|
||||
) : (
|
||||
props.children
|
||||
)}
|
||||
</BodyShort>
|
||||
{props.description && (
|
||||
<BodyShort
|
||||
size={size}
|
||||
id={inputDescriptionId}
|
||||
className="navds-checkbox__description"
|
||||
>
|
||||
{props.description}
|
||||
</BodyShort>
|
||||
)}
|
||||
<div id={errorId} aria-relevant="additions removals" aria-live="polite">
|
||||
{showErrorMsg && <ErrorMessage size={size}>{props.error}</ErrorMessage>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default Checkbox;
|
||||
@@ -0,0 +1,79 @@
|
||||
import React, { createContext, forwardRef, useContext } from "react";
|
||||
import cl from "classnames";
|
||||
import { Fieldset, FieldsetProps, FieldsetContext } from "..";
|
||||
|
||||
export interface CheckboxGroupState {
|
||||
readonly defaultValue: readonly string[];
|
||||
readonly value?: readonly string[];
|
||||
toggleValue(value: string): void;
|
||||
}
|
||||
|
||||
export const CheckboxGroupContext = createContext<CheckboxGroupState | null>(
|
||||
null
|
||||
);
|
||||
|
||||
export interface CheckboxGroupProps extends Omit<FieldsetProps, "onChange"> {
|
||||
/**
|
||||
* Checkboxes
|
||||
*/
|
||||
children: React.ReactNode;
|
||||
/**
|
||||
* Controlled state for group
|
||||
*/
|
||||
value?: string[];
|
||||
/**
|
||||
* Default checked checkboxes on render
|
||||
*/
|
||||
defaultValue?: string[];
|
||||
/**
|
||||
* Returns current checked checkboxes in group
|
||||
*/
|
||||
onChange?: (value: string[]) => void;
|
||||
}
|
||||
|
||||
const CheckboxGroup = forwardRef<HTMLFieldSetElement, CheckboxGroupProps>(
|
||||
(
|
||||
{
|
||||
value,
|
||||
defaultValue = [],
|
||||
onChange = () => {},
|
||||
children,
|
||||
className,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const state = value ?? [];
|
||||
|
||||
const fieldset = useContext(FieldsetContext);
|
||||
|
||||
return (
|
||||
<Fieldset
|
||||
{...rest}
|
||||
ref={ref}
|
||||
className={cl(
|
||||
className,
|
||||
"navds-checkbox-group",
|
||||
`navds-checkbox-group--${rest.size ?? fieldset?.size ?? "m"}`
|
||||
)}
|
||||
>
|
||||
<CheckboxGroupContext.Provider
|
||||
value={{
|
||||
value,
|
||||
defaultValue,
|
||||
toggleValue: (value: string) =>
|
||||
onChange(
|
||||
state.includes(value)
|
||||
? state.filter((v) => v !== value)
|
||||
: [...state, value]
|
||||
),
|
||||
}}
|
||||
>
|
||||
<div className="navds-checkboxes">{children}</div>
|
||||
</CheckboxGroupContext.Provider>
|
||||
</Fieldset>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default CheckboxGroup;
|
||||
@@ -0,0 +1,2 @@
|
||||
export { default as Checkbox, CheckboxProps } from "./Checkbox";
|
||||
export { default as CheckboxGroup, CheckboxGroupProps } from "./CheckboxGroup";
|
||||
@@ -0,0 +1,227 @@
|
||||
import { Meta, Canvas } from "@storybook/addon-docs";
|
||||
import { Checkbox, CheckboxGroup } from "../index";
|
||||
|
||||
<Meta title="ds-react/form/checkbox/intro" />
|
||||
|
||||
# Hvordan ta i bruk Checkbox
|
||||
|
||||
```jsx
|
||||
<CheckboxGroup legend="Mollit eiusmod">
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange">Orange</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<CheckboxGroup legend="Mollit eiusmod">
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange">Orange</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
</Canvas>
|
||||
|
||||
Label å checkbox settes her da med children
|
||||
|
||||
## Description
|
||||
|
||||
Man kan både sette en description på CheckboxGroup og selve checkbox
|
||||
|
||||
```jsx
|
||||
<CheckboxGroup legend="Culpa cupidatat" description="Exercitation do labore">
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange" description="Laborum ad">
|
||||
Orange
|
||||
</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<CheckboxGroup legend="Mollit eiusmod" description="Exercitation do labore">
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange" description="Laborum ad">
|
||||
Orange
|
||||
</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
</Canvas>
|
||||
|
||||
## Errors
|
||||
|
||||
```jsx
|
||||
<CheckboxGroup legend="Mollit eiusmod" error="Boks nr 2 må være valgt">
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange">Orange</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<CheckboxGroup legend="Mollit eiusmod" error="Boks nr 2 må være valgt">
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange">Orange</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
</Canvas>
|
||||
|
||||
## Errors uten errorPropagation
|
||||
|
||||
```jsx
|
||||
<CheckboxGroup
|
||||
legend="Mollit eiusmod"
|
||||
errorPropagation={false}
|
||||
error="Boks nr 2 må være valgt"
|
||||
>
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange">Orange</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<CheckboxGroup
|
||||
legend="Mollit eiusmod"
|
||||
errorPropagation={false}
|
||||
error="Boks nr 2 må være valgt"
|
||||
>
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange" error="Boksen må være valgt">
|
||||
Orange
|
||||
</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
</Canvas>
|
||||
|
||||
## Sizing
|
||||
|
||||
Checkboxer har default 44px høy klikkflate. Med size="s" blir denne til 24px slik som før
|
||||
|
||||
```jsx
|
||||
<CheckboxGroup legend="Mollit eiusmod" error="Boks nr 2 må være valgt" size="s">
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange">Orange</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<CheckboxGroup
|
||||
legend="Mollit eiusmod"
|
||||
error="Boks nr 2 må være valgt"
|
||||
size="s"
|
||||
>
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange" error="Boksen må være valgt">
|
||||
Orange
|
||||
</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
</Canvas>
|
||||
|
||||
## defaultValues
|
||||
|
||||
```jsx
|
||||
<CheckboxGroup legend="Mollit eiusmod" defaultValue={["Orange", "Melon"]}>
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange">Orange</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<CheckboxGroup legend="Mollit eiusmod" defaultValue={["Orange", "Melon"]}>
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange">Orange</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
</Canvas>
|
||||
|
||||
## hideLegend
|
||||
|
||||
Ved bruk av `hideLegend` på CheckboxGroup kan man gjøre slik at legend/description bare vises for skjermlesere
|
||||
|
||||
```jsx
|
||||
<CheckboxGroup legend="Mollit eiusmod" hideLegend>
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange">Orange</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<CheckboxGroup legend="Mollit eiusmod" hideLegend>
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange">Orange</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
</Canvas>
|
||||
|
||||
## hideLabel
|
||||
|
||||
Ved bruk av `hideLabel` kan man lettere ta i bruk checkbox internt i eks tabeller.
|
||||
|
||||
```jsx
|
||||
<CheckboxGroup legend="Mollit eiusmod" hideLegend>
|
||||
<Checkbox value="Apple" hideLabel>
|
||||
Apple
|
||||
</Checkbox>
|
||||
<Checkbox value="Orange" hideLabel>
|
||||
Orange
|
||||
</Checkbox>
|
||||
<Checkbox value="Melon" hideLabel>
|
||||
Melon
|
||||
</Checkbox>
|
||||
</CheckboxGroup>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<CheckboxGroup legend="Mollit eiusmod" hideLegend>
|
||||
<Checkbox value="Apple" hideLabel>
|
||||
Apple
|
||||
</Checkbox>
|
||||
<Checkbox value="Orange" hideLabel>
|
||||
Orange
|
||||
</Checkbox>
|
||||
<Checkbox value="Melon" hideLabel>
|
||||
Melon
|
||||
</Checkbox>
|
||||
</CheckboxGroup>
|
||||
</Canvas>
|
||||
|
||||
## Disabled
|
||||
|
||||
Ved bruk av `disabled` kan man både disabled enkelte checkboxer eller checkboxgruppen.
|
||||
|
||||
NOTE: Husk at disabled bør unngås!
|
||||
|
||||
```jsx
|
||||
<CheckboxGroup legend="Mollit eiusmod" disabled>
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange">Orange</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
|
||||
<CheckboxGroup legend="Mollit eiusmod" >
|
||||
<Checkbox value="Apple" disabled>Apple</Checkbox>
|
||||
<Checkbox value="Orange">Orange</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<div>
|
||||
<CheckboxGroup legend="Mollit eiusmod" disabled>
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange">Orange</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
<CheckboxGroup legend="Mollit eiusmod">
|
||||
<Checkbox value="Apple" disabled>
|
||||
Apple
|
||||
</Checkbox>
|
||||
<Checkbox value="Orange">Orange</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
</div>
|
||||
</Canvas>
|
||||
@@ -0,0 +1,96 @@
|
||||
import React from "react";
|
||||
import { Checkbox, CheckboxGroup } from "../../index";
|
||||
import { Meta } from "@storybook/react/types-6-0";
|
||||
export default {
|
||||
title: "ds-react/form/checkbox",
|
||||
component: Checkbox,
|
||||
} as Meta;
|
||||
|
||||
export const All = () => {
|
||||
return (
|
||||
<>
|
||||
<h1>Checkboxes</h1>
|
||||
<CheckboxGroup legend="Mollit eiusmod">
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange">Orange</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
<h2>description</h2>
|
||||
<CheckboxGroup
|
||||
legend="Mollit eiusmod"
|
||||
description="Exercitation do labore"
|
||||
>
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange" description="Laborum ad">
|
||||
Orange
|
||||
</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
<h2>error</h2>
|
||||
<CheckboxGroup legend="Mollit eiusmod" error="Boks nr 2 må være valgt">
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange">Orange</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
<h2>error uten errorPropagation</h2>
|
||||
<CheckboxGroup
|
||||
legend="Mollit eiusmod"
|
||||
errorPropagation={false}
|
||||
error="Boks nr 2 må være valgt"
|
||||
>
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange" error="Boksen må være valgt">
|
||||
Orange
|
||||
</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
<h2>Sizing</h2>
|
||||
<CheckboxGroup
|
||||
legend="Mollit eiusmod"
|
||||
error="Boks nr 2 må være valgt"
|
||||
size="s"
|
||||
>
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange">Orange</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
<h2>defaultValue</h2>
|
||||
<CheckboxGroup legend="Mollit eiusmod" defaultValue={["Orange", "Melon"]}>
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange">Orange</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
<h2>hideLenged</h2>
|
||||
<CheckboxGroup legend="Mollit eiusmod" hideLegend>
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange">Orange</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
<h2>hideLabel</h2>
|
||||
<CheckboxGroup legend="Mollit eiusmod">
|
||||
<Checkbox value="Apple" hideLabel>
|
||||
Apple
|
||||
</Checkbox>
|
||||
<Checkbox value="Orange" hideLabel>
|
||||
Orange
|
||||
</Checkbox>
|
||||
<Checkbox value="Melon" hideLabel>
|
||||
Melon
|
||||
</Checkbox>
|
||||
</CheckboxGroup>
|
||||
<h2>Disabled</h2>
|
||||
<CheckboxGroup legend="Mollit eiusmod" disabled>
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<Checkbox value="Orange">Orange</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
<CheckboxGroup legend="Mollit eiusmod">
|
||||
<Checkbox value="Apple" disabled>
|
||||
Apple
|
||||
</Checkbox>
|
||||
<Checkbox value="Orange">Orange</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
import { useContext } from "react";
|
||||
import { CheckboxProps } from "../..";
|
||||
import { useFormField } from "../useFormField";
|
||||
import { CheckboxGroupContext } from "./CheckboxGroup";
|
||||
|
||||
/**
|
||||
* Handles props for Checkboxes in context with Fieldset and CheckboxGroup
|
||||
*/
|
||||
const useCheckbox = ({ children, ...props }: CheckboxProps) => {
|
||||
const checkboxGroup = useContext(CheckboxGroupContext);
|
||||
|
||||
const { inputProps, ...rest } = useFormField(props, "checkbox");
|
||||
|
||||
if (checkboxGroup) {
|
||||
if (props.checked) {
|
||||
console.warn(
|
||||
"`checked` is unsupported on <Checkbox> elements within a <CheckboxGroup>. Please set a `value` or `defaultValue` on <CheckboxGroup> instead."
|
||||
);
|
||||
}
|
||||
if (props.value === null) {
|
||||
console.warn(
|
||||
"A <Checkbox> element within a <CheckboxGroup> requires a `value` property."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...rest,
|
||||
inputProps: {
|
||||
...inputProps,
|
||||
type: "checkbox",
|
||||
checked: checkboxGroup?.value
|
||||
? checkboxGroup.value.includes(props.value as string)
|
||||
: props.checked,
|
||||
defaultChecked: checkboxGroup
|
||||
? checkboxGroup.defaultValue.includes(props.value as string)
|
||||
: props.defaultChecked,
|
||||
onChange: (e) => {
|
||||
props.onChange && props.onChange(e);
|
||||
checkboxGroup && checkboxGroup.toggleValue(props.value as string);
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default useCheckbox;
|
||||
@@ -0,0 +1,66 @@
|
||||
import React, { forwardRef, HTMLAttributes } from "react";
|
||||
import cl from "classnames";
|
||||
import { Title } from "../..";
|
||||
|
||||
export interface ErrorSummaryProps extends HTMLAttributes<HTMLDivElement> {
|
||||
/**
|
||||
* ErrorSummaryItems
|
||||
*/
|
||||
children: React.ReactNode;
|
||||
/**
|
||||
* Changes padding and font-sizes
|
||||
* @default "m"
|
||||
*/
|
||||
size?: "m" | "s";
|
||||
/**
|
||||
* Heading above links
|
||||
*/
|
||||
heading?: React.ReactNode;
|
||||
/**
|
||||
* Allows setting a different HTML <tag>
|
||||
* @default "h2"
|
||||
*/
|
||||
headingTag?: React.ElementType<any>;
|
||||
}
|
||||
|
||||
const ErrorSummary = forwardRef<HTMLDivElement, ErrorSummaryProps>(
|
||||
(
|
||||
{ children, className, size = "m", headingTag = "h2", heading, ...rest },
|
||||
ref
|
||||
) => {
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
{...rest}
|
||||
className={cl(
|
||||
className,
|
||||
"navds-error-summary",
|
||||
`navds-error-summary--${size}`
|
||||
)}
|
||||
tabIndex={-1}
|
||||
role="region"
|
||||
>
|
||||
<Title
|
||||
className="navds-error-summary__title"
|
||||
component={headingTag}
|
||||
size="s"
|
||||
>
|
||||
{heading}
|
||||
</Title>
|
||||
<ul
|
||||
className={cl(
|
||||
"navds-error-summary__list",
|
||||
"navds-body-short",
|
||||
`navds-body--${size}`
|
||||
)}
|
||||
>
|
||||
{React.Children.map(children, (child) => {
|
||||
return <li key={child?.toString()}>{child}</li>;
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default ErrorSummary;
|
||||
@@ -0,0 +1,31 @@
|
||||
import React, { forwardRef } from "react";
|
||||
import cl from "classnames";
|
||||
import { OverridableComponent } from "../..";
|
||||
|
||||
export type ErrorType = OverridableComponent<ErrorSummaryItemProps>;
|
||||
|
||||
export interface ErrorSummaryItemProps {
|
||||
props: {
|
||||
/**
|
||||
* Link text
|
||||
*/
|
||||
children: React.ReactNode;
|
||||
} & React.HTMLAttributes<HTMLAnchorElement>;
|
||||
defaultComponent: "a";
|
||||
}
|
||||
|
||||
const ErrorSummaryItem: ErrorType = forwardRef(
|
||||
({ children, component: Component = "a", className, ...rest }, ref) => {
|
||||
return (
|
||||
<Component
|
||||
{...rest}
|
||||
ref={ref}
|
||||
className={cl(className, "navds-error-summary__item", "navds-link")}
|
||||
>
|
||||
{children}
|
||||
</Component>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default ErrorSummaryItem;
|
||||
@@ -0,0 +1,5 @@
|
||||
export { default as ErrorSummary, ErrorSummaryProps } from "./ErrorSummary";
|
||||
export {
|
||||
default as ErrorSummaryItem,
|
||||
ErrorSummaryItemProps,
|
||||
} from "./ErrorSummaryItem";
|
||||
@@ -0,0 +1,54 @@
|
||||
import { Meta, Canvas } from "@storybook/addon-docs";
|
||||
import { ErrorSummary, ErrorSummaryItem } from "../index";
|
||||
|
||||
<Meta title="ds-react/form/errorsummary/intro" />
|
||||
|
||||
# Hvordan ta i bruk ErrorSummary
|
||||
|
||||
`href` på `ErrorSummaryItem` linker til id som er satt på skjema-elementer.
|
||||
|
||||
```jsx
|
||||
<ErrorSummary heading="Eiusmod est cillum mollit pariatur deserunt">
|
||||
<ErrorSummaryItem href="#1">Checkbox må fylles ut</ErrorSummaryItem>
|
||||
<ErrorSummaryItem href="#2">
|
||||
Tekstfeltet må ha en godkjent e-mail
|
||||
</ErrorSummaryItem>
|
||||
</ErrorSummaryItem>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<ErrorSummary heading="Eiusmod est cillum mollit pariatur deserunt">
|
||||
<ErrorSummaryItem href="#1">Checkbox må fylles ut</ErrorSummaryItem>
|
||||
<ErrorSummaryItem href="#2">
|
||||
Tekstfeltet må ha en godkjent e-mail
|
||||
</ErrorSummaryItem>
|
||||
</ErrorSummary>
|
||||
</Canvas>
|
||||
|
||||
## Custom headingTag
|
||||
|
||||
`headingTag` lar deg sette heading til en annen html-tag en default "h2"
|
||||
|
||||
```jsx
|
||||
<ErrorSummary
|
||||
heading="Eiusmod est cillum mollit pariatur deserunt"
|
||||
headingTag="h3"
|
||||
>
|
||||
<ErrorSummaryItem href="#1">Checkbox må fylles ut</ErrorSummaryItem>
|
||||
<ErrorSummaryItem href="#2">
|
||||
Tekstfeltet må ha en godkjent e-mail
|
||||
</ErrorSummaryItem>
|
||||
</ErrorSummaryItem>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<ErrorSummary
|
||||
heading="Eiusmod est cillum mollit pariatur deserunt"
|
||||
headingTag="h3"
|
||||
>
|
||||
<ErrorSummaryItem href="#1">Checkbox må fylles ut</ErrorSummaryItem>
|
||||
<ErrorSummaryItem href="#2">
|
||||
Tekstfeltet må ha en godkjent e-mail
|
||||
</ErrorSummaryItem>
|
||||
</ErrorSummary>
|
||||
</Canvas>
|
||||
@@ -0,0 +1,28 @@
|
||||
import React from "react";
|
||||
import { Meta } from "@storybook/react/types-6-0";
|
||||
import { ErrorSummary, ErrorSummaryItem } from "..";
|
||||
export default {
|
||||
title: "ds-react/form/errorsummary",
|
||||
component: ErrorSummary,
|
||||
} as Meta;
|
||||
|
||||
export const All = () => {
|
||||
return (
|
||||
<>
|
||||
<h1>Error summary</h1>
|
||||
<ErrorSummary heading="Feiloppsummering komponent" headingTag="h4">
|
||||
<ErrorSummaryItem href="#1">Checkbox må fylles ut</ErrorSummaryItem>
|
||||
<ErrorSummaryItem href="#2">
|
||||
Tekstfeltet må ha en godkjent e-mail
|
||||
</ErrorSummaryItem>
|
||||
</ErrorSummary>
|
||||
<h2>size s</h2>
|
||||
<ErrorSummary size="s" heading="Feiloppsummering komponent">
|
||||
<ErrorSummaryItem href="#1">Checkbox må fylles ut</ErrorSummaryItem>
|
||||
<ErrorSummaryItem href="#2">
|
||||
Tekstfeltet må ha en godkjent e-mail
|
||||
</ErrorSummaryItem>
|
||||
</ErrorSummary>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
export {
|
||||
Checkbox,
|
||||
CheckboxProps,
|
||||
CheckboxGroup,
|
||||
CheckboxGroupProps,
|
||||
} from "./checkbox";
|
||||
export {
|
||||
default as Fieldset,
|
||||
FieldsetContext,
|
||||
FieldsetProps,
|
||||
} from "./Fieldset";
|
||||
export { Radio, RadioGroup, RadioGroupProps, RadioProps } from "./radio";
|
||||
export { default as Select, SelectProps } from "./Select";
|
||||
export {
|
||||
ErrorSummary,
|
||||
ErrorSummaryProps,
|
||||
ErrorSummaryItem,
|
||||
ErrorSummaryItemProps,
|
||||
} from "./error-summary";
|
||||
export { Counter, default as Textarea, TextareaProps } from "./Textarea";
|
||||
export { default as TextField, TextFieldProps } from "./TextField";
|
||||
export {
|
||||
default as ConfirmationPanel,
|
||||
ConfirmationPanelProps,
|
||||
} from "./ConfirmationPanel";
|
||||
@@ -0,0 +1,72 @@
|
||||
import React, { forwardRef, InputHTMLAttributes } from "react";
|
||||
import cl from "classnames";
|
||||
import { BodyShort, omit } from "../..";
|
||||
import ErrorMessage from "../ErrorMessage";
|
||||
import { FormFieldProps } from "../useFormField";
|
||||
import { useRadio } from "./useRadio";
|
||||
|
||||
export interface RadioProps
|
||||
extends FormFieldProps,
|
||||
Omit<InputHTMLAttributes<HTMLInputElement>, "size"> {
|
||||
/**
|
||||
* Label for radio
|
||||
*/
|
||||
children: React.ReactNode;
|
||||
value: string;
|
||||
}
|
||||
|
||||
const Radio = forwardRef<HTMLInputElement, RadioProps>((props, ref) => {
|
||||
const {
|
||||
inputProps,
|
||||
errorId,
|
||||
showErrorMsg,
|
||||
size,
|
||||
hasError,
|
||||
inputDescriptionId,
|
||||
} = useRadio(props);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cl(props.className, "navds-radio", `navds-radio--${size}`, {
|
||||
"navds-radio--error": hasError,
|
||||
"navds-radio--with-error-message": showErrorMsg,
|
||||
"navds-radio--with-description": !!props.description,
|
||||
})}
|
||||
>
|
||||
<input
|
||||
{...omit(props, [
|
||||
"children",
|
||||
"size",
|
||||
"error",
|
||||
"errorId",
|
||||
"description",
|
||||
])}
|
||||
{...inputProps}
|
||||
className="navds-radio__input"
|
||||
ref={ref}
|
||||
/>
|
||||
<BodyShort
|
||||
component="label"
|
||||
htmlFor={inputProps.id}
|
||||
size={size}
|
||||
className="navds-radio__label"
|
||||
>
|
||||
{props.children}
|
||||
</BodyShort>
|
||||
{props.description && (
|
||||
<BodyShort
|
||||
size={size}
|
||||
id={inputDescriptionId}
|
||||
className="navds-radio__description"
|
||||
>
|
||||
{props.description}
|
||||
</BodyShort>
|
||||
)}
|
||||
<div id={errorId} aria-relevant="additions removals" aria-live="polite">
|
||||
{showErrorMsg && <ErrorMessage size={size}>{props.error}</ErrorMessage>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default Radio;
|
||||
@@ -0,0 +1,89 @@
|
||||
import React, { forwardRef, useContext } from "react";
|
||||
import cl from "classnames";
|
||||
import { Fieldset, FieldsetContext, FieldsetProps } from "..";
|
||||
import { useId } from "../..";
|
||||
|
||||
export interface RadioGroupContextProps {
|
||||
name: string;
|
||||
defaultValue?: string;
|
||||
value?: string;
|
||||
onChange: (value: string) => void;
|
||||
required?: boolean;
|
||||
}
|
||||
|
||||
export const RadioGroupContext = React.createContext<RadioGroupContextProps | null>(
|
||||
null
|
||||
);
|
||||
|
||||
export interface RadioGroupProps extends Omit<FieldsetProps, "onChange"> {
|
||||
/**
|
||||
* Collection of <Radio>-elements
|
||||
*/
|
||||
children: React.ReactNode;
|
||||
/**
|
||||
* Override internal name
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* Default checked radiobutton
|
||||
*/
|
||||
defaultValue?: string;
|
||||
/**
|
||||
* Controlled state for Radiobutton
|
||||
*/
|
||||
value?: string;
|
||||
/**
|
||||
* Returns current checked radiobutton in group
|
||||
*/
|
||||
onChange?: (value: string) => void;
|
||||
/**
|
||||
* Tells Fieldset if group is required
|
||||
*/
|
||||
required?: boolean;
|
||||
}
|
||||
|
||||
const RadioGroup = forwardRef<HTMLFieldSetElement, RadioGroupProps>(
|
||||
(
|
||||
{
|
||||
children,
|
||||
className,
|
||||
name,
|
||||
defaultValue,
|
||||
value,
|
||||
onChange = () => {},
|
||||
required,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const fieldset = useContext(FieldsetContext);
|
||||
|
||||
const nameId = useId();
|
||||
|
||||
return (
|
||||
<Fieldset
|
||||
{...rest}
|
||||
ref={ref}
|
||||
className={cl(
|
||||
className,
|
||||
"navds-radio-group",
|
||||
`navds-radio-group--${rest.size ?? fieldset?.size ?? "m"}`
|
||||
)}
|
||||
>
|
||||
<RadioGroupContext.Provider
|
||||
value={{
|
||||
name: name ?? `radioGroupName-${nameId}`,
|
||||
defaultValue,
|
||||
value,
|
||||
onChange,
|
||||
required,
|
||||
}}
|
||||
>
|
||||
<div className="navds-radio-buttons">{children}</div>
|
||||
</RadioGroupContext.Provider>
|
||||
</Fieldset>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default RadioGroup;
|
||||
@@ -0,0 +1,2 @@
|
||||
export { default as Radio, RadioProps } from "./Radio";
|
||||
export { default as RadioGroup, RadioGroupProps } from "./RadioGroup";
|
||||
@@ -0,0 +1,191 @@
|
||||
import { Meta, Canvas } from "@storybook/addon-docs";
|
||||
import { Radio, RadioGroup } from "../index";
|
||||
|
||||
<Meta title="ds-react/form/radio/intro" />
|
||||
|
||||
# Hvordan ta i bruk Radio
|
||||
|
||||
```jsx
|
||||
<RadioGroup legend="Mollit eiusmod">
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange">Orange</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<RadioGroup legend="Mollit eiusmod">
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange">Orange</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
</Canvas>
|
||||
|
||||
Label å Radio settes her da med children
|
||||
|
||||
## Description
|
||||
|
||||
Man kan både sette en description på RadioGroup og selve Radio
|
||||
|
||||
```jsx
|
||||
<RadioGroup legend="Culpa cupidatat" description="Exercitation do labore">
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange" description="Laborum ad">
|
||||
Orange
|
||||
</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<RadioGroup legend="Mollit eiusmod" description="Exercitation do labore">
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange" description="Laborum ad">
|
||||
Orange
|
||||
</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
</Canvas>
|
||||
|
||||
## Errors
|
||||
|
||||
```jsx
|
||||
<RadioGroup legend="Mollit eiusmod" error="Boks nr 2 må være valgt">
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange">Orange</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<RadioGroup legend="Mollit eiusmod" error="Boks nr 2 må være valgt">
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange">Orange</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
</Canvas>
|
||||
|
||||
## Errors uten errorPropagation
|
||||
|
||||
```jsx
|
||||
<RadioGroup
|
||||
legend="Mollit eiusmod"
|
||||
errorPropagation={false}
|
||||
error="Boks nr 2 må være valgt"
|
||||
>
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange">Orange</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<RadioGroup
|
||||
legend="Mollit eiusmod"
|
||||
errorPropagation={false}
|
||||
error="Boks nr 2 må være valgt"
|
||||
>
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange" error="Boksen må være valgt">
|
||||
Orange
|
||||
</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
</Canvas>
|
||||
|
||||
## Sizing
|
||||
|
||||
Radioer har default 44px høy klikkflate. Med size="s" blir denne til 24px slik som før
|
||||
|
||||
```jsx
|
||||
<RadioGroup legend="Mollit eiusmod" error="Boks nr 2 må være valgt" size="s">
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange">Orange</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<RadioGroup legend="Mollit eiusmod" error="Boks nr 2 må være valgt" size="s">
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange" error="Boksen må være valgt">
|
||||
Orange
|
||||
</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
</Canvas>
|
||||
|
||||
## defaultValue
|
||||
|
||||
```jsx
|
||||
<RadioGroup legend="Mollit eiusmod" defaultValue="Orange">
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange">Orange</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<RadioGroup legend="Mollit eiusmod" defaultValue="Orange">
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange">Orange</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
</Canvas>
|
||||
|
||||
## hideLegend
|
||||
|
||||
Ved bruk av `hideLegend` på RadioGroup kan man gjøre slik at legend/description bare vises for skjermlesere
|
||||
|
||||
```jsx
|
||||
<RadioGroup legend="Mollit eiusmod" hideLegend>
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange">Orange</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<RadioGroup legend="Mollit eiusmod" hideLegend>
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange">Orange</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
</Canvas>
|
||||
|
||||
## Disabled
|
||||
|
||||
Ved bruk av `disabled` kan man både disabled enkelte Radioer eller Radiogruppen.
|
||||
|
||||
NOTE: Husk at disabled bør unngås!
|
||||
|
||||
```jsx
|
||||
<RadioGroup legend="Mollit eiusmod" disabled>
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange">Orange</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
|
||||
<RadioGroup legend="Mollit eiusmod" >
|
||||
<Radio value="Apple" disabled>Apple</Radio>
|
||||
<Radio value="Orange">Orange</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<div>
|
||||
<RadioGroup legend="Mollit eiusmod" disabled>
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange">Orange</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
<RadioGroup legend="Mollit eiusmod">
|
||||
<Radio value="Apple" disabled>
|
||||
Apple
|
||||
</Radio>
|
||||
<Radio value="Orange">Orange</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
</Canvas>
|
||||
@@ -0,0 +1,81 @@
|
||||
import React from "react";
|
||||
import { Meta } from "@storybook/react/types-6-0";
|
||||
import { RadioGroup, Radio } from "../index";
|
||||
export default {
|
||||
title: "ds-react/form/radio",
|
||||
component: RadioGroup,
|
||||
} as Meta;
|
||||
|
||||
export const All = () => {
|
||||
return (
|
||||
<>
|
||||
<h1>Radios</h1>
|
||||
<RadioGroup legend="Mollit eiusmod">
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange">Orange</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
<h2>description</h2>
|
||||
<RadioGroup legend="Mollit eiusmod" description="Exercitation do labore">
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange" description="Laborum ad">
|
||||
Orange
|
||||
</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
<h2>error</h2>
|
||||
<RadioGroup legend="Mollit eiusmod" error="Boks nr 2 må være valgt">
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange">Orange</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
<h2>error uten errorPropagation</h2>
|
||||
<RadioGroup
|
||||
legend="Mollit eiusmod"
|
||||
errorPropagation={false}
|
||||
error="Boks nr 2 må være valgt"
|
||||
>
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange" error="Boksen må være valgt">
|
||||
Orange
|
||||
</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
<h2>Sizing</h2>
|
||||
<RadioGroup
|
||||
legend="Mollit eiusmod"
|
||||
error="Boks nr 2 må være valgt"
|
||||
size="s"
|
||||
>
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange">Orange</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
<h2>defaultValue</h2>
|
||||
<RadioGroup legend="Mollit eiusmod" defaultValue="Orange">
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange">Orange</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
<h2>hideLenged</h2>
|
||||
<RadioGroup legend="Mollit eiusmod" hideLegend>
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange">Orange</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
<h2>Disabled</h2>
|
||||
<RadioGroup legend="Mollit eiusmod" disabled>
|
||||
<Radio value="Apple">Apple</Radio>
|
||||
<Radio value="Orange">Orange</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
<RadioGroup legend="Mollit eiusmod">
|
||||
<Radio value="Apple" disabled>
|
||||
Apple
|
||||
</Radio>
|
||||
<Radio value="Orange">Orange</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
import { useContext } from "react";
|
||||
import { useFormField } from "../useFormField";
|
||||
import { RadioProps } from "./Radio";
|
||||
import { RadioGroupContext } from "./RadioGroup";
|
||||
|
||||
/**
|
||||
* Handles props for Radios in context with Fieldset and RadioGroup
|
||||
*/
|
||||
export const useRadio = (props: RadioProps) => {
|
||||
const radioGroup = useContext(RadioGroupContext);
|
||||
|
||||
const { inputProps, ...rest } = useFormField(props, "radio");
|
||||
|
||||
if (!radioGroup) {
|
||||
console.warn("<Radio> must be used inside <RadioGroup>.");
|
||||
}
|
||||
|
||||
if (props?.required !== undefined) {
|
||||
console.warn("required is only supported on <RadioGroup>.");
|
||||
}
|
||||
|
||||
return {
|
||||
...rest,
|
||||
inputProps: {
|
||||
...inputProps,
|
||||
name: radioGroup?.name,
|
||||
checked:
|
||||
(radioGroup?.value ?? radioGroup?.defaultValue) === props.value
|
||||
? true
|
||||
: undefined,
|
||||
onChange: (e) => {
|
||||
props.onChange && props.onChange(e);
|
||||
radioGroup?.onChange && radioGroup.onChange(props.value);
|
||||
},
|
||||
required: radioGroup?.required,
|
||||
type: "radio",
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
import { Meta, Canvas } from "@storybook/addon-docs";
|
||||
import { ConfirmationPanelExample } from "./live-examples";
|
||||
|
||||
<Meta title="ds-react/form/confirmation-panel/intro" />
|
||||
|
||||
# Hvordan ta i bruk ConfirmationPanel
|
||||
|
||||
```jsx
|
||||
<ConfirmationPanel
|
||||
checked={checked}
|
||||
onChange={() => setChecked(!checked)}
|
||||
label="Checkbox label text"
|
||||
>
|
||||
Ipsum voluptate pariatur <Link href="#123">demolink</Link> anim officia minim
|
||||
ut mollit voluptate exercitation nulla mollit.
|
||||
</ConfirmationPanel>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<ConfirmationPanelExample />
|
||||
</Canvas>
|
||||
|
||||
## Størrelser
|
||||
|
||||
Kommer i størrelsene "m" og "s".
|
||||
|
||||
```jsx
|
||||
<ConfirmationPanel
|
||||
checked={checked}
|
||||
onChange={() => setChecked(!checked)}
|
||||
label="Checkbox label text"
|
||||
size="s"
|
||||
>
|
||||
Ipsum voluptate pariatur <Link href="#123">demolink</Link> anim officia minim
|
||||
ut mollit voluptate exercitation nulla mollit.
|
||||
</ConfirmationPanel>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<ConfirmationPanelExample size="s" />
|
||||
</Canvas>
|
||||
|
||||
## Errors
|
||||
|
||||
```jsx
|
||||
<ConfirmationPanel
|
||||
checked={checked}
|
||||
onChange={() => setChecked(!checked)}
|
||||
label="Checkbox label text"
|
||||
error="Laborum enim esse quis"
|
||||
>
|
||||
Ipsum voluptate pariatur <Link href="#123">demolink</Link> anim officia minim
|
||||
ut mollit voluptate exercitation nulla mollit.
|
||||
</ConfirmationPanel>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<ConfirmationPanelExample error="Laborum enim esse quis" />
|
||||
</Canvas>
|
||||
@@ -0,0 +1,62 @@
|
||||
import React, { useState } from "react";
|
||||
import { ConfirmationPanel } from "../index";
|
||||
import { Meta } from "@storybook/react/types-6-0";
|
||||
import { Link } from "../..";
|
||||
export default {
|
||||
title: "ds-react/form/confirmation-panel",
|
||||
component: ConfirmationPanel,
|
||||
} as Meta;
|
||||
|
||||
export const All = () => {
|
||||
const [checked, setChecked] = useState(false);
|
||||
return (
|
||||
<div>
|
||||
<h1>ConfirmationPanel</h1>
|
||||
<ConfirmationPanel
|
||||
checked={checked}
|
||||
onChange={() => setChecked(!checked)}
|
||||
label="Checkbox label text"
|
||||
>
|
||||
Ipsum voluptate pariatur <Link href="#123">testlink</Link> anim officia
|
||||
minim ut mollit voluptate exercitation nulla mollit.
|
||||
</ConfirmationPanel>
|
||||
<h2>size s</h2>
|
||||
<ConfirmationPanel
|
||||
checked={checked}
|
||||
onChange={() => setChecked(!checked)}
|
||||
label="Checkbox label text"
|
||||
size="s"
|
||||
>
|
||||
Ipsum voluptate pariatur <Link href="#123">testlink</Link> anim officia
|
||||
minim ut mollit voluptate exercitation nulla mollit.
|
||||
</ConfirmationPanel>
|
||||
<h3>error</h3>
|
||||
<ConfirmationPanel
|
||||
checked={checked}
|
||||
onChange={() => setChecked(!checked)}
|
||||
label="Checkbox label text"
|
||||
error="Ex cupidatat do do do"
|
||||
>
|
||||
Ipsum voluptate pariatur <Link href="#123">testlink</Link> anim officia
|
||||
minim ut mollit voluptate exercitation nulla mollit.
|
||||
</ConfirmationPanel>
|
||||
<h3>error small</h3>
|
||||
<ConfirmationPanel
|
||||
checked={checked}
|
||||
onChange={() => setChecked(!checked)}
|
||||
label="Checkbox label text"
|
||||
error="Ex cupidatat do do do"
|
||||
size="s"
|
||||
>
|
||||
Ipsum voluptate pariatur <Link href="#123">testlink</Link> anim officia
|
||||
minim ut mollit voluptate exercitation nulla mollit.
|
||||
</ConfirmationPanel>
|
||||
<h2>Empty</h2>
|
||||
<ConfirmationPanel
|
||||
checked={checked}
|
||||
onChange={() => setChecked(!checked)}
|
||||
label="Checkbox label text"
|
||||
></ConfirmationPanel>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,75 @@
|
||||
import React, { useState } from "react";
|
||||
import { Fieldset } from "../index";
|
||||
import { Meta } from "@storybook/react/types-6-0";
|
||||
import { Button, Checkbox, CheckboxGroup } from "../../index";
|
||||
export default {
|
||||
title: "ds-react/form/uu-demo",
|
||||
component: Fieldset,
|
||||
} as Meta;
|
||||
|
||||
export const Demo1 = () => {
|
||||
const [error, setError] = useState(undefined);
|
||||
const [fieldsetError, setFieldsetError] = useState(undefined);
|
||||
const [groupError, setGroupError] = useState(undefined);
|
||||
const [propagation, setPropagation] = useState(true);
|
||||
return (
|
||||
<div>
|
||||
<h1>Nested-erros + aria-describedby</h1>
|
||||
<div>
|
||||
<Button
|
||||
style={{ marginBottom: "2rem" }}
|
||||
onClick={() => {
|
||||
!!fieldsetError
|
||||
? setFieldsetError(undefined)
|
||||
: setFieldsetError("Fieldset error message");
|
||||
}}
|
||||
>
|
||||
Toggle fieldset-error
|
||||
</Button>
|
||||
<Button
|
||||
style={{ marginBottom: "2rem" }}
|
||||
onClick={() => {
|
||||
!!groupError
|
||||
? setGroupError(undefined)
|
||||
: setGroupError("CheckboxGroup error message");
|
||||
}}
|
||||
>
|
||||
Toggle checkboxgroup-error
|
||||
</Button>
|
||||
<Button
|
||||
style={{ marginBottom: "2rem" }}
|
||||
onClick={() => {
|
||||
!!error ? setError(undefined) : setError("Textfield error message");
|
||||
}}
|
||||
>
|
||||
Toggle checkbox-error
|
||||
</Button>
|
||||
<Button
|
||||
style={{ marginBottom: "2rem" }}
|
||||
onClick={() => setPropagation(!propagation)}
|
||||
>
|
||||
Toggle errorPropagation
|
||||
</Button>
|
||||
</div>
|
||||
<Fieldset
|
||||
errorId="FIELDSET-ERROR"
|
||||
legend="Mollit eiusmod"
|
||||
error={fieldsetError}
|
||||
>
|
||||
<CheckboxGroup
|
||||
errorId="GROUP-ERROR"
|
||||
errorPropagation={propagation}
|
||||
error={groupError}
|
||||
legend="checkboxgroup"
|
||||
hideLegend
|
||||
>
|
||||
<Checkbox>Checkbox nr 1</Checkbox>
|
||||
<Checkbox errorId="CHECKBOX-ERROR" error={error}>
|
||||
Checkbox nr 2
|
||||
</Checkbox>
|
||||
<Checkbox>Checkbox nr 3</Checkbox>
|
||||
</CheckboxGroup>
|
||||
</Fieldset>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,136 @@
|
||||
import { Meta, Canvas } from "@storybook/addon-docs";
|
||||
import { Fieldset, TextField } from "../index";
|
||||
|
||||
<Meta title="ds-react/form/fieldset/intro" />
|
||||
|
||||
# Hvordan ta i bruk Fieldset
|
||||
|
||||
```jsx
|
||||
<Fieldset legend="Mollit eiusmod">
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
</Fieldset>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Fieldset legend="Mollit eiusmod">
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
</Fieldset>
|
||||
</Canvas>
|
||||
|
||||
## Description
|
||||
|
||||
```jsx
|
||||
<Fieldset legend="Mollit eiusmod" description="Quis reprehenderit esse cillum">
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
</Fieldset>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Fieldset
|
||||
legend="Mollit eiusmod"
|
||||
description="Quis reprehenderit esse cillum"
|
||||
>
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
</Fieldset>
|
||||
</Canvas>
|
||||
|
||||
## Errors
|
||||
|
||||
```jsx
|
||||
<Fieldset legend="Mollit eiusmod" error="Fieldsett error">
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
</Fieldset>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Fieldset legend="Mollit eiusmod" error="Fieldsett error">
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
</Fieldset>
|
||||
</Canvas>
|
||||
|
||||
## Errors uten errorPropagation
|
||||
|
||||
```jsx
|
||||
<Fieldset
|
||||
legend="Mollit eiusmod"
|
||||
error="Fieldsett error"
|
||||
errorPropagation={false}
|
||||
>
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
</Fieldset>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Fieldset
|
||||
legend="Mollit eiusmod"
|
||||
error="Fieldsett error"
|
||||
errorPropagation={false}
|
||||
>
|
||||
<TextField label="Textfield label" hideLabel error="Må være fylt ut" />
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
</Fieldset>
|
||||
</Canvas>
|
||||
|
||||
## Sizing
|
||||
|
||||
Fieldset justerer automatisk sizing på skjema-elementene. Man kan overstyre dette med å sette sizing på
|
||||
`TextField` i eks dette eksemplet
|
||||
|
||||
```jsx
|
||||
<Fieldset size="s" legend="Mollit eiusmod">
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
</Fieldset>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Fieldset size="s" legend="Mollit eiusmod" description="Dolore minim">
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
</Fieldset>
|
||||
</Canvas>
|
||||
|
||||
## hideLegend
|
||||
|
||||
Ved bruk av `hideLegend` på Fieldset kan man gjøre slik at legend/description bare vises for skjermlesere
|
||||
|
||||
```jsx
|
||||
<Fieldset legend="Mollit eiusmod" description="Dolore minim" hideLegend>
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
</Fieldset>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Fieldset legend="Mollit eiusmod" description="Dolore minim" hideLegend>
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
</Fieldset>
|
||||
</Canvas>
|
||||
|
||||
## Disabled
|
||||
|
||||
Disabled på fieldset fikser styling og state for alle elementene
|
||||
|
||||
NOTE: Husk at disabled bør unngås!
|
||||
|
||||
```jsx
|
||||
<Fieldset legend="Mollit eiusmod" description="Dolore minim" disabled>
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
</Fieldset>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Fieldset legend="Mollit eiusmod" description="Dolore minim" disabled>
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
</Fieldset>
|
||||
</Canvas>
|
||||
@@ -0,0 +1,70 @@
|
||||
import React from "react";
|
||||
import { Fieldset } from "../index";
|
||||
import { Meta } from "@storybook/react/types-6-0";
|
||||
import { TextField } from "../../index";
|
||||
export default {
|
||||
title: "ds-react/form/fieldset",
|
||||
component: Fieldset,
|
||||
} as Meta;
|
||||
|
||||
export const All = () => {
|
||||
return (
|
||||
<div>
|
||||
<h1>Fieldset</h1>
|
||||
|
||||
<Fieldset legend="Mollit eiusmod">
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
</Fieldset>
|
||||
|
||||
<h2>Description</h2>
|
||||
|
||||
<Fieldset
|
||||
legend="Mollit eiusmod"
|
||||
description="Quis reprehenderit esse cillum"
|
||||
>
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
</Fieldset>
|
||||
|
||||
<h2>Errors</h2>
|
||||
|
||||
<Fieldset legend="Mollit eiusmod" error="Fieldsett error">
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
</Fieldset>
|
||||
|
||||
<h2>Errors uten errorPropagation</h2>
|
||||
|
||||
<Fieldset
|
||||
legend="Mollit eiusmod"
|
||||
error="Fieldsett error"
|
||||
errorPropagation={false}
|
||||
>
|
||||
<TextField label="Textfield label" hideLabel error="Må være fylt ut" />
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
</Fieldset>
|
||||
|
||||
<h2>Sizing</h2>
|
||||
|
||||
<Fieldset size="s" legend="Mollit eiusmod" description="Dolore minim">
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
</Fieldset>
|
||||
|
||||
<h2>hideLegend</h2>
|
||||
|
||||
<Fieldset legend="Mollit eiusmod" description="Dolore minim" hideLegend>
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
</Fieldset>
|
||||
|
||||
<h2>Disabled</h2>
|
||||
|
||||
<Fieldset legend="Mollit eiusmod" description="Dolore minim" disabled>
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
<TextField label="Textfield label" hideLabel />
|
||||
</Fieldset>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
import React, { useState } from "react";
|
||||
import { ConfirmationPanel } from "..";
|
||||
import { Link } from "../..";
|
||||
|
||||
export const ConfirmationPanelExample = ({
|
||||
size = "m",
|
||||
error,
|
||||
}: {
|
||||
size: "m" | "s";
|
||||
error?: string;
|
||||
}) => {
|
||||
const [checked, setChecked] = useState(false);
|
||||
|
||||
return (
|
||||
<ConfirmationPanel
|
||||
checked={checked}
|
||||
onChange={() => setChecked(!checked)}
|
||||
label="Checkbox label text"
|
||||
size={size}
|
||||
error={error}
|
||||
>
|
||||
Ipsum voluptate pariatur <Link href="#123">demolink</Link> anim officia
|
||||
minim ut mollit voluptate exercitation nulla mollit.
|
||||
</ConfirmationPanel>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,134 @@
|
||||
import { Meta, Canvas } from "@storybook/addon-docs";
|
||||
import { Select } from "../index";
|
||||
|
||||
<Meta title="ds-react/form/select/intro" />
|
||||
|
||||
# Hvordan ta i bruk Select
|
||||
|
||||
```jsx
|
||||
<Select label="Ipsum enim quis culpa">
|
||||
<option value="">Velg land</option>
|
||||
<option value="norge">Norge</option>
|
||||
<option value="sverige">Sverige</option>
|
||||
</Select>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Select label="Ipsum enim quis culpa">
|
||||
<option value="">Velg land</option>
|
||||
<option value="norge">Norge</option>
|
||||
<option value="sverige">Sverige</option>
|
||||
</Select>
|
||||
</Canvas>
|
||||
|
||||
## Description
|
||||
|
||||
```jsx
|
||||
<Select label="Ipsum enim quis culpa" description="Aute enim">
|
||||
<option value="">Velg land</option>
|
||||
<option value="norge">Norge</option>
|
||||
<option value="sverige">Sverige</option>
|
||||
</Select>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Select label="Ipsum enim quis culpa" description="Aute enim">
|
||||
<option value="">Velg land</option>
|
||||
<option value="norge">Norge</option>
|
||||
<option value="sverige">Sverige</option>
|
||||
</Select>
|
||||
</Canvas>
|
||||
|
||||
## Errors
|
||||
|
||||
```jsx
|
||||
<Select
|
||||
label="Ipsum enim quis culpa"
|
||||
description="Aute enim"
|
||||
error="Select error message"
|
||||
>
|
||||
<option value="">Velg land</option>
|
||||
<option value="norge">Norge</option>
|
||||
<option value="sverige">Sverige</option>
|
||||
</Select>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Select
|
||||
label="Ipsum enim quis culpa"
|
||||
description="Aute enim"
|
||||
error="Select error message"
|
||||
>
|
||||
<option value="">Velg land</option>
|
||||
<option value="norge">Norge</option>
|
||||
<option value="sverige">Sverige</option>
|
||||
</Select>
|
||||
</Canvas>
|
||||
|
||||
## Sizing
|
||||
|
||||
```jsx
|
||||
<Select
|
||||
label="Ipsum enim quis culpa"
|
||||
description="Aute enim"
|
||||
error="Select error message"
|
||||
size="s"
|
||||
>
|
||||
<option value="">Velg land</option>
|
||||
<option value="norge">Norge</option>
|
||||
<option value="sverige">Sverige</option>
|
||||
</Select>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Select
|
||||
label="Ipsum enim quis culpa"
|
||||
description="Aute enim"
|
||||
error="Select error message"
|
||||
size="s"
|
||||
>
|
||||
<option value="">Velg land</option>
|
||||
<option value="norge">Norge</option>
|
||||
<option value="sverige">Sverige</option>
|
||||
</Select>
|
||||
</Canvas>
|
||||
|
||||
## hideLabel
|
||||
|
||||
Ved bruk av `hideLabel` på TextField kan man gjøre slik at label/description bare vises for skjermlesere
|
||||
|
||||
```jsx
|
||||
<Select label="Ipsum enim quis culpa" description="Aute enim" hideLabel>
|
||||
<option value="">Velg land</option>
|
||||
<option value="norge">Norge</option>
|
||||
<option value="sverige">Sverige</option>
|
||||
</Select>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Select label="Ipsum enim quis culpa" description="Aute enim" hideLabel>
|
||||
<option value="">Velg land</option>
|
||||
<option value="norge">Norge</option>
|
||||
<option value="sverige">Sverige</option>
|
||||
</Select>
|
||||
</Canvas>
|
||||
|
||||
## Disabled
|
||||
|
||||
NOTE: Husk at disabled bør unngås!
|
||||
|
||||
```jsx
|
||||
<Select label="Ipsum enim quis culpa" description="Aute enim" disabled>
|
||||
<option value="">Velg land</option>
|
||||
<option value="norge">Norge</option>
|
||||
<option value="sverige">Sverige</option>
|
||||
</Select>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Select label="Ipsum enim quis culpa" description="Aute enim" disabled>
|
||||
<option value="">Velg land</option>
|
||||
<option value="norge">Norge</option>
|
||||
<option value="sverige">Sverige</option>
|
||||
</Select>
|
||||
</Canvas>
|
||||
@@ -0,0 +1,70 @@
|
||||
import React from "react";
|
||||
import { Select } from "../index";
|
||||
import { Meta } from "@storybook/react/types-6-0";
|
||||
export default {
|
||||
title: "ds-react/form/select",
|
||||
component: Select,
|
||||
} as Meta;
|
||||
|
||||
export const All = () => {
|
||||
return (
|
||||
<div>
|
||||
<h1>Select</h1>
|
||||
|
||||
<Select label="Ipsum enim quis culpa">
|
||||
<option value="">Velg land</option>
|
||||
<option value="norge">Norge</option>
|
||||
<option value="sverige">Sverige</option>
|
||||
</Select>
|
||||
|
||||
<h2>Description</h2>
|
||||
|
||||
<Select label="Ipsum enim quis culpa" description="Aute enim">
|
||||
<option value="">Velg land</option>
|
||||
<option value="norge">Norge</option>
|
||||
<option value="sverige">Sverige</option>
|
||||
</Select>
|
||||
|
||||
<h2>Errors</h2>
|
||||
|
||||
<Select
|
||||
label="Ipsum enim quis culpa"
|
||||
description="Aute enim"
|
||||
error="Select error message"
|
||||
>
|
||||
<option value="">Velg land</option>
|
||||
<option value="norge">Norge</option>
|
||||
<option value="sverige">Sverige</option>
|
||||
</Select>
|
||||
|
||||
<h2>Sizing</h2>
|
||||
|
||||
<Select
|
||||
label="Ipsum enim quis culpa"
|
||||
description="Aute enim"
|
||||
error="Select error message"
|
||||
size="s"
|
||||
>
|
||||
<option value="">Velg land</option>
|
||||
<option value="norge">Norge</option>
|
||||
<option value="sverige">Sverige</option>
|
||||
</Select>
|
||||
|
||||
<h2>hideLabel</h2>
|
||||
|
||||
<Select label="Ipsum enim quis culpa" description="Aute enim" hideLabel>
|
||||
<option value="">Velg land</option>
|
||||
<option value="norge">Norge</option>
|
||||
<option value="sverige">Sverige</option>
|
||||
</Select>
|
||||
|
||||
<h2>Disabled</h2>
|
||||
|
||||
<Select label="Ipsum enim quis culpa" description="Aute enim" disabled>
|
||||
<option value="">Velg land</option>
|
||||
<option value="norge">Norge</option>
|
||||
<option value="sverige">Sverige</option>
|
||||
</Select>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,86 @@
|
||||
import { Meta, Canvas } from "@storybook/addon-docs";
|
||||
import { TextField } from "../index";
|
||||
|
||||
<Meta title="ds-react/form/text-field/intro" />
|
||||
|
||||
# Hvordan ta i bruk TextField
|
||||
|
||||
```jsx
|
||||
<TextField label="Laborum excepteur" />
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<TextField label="Laborum excepteur" />
|
||||
</Canvas>
|
||||
|
||||
## Description
|
||||
|
||||
```jsx
|
||||
<TextField label="Laborum excepteur" description="Cillum mollit" />
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<TextField label="Laborum excepteur" description="Cillum mollit" />
|
||||
</Canvas>
|
||||
|
||||
## Errors
|
||||
|
||||
```jsx
|
||||
<TextField
|
||||
label="Laborum excepteur"
|
||||
description="Cillum mollit"
|
||||
error="TextField error"
|
||||
/>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<TextField
|
||||
label="Laborum excepteur"
|
||||
description="Cillum mollit"
|
||||
error="TextField error"
|
||||
/>
|
||||
</Canvas>
|
||||
|
||||
## Sizing
|
||||
|
||||
```jsx
|
||||
<TextField
|
||||
size="s"
|
||||
label="Laborum excepteur"
|
||||
description="Cillum mollit"
|
||||
error="TextField error"
|
||||
/>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<TextField
|
||||
size="s"
|
||||
label="Laborum excepteur"
|
||||
description="Cillum mollit"
|
||||
error="TextField error"
|
||||
/>
|
||||
</Canvas>
|
||||
|
||||
## hideLabel
|
||||
|
||||
Ved bruk av `hideLabel` på TextField kan man gjøre slik at label/description bare vises for skjermlesere
|
||||
|
||||
```jsx
|
||||
<TextField label="Laborum excepteur" description="Cillum mollit" hideLabel />
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<TextField label="Laborum excepteur" description="Cillum mollit" hideLabel />
|
||||
</Canvas>
|
||||
|
||||
## Disabled
|
||||
|
||||
NOTE: Husk at disabled bør unngås!
|
||||
|
||||
```jsx
|
||||
<TextField label="Laborum excepteur" description="Cillum mollit" disabled />
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<TextField label="Laborum excepteur" description="Cillum mollit" disabled />
|
||||
</Canvas>
|
||||
@@ -0,0 +1,54 @@
|
||||
import React from "react";
|
||||
import { TextField } from "../index";
|
||||
import { Meta } from "@storybook/react/types-6-0";
|
||||
export default {
|
||||
title: "ds-react/form/text-field",
|
||||
component: TextField,
|
||||
} as Meta;
|
||||
|
||||
export const All = () => {
|
||||
return (
|
||||
<div style={{ maxWidth: 400 }}>
|
||||
<h1>TextField</h1>
|
||||
|
||||
<TextField label="Laborum excepteur" />
|
||||
|
||||
<h2>Description</h2>
|
||||
|
||||
<TextField label="Laborum excepteur" description="Cillum mollit" />
|
||||
|
||||
<h2>Errors</h2>
|
||||
|
||||
<TextField
|
||||
label="Laborum excepteur"
|
||||
description="Cillum mollit"
|
||||
error="TextField error"
|
||||
/>
|
||||
|
||||
<h2>Sizing</h2>
|
||||
|
||||
<TextField
|
||||
size="s"
|
||||
label="Laborum excepteur"
|
||||
description="Cillum mollit"
|
||||
error="TextField error"
|
||||
/>
|
||||
|
||||
<h2>hideLabel</h2>
|
||||
|
||||
<TextField
|
||||
label="Laborum excepteur"
|
||||
description="Cillum mollit"
|
||||
hideLabel
|
||||
/>
|
||||
|
||||
<h2>Disabled</h2>
|
||||
|
||||
<TextField
|
||||
label="Laborum excepteur"
|
||||
description="Cillum mollit"
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,167 @@
|
||||
import { Meta, Canvas } from "@storybook/addon-docs";
|
||||
import { Select, Textarea } from "../index";
|
||||
|
||||
<Meta title="ds-react/form/textarea/intro" />
|
||||
|
||||
# Hvordan ta i bruk Textarea
|
||||
|
||||
```jsx
|
||||
<Textarea
|
||||
label="In anim elit"
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
/>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Textarea
|
||||
label="In anim elit"
|
||||
value="Ullamco culpa officia incididunt consectetur voluptate consectetur eiusmod incididunt. Irure velit nulla est sit sit. In qui qui exercitation voluptate magna id officia pariatur est minim nostrud deserunt fugiat dolor. Proident cillum anim veniam quis tempor labore. Amet cupidatat cillum amet Lorem fugiat sit id esse magna fugiat qui cillum incididunt."
|
||||
onChange={() => null}
|
||||
/>
|
||||
</Canvas>
|
||||
|
||||
## Description
|
||||
|
||||
```jsx
|
||||
<Textarea
|
||||
label="In anim elit"
|
||||
description="Reprehenderit esse proident"
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
/>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Textarea
|
||||
label="In anim elit"
|
||||
description="Reprehenderit esse proident"
|
||||
value="Ullamco culpa officia incididunt consectetur voluptate consectetur eiusmod incididunt. Irure velit nulla est sit sit. In qui qui exercitation voluptate magna id officia pariatur est minim nostrud deserunt fugiat dolor. Proident cillum anim veniam quis tempor labore. Amet cupidatat cillum amet Lorem fugiat sit id esse magna fugiat qui cillum incididunt."
|
||||
onChange={() => null}
|
||||
/>
|
||||
</Canvas>
|
||||
|
||||
## maxLength
|
||||
|
||||
Viser en liten counter i nedre høyre hjørne. Markeres med røst ved for mange tegn, men fungerer bare som en
|
||||
visuell validering.
|
||||
|
||||
```jsx
|
||||
<Textarea
|
||||
label="In anim elit"
|
||||
description="Reprehenderit esse proident"
|
||||
value={value}
|
||||
maxLength={400}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
/>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Textarea
|
||||
label="In anim elit"
|
||||
description="Reprehenderit esse proident"
|
||||
maxLength={400}
|
||||
value="Ullamco culpa officia incididunt consectetur voluptate consectetur eiusmod incididunt. Irure velit nulla est sit sit. In qui qui exercitation voluptate magna id officia pariatur est minim nostrud deserunt fugiat dolor. Proident cillum anim veniam quis tempor labore. Amet cupidatat cillum amet Lorem fugiat sit id esse magna fugiat qui cillum incididunt."
|
||||
onChange={() => null}
|
||||
/>
|
||||
</Canvas>
|
||||
|
||||
## Errors
|
||||
|
||||
```jsx
|
||||
<Textarea
|
||||
label="In anim elit"
|
||||
description="Reprehenderit esse proident"
|
||||
error="Textarea error"
|
||||
value={value}
|
||||
maxLength={400}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
/>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Textarea
|
||||
label="In anim elit"
|
||||
description="Reprehenderit esse proident"
|
||||
error="Textarea error"
|
||||
maxLength={400}
|
||||
value="Ullamco culpa officia incididunt consectetur voluptate consectetur eiusmod incididunt. Irure velit nulla est sit sit. In qui qui exercitation voluptate magna id officia pariatur est minim nostrud deserunt fugiat dolor. Proident cillum anim veniam quis tempor labore. Amet cupidatat cillum amet Lorem fugiat sit id esse magna fugiat qui cillum incididunt."
|
||||
onChange={() => null}
|
||||
/>
|
||||
</Canvas>
|
||||
|
||||
## Sizing
|
||||
|
||||
```jsx
|
||||
<Textarea
|
||||
label="In anim elit"
|
||||
description="Reprehenderit esse proident"
|
||||
value={value}
|
||||
maxLength={400}
|
||||
size="s"
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
/>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Textarea
|
||||
label="In anim elit"
|
||||
description="Reprehenderit esse proident"
|
||||
maxLength={400}
|
||||
size="s"
|
||||
value="Ullamco culpa officia incididunt consectetur voluptate consectetur eiusmod incididunt. Irure velit nulla est sit sit. In qui qui exercitation voluptate magna id officia pariatur est minim nostrud deserunt fugiat dolor. Proident cillum anim veniam quis tempor labore. Amet cupidatat cillum amet Lorem fugiat sit id esse magna fugiat qui cillum incididunt."
|
||||
onChange={() => null}
|
||||
/>
|
||||
</Canvas>
|
||||
|
||||
## hideLabel
|
||||
|
||||
Ved bruk av `hideLabel` på TextField kan man gjøre slik at label/description bare vises for skjermlesere
|
||||
|
||||
```jsx
|
||||
<Textarea
|
||||
label="In anim elit"
|
||||
description="Reprehenderit esse proident"
|
||||
value={value}
|
||||
maxLength={400}
|
||||
hideLabel
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
/>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Textarea
|
||||
label="In anim elit"
|
||||
description="Reprehenderit esse proident"
|
||||
maxLength={400}
|
||||
hideLabel
|
||||
value="Ullamco culpa officia incididunt consectetur voluptate consectetur eiusmod incididunt. Irure velit nulla est sit sit. In qui qui exercitation voluptate magna id officia pariatur est minim nostrud deserunt fugiat dolor. Proident cillum anim veniam quis tempor labore. Amet cupidatat cillum amet Lorem fugiat sit id esse magna fugiat qui cillum incididunt."
|
||||
onChange={() => null}
|
||||
/>
|
||||
</Canvas>
|
||||
|
||||
## Disabled
|
||||
|
||||
NOTE: Husk at disabled bør unngås!
|
||||
|
||||
```jsx
|
||||
<Textarea
|
||||
label="In anim elit"
|
||||
description="Reprehenderit esse proident"
|
||||
value={value}
|
||||
maxLength={400}
|
||||
disabled
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
/>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Textarea
|
||||
label="In anim elit"
|
||||
description="Reprehenderit esse proident"
|
||||
maxLength={400}
|
||||
disabled
|
||||
value="Ullamco culpa officia incididunt consectetur voluptate consectetur eiusmod incididunt. Irure velit nulla est sit sit. In qui qui exercitation voluptate magna id officia pariatur est minim nostrud deserunt fugiat dolor. Proident cillum anim veniam quis tempor labore. Amet cupidatat cillum amet Lorem fugiat sit id esse magna fugiat qui cillum incididunt."
|
||||
onChange={() => null}
|
||||
/>
|
||||
</Canvas>
|
||||
@@ -0,0 +1,86 @@
|
||||
import React, { useState } from "react";
|
||||
import { Textarea } from "../index";
|
||||
import { Meta } from "@storybook/react/types-6-0";
|
||||
export default {
|
||||
title: "ds-react/form/textarea",
|
||||
component: Textarea,
|
||||
} as Meta;
|
||||
|
||||
export const All = () => {
|
||||
const [value, setValue] = useState("");
|
||||
|
||||
const handleChange = (e) => {
|
||||
setValue(e.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ maxWidth: 400 }}>
|
||||
<h1>Textarea</h1>
|
||||
|
||||
<Textarea label="In anim elit" value={value} onChange={handleChange} />
|
||||
|
||||
<h2>Description</h2>
|
||||
|
||||
<Textarea
|
||||
label="In anim elit"
|
||||
description="Reprehenderit esse proident"
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
|
||||
<h2>maxLength</h2>
|
||||
|
||||
<Textarea
|
||||
label="In anim elit"
|
||||
description="Reprehenderit esse proident"
|
||||
maxLength={400}
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
|
||||
<h2>Errors</h2>
|
||||
|
||||
<Textarea
|
||||
label="In anim elit"
|
||||
description="Reprehenderit esse proident"
|
||||
error="Textarea error"
|
||||
maxLength={400}
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
|
||||
<h2>Sizing</h2>
|
||||
|
||||
<Textarea
|
||||
label="In anim elit"
|
||||
description="Reprehenderit esse proident"
|
||||
maxLength={400}
|
||||
size="s"
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
|
||||
<h2>hideLabel</h2>
|
||||
|
||||
<Textarea
|
||||
label="In anim elit"
|
||||
description="Reprehenderit esse proident"
|
||||
maxLength={400}
|
||||
hideLabel
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
|
||||
<h2>Disabled</h2>
|
||||
|
||||
<Textarea
|
||||
label="In anim elit"
|
||||
description="Reprehenderit esse proident"
|
||||
maxLength={400}
|
||||
disabled
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Loaded 100 of 199 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user