mirror of
https://github.com/navikt/aksel.git
synced 2026-10-14 17:52:02 +00:00
Compare commits
83
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b390573946 | ||
|
|
49cb003e0a | ||
|
|
a2812ef47f | ||
|
|
1f2b183c44 | ||
|
|
8ea26e0b8c | ||
|
|
0346ef8e93 | ||
|
|
32d7a4ea41 | ||
|
|
77e66721c1 | ||
|
|
56642ed7b5 | ||
|
|
50691a5d72 | ||
|
|
6638d7f47f | ||
|
|
86ddb14c82 | ||
|
|
bd053f6312 | ||
|
|
1aaadda1f1 | ||
|
|
a0ef4e93b4 | ||
|
|
0624b8be87 | ||
|
|
8b3bf2b6a1 | ||
|
|
ff48bea20b | ||
|
|
b12ff6b18d | ||
|
|
85373402e8 | ||
|
|
2887ecef6c | ||
|
|
b79b1aba80 | ||
|
|
21cfce48c7 | ||
|
|
dcef0bf82f | ||
|
|
2ec92d5b01 | ||
|
|
f3e6791d44 | ||
|
|
96a8db13c6 | ||
|
|
379bbbe61a | ||
|
|
8029c9553a | ||
|
|
86127c9d9d | ||
|
|
f845f20d94 | ||
|
|
4034ae5e37 | ||
|
|
d5f2e044e8 | ||
|
|
d7fdc6d73c | ||
|
|
c6c721a469 | ||
|
|
b26a906300 | ||
|
|
d18a731eed | ||
|
|
cbc5940a40 | ||
|
|
104ab0d51a | ||
|
|
9a73b23e09 | ||
|
|
81a18ea271 | ||
|
|
e21bd15423 | ||
|
|
329124dda9 | ||
|
|
1662dc91c0 | ||
|
|
071962fc29 | ||
|
|
0c5085002f | ||
|
|
2a468378dd | ||
|
|
626b9069d2 | ||
|
|
49c5e8f284 | ||
|
|
0d549cb87b | ||
|
|
c0ef8a4d7d | ||
|
|
3daa36efa7 | ||
|
|
16bec93d1f | ||
|
|
ad033d9b1a | ||
|
|
b55ead2301 | ||
|
|
92532dd586 | ||
|
|
5d3361615a | ||
|
|
7779d93bf3 | ||
|
|
31bd40c02c | ||
|
|
52eda50e3c | ||
|
|
e9e5084214 | ||
|
|
dd14eb272e | ||
|
|
022d3a6a6f | ||
|
|
fcbd614a34 | ||
|
|
0a9aa6d3a1 | ||
|
|
926437f06f | ||
|
|
288456a460 | ||
|
|
61f6b62c9e | ||
|
|
dc9ffdebaf | ||
|
|
c80cb199a1 | ||
|
|
5ec431456e | ||
|
|
9e0af943a1 | ||
|
|
9ed31d5401 | ||
|
|
5248625027 | ||
|
|
f62b9a6f7b | ||
|
|
c07dd59399 | ||
|
|
88e2c2b2fe | ||
|
|
924c21365b | ||
|
|
9e1b0ab1d1 | ||
|
|
9c4d41e4c8 | ||
|
|
16e141a624 | ||
|
|
08be6c0e8b | ||
|
|
becb01d429 |
No files matched your search
@@ -0,0 +1 @@
|
||||
509e1f2ded31a7d804422d05025454fac5a4c988
|
||||
@@ -117,3 +117,4 @@ react-docgen-docs.json
|
||||
cjs
|
||||
esm
|
||||
.vercel
|
||||
_docs.json
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Meta, Canvas } from "@storybook/addon-docs";
|
||||
|
||||
<Meta title="ds-react(deprecated)/intro" />
|
||||
|
||||
# Utdaterte pakker
|
||||
|
||||
På sikt vil komponentene under bli flyttet ut av ds-react eller erstattes av andre komponenter
|
||||
|
||||
- PageHeader -> @navikt/ds-react-navno
|
||||
- MicroCard -> @navikt/ds-react-navno
|
||||
|
||||
- StepIndicator -> Horisontal `<Stepper />`
|
||||
@@ -0,0 +1,17 @@
|
||||
.rowgap {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.colgap {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
flex-direction: column;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.colgap[data-theme="dark"],
|
||||
.rowgap[data-theme="dark"] {
|
||||
background-color: #262626;
|
||||
}
|
||||
+1
-1
@@ -10,7 +10,7 @@ module.exports = {
|
||||
return config;
|
||||
},
|
||||
devServer: { stats: "errors-only" },
|
||||
stories: () => getStories(),
|
||||
stories: () => [...getStories(), "./*.stories.mdx"],
|
||||
addons: [
|
||||
"@storybook/addon-docs",
|
||||
"@storybook/addon-a11y",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import "@navikt/ds-css/index.css";
|
||||
import "@navikt/ds-css-internal/index.css";
|
||||
import "./layout.css";
|
||||
import { initialize, mswDecorator } from "msw-storybook-addon";
|
||||
|
||||
initialize();
|
||||
@@ -7,12 +8,14 @@ initialize();
|
||||
export const decorators = [mswDecorator];
|
||||
|
||||
export const parameters = {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
/* actions: { argTypesRegex: "^on[A-Z].*" }, */
|
||||
options: {
|
||||
storySort: {
|
||||
method: "",
|
||||
order: [],
|
||||
order: ["ds-icons", "ds-react", ["Default"]],
|
||||
locales: "",
|
||||
},
|
||||
},
|
||||
viewMode: "docs",
|
||||
layout: "centered",
|
||||
};
|
||||
@@ -20,10 +20,22 @@ html {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
:root,
|
||||
[data-theme="light"] {
|
||||
--navds-shadow-focus: 0 0 0 3px var(--navds-semantic-color-focus);
|
||||
|
||||
color: var(--navds-semantic-color-text);
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
--navds-shadow-focus: var(--navds-shadow-focus-inverted);
|
||||
|
||||
color: var(--navds-semantic-color-text-inverted);
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: var(--navds-font-family);
|
||||
line-height: 1.333;
|
||||
color: var(--navds-semantic-color-text);
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
:root {
|
||||
:root,
|
||||
[data-theme="light"] {
|
||||
/* Primary */
|
||||
--navds-button-color-primary-text: var(--navds-semantic-color-text-inverted);
|
||||
--navds-button-color-primary-border-focus: var(
|
||||
@@ -19,7 +20,7 @@
|
||||
--navds-semantic-color-interaction-primary
|
||||
);
|
||||
--navds-button-color-secondary-text-hover: var(
|
||||
--navds-semantic-color-text-inverted
|
||||
--navds-semantic-color-interaction-primary
|
||||
);
|
||||
--navds-button-color-secondary-text-active: var(
|
||||
--navds-semantic-color-text-inverted
|
||||
@@ -34,7 +35,7 @@
|
||||
--navds-semantic-color-component-background-light
|
||||
);
|
||||
--navds-button-color-secondary-background-hover: var(
|
||||
--navds-semantic-color-interaction-primary-hover
|
||||
--navds-semantic-color-interaction-primary-hover-subtle
|
||||
);
|
||||
--navds-button-color-secondary-background-active: var(
|
||||
--navds-semantic-color-interaction-primary-selected
|
||||
@@ -47,8 +48,8 @@
|
||||
--navds-button-color-tertiary-text-active: var(
|
||||
--navds-semantic-color-text-inverted
|
||||
);
|
||||
--navds-button-color-tertiary-border-hover: var(
|
||||
--navds-semantic-color-interaction-primary
|
||||
--navds-button-color-tertiary-background-hover: var(
|
||||
--navds-semantic-color-interaction-primary-hover-subtle
|
||||
);
|
||||
--navds-button-color-tertiary-border-focus: var(
|
||||
--navds-semantic-color-interaction-primary
|
||||
@@ -80,6 +81,39 @@
|
||||
--navds-loader-color-on-button-foreground: currentColor;
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
/* Primary */
|
||||
--navds-button-color-primary-text: var(--navds-semantic-color-text);
|
||||
--navds-button-color-primary-border-focus: var(--navds-semantic-color-text);
|
||||
--navds-button-color-primary-background: var(--navds-global-color-blue-200);
|
||||
--navds-button-color-primary-background-hover: var(
|
||||
--navds-global-color-blue-300
|
||||
);
|
||||
--navds-button-color-primary-background-active: var(
|
||||
--navds-global-color-blue-400
|
||||
);
|
||||
|
||||
/* Secondary */
|
||||
--navds-button-color-secondary-text: var(--navds-global-color-blue-200);
|
||||
--navds-button-color-secondary-text-hover: var(--navds-global-color-blue-200);
|
||||
--navds-button-color-secondary-text-active: var(
|
||||
--navds-global-color-blue-200
|
||||
);
|
||||
--navds-button-color-secondary-border: var(--navds-global-color-blue-200);
|
||||
--navds-button-color-secondary-border-focus-active-hover: var(
|
||||
--navds-semantic-color-text
|
||||
);
|
||||
--navds-button-color-secondary-background: var(
|
||||
--navds-semantic-color-component-background-inverted
|
||||
);
|
||||
--navds-button-color-secondary-background-hover: var(
|
||||
--navds-global-color-blue-900
|
||||
);
|
||||
--navds-button-color-secondary-background-active: var(
|
||||
--navds-global-color-blue-800
|
||||
);
|
||||
}
|
||||
|
||||
.navds-button {
|
||||
display: inline-flex;
|
||||
cursor: pointer;
|
||||
@@ -165,7 +199,6 @@
|
||||
.navds-button--secondary:hover {
|
||||
color: var(--navds-button-color-secondary-text-hover);
|
||||
background-color: var(--navds-button-color-secondary-background-hover);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.navds-button--secondary:focus {
|
||||
@@ -179,7 +212,6 @@
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.navds-button--secondary:focus:hover,
|
||||
.navds-button--secondary:focus:active {
|
||||
box-shadow: inset 0 0 0 1px
|
||||
var(--navds-button-color-secondary-border-focus-active-hover),
|
||||
@@ -202,7 +234,7 @@
|
||||
}
|
||||
|
||||
.navds-button--tertiary:hover {
|
||||
box-shadow: inset 0 0 0 2px var(--navds-button-color-tertiary-border-hover);
|
||||
background-color: var(--navds-button-color-tertiary-background-hover);
|
||||
}
|
||||
|
||||
.navds-button--tertiary:focus {
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
:root {
|
||||
--navds-content-container-max-width: 79.5rem;
|
||||
}
|
||||
|
||||
.navds-content-container {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 79.5rem;
|
||||
max-width: var(--navds-content-container-max-width);
|
||||
padding: var(--navds-spacing-4);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
:root {
|
||||
:root,
|
||||
[data-theme="light"] {
|
||||
--navds-search-color-text: var(--navds-semantic-color-text);
|
||||
--navds-search-color-border: var(--navds-semantic-color-border);
|
||||
--navds-search-color-border-hover: var(
|
||||
--navds-semantic-color-interaction-primary
|
||||
);
|
||||
--navds-search-color-clear-hover: var(--navds-global-color-blue-500);
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
--navds-search-color-text: var(--navds-semantic-color-text-inverted);
|
||||
--navds-search-color-border: var(--navds-semantic-color-border-inverted);
|
||||
--navds-search-color-border-hover: var(--navds-global-color-blue-200);
|
||||
--navds-search-color-clear-hover: var(--navds-global-color-blue-200);
|
||||
}
|
||||
|
||||
.navds-search {
|
||||
@@ -22,22 +32,45 @@
|
||||
}
|
||||
|
||||
.navds-search__input {
|
||||
padding-right: var(--navds-spacing-12);
|
||||
padding-right: var(--navds-spacing-10);
|
||||
}
|
||||
|
||||
.navds-form-field--small .navds-search__input {
|
||||
padding-right: var(--navds-spacing-8);
|
||||
}
|
||||
|
||||
.navds-search__input--simple {
|
||||
padding-left: var(--navds-spacing-11);
|
||||
}
|
||||
|
||||
.navds-form-field--small .navds-search__input--simple {
|
||||
padding-left: var(--navds-spacing-7);
|
||||
}
|
||||
|
||||
.navds-search__input:not(.navds-search__input--simple) {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.navds-form-field--small .navds-search__input {
|
||||
min-height: 32px;
|
||||
padding: 0.15rem;
|
||||
padding-right: var(--navds-spacing-8);
|
||||
.navds-search__search-icon {
|
||||
position: absolute;
|
||||
left: var(--navds-spacing-3);
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
pointer-events: none;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.navds-form-field--small .navds-search__search-icon {
|
||||
left: var(--navds-spacing-2);
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.navds-search__button-clear {
|
||||
position: absolute;
|
||||
right: 0.75rem;
|
||||
border-radius: var(--navds-border-radius-medium);
|
||||
color: var(--navds-semantic-color-text);
|
||||
color: var(--navds-search-color-text);
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
top: 50%;
|
||||
@@ -59,7 +92,7 @@
|
||||
}
|
||||
|
||||
.navds-search__button-clear:hover {
|
||||
color: var(--navds-global-color-blue-500);
|
||||
color: var(--navds-search-color-clear-hover);
|
||||
}
|
||||
|
||||
.navds-search__button-clear:focus {
|
||||
@@ -84,13 +117,13 @@
|
||||
min-width: 40px;
|
||||
}
|
||||
|
||||
.navds-search__button-search.navds-button--tertiary {
|
||||
.navds-search__button-search.navds-button--secondary {
|
||||
box-shadow: -1px 0 0 0 var(--navds-search-color-border) inset,
|
||||
0 1px 0 0 var(--navds-search-color-border) inset,
|
||||
0 -1px 0 0 var(--navds-search-color-border) inset;
|
||||
}
|
||||
|
||||
.navds-search__button-search.navds-button--tertiary:hover {
|
||||
.navds-search__button-search.navds-button--secondary:hover {
|
||||
box-shadow: -1px 0 0 0 var(--navds-search-color-border-hover) inset,
|
||||
0 1px 0 0 var(--navds-search-color-border-hover) inset,
|
||||
0 -1px 0 0 var(--navds-search-color-border-hover) inset,
|
||||
@@ -99,21 +132,21 @@
|
||||
}
|
||||
|
||||
.navds-search__wrapper-inner:focus-within
|
||||
+ .navds-search__button-search.navds-button--tertiary:hover {
|
||||
+ .navds-search__button-search.navds-button--secondary:hover {
|
||||
z-index: auto;
|
||||
}
|
||||
|
||||
.navds-search__button-search.navds-button--tertiary:focus {
|
||||
.navds-search__button-search.navds-button--secondary:focus {
|
||||
box-shadow: 0 0 0 1px var(--navds-search-color-border) inset,
|
||||
var(--navds-shadow-focus);
|
||||
}
|
||||
|
||||
.navds-search__button-search.navds-button--tertiary:focus:hover {
|
||||
.navds-search__button-search.navds-button--secondary:focus:hover {
|
||||
box-shadow: 0 0 0 1px var(--navds-search-color-border-hover) inset,
|
||||
var(--navds-shadow-focus);
|
||||
}
|
||||
|
||||
.navds-search__button-search.navds-button--tertiary:focus:active {
|
||||
.navds-search__button-search.navds-button--secondary:focus:active {
|
||||
box-shadow: 0 0 0 1px white inset, var(--navds-shadow-focus);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
:root {
|
||||
:root,
|
||||
[data-theme="light"] {
|
||||
--navds-text-field-color-text: var(--navds-semantic-color-text);
|
||||
--navds-text-field-color-background: var(
|
||||
--navds-semantic-color-component-background-light
|
||||
@@ -18,11 +19,24 @@
|
||||
--navds-semantic-color-component-background-alternate
|
||||
);
|
||||
--navds-text-field-color-text-disabled: var(--navds-semantic-color-text);
|
||||
--navds-text-field-color-placeholder-text: var(
|
||||
--navds-semantic-color-text-muted
|
||||
);
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
--navds-text-field-color-text: var(--navds-semantic-color-text-inverted);
|
||||
--navds-text-field-color-background: var(
|
||||
--navds-semantic-color-component-background-dark
|
||||
);
|
||||
--navds-text-field-color-border: var(--navds-semantic-color-border-inverted);
|
||||
--navds-text-field-color-border-hover: var(--navds-global-color-blue-200);
|
||||
--navds-text-field-color-placeholder-text: var(--navds-global-color-gray-500);
|
||||
}
|
||||
|
||||
.navds-text-field__input {
|
||||
appearance: none;
|
||||
padding: 0.5rem;
|
||||
padding: var(--navds-spacing-2);
|
||||
background-color: var(--navds-text-field-color-background);
|
||||
border-radius: var(--navds-border-radius-medium);
|
||||
border: 1px solid var(--navds-text-field-color-border);
|
||||
@@ -31,7 +45,11 @@
|
||||
color: var(--navds-text-field-color-text);
|
||||
}
|
||||
|
||||
.navds-form-field--small > .navds-text-field__input {
|
||||
.navds-text-field__input::placeholder {
|
||||
color: var(--navds-text-field-color-placeholder-text);
|
||||
}
|
||||
|
||||
.navds-form-field--small .navds-text-field__input {
|
||||
padding: 0 0.25rem;
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
@@ -17,13 +17,16 @@
|
||||
@import "pagination.css";
|
||||
@import "popover.css";
|
||||
@import "tag.css";
|
||||
@import "tooltip.css";
|
||||
@import "toggle-group.css";
|
||||
@import "panel.css";
|
||||
@import "link-panel.css";
|
||||
@import "read-more.css";
|
||||
@import "speech-bubble.css";
|
||||
@import "step-indicator.css";
|
||||
@import "stepper.css";
|
||||
@import "table.css";
|
||||
@import "tabs.css";
|
||||
|
||||
/* Navno spesific packages */
|
||||
@import "page-header.css";
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
|
||||
.navds-link svg {
|
||||
color: var(--navds-link-color-icon);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.navds-link:focus svg {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-css",
|
||||
"version": "0.16.8",
|
||||
"version": "0.17.0",
|
||||
"private": false,
|
||||
"description": "Css for NAV Designsystem components",
|
||||
"author": "NAV Designsystem team",
|
||||
@@ -17,14 +17,15 @@
|
||||
},
|
||||
"main": "./dist/index.css",
|
||||
"scripts": {
|
||||
"build": "postcss --use postcss-import -o dist/index.css index.css",
|
||||
"build": "postcss --use postcss-import postcss-combine-duplicated-selectors -o dist/index.css index.css",
|
||||
"watch": "postcss --watch --use postcss-import -o dist/index.css index.css"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@navikt/ds-tokens": "^0.8.4",
|
||||
"@navikt/ds-tokens": "^0.9.0",
|
||||
"normalize.css": "^8.0.1",
|
||||
"postcss": "^8.3.6",
|
||||
"postcss-cli": "^8.3.1",
|
||||
"postcss-combine-duplicated-selectors": "10.0.3",
|
||||
"postcss-import": "^14.0.2"
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
align-items: center;
|
||||
gap: var(--navds-spacing-2);
|
||||
color: var(--navds-semantic-color-link);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.navds-read-more:hover {
|
||||
@@ -24,6 +25,7 @@
|
||||
}
|
||||
|
||||
.navds-read-more__expand-icon {
|
||||
flex-shrink: 0;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
.navds-stepper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
/* Step */
|
||||
.navds-stepper__step {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
padding: calc(2.25rem / 2) 0;
|
||||
display: flex;
|
||||
background: none;
|
||||
border: none;
|
||||
appearance: none;
|
||||
width: 100%;
|
||||
color: var(--navds-semantic-color-text);
|
||||
text-decoration: none;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.navds-stepper__step-number {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
margin: 0;
|
||||
margin-right: var(--navds-spacing-3);
|
||||
border-radius: var(--navds-border-radius-full);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--navds-semantic-color-interaction-primary);
|
||||
box-shadow: inset 0 0 0 2px var(--navds-semantic-color-interaction-primary);
|
||||
background-color: var(--navds-semantic-color-component-background-light);
|
||||
}
|
||||
|
||||
/* Step-states: focus, active, hover */
|
||||
.navds-stepper__step-wrapper:hover
|
||||
> .navds-stepper__step
|
||||
> .navds-stepper__step-number {
|
||||
background-color: var(
|
||||
--navds-semantic-color-interaction-primary-hover-subtle
|
||||
);
|
||||
}
|
||||
|
||||
.navds-stepper__step--active > .navds-stepper__step-number,
|
||||
.navds-stepper__step-wrapper:hover
|
||||
> .navds-stepper__step--active
|
||||
> .navds-stepper__step-number {
|
||||
color: var(--navds-semantic-color-text-inverted);
|
||||
background-color: var(--navds-semantic-color-interaction-primary-selected);
|
||||
box-shadow: inset 0 0 0 2px
|
||||
var(--navds-semantic-color-interaction-primary-selected);
|
||||
}
|
||||
|
||||
.navds-stepper__step:focus {
|
||||
box-shadow: var(--navds-shadow-focus);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.navds-stepper__step--active {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/* Step label */
|
||||
.navds-stepper__step-label {
|
||||
margin-top: 2px;
|
||||
color: var(--navds-semantic-color-interaction-primary);
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.navds-stepper__step:hover > .navds-stepper__step-label {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.navds-stepper__step--active > .navds-stepper__step-label {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.navds-stepper__step--active:hover > .navds-stepper__step-label {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Step Horizontal Lines */
|
||||
|
||||
.navds-stepper__step-wrapper:not(:last-child) > .navds-stepper__step::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: calc(28px + 8px + (2.25rem / 2));
|
||||
left: 13px;
|
||||
height: calc(100% - 2.75rem);
|
||||
display: block;
|
||||
border-left: 2px solid var(--navds-semantic-color-border-muted);
|
||||
border-radius: var(--navds-border-radius-medium);
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
@@ -47,7 +47,20 @@
|
||||
|
||||
.navds-table--zebra-stripes
|
||||
.navds-table__body
|
||||
.navds-table__row:nth-of-type(odd):not(:hover):not(.navds-table__row--selected) {
|
||||
.navds-table__row:nth-child(odd):not(:hover):not(.navds-table__row--selected) {
|
||||
background-color: var(--navds-table-row-color-background-zebra);
|
||||
}
|
||||
|
||||
.navds-table--zebra-stripes
|
||||
.navds-table__body
|
||||
.navds-table__expandable-row:nth-child(4n
|
||||
+ 1):not(:hover):not(.navds-table__row--selected) {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.navds-table--zebra-stripes
|
||||
.navds-table__body
|
||||
.navds-table__expanded-row:nth-child(4n) {
|
||||
background-color: var(--navds-table-row-color-background-zebra);
|
||||
}
|
||||
|
||||
@@ -141,3 +154,80 @@
|
||||
font-size: 1rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.navds-table__expandable-row--open .navds-table__header-cell,
|
||||
.navds-table__expandable-row--open .navds-table__data-cell {
|
||||
border-color: var(--navds-semantic-color-border-muted);
|
||||
}
|
||||
|
||||
.navds-table__expandable-row--open .navds-table__toggle-expand-cell--open {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.navds-table__toggle-expand-cell {
|
||||
padding: 0;
|
||||
width: 56px;
|
||||
}
|
||||
|
||||
.navds-table--small .navds-table__toggle-expand-cell {
|
||||
padding: 0;
|
||||
width: 36px;
|
||||
}
|
||||
|
||||
.navds-table__toggle-expand-button {
|
||||
all: unset;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
padding: var(--navds-spacing-4);
|
||||
}
|
||||
|
||||
.navds-table--small .navds-table__toggle-expand-button {
|
||||
padding: var(--navds-spacing-2);
|
||||
}
|
||||
|
||||
.navds-table__toggle-expand-button:focus {
|
||||
box-shadow: inset var(--navds-shadow-focus);
|
||||
}
|
||||
|
||||
.navds-table__expandable-icon {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.navds-table--small .navds-table__expandable-icon {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.navds-table__toggle-expand-button:hover .navds-table__expandable-icon,
|
||||
.navds-table__expandable-icon--filled {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navds-table__toggle-expand-button:hover .navds-table__expandable-icon--filled {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.navds-table__toggle-expand-cell--open .navds-table__expandable-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.navds-table__expanded-row-cell {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.navds-table__expanded-row-cell:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navds-table__expanded-row-collapse {
|
||||
transition: height 250ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
border-bottom: 1px solid var(--navds-table-cell-color-border);
|
||||
}
|
||||
|
||||
.navds-table__expanded-row-content {
|
||||
padding: var(--navds-spacing-4) 4.25rem;
|
||||
}
|
||||
|
||||
.navds-table--small .navds-table__expanded-row-content {
|
||||
padding: var(--navds-spacing-2) var(--navds-spacing-12);
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
.navds-tabs__tablist-wrapper {
|
||||
box-shadow: inset 0 -1px 0 0 var(--navds-global-color-gray-300);
|
||||
width: 100%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.navds-tabs__tablist {
|
||||
display: flex;
|
||||
max-width: 100%;
|
||||
width: auto;
|
||||
scroll-behavior: smooth;
|
||||
-ms-overflow-style: none; /* for Internet Explorer, Edge */
|
||||
scrollbar-width: none; /* for Firefox */
|
||||
overflow-x: scroll;
|
||||
}
|
||||
|
||||
.navds-tabs__tablist::-webkit-scrollbar {
|
||||
display: none; /* for Chrome, Safari, and Opera */
|
||||
}
|
||||
|
||||
.navds-tabs__scroll-button {
|
||||
padding: var(--navds-spacing-3) var(--navds-spacing-4);
|
||||
width: 44px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.navds-tabs__scroll-button--hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.navds-tabs__scroll-button svg {
|
||||
font-size: 1.25rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.navds-tabs--small .navds-tabs__scroll-button {
|
||||
padding: 0.375rem var(--navds-spacing-4);
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
.navds-tabs__tab {
|
||||
min-height: 48px;
|
||||
padding: var(--navds-spacing-3) var(--navds-spacing-4);
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--navds-semantic-color-text-muted);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.navds-tabs__tab:hover {
|
||||
box-shadow: inset 0 -3px 0 0 var(--navds-global-color-gray-300);
|
||||
}
|
||||
|
||||
.navds-tabs__tab[aria-selected="true"] {
|
||||
box-shadow: inset 0 -3px 0 0 var(--navds-semantic-color-interaction-primary);
|
||||
color: var(--navds-semantic-color-text);
|
||||
}
|
||||
|
||||
.navds-tabs__tab:focus {
|
||||
outline: none;
|
||||
box-shadow: inset var(--navds-shadow-focus);
|
||||
color: var(--navds-semantic-color-text);
|
||||
}
|
||||
|
||||
.navds-tabs__tab-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--navds-spacing-1);
|
||||
}
|
||||
|
||||
.navds-tabs__tab-icon--top > .navds-tabs__tab-inner {
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.navds-tabs__tab--small {
|
||||
min-height: 32px;
|
||||
padding: 0.375rem var(--navds-spacing-4);
|
||||
}
|
||||
|
||||
.navds-tabs__tab-icon--top,
|
||||
.navds-tabs__tab--small.navds-tabs__tab-icon--top {
|
||||
padding: var(--navds-spacing-1) var(--navds-spacing-4);
|
||||
}
|
||||
|
||||
.navds-tabs__tab svg,
|
||||
.navds-tabs__tab--small.navds-tabs__tab--icon-only svg,
|
||||
.navds-tabs__tab--small.navds-tabs__tab-icon--top svg {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.navds-tabs__tab--small svg {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.navds-tabs__tab--icon-only svg,
|
||||
.navds-tabs__tab-icon--top svg {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.navds-tabs__tabpanel:focus {
|
||||
outline: none;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
@keyframes tooltipFadeIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.navds-tooltip {
|
||||
z-index: var(--navds-z-index-tooltip);
|
||||
}
|
||||
|
||||
.navds-tooltip__inner {
|
||||
background-color: var(--navds-semantic-color-component-background-inverted);
|
||||
color: var(--navds-semantic-color-text-inverted);
|
||||
border-radius: var(--navds-border-radius-small);
|
||||
padding: 0 var(--navds-spacing-2);
|
||||
align-items: center;
|
||||
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.05))
|
||||
drop-shadow(0 1px 3px rgba(0, 0, 0, 0.1));
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
animation-duration: 0.2s;
|
||||
animation-name: tooltipFadeIn;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.navds-tooltip__arrow {
|
||||
height: 7px;
|
||||
width: 7px;
|
||||
transform: rotate(45deg);
|
||||
z-index: -1;
|
||||
background-color: var(--navds-semantic-color-component-background-inverted);
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.navds-tooltip__keys {
|
||||
padding-bottom: var(--navds-spacing-1);
|
||||
display: flex;
|
||||
gap: var(--navds-spacing-1);
|
||||
}
|
||||
|
||||
.navds-tooltip__key {
|
||||
font-family: var(--navds-font-family);
|
||||
background-color: var(--navds-global-color-gray-700);
|
||||
color: var(--navds-semantic-color-text-inverted);
|
||||
border-radius: var(--navds-border-radius-small);
|
||||
padding: 0 var(--navds-spacing-1);
|
||||
min-width: 18px;
|
||||
height: 18px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-icons",
|
||||
"version": "0.8.6",
|
||||
"version": "0.8.11",
|
||||
"private": false,
|
||||
"description": "NAVs egne ikoner i SVG og React format",
|
||||
"repository": {
|
||||
@@ -26,7 +26,7 @@
|
||||
"/meta.json"
|
||||
],
|
||||
"scripts": {
|
||||
"create-package-json-pointers-to-esm": "node ../../../utilities/scripts/createPackageJsonsWithESMPointers.js",
|
||||
"create-package-json-pointers-to-esm": "node ../../../scripts/createPackageJsonsWithESMPointers.js",
|
||||
"create-icons": "svgr --out-dir src svg",
|
||||
"clean": "rimraf src cjs esm",
|
||||
"build": "yarn clean && copyfiles util/* src && yarn create-icons && tsc && tsc -p tsconfig.esm.json && yarn create-package-json-pointers-to-esm",
|
||||
@@ -36,8 +36,8 @@
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^17.0.30",
|
||||
"react": "^17.0.0"
|
||||
"@types/react": "^17.0.30 || ^18.0.0",
|
||||
"react": "^17.0.0 || ^18.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@svgr/cli": "^5.5.0",
|
||||
@@ -49,7 +49,7 @@
|
||||
"dotenv": "^10.0.0",
|
||||
"lodash.kebabcase": "^4.1.1",
|
||||
"lodash.startcase": "4.4.0",
|
||||
"react": "^16.8.0 || ^17.0.0",
|
||||
"react": "^18.0.0",
|
||||
"rimraf": "3.0.2",
|
||||
"sharp": "0.29.1",
|
||||
"ts-node": "^10.4.0"
|
||||
|
||||
@@ -35,8 +35,8 @@ function defaultTemplate(
|
||||
${imports}
|
||||
${interfaces}
|
||||
const ${componentName} = React.forwardRef((${props}) => {
|
||||
let titleId: string | undefined = useId(_titleId);
|
||||
titleId = title ? titleId : undefined;
|
||||
let titleId: string | undefined = useId();
|
||||
titleId = title ? _titleId ? _titleId : "title-" + titleId : undefined;
|
||||
return ${jsx};
|
||||
});
|
||||
export default ${componentName}`;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-react",
|
||||
"version": "0.17.11",
|
||||
"version": "0.18.3",
|
||||
"private": false,
|
||||
"description": "NAV designsystem react components",
|
||||
"author": "NAV Designsystem team",
|
||||
@@ -24,19 +24,23 @@
|
||||
"files": [
|
||||
"/cjs",
|
||||
"/esm",
|
||||
"/src"
|
||||
"/src",
|
||||
"_docs.json"
|
||||
],
|
||||
"scripts": {
|
||||
"create-package-json-pointers-to-esm": "node ../../../utilities/scripts/createPackageJsonsWithESMPointers.js",
|
||||
"docgen": "yarn ts-node ../../../scripts/docgen.ts",
|
||||
"create-package-json-pointers-to-esm": "node ../../../scripts/createPackageJsonsWithESMPointers.js",
|
||||
"clean": "rimraf cjs esm",
|
||||
"build": "yarn run clean && tsc && tsc -p tsconfig.esm.json && yarn create-package-json-pointers-to-esm",
|
||||
"build": "yarn run clean && tsc && tsc -p tsconfig.esm.json && yarn create-package-json-pointers-to-esm && yarn docgen",
|
||||
"watch": "tsc --watch -p tsconfig.esm.json",
|
||||
"test": "jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@floating-ui/react-dom": "0.6.0",
|
||||
"@material-ui/core": "^4.12.3",
|
||||
"@navikt/ds-icons": "^0.8.6",
|
||||
"@navikt/ds-icons": "^0.8.11",
|
||||
"@popperjs/core": "^2.10.1",
|
||||
"@radix-ui/react-tabs": "0.1.5",
|
||||
"@radix-ui/react-toggle-group": "0.1.5",
|
||||
"classnames": "^2.2.6",
|
||||
"react-collapse": "^5.1.0",
|
||||
@@ -46,25 +50,28 @@
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/jest-dom": "^5.14.1",
|
||||
"@testing-library/react": "^12.1.0",
|
||||
"@testing-library/user-event": "^13.2.1",
|
||||
"@types/faker": "^5.5.8",
|
||||
"@testing-library/jest-dom": "^5.16.0",
|
||||
"@testing-library/react": "^13.0.0",
|
||||
"@testing-library/user-event": "^14.0.0",
|
||||
"@types/faker": "5.5.8",
|
||||
"@types/jest": "^27.0.1",
|
||||
"@types/react-collapse": "^5.0.1",
|
||||
"@types/react-modal": "^3.13.1",
|
||||
"@types/styled-components": "^5.1.14",
|
||||
"copyfiles": "^2.4.1",
|
||||
"faker": "^5.5.3",
|
||||
"jest": "^27.2.0",
|
||||
"react-router-dom": "^6.1.0",
|
||||
"faker": "5.5.3",
|
||||
"fast-glob": "3.2.11",
|
||||
"jest": "^27.5.0",
|
||||
"react-docgen-typescript": "2.2.2",
|
||||
"react-router-dom": "^6.3.0",
|
||||
"rimraf": "3.0.2",
|
||||
"styled-components": "^5.3.1",
|
||||
"swr": "^1.1.2",
|
||||
"ts-jest": "^27.0.5"
|
||||
"ts-jest": "^27.1.0",
|
||||
"ts-node": "10.7.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^17.0.30",
|
||||
"react": "^17.0.0"
|
||||
"@types/react": "^17.0.30 || ^18.0.0",
|
||||
"react": "^17.0.0 || ^18.0.0"
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ export interface AccordionProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const Accordion = forwardRef<HTMLDivElement, AccordionProps>(
|
||||
export const Accordion = forwardRef<HTMLDivElement, AccordionProps>(
|
||||
({ className, ...rest }, ref) => (
|
||||
<div {...rest} className={cl("navds-accordion", className)} ref={ref} />
|
||||
)
|
||||
|
||||
@@ -7,7 +7,7 @@ import { useClientLayoutEffect, useId } from "..";
|
||||
export interface AccordionHeaderProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
/**
|
||||
* Button content
|
||||
* Accordion button content
|
||||
*/
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import React, { createContext, forwardRef, useState } from "react";
|
||||
export interface AccordionItemProps
|
||||
extends React.HTMLAttributes<HTMLDivElement> {
|
||||
/**
|
||||
* Content inside accordion item
|
||||
* Content inside Accordion.Item
|
||||
*/
|
||||
children: React.ReactNode;
|
||||
/**
|
||||
@@ -13,7 +13,7 @@ export interface AccordionItemProps
|
||||
*/
|
||||
open?: boolean;
|
||||
/**
|
||||
* Defaults the accordion to opened state
|
||||
* Defaults the accordion to opened state if not controlled
|
||||
* @default false
|
||||
*/
|
||||
defaultOpen?: boolean;
|
||||
|
||||
@@ -5,7 +5,7 @@ import AccordionItem from "./AccordionItem";
|
||||
import { Accordion } from ".";
|
||||
|
||||
export default {
|
||||
title: "ds-react/accordion",
|
||||
title: "ds-react/Accordion",
|
||||
component: Accordion,
|
||||
subcomponents: {
|
||||
AccordionItem,
|
||||
@@ -14,77 +14,89 @@ export default {
|
||||
},
|
||||
};
|
||||
|
||||
export const All = () => {
|
||||
const Content = () => (
|
||||
<Accordion.Content>
|
||||
Magna aliquip aliquip fugiat nostrud nostrud velit pariatur veniam officia
|
||||
laboris voluptate officia pariatur.Lorem est ex anim velit occaecat nisi qui
|
||||
nostrud sit consectetur consectetur officia nostrud ullamco. Est ex duis
|
||||
proident nostrud elit qui laborum anim minim eu eiusmod. Veniam in nostrud
|
||||
sunt tempor velit incididunt sint ex dolor qui velit id eu. Deserunt magna
|
||||
sunt velit in. Est exercitation id cillum qui do. Minim adipisicing nostrud
|
||||
commodo proident occaecat aliquip nulla anim proident reprehenderit. Magna
|
||||
ipsum officia veniam cupidatat duis veniam dolore reprehenderit mollit
|
||||
velit.Ut consequat commodo minim occaecat id pariatur. Nisi enim tempor
|
||||
laborum commodo. Tempor sit quis nostrud eu cupidatat sunt commodo
|
||||
reprehenderit irure deserunt eiusmod ipsum. Exercitation quis commodo cillum
|
||||
eiusmod eiusmod. Do laborum qui proident commodo adipisicing eiusmod id.
|
||||
</Accordion.Content>
|
||||
);
|
||||
|
||||
export const Default = (props) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const Item = () =>
|
||||
props.controlled ? (
|
||||
<Accordion.Item
|
||||
open={open}
|
||||
renderContentWhenClosed={props.renderContentWhenClosed}
|
||||
>
|
||||
<Accordion.Header onClick={() => setOpen(!open)}>
|
||||
Accordion header text
|
||||
</Accordion.Header>
|
||||
<Content />
|
||||
</Accordion.Item>
|
||||
) : (
|
||||
<Accordion.Item renderContentWhenClosed={props.renderContentWhenClosed}>
|
||||
<Accordion.Header>Accordion header text</Accordion.Header>
|
||||
<Content />
|
||||
</Accordion.Item>
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<h1>Accordion</h1>
|
||||
<h2>Controlled</h2>
|
||||
<Accordion>
|
||||
<Accordion.Item open={open}>
|
||||
<Accordion.Header onClick={() => setOpen(!open)}>
|
||||
Accordion header text
|
||||
</Accordion.Header>
|
||||
<Accordion.Content>
|
||||
Magna aliquip aliquip fugiat nostrud nostrud velit pariatur veniam
|
||||
officia laboris voluptate officia pariatur.Lorem est ex anim velit
|
||||
occaecat nisi qui nostrud sit consectetur consectetur officia
|
||||
nostrud ullamco. Est ex duis proident nostrud elit qui laborum anim
|
||||
minim eu eiusmod. Veniam in nostrud sunt tempor velit incididunt
|
||||
sint ex dolor qui velit id eu. Deserunt magna sunt velit in. Est
|
||||
exercitation id cillum qui do. Minim adipisicing nostrud commodo
|
||||
proident occaecat aliquip nulla anim proident reprehenderit. Magna
|
||||
ipsum officia veniam cupidatat duis veniam dolore reprehenderit
|
||||
mollit velit.Ut consequat commodo minim occaecat id pariatur. Nisi
|
||||
enim tempor laborum commodo. Tempor sit quis nostrud eu cupidatat
|
||||
sunt commodo reprehenderit irure deserunt eiusmod ipsum.
|
||||
Exercitation quis commodo cillum eiusmod eiusmod. Do laborum qui
|
||||
proident commodo adipisicing eiusmod id.
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
</Accordion>
|
||||
<h2>Un-controlled</h2>
|
||||
<Accordion>
|
||||
<Accordion.Item>
|
||||
<Accordion.Header>Accordion header text</Accordion.Header>
|
||||
<Accordion.Content>
|
||||
Magna aliquip aliquip fugiat nostrud nostrud velit pariatur veniam
|
||||
officia laboris voluptate officia pariatur.Lorem est ex anim velit
|
||||
occaecat nisi qui nostrud sit consectetur consectetur officia
|
||||
nostrud ullamco. Est ex duis proident nostrud elit qui laborum anim
|
||||
minim eu eiusmod. Veniam in nostrud sunt tempor velit incididunt
|
||||
sint ex dolor qui velit id eu. Deserunt magna sunt velit in. Est
|
||||
exercitation id cillum qui do. Minim adipisicing nostrud commodo
|
||||
proident occaecat aliquip nulla anim proident reprehenderit. Magna
|
||||
ipsum officia veniam cupidatat duis veniam dolore reprehenderit
|
||||
mollit velit.Ut consequat commodo minim occaecat id pariatur. Nisi
|
||||
enim tempor laborum commodo. Tempor sit quis nostrud eu cupidatat
|
||||
sunt commodo reprehenderit irure deserunt eiusmod ipsum.
|
||||
Exercitation quis commodo cillum eiusmod eiusmod. Do laborum qui
|
||||
proident commodo adipisicing eiusmod id.
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
<Accordion.Item>
|
||||
<Accordion.Header>Accordion header text</Accordion.Header>
|
||||
<Accordion.Content>
|
||||
Magna aliquip aliquip fugiat nostrud nostrud velit pariatur veniam
|
||||
officia laboris voluptate officia pariatur.Lorem est ex anim velit
|
||||
occaecat nisi qui nostrud sit consectetur consectetur officia
|
||||
nostrud ullamco. Est ex duis proident nostrud elit qui laborum anim
|
||||
minim eu eiusmod. Veniam in nostrud sunt tempor velit incididunt
|
||||
sint ex dolor qui velit id eu. Deserunt magna sunt velit in. Est
|
||||
exercitation id cillum qui do. Minim adipisicing nostrud commodo
|
||||
proident occaecat aliquip nulla anim proident reprehenderit. Magna
|
||||
ipsum officia veniam cupidatat duis veniam dolore reprehenderit
|
||||
mollit velit.Ut consequat commodo minim occaecat id pariatur. Nisi
|
||||
enim tempor laborum commodo. Tempor sit quis nostrud eu cupidatat
|
||||
sunt commodo reprehenderit irure deserunt eiusmod ipsum.
|
||||
Exercitation quis commodo cillum eiusmod eiusmod. Do laborum qui
|
||||
proident commodo adipisicing eiusmod id.
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
</Accordion>
|
||||
</>
|
||||
<Accordion>
|
||||
{[...Array(props.nItems ? props.nItems : 2)].map((_, y) => (
|
||||
<Item key={y} />
|
||||
))}
|
||||
</Accordion>
|
||||
);
|
||||
};
|
||||
|
||||
Default.args = {
|
||||
controlled: false,
|
||||
renderContentWhenClosed: false,
|
||||
nItems: 2,
|
||||
};
|
||||
|
||||
export const Controlled = () => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [open2, setOpen2] = useState(false);
|
||||
|
||||
return (
|
||||
<Accordion>
|
||||
<Accordion.Item open={open}>
|
||||
<Accordion.Header onClick={() => setOpen(!open)}>
|
||||
Accordion header text
|
||||
</Accordion.Header>
|
||||
<Content />
|
||||
</Accordion.Item>
|
||||
<Accordion.Item open={open2}>
|
||||
<Accordion.Header onClick={() => setOpen2(!open2)}>
|
||||
Accordion header text
|
||||
</Accordion.Header>
|
||||
<Content />
|
||||
</Accordion.Item>
|
||||
</Accordion>
|
||||
);
|
||||
};
|
||||
|
||||
export const Uncontrolled = () => (
|
||||
<Accordion>
|
||||
<Accordion.Item>
|
||||
<Accordion.Header>Accordion header text</Accordion.Header>
|
||||
<Content />
|
||||
</Accordion.Item>
|
||||
<Accordion.Item>
|
||||
<Accordion.Header>Accordion header text</Accordion.Header>
|
||||
<Content />
|
||||
</Accordion.Item>
|
||||
</Accordion>
|
||||
);
|
||||
@@ -1,2 +1 @@
|
||||
export { default as Accordion } from "./Accordion";
|
||||
export * from "./Accordion";
|
||||
export { AccordionProps, default as Accordion } from "./Accordion";
|
||||
@@ -23,7 +23,7 @@ export interface AlertProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
*/
|
||||
size?: "medium" | "small";
|
||||
/**
|
||||
* Toggles full-width Alert
|
||||
* Toggles full-width Alert (removes border-radius)
|
||||
* @default false
|
||||
*/
|
||||
fullWidth?: boolean;
|
||||
@@ -52,7 +52,7 @@ export interface AlertContextProps {
|
||||
size: "medium" | "small";
|
||||
}
|
||||
|
||||
const Alert = forwardRef<HTMLDivElement, AlertProps>(
|
||||
export const Alert = forwardRef<HTMLDivElement, AlertProps>(
|
||||
(
|
||||
{
|
||||
children,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from "react";
|
||||
import { Alert } from ".";
|
||||
import { BodyLong, Heading } from "..";
|
||||
import { BodyLong, Heading as DsHeading } from "..";
|
||||
|
||||
export default {
|
||||
title: "ds-react/alert",
|
||||
title: "ds-react/Alert",
|
||||
component: Alert,
|
||||
};
|
||||
|
||||
@@ -14,111 +14,101 @@ const variants: Array<"error" | "warning" | "info" | "success"> = [
|
||||
"success",
|
||||
];
|
||||
|
||||
export const All = () => {
|
||||
export const Default = (props) => (
|
||||
<Alert
|
||||
variant={props.variant}
|
||||
size={props.size}
|
||||
fullWidth={props.fullWidth}
|
||||
inline={props.inline}
|
||||
>
|
||||
{props.children}
|
||||
</Alert>
|
||||
);
|
||||
|
||||
Default.args = {
|
||||
variant: "info",
|
||||
children: "Id elit esse enim reprehenderit enim nisi veniam nostrud.",
|
||||
};
|
||||
|
||||
export const Small = () => {
|
||||
return (
|
||||
<>
|
||||
<h1>Alert</h1>
|
||||
<div className="colgap">
|
||||
{variants.map((variant, i) => (
|
||||
<Alert key={variant} variant={variant}>
|
||||
<Alert key={variant} variant={variant} size="small">
|
||||
{new Array(i + 1).fill(
|
||||
"Id elit esse enim reprehenderit enim nisi veniam nostrud."
|
||||
)}
|
||||
</Alert>
|
||||
))}
|
||||
<h2>Small</h2>
|
||||
<div>
|
||||
{variants.map((variant, i) => (
|
||||
<Alert key={variant} variant={variant} size="small">
|
||||
{new Array(i + 1).fill(
|
||||
"Id elit esse enim reprehenderit enim nisi veniam nostrud."
|
||||
)}
|
||||
</Alert>
|
||||
))}
|
||||
</div>
|
||||
<h2>Alert fullWidth</h2>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const FullWidth = () => {
|
||||
return (
|
||||
<div className="colgap">
|
||||
{variants.map((variant, i) => (
|
||||
<Alert fullWidth key={variant} variant={variant}>
|
||||
<Alert key={variant} variant={variant} fullWidth>
|
||||
{new Array(i + 1).fill(
|
||||
"Id elit esse enim reprehenderit enim nisi veniam nostrud."
|
||||
)}
|
||||
</Alert>
|
||||
))}
|
||||
<h2>Small</h2>
|
||||
<div>
|
||||
{variants.map((variant, i) => (
|
||||
<Alert fullWidth key={variant} variant={variant} size="small">
|
||||
{new Array(i + 1).fill(
|
||||
"Id elit esse enim reprehenderit enim nisi veniam nostrud."
|
||||
)}
|
||||
</Alert>
|
||||
))}
|
||||
</div>
|
||||
<h2>Inline</h2>
|
||||
<div>
|
||||
{variants.map((variant, i) => (
|
||||
<Alert inline key={variant} variant={variant}>
|
||||
{new Array(i + 1).fill(
|
||||
"Id elit esse enim reprehenderit enim nisi veniam nostrud."
|
||||
)}
|
||||
</Alert>
|
||||
))}
|
||||
</div>
|
||||
<h2>Inline small</h2>
|
||||
<div>
|
||||
{variants.map((variant, i) => (
|
||||
<Alert inline key={variant} variant={variant} size="small">
|
||||
{new Array(i + 1).fill(
|
||||
"Id elit esse enim reprehenderit enim nisi veniam nostrud."
|
||||
)}
|
||||
</Alert>
|
||||
))}
|
||||
</div>
|
||||
<h2>Med Heading</h2>
|
||||
<div>
|
||||
{variants.map((variant, i) => (
|
||||
<Alert key={variant} variant={variant}>
|
||||
<Heading spacing size="small" level="3">
|
||||
Aliquip duis est in commodo pariatur
|
||||
</Heading>
|
||||
<BodyLong spacing>
|
||||
Ullamco ullamco laborum et commodo sint culpa cupidatat culpa qui
|
||||
laboris ex. Labore ex occaecat proident qui qui fugiat magna.
|
||||
Fugiat sint commodo consequat eu aute.
|
||||
</BodyLong>
|
||||
<Heading level="4" size="xsmall" spacing>
|
||||
Ullamco eiusmod Lorem eiusmod eu.
|
||||
</Heading>
|
||||
<BodyLong>
|
||||
Ullamco ullamco laborum et commodo sint culpa cupidatat culpa qui
|
||||
laboris ex. Labore ex occaecat proident qui qui fugiat magna.
|
||||
Fugiat sint commodo consequat eu aute.
|
||||
</BodyLong>
|
||||
</Alert>
|
||||
))}
|
||||
</div>
|
||||
<h2>Med Heading small</h2>
|
||||
<div>
|
||||
{variants.map((variant, i) => (
|
||||
<Alert key={variant} variant={variant} size="small">
|
||||
<Heading spacing size="small" level="3">
|
||||
Aliquip duis est in commodo pariatur
|
||||
</Heading>
|
||||
<BodyLong spacing>
|
||||
Ullamco ullamco laborum et commodo sint culpa cupidatat culpa qui
|
||||
laboris ex. Labore ex occaecat proident qui qui fugiat magna.
|
||||
Fugiat sint commodo consequat eu aute.
|
||||
</BodyLong>
|
||||
<Heading level="4" size="xsmall" spacing>
|
||||
Ullamco eiusmod Lorem eiusmod eu.
|
||||
</Heading>
|
||||
<BodyLong>
|
||||
Ullamco ullamco laborum et commodo sint culpa cupidatat culpa qui
|
||||
laboris ex. Labore ex occaecat proident qui qui fugiat magna.
|
||||
Fugiat sint commodo consequat eu aute.
|
||||
</BodyLong>
|
||||
</Alert>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
{variants.map((variant, i) => (
|
||||
<Alert key={variant} variant={variant} fullWidth size="small">
|
||||
{new Array(i + 1).fill(
|
||||
"Id elit esse enim reprehenderit enim nisi veniam nostrud."
|
||||
)}
|
||||
</Alert>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Inline = () => {
|
||||
return (
|
||||
<div className="colgap">
|
||||
{variants.map((variant, i) => (
|
||||
<Alert key={variant} variant={variant} inline>
|
||||
{new Array(i + 1).fill(
|
||||
"Id elit esse enim reprehenderit enim nisi veniam nostrud."
|
||||
)}
|
||||
</Alert>
|
||||
))}
|
||||
{variants.map((variant, i) => (
|
||||
<Alert key={variant} variant={variant} inline size="small">
|
||||
{new Array(i + 1).fill(
|
||||
"Id elit esse enim reprehenderit enim nisi veniam nostrud."
|
||||
)}
|
||||
</Alert>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Heading = () => {
|
||||
return (
|
||||
<div className="colgap">
|
||||
<Alert variant="info">
|
||||
<DsHeading spacing size="small" level="3">
|
||||
Aliquip duis est in commodo pariatur
|
||||
</DsHeading>
|
||||
<BodyLong>
|
||||
Ullamco ullamco laborum et commodo sint culpa cupidatat culpa qui
|
||||
laboris ex. Labore ex occaecat proident qui qui fugiat magna. Fugiat
|
||||
sint commodo consequat eu aute.
|
||||
</BodyLong>
|
||||
</Alert>
|
||||
<Alert variant="info" size="small">
|
||||
<DsHeading spacing size="xsmall" level="3">
|
||||
Aliquip duis est in commodo pariatur
|
||||
</DsHeading>
|
||||
<BodyLong>
|
||||
Ullamco ullamco laborum et commodo sint culpa cupidatat culpa qui
|
||||
laboris ex. Labore ex occaecat proident qui qui fugiat magna. Fugiat
|
||||
sint commodo consequat eu aute.
|
||||
</BodyLong>
|
||||
</Alert>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,2 +1,2 @@
|
||||
export { default as Alert } from "./Alert";
|
||||
export * from "./Alert";
|
||||
export { AlertProps } from "./Alert";
|
||||
@@ -7,11 +7,11 @@ import { useClientLayoutEffect } from "../util";
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
/**
|
||||
* Component content
|
||||
* Button content
|
||||
*/
|
||||
children: React.ReactNode;
|
||||
/**
|
||||
* Changes design and interactions
|
||||
* Changes design and interaction-visuals
|
||||
* @default "primary"
|
||||
*/
|
||||
variant?: "primary" | "secondary" | "tertiary" | "danger";
|
||||
@@ -33,7 +33,10 @@ export interface ButtonProps
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
const Button: OverridableComponent<ButtonProps, HTMLButtonElement> = forwardRef(
|
||||
export const Button: OverridableComponent<
|
||||
ButtonProps,
|
||||
HTMLButtonElement
|
||||
> = forwardRef(
|
||||
(
|
||||
{
|
||||
as: Component = "button",
|
||||
|
||||
@@ -1,30 +1,29 @@
|
||||
import React, { useState } from "react";
|
||||
import { Star } from "@navikt/ds-icons";
|
||||
import React from "react";
|
||||
import { Button } from "./index";
|
||||
import { Success } from "@navikt/ds-icons";
|
||||
|
||||
export default {
|
||||
title: "ds-react/button",
|
||||
title: "ds-react/Button",
|
||||
component: Button,
|
||||
parameters: {
|
||||
chromatic: { delay: 300 },
|
||||
},
|
||||
argTypes: {
|
||||
variant: {
|
||||
control: {
|
||||
type: "radio",
|
||||
options: ["primary", "secondary", "tertiary", "danger"],
|
||||
},
|
||||
},
|
||||
size: {
|
||||
control: {
|
||||
type: "radio",
|
||||
options: ["medium", "small"],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const Section = ({ children }) => (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
gap: 16,
|
||||
gridAutoFlow: "column",
|
||||
justifyContent: "start",
|
||||
padding: 24,
|
||||
paddingLeft: 0,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
const variants: Array<"primary" | "secondary" | "tertiary" | "danger"> = [
|
||||
"primary",
|
||||
"secondary",
|
||||
@@ -39,119 +38,132 @@ const varSwitch = {
|
||||
danger: "Danger",
|
||||
};
|
||||
|
||||
export const All = () => {
|
||||
const [loadingState, setLoadingState] = useState(true);
|
||||
const [content, setContent] = useState<string>("");
|
||||
|
||||
const toggleLoading = () => {
|
||||
setLoadingState(!loadingState);
|
||||
};
|
||||
|
||||
export const Default = (props) => {
|
||||
return (
|
||||
<div style={{ paddingLeft: "1rem" }}>
|
||||
<h1>Button</h1>
|
||||
<Section>
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant}>
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</Section>
|
||||
<h2>disabled</h2>
|
||||
<Section>
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} disabled>
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</Section>
|
||||
<h2>As link</h2>
|
||||
<Section>
|
||||
{variants.map((variant) => (
|
||||
<Button as="a" key={variant} variant={variant} href="the-link">
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</Section>
|
||||
<h2>Small</h2>
|
||||
<Section>
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} size="small">
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</Section>
|
||||
<h2>Xsmall</h2>
|
||||
<Section>
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} size="xsmall">
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</Section>
|
||||
<h2>Button w/icon</h2>
|
||||
<Section>
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant}>
|
||||
{variant} <Success />
|
||||
</Button>
|
||||
))}
|
||||
</Section>
|
||||
<Section>
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant}>
|
||||
<span className="navds-sr-only">Success ikon</span>
|
||||
<Success />
|
||||
</Button>
|
||||
))}
|
||||
</Section>
|
||||
<h2>Small w/icon</h2>
|
||||
<Section>
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} size="small">
|
||||
<Success /> {variant}
|
||||
</Button>
|
||||
))}
|
||||
</Section>
|
||||
<Section>
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} size="small">
|
||||
<span className="navds-sr-only">Success ikon</span>
|
||||
<Success />
|
||||
</Button>
|
||||
))}
|
||||
</Section>
|
||||
<h2>Button w/loader</h2>
|
||||
<Button onClick={toggleLoading}>Toggle loaders</Button>
|
||||
<Button onClick={() => setContent((content) => `${content} wat`)}>
|
||||
Change content
|
||||
</Button>
|
||||
<Section>
|
||||
{variants.map((variant) => (
|
||||
<Button
|
||||
key={variant}
|
||||
variant={variant}
|
||||
loading={loadingState}
|
||||
onClick={toggleLoading}
|
||||
>
|
||||
{content || varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</Section>
|
||||
<h2>Small w/loader</h2>
|
||||
<Section>
|
||||
{variants.map((variant) => (
|
||||
<Button
|
||||
key={variant}
|
||||
variant={variant}
|
||||
size="small"
|
||||
loading={loadingState}
|
||||
onClick={toggleLoading}
|
||||
>
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</Section>
|
||||
</div>
|
||||
<Button variant={props.variant} size={props.size} loading={props.loading}>
|
||||
{props.icon ? <Star /> : null}
|
||||
{props.children}
|
||||
{props.icon ? <Star /> : null}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
Default.args = {
|
||||
icon: false,
|
||||
loading: false,
|
||||
children: "Knapp",
|
||||
};
|
||||
|
||||
export const Small = () => (
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} size="small">
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
export const XSmall = () => (
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} size="xsmall">
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
export const Loading = () => (
|
||||
<div className="colgap">
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} loading>
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} loading size="small">
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} loading size="xsmall">
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const Icon = () => (
|
||||
<div className="colgap">
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant}>
|
||||
<Star />
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} size="small">
|
||||
<Star />
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} size="xsmall">
|
||||
<Star />
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const IconWText = () => (
|
||||
<div className="colgap">
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant}>
|
||||
<Star />
|
||||
{varSwitch[variant]}
|
||||
<Star />
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} size="small">
|
||||
<Star />
|
||||
{varSwitch[variant]}
|
||||
<Star />
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} size="xsmall">
|
||||
<Star />
|
||||
{varSwitch[variant]}
|
||||
<Star />
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const Link = () => (
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} as="a" href="#thecakeisalie">
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
@@ -1,2 +1,2 @@
|
||||
export { default as Button } from "./Button";
|
||||
export * from "./Button";
|
||||
export { ButtonProps } from "./Button";
|
||||
@@ -1,2 +1,2 @@
|
||||
export { default as MicroCard } from "./MicroCard";
|
||||
export * from "./MicroCard";
|
||||
export { MicroCardProps } from "./MicroCard";
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Meta, Canvas } from "@storybook/addon-docs";
|
||||
import { MicroCard } from "../index.ts";
|
||||
|
||||
<Meta title="ds-react/card/intro" />
|
||||
<Meta title="ds-react(deprecated)/card/intro" />
|
||||
|
||||
# Hvordan ta i bruk card
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from "react";
|
||||
import { MicroCard } from "../index";
|
||||
import { Meta } from "@storybook/react/types-6-0";
|
||||
export default {
|
||||
title: "ds-react/card",
|
||||
title: "ds-react(deprecated)/card",
|
||||
component: MicroCard,
|
||||
} as Meta;
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@ import React, { forwardRef } from "react";
|
||||
import cl from "classnames";
|
||||
import { BodyLong, Checkbox, CheckboxProps } from "..";
|
||||
|
||||
export interface ConfirmationPanelProps extends Partial<CheckboxProps> {
|
||||
export interface ConfirmationPanelProps
|
||||
extends Omit<CheckboxProps, "children"> {
|
||||
/**
|
||||
* Additional information on panel
|
||||
*/
|
||||
@@ -10,36 +11,33 @@ export interface ConfirmationPanelProps extends Partial<CheckboxProps> {
|
||||
/**
|
||||
* Checkbox label
|
||||
*/
|
||||
label: string;
|
||||
/**
|
||||
* Checked state for checkbox
|
||||
*/
|
||||
checked: boolean;
|
||||
label: React.ReactNode;
|
||||
}
|
||||
|
||||
const ConfirmationPanel = forwardRef<HTMLDivElement, ConfirmationPanelProps>(
|
||||
({ className, children, label, ...props }, ref) => {
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cl("navds-confirmation-panel", className, {
|
||||
"navds-confirmation-panel--small": props.size === "small",
|
||||
"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 const ConfirmationPanel = forwardRef<
|
||||
HTMLDivElement,
|
||||
ConfirmationPanelProps
|
||||
>(({ className, children, label, ...props }, ref) => {
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cl("navds-confirmation-panel", className, {
|
||||
"navds-confirmation-panel--small": props.size === "small",
|
||||
"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;
|
||||
@@ -24,6 +24,7 @@ export type FieldsetContextProps = {
|
||||
export const FieldsetContext = React.createContext<FieldsetContextProps | null>(
|
||||
null
|
||||
);
|
||||
|
||||
export interface FieldsetProps
|
||||
extends FormFieldProps,
|
||||
FieldsetHTMLAttributes<HTMLFieldSetElement> {
|
||||
@@ -46,7 +47,7 @@ export interface FieldsetProps
|
||||
errorPropagation?: boolean;
|
||||
}
|
||||
|
||||
const Fieldset = forwardRef<HTMLFieldSetElement, FieldsetProps>(
|
||||
export const Fieldset = forwardRef<HTMLFieldSetElement, FieldsetProps>(
|
||||
(props, ref) => {
|
||||
const {
|
||||
inputProps,
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
export { default, FieldsetProps, FieldsetContext } from "./Fieldset";
|
||||
export {
|
||||
default as Fieldset,
|
||||
FieldsetProps,
|
||||
FieldsetContext,
|
||||
} from "./Fieldset";
|
||||
@@ -19,88 +19,92 @@ export interface SelectProps
|
||||
/**
|
||||
* Label for select
|
||||
*/
|
||||
label: string;
|
||||
label: React.ReactNode;
|
||||
/**
|
||||
* 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");
|
||||
export 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;
|
||||
const {
|
||||
children,
|
||||
label,
|
||||
className,
|
||||
description,
|
||||
htmlSize,
|
||||
hideLabel = false,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cl(
|
||||
className,
|
||||
"navds-form-field",
|
||||
`navds-form-field--${size}`,
|
||||
{
|
||||
"navds-select--error": hasError,
|
||||
"navds-select--disabled": !!inputProps.disabled,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<Label
|
||||
htmlFor={inputProps.id}
|
||||
size={size}
|
||||
as="label"
|
||||
className={cl("navds-select__label", {
|
||||
"navds-sr-only": hideLabel,
|
||||
})}
|
||||
return (
|
||||
<div
|
||||
className={cl(
|
||||
className,
|
||||
"navds-form-field",
|
||||
`navds-form-field--${size}`,
|
||||
{
|
||||
"navds-select--error": hasError,
|
||||
"navds-select--disabled": !!inputProps.disabled,
|
||||
}
|
||||
)}
|
||||
>
|
||||
{label}
|
||||
</Label>
|
||||
{!!description && (
|
||||
<BodyShort
|
||||
as="div"
|
||||
className={cl("navds-select__description", {
|
||||
<Label
|
||||
htmlFor={inputProps.id}
|
||||
size={size}
|
||||
as="label"
|
||||
className={cl("navds-select__label", {
|
||||
"navds-sr-only": hideLabel,
|
||||
})}
|
||||
id={inputDescriptionId}
|
||||
size={size}
|
||||
>
|
||||
{description}
|
||||
</BodyShort>
|
||||
)}
|
||||
<div className="navds-select__container">
|
||||
<select
|
||||
{...omit(rest, ["error", "errorId", "size"])}
|
||||
{...inputProps}
|
||||
ref={ref}
|
||||
className={cl(
|
||||
"navds-select__input",
|
||||
"navds-body-short",
|
||||
`navds-body--${size ?? "medium"}`
|
||||
{label}
|
||||
</Label>
|
||||
{!!description && (
|
||||
<BodyShort
|
||||
as="div"
|
||||
className={cl("navds-select__description", {
|
||||
"navds-sr-only": hideLabel,
|
||||
})}
|
||||
id={inputDescriptionId}
|
||||
size={size}
|
||||
>
|
||||
{description}
|
||||
</BodyShort>
|
||||
)}
|
||||
<div className="navds-select__container">
|
||||
<select
|
||||
{...omit(rest, ["error", "errorId", "size"])}
|
||||
{...inputProps}
|
||||
ref={ref}
|
||||
className={cl(
|
||||
"navds-select__input",
|
||||
"navds-body-short",
|
||||
`navds-body--${size ?? "medium"}`
|
||||
)}
|
||||
size={props.htmlSize}
|
||||
>
|
||||
{children}
|
||||
</select>
|
||||
<Expand className="navds-select__chevron" aria-hidden />
|
||||
</div>
|
||||
<div id={errorId} aria-relevant="additions removals" aria-live="polite">
|
||||
{showErrorMsg && (
|
||||
<ErrorMessage size={size}>{props.error}</ErrorMessage>
|
||||
)}
|
||||
size={props.htmlSize}
|
||||
>
|
||||
{children}
|
||||
</select>
|
||||
<Expand className="navds-select__chevron" aria-hidden />
|
||||
</div>
|
||||
</div>
|
||||
<div id={errorId} aria-relevant="additions removals" aria-live="polite">
|
||||
{showErrorMsg && <ErrorMessage size={size}>{props.error}</ErrorMessage>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default Select;
|
||||
@@ -51,92 +51,94 @@ export interface SwitchProps
|
||||
position?: "left" | "right";
|
||||
}
|
||||
|
||||
const Switch = forwardRef<HTMLInputElement, SwitchProps>((props, ref) => {
|
||||
const { inputProps, size } = useFormField(props, "switch");
|
||||
export const Switch = forwardRef<HTMLInputElement, SwitchProps>(
|
||||
(props, ref) => {
|
||||
const { inputProps, size } = useFormField(props, "switch");
|
||||
|
||||
const {
|
||||
children,
|
||||
className,
|
||||
description,
|
||||
hideLabel = false,
|
||||
loading,
|
||||
checked: checkedProp,
|
||||
defaultChecked,
|
||||
position = "left",
|
||||
...rest
|
||||
} = props;
|
||||
const {
|
||||
children,
|
||||
className,
|
||||
description,
|
||||
hideLabel = false,
|
||||
loading,
|
||||
checked: checkedProp,
|
||||
defaultChecked,
|
||||
position = "left",
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
const Description = size === "medium" ? BodyShort : Detail;
|
||||
const Description = size === "medium" ? BodyShort : Detail;
|
||||
|
||||
const [checked, setChecked] = useState(
|
||||
defaultChecked ?? checkedProp ?? false
|
||||
);
|
||||
const [checked, setChecked] = useState(
|
||||
defaultChecked ?? checkedProp ?? false
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
checkedProp !== undefined && setChecked(checkedProp);
|
||||
}, [checkedProp]);
|
||||
useEffect(() => {
|
||||
checkedProp !== undefined && setChecked(checkedProp);
|
||||
}, [checkedProp]);
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setChecked(e.target.checked);
|
||||
props.onChange && props.onChange(e);
|
||||
};
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setChecked(e.target.checked);
|
||||
props.onChange && props.onChange(e);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cl(
|
||||
"navds-switch",
|
||||
props.className,
|
||||
`navds-switch--${size}`,
|
||||
`navds-switch--${position}`,
|
||||
{
|
||||
"navds-switch--loading": loading,
|
||||
"navds-switch--disabled": inputProps.disabled ?? loading,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<input
|
||||
{...omit(rest, ["size"])}
|
||||
{...omit(inputProps, ["aria-invalid", "aria-describedby"])}
|
||||
disabled={inputProps.disabled ?? loading}
|
||||
checked={checkedProp}
|
||||
defaultChecked={defaultChecked}
|
||||
ref={ref}
|
||||
type="checkbox"
|
||||
onChange={(e) => handleChange(e)}
|
||||
className={cl(className, "navds-switch__input")}
|
||||
/>
|
||||
<span className="navds-switch__track">
|
||||
<span className="navds-switch__thumb">
|
||||
{loading ? (
|
||||
<Loader size="xsmall" aria-live="polite" />
|
||||
) : checked ? (
|
||||
<SelectedIcon />
|
||||
) : null}
|
||||
return (
|
||||
<div
|
||||
className={cl(
|
||||
"navds-switch",
|
||||
props.className,
|
||||
`navds-switch--${size}`,
|
||||
`navds-switch--${position}`,
|
||||
{
|
||||
"navds-switch--loading": loading,
|
||||
"navds-switch--disabled": inputProps.disabled ?? loading,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<input
|
||||
{...omit(rest, ["size"])}
|
||||
{...omit(inputProps, ["aria-invalid", "aria-describedby"])}
|
||||
disabled={inputProps.disabled ?? loading}
|
||||
checked={checkedProp}
|
||||
defaultChecked={defaultChecked}
|
||||
ref={ref}
|
||||
type="checkbox"
|
||||
onChange={(e) => handleChange(e)}
|
||||
className={cl(className, "navds-switch__input")}
|
||||
/>
|
||||
<span className="navds-switch__track">
|
||||
<span className="navds-switch__thumb">
|
||||
{loading ? (
|
||||
<Loader size="xsmall" aria-live="polite" />
|
||||
) : checked ? (
|
||||
<SelectedIcon />
|
||||
) : null}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<label htmlFor={inputProps.id} className="navds-switch__label-wrapper">
|
||||
<div
|
||||
className={cl("navds-switch__content", {
|
||||
"navds-sr-only": hideLabel,
|
||||
"navds-switch--with-description": !!description && !hideLabel,
|
||||
})}
|
||||
>
|
||||
<BodyShort as="div" size={size} className="navds-switch__label">
|
||||
{children}
|
||||
</BodyShort>
|
||||
{description && (
|
||||
<Description
|
||||
as="div"
|
||||
size="small"
|
||||
className="navds-switch__description"
|
||||
>
|
||||
{description}
|
||||
</Description>
|
||||
)}
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
<label htmlFor={inputProps.id} className="navds-switch__label-wrapper">
|
||||
<div
|
||||
className={cl("navds-switch__content", {
|
||||
"navds-sr-only": hideLabel,
|
||||
"navds-switch--with-description": !!description && !hideLabel,
|
||||
})}
|
||||
>
|
||||
<BodyShort as="div" size={size} className="navds-switch__label">
|
||||
{children}
|
||||
</BodyShort>
|
||||
{description && (
|
||||
<Description
|
||||
as="div"
|
||||
size="small"
|
||||
className="navds-switch__description"
|
||||
>
|
||||
{description}
|
||||
</Description>
|
||||
)}
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default Switch;
|
||||
@@ -7,6 +7,14 @@ import { FormFieldProps, useFormField } from "./useFormField";
|
||||
export interface TextFieldProps
|
||||
extends FormFieldProps,
|
||||
Omit<InputHTMLAttributes<HTMLInputElement>, "size"> {
|
||||
/**
|
||||
* The current value (controlled).
|
||||
*/
|
||||
value?: string;
|
||||
/**
|
||||
* The default value (uncontrolled).
|
||||
*/
|
||||
defaultValue?: string;
|
||||
/**
|
||||
* Expose the HTML size attribute
|
||||
*/
|
||||
@@ -26,93 +34,97 @@ export interface TextFieldProps
|
||||
type?: "email" | "number" | "password" | "tel" | "text" | "url";
|
||||
}
|
||||
|
||||
const TextField = forwardRef<HTMLInputElement, TextFieldProps>((props, ref) => {
|
||||
const {
|
||||
inputProps,
|
||||
errorId,
|
||||
showErrorMsg,
|
||||
hasError,
|
||||
size,
|
||||
inputDescriptionId,
|
||||
} = useFormField(props, "textField");
|
||||
export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
|
||||
(props, ref) => {
|
||||
const {
|
||||
inputProps,
|
||||
errorId,
|
||||
showErrorMsg,
|
||||
hasError,
|
||||
size,
|
||||
inputDescriptionId,
|
||||
} = useFormField(props, "textField");
|
||||
|
||||
const {
|
||||
label,
|
||||
className,
|
||||
description,
|
||||
htmlSize,
|
||||
hideLabel = false,
|
||||
type = "text",
|
||||
...rest
|
||||
} = props;
|
||||
const {
|
||||
label,
|
||||
className,
|
||||
description,
|
||||
htmlSize,
|
||||
hideLabel = false,
|
||||
type = "text",
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cl(
|
||||
className,
|
||||
"navds-form-field",
|
||||
`navds-form-field--${size}`,
|
||||
{
|
||||
"navds-text-field--error": hasError,
|
||||
"navds-text-field--disabled": !!inputProps.disabled,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<Label
|
||||
htmlFor={inputProps.id}
|
||||
size={size}
|
||||
as="label"
|
||||
className={cl("navds-text-field__label", {
|
||||
"navds-sr-only": hideLabel,
|
||||
})}
|
||||
>
|
||||
{label}
|
||||
</Label>
|
||||
|
||||
{!!description && (
|
||||
<>
|
||||
{size === "medium" ? (
|
||||
<BodyShort
|
||||
className={cl("navds-text-field__description", {
|
||||
"navds-sr-only": hideLabel,
|
||||
})}
|
||||
id={inputDescriptionId}
|
||||
size="small"
|
||||
as="div"
|
||||
>
|
||||
{description}
|
||||
</BodyShort>
|
||||
) : (
|
||||
<Detail
|
||||
className={cl("navds-text-field__description", {
|
||||
"navds-sr-only": hideLabel,
|
||||
})}
|
||||
id={inputDescriptionId}
|
||||
size="small"
|
||||
as="div"
|
||||
>
|
||||
{description}
|
||||
</Detail>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<input
|
||||
{...omit(rest, ["error", "errorId", "size"])}
|
||||
{...inputProps}
|
||||
ref={ref}
|
||||
type={type}
|
||||
return (
|
||||
<div
|
||||
className={cl(
|
||||
"navds-text-field__input",
|
||||
"navds-body-short",
|
||||
`navds-body-${size ?? "medium"}`
|
||||
className,
|
||||
"navds-form-field",
|
||||
`navds-form-field--${size}`,
|
||||
{
|
||||
"navds-text-field--error": hasError,
|
||||
"navds-text-field--disabled": !!inputProps.disabled,
|
||||
}
|
||||
)}
|
||||
size={htmlSize}
|
||||
/>
|
||||
<div id={errorId} aria-relevant="additions removals" aria-live="polite">
|
||||
{showErrorMsg && <ErrorMessage size={size}>{props.error}</ErrorMessage>}
|
||||
>
|
||||
<Label
|
||||
htmlFor={inputProps.id}
|
||||
size={size}
|
||||
as="label"
|
||||
className={cl("navds-text-field__label", {
|
||||
"navds-sr-only": hideLabel,
|
||||
})}
|
||||
>
|
||||
{label}
|
||||
</Label>
|
||||
|
||||
{!!description && (
|
||||
<>
|
||||
{size === "medium" ? (
|
||||
<BodyShort
|
||||
className={cl("navds-text-field__description", {
|
||||
"navds-sr-only": hideLabel,
|
||||
})}
|
||||
id={inputDescriptionId}
|
||||
size="small"
|
||||
as="div"
|
||||
>
|
||||
{description}
|
||||
</BodyShort>
|
||||
) : (
|
||||
<Detail
|
||||
className={cl("navds-text-field__description", {
|
||||
"navds-sr-only": hideLabel,
|
||||
})}
|
||||
id={inputDescriptionId}
|
||||
size="small"
|
||||
as="div"
|
||||
>
|
||||
{description}
|
||||
</Detail>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<input
|
||||
{...omit(rest, ["error", "errorId", "size"])}
|
||||
{...inputProps}
|
||||
ref={ref}
|
||||
type={type}
|
||||
className={cl(
|
||||
"navds-text-field__input",
|
||||
"navds-body-short",
|
||||
`navds-body-${size ?? "medium"}`
|
||||
)}
|
||||
size={htmlSize}
|
||||
/>
|
||||
<div id={errorId} aria-relevant="additions removals" aria-live="polite">
|
||||
{showErrorMsg && (
|
||||
<ErrorMessage size={size}>{props.error}</ErrorMessage>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default TextField;
|
||||
@@ -16,8 +16,8 @@ export interface TextareaProps
|
||||
* Visually allowed length of content
|
||||
*/
|
||||
maxLength?: number;
|
||||
value: string;
|
||||
onChange: React.ChangeEventHandler<HTMLTextAreaElement>;
|
||||
value?: string;
|
||||
defaultValue?: string;
|
||||
/**
|
||||
* Maximum number of rows to display.
|
||||
* @bug Internal scrolling with `maxLength` scrolls over maxLength-text
|
||||
@@ -37,7 +37,7 @@ export interface TextareaProps
|
||||
hideLabel?: boolean;
|
||||
}
|
||||
|
||||
const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
(props, ref) => {
|
||||
const {
|
||||
inputProps,
|
||||
@@ -119,7 +119,7 @@ const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
</span>
|
||||
<Counter
|
||||
maxLength={maxLength}
|
||||
currentLength={props.value.length}
|
||||
currentLength={props.value?.length}
|
||||
size={size}
|
||||
/>
|
||||
</>
|
||||
|
||||
@@ -6,11 +6,12 @@ import { Checkbox, CheckboxGroup } from ".";
|
||||
|
||||
const firstArgumentOfFirstCall = (fn: jest.Mock) => fn.mock.calls[0][0];
|
||||
|
||||
test("checkbox group chains onChange calls", () => {
|
||||
test("checkbox group chains onChange calls", async () => {
|
||||
const onGroupChange = jest.fn();
|
||||
const onChange = jest.fn();
|
||||
const value = faker.datatype.string();
|
||||
const label = faker.datatype.string();
|
||||
const user = userEvent.setup();
|
||||
|
||||
render(
|
||||
<CheckboxGroup legend="legend" onChange={onGroupChange}>
|
||||
@@ -20,7 +21,7 @@ test("checkbox group chains onChange calls", () => {
|
||||
</CheckboxGroup>
|
||||
);
|
||||
|
||||
userEvent.click(screen.getByLabelText(label));
|
||||
await user.click(screen.getByLabelText(label));
|
||||
|
||||
expect(onGroupChange).toBeCalledTimes(1);
|
||||
expect(onGroupChange).toBeCalledWith([value]);
|
||||
@@ -36,21 +37,24 @@ describe("Checkbox handles controlled-state correctly", () => {
|
||||
</CheckboxGroup>
|
||||
);
|
||||
|
||||
test("Checkbox is still checked after click when controlled", () => {
|
||||
test("Checkbox is still checked after click when controlled", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<CheckboxComponent value={["value1", "value2"]} />);
|
||||
userEvent.click(screen.getByLabelText("label1"));
|
||||
userEvent.click(screen.getByLabelText("label2"));
|
||||
await user.click(screen.getByLabelText("label1"));
|
||||
await user.click(screen.getByLabelText("label2"));
|
||||
|
||||
expect((screen.getByLabelText("label1") as HTMLInputElement).checked).toBe(
|
||||
true
|
||||
);
|
||||
|
||||
expect((screen.getByLabelText("label2") as HTMLInputElement).checked).toBe(
|
||||
true
|
||||
);
|
||||
});
|
||||
|
||||
test("onChange called with expected values", () => {
|
||||
test("onChange called with expected values", async () => {
|
||||
const onGroupChange = jest.fn();
|
||||
const user = userEvent.setup();
|
||||
|
||||
render(
|
||||
<CheckboxComponent
|
||||
@@ -59,11 +63,11 @@ describe("Checkbox handles controlled-state correctly", () => {
|
||||
/>
|
||||
);
|
||||
|
||||
userEvent.click(screen.getByLabelText("label1"));
|
||||
await user.click(screen.getByLabelText("label1"));
|
||||
|
||||
expect(onGroupChange).lastCalledWith(["value2"]);
|
||||
|
||||
userEvent.click(screen.getByLabelText("label2"));
|
||||
await user.click(screen.getByLabelText("label2"));
|
||||
|
||||
expect(onGroupChange).lastCalledWith(["value1"]);
|
||||
});
|
||||
|
||||
@@ -31,70 +31,72 @@ export interface CheckboxProps
|
||||
indeterminate?: boolean;
|
||||
}
|
||||
|
||||
const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>((props, ref) => {
|
||||
const { inputProps, hasError, size } = useCheckbox(props);
|
||||
export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
||||
(props, ref) => {
|
||||
const { inputProps, hasError, size } = useCheckbox(props);
|
||||
|
||||
const Description = size === "medium" ? BodyShort : Detail;
|
||||
const Description = size === "medium" ? BodyShort : Detail;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cl(
|
||||
props.className,
|
||||
"navds-checkbox",
|
||||
`navds-checkbox--${size}`,
|
||||
{
|
||||
"navds-checkbox--error": hasError,
|
||||
"navds-checkbox--disabled": inputProps.disabled,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<input
|
||||
{...omit(props, [
|
||||
"children",
|
||||
"size",
|
||||
"error",
|
||||
"description",
|
||||
"hideLabel",
|
||||
"indeterminate",
|
||||
])}
|
||||
{...inputProps}
|
||||
type="checkbox"
|
||||
className="navds-checkbox__input"
|
||||
aria-checked={props.indeterminate ? "mixed" : inputProps.checked}
|
||||
ref={(el) => {
|
||||
if (el) {
|
||||
el.indeterminate = props.indeterminate ?? false;
|
||||
return (
|
||||
<div
|
||||
className={cl(
|
||||
props.className,
|
||||
"navds-checkbox",
|
||||
`navds-checkbox--${size}`,
|
||||
{
|
||||
"navds-checkbox--error": hasError,
|
||||
"navds-checkbox--disabled": inputProps.disabled,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<input
|
||||
{...omit(props, [
|
||||
"children",
|
||||
"size",
|
||||
"error",
|
||||
"description",
|
||||
"hideLabel",
|
||||
"indeterminate",
|
||||
])}
|
||||
{...inputProps}
|
||||
type="checkbox"
|
||||
className="navds-checkbox__input"
|
||||
aria-checked={props.indeterminate ? "mixed" : inputProps.checked}
|
||||
ref={(el) => {
|
||||
if (el) {
|
||||
el.indeterminate = props.indeterminate ?? false;
|
||||
}
|
||||
|
||||
if (typeof ref === "function") {
|
||||
ref(el);
|
||||
} else if (ref != null) {
|
||||
ref.current = el;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<label htmlFor={inputProps.id} className="navds-checkbox__label">
|
||||
<div
|
||||
className={cl("navds-checkbox__content", {
|
||||
"navds-sr-only": props.hideLabel,
|
||||
})}
|
||||
>
|
||||
<BodyShort as="div" size={size}>
|
||||
{props.children}
|
||||
</BodyShort>
|
||||
{props.description && (
|
||||
<Description
|
||||
as="div"
|
||||
size="small"
|
||||
className="navds-checkbox__description"
|
||||
>
|
||||
{props.description}
|
||||
</Description>
|
||||
)}
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
if (typeof ref === "function") {
|
||||
ref(el);
|
||||
} else if (ref != null) {
|
||||
ref.current = el;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<label htmlFor={inputProps.id} className="navds-checkbox__label">
|
||||
<div
|
||||
className={cl("navds-checkbox__content", {
|
||||
"navds-sr-only": props.hideLabel,
|
||||
})}
|
||||
>
|
||||
<BodyShort as="div" size={size}>
|
||||
{props.children}
|
||||
</BodyShort>
|
||||
{props.description && (
|
||||
<Description
|
||||
as="div"
|
||||
size="small"
|
||||
className="navds-checkbox__description"
|
||||
>
|
||||
{props.description}
|
||||
</Description>
|
||||
)}
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default Checkbox;
|
||||
@@ -35,7 +35,10 @@ export interface CheckboxGroupProps
|
||||
onChange?: (value: any[]) => void;
|
||||
}
|
||||
|
||||
const CheckboxGroup = forwardRef<HTMLFieldSetElement, CheckboxGroupProps>(
|
||||
export const CheckboxGroup = forwardRef<
|
||||
HTMLFieldSetElement,
|
||||
CheckboxGroupProps
|
||||
>(
|
||||
(
|
||||
{ value, defaultValue, onChange = () => {}, children, className, ...rest },
|
||||
ref
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
import React, { useState } from "react";
|
||||
import { Checkbox, CheckboxGroup } from "../../index";
|
||||
import { Meta } from "@storybook/react/types-6-0";
|
||||
|
||||
export default {
|
||||
title: "ds-react/Form/Checkbox",
|
||||
component: Checkbox,
|
||||
subcomponents: {
|
||||
CheckboxGroup,
|
||||
},
|
||||
} as Meta;
|
||||
|
||||
export const Default = (props) => {
|
||||
const [state, setState] = useState(["checkbox1"]);
|
||||
|
||||
return (
|
||||
<CheckboxGroup
|
||||
legend={props.legend}
|
||||
description={props.description}
|
||||
value={props.controlled ? state : undefined}
|
||||
onChange={props.controlled ? setState : undefined}
|
||||
hideLegend={props.hideLegend}
|
||||
error={props.errorGroup ? "Errormelding" : undefined}
|
||||
{...props}
|
||||
>
|
||||
<Checkbox
|
||||
value="checkbox1"
|
||||
indeterminate={props.indeterminate}
|
||||
hideLabel={props.hideLabel}
|
||||
>
|
||||
{props.children || "Apple"}
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
value="checkbox2"
|
||||
error={props.errorSingle}
|
||||
description={
|
||||
props.checkboxDescription ? "Orange description" : undefined
|
||||
}
|
||||
indeterminate={props.indeterminate}
|
||||
hideLabel={props.hideLabel}
|
||||
>
|
||||
{props.children || "Orange"}
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
value="checkbox3"
|
||||
indeterminate={props.indeterminate}
|
||||
hideLabel={props.hideLabel}
|
||||
>
|
||||
{props.children || "Banana"}
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
value="checkbox4"
|
||||
indeterminate={props.indeterminate}
|
||||
hideLabel={props.hideLabel}
|
||||
>
|
||||
{props.children || "Melon"}
|
||||
</Checkbox>
|
||||
</CheckboxGroup>
|
||||
);
|
||||
};
|
||||
|
||||
Default.args = {
|
||||
controlled: false,
|
||||
legend: "Legend-tekst",
|
||||
checkboxDescription: false,
|
||||
hideLegend: false,
|
||||
errorSingle: false,
|
||||
children: "",
|
||||
description: "",
|
||||
};
|
||||
|
||||
export const Group = () => (
|
||||
<CheckboxGroup legend="Group legend" defaultValue={["tekst2"]}>
|
||||
<Checkbox value="tekst">Checkboxtekst</Checkbox>
|
||||
<Checkbox value="tekst2">Checkboxtekst</Checkbox>
|
||||
</CheckboxGroup>
|
||||
);
|
||||
|
||||
export const GroupError = () => (
|
||||
<CheckboxGroup
|
||||
legend="Group legend"
|
||||
defaultValue={["tekst2"]}
|
||||
error="Group errormelding"
|
||||
>
|
||||
<Checkbox value="tekst">Checkboxtekst</Checkbox>
|
||||
<Checkbox value="tekst2">Checkboxtekst</Checkbox>
|
||||
</CheckboxGroup>
|
||||
);
|
||||
|
||||
export const GroupSmall = () => (
|
||||
<CheckboxGroup legend="Group legend" defaultValue={["tekst2"]} size="small">
|
||||
<Checkbox value="tekst">Checkboxtekst</Checkbox>
|
||||
<Checkbox value="tekst2">Checkboxtekst</Checkbox>
|
||||
</CheckboxGroup>
|
||||
);
|
||||
|
||||
export const GroupDescription = () => (
|
||||
<CheckboxGroup
|
||||
legend="Group legend"
|
||||
defaultValue={["tekst2"]}
|
||||
description="Group description"
|
||||
>
|
||||
<Checkbox value="tekst">Checkboxtekst</Checkbox>
|
||||
<Checkbox value="tekst2">Checkboxtekst</Checkbox>
|
||||
</CheckboxGroup>
|
||||
);
|
||||
|
||||
export const Single = () => (
|
||||
<div className="colspan">
|
||||
<Checkbox value="tekst">Checkboxtekst</Checkbox>
|
||||
<Checkbox value="tekst" defaultChecked>
|
||||
Checkboxtekst
|
||||
</Checkbox>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const SingleSmall = () => (
|
||||
<div className="colspan">
|
||||
<Checkbox value="tekst" size="small">
|
||||
Checkboxtekst
|
||||
</Checkbox>
|
||||
<Checkbox value="tekst" defaultChecked size="small">
|
||||
Checkboxtekst
|
||||
</Checkbox>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const SingleDescription = () => (
|
||||
<div className="colspan">
|
||||
<Checkbox value="tekst" description="checkboxdescription">
|
||||
Checkboxtekst
|
||||
</Checkbox>
|
||||
<Checkbox value="tekst" defaultChecked description="checkboxdescription">
|
||||
Checkboxtekst
|
||||
</Checkbox>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const SingleError = () => (
|
||||
<div className="colspan">
|
||||
<Checkbox value="tekst" error>
|
||||
Checkboxtekst
|
||||
</Checkbox>
|
||||
<Checkbox value="tekst" defaultChecked error>
|
||||
Checkboxtekst
|
||||
</Checkbox>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const Indeterminate = () => {
|
||||
const [checked, setChecked] = useState([true, false]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Checkbox
|
||||
checked={checked[0] && checked[1]}
|
||||
indeterminate={checked[0] !== checked[1]}
|
||||
onChange={(e) => setChecked([e.target.checked, e.target.checked])}
|
||||
>
|
||||
Parent
|
||||
</Checkbox>
|
||||
<div style={{ paddingLeft: "2rem" }}>
|
||||
<Checkbox
|
||||
checked={checked[0]}
|
||||
onChange={(e) => setChecked([e.target.checked, checked[1]])}
|
||||
>
|
||||
Child 1
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
checked={checked[1]}
|
||||
onChange={(e) => setChecked([checked[0], e.target.checked])}
|
||||
>
|
||||
Child 2
|
||||
</Checkbox>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,203 +0,0 @@
|
||||
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
|
||||
|
||||
Feilmeldinger kan bare settes på gruppa
|
||||
|
||||
```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>
|
||||
|
||||
Enkelt-checkboxer tar en `boolean` error prop
|
||||
|
||||
```jsx
|
||||
<Checkbox value="Apple" error>
|
||||
Apple
|
||||
</Checkbox>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Checkbox value="Apple" error>
|
||||
Apple
|
||||
</Checkbox>
|
||||
</Canvas>
|
||||
|
||||
## Sizing
|
||||
|
||||
Checkboxer har default 48px høy klikkflate. Med size="small" blir klikkflaten 32px
|
||||
|
||||
```jsx
|
||||
<CheckboxGroup
|
||||
legend="Mollit eiusmod"
|
||||
error="Boks nr 2 må være valgt"
|
||||
size="small"
|
||||
>
|
||||
<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="small"
|
||||
>
|
||||
<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
|
||||
<Checkbox value="Orange" hideLabel>
|
||||
Orange
|
||||
</Checkbox>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<Checkbox value="Orange" hideLabel>
|
||||
Orange
|
||||
</Checkbox>
|
||||
</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>
|
||||
@@ -1,109 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import { Checkbox, CheckboxGroup } from "../../index";
|
||||
import { Meta } from "@storybook/react/types-6-0";
|
||||
import { CheckboxGroupProps } from "..";
|
||||
export default {
|
||||
title: "ds-react/form/checkbox",
|
||||
component: Checkbox,
|
||||
} as Meta;
|
||||
|
||||
export const Indeterminate = () => {
|
||||
const [checked, setChecked] = useState([true, false]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Checkbox
|
||||
checked={checked[0] && checked[1]}
|
||||
indeterminate={checked[0] !== checked[1]}
|
||||
onChange={(e) => setChecked([e.target.checked, e.target.checked])}
|
||||
>
|
||||
Parent
|
||||
</Checkbox>
|
||||
<div style={{ paddingLeft: "2rem" }}>
|
||||
<Checkbox
|
||||
checked={checked[0]}
|
||||
onChange={(e) => setChecked([e.target.checked, checked[1]])}
|
||||
>
|
||||
Child 1
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
checked={checked[1]}
|
||||
onChange={(e) => setChecked([checked[0], e.target.checked])}
|
||||
>
|
||||
Child 2
|
||||
</Checkbox>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const All = () => {
|
||||
const Checkboxes = (
|
||||
props: Omit<CheckboxGroupProps, "legend" | "description" | "children">
|
||||
) => (
|
||||
<CheckboxGroup
|
||||
legend="Mollit eiusmod"
|
||||
description="Exercitation do labore"
|
||||
{...props}
|
||||
>
|
||||
<Checkbox value={1}>Apple</Checkbox>
|
||||
<Checkbox value="Orange" description="Laborum ad">
|
||||
Orange
|
||||
</Checkbox>
|
||||
<Checkbox value="Banana" description={<div>Laborum ad</div>}>
|
||||
Banana
|
||||
</Checkbox>
|
||||
<Checkbox value="Melon">Melon</Checkbox>
|
||||
</CheckboxGroup>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>Checkbox</h1>
|
||||
<h2>Single checkbox</h2>
|
||||
<Checkbox value="Apple">Apple</Checkbox>
|
||||
<h3>Desription</h3>
|
||||
<Checkbox value={1} description="Laborum ad" defaultChecked>
|
||||
Apple
|
||||
</Checkbox>
|
||||
<h3>Error</h3>
|
||||
<Checkbox value="Apple" error>
|
||||
Apple
|
||||
</Checkbox>
|
||||
<Checkbox value="Apple" error defaultChecked>
|
||||
Orange
|
||||
</Checkbox>
|
||||
<h3>Hide label</h3>
|
||||
<Checkbox value="Apple" hideLabel description="Laborum ad">
|
||||
Apple
|
||||
</Checkbox>
|
||||
<h3>Disabled</h3>
|
||||
<Checkbox value="Apple" disabled>
|
||||
Apple
|
||||
</Checkbox>
|
||||
<Checkbox value="Orange" description="Laborum ad" disabled defaultChecked>
|
||||
Orange
|
||||
</Checkbox>
|
||||
<h3>Indeterminate</h3>
|
||||
<Checkbox value="Apple" indeterminate>
|
||||
Apple
|
||||
</Checkbox>
|
||||
<Checkbox value="Orange" indeterminate size="small">
|
||||
Orange
|
||||
</Checkbox>
|
||||
|
||||
<h2>Checkbox group</h2>
|
||||
<Checkboxes />
|
||||
<h3>Error</h3>
|
||||
<Checkboxes error="Dette er en feilmelding" />
|
||||
<h3>Small</h3>
|
||||
<Checkboxes size="small" />
|
||||
<h3>Small + error</h3>
|
||||
<Checkboxes size="small" error="Dette er en feilmelding" />
|
||||
<h3>Default value</h3>
|
||||
<Checkboxes defaultValue={[1, "Melon"]} />
|
||||
<h3>Disabled</h3>
|
||||
<Checkboxes disabled />
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -31,7 +31,7 @@ interface ErrorSummaryComponent
|
||||
Item: ErrorSummaryItemType;
|
||||
}
|
||||
|
||||
const ErrorSummary = forwardRef<HTMLDivElement, ErrorSummaryProps>(
|
||||
export const ErrorSummary = forwardRef<HTMLDivElement, ErrorSummaryProps>(
|
||||
(
|
||||
{
|
||||
children,
|
||||
|
||||
@@ -15,7 +15,7 @@ export type ErrorSummaryItemType = OverridableComponent<
|
||||
HTMLAnchorElement
|
||||
>;
|
||||
|
||||
const ErrorSummaryItem: ErrorSummaryItemType = forwardRef(
|
||||
export const ErrorSummaryItem: ErrorSummaryItemType = forwardRef(
|
||||
({ children, as: Component = "a", className, ...rest }, ref) => {
|
||||
return (
|
||||
<Component
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import React from "react";
|
||||
import { Meta } from "@storybook/react/types-6-0";
|
||||
import { ErrorSummary } from "..";
|
||||
export default {
|
||||
title: "ds-react/Form/Errorsummary",
|
||||
component: ErrorSummary,
|
||||
argTypes: {
|
||||
headingTag: {
|
||||
control: {
|
||||
type: "text",
|
||||
},
|
||||
},
|
||||
size: {
|
||||
control: {
|
||||
type: "radio",
|
||||
options: ["medium", "small"],
|
||||
},
|
||||
},
|
||||
},
|
||||
} as Meta;
|
||||
|
||||
export const Default = (props) => (
|
||||
<ErrorSummary
|
||||
heading="Feiloppsummering komponent"
|
||||
headingTag={props.headingTag || "h2"}
|
||||
size={props.size ?? undefined}
|
||||
>
|
||||
<ErrorSummary.Item href="#1">Checkbox må fylles ut</ErrorSummary.Item>
|
||||
<ErrorSummary.Item href="#2">
|
||||
Tekstfeltet må ha en godkjent e-mail
|
||||
</ErrorSummary.Item>
|
||||
</ErrorSummary>
|
||||
);
|
||||
|
||||
export const Small = () => (
|
||||
<ErrorSummary heading="Feiloppsummering komponent" size="small">
|
||||
<ErrorSummary.Item href="#1">Checkbox må fylles ut</ErrorSummary.Item>
|
||||
<ErrorSummary.Item href="#2">
|
||||
Tekstfeltet må ha en godkjent e-mail
|
||||
</ErrorSummary.Item>
|
||||
</ErrorSummary>
|
||||
);
|
||||
@@ -1,2 +1,2 @@
|
||||
export { default as ErrorSummary } from "./ErrorSummary";
|
||||
export * from "./ErrorSummary";
|
||||
export { ErrorSummaryProps } from "./ErrorSummary";
|
||||
@@ -1,54 +0,0 @@
|
||||
import { Meta, Canvas } from "@storybook/addon-docs";
|
||||
import { ErrorSummary } from "../index";
|
||||
|
||||
<Meta title="ds-react/form/errorsummary/intro" />
|
||||
|
||||
# Hvordan ta i bruk ErrorSummary
|
||||
|
||||
`href` på `ErrorSummary.Item` linker til id som er satt på skjema-elementer.
|
||||
|
||||
```jsx
|
||||
<ErrorSummary heading="Eiusmod est cillum mollit pariatur deserunt">
|
||||
<ErrorSummary.Item href="#1">Checkbox må fylles ut</ErrorSummary.Item>
|
||||
<ErrorSummary.Item href="#2">
|
||||
Tekstfeltet må ha en godkjent e-mail
|
||||
</ErrorSummary.Item>
|
||||
</ErrorSummary>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<ErrorSummary heading="Eiusmod est cillum mollit pariatur deserunt">
|
||||
<ErrorSummary.Item href="#1">Checkbox må fylles ut</ErrorSummary.Item>
|
||||
<ErrorSummary.Item href="#2">
|
||||
Tekstfeltet må ha en godkjent e-mail
|
||||
</ErrorSummary.Item>
|
||||
</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"
|
||||
>
|
||||
<ErrorSummary.Item href="#1">Checkbox må fylles ut</ErrorSummary.Item>
|
||||
<ErrorSummary.Item href="#2">
|
||||
Tekstfeltet må ha en godkjent e-mail
|
||||
</ErrorSummary.Item>
|
||||
</ErrorSummary>
|
||||
```
|
||||
|
||||
<Canvas>
|
||||
<ErrorSummary
|
||||
heading="Eiusmod est cillum mollit pariatur deserunt"
|
||||
headingTag="h3"
|
||||
>
|
||||
<ErrorSummary.Item href="#1">Checkbox må fylles ut</ErrorSummary.Item>
|
||||
<ErrorSummary.Item href="#2">
|
||||
Tekstfeltet må ha en godkjent e-mail
|
||||
</ErrorSummary.Item>
|
||||
</ErrorSummary>
|
||||
</Canvas>
|
||||
@@ -1,28 +0,0 @@
|
||||
import React from "react";
|
||||
import { Meta } from "@storybook/react/types-6-0";
|
||||
import { ErrorSummary } 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">
|
||||
<ErrorSummary.Item href="#1">Checkbox må fylles ut</ErrorSummary.Item>
|
||||
<ErrorSummary.Item href="#2">
|
||||
Tekstfeltet må ha en godkjent e-mail
|
||||
</ErrorSummary.Item>
|
||||
</ErrorSummary>
|
||||
<h2>size small</h2>
|
||||
<ErrorSummary size="small" heading="Feiloppsummering komponent">
|
||||
<ErrorSummary.Item href="#1">Checkbox må fylles ut</ErrorSummary.Item>
|
||||
<ErrorSummary.Item href="#2">
|
||||
Tekstfeltet må ha en godkjent e-mail
|
||||
</ErrorSummary.Item>
|
||||
</ErrorSummary>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,22 +1,18 @@
|
||||
export {
|
||||
Checkbox,
|
||||
CheckboxProps,
|
||||
CheckboxGroup,
|
||||
CheckboxGroupProps,
|
||||
CheckboxProps,
|
||||
} from "./checkbox";
|
||||
export {
|
||||
default as Fieldset,
|
||||
FieldsetContext,
|
||||
FieldsetProps,
|
||||
} from "./Fieldset";
|
||||
ConfirmationPanelProps,
|
||||
default as ConfirmationPanel,
|
||||
} from "./ConfirmationPanel";
|
||||
export { ErrorSummary, ErrorSummaryProps } from "./error-summary";
|
||||
export { Fieldset, FieldsetContext, FieldsetProps } from "./Fieldset";
|
||||
export { Radio, RadioGroup, RadioGroupProps, RadioProps } from "./radio";
|
||||
export { Search, SearchProps, SearchClearEvent } from "./search";
|
||||
export { Search, SearchClearEvent, SearchProps } from "./search";
|
||||
export { default as Select, SelectProps } from "./Select";
|
||||
export { default as Switch, SwitchProps } from "./Switch";
|
||||
export { ErrorSummary, ErrorSummaryProps } 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";
|
||||
@@ -31,7 +31,9 @@ describe("Controlled RadioGroup", () => {
|
||||
});
|
||||
|
||||
describe("Uncontrolled RadioGroup", () => {
|
||||
test("handles state correctly", () => {
|
||||
test("handles state correctly", async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
render(<Group />);
|
||||
|
||||
const input1 = screen.getByLabelText(label1) as HTMLInputElement;
|
||||
@@ -40,13 +42,14 @@ describe("Uncontrolled RadioGroup", () => {
|
||||
expect(input1.checked).toBe(false);
|
||||
expect(input2.checked).toBe(false);
|
||||
|
||||
userEvent.click(screen.getByLabelText(label2));
|
||||
await user.click(screen.getByLabelText(label2));
|
||||
|
||||
expect(input1.checked).toBe(false);
|
||||
expect(input2.checked).toBe(true);
|
||||
});
|
||||
|
||||
test("handles defaultValue correctly", () => {
|
||||
test("handles defaultValue correctly", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<Group defaultValue={value1} />);
|
||||
|
||||
const input1 = screen.getByLabelText(label1) as HTMLInputElement;
|
||||
@@ -55,7 +58,7 @@ describe("Uncontrolled RadioGroup", () => {
|
||||
expect(input1.checked).toBe(true);
|
||||
expect(input2.checked).toBe(false);
|
||||
|
||||
userEvent.click(screen.getByLabelText(label2));
|
||||
await user.click(screen.getByLabelText(label2));
|
||||
|
||||
expect(input1.checked).toBe(false);
|
||||
expect(input2.checked).toBe(true);
|
||||
|
||||
@@ -17,7 +17,7 @@ export interface RadioProps
|
||||
value: any;
|
||||
}
|
||||
|
||||
const Radio = forwardRef<HTMLInputElement, RadioProps>((props, ref) => {
|
||||
export const Radio = forwardRef<HTMLInputElement, RadioProps>((props, ref) => {
|
||||
const { inputProps, size, hasError } = useRadio(props);
|
||||
|
||||
const Description = size === "medium" ? BodyShort : Detail;
|
||||
|
||||
@@ -46,7 +46,7 @@ export interface RadioGroupProps
|
||||
required?: boolean;
|
||||
}
|
||||
|
||||
const RadioGroup = forwardRef<HTMLFieldSetElement, RadioGroupProps>(
|
||||
export const RadioGroup = forwardRef<HTMLFieldSetElement, RadioGroupProps>(
|
||||
(
|
||||
{
|
||||
children,
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
import React, { useState } from "react";
|
||||
import { Radio, RadioGroup } from "../../index";
|
||||
import { Meta } from "@storybook/react/types-6-0";
|
||||
|
||||
export default {
|
||||
title: "ds-react/Form/Radio",
|
||||
component: Radio,
|
||||
subcomponents: {
|
||||
RadioGroup,
|
||||
},
|
||||
} as Meta;
|
||||
|
||||
export const Default = (props) => {
|
||||
const [state, setState] = useState("radio1");
|
||||
|
||||
return (
|
||||
<RadioGroup
|
||||
legend={props.legend}
|
||||
description={props.description}
|
||||
value={props.controlled ? state : undefined}
|
||||
onChange={props.controlled ? setState : undefined}
|
||||
hideLegend={props.hideLegend}
|
||||
error={props.errorGroup ? "Errormelding" : undefined}
|
||||
{...props}
|
||||
>
|
||||
<Radio value="radio1">{props.children || "Apple"}</Radio>
|
||||
<Radio
|
||||
value="radio2"
|
||||
description={props.radioDescription ? "Orange description" : undefined}
|
||||
>
|
||||
{props.children || "Orange"}
|
||||
</Radio>
|
||||
<Radio value="radio3">{props.children || "Banana"}</Radio>
|
||||
<Radio value="radio4">{props.children || "Melon"}</Radio>
|
||||
</RadioGroup>
|
||||
);
|
||||
};
|
||||
|
||||
Default.args = {
|
||||
controlled: false,
|
||||
legend: "Legend-tekst",
|
||||
radioDescription: false,
|
||||
hideLegend: false,
|
||||
children: "",
|
||||
description: "",
|
||||
};
|
||||
|
||||
export const Group = () => (
|
||||
<RadioGroup legend="Group legend" defaultValue={"tekst2"}>
|
||||
<Radio value="tekst">Radiotekst</Radio>
|
||||
<Radio value="tekst2">Radiotekst</Radio>
|
||||
</RadioGroup>
|
||||
);
|
||||
|
||||
export const GroupError = () => (
|
||||
<RadioGroup
|
||||
legend="Group legend"
|
||||
defaultValue={"tekst2"}
|
||||
error="Group errormelding"
|
||||
>
|
||||
<Radio value="tekst">Radiotekst</Radio>
|
||||
<Radio value="tekst2">Radiotekst</Radio>
|
||||
</RadioGroup>
|
||||
);
|
||||
|
||||
export const GroupSmall = () => (
|
||||
<RadioGroup legend="Group legend" defaultValue={"tekst2"} size="small">
|
||||
<Radio value="tekst">Radiotekst</Radio>
|
||||
<Radio value="tekst2">Radiotekst</Radio>
|
||||
</RadioGroup>
|
||||
);
|
||||
|
||||
export const GroupDescription = () => (
|
||||
<RadioGroup
|
||||
legend="Group legend"
|
||||
defaultValue={"tekst2"}
|
||||
description="Group description"
|
||||
>
|
||||
<Radio value="tekst">Radiotekst</Radio>
|
||||
<Radio value="tekst2">Radiotekst</Radio>
|
||||
</RadioGroup>
|
||||
);
|
||||
@@ -1,173 +0,0 @@
|
||||
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
|
||||
|
||||
Feilmeldinger kan bare settes på gruppa
|
||||
|
||||
```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>
|
||||
|
||||
## Sizing
|
||||
|
||||
Radioknapper har default 48px høy klikkflate. Med size="small" blir klikkflaten 32px
|
||||
|
||||
```jsx
|
||||
<RadioGroup
|
||||
legend="Mollit eiusmod"
|
||||
error="Boks nr 2 må være valgt"
|
||||
size="small"
|
||||
>
|
||||
<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="small"
|
||||
>
|
||||
<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>
|
||||
@@ -1,51 +0,0 @@
|
||||
import React from "react";
|
||||
import { Meta } from "@storybook/react/types-6-0";
|
||||
import { RadioGroup, Radio } from "../index";
|
||||
import { RadioGroupProps } from "../RadioGroup";
|
||||
export default {
|
||||
title: "ds-react/form/radio",
|
||||
component: RadioGroup,
|
||||
} as Meta;
|
||||
|
||||
export const All = () => {
|
||||
const Radios = (props: Omit<RadioGroupProps, "legend" | "children">) => (
|
||||
<RadioGroup
|
||||
legend="Mollit eiusmod"
|
||||
description={<div>"Exercitation do labore"</div>}
|
||||
{...props}
|
||||
>
|
||||
<Radio value={1}>Apple</Radio>
|
||||
<Radio value={false} description={<div>Laborum ad</div>}>
|
||||
Orange
|
||||
</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>Radio group</h1>
|
||||
<Radios />
|
||||
<h2>Error</h2>
|
||||
<Radios error="Dette er en feilmelding" />
|
||||
<h2>Small</h2>
|
||||
<Radios size="small" />
|
||||
<h2>Small + error</h2>
|
||||
<Radios size="small" error="Dette er en feilmelding" />
|
||||
<h2>Default value</h2>
|
||||
<Radios defaultValue={1} />
|
||||
<h2>Disabled</h2>
|
||||
<RadioGroup legend="Mollit eiusmod" description="Exercitation do labore">
|
||||
<Radio value="Apple" disabled>
|
||||
Apple
|
||||
</Radio>
|
||||
<Radio value={false} description="Laborum ad" disabled>
|
||||
Orange
|
||||
</Radio>
|
||||
<Radio value="Melon">Melon</Radio>
|
||||
</RadioGroup>
|
||||
<h2>Disabled group</h2>
|
||||
<Radios disabled />
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,10 +1,9 @@
|
||||
import { Close } from "@navikt/ds-icons";
|
||||
import { Close, Search as SearchIcon } from "@navikt/ds-icons";
|
||||
import cl from "classnames";
|
||||
import React, {
|
||||
forwardRef,
|
||||
InputHTMLAttributes,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
@@ -39,10 +38,6 @@ export interface SearchProps
|
||||
* Callback for value-change in input
|
||||
*/
|
||||
onChange?: (value: string) => void;
|
||||
/**
|
||||
* Callback for <Search.Button/> click or onSubmit in form
|
||||
*/
|
||||
onSearch?: (value: string | number | readonly string[]) => void;
|
||||
/**
|
||||
* Callback for click on clear-button or Escape keydown
|
||||
*/
|
||||
@@ -59,9 +54,9 @@ export interface SearchProps
|
||||
clearButton?: boolean;
|
||||
/**
|
||||
* Changes button-variant
|
||||
* @default "tertiary"
|
||||
* @default "primary"
|
||||
*/
|
||||
variant?: "tertiary" | "primary";
|
||||
variant?: "primary" | "secondary" | "simple";
|
||||
}
|
||||
|
||||
interface SearchComponent
|
||||
@@ -74,159 +69,157 @@ interface SearchComponent
|
||||
export interface SearchContextProps {
|
||||
disabled?: boolean;
|
||||
size: "medium" | "small";
|
||||
variant?: "tertiary" | "primary";
|
||||
onSearch?: () => void;
|
||||
variant: "primary" | "secondary" | "simple";
|
||||
}
|
||||
|
||||
export const SearchContext = React.createContext<SearchContextProps | null>(
|
||||
null
|
||||
);
|
||||
|
||||
const Search = forwardRef<HTMLInputElement, SearchProps>((props, ref) => {
|
||||
const { inputProps, size = "medium", inputDescriptionId } = useSearch(
|
||||
props,
|
||||
"searchfield"
|
||||
);
|
||||
export const Search = forwardRef<HTMLInputElement, SearchProps>(
|
||||
(props, ref) => {
|
||||
const { inputProps, size = "medium", inputDescriptionId } = useSearch(
|
||||
props,
|
||||
"searchfield"
|
||||
);
|
||||
|
||||
const {
|
||||
className,
|
||||
hideLabel = true,
|
||||
label,
|
||||
description,
|
||||
value,
|
||||
clearButtonLabel,
|
||||
onClear,
|
||||
clearButton = true,
|
||||
children,
|
||||
onSearch,
|
||||
variant = "tertiary",
|
||||
...rest
|
||||
} = props;
|
||||
const {
|
||||
className,
|
||||
hideLabel = true,
|
||||
label,
|
||||
description,
|
||||
value,
|
||||
clearButtonLabel,
|
||||
onClear,
|
||||
clearButton = true,
|
||||
children,
|
||||
variant = "primary",
|
||||
defaultValue,
|
||||
onChange,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
const searchRef = useRef<HTMLInputElement | null>(null);
|
||||
const mergedRef = mergeRefs([searchRef, ref]);
|
||||
const [wrapperRef, setWrapperRef] = useState<HTMLDivElement | null>(null);
|
||||
const searchRef = useRef<HTMLInputElement | null>(null);
|
||||
const mergedRef = mergeRefs([searchRef, ref]);
|
||||
const [wrapperRef, setWrapperRef] = useState<HTMLDivElement | null>(null);
|
||||
|
||||
const [controlledValue, setControlledValue] = useState(value ?? "");
|
||||
const [internalValue, setInternalValue] = useState(defaultValue ?? "");
|
||||
|
||||
const handleChange = useCallback(
|
||||
(v: string) => {
|
||||
searchRef.current && value === undefined && setControlledValue(v);
|
||||
props?.onChange?.(v);
|
||||
},
|
||||
[props, value]
|
||||
);
|
||||
|
||||
const handleClear = useCallback(
|
||||
(event: SearchClearEvent) => {
|
||||
onClear?.(event);
|
||||
handleChange("");
|
||||
if (searchRef.current && value === undefined) {
|
||||
searchRef.current.value = "";
|
||||
}
|
||||
searchRef.current && searchRef.current?.focus?.();
|
||||
},
|
||||
[handleChange, onClear, value]
|
||||
);
|
||||
|
||||
useEventListener(
|
||||
"keydown",
|
||||
useCallback(
|
||||
(e) => {
|
||||
if (e.key === "Escape") {
|
||||
e.preventDefault();
|
||||
handleClear({ trigger: "Escape", event: e });
|
||||
}
|
||||
const handleChange = useCallback(
|
||||
(v: string) => {
|
||||
value === undefined && setInternalValue(v);
|
||||
onChange?.(v);
|
||||
},
|
||||
[handleClear]
|
||||
),
|
||||
wrapperRef
|
||||
);
|
||||
[onChange, value]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
value !== undefined && setControlledValue(value);
|
||||
}, [value]);
|
||||
const handleClear = useCallback(
|
||||
(event: SearchClearEvent) => {
|
||||
onClear?.(event);
|
||||
handleChange("");
|
||||
searchRef.current && searchRef.current?.focus?.();
|
||||
},
|
||||
[handleChange, onClear]
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={setWrapperRef}
|
||||
className={cl(
|
||||
className,
|
||||
"navds-form-field",
|
||||
`navds-form-field--${size}`,
|
||||
"navds-search",
|
||||
{
|
||||
"navds-search--disabled": !!inputProps.disabled,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<Label
|
||||
htmlFor={inputProps.id}
|
||||
size={size}
|
||||
as="label"
|
||||
className={cl("navds-text-field__label", {
|
||||
"navds-sr-only": hideLabel,
|
||||
})}
|
||||
useEventListener(
|
||||
"keydown",
|
||||
useCallback(
|
||||
(e) => {
|
||||
if (e.key === "Escape") {
|
||||
e.preventDefault();
|
||||
handleClear({ trigger: "Escape", event: e });
|
||||
}
|
||||
},
|
||||
[handleClear]
|
||||
),
|
||||
wrapperRef
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={setWrapperRef}
|
||||
className={cl(
|
||||
className,
|
||||
"navds-form-field",
|
||||
`navds-form-field--${size}`,
|
||||
"navds-search",
|
||||
{
|
||||
"navds-search--disabled": !!inputProps.disabled,
|
||||
}
|
||||
)}
|
||||
>
|
||||
{label}
|
||||
</Label>
|
||||
{!!description && (
|
||||
<BodyShort
|
||||
as="div"
|
||||
className={cl("navds-text-field__description", {
|
||||
<Label
|
||||
htmlFor={inputProps.id}
|
||||
size={size}
|
||||
as="label"
|
||||
className={cl("navds-text-field__label", {
|
||||
"navds-sr-only": hideLabel,
|
||||
})}
|
||||
id={inputDescriptionId}
|
||||
size={size}
|
||||
>
|
||||
{description}
|
||||
</BodyShort>
|
||||
)}
|
||||
<div className="navds-search__wrapper">
|
||||
<div className="navds-search__wrapper-inner">
|
||||
<input
|
||||
ref={mergedRef}
|
||||
{...omit(rest, ["size"])}
|
||||
{...inputProps}
|
||||
{...(props.value !== undefined && { value: props.value })}
|
||||
onChange={(e) => handleChange(e.target.value)}
|
||||
type="search"
|
||||
role="searchbox"
|
||||
className={cl(
|
||||
className,
|
||||
"navds-search__input",
|
||||
"navds-text-field__input",
|
||||
"navds-body-short",
|
||||
`navds-body-${size ?? "medium"}`
|
||||
{label}
|
||||
</Label>
|
||||
{!!description && (
|
||||
<BodyShort
|
||||
as="div"
|
||||
className={cl("navds-text-field__description", {
|
||||
"navds-sr-only": hideLabel,
|
||||
})}
|
||||
id={inputDescriptionId}
|
||||
size={size}
|
||||
>
|
||||
{description}
|
||||
</BodyShort>
|
||||
)}
|
||||
<div className="navds-search__wrapper">
|
||||
<div className="navds-search__wrapper-inner">
|
||||
{variant === "simple" && (
|
||||
<SearchIcon aria-hidden className="navds-search__search-icon" />
|
||||
)}
|
||||
/>
|
||||
{controlledValue && clearButton && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => handleClear({ trigger: "Click", event: e })}
|
||||
className="navds-search__button-clear"
|
||||
>
|
||||
<span className="navds-sr-only">
|
||||
{clearButtonLabel ? clearButtonLabel : "Tøm"}
|
||||
</span>
|
||||
<Close aria-hidden />
|
||||
</button>
|
||||
)}
|
||||
<input
|
||||
ref={mergedRef}
|
||||
{...omit(rest, ["size"])}
|
||||
{...inputProps}
|
||||
value={value ?? internalValue}
|
||||
onChange={(e) => handleChange(e.target.value)}
|
||||
type="search"
|
||||
role="searchbox"
|
||||
className={cl(
|
||||
className,
|
||||
"navds-search__input",
|
||||
`navds-search__input--${variant}`,
|
||||
"navds-text-field__input",
|
||||
"navds-body-short",
|
||||
`navds-body-${size}`
|
||||
)}
|
||||
/>
|
||||
{(value ?? internalValue) && clearButton && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => handleClear({ trigger: "Click", event: e })}
|
||||
className="navds-search__button-clear"
|
||||
>
|
||||
<span className="navds-sr-only">
|
||||
{clearButtonLabel ? clearButtonLabel : "Tøm"}
|
||||
</span>
|
||||
<Close aria-hidden />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<SearchContext.Provider
|
||||
value={{
|
||||
size,
|
||||
disabled: inputProps.disabled,
|
||||
variant,
|
||||
}}
|
||||
>
|
||||
{children ? children : variant !== "simple" && <SearchButton />}
|
||||
</SearchContext.Provider>
|
||||
</div>
|
||||
<SearchContext.Provider
|
||||
value={{
|
||||
size,
|
||||
disabled: inputProps.disabled,
|
||||
variant,
|
||||
onSearch: () => onSearch?.(controlledValue),
|
||||
}}
|
||||
>
|
||||
{children ? children : <SearchButton />}
|
||||
</SearchContext.Provider>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}) as SearchComponent;
|
||||
);
|
||||
}
|
||||
) as SearchComponent;
|
||||
|
||||
Search.Button = SearchButton;
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ export type SearchButtonType = React.ForwardRefExoticComponent<
|
||||
>;
|
||||
|
||||
const SearchButton: SearchButtonType = forwardRef(
|
||||
({ className, children, disabled, onClick, ...rest }, ref) => {
|
||||
({ className, children, disabled, ...rest }, ref) => {
|
||||
const context = useContext(SearchContext);
|
||||
|
||||
if (context === null) {
|
||||
@@ -25,7 +25,7 @@ const SearchButton: SearchButtonType = forwardRef(
|
||||
return null;
|
||||
}
|
||||
|
||||
const { size, variant, onSearch } = context;
|
||||
const { size, variant } = context;
|
||||
|
||||
return (
|
||||
<Button
|
||||
@@ -33,13 +33,9 @@ const SearchButton: SearchButtonType = forwardRef(
|
||||
{...rest}
|
||||
ref={ref}
|
||||
size={size}
|
||||
variant={variant}
|
||||
variant={variant === "secondary" ? "secondary" : "primary"}
|
||||
className={cl("navds-search__button-search", className)}
|
||||
disabled={context?.disabled ?? disabled}
|
||||
onClick={(e) => {
|
||||
onSearch?.();
|
||||
onClick?.(e);
|
||||
}}
|
||||
>
|
||||
<Search aria-hidden />
|
||||
{children ? children : <span className="navds-sr-only">Søk</span>}
|
||||
|
||||
@@ -3,92 +3,139 @@ import React, { useState } from "react";
|
||||
|
||||
import { Search } from "../index";
|
||||
export default {
|
||||
title: "ds-react/form/search",
|
||||
title: "ds-react/Form/Search",
|
||||
component: Search,
|
||||
argTypes: {
|
||||
clearButton: {
|
||||
control: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
size: {
|
||||
control: {
|
||||
type: "radio",
|
||||
options: ["medium", "small"],
|
||||
},
|
||||
},
|
||||
variant: {
|
||||
control: {
|
||||
type: "radio",
|
||||
options: ["primary", "secondary", "simple"],
|
||||
},
|
||||
},
|
||||
},
|
||||
} as Meta;
|
||||
|
||||
export const All = () => {
|
||||
const [value, setValue] = useState("");
|
||||
export const Default = (props) => {
|
||||
const [state, setState] = useState("");
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
maxWidth: 400,
|
||||
}}
|
||||
>
|
||||
<h1>Search</h1>
|
||||
|
||||
<Search label="Søk alle sider om X og Y" onSearch={console.log}></Search>
|
||||
<h2>Primary search</h2>
|
||||
<div data-theme={props.darkmode ? "dark" : "light"}>
|
||||
<Search
|
||||
label="Søk alle sider om X og Y"
|
||||
onSearch={console.log}
|
||||
variant="primary"
|
||||
></Search>
|
||||
|
||||
<h2>Search small</h2>
|
||||
<Search
|
||||
label="Søk alle sider om X og Y"
|
||||
description="Beskrivelse av søket"
|
||||
size="small"
|
||||
>
|
||||
<Search.Button />
|
||||
</Search>
|
||||
<br />
|
||||
<Search
|
||||
label="Søk alle sider om X og Y"
|
||||
description="Beskrivelse av søket"
|
||||
size="small"
|
||||
hideLabel
|
||||
variant="primary"
|
||||
>
|
||||
<Search.Button />
|
||||
</Search>
|
||||
|
||||
<h2>Med knappe-tekst</h2>
|
||||
<Search label="Søk alle sider om X og Y" hideLabel={false}>
|
||||
<Search.Button>Søk</Search.Button>
|
||||
</Search>
|
||||
<Search
|
||||
label="Søk alle sider om X og Y"
|
||||
hideLabel={false}
|
||||
variant="primary"
|
||||
>
|
||||
<Search.Button>Søk</Search.Button>
|
||||
</Search>
|
||||
<h2>Hidelabel false</h2>
|
||||
<Search label="Søk alle sider om X og Y" hideLabel={false}>
|
||||
<Search.Button />
|
||||
</Search>
|
||||
<h2>Controlled state </h2>
|
||||
<Search
|
||||
value={value}
|
||||
label="Søk alle sider om X og Y"
|
||||
description="Beskrivelse av søket"
|
||||
onChange={(e) => setValue(e)}
|
||||
onClear={() => setValue("")}
|
||||
>
|
||||
<Search.Button />
|
||||
</Search>
|
||||
<h2>No clear button</h2>
|
||||
<Search
|
||||
hideLabel
|
||||
label="Søk alle sider om X og Y"
|
||||
description="Beskrivelse av søket"
|
||||
clearButton={false}
|
||||
>
|
||||
<Search.Button />
|
||||
</Search>
|
||||
value={props.controlled ? state : undefined}
|
||||
onChange={props.controlled ? setState : null}
|
||||
label="Søk"
|
||||
size={props.size}
|
||||
clearButton={props.clearButton}
|
||||
variant={props.variant}
|
||||
hideLabel={props.hideLabel}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const UUDemo = () => {
|
||||
return (
|
||||
<Search label="Søk på nav.no" onSearch={console.log} placeholder="Søk">
|
||||
<Search.Button />
|
||||
</Search>
|
||||
);
|
||||
Default.args = {
|
||||
controlled: false,
|
||||
darkmode: false,
|
||||
hideLabel: true,
|
||||
};
|
||||
|
||||
export const Small = () => (
|
||||
<div className="rowgap">
|
||||
<div className="colgap">
|
||||
<Search label="Søk" size="small" />
|
||||
<Search label="Søk" variant="secondary" size="small" />
|
||||
<Search label="Søk" variant="simple" size="small" />
|
||||
</div>
|
||||
<div className="colgap" data-theme="dark">
|
||||
<Search label="Søk" size="small" />
|
||||
<Search label="Søk" variant="secondary" size="small" />
|
||||
<Search label="Søk" variant="simple" size="small" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const Variants = () => (
|
||||
<div className="rowgap">
|
||||
<div className="colgap">
|
||||
<Search label="Søk" />
|
||||
<Search label="Søk" variant="secondary" />
|
||||
<Search label="Søk" variant="simple" />
|
||||
</div>
|
||||
<div className="colgap" data-theme="dark">
|
||||
<Search label="Søk" />
|
||||
<Search label="Søk" variant="secondary" />
|
||||
<Search label="Søk" variant="simple" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const Placeholder = () => (
|
||||
<div className="rowgap">
|
||||
<div className="colgap">
|
||||
<Search label="Søk" placeholder="Søk" />
|
||||
</div>
|
||||
<div className="colgap" data-theme="dark">
|
||||
<Search label="Søk" placeholder="Søk" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const Text = () => (
|
||||
<div className="rowgap">
|
||||
<div className="colgap">
|
||||
<Search label="Søk" value="Søketekst" />
|
||||
<Search label="Søk" variant="secondary" value="Søketekst" />
|
||||
<Search label="Søk" variant="simple" value="Søketekst" />
|
||||
</div>
|
||||
<div className="colgap" data-theme="dark">
|
||||
<Search label="Søk" value="Søketekst" />
|
||||
<Search label="Søk" variant="secondary" value="Søketekst" />
|
||||
<Search label="Søk" variant="simple" value="Søketekst" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const WLabel = () => (
|
||||
<div className="rowgap">
|
||||
<div className="colgap">
|
||||
<Search label="Label søk" variant="simple" hideLabel={false} />
|
||||
<Search
|
||||
label="Label søk"
|
||||
description="Description søk"
|
||||
variant="simple"
|
||||
hideLabel={false}
|
||||
/>
|
||||
</div>
|
||||
<div className="colgap" data-theme="dark">
|
||||
<Search label="Label søk" variant="simple" hideLabel={false} />
|
||||
<Search
|
||||
label="Label søk"
|
||||
description="Description søk"
|
||||
variant="simple"
|
||||
hideLabel={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const NoClearButton = () => (
|
||||
<div className="colgap">
|
||||
<Search label="Label søk" clearButton={false} value="søketekst" />
|
||||
<Search
|
||||
label="Label søk"
|
||||
variant="simple"
|
||||
clearButton={false}
|
||||
value="søketekst"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -57,6 +57,13 @@ export const All = () => {
|
||||
onChange={() => setChecked(!checked)}
|
||||
label="Checkbox label text"
|
||||
></ConfirmationPanel>
|
||||
<h2>Uncontrolled</h2>
|
||||
<ConfirmationPanel label="Checkbox label text"></ConfirmationPanel>
|
||||
<h3>defaultChecked</h3>
|
||||
<ConfirmationPanel
|
||||
defaultChecked
|
||||
label="Checkbox label text"
|
||||
></ConfirmationPanel>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -19,6 +19,14 @@ export const All = () => {
|
||||
|
||||
<Textarea label="In anim elit" value={value} onChange={handleChange} />
|
||||
|
||||
<h2>Uncontrolled</h2>
|
||||
|
||||
<Textarea label="In anim elit" />
|
||||
|
||||
<h3>defaultValue</h3>
|
||||
|
||||
<Textarea label="In anim elit" defaultValue="wat" />
|
||||
|
||||
<h2>Description</h2>
|
||||
|
||||
<Textarea
|
||||
|
||||
@@ -25,7 +25,7 @@ export interface CellProps extends HTMLAttributes<HTMLDivElement> {
|
||||
lg?: Column;
|
||||
}
|
||||
|
||||
const Cell = forwardRef<HTMLDivElement, CellProps>(
|
||||
export const Cell = forwardRef<HTMLDivElement, CellProps>(
|
||||
({ children, xs, sm, md, lg, className, ...rest }, ref) => {
|
||||
return (
|
||||
<div
|
||||
|
||||
@@ -8,14 +8,15 @@ export interface ContentContainerProps extends HTMLAttributes<HTMLDivElement> {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const ContentContainer = forwardRef<HTMLDivElement, ContentContainerProps>(
|
||||
({ className, ...rest }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cl("navds-content-container", className)}
|
||||
{...rest}
|
||||
/>
|
||||
)
|
||||
);
|
||||
export const ContentContainer = forwardRef<
|
||||
HTMLDivElement,
|
||||
ContentContainerProps
|
||||
>(({ className, ...rest }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cl("navds-content-container", className)}
|
||||
{...rest}
|
||||
/>
|
||||
));
|
||||
|
||||
export default ContentContainer;
|
||||
@@ -7,7 +7,8 @@ export interface GridProps extends HTMLAttributes<HTMLDivElement> {
|
||||
*/
|
||||
children: React.ReactNode;
|
||||
}
|
||||
const Grid = forwardRef<HTMLDivElement, GridProps>(
|
||||
|
||||
export const Grid = forwardRef<HTMLDivElement, GridProps>(
|
||||
({ children, className, ...rest }, ref) => (
|
||||
<div ref={ref} className={cl("navds-grid", className)} {...rest}>
|
||||
{children}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export { default as Cell } from "./Cell";
|
||||
export * from "./Cell";
|
||||
export { default as Grid } from "./Grid";
|
||||
export * from "./Grid";
|
||||
export { default as ContentContainer } from "./ContentContainer";
|
||||
export * from "./ContentContainer";
|
||||
export { default as Cell, CellProps } from "./Cell";
|
||||
export { default as Grid, GridProps } from "./Grid";
|
||||
export {
|
||||
default as ContentContainer,
|
||||
ContentContainerProps,
|
||||
} from "./ContentContainer";
|
||||
@@ -18,7 +18,7 @@ export interface GuidePanelProps extends HTMLAttributes<HTMLDivElement> {
|
||||
poster?: boolean;
|
||||
}
|
||||
|
||||
const GuidePanel = forwardRef<HTMLDivElement, GuidePanelProps>(
|
||||
export const GuidePanel = forwardRef<HTMLDivElement, GuidePanelProps>(
|
||||
(
|
||||
{ children, className, illustration, poster = false, color, ...rest },
|
||||
ref
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
export { default as GuidePanel } from "./GuidePanel";
|
||||
export * from "./GuidePanel";
|
||||
export { default as GuidePanel, GuidePanelProps } from "./GuidePanel";
|
||||
export { GuideProps } from "./Guide";
|
||||
@@ -13,7 +13,7 @@ export interface HelpTextProps
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const HelpText = forwardRef<HTMLButtonElement, HelpTextProps>(
|
||||
export const HelpText = forwardRef<HTMLButtonElement, HelpTextProps>(
|
||||
(
|
||||
{
|
||||
className,
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export { default as HelpText } from "./HelpText";
|
||||
export * from "./HelpText";
|
||||
export { HelpTextProps } from "./HelpText";
|
||||
@@ -16,9 +16,12 @@ export * from "./popover";
|
||||
export * from "./read-more";
|
||||
export * from "./speech-bubble";
|
||||
export * from "./step-indicator";
|
||||
export * from "./stepper";
|
||||
export * from "./tag";
|
||||
export * from "./toggle-group";
|
||||
export * from "./table";
|
||||
export * from "./tabs";
|
||||
export * from "./tooltip";
|
||||
export * from "./typography";
|
||||
export * from "./util";
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ interface LinkPanelComponentType
|
||||
Description: LinkPanelDescriptionType;
|
||||
}
|
||||
|
||||
const LinkPanelComponent: OverridableComponent<
|
||||
export const LinkPanelComponent: OverridableComponent<
|
||||
LinkPanelProps,
|
||||
HTMLAnchorElement
|
||||
> = forwardRef(
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export { default as LinkPanel } from "./LinkPanel";
|
||||
export * from "./LinkPanel";
|
||||
export { LinkPanelProps } from "./LinkPanel";
|
||||
@@ -10,7 +10,7 @@ export interface LinkProps
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const Link: OverridableComponent<
|
||||
export const Link: OverridableComponent<
|
||||
LinkProps,
|
||||
HTMLAnchorElement
|
||||
> = forwardRef(({ as: Component = "a", className, ...rest }, ref) => (
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export { default as Link } from "./Link";
|
||||
export * from "./Link";
|
||||
export { LinkProps } from "./Link";
|
||||
@@ -25,7 +25,7 @@ export interface LoaderProps extends SVGProps<SVGSVGElement> {
|
||||
variant?: "neutral" | "interaction" | "inverted";
|
||||
}
|
||||
|
||||
const Loader = forwardRef<SVGSVGElement, LoaderProps>(
|
||||
export const Loader = forwardRef<SVGSVGElement, LoaderProps>(
|
||||
(
|
||||
{
|
||||
children,
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export { default as Loader } from "./Loader";
|
||||
export * from "./Loader";
|
||||
export { LoaderProps } from "./Loader";
|
||||
@@ -17,7 +17,7 @@ interface MenuComponent
|
||||
Item: MenuItemType;
|
||||
}
|
||||
|
||||
const Menu = forwardRef<HTMLElement, MenuProps>(
|
||||
export const Menu = forwardRef<HTMLElement, MenuProps>(
|
||||
({ children, className, ...rest }, ref) => (
|
||||
<nav
|
||||
{...rest}
|
||||
|
||||
@@ -35,7 +35,7 @@ export type MenuCollapseType = React.ForwardRefExoticComponent<
|
||||
MenuCollapseProps & React.RefAttributes<HTMLDivElement>
|
||||
>;
|
||||
|
||||
const Collapse: MenuCollapseType = forwardRef(
|
||||
export const Collapse: MenuCollapseType = forwardRef(
|
||||
({ children, defaultOpen = false, title, className, ...rest }, ref) => {
|
||||
const [isOpen, setIsOpen] = useState(defaultOpen);
|
||||
const context = useContext(NestingContext);
|
||||
|
||||
@@ -17,7 +17,7 @@ export type MenuItemType = OverridableComponent<
|
||||
HTMLAnchorElement
|
||||
>;
|
||||
|
||||
const Item: MenuItemType = forwardRef(
|
||||
export const Item: MenuItemType = forwardRef(
|
||||
(
|
||||
{ children, as: Component = "a", active = false, className, ...rest },
|
||||
ref
|
||||
|
||||
@@ -59,7 +59,7 @@ type ModalLifecycle = {
|
||||
setAppElement?: (element: any) => void;
|
||||
};
|
||||
|
||||
const Modal = forwardRef<ReactModal, ModalProps>(
|
||||
export const Modal = forwardRef<ReactModal, ModalProps>(
|
||||
(
|
||||
{
|
||||
children,
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
export { default as Modal } from "./Modal";
|
||||
export { default as Modal, ModalProps } from "./Modal";
|
||||
export { ModalContentProps } from "./ModalContent";
|
||||
export * from "./Modal";
|
||||
@@ -1,2 +1,2 @@
|
||||
export { default as PageHeader } from "./PageHeader";
|
||||
export * from "./PageHeader";
|
||||
export { PageHeaderProps } from "./PageHeader";
|
||||
@@ -2,7 +2,7 @@ import { Meta, Canvas } from "@storybook/addon-docs";
|
||||
import { PageHeader } from "../index";
|
||||
import { illustrationPictogram } from "./pictogram";
|
||||
|
||||
<Meta title="ds-react/page-header/intro" />
|
||||
<Meta title="ds-react(deprecated)/page-header/intro" />
|
||||
|
||||
# Hvordan ta i bruk PageHeader
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { PageHeader } from "../index";
|
||||
import { Meta } from "@storybook/react/types-6-0";
|
||||
import { illustrationPictogram } from "./pictogram";
|
||||
export default {
|
||||
title: "ds-react/page-header",
|
||||
title: "ds-react(deprecated)/page-header",
|
||||
component: PageHeader,
|
||||
} as Meta;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import cl from "classnames";
|
||||
import { Back, Next } from "@navikt/ds-icons";
|
||||
import { BodyShort } from "..";
|
||||
|
||||
interface PaginationProps extends React.HTMLAttributes<HTMLElement> {
|
||||
export interface PaginationProps extends React.HTMLAttributes<HTMLElement> {
|
||||
/**
|
||||
* Current page
|
||||
*/
|
||||
@@ -71,7 +71,7 @@ export const getSteps = ({
|
||||
];
|
||||
};
|
||||
|
||||
const Pagination = forwardRef<HTMLElement, PaginationProps>(
|
||||
export const Pagination = forwardRef<HTMLElement, PaginationProps>(
|
||||
(
|
||||
{
|
||||
page,
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export { default as Pagination } from "./Pagination";
|
||||
export * from "./Pagination";
|
||||
export { PaginationProps } from "./Pagination";
|
||||
@@ -16,7 +16,7 @@ export interface PanelProps extends React.HTMLAttributes<HTMLElement> {
|
||||
|
||||
export type PanelType = OverridableComponent<PanelProps, HTMLElement>;
|
||||
|
||||
const Panel: PanelType = forwardRef(
|
||||
export const Panel: PanelType = forwardRef(
|
||||
(
|
||||
{ children, className, border = false, as: Component = "div", ...rest },
|
||||
ref
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export { default as Panel } from "./Panel";
|
||||
export * from "./Panel";
|
||||
export { PanelProps } from "./Panel";
|
||||
@@ -67,7 +67,7 @@ interface PopoverComponent
|
||||
Content: PopoverContentType;
|
||||
}
|
||||
|
||||
const Popover = forwardRef<HTMLDivElement, PopoverProps>(
|
||||
export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
|
||||
(
|
||||
{
|
||||
className,
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
export { default as Popover } from "./Popover";
|
||||
export * from "./Popover";
|
||||
export { default as Popover, PopoverProps } from "./Popover";
|
||||
export { PopoverContentProps } from "./PopoverContent";
|
||||
@@ -31,7 +31,7 @@ export interface ReadMoreProps
|
||||
renderContentWhenClosed?: boolean;
|
||||
}
|
||||
|
||||
const ReadMore = forwardRef<HTMLButtonElement, ReadMoreProps>(
|
||||
export const ReadMore = forwardRef<HTMLButtonElement, ReadMoreProps>(
|
||||
(
|
||||
{
|
||||
className,
|
||||
@@ -55,6 +55,7 @@ const ReadMore = forwardRef<HTMLButtonElement, ReadMoreProps>(
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
{...rest}
|
||||
className={cl(
|
||||
"navds-read-more",
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
export { default as ReadMore } from "./ReadMore";
|
||||
export * from "./ReadMore";
|
||||
export { default as ReadMore, ReadMoreProps } from "./ReadMore";
|
||||
@@ -17,7 +17,7 @@ export const All = () => {
|
||||
<ReadMore
|
||||
open={open}
|
||||
onClick={() => setOpen(!open)}
|
||||
header="ReadMore header text"
|
||||
header="ReadMore header text ReadMore header text ReadMore header text ReadMore header text ReadMore header text"
|
||||
>
|
||||
Magna aliquip aliquip fugiat nostrud nostrud velit pariatur veniam
|
||||
officia laboris voluptate officia pariatur.Lorem est ex anim velit
|
||||
|
||||
@@ -37,7 +37,7 @@ interface SpeechBubbleComponent
|
||||
Bubble: BubbleType;
|
||||
}
|
||||
|
||||
const SpeechBubble = forwardRef<HTMLDivElement, SpeechBubbleProps>(
|
||||
export const SpeechBubble = forwardRef<HTMLDivElement, SpeechBubbleProps>(
|
||||
(
|
||||
{
|
||||
children,
|
||||
|
||||
Loaded 100 of 197 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user