Compare commits

...
Author SHA1 Message Date
github-actions[bot]andgithub-actions[bot] 6385c4686e Version Packages (#2039)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-06-08 16:07:32 +02:00
Ken 30068dca3f 📝 La til jsdoc for skeleton-komponent 2023-06-08 16:03:27 +02:00
github-actions[bot]andgithub-actions[bot] 3aa04d2375 Version Packages (#2038)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-06-08 15:25:09 +02:00
Ken 91343563c9 🐛 Fikset markering av tekst internt i Skeleton-komponent 2023-06-08 15:21:52 +02:00
Ken d5c8112339 📝 Fikset typo i skeleton-docs 2023-06-08 15:02:24 +02:00
github-actions[bot]andgithub-actions[bot] e6cc9d1b4f Version Packages (#2031)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-06-08 14:49:16 +02:00
Ken db8c38a094 [Ny komponent] Skeleton (#1821) 2023-06-08 14:44:08 +02:00
Ken 35041e64eb Update README.md 2023-06-08 08:17:20 +02:00
Ken 690422d824 🐛 Fikset darkmode for skjemakomponenter 2023-06-07 20:10:28 +02:00
Ken b54bebd308 ⚡ Forbedret søk 2023-06-07 16:11:40 +02:00
Ken 8db194170c 🐛 Fikset chips.css bug etter merge 2023-06-07 15:45:00 +02:00
Ken 7b42f536aa 🎨 Oppdatert Chips-komponent (#2035) 2023-06-07 15:39:11 +02:00
Ken b2f796d681 💄 Text-subtle, icon-subtle til 700 nivå, form-description farger(#2036) 2023-06-07 15:22:02 +02:00
17d92c9ed5 add jsdoc (it's mostly copilot + some tweaks) (#2034)
* 📝 add jsdoc (it's mostly copilot + some tweaks)

* 😂 emojis

* 🏷️ add jsdoc for overridableComponents

* 🏷️ Oppdatert docgen for nestede komponenter

* 🎨 Oppdatert chat

* 🏷️ Dokumentert date-hooks

* 🏷️ Expansioncard-props

* 🏷️ Stepper.step jsdoc

* 🏷️ Tabs jsdoc

* 🏷️ Linkpaneltypes

* 🏷️ List jsdoc

* 🏷️ list jsdoc

* 🏷️ InternalHeader-docs

* 🏷️ jsdoc for dropdown

* 🏷️ Timeline jsdoc

---------

Co-authored-by: Ken <26967723+KenAJoh@users.noreply.github.com>
Co-authored-by: Ken <ken.aleksander@gmail.com>
2023-06-07 14:19:34 +02:00
Ken 7bae5dce88 🎨 Fikset søketreff for CSS + overflow av ikonsøk-form 2023-06-06 15:43:38 +02:00
Ken 6aca0a4b6a 🎨 Data-tokens (#2032) 2023-06-06 13:49:31 +02:00
Ken 4f7fde22a3 🐛 Regex-fix for sanity-url er 2023-06-06 13:45:34 +02:00
Ken 0dad69a8df 💄 Fadein frontpage-cards 2023-06-05 22:34:37 +02:00
Julian Nymark c028f36e2b Indent prop added to accordion (#2027) 2023-06-05 19:38:44 +02:00
Ken 988fb36619 📝 Nettside-readme 2023-06-05 17:25:09 +02:00
Ken f61cd88627 📝 Oppdatert readme 2023-06-05 17:10:26 +02:00
137 changed files with 2540 additions and 776 deletions

No files matched your search

+6
View File
@@ -1,5 +1,11 @@
# @navikt/aksel-icons
## 4.1.2
## 4.1.1
## 4.1.0
## 4.0.0
## 3.4.2
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/aksel-icons",
"version": "4.0.0",
"version": "4.1.2",
"author": "Aksel | NAV",
"homepage": "https://aksel.nav.no/ikoner",
"repository": {
+13
View File
@@ -1,5 +1,18 @@
# @navikt/aksel-stylelint
## 4.1.2
## 4.1.1
## 4.1.0
### Minor Changes
- [#2035](https://github.com/navikt/aksel/pull/2035) [`7b42f536a`](https://github.com/navikt/aksel/commit/7b42f536aa90c1b5dbe2b19f1bbe292701546420) Thanks [@KenAJoh](https://github.com/KenAJoh)! - :tada: Oppdatert Chips
- Toggle Chips har nå varianter: neutral og action
- Toggle Chips har nå en ny prop: `checkmark` som slår av/på checkmark ved selected-state
## 4.0.0
## 3.4.2
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/aksel-stylelint",
"version": "4.0.0",
"version": "4.1.2",
"author": "Aksel | NAV",
"homepage": "https://aksel.nav.no/grunnleggende/kode/stylelint",
"repository": {
@@ -35,8 +35,8 @@
"dev": "yarn watch:lint"
},
"devDependencies": {
"@navikt/ds-css": "^4.0.0",
"@navikt/ds-tokens": "^4.0.0",
"@navikt/ds-css": "^4.1.2",
"@navikt/ds-tokens": "^4.1.2",
"@types/jest": "^29.0.0",
"concurrently": "7.2.1",
"copyfiles": "2.4.1",
@@ -20,4 +20,9 @@ export const deprecations: DeprecatedList = [
"Class were moved to '@navikt/ds-css' and renamed with 'navds'-prefix in v4.0.0. Docs: https://aksel.nav.no/grunnleggende/kode/endringslogg#h728704adeb59.",
deprecatePrefix: true,
},
{
classes: ["navds-chips--icon-left"],
message:
"In v4.1.0 Chips. Toggle no longer handles special alignment for checkmark-icon, thus removing this class",
},
];
+21
View File
@@ -1,5 +1,26 @@
# @navikt/aksel
## 4.1.2
### Patch Changes
- Updated dependencies []:
- @navikt/ds-css@4.1.2
## 4.1.1
### Patch Changes
- Updated dependencies [[`91343563c`](https://github.com/navikt/aksel/commit/91343563c916a554d8ade5401c28ab4c3b3e26af)]:
- @navikt/ds-css@4.1.1
## 4.1.0
### Patch Changes
- Updated dependencies [[`7b42f536a`](https://github.com/navikt/aksel/commit/7b42f536aa90c1b5dbe2b19f1bbe292701546420), [`c028f36e2`](https://github.com/navikt/aksel/commit/c028f36e2bc58223ebf8b655980dde7eafb30add), [`b2f796d68`](https://github.com/navikt/aksel/commit/b2f796d681f1c1d76d26d1fd743268c8c618a854), [`db8c38a09`](https://github.com/navikt/aksel/commit/db8c38a094cd183db54aebecb62d5b223920a040)]:
- @navikt/ds-css@4.1.0
## 4.0.0
### Major Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/aksel",
"version": "4.0.0",
"version": "4.1.2",
"description": "Aksel command line interface. Handles css-imports, codemods and more",
"author": "Aksel | NAV designsystem team",
"license": "MIT",
@@ -29,7 +29,7 @@
},
"homepage": "https://aksel.nav.no/grunnleggende/kode/kommandolinje",
"dependencies": {
"@navikt/ds-css": "4.0.0",
"@navikt/ds-css": "4.1.2",
"axios": "1.3.6",
"chalk": "4.1.0",
"clipboardy": "^2.3.0",
+30
View File
@@ -1,5 +1,35 @@
# @navikt/ds-css
## 4.1.2
## 4.1.1
### Patch Changes
- [`91343563c`](https://github.com/navikt/aksel/commit/91343563c916a554d8ade5401c28ab4c3b3e26af) Thanks [@KenAJoh](https://github.com/KenAJoh)! - :bug: Fikset markering av tekst i skeleton.
## 4.1.0
### Minor Changes
- [#2035](https://github.com/navikt/aksel/pull/2035) [`7b42f536a`](https://github.com/navikt/aksel/commit/7b42f536aa90c1b5dbe2b19f1bbe292701546420) Thanks [@KenAJoh](https://github.com/KenAJoh)! - :tada: Oppdatert Chips
- Toggle Chips har nå varianter: neutral og action
- Toggle Chips har nå en ny prop: `checkmark` som slår av/på checkmark ved selected-state
- [#2036](https://github.com/navikt/aksel/pull/2036) [`b2f796d68`](https://github.com/navikt/aksel/commit/b2f796d681f1c1d76d26d1fd743268c8c618a854) Thanks [@KenAJoh](https://github.com/KenAJoh)! - - Oppdatert text-subtle og icon-subtle tokens til 700-skala (tidligere 600).
- Icon-subtle bruker nå grayalpha.
- Alle description-felter på fieldsets har nå text-subtle som farge.
- [#1821](https://github.com/navikt/aksel/pull/1821) [`db8c38a09`](https://github.com/navikt/aksel/commit/db8c38a094cd183db54aebecb62d5b223920a040) Thanks [@KenAJoh](https://github.com/KenAJoh)! - :tada: Ny komponent Skeleton!
- varianter: text, circle, rounded og rectangle
### Patch Changes
- [#2027](https://github.com/navikt/aksel/pull/2027) [`c028f36e2`](https://github.com/navikt/aksel/commit/c028f36e2bc58223ebf8b655980dde7eafb30add) Thanks [@JulianNymark](https://github.com/JulianNymark)! - :sparkles: La til `indent`-prop på Accordion
## 4.0.0
### Major Changes
+6 -1
View File
@@ -141,11 +141,16 @@
/*************************
* Content *
*************************/
.navds-accordion__content {
padding: 0 var(--a-spacing-3) var(--a-spacing-5) var(--a-spacing-11);
padding: 0 var(--a-spacing-3) var(--a-spacing-5);
animation: fadeAccordionContent 250ms ease;
}
.navds-accordion--indent > :where(.navds-accordion__item) > :where(.navds-accordion__content) {
padding: 0 var(--a-spacing-3) var(--a-spacing-5) var(--a-spacing-11);
}
.navds-accordion__content--closed {
display: none;
}
+27 -22
View File
@@ -20,7 +20,7 @@
cursor: pointer;
align-items: center;
justify-content: center;
gap: var(--a-spacing-05);
gap: var(--a-spacing-1);
margin: 0;
padding: 0 var(--a-spacing-3);
text-decoration: none;
@@ -34,14 +34,14 @@
}
.navds-chips__toggle {
box-shadow: inset 0 0 0 1px var(--ac-chip-toggle-border, var(--a-border-default));
background-color: var(--ac-chip-toggle-bg, var(--a-surface-neutral-subtle));
box-shadow: inset 0 0 0 1px var(--ac-chip-toggle-border, var(--a-border-subtle));
background-color: var(--ac-chip-toggle-bg, var(--a-surface-action-subtle));
color: var(--ac-chip-toggle-text, var(--a-text-default));
}
.navds-chips__toggle:hover {
box-shadow: inset 0 0 0 1px var(--ac-chip-toggle-hover-border, var(--a-border-strong));
background-color: var(--ac-chip-toggle-hover-bg, var(--a-surface-neutral-subtle-hover));
box-shadow: inset 0 0 0 1px var(--ac-chip-toggle-hover-border, var(--a-border-subtle-hover));
background-color: var(--ac-chip-toggle-hover-bg, var(--a-surface-action-subtle-hover));
}
.navds-chips__toggle[aria-pressed="true"] {
@@ -54,6 +54,28 @@
background-color: var(--ac-chip-toggle-pressed-hover-bg, var(--a-surface-action-selected-hover));
}
/* Toggle variant neutral */
.navds-chips__toggle--neutral {
box-shadow: inset 0 0 0 1px var(--ac-chip-toggle-neutral-border, var(--a-border-subtle));
background-color: var(--ac-chip-toggle-neutral-bg, var(--a-surface-neutral-subtle));
color: var(--ac-chip-toggle-neutral-text, var(--a-text-default));
}
.navds-chips__toggle--neutral:hover {
box-shadow: inset 0 0 0 1px var(--ac-chip-toggle-neutral-hover-border, var(--a-border-subtle-hover));
background-color: var(--ac-chip-toggle-neutral-hover-bg, var(--a-surface-neutral-subtle-hover));
}
.navds-chips__toggle--neutral[aria-pressed="true"] {
box-shadow: none;
background-color: var(--ac-chip-toggle-neutral-pressed-bg, var(--a-surface-neutral-selected));
color: var(--ac-chip-toggle-neutral-pressed-text, var(--a-text-on-neutral));
}
.navds-chips__toggle--neutral[aria-pressed="true"]:hover {
background-color: var(--ac-chip-toggle-neutral-pressed-hover-bg, var(--a-surface-neutral-selected));
}
.navds-chips__toggle:focus-visible {
box-shadow: 0 0 0 2px var(--ac-chip-toggle-focus, var(--a-border-focus));
}
@@ -99,19 +121,6 @@
border-radius: var(--a-border-radius-full);
}
.navds-chips__toggle-icon {
width: 1.5rem;
height: 1.5rem;
display: grid;
place-items: center;
border-radius: var(--a-border-radius-full);
}
.navds-chips--small .navds-chips__toggle-icon {
width: 1.25rem;
height: 1.25rem;
}
.navds-chips--small .navds-chips__removable-icon {
width: 1.25rem;
height: 1.25rem;
@@ -161,7 +170,3 @@
.navds-chips--small .navds-chips--icon-right {
padding-right: var(--a-spacing-05);
}
.navds-chips--small .navds-chips--icon-left {
padding-left: 0.375rem;
}
+1
View File
@@ -127,6 +127,7 @@ const StyleMappings = {
{ component: "ReadMore", main: "read-more.css", dependencies: [typoCss] },
{ component: "Search", main: formCss, dependencies: [typoCss] },
{ component: "Select", main: formCss, dependencies: [typoCss] },
{ component: "Skeleton", main: "skeleton.css", dependencies: [] },
{ component: "Stepper", main: "stepper.css", dependencies: [typoCss] },
{ component: "Switch", main: formCss, dependencies: [typoCss] },
{ component: "Table", main: "table.css", dependencies: [typoCss] },
+8
View File
@@ -1,3 +1,7 @@
[data-theme="dark"] {
--ac-form-description: var(--a-text-on-inverted);
}
.navds-fieldset {
margin: 0;
padding: 0;
@@ -9,6 +13,10 @@
margin-top: var(--a-spacing-2);
}
.navds-fieldset__description {
color: var(--ac-form-description, var(--a-text-subtle));
}
.navds-fieldset > .navds-fieldset__description:not(:empty) {
margin-top: 0.125rem;
}
+5
View File
@@ -1,3 +1,7 @@
[data-theme="dark"] {
--ac-form-description: var(--a-text-on-inverted);
}
.navds-form-field {
display: grid;
justify-items: start;
@@ -6,6 +10,7 @@
.navds-form-field__description {
margin-top: -6px;
color: var(--ac-form-description, var(--a-text-subtle));
}
.navds-form-field .navds-error-message,
+1
View File
@@ -28,6 +28,7 @@
@import "panel.css";
@import "link-panel.css";
@import "read-more.css";
@import "skeleton.css";
@import "stepper.css";
@import "table.css";
@import "tabs.css";
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-css",
"version": "4.0.0",
"version": "4.1.2",
"description": "CSS for NAV Designsystem",
"author": "Aksel | NAV designsystem team",
"keywords": [
@@ -27,7 +27,7 @@
"css:get-version": "node config/get-version.js"
},
"devDependencies": {
"@navikt/ds-tokens": "^4.0.0",
"@navikt/ds-tokens": "^4.1.2",
"cssnano": "6.0.0",
"fast-glob": "3.2.11",
"lodash": "4.17.21",
+56
View File
@@ -0,0 +1,56 @@
.navds-skeleton {
display: block;
background-color: var(--ac-skeleton-bg, var(--a-surface-neutral-moderate));
height: 1.3em;
animation: akselSkeletonAnimation 0.8s linear infinite alternate;
pointer-events: none;
}
.navds-skeleton--has-children {
color: transparent;
}
.navds-skeleton--has-children > * {
visibility: hidden;
}
.navds-skeleton--has-children.navds-skeleton--no-height {
height: auto;
}
.navds-skeleton--has-children.navds-skeleton--no-width {
width: fit-content;
}
.navds-skeleton--text {
height: auto;
transform-origin: 0 55%;
transform: scale(1, 0.6);
border-radius: var(--a-border-radius-medium);
}
.navds-skeleton--text:empty::before {
content: "\00a0";
}
.navds-skeleton--circle {
border-radius: var(--a-border-radius-full);
}
.navds-skeleton--rectangle {
border-radius: 0;
}
.navds-skeleton--rounded {
border-radius: var(--a-border-radius-xlarge);
}
@keyframes akselSkeletonAnimation {
0% {
opacity: 1;
}
100% {
opacity: 0.4;
}
}
+19 -4
View File
@@ -86,14 +86,22 @@
"--ac-chat-top-text": "--a-text-default"
},
"chips": {
"--ac-chip-toggle-border": "--a-border-default",
"--ac-chip-toggle-bg": "--a-surface-neutral-subtle",
"--ac-chip-toggle-border": "--a-border-subtle",
"--ac-chip-toggle-bg": "--a-surface-action-subtle",
"--ac-chip-toggle-text": "--a-text-default",
"--ac-chip-toggle-hover-border": "--a-border-strong",
"--ac-chip-toggle-hover-bg": "--a-surface-neutral-subtle-hover",
"--ac-chip-toggle-hover-border": "--a-border-subtle-hover",
"--ac-chip-toggle-hover-bg": "--a-surface-action-subtle-hover",
"--ac-chip-toggle-pressed-bg": "--a-surface-action-selected",
"--ac-chip-toggle-pressed-text": "--a-text-on-action",
"--ac-chip-toggle-pressed-hover-bg": "--a-surface-action-selected-hover",
"--ac-chip-toggle-neutral-border": "--a-border-subtle",
"--ac-chip-toggle-neutral-bg": "--a-surface-neutral-subtle",
"--ac-chip-toggle-neutral-text": "--a-text-default",
"--ac-chip-toggle-neutral-hover-border": "--a-border-subtle-hover",
"--ac-chip-toggle-neutral-hover-bg": "--a-surface-neutral-subtle-hover",
"--ac-chip-toggle-neutral-pressed-bg": "--a-surface-neutral-selected",
"--ac-chip-toggle-neutral-pressed-text": "--a-text-on-neutral",
"--ac-chip-toggle-neutral-pressed-hover-bg": "--a-surface-neutral-selected",
"--ac-chip-toggle-focus": "--a-border-focus",
"--ac-chip-removable-action-bg": "--a-surface-action-selected",
"--ac-chip-removable-action-text": "--a-text-on-action",
@@ -206,6 +214,9 @@
"--ac-read-more-active-bg": "--a-surface-active",
"--ac-read-more-line": "--a-border-divider"
},
"skeleton": {
"--ac-skeleton-bg": "--a-surface-neutral-moderate"
},
"stepper": {
"--ac-stepper-text": "--a-surface-action",
"--ac-stepper-line": "--a-border-default",
@@ -349,6 +360,10 @@
"--ac-radio-checkbox-error-border": "--a-border-danger",
"--ac-radio-checkbox-error-hover-bg": "--a-surface-danger-subtle"
},
"forms": {
"--ac-form-description": "--a-text-subtle",
"--ac-form-subdescription": "--a-text-subtle"
},
"search": {
"--ac-search-button-border": "--a-border-default",
"--ac-search-button-border-hover": "--a-border-action",
+38
View File
@@ -1,5 +1,43 @@
# @navikt/ds-react
## 4.1.2
### Patch Changes
- [`30068dca3`](https://github.com/navikt/aksel/commit/30068dca3fcdf4bf7bbfbfb3d09baa9fee003962) Thanks [@KenAJoh](https://github.com/KenAJoh)! - Jsdoc for Skeleton-komponent
- Updated dependencies []:
- @navikt/aksel-icons@4.1.2
## 4.1.1
### Patch Changes
- Updated dependencies []:
- @navikt/aksel-icons@4.1.1
## 4.1.0
### Minor Changes
- [#2035](https://github.com/navikt/aksel/pull/2035) [`7b42f536a`](https://github.com/navikt/aksel/commit/7b42f536aa90c1b5dbe2b19f1bbe292701546420) Thanks [@KenAJoh](https://github.com/KenAJoh)! - :tada: Oppdatert Chips
- Toggle Chips har nå varianter: neutral og action
- Toggle Chips har nå en ny prop: `checkmark` som slår av/på checkmark ved selected-state
- [#1821](https://github.com/navikt/aksel/pull/1821) [`db8c38a09`](https://github.com/navikt/aksel/commit/db8c38a094cd183db54aebecb62d5b223920a040) Thanks [@KenAJoh](https://github.com/KenAJoh)! - :tada: Ny komponent Skeleton!
- varianter: text, circle, rounded og rectangle
### Patch Changes
- [#2034](https://github.com/navikt/aksel/pull/2034) [`17d92c9ed`](https://github.com/navikt/aksel/commit/17d92c9ed5f82a80f99a1512989744343edf60b3) Thanks [@JulianNymark](https://github.com/JulianNymark)! - Add JSDoc typings
- [#2027](https://github.com/navikt/aksel/pull/2027) [`c028f36e2`](https://github.com/navikt/aksel/commit/c028f36e2bc58223ebf8b655980dde7eafb30add) Thanks [@JulianNymark](https://github.com/JulianNymark)! - :sparkles: La til `indent`-prop på Accordion
- Updated dependencies []:
- @navikt/aksel-icons@4.1.0
## 4.0.0
### Major Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-react",
"version": "4.0.0",
"version": "4.1.2",
"description": "Aksel react-components for NAV designsystem",
"author": "Aksel | NAV designsystem team",
"license": "MIT",
@@ -38,7 +38,7 @@
},
"dependencies": {
"@floating-ui/react": "0.24.1",
"@navikt/aksel-icons": "^4.0.0",
"@navikt/aksel-icons": "^4.1.2",
"@radix-ui/react-tabs": "1.0.0",
"@radix-ui/react-toggle-group": "1.0.0",
"clsx": "^1.2.1",
+49 -7
View File
@@ -1,17 +1,32 @@
import cl from "clsx";
import React, { forwardRef } from "react";
import AccordionItem, { AccordionItemType } from "./AccordionItem";
import AccordionContent, { AccordionContentType } from "./AccordionContent";
import AccordionHeader, { AccordionHeaderType } from "./AccordionHeader";
import AccordionItem, { AccordionItemProps } from "./AccordionItem";
import AccordionContent, { AccordionContentProps } from "./AccordionContent";
import AccordionHeader, { AccordionHeaderProps } from "./AccordionHeader";
import { AccordionContext } from "./AccordionContext";
interface AccordionComponent
extends React.ForwardRefExoticComponent<
AccordionProps & React.RefAttributes<HTMLDivElement>
> {
Item: AccordionItemType;
Header: AccordionHeaderType;
Content: AccordionContentType;
/**
* @see 🏷️ {@link AccordionItemProps}
*/
Item: React.ForwardRefExoticComponent<
AccordionItemProps & React.RefAttributes<HTMLDivElement>
>;
/**
* @see 🏷️ {@link AccordionHeaderProps}
*/
Header: React.ForwardRefExoticComponent<
AccordionHeaderProps & React.RefAttributes<HTMLButtonElement>
>;
/**
* @see 🏷️ {@link AccordionContentProps}
*/
Content: React.ForwardRefExoticComponent<
AccordionContentProps & React.RefAttributes<HTMLDivElement>
>;
}
export interface AccordionProps extends React.HTMLAttributes<HTMLDivElement> {
@@ -27,12 +42,37 @@ export interface AccordionProps extends React.HTMLAttributes<HTMLDivElement> {
* @default "medium"
*/
size?: "large" | "medium" | "small";
/**
* Whether to indent content or not
* @default true
*/
indent?: boolean;
/**
* Instances of Accordion.Item
*/
children: React.ReactNode;
}
/**
* A component that displays collapsible content sections.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/accordion)
* @see 🏷️ {@link AccordionProps}
*
* @example
* ```jsx
* <Accordion>
* <Accordion.Item>
* <Accordion.Header>Section 1</Accordion.Header>
* <Accordion.Content>Content 1</Accordion.Content>
* </Accordion.Item>
* <Accordion.Item>
* <Accordion.Header>Section 2</Accordion.Header>
* <Accordion.Content>Content 2</Accordion.Content>
* </Accordion.Item>
* </Accordion>
* ```
*/
export const Accordion = forwardRef<HTMLDivElement, AccordionProps>(
(
{
@@ -40,6 +80,7 @@ export const Accordion = forwardRef<HTMLDivElement, AccordionProps>(
variant = "default",
headingSize = "small",
size = "medium",
indent = true,
...rest
},
ref
@@ -57,7 +98,8 @@ export const Accordion = forwardRef<HTMLDivElement, AccordionProps>(
className={cl(
"navds-accordion",
className,
`navds-accordion--${size}`
`navds-accordion--${size}`,
{ "navds-accordion--indent": indent }
)}
ref={ref}
/>
@@ -11,11 +11,7 @@ export interface AccordionContentProps
children: React.ReactNode;
}
export type AccordionContentType = React.ForwardRefExoticComponent<
AccordionContentProps & React.RefAttributes<HTMLDivElement>
>;
const AccordionContent: AccordionContentType = forwardRef(
const AccordionContent = forwardRef<HTMLDivElement, AccordionContentProps>(
({ children, className, ...rest }, ref) => {
const context = useContext(AccordionItemContext);
@@ -13,11 +13,7 @@ export interface AccordionHeaderProps
children: React.ReactNode;
}
export type AccordionHeaderType = React.ForwardRefExoticComponent<
AccordionHeaderProps & React.RefAttributes<HTMLButtonElement>
>;
const AccordionHeader: AccordionHeaderType = forwardRef(
const AccordionHeader = forwardRef<HTMLButtonElement, AccordionHeaderProps>(
({ children, className, onClick, ...rest }, ref) => {
const itemContext = useContext(AccordionItemContext);
const accordionContext = useContext(AccordionContext);
@@ -27,10 +27,6 @@ export interface AccordionItemProps
defaultOpen?: boolean;
}
export type AccordionItemType = React.ForwardRefExoticComponent<
AccordionItemProps & React.RefAttributes<HTMLDivElement>
>;
export interface AccordionItemContextProps {
open: boolean;
toggleOpen: () => void;
@@ -39,7 +35,7 @@ export interface AccordionItemContextProps {
export const AccordionItemContext =
createContext<AccordionItemContextProps | null>(null);
const AccordionItem: AccordionItemType = forwardRef(
const AccordionItem = forwardRef<HTMLDivElement, AccordionItemProps>(
(
{ children, className, open, defaultOpen = false, onClick, id, ...rest },
ref
@@ -114,11 +114,12 @@ export const Default = {
},
args: {
controlled: "false",
controlled: false,
nItems: 2,
variant: "default",
headingSize: "medium",
size: "medium",
indent: true,
},
};
@@ -137,7 +138,7 @@ export const DefaultOpen = {
args: {
openItems: [1, 2],
controlled: "false",
controlled: false,
nItems: 5,
variant: "neutral",
headingSize: "large",
@@ -251,6 +252,7 @@ export const WithTable = {
args: {
variant: "default",
headingSize: "large",
indent: false,
},
};
+9
View File
@@ -53,6 +53,15 @@ export interface AlertContextProps {
size: "medium" | "small";
}
/**
* A component for displaying alerts
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/alert)
* @see 🏷️ {@link AlertProps}
* @example
* ```jsx
* <Alert variant="error">Dette er en feilmelding</Alert>
* ```
*/
export const Alert = forwardRef<HTMLDivElement, AlertProps>(
(
{
+10
View File
@@ -47,6 +47,16 @@ export interface ButtonProps
iconPosition?: "left" | "right";
}
/**
* A button component
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/button)
* @see 🏷️ {@link ButtonProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
* @example
* ```jsx
* <Button>Klikk meg</Button>
* ```
*/
export const Button: OverridableComponent<ButtonProps, HTMLButtonElement> =
forwardRef(
(
+1 -5
View File
@@ -25,11 +25,7 @@ export interface BubbleProps extends HTMLAttributes<HTMLDivElement> {
toptextPosition?: "left" | "right";
}
export type BubbleType = React.ForwardRefExoticComponent<
BubbleProps & React.RefAttributes<HTMLDivElement>
>;
const Bubble: BubbleType = forwardRef(
const Bubble = forwardRef<HTMLDivElement, BubbleProps>(
(
{
children,
+23 -2
View File
@@ -1,6 +1,6 @@
import React, { forwardRef, HTMLAttributes } from "react";
import cl from "clsx";
import Bubble, { BubbleType } from "./Bubble";
import Bubble, { BubbleProps } from "./Bubble";
import { BodyLong, BodyShort } from "../typography";
export interface ChatProps extends HTMLAttributes<HTMLDivElement> {
@@ -44,9 +44,30 @@ interface ChatComponent
extends React.ForwardRefExoticComponent<
ChatProps & React.RefAttributes<HTMLDivElement>
> {
Bubble: BubbleType;
/**
* @see 🏷️ {@link BubbleProps}
*/
Bubble: React.ForwardRefExoticComponent<
BubbleProps & React.RefAttributes<HTMLDivElement>
>;
}
/**
* A component for displaying chat messages.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/chat)
* @see 🏷️ {@link ChatProps}
*
* @example
* ```jsx
* <Chat>
* <Chat.Bubble avatar="A" name="Alice">Hello!</Chat.Bubble>
* </Chat>
* <Chat>
* <Chat.Bubble avatar="B" name="Bob">Hi there!</Chat.Bubble>
* </Chat>
* ```
*/
export const Chat = forwardRef<HTMLDivElement, ChatProps>(
(
{
+42 -4
View File
@@ -1,7 +1,8 @@
import cl from "clsx";
import React, { forwardRef, HTMLAttributes } from "react";
import ToggleChips, { ToggleChipsType } from "./Toggle";
import RemovableChips, { RemovableChipsType } from "./Removable";
import ToggleChips, { ToggleChipsProps } from "./Toggle";
import RemovableChips, { RemovableChipsProps } from "./Removable";
import { OverridableComponent } from "../util/OverridableComponent";
export interface ChipsProps extends HTMLAttributes<HTMLUListElement> {
children: React.ReactNode;
@@ -16,10 +17,47 @@ interface ChipsComponent
extends React.ForwardRefExoticComponent<
ChipsProps & React.RefAttributes<HTMLUListElement>
> {
Toggle: ToggleChipsType;
Removable: RemovableChipsType;
/**
* Toggle between selected-states.
* @see 🏷️ {@link ToggleChipsProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
*/
Toggle: OverridableComponent<ToggleChipsProps, HTMLButtonElement>;
/**
* Remove filter or the likes on click
* @see 🏷️ {@link RemovableChipsProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
*/
Removable: OverridableComponent<RemovableChipsProps, HTMLButtonElement>;
}
/**
* A component that displays a list of items as chips.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/chips)
* @see 🏷️ {@link ChipsProps}
*
* @example
* ```jsx
<Chips size="small">
{options.map((c) => (
<Chips.Toggle
selected={selected.includes(c)}
key={c}
onClick={() =>
setSelected(
selected.includes(c)
? selected.filter((x) => x !== c)
: [...selected, c]
)
}
>
{c}
</Chips.Toggle>
))}
</Chips>
* ```
*/
export const Chips: ChipsComponent = forwardRef<HTMLUListElement, ChipsProps>(
({ className, size = "medium", children, ...rest }, ref) => {
return (
+1 -4
View File
@@ -22,9 +22,6 @@ export interface RemovableChipsProps
onDelete?: () => void;
}
export interface RemovableChipsType
extends OverridableComponent<RemovableChipsProps, HTMLButtonElement> {}
export const RemovableChips: OverridableComponent<
RemovableChipsProps,
HTMLButtonElement
@@ -63,6 +60,6 @@ export const RemovableChips: OverridableComponent<
</Component>
);
}
) as RemovableChipsType;
);
export default RemovableChips;
+47 -11
View File
@@ -1,4 +1,3 @@
import { CheckmarkIcon } from "@navikt/aksel-icons";
import cl from "clsx";
import React, { forwardRef } from "react";
import { OverridableComponent } from "../util/OverridableComponent";
@@ -10,27 +9,64 @@ export interface ToggleChipsProps
* Toggles aria-pressed and visual-changes
*/
selected?: boolean;
/**
* Chip-variants
* @default "action"
*/
variant?: "action" | "neutral";
/**
* Toggles display of checkmark on selected
* @default true
*/
checkmark?: boolean;
}
export interface ToggleChipsType
extends OverridableComponent<ToggleChipsProps, HTMLButtonElement> {}
export const ToggleChips: ToggleChipsType = forwardRef(
export const ToggleChips: OverridableComponent<
ToggleChipsProps,
HTMLButtonElement
> = forwardRef(
(
{ className, children, selected, as: Component = "button", ...rest },
{
className,
children,
selected,
variant = "action",
checkmark = true,
as: Component = "button",
...rest
},
ref
) => {
return (
<Component
{...rest}
ref={ref}
className={cl("navds-chips__chip navds-chips__toggle", className, {
"navds-chips--icon-left": selected,
})}
className={cl(
"navds-chips__chip navds-chips__toggle",
className,
`navds-chips__toggle--${variant}`
)}
aria-pressed={selected}
>
{selected && (
<CheckmarkIcon aria-hidden className="navds-chips__toggle-icon" />
{selected && checkmark && (
<svg
aria-hidden
className="navds-chips__toggle-icon"
width="10"
height="8"
viewBox="0 0 10 8"
fill="none"
xmlns="http://www.w3.org/2000/svg"
focusable={false}
role="img"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9.51894 0.45851C9.81799 0.745107 9.8281 1.21987 9.5415 1.51893L3.7915 7.51893C3.51247 7.81009 3.05315 7.82848 2.75174 7.56056L0.501735 5.56056C0.192148 5.28537 0.164263 4.81132 0.439451 4.50173C0.71464 4.19214 1.18869 4.16426 1.49828 4.43944L3.20835 5.95951L8.45852 0.481072C8.74511 0.182015 9.21988 0.171913 9.51894 0.45851Z"
fill="currentColor"
/>
</svg>
)}
<span className="navds-chips__chip-text">{children}</span>
</Component>
+73 -20
View File
@@ -66,25 +66,78 @@ export const Default = {
};
export const Toggle = () => {
const [selected, setSelected] = useState<number[]>([]);
const [selected, setSelected] = useState<number[]>([2, 4]);
return (
<Chips>
{options.map((c, y) => (
<Chips.Toggle
selected={selected.includes(y)}
onClick={() =>
setSelected(
selected.includes(y)
? selected.filter((x) => x !== y)
: [...selected, y]
)
}
key={y}
>
{c}
</Chips.Toggle>
))}
</Chips>
<div className="colgap">
<Chips>
{options.map((c, y) => (
<Chips.Toggle
selected={selected.includes(y)}
onClick={() =>
setSelected(
selected.includes(y)
? selected.filter((x) => x !== y)
: [...selected, y]
)
}
key={y}
>
{c}
</Chips.Toggle>
))}
</Chips>
<Chips>
{options.map((c, y) => (
<Chips.Toggle
variant="neutral"
selected={selected.includes(y)}
onClick={() =>
setSelected(
selected.includes(y)
? selected.filter((x) => x !== y)
: [...selected, y]
)
}
key={y}
>
{c}
</Chips.Toggle>
))}
</Chips>
</div>
);
};
export const ToggleNoCheckmark = () => {
const [selected, setSelected] = useState<number>(2);
return (
<div className="colgap">
<Chips>
{options.map((c, y) => (
<Chips.Toggle
selected={selected === y}
checkmark={false}
onClick={() => setSelected(y)}
key={y}
>
{c}
</Chips.Toggle>
))}
</Chips>
<Chips>
{options.map((c, y) => (
<Chips.Toggle
variant="neutral"
selected={selected === y}
checkmark={false}
onClick={() => setSelected(y)}
key={y}
>
{c}
</Chips.Toggle>
))}
</Chips>
</div>
);
};
@@ -108,7 +161,7 @@ export const Removable = () => {
};
export const Regular = () => {
const [selected, setSelected] = useState<number[]>([]);
const [selected, setSelected] = useState<number[]>([2]);
return (
<div className="colgap">
<Chips>
@@ -138,7 +191,7 @@ export const Regular = () => {
};
export const Small = () => {
const [selected, setSelected] = useState<number[]>([]);
const [selected, setSelected] = useState<number[]>([2, 4]);
return (
<div className="colgap">
<Chips size="small">
@@ -65,6 +65,17 @@ export interface CopyButtonProps
activeTitle?: string;
}
/**
* A button component that copies text to the clipboard when clicked.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/copybutton)
* @see 🏷️ {@link CopyButtonProps}
*
* @example
* ```jsx
<CopyButton copyText="3.14" />
* ```
*/
export const CopyButton = forwardRef<HTMLButtonElement, CopyButtonProps>(
(
{
+105 -115
View File
@@ -28,131 +28,121 @@ export interface DateInputProps
variant?: "datepicker" | "monthpicker";
}
export type DateInputType = React.ForwardRefExoticComponent<
DateInputProps & React.RefAttributes<HTMLInputElement>
>;
const DateInput = forwardRef<HTMLInputElement, DateInputProps>((props, ref) => {
const {
className,
hideLabel = false,
label,
description,
variant = "datepicker",
...rest
} = props;
const DateInput: DateInputType = forwardRef<HTMLInputElement, DateInputProps>(
(props, ref) => {
const {
className,
hideLabel = false,
label,
description,
variant = "datepicker",
...rest
} = props;
const isDatepickerVariant = variant === "datepicker";
const isDatepickerVariant = variant === "datepicker";
const conditionalVariables = {
prefix: isDatepickerVariant ? "datepicker-input" : "monthpicker-input",
iconTitle: {
open: isDatepickerVariant ? "Åpne datovelger" : "Åpne månedsvelger",
close: isDatepickerVariant ? "Lukk datovelger" : "Lukk månedsvelger",
},
};
const conditionalVariables = {
prefix: isDatepickerVariant ? "datepicker-input" : "monthpicker-input",
iconTitle: {
open: isDatepickerVariant ? "Åpne datovelger" : "Åpne månedsvelger",
close: isDatepickerVariant ? "Lukk datovelger" : "Lukk månedsvelger",
},
};
const { onOpen, ariaId, open } = useDateInputContext();
const { onOpen, ariaId, open } = useDateInputContext();
const {
inputProps,
size = "medium",
inputDescriptionId,
errorId,
showErrorMsg,
hasError,
} = useFormField(props, conditionalVariables.prefix);
const {
inputProps,
size = "medium",
inputDescriptionId,
errorId,
showErrorMsg,
hasError,
} = useFormField(props, conditionalVariables.prefix);
return (
<div
className={cl(
className,
"navds-form-field",
`navds-form-field--${size}`,
"navds-date__field",
{
"navds-text-field--error": hasError,
"navds-date__field--error": hasError,
"navds-form-field--disabled": !!inputProps.disabled,
"navds-text-field--disabled": !!inputProps.disabled,
}
)}
return (
<div
className={cl(
className,
"navds-form-field",
`navds-form-field--${size}`,
"navds-date__field",
{
"navds-text-field--error": hasError,
"navds-date__field--error": hasError,
"navds-form-field--disabled": !!inputProps.disabled,
"navds-text-field--disabled": !!inputProps.disabled,
}
)}
>
<Label
htmlFor={inputProps.id}
size={size}
className={cl("navds-form-field__label", {
"navds-sr-only": hideLabel,
})}
>
<Label
htmlFor={inputProps.id}
size={size}
className={cl("navds-form-field__label", {
{label}
</Label>
{!!description && (
<BodyShort
as="div"
className={cl("navds-form-field__description", {
"navds-sr-only": hideLabel,
})}
id={inputDescriptionId}
size={size}
>
{label}
</Label>
{!!description && (
<BodyShort
as="div"
className={cl("navds-form-field__description", {
"navds-sr-only": hideLabel,
})}
id={inputDescriptionId}
size={size}
>
{description}
</BodyShort>
)}
<div className="navds-date__field-wrapper">
<input
ref={ref}
{...omit(rest, ["error", "errorId", "size"])}
{...inputProps}
autoComplete="off"
aria-controls={ariaId}
className={cl(
"navds-date__field-input",
"navds-text-field__input",
"navds-body-short",
`navds-body-${size}`
)}
size={14}
/>
<button
disabled={inputProps.disabled}
tabIndex={open ? -1 : 0}
onClick={() => onOpen()}
type="button"
className="navds-date__field-button"
>
<CalendarIcon
pointerEvents="none"
title={
open
? conditionalVariables.iconTitle.close
: conditionalVariables.iconTitle.open
}
/>
</button>
</div>
<div
className="navds-form-field__error"
id={errorId}
aria-relevant="additions removals"
aria-live="polite"
>
{showErrorMsg && (
<ErrorMessage size={size}>{props.error}</ErrorMessage>
{description}
</BodyShort>
)}
<div className="navds-date__field-wrapper">
<input
ref={ref}
{...omit(rest, ["error", "errorId", "size"])}
{...inputProps}
autoComplete="off"
aria-controls={ariaId}
className={cl(
"navds-date__field-input",
"navds-text-field__input",
"navds-body-short",
`navds-body-${size}`
)}
</div>
size={14}
/>
<button
disabled={inputProps.disabled}
tabIndex={open ? -1 : 0}
onClick={() => onOpen()}
type="button"
className="navds-date__field-button"
>
<CalendarIcon
pointerEvents="none"
title={
open
? conditionalVariables.iconTitle.close
: conditionalVariables.iconTitle.open
}
/>
</button>
</div>
);
}
<div
className="navds-form-field__error"
id={errorId}
aria-relevant="additions removals"
aria-live="polite"
>
{showErrorMsg && <ErrorMessage size={size}>{props.error}</ErrorMessage>}
</div>
</div>
);
});
export const DatePickerInput = forwardRef<HTMLInputElement, DateInputProps>(
(props, ref) => <DateInput {...props} ref={ref} />
);
export const DatePickerInput: DateInputType = forwardRef<
HTMLInputElement,
DateInputProps
>((props, ref) => <DateInput {...props} ref={ref} />);
export const MonthPickerInput: DateInputType = forwardRef<
HTMLInputElement,
DateInputProps
>((props, ref) => <DateInput {...props} variant="monthpicker" ref={ref} />);
export const MonthPickerInput = forwardRef<HTMLInputElement, DateInputProps>(
(props, ref) => <DateInput {...props} variant="monthpicker" ref={ref} />
);
@@ -12,7 +12,7 @@ import {
SelectSingleEventHandler,
} from "react-day-picker";
import { omit, Popover, useId } from "../..";
import { DateInputType, DatePickerInput } from "../DateInput";
import { DateInputProps, DatePickerInput } from "../DateInput";
import { DateContext } from "../context";
import { getLocaleFromString, labels } from "../utils";
import { Caption, DropdownCaption } from "./caption";
@@ -120,10 +120,48 @@ export type DatePickerProps = DatePickerDefaultProps & ConditionalModeProps;
interface DatePickerComponent
extends React.ForwardRefExoticComponent<DatePickerProps> {
/**
* @example
* ```jsx
* <DatePicker.Standalone
* dropdownCaption
* fromDate={new Date("2020-10-01")}
* toDate={new Date("2024-10-01")}
* />
* ```
*/
Standalone: DatePickerStandaloneType;
Input: DateInputType;
/**
* Custom TextField for DatePicker
* @see 🏷️ {@link DateInputProps}
*/
Input: React.ForwardRefExoticComponent<
DateInputProps & React.RefAttributes<HTMLInputElement>
>;
}
/**
* A component that allows users to select a date from a calendar.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/datepicker)
* @see 🏷️ {@link DatePickerProps}
*
* @example
* ```jsx
* const { inputProps, datepickerProps } = useMonthpicker({
* onMonthChange: console.log,
* });
*
* return (
* <DatePicker {...datepickerProps} dropdownCaption>
* <DatePicker.Input
* {...inputProps}
* label="Velg dato"
* />
* </DatePicker>
* );
* ```
*/
export const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(
(
{
@@ -113,6 +113,19 @@ const getValidationMessage = (val = {}): DateValidationT => ({
...val,
});
/**
*
* @see 🏷️ {@link UseDatepickerOptions}
* @see 🏷️ {@link UseDatepickerValue}
* @see 🏷️ {@link DateValidationT}
* @example
* const { datepickerProps, inputProps } = useDatepicker({
* fromDate: new Date("Aug 23 2019"),
* toDate: new Date("Feb 23 2024"),
* onDateChange: console.log,
* onValidate: console.log,
* });
*/
export const useDatepicker = (
opt: UseDatepickerOptions = {}
): UseDatepickerValue => {
@@ -110,6 +110,19 @@ const getIsAfter = (opt: { toDate?: Date; date?: Date }) =>
(opt.toDate.getFullYear() === opt.date.getFullYear() &&
opt.toDate.getMonth() < opt.date.getMonth()));
/**
*
* @see 🏷️ {@link UseMonthPickerOptions}
* @see 🏷️ {@link UseMonthPickerValue}
* @see 🏷️ {@link MonthValidationT}
* @example
* const { monthpickerProps, inputProps } = useMonthpicker({
* fromDate: new Date("Aug 23 2019"),
* toDate: new Date("Feb 23 2024"),
* onMonthChange: console.log,
* onValidate: console.log,
* });
*/
export const useMonthpicker = (
opt: UseMonthPickerOptions = {}
): UseMonthPickerValue => {
@@ -102,7 +102,7 @@ const RANGE = {
TO: "TO",
} as const;
type RangeT = typeof RANGE[keyof typeof RANGE];
type RangeT = (typeof RANGE)[keyof typeof RANGE];
const fromValidation = (day: Date, opt?: UseRangeDatepickerOptions) => {
const isBefore =
@@ -190,6 +190,18 @@ const initialValidation = (
return getValidationMessage({ ...fromVal }, { ...toVal });
};
/**
*
* @see 🏷️ {@link UseRangeDatepickerOptions}
* @see 🏷️ {@link UseRangeDatepickerValue}
* @see 🏷️ {@link RangeValidationT}
* @example
* const { datepickerProps, fromInputProps, toInputProps } = useRangeDatepicker({
* fromDate: new Date("Aug 23 2019"),
* onRangeChange: console.log,
* onValidate: console.log,
* });
*/
export const useRangeDatepicker = (
opt: UseRangeDatepickerOptions = {}
): UseRangeDatepickerValue => {
@@ -2,7 +2,7 @@ import cl from "clsx";
import React, { forwardRef, useRef, useState } from "react";
import { RootProvider } from "react-day-picker";
import { Popover, useId } from "../..";
import { DateInputType, MonthPickerInput } from "../DateInput";
import { DateInputProps, MonthPickerInput } from "../DateInput";
import { DateContext, SharedMonthProvider } from "../context";
import { getLocaleFromString, Matcher } from "../utils";
import MonthCaption from "./MonthCaption";
@@ -91,15 +91,47 @@ export interface MonthPickerProps extends React.HTMLAttributes<HTMLDivElement> {
interface MonthPickerComponent
extends React.ForwardRefExoticComponent<MonthPickerProps> {
/**
* Variant without popover
* @example
* ```jsx
* <MonthPicker.Standalone
* dropdownCaption
* fromDate={new Date("1 Oct 2020")}
* toDate={new Date("1 Oct 2024")}
* />
* ```
*/
Standalone: MonthPickerStandaloneType;
/**
* Built-in Inputfield
* Custom TextField for MonthPicker
* @see 🏷️ {@link DateInputProps}
*/
Input: DateInputType;
Input: React.ForwardRefExoticComponent<
DateInputProps & React.RefAttributes<HTMLInputElement>
>;
}
/**
* A component that displays a month picker.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/monthpicker)
* @see 🏷️ {@link MonthPickerProps}
*
* @example
* ```jsx
* const { inputProps, monthpickerProps } = useMonthpicker({
* onMonthChange: console.log,
* });
*
* return (
* <MonthPicker {...monthpickerProps} dropdownCaption>
* <MonthPicker.Input
* {...inputProps}
* label="Velg måned"
* />
* </MonthPicker>
* );
* ```
*/
export const MonthPicker = forwardRef<HTMLDivElement, MonthPickerProps>(
(
{
+41 -2
View File
@@ -1,5 +1,5 @@
import React, { createContext, useState } from "react";
import Toggle, { ToggleType } from "./Toggle";
import Toggle, { ToggleProps } from "./Toggle";
import Menu, { MenuType } from "./Menu";
export interface DropdownProps {
@@ -24,7 +24,15 @@ export interface DropdownProps {
}
export interface DropdownType extends React.FC<DropdownProps> {
Toggle: ToggleType;
/**
* @see 🏷️ {@link ToggleProps}
*/
Toggle: React.ForwardRefExoticComponent<
ToggleProps & React.RefAttributes<HTMLButtonElement>
>;
/**
* @see 🏷️ {@link MenuType}
*/
Menu: MenuType;
}
@@ -38,6 +46,37 @@ export interface DropdownContextType {
export const DropdownContext = createContext<DropdownContextType | null>(null);
/**
* A component that displays a dropdown menu when the user clicks on its toggle button.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/dropdown)
* @see 🏷️ {@link DropdownProps}
*
* @example
* ```jsx
* <Dropdown>
* <Button as={Dropdown.Toggle}>Toggle</Button>
* <Dropdown.Menu>
* <Dropdown.Menu.GroupedList>
* <Dropdown.Menu.GroupedList.Heading>
* Systemer og oppslagsverk
* </Dropdown.Menu.GroupedList.Heading>
* <Dropdown.Menu.GroupedList.Item>
* Gosys
* </Dropdown.Menu.GroupedList.Item>
* <Dropdown.Menu.GroupedList.Item>
* Infotrygd
* </Dropdown.Menu.GroupedList.Item>
* </Dropdown.Menu.GroupedList>
* <Dropdown.Menu.Divider />
* <Dropdown.Menu.List>
* <Dropdown.Menu.List.Item>Gosys</Dropdown.Menu.List.Item>
* <Dropdown.Menu.List.Item>Infotrygd</Dropdown.Menu.List.Item>
* </Dropdown.Menu.List>
* </Dropdown.Menu>
* </Dropdown>
* ```
*/
export const Dropdown = (({
children,
onSelect,
@@ -1,18 +1,15 @@
import React, { forwardRef } from "react";
import cl from "clsx";
export type DividerType = React.ForwardRefExoticComponent<
React.HTMLAttributes<HTMLHRElement> & React.RefAttributes<HTMLHRElement>
>;
export const Divider: DividerType = forwardRef(
({ className, ...rest }, ref) => (
<hr
{...rest}
ref={ref}
className={cl("navds-dropdown__divider", className)}
/>
)
);
export const Divider = forwardRef<
HTMLHRElement,
React.HTMLAttributes<HTMLHRElement>
>(({ className, ...rest }, ref) => (
<hr
{...rest}
ref={ref}
className={cl("navds-dropdown__divider", className)}
/>
));
export default Divider;
@@ -9,23 +9,20 @@ export interface GroupedHeadingProps
children: React.ReactNode;
}
export type GroupedHeadingType = React.ForwardRefExoticComponent<
GroupedHeadingProps & React.RefAttributes<HTMLElement>
>;
export const GroupedHeading: GroupedHeadingType = forwardRef(
({ className, ...rest }, ref) => (
<dt
{...rest}
ref={ref}
className={cl(
"navds-dropdown__list-heading",
"navds-heading",
"navds-heading--xsmall",
className
)}
/>
)
);
export const GroupedHeading = forwardRef<
HTMLDetailsElement,
GroupedHeadingProps
>(({ className, ...rest }, ref) => (
<dt
{...rest}
ref={ref}
className={cl(
"navds-dropdown__list-heading",
"navds-heading",
"navds-heading--xsmall",
className
)}
/>
));
export default GroupedHeading;
@@ -11,35 +11,31 @@ export interface GroupedItemProps
children: React.ReactNode;
}
export type GroupedItemType = OverridableComponent<
export const GroupedItem: OverridableComponent<
GroupedItemProps,
HTMLButtonElement
>;
> = forwardRef(({ as: Component = "button", className, ...rest }, ref) => {
const context = useContext(DropdownContext);
export const GroupedItem: GroupedItemType = forwardRef(
({ as: Component = "button", className, ...rest }, ref) => {
const context = useContext(DropdownContext);
return (
<dd className="navds-dropdown__list-item">
<Component
{...rest}
value={rest.children}
onClick={(event: React.MouseEvent<HTMLElement, MouseEvent>) => {
context?.onSelect?.(event);
rest?.onClick?.(event);
}}
ref={ref}
className={cl(
"navds-dropdown__item",
"navds-body-short",
"navds-body-short--small",
className
)}
/>
</dd>
);
}
);
return (
<dd className="navds-dropdown__list-item">
<Component
{...rest}
value={rest.children}
onClick={(event: React.MouseEvent<HTMLElement, MouseEvent>) => {
context?.onSelect?.(event);
rest?.onClick?.(event);
}}
ref={ref}
className={cl(
"navds-dropdown__item",
"navds-body-short",
"navds-body-short--small",
className
)}
/>
</dd>
);
});
export default GroupedItem;
@@ -1,7 +1,8 @@
import React, { forwardRef } from "react";
import cl from "clsx";
import GroupedHeading, { GroupedHeadingType } from "./Heading";
import GroupedItem, { GroupedItemType } from "./Item";
import React, { forwardRef } from "react";
import { OverridableComponent } from "../../../util/OverridableComponent";
import GroupedHeading, { GroupedHeadingProps } from "./Heading";
import GroupedItem, { GroupedItemProps } from "./Item";
export interface GroupedListProps
extends React.HTMLAttributes<HTMLDListElement> {
@@ -15,8 +16,17 @@ export interface GroupedListType
extends React.ForwardRefExoticComponent<
GroupedListProps & React.RefAttributes<HTMLDListElement>
> {
Heading: GroupedHeadingType;
Item: GroupedItemType;
/**
* @see 🏷️ {@link GroupedHeadingProps}
*/
Heading: React.ForwardRefExoticComponent<
GroupedHeadingProps & React.RefAttributes<HTMLDetailsElement>
>;
/**
* @see 🏷️ {@link GroupedItemProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
*/
Item: OverridableComponent<GroupedItemProps, HTMLButtonElement>;
}
export const DescriptionList = forwardRef(
@@ -10,13 +10,8 @@ export interface ListItemProps extends React.ButtonHTMLAttributes<HTMLElement> {
children: React.ReactNode;
}
export type ListItemType = OverridableComponent<
ListItemProps,
HTMLButtonElement
>;
export const ListItem: ListItemType = forwardRef(
({ as: Component = "button", className, ...rest }, ref) => {
export const ListItem: OverridableComponent<ListItemProps, HTMLButtonElement> =
forwardRef(({ as: Component = "button", className, ...rest }, ref) => {
const context = useContext(DropdownContext);
return (
@@ -38,7 +33,6 @@ export const ListItem: ListItemType = forwardRef(
/>
</li>
);
}
);
});
export default ListItem;
@@ -1,6 +1,7 @@
import React, { forwardRef } from "react";
import cl from "clsx";
import ListItem, { ListItemType } from "./Item";
import React, { forwardRef } from "react";
import { OverridableComponent } from "../../../util/OverridableComponent";
import ListItem, { ListItemProps } from "./Item";
export interface ListProps extends React.HTMLAttributes<HTMLUListElement> {
/**
@@ -13,7 +14,11 @@ export interface ListType
extends React.ForwardRefExoticComponent<
ListProps & React.RefAttributes<HTMLUListElement>
> {
Item: ListItemType;
/**
* @see 🏷️ {@link ListItemProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
*/
Item: OverridableComponent<ListItemProps, HTMLButtonElement>;
}
export const List = forwardRef(({ className, children, ...rest }, ref) => (
+14 -3
View File
@@ -1,8 +1,8 @@
import { Popover } from "../../popover";
import cl from "clsx";
import React, { forwardRef, useContext } from "react";
import { Popover } from "../../popover";
import { DropdownContext } from "../Dropdown";
import Divider, { DividerType } from "./Divider";
import Divider from "./Divider";
import GroupedList, { GroupedListType } from "./GroupedList";
import List, { ListType } from "./List";
@@ -43,9 +43,20 @@ export interface MenuType<Props = MenuProps>
extends React.ForwardRefExoticComponent<
Props & React.RefAttributes<HTMLDivElement>
> {
/**
* @see 🏷️ {@link ListType}
*/
List: ListType;
/**
* @see 🏷️ {@link GroupedListType}
*/
GroupedList: GroupedListType;
Divider: DividerType;
/**
* @see 🏷️ {@link React.HTMLAttributes<HTMLHRElement>}
*/
Divider: React.ForwardRefExoticComponent<
React.HTMLAttributes<HTMLHRElement> & React.RefAttributes<HTMLHRElement>
>;
}
export const Menu = forwardRef<HTMLDivElement, MenuProps>(
+1 -5
View File
@@ -10,11 +10,7 @@ export interface ToggleProps
children: React.ReactNode;
}
export type ToggleType = React.ForwardRefExoticComponent<
ToggleProps & React.RefAttributes<HTMLButtonElement>
>;
export const Toggle: ToggleType = forwardRef(
export const Toggle = forwardRef<HTMLButtonElement, ToggleProps>(
({ className, onClick, ...rest }, ref) => {
const context = useContext(DropdownContext);
@@ -1,28 +1,48 @@
import cl from "clsx";
import React, { createContext, forwardRef, useRef, useState } from "react";
import { OverridableComponent } from "../util/OverridableComponent";
import ExpansionCardContent, {
ExpansionCardContentType,
ExpansionCardContentProps,
} from "./ExpansionCardContent";
import {
ExpansionCardDescription,
ExpansionCardDescriptionType,
ExpansionCardDescriptionProps,
} from "./ExpansionCardDescription";
import ExpansionCardHeader, {
ExpansionCardHeaderType,
ExpansionCardHeaderProps,
} from "./ExpansionCardHeader";
import {
ExpansionCardTitle,
ExpansionCardTitleType,
ExpansionCardTitleProps,
} from "./ExpansionCardTitle";
interface ExpansionCardComponent
extends React.ForwardRefExoticComponent<
ExpansionCardProps & React.RefAttributes<HTMLDivElement>
> {
Header: ExpansionCardHeaderType;
Title: ExpansionCardTitleType;
Description: ExpansionCardDescriptionType;
Content: ExpansionCardContentType;
/**
* @see 🏷️ {@link ExpansionCardHeaderProps}
*/
Header: React.ForwardRefExoticComponent<
ExpansionCardHeaderProps & React.RefAttributes<HTMLDivElement>
>;
/**
* @see 🏷️ {@link ExpansionCardTitleProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
*/
Title: OverridableComponent<ExpansionCardTitleProps, HTMLHeadingElement>;
/**
* @see 🏷️ {@link ExpansionCardDescriptionProps}
*/
Description: React.ForwardRefExoticComponent<
ExpansionCardDescriptionProps & React.RefAttributes<HTMLParagraphElement>
>;
/**
* @see 🏷️ {@link ExpansionCardContentProps}
*/
Content: React.ForwardRefExoticComponent<
ExpansionCardContentProps & React.RefAttributes<HTMLDivElement>
>;
}
interface ExpansionCardCommonProps
@@ -77,6 +97,24 @@ export const ExpansionCardContext = createContext<ExpansionCardContextProps>({
export type ExpansionCardProps = ExpansionCardCommonProps &
ExpansionCardConditionalProps;
/**
* A component that displays an expandable card.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/expansioncard)
* @see 🏷️ {@link ExpansionCardProps}
*
* @example
* ```jsx
* <ExpansionCard aria-label="default-demo">
* <ExpansionCard.Header>
* <ExpansionCard.Title>Utbetaling av sykepenger</ExpansionCard.Title>
* </ExpansionCard.Header>
* <ExpansionCard.Content>
* <Innhold />
* </ExpansionCard.Content>
* </ExpansionCard>
* ```
*/
export const ExpansionCard = forwardRef<HTMLDivElement, ExpansionCardProps>(
(
{
@@ -8,36 +8,33 @@ export interface ExpansionCardContentProps
children: React.ReactNode;
}
export type ExpansionCardContentType = React.ForwardRefExoticComponent<
ExpansionCardContentProps & React.RefAttributes<HTMLDivElement>
>;
const ExpansionCardContent = forwardRef<
HTMLDivElement,
ExpansionCardContentProps
>(({ children, className, ...rest }, ref) => {
const panelContext = useContext(ExpansionCardContext);
const ExpansionCardContent: ExpansionCardContentType = forwardRef(
({ children, className, ...rest }, ref) => {
const panelContext = useContext(ExpansionCardContext);
if (panelContext === null) {
console.error(
"<ExpansionCard.Content> has to be used within an <ExpansionCard>"
);
return null;
}
return (
<BodyLong
{...rest}
ref={ref}
as="div"
className={cl("navds-expansioncard__content", className, {
"navds-expansioncard__content--closed": !panelContext.open,
})}
aria-hidden={!panelContext.open}
size={panelContext.size}
>
<div className="navds-expansioncard__content-inner">{children}</div>
</BodyLong>
if (panelContext === null) {
console.error(
"<ExpansionCard.Content> has to be used within an <ExpansionCard>"
);
return null;
}
);
return (
<BodyLong
{...rest}
ref={ref}
as="div"
className={cl("navds-expansioncard__content", className, {
"navds-expansioncard__content--closed": !panelContext.open,
})}
aria-hidden={!panelContext.open}
size={panelContext.size}
>
<div className="navds-expansioncard__content-inner">{children}</div>
</BodyLong>
);
});
export default ExpansionCardContent;
@@ -3,33 +3,31 @@ import cl from "clsx";
import { BodyLong } from "../typography/BodyLong";
import { ExpansionCardContext } from "./ExpansionCard";
interface ExpansionCardDescriptionProps
export interface ExpansionCardDescriptionProps
extends React.HTMLAttributes<HTMLParagraphElement> {
children: React.ReactNode;
}
export type ExpansionCardDescriptionType = React.ForwardRefExoticComponent<
ExpansionCardDescriptionProps & React.RefAttributes<HTMLParagraphElement>
>;
export const ExpansionCardDescription = forwardRef<
HTMLParagraphElement,
ExpansionCardDescriptionProps
>(({ className, ...rest }, ref) => {
const panelContext = useContext(ExpansionCardContext);
export const ExpansionCardDescription: ExpansionCardDescriptionType =
forwardRef(({ className, ...rest }, ref) => {
const panelContext = useContext(ExpansionCardContext);
if (panelContext === null) {
console.error(
"<ExpansionCard.Description> has to be used within an <ExpansionCard>"
);
return null;
}
return (
<BodyLong
{...rest}
as="p"
ref={ref}
className={cl("navds-link-panel__description", className)}
size={panelContext.size}
/>
if (panelContext === null) {
console.error(
"<ExpansionCard.Description> has to be used within an <ExpansionCard>"
);
});
return null;
}
return (
<BodyLong
{...rest}
as="p"
ref={ref}
className={cl("navds-link-panel__description", className)}
size={panelContext.size}
/>
);
});
@@ -8,43 +8,40 @@ export interface ExpansionCardHeaderProps
children: React.ReactNode;
}
export type ExpansionCardHeaderType = React.ForwardRefExoticComponent<
ExpansionCardHeaderProps & React.RefAttributes<HTMLDivElement>
>;
const ExpansionCardHeader = forwardRef<
HTMLDivElement,
ExpansionCardHeaderProps
>(({ children, className, ...rest }, ref) => {
const panelContext = useContext(ExpansionCardContext);
const ExpansionCardHeader: ExpansionCardHeaderType = forwardRef(
({ children, className, ...rest }, ref) => {
const panelContext = useContext(ExpansionCardContext);
if (panelContext === null) {
console.error(
"<ExpansionCard.Header> has to be used within an <ExpansionCard>"
);
return null;
}
return (
<div
ref={ref}
{...rest}
className={cl("navds-expansioncard__header", className)}
>
<div className="navds-expansioncard__header-content">{children}</div>
<button
className="navds-expansioncard__header-button"
onClick={() => panelContext.toggleOpen()}
type="button"
aria-expanded={panelContext.open}
>
<ChevronDownIcon
className="navds-expansioncard__header-chevron"
title="Vis mer"
/>
</button>
</div>
if (panelContext === null) {
console.error(
"<ExpansionCard.Header> has to be used within an <ExpansionCard>"
);
return null;
}
);
return (
<div
ref={ref}
{...rest}
className={cl("navds-expansioncard__header", className)}
>
<div className="navds-expansioncard__header-content">{children}</div>
<button
className="navds-expansioncard__header-button"
onClick={() => panelContext.toggleOpen()}
type="button"
aria-expanded={panelContext.open}
>
<ChevronDownIcon
className="navds-expansioncard__header-chevron"
title="Vis mer"
/>
</button>
</div>
);
});
export default ExpansionCardHeader;
@@ -2,7 +2,7 @@ import React, { forwardRef } from "react";
import cl from "clsx";
import { OverridableComponent } from "../util/OverridableComponent";
interface ExpansionCardTitleProps
export interface ExpansionCardTitleProps
extends React.HTMLAttributes<HTMLHeadingElement> {
children: React.ReactNode;
/**
@@ -12,12 +12,10 @@ interface ExpansionCardTitleProps
size?: "large" | "medium" | "small";
}
export type ExpansionCardTitleType = OverridableComponent<
export const ExpansionCardTitle: OverridableComponent<
ExpansionCardTitleProps,
HTMLHeadingElement
>;
export const ExpansionCardTitle: ExpansionCardTitleType = forwardRef(
> = forwardRef(
({ className, as: Component = "h3", size = "medium", ...rest }, ref) => (
<Component
{...rest}
@@ -26,6 +26,24 @@ export interface ConfirmationPanelProps
errorId?: string;
}
/**
* A component that displays a confirmation checkbox with a label.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/confirmationpanel)
* @see 🏷️ {@link ConfirmationPanelProps}
*
* @example
* ```jsx
<ConfirmationPanel
checked={state}
label="Ja, jeg samtykker."
onChange={() => setState((x) => !x)}
>
For å komme videre må du gi oss lov til å hente inn og bruke opplysninger
om deg.
</ConfirmationPanel>
* ```
*/
export const ConfirmationPanel = forwardRef<
HTMLInputElement,
ConfirmationPanelProps
+16
View File
@@ -30,6 +30,22 @@ export interface SelectProps
style?: React.CSSProperties;
}
/**
* A component that displays a select input field.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/select)
* @see 🏷️ {@link SelectProps}
*
* @example
* ```jsx
* <Select label="Hvilket land har du bosted i.">
* <option value="">Velg land</option>
* <option value="norge">Norge</option>
* <option value="sverige">Sverige</option>
* <option value="danmark">Danmark</option>
* </Select>
* ```
*/
export const Select = forwardRef<HTMLSelectElement, SelectProps>(
(props, ref) => {
const {
+11
View File
@@ -55,6 +55,17 @@ export interface SwitchProps
description?: string;
}
/**
* A component that displays a switch input field.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/switch)
* @see 🏷️ {@link SwitchProps}
*
* @example
* ```jsx
* <Switch>Slå på notifikasjoner</Switch>
* ```
*/
export const Switch = forwardRef<HTMLInputElement, SwitchProps>(
(props, ref) => {
const { inputProps, size } = useFormField(props, "switch");
+11
View File
@@ -33,6 +33,17 @@ export interface TextFieldProps
type?: "email" | "number" | "password" | "tel" | "text" | "url";
}
/**
* A component that displays a text input field with a label.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/textfield)
* @see 🏷️ {@link TextFieldProps}
*
* @example
* ```jsx
* <TextField label="Har du noen tilbakemeldinger?" />
* ```
*/
export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
(props, ref) => {
const {
+11
View File
@@ -55,6 +55,17 @@ export interface TextareaProps
};
}
/**
* A component that displays a textarea input field with a label.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/textarea)
* @see 🏷️ {@link TextareaProps}
*
* @example
* ```jsx
* <Textarea label="Har du noen tilbakemeldinger?" />
* ```
*/
export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
(props, ref) => {
const {
@@ -35,6 +35,21 @@ export interface CheckboxGroupProps
onChange?: (value: any[]) => void;
}
/**
* A component that allows users to select one or more options from a list.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/checkbox)
* @see 🏷️ {@link CheckboxProps}
*
* @example
* ```jsx
* <CheckboxGroup legend="Hvor vil du sitte?">
* <Checkbox value="Bakerst">Bakerst</Checkbox>
* <Checkbox value="Midterst">Midterst</Checkbox>
* <Checkbox value="Fremst">Fremst</Checkbox>
* </CheckboxGroup>
* ```
*/
export const CheckboxGroup = forwardRef<
HTMLFieldSetElement,
CheckboxGroupProps
@@ -32,6 +32,24 @@ interface ErrorSummaryComponent
Item: ErrorSummaryItemType;
}
/**
* A component that displays a summary of errors.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/errorsummary)
* @see 🏷️ {@link ErrorSummaryProps}
*
* @example
* ```jsx
* <ErrorSummary heading="Du må fikse disse feilene før du kan sende inn søknad.">
* <ErrorSummary.Item href="#1">
* Felt må fylles ut med alder
* </ErrorSummary.Item>
* <ErrorSummary.Item href="#2">
* Tekstfeltet må ha en godkjent e-mail
* </ErrorSummary.Item>
* </ErrorSummary>
* ```
*/
export const ErrorSummary = forwardRef<HTMLDivElement, ErrorSummaryProps>(
(
{
@@ -47,8 +47,8 @@ export interface RadioGroupProps
/**
* Form radio group
* @see https://aksel.nav.no/komponenter/core/radio
* @see {@link RadioGroupProps}
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/radio)
* @see 🏷️ {@link RadioGroupProps}
* @example
* <RadioGroup legend="Får du AAP nå?">
* <Radio value="ja">Ja</Radio>
@@ -91,6 +91,19 @@ export const SearchContext = React.createContext<SearchContextProps | null>(
null
);
/**
* A component that displays a search input field.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/search)
* @see 🏷️ {@link SearchProps}
*
* @example
* ```jsx
* <form>
* <Search label="Søk alle NAV sine sider" variant="primary" />
* </form>
* ```
*/
export const Search = forwardRef<HTMLInputElement, SearchProps>(
(props, ref) => {
const {
@@ -18,6 +18,21 @@ export interface GuidePanelProps extends HTMLAttributes<HTMLDivElement> {
poster?: boolean;
}
/**
* A component that displays a guide panel.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/guidepanel)
* @see 🏷️ {@link GuidePanelProps}
*
* @example
* ```jsx
* <GuidePanel>
* Saksbehandlingstiden varierer fra kommune til kommune. Hvis det går mer
* enn X måneder siden du søkte, skal du få brev om at saksbehandlingstiden
* er forlenget.
* </GuidePanel>
* ```
*/
export const GuidePanel = forwardRef<HTMLDivElement, GuidePanelProps>(
(
{ children, className, illustration, poster = false, color, ...rest },
@@ -31,6 +31,19 @@ export interface HelpTextProps
| "left-end";
}
/**
* A component that displays a help text button with a popover.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/helptext)
* @see 🏷️ {@link HelpTextProps}
*
* @example
* ```jsx
* <HelpText title="Hvor kommer dette fra?">
* Informasjonen er hentet fra X sin statistikk fra 2021
* </HelpText>
* ```
*/
export const HelpText = forwardRef<HTMLButtonElement, HelpTextProps>(
(
{
+1
View File
@@ -22,6 +22,7 @@ export * from "./panel";
export * from "./popover";
export * from "./provider";
export * from "./read-more";
export * from "./skeleton";
export * from "./stepper";
export * from "./table";
export * from "./tabs";
@@ -1,17 +1,18 @@
import cl from "clsx";
import React, { forwardRef, HTMLAttributes } from "react";
import { OverridableComponent } from "../util/OverridableComponent";
import InternalHeaderButton, {
InternalHeaderButtonProps,
} from "./InternalHeaderButton";
import InternalHeaderTitle, {
InternalHeaderTitleType,
InternalHeaderTitleProps,
} from "./InternalHeaderTitle";
import InternalHeaderUser, {
InternalHeaderUserType,
InternalHeaderUserProps,
} from "./InternalHeaderUser";
import InternalHeaderButton, {
InternalHeaderButtonType,
} from "./InternalHeaderButton";
import InternalHeaderUserButton, {
InternalHeaderUserButtonType,
InternalHeaderUserButtonProps,
} from "./InternalHeaderUserButton";
import cl from "clsx";
export interface InternalHeaderProps extends HTMLAttributes<HTMLElement> {
children: React.ReactNode;
@@ -21,12 +22,60 @@ interface InternalHeaderComponent
extends React.ForwardRefExoticComponent<
InternalHeaderProps & React.RefAttributes<HTMLElement>
> {
Title: InternalHeaderTitleType;
User: InternalHeaderUserType;
Button: InternalHeaderButtonType;
UserButton: InternalHeaderUserButtonType;
/**
* @see 🏷️ {@link InternalHeaderTitleProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
*/
Title: OverridableComponent<InternalHeaderTitleProps, HTMLAnchorElement>;
/**
* @see 🏷️ {@link InternalHeaderUserProps}
*/
User: React.ForwardRefExoticComponent<
InternalHeaderUserProps & React.RefAttributes<HTMLDivElement>
>;
/**
* @see 🏷️ {@link InternalHeaderButtonProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
*/
Button: OverridableComponent<InternalHeaderButtonProps, HTMLButtonElement>;
/**
* @see 🏷️ {@link InternalHeaderUserButtonProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
*/
UserButton: OverridableComponent<
InternalHeaderUserButtonProps,
HTMLButtonElement
>;
}
/**
* Simple Header for internal pages and systems.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/i-header)
* @see 🏷️ {@link InternalHeaderProps}
*
* @example
* ```jsx
* <InternalHeader>
* <InternalHeader.Title as="h1">Sykepenger</InternalHeader.Title>
* <InternalHeader.User name="Ola Normann" className="ml-auto" />
* </InternalHeader>
* ```
* @example
* ```jsx
* <InternalHeader >
* <InternalHeader.Title href="/#home">Tittel med lenke</InternalHeader.Title>
* <Dropdown>
* <InternalHeader.Button
* as={Dropdown.Toggle}
* >
* <MenuGridIcon title="MenuGridIconer og oppslagsverk" />
* </InternalHeader.Button>
* <Dropdown.Menu />
* </Dropdown>
* </InternalHeader>
* ```
*/
export const InternalHeader = forwardRef(({ className, ...rest }, ref) => (
<header
data-theme="dark"
@@ -9,20 +9,15 @@ export interface InternalHeaderButtonProps
*/
children: React.ReactNode;
}
export type InternalHeaderButtonType = OverridableComponent<
export const InternalHeaderButton: OverridableComponent<
InternalHeaderButtonProps,
HTMLButtonElement
>;
export const InternalHeaderButton: InternalHeaderButtonType = forwardRef(
({ as: Component = "button", className, ...rest }, ref) => (
<Component
{...rest}
ref={ref}
className={cl("navds-internalheader__button", className)}
/>
)
);
> = forwardRef(({ as: Component = "button", className, ...rest }, ref) => (
<Component
{...rest}
ref={ref}
className={cl("navds-internalheader__button", className)}
/>
));
export default InternalHeaderButton;
@@ -10,26 +10,18 @@ export interface InternalHeaderTitleProps
children: React.ReactNode;
}
export type InternalHeaderTitleType = OverridableComponent<
export const InternalHeaderTitle: OverridableComponent<
InternalHeaderTitleProps,
HTMLAnchorElement
>;
export const InternalHeaderTitle: InternalHeaderTitleType = forwardRef(
({ as: Component = "a", children, className, ...rest }, ref) => (
<Component
{...rest}
ref={ref}
size="xsmall"
className={cl(
"navds-internalheader__title",
"navds-body-short",
className
)}
>
<span>{children}</span>
</Component>
)
);
> = forwardRef(({ as: Component = "a", children, className, ...rest }, ref) => (
<Component
{...rest}
ref={ref}
size="xsmall"
className={cl("navds-internalheader__title", "navds-body-short", className)}
>
<span>{children}</span>
</Component>
));
export default InternalHeaderTitle;
@@ -14,10 +14,6 @@ export interface InternalHeaderUserProps
description?: string;
}
export type InternalHeaderUserType = React.ForwardRefExoticComponent<
InternalHeaderUserProps & React.RefAttributes<HTMLDivElement>
>;
export const InternalHeaderUser = forwardRef<
HTMLDivElement,
InternalHeaderUserProps
@@ -17,27 +17,24 @@ export interface InternalHeaderUserButtonProps
description?: string;
}
export type InternalHeaderUserButtonType = OverridableComponent<
export const InternalHeaderUserButton: OverridableComponent<
InternalHeaderUserButtonProps,
HTMLButtonElement
>;
export const InternalHeaderUserButton: InternalHeaderUserButtonType =
forwardRef(({ as, name, description, className, ...rest }, ref) => (
<InternalHeaderButton
{...rest}
as={as}
ref={ref}
className={cl("navds-internalheader__user-button", className)}
>
<div>
<BodyShort size="small" as="div">
{name}
</BodyShort>
{description && <Detail as="div">{description}</Detail>}
</div>
<ChevronDownIcon title="vis meny" />
</InternalHeaderButton>
));
> = forwardRef(({ as, name, description, className, ...rest }, ref) => (
<InternalHeaderButton
{...rest}
as={as}
ref={ref}
className={cl("navds-internalheader__user-button", className)}
>
<div>
<BodyShort size="small" as="div">
{name}
</BodyShort>
{description && <Detail as="div">{description}</Detail>}
</div>
<ChevronDownIcon title="vis meny" />
</InternalHeaderButton>
));
export default InternalHeaderUserButton;
@@ -2,10 +2,10 @@ import React, { forwardRef } from "react";
import { Panel, OverridableComponent } from "..";
import cl from "clsx";
import { LinkPanelTitle, LinkPanelTitleType } from "./LinkPanelTitle";
import { LinkPanelTitle, LinkPanelTitleProps } from "./LinkPanelTitle";
import {
LinkPanelDescription,
LinkPanelDescriptionType,
LinkPanelDescriptionProps,
} from "./LinkPanelDescription";
import { ChevronRightIcon } from "@navikt/aksel-icons";
@@ -24,10 +24,36 @@ export interface LinkPanelProps
interface LinkPanelComponentType
extends OverridableComponent<LinkPanelProps, HTMLAnchorElement> {
Title: LinkPanelTitleType;
Description: LinkPanelDescriptionType;
/**
* @see 🏷️ {@link LinkPanelDescriptionProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
*/
Title: OverridableComponent<LinkPanelTitleProps, HTMLDivElement>;
/**
* @see 🏷️ {@link LinkPanelDescriptionProps}
*/
Description: React.ForwardRefExoticComponent<
LinkPanelDescriptionProps & React.RefAttributes<HTMLDivElement>
>;
}
/**
* A component that displays a link panel.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/linkpanel)
* @see 🏷️ {@link LinkPanelProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
*
* @example
* ```jsx
* <LinkPanel href="#" border>
* <LinkPanel.Title>Arbeidssøker eller permittert</LinkPanel.Title>
* <LinkPanel.Description>
* Om jobb, registrering, CV, dagpenger og feriepenger av dagpenger
* </LinkPanel.Description>
* </LinkPanel>
* ```
*/
export const LinkPanelComponent: OverridableComponent<
LinkPanelProps,
HTMLAnchorElement
@@ -2,22 +2,19 @@ import React, { forwardRef } from "react";
import cl from "clsx";
import { BodyLong } from "..";
interface LinkPanelDescriptionProps
export interface LinkPanelDescriptionProps
extends React.HTMLAttributes<HTMLDivElement> {
children: React.ReactNode;
}
export type LinkPanelDescriptionType = React.ForwardRefExoticComponent<
LinkPanelDescriptionProps & React.RefAttributes<HTMLDivElement>
>;
export const LinkPanelDescription: LinkPanelDescriptionType = forwardRef(
({ className, ...rest }, ref) => (
<BodyLong
{...rest}
as="div"
ref={ref}
className={cl("navds-link-panel__description", className)}
/>
)
);
export const LinkPanelDescription = forwardRef<
HTMLDivElement,
LinkPanelDescriptionProps
>(({ className, ...rest }, ref) => (
<BodyLong
{...rest}
as="div"
ref={ref}
className={cl("navds-link-panel__description", className)}
/>
));
@@ -2,26 +2,23 @@ import React, { forwardRef } from "react";
import cl from "clsx";
import { OverridableComponent } from "../util/OverridableComponent";
interface LinkPanelTitleProps extends React.HTMLAttributes<HTMLDivElement> {
export interface LinkPanelTitleProps
extends React.HTMLAttributes<HTMLDivElement> {
children: React.ReactNode;
}
export type LinkPanelTitleType = OverridableComponent<
export const LinkPanelTitle: OverridableComponent<
LinkPanelTitleProps,
HTMLDivElement
>;
export const LinkPanelTitle: LinkPanelTitleType = forwardRef(
({ className, as: Component = "div", ...rest }, ref) => (
<Component
{...rest}
ref={ref}
className={cl(
"navds-link-panel__title",
"navds-heading",
"navds-heading--medium",
className
)}
/>
)
);
> = forwardRef(({ className, as: Component = "div", ...rest }, ref) => (
<Component
{...rest}
ref={ref}
className={cl(
"navds-link-panel__title",
"navds-heading",
"navds-heading--medium",
className
)}
/>
));
+13
View File
@@ -10,6 +10,19 @@ export interface LinkProps
children: React.ReactNode;
}
/**
* A component that displays a hyperlink.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/link)
* @see 🏷️ {@link LinkProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
*
* @example
* ```jsx
* <Link href="#">lenke til ny side</Link>
* <Link as={ReactRouter.Link} to="#">lenke til ny side</Link>
* ```
*/
export const Link: OverridableComponent<LinkProps, HTMLAnchorElement> =
forwardRef(({ as: Component = "a", className, ...rest }, ref) => (
<Component {...rest} ref={ref} className={cl("navds-link", className)} />
+7 -2
View File
@@ -2,7 +2,7 @@ import cl from "clsx";
import React, { createContext, forwardRef, useContext } from "react";
import { BodyShort, Heading } from "../typography";
import { useId } from "../util/useId";
import { ListItem, ListItemType } from "./ListItem";
import { ListItem, ListItemProps } from "./ListItem";
export interface ListProps extends React.HTMLAttributes<HTMLDivElement> {
children: React.ReactNode;
@@ -28,7 +28,12 @@ export interface ListProps extends React.HTMLAttributes<HTMLDivElement> {
export interface ListComponent
extends React.ForwardRefExoticComponent<ListProps> {
Item: ListItemType;
/**
* @see 🏷️ {@link ListItemProps}
*/
Item: React.ForwardRefExoticComponent<
ListItemProps & React.RefAttributes<HTMLLIElement>
>;
}
interface ListContextProps {
+1 -6
View File
@@ -18,12 +18,7 @@ export interface ListItemProps extends React.HTMLAttributes<HTMLLIElement> {
icon?: React.ReactNode;
}
export interface ListItemType
extends React.ForwardRefExoticComponent<
ListItemProps & React.RefAttributes<HTMLLIElement>
> {}
export const ListItem: ListItemType = forwardRef(
export const ListItem = forwardRef<HTMLLIElement, ListItemProps>(
({ className, children, title, icon, ...rest }, ref) => {
const { listType, isNested } = useContext(ListContext);
+11
View File
@@ -38,6 +38,17 @@ export type LoaderType = React.ForwardRefExoticComponent<
LoaderProps & React.RefAttributes<SVGSVGElement>
>;
/**
* A component that displays a loading spinner.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/loader)
* @see 🏷️ {@link LoaderProps}
*
* @example
* ```jsx
* <Loader size="3xlarge" title="venter..." />
* ```
*/
export const Loader: LoaderType = forwardRef<SVGSVGElement, LoaderProps>(
(
{
+27
View File
@@ -71,6 +71,33 @@ type ModalLifecycle = {
setAppElement: (element: any) => void;
};
/**
* A component that displays a modal dialog.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/modal)
* @see 🏷️ {@link ModalProps}
*
* @example
* ```jsx
* const [open, setOpen] = useState(false);
*
* <Modal
* open={open}
* aria-label="Modal demo"
* onClose={() => setOpen((x) => !x)}
* aria-labelledby="modal-heading"
* >
* <Modal.Content>
* <Heading spacing level="1" size="large" id="modal-heading">
* Viktig info
* </Heading>
* <BodyLong spacing>
* Hallo!
* </BodyLong>
* </Modal.Content>
* </Modal>
* ```
*/
export const Modal = forwardRef<ReactModal, ModalProps>(
(
{
@@ -89,6 +89,23 @@ export const getSteps = ({
];
};
/**
* A component that displays pagination controls.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/pagination)
* @see 🏷️ {@link PaginationProps}
*
* @example
* ```jsx
* <Pagination
* page={pageState}
* onPageChange={(x) => setPageState(x)}
* count={9}
* boundaryCount={1}
* siblingCount={1}
* />
* ```
*/
export const Pagination = forwardRef<HTMLElement, PaginationProps>(
(
{
+19
View File
@@ -16,6 +16,25 @@ export interface PanelProps extends React.HTMLAttributes<HTMLElement> {
export type PanelType = OverridableComponent<PanelProps, HTMLElement>;
/**
* A component that displays a bordered panel with heading and body.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/panel)
* @see 🏷️ {@link PanelProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
*
* @example
* ```jsx
* <Panel border>
* <Heading spacing level="2" size="large">
* Søk om økonomisk sosialhjelp
* </Heading>
* <BodyLong>
* Du kan søke om det du trenger økonomisk støtte til.
* </BodyLong>
* </Panel>
* ```
*/
export const Panel: PanelType = forwardRef(
(
{ children, className, border = false, as: Component = "div", ...rest },
@@ -81,6 +81,26 @@ interface PopoverComponent
Content: PopoverContentType;
}
/**
* A component that displays a popover.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/popover)
* @see 🏷️ {@link PopoverProps}
*
* @example
* ```jsx
* <Button ref={buttonRef} onClick={() => setOpenState(true)}>
* Åpne popover
* </Button>
* <Popover
* open={openState}
* onClose={() => setOpenState(false)}
* anchorEl={buttonRef.current}
* >
* <Popover.Content>Innhold her!</Popover.Content>
* </Popover>
* ```
*/
export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
(
{
@@ -23,6 +23,19 @@ export interface ProviderProps {
export const useProvider = () => useContext(ProviderContext);
/**
* Provides added context to the component tree.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/provider)
* @see 🏷️ {@link ProviderProps}
*
* @example
* ```jsx
* <Provider rootElement={rootElement}>
* {app}
* </Provider>
* ```
*/
export const Provider = ({ children, ...rest }: ProviderProps) => {
return (
<ProviderContext.Provider value={rest}>{children}</ProviderContext.Provider>
@@ -32,8 +32,8 @@ export interface ReadMoreProps
/**
* ReadMore
* @see https://aksel.nav.no/komponenter/core/read-more
* @see {@link ReadMoreProps}
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/read-more)
* @see 🏷️ {@link ReadMoreProps}
*
* @example
* // Default
@@ -0,0 +1,57 @@
import React, { forwardRef } from "react";
import cl from "clsx";
export interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
/**
* @default text
*/
variant?: "circle" | "rectangle" | "rounded" | "text";
/**
* When not inferring height from children, you must specify height
*/
height?: number | string;
/**
* When not inferring width from children, you must specify width
*/
width?: number | string;
}
/**
* Simple skeleton loader
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/skeleton)
* @see 🏷️ {@link SkeletonProps}
* @example
* ```jsx
* <Skeleton variant="circle" height="5rem" width="5rem" />
* ```
*/
export const Skeleton = forwardRef<HTMLDivElement, SkeletonProps>(
(
{ className, children, height, width, style, variant = "text", ...rest },
ref
) => {
return (
<div
{...rest}
ref={ref}
className={cl(
"navds-skeleton",
className,
`navds-skeleton--${variant}`,
{
"navds-skeleton--has-children": Boolean(children),
"navds-skeleton--no-height": !height,
"navds-skeleton--no-width": !width,
}
)}
style={{ ...style, width, height }}
aria-hidden
>
{children}
</div>
);
}
);
export default Skeleton;
+2
View File
@@ -0,0 +1,2 @@
export { default as Skeleton } from "./Skeleton";
export type { SkeletonProps } from "./Skeleton";
@@ -0,0 +1,118 @@
import React from "react";
import { Skeleton } from ".";
import { Alert } from "../alert";
import { Button } from "../button";
import { Checkbox } from "../form";
import { BodyLong, Heading } from "../typography";
export default {
title: "ds-react/Skeleton",
component: Skeleton,
decorators: [
(Story) => (
<div style={{ display: "grid", gap: "0.5rem" }}>
<Story />
</div>
),
],
};
export const Default = {
render: () => (
<div>
<Skeleton>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur
voluptas sint dolore omnis quia consequatur beatae vero cum officia
debitis. Quidem debitis omnis reprehenderit nobis rerum. Nulla, magnam?
Saepe, eveniet? Test
</Skeleton>
<Skeleton>
<Alert variant="info">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur
voluptas sint dolore omnis quia consequatur beatae vero cum officia
debitis. Quidem debitis omnis reprehenderit nobis rerum. Nulla,
magnam? Saepe, eveniet?
</Alert>
</Skeleton>
<Skeleton>
<BodyLong>
Quidem debitis omnis reprehenderit nobis rerum. Nulla, magnam? Saepe,
eveniet?
</BodyLong>
<Checkbox value="test">Valg 1</Checkbox>
<Checkbox value="tes2">Valg 2</Checkbox>
<div style={{ display: "flex", gap: "2rem" }}>
<Button>Send inn</Button>
<Button>Tilbake</Button>
</div>
</Skeleton>
</div>
),
};
export const Shapes = {
render: () => (
<>
<Skeleton variant="text"></Skeleton>
<Skeleton variant="circle" width={60} height={60}></Skeleton>
<Skeleton variant="rectangle" width={200} height={40}></Skeleton>
<Skeleton variant="rounded" width={200} height={40}></Skeleton>
</>
),
};
export const WrappingComponents = {
render: () => (
<Skeleton style={{ display: "grid", gap: "0.5rem" }}>
<BodyLong>
Quidem debitis omnis reprehenderit nobis rerum. Nulla, magnam? Saepe,
eveniet?
</BodyLong>
<Checkbox value="test">Valg 1</Checkbox>
<Checkbox value="tes2">Valg 2</Checkbox>
<div style={{ display: "flex", gap: "2rem" }}>
<Button>Send inn</Button>
<Button>Tilbake</Button>
</div>
</Skeleton>
),
};
export const TextSizing = {
render: () => (
<div style={{ display: "grid", width: 300 }}>
<Skeleton>
<Heading level="1" size="xlarge">
Placeholder
</Heading>
</Skeleton>
<Skeleton>
<BodyLong>Placeholder</BodyLong>
</Skeleton>
<BodyLong as={Skeleton}>Placeholder</BodyLong>
</div>
),
};
export const NativeText = {
render: () => (
<div>
<h1>
<Skeleton>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur
voluptas sint dolore omnis quia consequatur beatae vero cum officia
debitis. Quidem debitis omnis reprehenderit nobis rerum. Nulla,
magnam? Saepe, eveniet? Test
</Skeleton>
</h1>
<Skeleton>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur
voluptas sint dolore omnis quia consequatur beatae vero cum officia
debitis. Quidem debitis omnis reprehenderit nobis rerum. Nulla,
magnam? Saepe, eveniet? Test
</p>
</Skeleton>
</div>
),
};
+57 -60
View File
@@ -45,69 +45,66 @@ const CompletedIcon = () => (
</svg>
);
export interface StepperStepType
extends OverridableComponent<StepperStepProps, HTMLAnchorElement> {}
export const Step: OverridableComponent<StepperStepProps, HTMLAnchorElement> =
forwardRef(
(
{
className,
children,
as: Component = "a",
unsafe_index = 0,
completed = false,
interactive,
...rest
},
ref
) => {
const context = useContext(StepperContext);
if (context === null) {
console.error("<Stepper.Step> has to be used within <Stepper>");
return null;
}
const { activeStep } = context;
export const StepComponent: OverridableComponent<
StepperStepProps,
HTMLAnchorElement
> = forwardRef(
(
{
className,
children,
as: Component = "a",
unsafe_index = 0,
completed = false,
interactive,
...rest
},
ref
) => {
const context = useContext(StepperContext);
if (context === null) {
console.error("<Stepper.Step> has to be used within <Stepper>");
return null;
}
const { activeStep } = context;
const isInteractive = interactive ?? context?.interactive;
const isInteractive = interactive ?? context?.interactive;
const Comp = isInteractive ? Component : "div";
const Comp = isInteractive ? Component : "div";
return (
<Comp
{...rest}
aria-current={activeStep === unsafe_index}
ref={ref}
className={cl("navds-stepper__step", className, {
"navds-stepper__step--active": activeStep === unsafe_index,
"navds-stepper__step--behind": activeStep > unsafe_index,
"navds-stepper__step--non-interactive": !isInteractive,
"navds-stepper__step--completed": completed,
})}
onClick={(e) => {
isInteractive && context.onStepChange(unsafe_index + 1);
rest?.onClick?.(e);
}}
>
{completed ? (
<span className="navds-stepper__circle navds-stepper__circle--success">
<CompletedIcon />
</span>
) : (
<Label className="navds-stepper__circle" as="span" aria-hidden="true">
{unsafe_index + 1}
return (
<Comp
{...rest}
aria-current={activeStep === unsafe_index}
ref={ref}
className={cl("navds-stepper__step", className, {
"navds-stepper__step--active": activeStep === unsafe_index,
"navds-stepper__step--behind": activeStep > unsafe_index,
"navds-stepper__step--non-interactive": !isInteractive,
"navds-stepper__step--completed": completed,
})}
onClick={(e) => {
isInteractive && context.onStepChange(unsafe_index + 1);
rest?.onClick?.(e);
}}
>
{completed ? (
<span className="navds-stepper__circle navds-stepper__circle--success">
<CompletedIcon />
</span>
) : (
<Label
className="navds-stepper__circle"
as="span"
aria-hidden="true"
>
{unsafe_index + 1}
</Label>
)}
<Label as="span" className="navds-stepper__content">
{children}
</Label>
)}
<Label as="span" className="navds-stepper__content">
{children}
</Label>
</Comp>
);
}
);
const Step = StepComponent as StepperStepType;
</Comp>
);
}
);
export default Step;
+31 -2
View File
@@ -1,6 +1,7 @@
import React, { createContext, forwardRef } from "react";
import cl from "clsx";
import Step, { StepperStepProps, StepperStepType } from "./Step";
import Step, { StepperStepProps } from "./Step";
import { OverridableComponent } from "../util/OverridableComponent";
export interface StepperProps extends React.HTMLAttributes<HTMLOListElement> {
/**
@@ -33,7 +34,11 @@ interface StepperComponent
extends React.ForwardRefExoticComponent<
StepperProps & React.RefAttributes<HTMLOListElement>
> {
Step: StepperStepType;
/**
* @see 🏷️ {@link StepperStepProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
*/
Step: OverridableComponent<StepperStepProps, HTMLAnchorElement>;
}
interface StepperContextProps {
@@ -46,6 +51,30 @@ interface StepperContextProps {
export const StepperContext = createContext<StepperContextProps | null>(null);
/**
* A component that displays a stepper with clickable steps.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/stepper)
* @see 🏷️ {@link StepperProps}
*
* @example
* ```jsx
* <>
* <Heading size="medium" spacing level="2" id="stepper-heading">
* Søknadssteg
* </Heading>
* <Stepper
* aria-labelledby="stepper-heading"
* activeStep={activeStep}
* onStepChange={(x) => setActiveStep(x)}
* >
* <Stepper.Step href="#">Start søknad</Stepper.Step>
* <Stepper.Step href="#">Saksopplysninger</Stepper.Step>
* <Stepper.Step href="#">Vedlegg</Stepper.Step>
* </Stepper>
* </>
* ```
*/
export const Stepper: StepperComponent = forwardRef<
HTMLOListElement,
StepperProps
+32
View File
@@ -56,6 +56,38 @@ export interface TableContextProps {
export const TableContext = createContext<TableContextProps | null>(null);
/**
* A component that displays a table with headers and rows.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/table)
* @see 🏷️ {@link TableProps}
*
* @example
* ```jsx
* <Table>
* <Table.Header>
* <Table.Row>
* <Table.HeaderCell scope="col">Navn</Table.HeaderCell>
* <Table.HeaderCell scope="col">Fødseslnr.</Table.HeaderCell>
* <Table.HeaderCell scope="col">Start</Table.HeaderCell>
* </Table.Row>
* </Table.Header>
* <Table.Body>
* {data.map(({ name, fnr, start }, i) => {
* return (
* <Table.Row key={i + fnr}>
* <Table.HeaderCell scope="row">{name}</Table.HeaderCell>
* <Table.DataCell>{fnr}</Table.DataCell>
* <Table.DataCell>
* {format(new Date(start), "dd.MM.yyyy")}
* </Table.DataCell>
* </Table.Row>
* );
* })}
* </Table.Body>
* </Table>
* ```
*/
export const Table = forwardRef(
(
{
+38 -39
View File
@@ -20,47 +20,46 @@ export interface TabProps
value: string;
}
export type TabType = OverridableComponent<TabProps, HTMLButtonElement>;
export const Tab: OverridableComponent<TabProps, HTMLButtonElement> =
forwardRef(
(
{ className, as: Component = "button", label, icon, value, ...rest },
ref
) => {
const context = useContext(TabsContext);
export const Tab: TabType = forwardRef(
(
{ className, as: Component = "button", label, icon, value, ...rest },
ref
) => {
const context = useContext(TabsContext);
if (!label && !icon) {
console.error("<Tabs.Tab/> needs label/icon");
return null;
}
if (!label && !icon) {
console.error("<Tabs.Tab/> needs label/icon");
return null;
}
return (
<RadixTabs.Trigger value={value} asChild>
<Component
ref={ref}
className={cl(
"navds-tabs__tab",
`navds-tabs__tab--${context?.size ?? "medium"}`,
`navds-tabs__tab-icon--${context?.iconPosition}`,
className,
{
"navds-tabs__tab--icon-only": icon && !label,
}
)}
{...rest}
>
<BodyShort
as="span"
className="navds-tabs__tab-inner"
size={context?.size}
return (
<RadixTabs.Trigger value={value} asChild>
<Component
ref={ref}
className={cl(
"navds-tabs__tab",
`navds-tabs__tab--${context?.size ?? "medium"}`,
`navds-tabs__tab-icon--${context?.iconPosition}`,
className,
{
"navds-tabs__tab--icon-only": icon && !label,
}
)}
{...rest}
>
{icon}
{label}
</BodyShort>
</Component>
</RadixTabs.Trigger>
);
}
);
<BodyShort
as="span"
className="navds-tabs__tab-inner"
size={context?.size}
>
{icon}
{label}
</BodyShort>
</Component>
</RadixTabs.Trigger>
);
}
);
export default Tab;
+1 -5
View File
@@ -19,10 +19,6 @@ export interface TabListProps extends React.HTMLAttributes<HTMLDivElement> {
children: React.ReactNode;
}
export type TabListType = React.ForwardRefExoticComponent<
TabListProps & React.RefAttributes<HTMLDivElement>
>;
export const TabList = forwardRef<HTMLDivElement, TabListProps>(
({ className, ...rest }, ref) => {
const context = useContext(TabsContext);
@@ -127,6 +123,6 @@ export const TabList = forwardRef<HTMLDivElement, TabListProps>(
</div>
);
}
) as TabListType;
);
export default TabList;
+1 -5
View File
@@ -13,10 +13,6 @@ export interface TabPanelProps extends React.HTMLAttributes<HTMLDivElement> {
value: string;
}
export type TabPanelType = React.ForwardRefExoticComponent<
TabPanelProps & React.RefAttributes<HTMLDivElement>
>;
const TabPanel = forwardRef<HTMLDivElement, TabPanelProps>(
({ className, ...rest }, ref) => (
<TabsContent
@@ -25,6 +21,6 @@ const TabPanel = forwardRef<HTMLDivElement, TabPanelProps>(
className={cl("navds-tabs__tabpanel", className)}
/>
)
) as TabPanelType;
);
export default TabPanel;
+48 -7
View File
@@ -1,9 +1,10 @@
import * as RadixTabs from "@radix-ui/react-tabs";
import cl from "clsx";
import React, { createContext, forwardRef, HTMLAttributes } from "react";
import * as RadixTabs from "@radix-ui/react-tabs";
import Tab, { TabType } from "./Tab";
import TabList, { TabListType } from "./TabList";
import TabPanel, { TabPanelType } from "./TabPanel";
import { OverridableComponent } from "../util/OverridableComponent";
import Tab, { TabProps } from "./Tab";
import TabList, { TabListProps } from "./TabList";
import TabPanel, { TabPanelProps } from "./TabPanel";
export interface TabsProps
extends Omit<HTMLAttributes<HTMLDivElement>, "onChange" | "dir"> {
@@ -46,9 +47,23 @@ interface TabsComponent
extends React.ForwardRefExoticComponent<
TabsProps & React.RefAttributes<HTMLDivElement>
> {
Tab: TabType;
List: TabListType;
Panel: TabPanelType;
/**
* @see 🏷️ {@link TabProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
*/
Tab: OverridableComponent<TabProps, HTMLButtonElement>;
/**
* @see 🏷️ {@link TabListProps}
*/
List: React.ForwardRefExoticComponent<
TabListProps & React.RefAttributes<HTMLDivElement>
>;
/**
* @see 🏷️ {@link TabPanelProps}
*/
Panel: React.ForwardRefExoticComponent<
TabPanelProps & React.RefAttributes<HTMLDivElement>
>;
}
interface TabsContextProps {
@@ -59,6 +74,32 @@ interface TabsContextProps {
export const TabsContext = createContext<TabsContextProps | null>(null);
/**
* A component that displays a set of tabs that can be used to switch between different views.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/tabs)
* @see 🏷️ {@link TabsProps}
*
* @example
* ```jsx
* <Tabs defaultValue="logg">
* <Tabs.List>
* <Tabs.Tab value="logg" label="Logg" />
* <Tabs.Tab value="inbox" label="Inbox" />
* <Tabs.Tab value="sendt" label="Sendt" />
* </Tabs.List>
* <Tabs.Panel value="logg" className="h-24 w-full bg-gray-50 p-4">
* Logg-tab
* </Tabs.Panel>
* <Tabs.Panel value="inbox" className="h-24 w-full bg-gray-50 p-4">
* Inbox-tab
* </Tabs.Panel>
* <Tabs.Panel value="sendt" className="h-24 w-full bg-gray-50 p-4">
* Sendt-tab
* </Tabs.Panel>
* </Tabs>
* ```
*/
export const Tabs = forwardRef<HTMLDivElement, TabsProps>(
(
{
+11
View File
@@ -38,6 +38,17 @@ export interface TagProps extends HTMLAttributes<HTMLSpanElement> {
size?: "medium" | "small" | "xsmall";
}
/**
* A component that displays a small label with a text and a background color.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/tag)
* @see 🏷️ {@link TagProps}
*
* @example
* ```jsx
* <Tag variant="success">Success</Tag>
* ```
*/
export const Tag = forwardRef<HTMLSpanElement, TagProps>(
({ className, variant, size = "medium", ...rest }, ref) => (
<BodyShort
+22 -4
View File
@@ -38,23 +38,41 @@ export interface TimelineProps extends React.HTMLAttributes<HTMLDivElement> {
interface TimelineComponent
extends React.ForwardRefExoticComponent<TimelineProps> {
/**
* Built-in timeline row
* @see 🏷️ {@link TimelineRowType}
*/
Row: TimelineRowType;
/**
* Built-in row period
* @see 🏷️ {@link PeriodType}
*/
Period: PeriodType;
/**
* Built-in timeline pin
* @see 🏷️ {@link PinType}
*/
Pin: PinType;
/**
* Built-in timeline zoom-component
* @see 🏷️ {@link ZoomType}
*/
Zoom: ZoomType;
}
/**
* A component that displays a timeline of events. Meant for Internal systems.
* @note Component is made for desktop enviroments and will start having issues on smaller screens.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/timeline)
* @see 🏷️ {@link TimelineProps}
*
* @example
* ```jsx
* <Timeline>
* <Timeline.Row>
* <Timeline.Period start={new Date("2020-01-01")} end={new Date("2020-01-31")}>
* <p>Period 1</p>
* </Timeline.Period>
* <Timeline.Row>
* </Timeline>
* ```
*/
export const Timeline = forwardRef<HTMLDivElement, TimelineProps>(
({ children, startDate, endDate, direction = "left", ...rest }, ref) => {
const isMultipleRows = Array.isArray(children);
@@ -1,3 +1,4 @@
import * as RadixToggleGroup from "@radix-ui/react-toggle-group";
import cl from "clsx";
import React, {
createContext,
@@ -5,9 +6,8 @@ import React, {
HTMLAttributes,
useState,
} from "react";
import ToggleItem, { ToggleItemType } from "./ToggleItem";
import * as RadixToggleGroup from "@radix-ui/react-toggle-group";
import { Label, useId } from "..";
import ToggleItem, { ToggleItemProps } from "./ToggleItem";
export interface ToggleGroupProps
extends Omit<HTMLAttributes<HTMLDivElement>, "onChange" | "dir"> {
@@ -47,7 +47,12 @@ interface ToggleGroupComponent
extends React.ForwardRefExoticComponent<
ToggleGroupProps & React.RefAttributes<HTMLDivElement>
> {
Item: ToggleItemType;
/**
* @see 🏷️ {@link ToggleItemProps}
*/
Item: React.ForwardRefExoticComponent<
ToggleItemProps & React.RefAttributes<HTMLButtonElement>
>;
}
interface ToggleContextProps {
@@ -58,6 +63,21 @@ export const ToggleGroupContext = createContext<ToggleContextProps | null>(
null
);
/**
* A component that displays a group of toggle buttons.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/toggle-group)
* @see 🏷️ {@link ToggleGroupProps}
*
* @example
* ```jsx
* <ToggleGroup defaultValue="lest" onChange={console.log} size="small">
* <ToggleGroup.Item value="ulest">Ulest</ToggleGroup.Item>
* <ToggleGroup.Item value="lest">Leste</ToggleGroup.Item>
* <ToggleGroup.Item value="sendt">Sendt</ToggleGroup.Item>
* </ToggleGroup>
* ```
*/
export const ToggleGroup = forwardRef<HTMLDivElement, ToggleGroupProps>(
(
{
@@ -16,10 +16,6 @@ export interface ToggleItemProps
value: string;
}
export type ToggleItemType = React.ForwardRefExoticComponent<
ToggleItemProps & React.RefAttributes<HTMLButtonElement>
>;
const ToggleItem = forwardRef<HTMLButtonElement, ToggleItemProps>(
({ className, children, ...rest }, ref) => {
const context = useContext(ToggleGroupContext);
@@ -40,6 +36,6 @@ const ToggleItem = forwardRef<HTMLButtonElement, ToggleItemProps>(
</RadixToggleGroup.Item>
);
}
) as ToggleItemType;
);
export default ToggleItem;
@@ -75,6 +75,19 @@ export interface TooltipProps extends HTMLAttributes<HTMLDivElement> {
keys?: string[];
}
/**
* A component that displays a tooltip when the user hovers over its child element.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/tooltip)
* @see 🏷️ {@link TooltipProps}
*
* @example
* ```jsx
* <Tooltip content="Skriv ut dokument">
* <Button icon={<PrinterLargeIcon title="demo knapp" />} />
* </Tooltip>
* ```
*/
export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
(
{
@@ -19,6 +19,20 @@ export interface BodyLongProps
spacing?: boolean;
}
/**
* Part of a set of components for displaying text with consistent typography.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/typography)
* @see 🏷️ {@link BodyLongProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
*
* @example
* ```jsx
* <BodyLong level="1" size="xlarge">
* Pengestøtte når du er syk
* </BodyLong>
* ```
*/
export const BodyLong: OverridableComponent<
BodyLongProps,
HTMLParagraphElement
@@ -19,6 +19,20 @@ export interface BodyShortProps
spacing?: boolean;
}
/**
* Part of a set of components for displaying text with consistent typography.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/typography)
* @see 🏷️ {@link BodyShortProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
*
* @example
* ```jsx
* <BodyShort level="1" size="xlarge">
* Pengestøtte når du er syk
* </BodyShort>
* ```
*/
export const BodyShort: OverridableComponent<
BodyShortProps,
HTMLParagraphElement
Loaded 100 of 137 files, more files were not shown because too many files have changed in this diff. Show more