Compare commits

...
Author SHA1 Message Date
github-actions[bot]andgithub-actions[bot] 4742f2f580 Version Packages (#2275)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-09-13 14:58:02 +02:00
Ken 9f2052e1c2 🐛 Width fungerte ikke med inline-variant av skeleton (#2273) 2023-09-13 14:42:05 +02:00
Julian Nymark f6fcf0c4fd :arrow-up: add missing typescript version bump in main (#2272) 2023-09-13 11:46:38 +02:00
83c9194a48 initial box (heavily inspired by shopify Box) (#2195)
* initial box (heavily inspired by shopify Box)

* 🎨 Theming-demo

* rm printHidden prop

* sr-only: clip is deprecated, adding clip-path

* setting up padding story box primitive

* 95% complete padding example for Box (dynamic css code unfolding with types)

* WIP on padding/margin for box

* working box padding/block/inline/margin?

* remove console.log

* story for Box, copy implementation from padding to apply to margin as well

* remove unwanted props on Box

* refactor semantic-colors.json, use json import for types in Box.tsx

* squashme

* Box: working border & background

* 🔥 remove props on Box we will not implement in v1

* refactoring / less things needed (no margin) and things that are broken show up in stories

* 🐛 fix erroneous padding assignment (a flipped index)

* fully recreated LinkPanel

* box: add all borderRadius props

* box: complete example for chat bubbles

* 📝 refactor box hover props to be an object instead

* checkout main yarn.lock

* yarn changeset

* 📝 add jsdoc for Box

* 📝 add token documentation

* 🚧 Box: add barrel file

* 🔥 remove overriding tokens for Box

* ♻️ refactor the borderRadius API

* 🔥 remove console.logs

* bump ts version (make them all equal)

* fix new type error that surfaced when upgrading TS

* add yarn.lock

* 🚧 testing with older TS version again

* Revert "🚧 testing with older TS version again"

This reverts commit ca09f3c419.

* add minimum permissions check utility (official github action)

* Revert "add minimum permissions check utility (official github action)"

This reverts commit f9dd5ea436.

* test with "read-all|write-all" for a chromatic.yml action

* remove unused comments

* 🚧 try skip a test suite

* Revert "🚧 try skip a test suite"

This reverts commit ccf4711c25.

* 🚧 update all node-version to 19

* 💥 Force-tester GHA

* 💥 bump node-version to 20

* 💥 test with jsonModules again, but this time with node v20

* 🚧 revert type erasure (for tests)

* 🔥 remove hover from Box

* 🚧 test with module identifier import

* 🚧 squashme

* a working token type solution

* 📝 group Primitives in storybook

* no longer assert type, hint instead

* 📝 improve jsdoc for Box

* 📝 improve jsdoc for Box

* 🚧 test relative import for github action

* 🚧 test ordering of yarn builds

* 🚧 test ordering of yarn workspaces

* 🚧 test dependency for yarn workspaces

* 🐛 fix human error in token refactoring

* 📝 reword jsdoc

* ♻️ refactor

* 🚧 test again with module identifier import

* squashme

* 🚧 fully revert to importing .json

* 🚧 remove duplicate types

* 🔥 remove style-dicitonary format (now unused), fix shadow.json refs

* remove devDependency on tokens (for react)

* 📝♻️ update comments & naming

* 🚚 Oppdatert CSS-config etter ny primitives gruppering

* make border-color also control border-style

* add examples for Box to aksel.nav.no

* ⬆️ Yarn sort av dependencies

* 🎨 BorderWidth tokens

* 🎨 Css for borderRadius

* 🎨 Setup responsiveRadius utility

* ♻️ Forenklet borderRadius

* 🎨 refactor padding in box

* 🔥 Fjernet unødvendig kode

* 🎨 Oppdatert token for borderWidth

* 🐛 Default 0px border

* 🏷️ Refactor types

* 🐛 Fikset stories

* ♻️ refactor away one of the getResponsiveProps(), renaming

* ♻️ refactor + add token exceptions

* 🐛 new props based on BoxProps

* 📝 Oppdatert box-eksempler

* 📝 border-eksempler

* 📝 shadow-eksempel

* 📝 header demo

* 🔥 Fjernet theming demo, la til panel-demo

* 🚚 Flyttet show/hide inn i primitives

* 🚚 extract stateful colors to separate files

* 🚚 move shadow stateful tokens as well

* ♻️ rename some Box types

* 🚚 re-add missing token

* 🚚 move types file to utils, (bonus: fix some jsdoc)

* ➕ add @navikt/ds-tokens to react

* Update .changeset/happy-pianos-cheat.md

---------

Co-authored-by: Ken <ken.aleksander@gmail.com>
Co-authored-by: Lars Hansen <lars.eirik.korsgaard.hansen@nav.no>
Co-authored-by: Ken <26967723+KenAJoh@users.noreply.github.com>
2023-09-13 11:25:35 +02:00
github-actions[bot]andgithub-actions[bot] f5f859f845 Version Packages (#2271)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-09-11 21:41:26 +02:00
Ken 2eaf531cfe 🐛 Fikset kalkulering av fromDate/toDate (#2269) 2023-09-11 21:38:36 +02:00
Halvor Haugan a9a17ce050 📝 Fjern desc på default eksempel på GuidePanel (#2267) 2023-09-11 13:06:59 +02:00
Trong Huu Nguyen c5644da130 chore: update fakedings url (#2268) 2023-09-11 12:58:32 +02:00
Julian NymarkandKen 3af95c4c1f Bump node and TS versions (#2249)
* 🚧 update all node-version to 19

* 💥 bump node-version to 20

* bump ts version (make them all equal)

* fix new type error that surfaced when upgrading TS

* ⬆️ bump ts-node

* 🚧 add ts-jest to aksel-stylelint (just a test)

---------

Co-authored-by: Ken <26967723+KenAJoh@users.noreply.github.com>
2023-09-11 09:58:13 +02:00
Ken d1bd13f4d1 🐛 stories for aksel.nav.no indekserte ikke riktig 2023-09-08 14:49:55 +02:00
Ken 9f048877e4 🐛 Fikset sanity min title-felt 2023-09-07 18:47:03 +02:00
Ken 39b2ef49b2 📝 Bedre visning for typo-eksempler 2023-09-07 15:02:16 +02:00
Ken ccf3f30ab4 🐛 Fikset eksempler for show/hide 2023-09-07 14:54:43 +02:00
Ken 3592f04eab 🐛 Fikset parsing av kodesnippet 2023-09-07 14:42:02 +02:00
github-actions[bot]andgithub-actions[bot] fbc598529c Version Packages (#2262)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-09-07 14:24:26 +02:00
Ken 1df8dcd857 🎨 Oppdatert prismjs og codeview (#2251) 2023-09-07 14:02:10 +02:00
Ken 7be9dd88ca Responsive Show/Hide-komponenter (#2222) 2023-09-07 12:47:49 +02:00
Ken 4d9691413a 🐛 Fikset lightmode-theming (#2238) 2023-09-07 12:45:31 +02:00
Ken 2989853f39 ♻️ Oppdatert Search escape håndtering (#2245) 2023-09-07 12:41:45 +02:00
Ken bff7c836f8 🎨 ErrorSummary border-radius (#2256) 2023-09-07 12:41:21 +02:00
github-actions[bot]andgithub-actions[bot] b906ca469d Version Packages (#2259)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-09-07 10:42:56 +02:00
Halvor Haugan ed9286f75b 🐛 Popover: sjekk at det er et HTML-element som får fokus (#2258) 2023-09-07 10:39:03 +02:00
github-actions[bot]andgithub-actions[bot] 445f6b8309 Version Packages (#2252)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-09-07 09:10:15 +02:00
Ken 27dacfdbe9 🐛 Fikset SVG import path (#2250) 2023-09-06 20:12:49 +02:00
Ken b8b7ad142d 🎨 Synket alert med figma (#2240) 2023-09-06 15:59:31 +02:00
github-actions[bot]andgithub-actions[bot] 29b244e69b Version Packages (#2248)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-09-06 15:07:20 +02:00
KenandLars Eirik Korsgaard Hansen 6f2325bbb3 🎨 HGrid align-prop (#2242)
Co-authored-by: Lars Eirik Korsgaard Hansen <71271458+larseirikhansen@users.noreply.github.com>
2023-09-06 15:04:26 +02:00
github-actions[bot]andgithub-actions[bot] 9f575b76b8 Version Packages (#2246)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-09-06 11:11:51 +02:00
Ken 4e05993427 🎨 Skeleton as-prop (#2239) 2023-09-06 11:03:28 +02:00
Halvor Haugan 85a7521197 🐛 fiks createPackageJsonsWithESMPointers i Windows (#2237) 2023-09-05 12:35:31 +02:00
Halvor HauganandKen f635be70d0 🏷️ Forbedret typesjekking i stories (#2234)
Co-authored-by: Ken <26967723+KenAJoh@users.noreply.github.com>
2023-09-04 17:06:34 +02:00
Ken b675a5b9ba 🛂 Permissions for chromatic-workflow (#2235) 2023-09-04 17:04:11 +02:00
Ken cc842113c3 ✨ Primitives-kategori 2023-09-04 12:09:35 +02:00
Ken f36d4c46d7 🐛 Fikset Typo-eksempler, dupliserte prop-entries 2023-09-03 14:22:40 +02:00
Ken d7bd84f6ee ⬆️ Oppdatert sanity (#2228) 2023-09-03 13:18:38 +02:00
github-actions[bot]andgithub-actions[bot] c33702bf08 Version Packages (#2230)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-09-03 12:39:10 +02:00
Ken 57efe4b8ae 🛂 CI-action har nå write-access på PR 2023-09-03 12:28:37 +02:00
Halvor Haugan b0da33c366 🐛 DatePicker: Riktig skriftstørrelse på small input (#2232) 2023-09-01 14:36:32 +02:00
Sebastian Oliver Søberg c67e051bdc Fix month comparison, dont respect day of month when comparing months (#2231) 2023-09-01 14:21:23 +02:00
Halvor Haugan 960a08247c 💄 GuidePanel: justert design (#2227) 2023-09-01 12:43:07 +02:00
dependabot[bot] b1a1a896d5 ⬆️ Bump @adobe/css-tools from 4.2.0 to 4.3.1 (#2226)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-01 12:22:57 +02:00
Julian Nymark 596b94ffae 🐛 move internal token definition to a larger scope (#2229)
* 🐛 move internal token definition to a larger scope

when the scope only covered the __header, the __item could
not use the same token, and it was undefined. Setting this on
a shared parent (the topmost accordion) fixes this.

* changeset
2023-08-31 16:14:53 +02:00
github-actions[bot]andgithub-actions[bot] 273a0cd78f Version Packages (#2225)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-08-31 13:38:42 +02:00
Halvor Haugan 9ab920a288 ♿ Textarea: Skjermleser-spesifikk tekst leses opp sammenhengende (#2216) 2023-08-29 10:20:20 +02:00
Ken 03cdeff3a0 🎨 Oppdatert Typo-komponenter (#2211) 2023-08-28 18:38:11 +02:00
274 changed files with 7437 additions and 2793 deletions

No files matched your search

+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
steps:
- uses: actions/setup-node@v3
with:
node-version: "16"
node-version: "20"
- uses: actions/checkout@v3
- name: add tokens to .env
run: |
+2 -2
View File
@@ -16,7 +16,7 @@ jobs:
steps:
- uses: actions/setup-node@v3
with:
node-version: "16"
node-version: "20"
- uses: actions/checkout@v3
- name: add tokens to .env
run: |
@@ -51,7 +51,7 @@ jobs:
steps:
- uses: actions/setup-node@v3
with:
node-version: "16"
node-version: "20"
- uses: actions/checkout@v3
- name: add tokens to .env
run: |
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
steps:
- uses: actions/setup-node@v3
with:
node-version: "16"
node-version: "20"
- uses: actions/checkout@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # Use commit-sha1 instead of tag for security concerns
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
fetch-depth: 0 # Required to retrieve git history
- uses: actions/setup-node@v3
with:
node-version: 14
node-version: "20"
- name: Restore cache
uses: actions/cache@v3
+9 -5
View File
@@ -15,6 +15,10 @@ jobs:
visual_regression_test:
name: "visual regression test (chromatic)"
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
contents: write
steps:
- uses: actions/checkout@v3
with:
@@ -22,7 +26,7 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: 16.13.0
node-version: "20"
cache: yarn
- name: Restore cache
@@ -54,7 +58,7 @@ jobs:
- name: replace storybook url
if: "!contains(github.event.head_commit.message, '[ci skip]') && github.event_name != 'push'"
uses: frabert/replace-string-action@v2.0
uses: frabert/replace-string-action@v2
id: storybook_url
with:
pattern: "(iframe.html)"
@@ -70,7 +74,7 @@ jobs:
- name: Find Comment
if: "!contains(github.event.head_commit.message, '[ci skip]') && github.event_name != 'push'"
uses: peter-evans/find-comment@v1
uses: peter-evans/find-comment@v2
id: fc
with:
issue-number: ${{ github.event.pull_request.number }}
@@ -79,7 +83,7 @@ jobs:
- name: Create or update comment
if: steps.chromatic_tests.outcome == 'success' && !contains(github.event.head_commit.message, '[ci skip]') && github.event_name != 'push'
uses: peter-evans/create-or-update-comment@v1
uses: peter-evans/create-or-update-comment@v3
with:
comment-id: ${{ steps.fc.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
@@ -91,7 +95,7 @@ jobs:
- name: Create or update failed comment
if: steps.chromatic_tests.outcome != 'success' && !contains(github.event.head_commit.message, '[ci skip]') && github.event_name != 'push'
uses: peter-evans/create-or-update-comment@v1
uses: peter-evans/create-or-update-comment@v3
with:
comment-id: ${{ steps.fc.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
+3 -1
View File
@@ -13,6 +13,8 @@ jobs:
name: "Validate build"
if: "!contains(github.event.head_commit.message, '[ci skip]')"
runs-on: ubuntu-latest
permissions:
pull-requests: "write"
steps:
- uses: actions/checkout@v3
with:
@@ -20,7 +22,7 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: 16.13.0
node-version: "20"
cache: yarn
- name: Restore cache
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
node-version: "20"
- name: add tokens to .env
run: |
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: 16.13.0
node-version: "20"
cache: yarn
- uses: denoland/setup-deno@v1
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
steps:
- uses: actions/setup-node@v3
with:
node-version: "16"
node-version: "20"
- uses: actions/checkout@v3
- name: add tokens to .env
run: |
+22
View File
@@ -1,5 +1,27 @@
# @navikt/aksel-icons
## 5.5.0
## 5.4.1
## 5.4.0
## 5.3.5
## 5.3.4
### Patch Changes
- :bug: SVG import map er nå riktig path ([#2250](https://github.com/navikt/aksel/pull/2250))
## 5.3.3
## 5.3.2
## 5.3.1
## 5.3.0
## 5.2.1
## 5.2.0
@@ -27,7 +27,7 @@
"@vitejs/plugin-react": "^3.1.0",
"postcss": "^8.4.0",
"postcss-url": "^10.1.3",
"typescript": "^4.8.0",
"typescript": "^5.1.6",
"vite": "^4.2.0",
"vite-plugin-singlefile": "^0.13.3",
"vite-plugin-svgr": "^2.4.0"
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/aksel-icons",
"version": "5.2.1",
"version": "5.5.0",
"author": "Aksel | NAV",
"homepage": "https://aksel.nav.no/ikoner",
"repository": {
@@ -33,7 +33,7 @@
"import": "./dist/react/esm/index.js",
"require": "./dist/react/cjs/index.js"
},
"./svg/*.svg": "./dist/react/svg/*.svg",
"./svg/*.svg": "./dist/svg/*.svg",
"./metadata": {
"types": "./dist/metadata.d.ts",
"default": "./dist/metadata.js"
@@ -76,7 +76,7 @@
"lodash.startcase": "4.4.0",
"react": "^18.0.0",
"rehype-parse": "8.0.4",
"typescript": "^4.8.0",
"typescript": "^5.1.6",
"unified": "10.1.2"
},
"jest": {
+1 -1
View File
@@ -1,5 +1,5 @@
{
"extends": "../../tsconfig.json",
"extends": "../../tsconfig.build.json",
"compilerOptions": {
"outDir": "./dist/react/cjs",
"module": "commonjs",
+18
View File
@@ -1,5 +1,23 @@
# @navikt/aksel-stylelint
## 5.5.0
## 5.4.1
## 5.4.0
## 5.3.5
## 5.3.4
## 5.3.3
## 5.3.2
## 5.3.1
## 5.3.0
## 5.2.1
## 5.2.0
+5 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/aksel-stylelint",
"version": "5.2.1",
"version": "5.5.0",
"author": "Aksel | NAV",
"homepage": "https://aksel.nav.no/grunnleggende/kode/stylelint",
"repository": {
@@ -35,8 +35,8 @@
"dev": "yarn watch:lint"
},
"devDependencies": {
"@navikt/ds-css": "^5.2.1",
"@navikt/ds-tokens": "^5.2.1",
"@navikt/ds-css": "^5.5.0",
"@navikt/ds-tokens": "^5.5.0",
"@types/jest": "^29.0.0",
"concurrently": "7.2.1",
"copyfiles": "2.4.1",
@@ -45,7 +45,8 @@
"postcss-selector-parser": "^6.0.13",
"postcss-value-parser": "^4.2.0",
"stylelint": "^14.8.5",
"typescript": "^4.8.0"
"ts-jest": "^29.0.0",
"typescript": "^5.1.6"
},
"jest": {
"preset": "jest-preset-stylelint",
@@ -38,4 +38,16 @@ export const deprecations: DeprecatedList = [
classes: ["navds-modal__content"],
message: "Renamed to `.navds-modal__body` in v5.0.0",
},
{
classes: ["navds-guide__illustration"],
message: "Use `.navds-guide` instead",
},
{
classes: [
"navds-guide__illustration--small",
"navds-guide__illustration--medium",
],
message:
"There is no 1:1 replacement for this, the size will depend on the 'poster' prop and the viewport width",
},
];
+63
View File
@@ -1,5 +1,68 @@
# @navikt/aksel
## 5.5.0
### Patch Changes
- Updated dependencies [[`9f2052e1c`](https://github.com/navikt/aksel/commit/9f2052e1c2f31735896d082f3fece66b080a4f4e), [`83c9194a4`](https://github.com/navikt/aksel/commit/83c9194a480fd3d184f673815522f230ed5d77bb)]:
- @navikt/ds-css@5.5.0
## 5.4.1
### Patch Changes
- Updated dependencies []:
- @navikt/ds-css@5.4.1
## 5.4.0
### Patch Changes
- Updated dependencies [[`bff7c836f`](https://github.com/navikt/aksel/commit/bff7c836f8b0c604da1bfac49f60d6ae07d04624), [`7be9dd88c`](https://github.com/navikt/aksel/commit/7be9dd88ca8751aa03ddb9f40c21990b6d81a26a)]:
- @navikt/ds-css@5.4.0
## 5.3.5
### Patch Changes
- Updated dependencies []:
- @navikt/ds-css@5.3.5
## 5.3.4
### Patch Changes
- Updated dependencies [[`b8b7ad142`](https://github.com/navikt/aksel/commit/b8b7ad142dfb8a202c4adb115e3d2491ce917205)]:
- @navikt/ds-css@5.3.4
## 5.3.3
### Patch Changes
- Updated dependencies [[`6f2325bbb`](https://github.com/navikt/aksel/commit/6f2325bbb32de87d649a476a8c58e5f352e1d016)]:
- @navikt/ds-css@5.3.3
## 5.3.2
### Patch Changes
- Updated dependencies [[`4e0599342`](https://github.com/navikt/aksel/commit/4e0599342761f2a0fe2177c370f4bcf4fab7ef8a)]:
- @navikt/ds-css@5.3.2
## 5.3.1
### Patch Changes
- Updated dependencies [[`596b94ffa`](https://github.com/navikt/aksel/commit/596b94ffaedf05b3ce96917c0d4203569f3c8cf0), [`960a08247`](https://github.com/navikt/aksel/commit/960a08247cf3370eca76febeb18c8bfe9ba3bff5)]:
- @navikt/ds-css@5.3.1
## 5.3.0
### Patch Changes
- Updated dependencies [[`03cdeff3a`](https://github.com/navikt/aksel/commit/03cdeff3a0053e91c45204df92168ae0e824d31c)]:
- @navikt/ds-css@5.3.0
## 5.2.1
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/aksel",
"version": "5.2.1",
"version": "5.5.0",
"description": "Aksel command line interface. Handles css-imports, codemods and more",
"author": "Aksel | NAV designsystem team",
"license": "MIT",
@@ -29,7 +29,7 @@
},
"homepage": "https://aksel.nav.no/grunnleggende/kode/kommandolinje",
"dependencies": {
"@navikt/ds-css": "5.2.1",
"@navikt/ds-css": "5.5.0",
"axios": "1.3.6",
"chalk": "4.1.0",
"clipboardy": "^2.3.0",
@@ -49,7 +49,7 @@
"jest": "^29.0.0",
"rimraf": "3.0.2",
"ts-jest": "^29.0.0",
"typescript": "^4.8.0"
"typescript": "^5.1.6"
},
"sideEffects": false,
"engines": {
@@ -7,6 +7,7 @@ import {
componentDir,
rootDir,
globalDir,
primitivesCss,
} from "@navikt/ds-css/config/_mappings";
import { inquiry } from "./inquiry";
import clipboard from "clipboardy";
@@ -143,6 +144,13 @@ function advancedOutput(
componentImportsList.unshift(formCss);
}
if (componentImportsList.find((x) => x === primitivesCss)) {
componentImportsList = componentImportsList.filter(
(x) => x !== primitivesCss
);
componentImportsList.unshift(primitivesCss);
}
if (componentImportsList.find((x) => x === typoCss)) {
componentImportsList = componentImportsList.filter((x) => x !== typoCss);
componentImportsList.unshift(typoCss);
+56
View File
@@ -1,5 +1,61 @@
# @navikt/ds-css
## 5.5.0
### Minor Changes
- Box: Ny primitive, erstatter dagens `Panel` ([#2195](https://github.com/navikt/aksel/pull/2195))
### Patch Changes
- Skeleton: Width fungerer nå med inline-variant av Skeleton ([#2273](https://github.com/navikt/aksel/pull/2273))
## 5.4.1
## 5.4.0
### Minor Changes
- Primitives: Nye komponenter `Show` og `Hide` er lagt til. ([#2222](https://github.com/navikt/aksel/pull/2222))
### Patch Changes
- ErrorSummary: Har nå 8px border-radius ([#2256](https://github.com/navikt/aksel/pull/2256))
## 5.3.5
## 5.3.4
### Patch Changes
- Alert: 12px -> 8px gap mellom tekst og ikon ved `size="small"` ([#2240](https://github.com/navikt/aksel/pull/2240))
## 5.3.3
### Patch Changes
- HGrid: Har nå `align`-prop for bedre kontroll over child-elementer ([#2242](https://github.com/navikt/aksel/pull/2242))
## 5.3.2
### Patch Changes
- Skeleton: Lagt til as-prop for inline brk av Skeleton med span ([#2239](https://github.com/navikt/aksel/pull/2239))
## 5.3.1
### Patch Changes
- :bug: fix missing accordion bottom box-shadow on last element (when opened) ([#2229](https://github.com/navikt/aksel/pull/2229))
- :lipstick: GuidePanel: justert design ([#2227](https://github.com/navikt/aksel/pull/2227))
## 5.3.0
### Minor Changes
- Typography: Oppdatert med typo-klasser for `textColor`, `weight`, `align`, `visuallyHidden` og `truncated`. ([#2211](https://github.com/navikt/aksel/pull/2211))
## 5.2.1
### Patch Changes
+4 -1
View File
@@ -1,3 +1,7 @@
.navds-accordion {
--__ac-accordion-header-shadow-color: var(--ac-accordion-header-border, var(--a-border-divider));
}
.navds-accordion__item:focus-within {
position: relative;
}
@@ -6,7 +10,6 @@
* Header *
*************************/
.navds-accordion__header {
--__ac-accordion-header-shadow-color: var(--ac-accordion-header-border, var(--a-border-divider));
--__ac-accordion-header-shadow: inset 2px 0 0 0 var(--a-transparent), inset -2px 0 0 0 var(--a-transparent),
inset 0 2px 0 0 var(--__ac-accordion-header-shadow-color);
+16 -6
View File
@@ -11,8 +11,17 @@
max-width: 43.5rem;
}
.navds-alert--close-button > .navds-alert__wrapper {
margin-block-start: var(--a-spacing-05);
}
.navds-alert--small.navds-alert--close-button > .navds-alert__wrapper {
margin-block-start: var(--a-spacing-1);
}
.navds-alert--small {
padding: var(--a-spacing-2) var(--a-spacing-4);
gap: var(--a-spacing-2);
}
.navds-alert--full-width {
@@ -24,19 +33,20 @@
font-size: 1.5rem;
align-self: flex-start;
height: var(--a-font-line-height-xlarge);
margin-inline: var(--a-spacing-1);
margin-block: 0;
margin-block-start: -1px;
background: radial-gradient(circle, var(--a-surface-default) 50%, 0, transparent);
}
.navds-alert--close-button > .navds-alert__icon,
.navds-alert--small > .navds-alert__icon {
margin-block-start: 0;
height: var(--a-font-line-height-large);
}
.navds-alert--small > .navds-alert__icon {
height: var(--a-font-line-height-large);
.navds-alert--close-button > .navds-alert__icon {
margin-block-start: var(--a-spacing-05);
}
.navds-alert--small.navds-alert--close-button > .navds-alert__icon {
margin-block-start: var(--a-spacing-1);
}
.navds-alert--error {
+2
View File
@@ -28,6 +28,7 @@
.navds-sr-only {
border: 0;
clip: rect(0, 0, 0, 0);
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
@@ -50,6 +51,7 @@
.navds-sr-only.focusable:active,
.navds-sr-only.focusable:focus {
clip: auto;
clip-path: none;
height: auto;
margin: 0;
overflow: visible;
+66 -34
View File
@@ -1,18 +1,35 @@
[data-theme="dark"] {
--ac-button-primary-text: var(--a-gray-900);
--ac-button-primary-bg: var(--a-blue-200);
--ac-button-primary-focus-border: var(--a-gray-900);
--ac-button-primary-hover-bg: var(--a-blue-300);
--ac-button-primary-active-bg: var(--a-blue-400);
--ac-button-secondary-text: var(--a-white);
--ac-button-secondary-hover-text: var(--a-white);
--ac-button-secondary-active-text: var(--a-white);
--ac-button-secondary-active-focus-border: var(--a-gray-900);
--ac-button-secondary-bg: var(--a-gray-900);
--ac-button-secondary-border: var(--a-blue-200);
--ac-button-secondary-hover-bg: var(--a-gray-800);
--ac-button-secondary-focus-border: var(--a-blue-200);
--ac-button-secondary-active-bg: var(--a-gray-700);
--__ac-button-primary-text: var(--a-gray-900);
--__ac-button-primary-bg: var(--a-blue-200);
--__ac-button-primary-focus-border: var(--a-gray-900);
--__ac-button-primary-hover-bg: var(--a-blue-300);
--__ac-button-primary-active-bg: var(--a-blue-400);
--__ac-button-secondary-text: var(--a-white);
--__ac-button-secondary-hover-text: var(--a-white);
--__ac-button-secondary-active-text: var(--a-white);
--__ac-button-secondary-active-focus-border: var(--a-gray-900);
--__ac-button-secondary-bg: var(--a-gray-900);
--__ac-button-secondary-border: var(--a-blue-200);
--__ac-button-secondary-hover-bg: var(--a-gray-800);
--__ac-button-secondary-focus-border: var(--a-blue-200);
--__ac-button-secondary-active-bg: var(--a-gray-700);
}
[data-theme="light"] {
--__ac-button-primary-text: initial;
--__ac-button-primary-bg: initial;
--__ac-button-primary-focus-border: initial;
--__ac-button-primary-hover-bg: initial;
--__ac-button-primary-active-bg: initial;
--__ac-button-secondary-text: initial;
--__ac-button-secondary-hover-text: initial;
--__ac-button-secondary-active-text: initial;
--__ac-button-secondary-active-focus-border: initial;
--__ac-button-secondary-bg: initial;
--__ac-button-secondary-border: initial;
--__ac-button-secondary-hover-bg: initial;
--__ac-button-secondary-focus-border: initial;
--__ac-button-secondary-active-bg: initial;
}
.navds-button {
@@ -109,25 +126,29 @@
*************************/
.navds-button--primary {
background-color: var(--ac-button-primary-bg, var(--a-surface-action));
color: var(--ac-button-primary-text, var(--a-text-on-action));
background-color: var(--ac-button-primary-bg, var(--__ac-button-primary-bg, var(--a-surface-action)));
color: var(--ac-button-primary-text, var(--__ac-button-primary-text, var(--a-text-on-action)));
}
.navds-button--primary:hover {
background-color: var(--ac-button-primary-hover-bg, var(--a-surface-action-hover));
background-color: var(--ac-button-primary-hover-bg, var(--__ac-button-primary-hover-bg, var(--a-surface-action-hover)));
}
.navds-button--primary:active {
background-color: var(--ac-button-primary-active-bg, var(--a-surface-action-active));
background-color: var(--ac-button-primary-active-bg, var(--__ac-button-primary-active-bg, var(--a-surface-action-active)));
}
.navds-button--primary:focus-visible {
box-shadow: inset 0 0 0 1px var(--ac-button-primary-focus-border, var(--a-surface-default)), var(--a-shadow-focus);
box-shadow: inset 0 0 0 1px
var(--ac-button-primary-focus-border, var(--__ac-button-primary-focus-border, var(--a-surface-default))),
var(--a-shadow-focus);
}
@supports not selector(:focus-visible) {
.navds-button--primary:focus {
box-shadow: inset 0 0 0 1px var(--ac-button-primary-focus-border, var(--a-surface-default)), var(--a-shadow-focus);
box-shadow: inset 0 0 0 1px
var(--ac-button-primary-focus-border, var(--__ac-button-primary-focus-border, var(--a-surface-default))),
var(--a-shadow-focus);
}
}
@@ -173,47 +194,58 @@
**************************/
.navds-button--secondary {
color: var(--ac-button-secondary-text, var(--a-text-action));
background-color: var(--ac-button-secondary-bg, var(--a-surface-transparent));
box-shadow: inset 0 0 0 2px var(--ac-button-secondary-border, var(--a-border-action));
color: var(--ac-button-secondary-text, var(--__ac-button-secondary-text, var(--a-text-action)));
background-color: var(--ac-button-secondary-bg, var(--__ac-button-secondary-bg, var(--a-surface-transparent)));
box-shadow: inset 0 0 0 2px var(--ac-button-secondary-border, var(--__ac-button-secondary-border, var(--a-border-action)));
}
.navds-button--secondary:hover {
color: var(--ac-button-secondary-hover-text, var(--a-text-action-on-action-subtle));
background-color: var(--ac-button-secondary-hover-bg, var(--a-surface-action-subtle-hover));
color: var(--ac-button-secondary-hover-text, var(--__ac-button-secondary-hover-text, var(--a-text-action-on-action-subtle)));
background-color: var(
--ac-button-secondary-hover-bg,
var(--__ac-button-secondary-hover-bg, var(--a-surface-action-subtle-hover))
);
}
.navds-button--secondary:focus-visible {
box-shadow: inset 0 0 0 2px var(--ac-button-secondary-focus-border, var(--a-border-action)), var(--a-shadow-focus);
box-shadow: inset 0 0 0 2px
var(--ac-button-secondary-focus-border, var(--__ac-button-secondary-focus-border, var(--a-border-action))),
var(--a-shadow-focus);
}
@supports not selector(:focus-visible) {
.navds-button--secondary:focus {
box-shadow: inset 0 0 0 2px var(--ac-button-secondary-focus-border, var(--a-border-action)), var(--a-shadow-focus);
box-shadow: inset 0 0 0 2px
var(--ac-button-secondary-focus-border, var(--__ac-button-secondary-focus-border, var(--a-border-action))),
var(--a-shadow-focus);
}
}
.navds-button--secondary:active {
color: var(--ac-button-secondary-active-text, var(--a-text-on-action));
background-color: var(--ac-button-secondary-active-bg, var(--a-surface-action-active));
color: var(--ac-button-secondary-active-text, var(--__ac-button-secondary-active-text, var(--a-text-on-action)));
background-color: var(--ac-button-secondary-active-bg, var(--__ac-button-secondary-active-bg, var(--a-surface-action-active)));
box-shadow: none;
}
.navds-button--secondary:focus-visible:active {
box-shadow: inset 0 0 0 1px var(--ac-button-secondary-active-focus-border, var(--a-surface-default)), var(--a-shadow-focus);
box-shadow: inset 0 0 0 1px
var(--ac-button-secondary-active-focus-border, var(--__ac-button-secondary-active-focus-border, var(--a-surface-default))),
var(--a-shadow-focus);
}
@supports not selector(:focus-visible) {
.navds-button--secondary:focus:active {
box-shadow: inset 0 0 0 1px var(--ac-button-secondary-active-focus-border, var(--a-surface-default)), var(--a-shadow-focus);
box-shadow: inset 0 0 0 1px
var(--ac-button-secondary-active-focus-border, var(--__ac-button-secondary-active-focus-border, var(--a-surface-default))),
var(--a-shadow-focus);
}
}
.navds-button--secondary:where(:disabled, .navds-button--disabled),
.navds-button--secondary:hover:where(:disabled, .navds-button--disabled) {
color: var(--ac-button-secondary-text, var(--a-text-action));
background-color: var(--ac-button-secondary-bg, var(--a-surface-transparent));
box-shadow: inset 0 0 0 2px var(--ac-button-secondary-border, var(--a-border-action));
color: var(--ac-button-secondary-text, var(--__ac-button-secondary-text, var(--a-text-action)));
background-color: var(--ac-button-secondary-bg, var(--__ac-button-secondary-bg, var(--a-surface-transparent)));
box-shadow: inset 0 0 0 2px var(--ac-button-secondary-border, var(--__ac-button-secondary-border, var(--a-border-action)));
}
/**************************
+1
View File
@@ -3,6 +3,7 @@ export declare const globalDir = "dist/global";
export declare const componentDir = "dist/component";
export declare const typoCss = "typography.css";
export declare const formCss = "form.css";
export declare const primitivesCss = "primitives.css";
export declare const componentsCss = "components.css";
export declare const StyleMappings: {
baseline: {
+30 -16
View File
@@ -4,6 +4,7 @@ const componentDir = "dist/component";
const typoCss = "typography.css";
const formCss = "form.css";
const primitivesCss = "primitives.css";
const componentsCss = "components.css";
const StyleMappings = {
@@ -30,6 +31,34 @@ const StyleMappings = {
},
],
components: [
{
component: "Box",
main: primitivesCss,
},
{
component: "HGrid",
main: primitivesCss,
},
{
component: "HStack",
main: primitivesCss,
},
{
component: "VStack",
main: primitivesCss,
},
{
component: "Spacer",
main: primitivesCss,
},
{
component: "Show",
main: primitivesCss,
},
{
component: "Hide",
main: primitivesCss,
},
{
component: "Accordion",
main: "accordion.css",
@@ -99,10 +128,6 @@ const StyleMappings = {
main: "help-text.css",
dependencies: ["popover.css"],
},
{
component: "HGrid",
main: "hgrid.css",
},
{ component: "Ingress", main: typoCss },
{
component: "InternalHeader",
@@ -138,18 +163,6 @@ const StyleMappings = {
{ component: "Select", main: formCss, dependencies: [typoCss] },
{ component: "Skeleton", main: "skeleton.css", dependencies: [] },
{ component: "Stepper", main: "stepper.css", dependencies: [typoCss] },
{
component: "HStack",
main: "stack.css",
},
{
component: "VStack",
main: "stack.css",
},
{
component: "Spacer",
main: "stack.css",
},
{ component: "Switch", main: formCss, dependencies: [typoCss] },
{ component: "Table", main: "table.css", dependencies: [typoCss] },
{ component: "Tabs", main: "tabs.css", dependencies: [typoCss] },
@@ -184,6 +197,7 @@ module.exports = {
StyleMappings,
typoCss,
formCss,
primitivesCss,
componentsCss,
rootDir,
globalDir,
+6
View File
@@ -16,6 +16,7 @@ const {
rootDir,
globalDir,
componentDir,
primitivesCss,
} = require("./_mappings.js");
run();
@@ -123,6 +124,11 @@ function buildFragmentFiles() {
output: `${componentDir}/${formCss}`,
});
files.push({
input: "primitives/index.css",
output: `${componentDir}/${primitivesCss}`,
});
return files;
}
+24 -17
View File
@@ -1,10 +1,17 @@
[data-theme="dark"] .navds-copybutton,
[data-theme="dark"].navds-copybutton {
--a-text-action: var(--a-blue-300);
--a-surface-hover: rgb(214 231 255 /0.13);
--a-icon-success: rgb(51 170 95 /1);
--a-text-subtle: rgb(231 240 254 /0.69);
--a-text-default: rgb(251 252 254 /0.96);
[data-theme="dark"] {
--__ac-copybutton-action-text: var(--a-blue-300);
--__ac-copybutton-bg-hover: rgb(214 231 255 /0.13);
--__ac-copybutton-icon-success: rgb(51 170 95 /1);
--__ac-copybutton-neutral-text: rgb(231 240 254 /0.69);
--__ac-copybutton-text: rgb(251 252 254 /0.96);
}
[data-theme="light"] {
--__ac-copybutton-action-text: initial;
--__ac-copybutton-bg-hover: initial;
--__ac-copybutton-icon-success: initial;
--__ac-copybutton-neutral-text: initial;
--__ac-copybutton-text: initial;
}
.navds-copybutton {
@@ -84,46 +91,46 @@
/* Variant/action */
.navds-copybutton--action {
color: var(--ac-copybutton-action-text, var(--a-text-action));
color: var(--ac-copybutton-action-text, var(--__ac-copybutton-action-text, var(--a-text-action)));
background-color: var(--ac-copybutton-action-bg, var(--a-surface-transparent));
}
.navds-copybutton--action:hover {
color: var(--ac-copybutton-action-hover-text, var(--a-text-action));
background-color: var(--ac-copybutton-action-hover-bg, var(--a-surface-hover));
color: var(--ac-copybutton-action-hover-text, var(--__ac-copybutton-action-text, var(--a-text-action)));
background-color: var(--ac-copybutton-action-hover-bg, var(--__ac-copybutton-bg-hover, var(--a-surface-hover)));
}
.navds-copybutton--action:where(:disabled),
.navds-copybutton--action:hover:where(:disabled) {
color: var(--ac-copybutton-action-text, var(--a-text-action));
color: var(--ac-copybutton-action-text, var(--__ac-copybutton-action-text, var(--a-text-action)));
background-color: var(--ac-copybutton-action-bg, var(--a-surface-transparent));
box-shadow: none;
}
.navds-copybutton--active.navds-copybutton--action {
color: var(--ac-copybutton-action-active-text, var(--a-icon-success));
color: var(--ac-copybutton-action-active-text, var(--__ac-copybutton-icon-success, var(--a-icon-success)));
}
/* Variant/neutral */
.navds-copybutton--neutral {
color: var(--ac-copybutton-neutral-text, var(--a-text-subtle));
color: var(--ac-copybutton-neutral-text, var(--__ac-copybutton-neutral-text, var(--a-text-subtle)));
background-color: var(--ac-copybutton-neutral-bg, var(--a-surface-transparent));
}
.navds-copybutton--neutral:hover {
color: var(--ac-copybutton-neutral-hover-text, var(--a-text-default));
background-color: var(--ac-copybutton-neutral-hover-bg, var(--a-surface-hover));
color: var(--ac-copybutton-neutral-hover-text, var(--__ac-copybutton-text, var(--a-text-default)));
background-color: var(--ac-copybutton-neutral-hover-bg, var(--__ac-copybutton-bg-hover, var(--a-surface-hover)));
}
.navds-copybutton--neutral:where(:disabled, .navds-copybutton--disabled),
.navds-copybutton--neutral:hover:where(:disabled, .navds-copybutton--disabled) {
color: var(--ac-copybutton-neutral-text, var(--a-text-default));
color: var(--ac-copybutton-neutral-text, var(--__ac-copybutton-text, var(--a-text-default)));
background-color: var(--ac-copybutton-neutral-bg, var(--a-surface-transparent));
box-shadow: none;
}
.navds-copybutton--active.navds-copybutton--neutral {
color: var(--ac-copybutton-neutral-active-text, var(--a-text-default));
color: var(--ac-copybutton-neutral-active-text, var(--__ac-copybutton-text, var(--a-text-default)));
}
.navds-copybutton__content {
+1
View File
@@ -2,6 +2,7 @@
background-color: var(--ac-error-summary-bg, var(--a-surface-default));
padding: var(--a-spacing-5);
border: 4px solid var(--ac-error-summary-border, var(--a-border-danger));
border-radius: var(--a-border-radius-large);
}
.navds-error-summary--small {
+6 -2
View File
@@ -1,5 +1,9 @@
[data-theme="dark"] {
--ac-form-description: var(--a-text-on-inverted);
--__ac-form-description: var(--a-text-on-inverted);
}
[data-theme="light"] {
--__ac-form-description: initial;
}
.navds-fieldset {
@@ -14,7 +18,7 @@
}
.navds-fieldset__description {
color: var(--ac-form-description, var(--a-text-subtle));
color: var(--ac-form-description, var(--__ac-form-description, var(--a-text-subtle)));
}
.navds-fieldset > .navds-fieldset__description:not(:empty) {
+6 -2
View File
@@ -1,5 +1,9 @@
[data-theme="dark"] {
--ac-form-description: var(--a-text-on-inverted);
--__ac-form-description: var(--a-text-on-inverted);
}
[data-theme="light"] {
--__ac-form-description: initial;
}
.navds-form-field {
@@ -10,7 +14,7 @@
.navds-form-field__description {
margin-top: -0.375rem;
color: var(--ac-form-description, var(--a-text-subtle));
color: var(--ac-form-description, var(--__ac-form-description, var(--a-text-subtle)));
}
.navds-form-field .navds-error-message,
+38 -22
View File
@@ -1,9 +1,17 @@
[data-theme="dark"] {
--ac-search-button-border: var(--a-border-on-inverted);
--ac-search-button-border-hover: var(--a-blue-200);
--ac-search-clear-icon: var(--a-white);
--ac-search-clear-icon-hover: var(--a-blue-200);
--ac-search-error-border: var(--a-red-300);
--__ac-search-button-border: var(--a-border-on-inverted);
--__ac-search-button-border-hover: var(--a-blue-200);
--__ac-search-clear-icon: var(--a-white);
--__ac-search-clear-icon-hover: var(--a-blue-200);
--__ac-search-error-border: var(--a-red-300);
}
[data-theme="light"] {
--__ac-search-button-border: initial;
--__ac-search-button-border-hover: initial;
--__ac-search-clear-icon: initial;
--__ac-search-clear-icon-hover: initial;
--__ac-search-error-border: initial;
}
.navds-search {
@@ -65,7 +73,7 @@
position: absolute;
right: 0.75rem;
border-radius: var(--a-border-radius-medium);
color: var(--ac-search-clear-icon, var(--a-text-default));
color: var(--ac-search-clear-icon, var(--__ac-search-clear-icon, var(--a-text-default)));
height: 32px;
width: 32px;
top: 50%;
@@ -87,7 +95,7 @@
}
.navds-search__button-clear:hover {
color: var(--ac-search-clear-icon-hover, var(--a-text-action));
color: var(--ac-search-clear-icon-hover, var(--__ac-search-clear-icon-hover, var(--a-text-action)));
}
.navds-search__button-clear:focus-visible {
@@ -120,16 +128,17 @@
}
.navds-search__button-search.navds-button--secondary {
box-shadow: -1px 0 0 0 var(--ac-search-button-border, var(--a-border-default)) inset,
0 1px 0 0 var(--ac-search-button-border, var(--a-border-default)) inset,
0 -1px 0 0 var(--ac-search-button-border, var(--a-border-default)) inset;
box-shadow: -1px 0 0 0 var(--ac-search-button-border, var(--__ac-search-button-border, var(--a-border-default))) inset,
0 1px 0 0 var(--ac-search-button-border, var(--__ac-search-button-border, var(--a-border-default))) inset,
0 -1px 0 0 var(--ac-search-button-border, var(--__ac-search-button-border, var(--a-border-default))) inset;
}
.navds-search__button-search.navds-button--secondary:hover {
box-shadow: -1px 0 0 0 var(--ac-search-button-border-hover, var(--a-border-action)) inset,
0 1px 0 0 var(--ac-search-button-border-hover, var(--a-border-action)) inset,
0 -1px 0 0 var(--ac-search-button-border-hover, var(--a-border-action)) inset,
-1px 0 0 0 var(--ac-search-button-border-hover, var(--a-border-action));
box-shadow: -1px 0 0 0 var(--ac-search-button-border-hover, var(--__ac-search-button-border-hover, var(--a-border-action)))
inset,
0 1px 0 0 var(--ac-search-button-border-hover, var(--__ac-search-button-border-hover, var(--a-border-action))) inset,
0 -1px 0 0 var(--ac-search-button-border-hover, var(--__ac-search-button-border-hover, var(--a-border-action))) inset,
-1px 0 0 0 var(--ac-search-button-border-hover, var(--__ac-search-button-border-hover, var(--a-border-action)));
z-index: 1;
}
@@ -138,11 +147,13 @@
}
.navds-search__button-search.navds-button--secondary:focus-visible {
box-shadow: 0 0 0 1px var(--ac-search-button-border, var(--a-border-default)) inset, var(--a-shadow-focus);
box-shadow: 0 0 0 1px var(--ac-search-button-border, var(--__ac-search-button-border, var(--a-border-default))) inset,
var(--a-shadow-focus);
}
.navds-search__button-search.navds-button--secondary:focus-visible:hover {
box-shadow: 0 0 0 1px var(--ac-search-button-border-hover, var(--a-border-action)) inset, var(--a-shadow-focus);
box-shadow: 0 0 0 1px var(--ac-search-button-border-hover, var(--__ac-search-button-border-hover, var(--a-border-action))) inset,
var(--a-shadow-focus);
}
.navds-search__button-search.navds-button--secondary:focus-visible:active {
@@ -151,11 +162,14 @@
@supports not selector(:focus-visible) {
.navds-search__button-search.navds-button--secondary:focus {
box-shadow: 0 0 0 1px var(--ac-search-button-border, var(--a-border-default)) inset, var(--a-shadow-focus);
box-shadow: 0 0 0 1px var(--ac-search-button-border, var(--__ac-search-button-border, var(--a-border-default))) inset,
var(--a-shadow-focus);
}
.navds-search__button-search.navds-button--secondary:focus:hover {
box-shadow: 0 0 0 1px var(--ac-search-button-border-hover, var(--a-border-action)) inset, var(--a-shadow-focus);
box-shadow: 0 0 0 1px var(--ac-search-button-border-hover, var(--__ac-search-button-border-hover, var(--a-border-action)))
inset,
var(--a-shadow-focus);
}
.navds-search__button-search.navds-button--secondary:focus:active {
@@ -165,12 +179,13 @@
/* Error-handling */
.navds-search--error .navds-search__input:not(:hover):not(:disabled) {
border-color: var(--ac-search-error-border, var(--a-border-danger));
box-shadow: inset 0 0 0 1px var(--ac-search-error-border, var(--a-border-danger));
border-color: var(--ac-search-error-border, var(--__ac-search-error-border, var(--a-border-danger)));
box-shadow: inset 0 0 0 1px var(--ac-search-error-border, var(--__ac-search-error-border, var(--a-border-danger)));
}
.navds-search--error .navds-search__input:focus-visible:not(:hover):not(:disabled) {
box-shadow: inset 0 0 0 1px var(--ac-search-error-border, var(--a-border-danger)), var(--a-shadow-focus);
box-shadow: inset 0 0 0 1px var(--ac-search-error-border, var(--__ac-search-error-border, var(--a-border-danger))),
var(--a-shadow-focus);
}
/* Focus layering */
@@ -182,7 +197,8 @@
@supports not selector(:focus-visible) {
.navds-search--error .navds-search__input:focus:not(:hover):not(:disabled) {
box-shadow: inset 0 0 0 1px var(--ac-search-error-border, var(--a-border-danger)), var(--a-shadow-focus);
box-shadow: inset 0 0 0 1px var(--ac-search-error-border, var(--__ac-search-error-border, var(--a-border-danger))),
var(--a-shadow-focus);
}
.navds-search__input:focus,
+24 -15
View File
@@ -1,21 +1,30 @@
[data-theme="dark"] {
--ac-textfield-text: var(--a-text-on-inverted);
--ac-textfield-bg: var(--a-surface-inverted);
--ac-textfield-border: var(--a-border-on-inverted);
--ac-textfield-hover-border: var(--a-blue-200);
--ac-textfield-placeholder: var(--a-gray-500);
--ac-textfield-error-border: var(--a-red-300);
--__ac-textfield-text: var(--a-text-on-inverted);
--__ac-textfield-bg: var(--a-surface-inverted);
--__ac-textfield-border: var(--a-border-on-inverted);
--__ac-textfield-hover-border: var(--a-blue-200);
--__ac-textfield-placeholder: var(--a-gray-500);
--__ac-textfield-error-border: var(--a-red-300);
}
[data-theme="light"] {
--__ac-textfield-text: initial;
--__ac-textfield-bg: initial;
--__ac-textfield-border: initial;
--__ac-textfield-hover-border: initial;
--__ac-textfield-placeholder: initial;
--__ac-textfield-error-border: initial;
}
.navds-text-field__input {
appearance: none;
padding: var(--a-spacing-2);
background-color: var(--ac-textfield-bg, var(--a-surface-default));
background-color: var(--ac-textfield-bg, var(--__ac-textfield-bg, var(--a-surface-default)));
border-radius: var(--a-border-radius-medium);
border: 1px solid var(--ac-textfield-border, var(--a-border-default));
border: 1px solid var(--ac-textfield-border, var(--__ac-textfield-border, var(--a-border-default)));
min-height: 3rem;
width: 100%;
color: var(--ac-textfield-text, var(--a-text-default));
color: var(--ac-textfield-text, var(--__ac-textfield-text, var(--a-text-default)));
}
.navds-text-field__input[size] {
@@ -23,7 +32,7 @@
}
.navds-text-field__input::placeholder {
color: var(--ac-textfield-placeholder, var(--a-text-subtle));
color: var(--ac-textfield-placeholder, var(--__ac-textfield-placeholder, var(--a-text-subtle)));
}
.navds-form-field--small .navds-text-field__input {
@@ -32,7 +41,7 @@
}
.navds-text-field__input:hover {
border-color: var(--ac-textfield-hover-border, var(--a-border-action));
border-color: var(--ac-textfield-hover-border, var(--__ac-textfield-hover-border, var(--a-border-action)));
}
.navds-text-field__input:focus-visible {
@@ -51,8 +60,8 @@
Error handling
*/
.navds-text-field--error > .navds-text-field__input:not(:hover):not(:disabled) {
border-color: var(--ac-textfield-error-border, var(--a-border-danger));
box-shadow: 0 0 0 1px var(--ac-textfield-error-border, var(--a-border-danger));
border-color: var(--ac-textfield-error-border, var(--__ac-textfield-error-border, var(--a-border-danger)));
box-shadow: 0 0 0 1px var(--ac-textfield-error-border, var(--__ac-textfield-error-border, var(--a-border-danger)));
}
.navds-text-field--error > .navds-text-field__input:focus-visible:not(:hover):not(:disabled) {
@@ -67,8 +76,8 @@
/* Disabled handling */
.navds-text-field__input:disabled {
background-color: var(--ac-textfield-bg, var(--a-surface-default));
border-color: var(--ac-textfield-border, var(--a-border-default));
background-color: var(--ac-textfield-bg, var(--__ac-textfield-bg, var(--a-surface-default)));
border-color: var(--ac-textfield-border, var(--__ac-textfield-border, var(--a-border-default)));
box-shadow: none;
cursor: not-allowed;
}
+32 -21
View File
@@ -1,12 +1,23 @@
[data-theme="dark"] {
--ac-textarea-text: var(--a-text-on-inverted);
--ac-textarea-bg: var(--a-transparent);
--ac-textarea-border: var(--a-border-on-inverted);
--ac-textarea-hover-border: var(--a-blue-200);
--ac-textarea-placeholder: var(--a-gray-500);
--ac-textarea-error-border: var(--a-red-300);
--ac-textarea-counter-text: var(--a-gray-300);
--ac-textarea-counter-error-text: var(--a-red-300);
--__ac-textarea-text: var(--a-text-on-inverted);
--__ac-textarea-bg: var(--a-transparent);
--__ac-textarea-border: var(--a-border-on-inverted);
--__ac-textarea-hover-border: var(--a-blue-200);
--__ac-textarea-placeholder: var(--a-gray-500);
--__ac-textarea-error-border: var(--a-red-300);
--__ac-textarea-counter-text: var(--a-gray-300);
--__ac-textarea-counter-error-text: var(--a-red-300);
}
[data-theme="light"] {
--__ac-textarea-text: initial;
--__ac-textarea-bg: initial;
--__ac-textarea-border: initial;
--__ac-textarea-hover-border: initial;
--__ac-textarea-placeholder: initial;
--__ac-textarea-error-border: initial;
--__ac-textarea-counter-text: initial;
--__ac-textarea-counter-error-text: initial;
}
.navds-textarea__wrapper {
@@ -17,13 +28,13 @@
.navds-textarea__input {
appearance: none;
padding: var(--a-spacing-2);
background-color: var(--ac-textarea-bg, var(--a-surface-default));
background-color: var(--ac-textarea-bg, var(--__ac-textarea-bg, var(--a-surface-default)));
border-radius: var(--a-border-radius-medium);
border: 1px solid var(--ac-textarea-border, var(--a-border-default));
border: 1px solid var(--ac-textarea-border, var(--__ac-textarea-border, var(--a-border-default)));
resize: none;
width: 100%;
display: block;
color: var(--ac-textarea-text, var(--a-text-default));
color: var(--ac-textarea-text, var(--__ac-textarea-text, var(--a-text-default)));
}
.navds-textarea--counter {
@@ -31,11 +42,11 @@
}
.navds-textarea__input::placeholder {
color: var(--ac-textarea-placeholder, var(--a-text-subtle));
color: var(--ac-textarea-placeholder, var(--__ac-textarea-placeholder, var(--a-text-subtle)));
}
.navds-textarea__input:hover {
border-color: var(--ac-textarea-hover-border, var(--a-border-action));
border-color: var(--ac-textarea-hover-border, var(--__ac-textarea-hover-border, var(--a-border-action)));
}
.navds-textarea__input:focus-visible {
@@ -60,7 +71,7 @@
.navds-textarea__counter {
pointer-events: none;
color: var(--ac-textarea-counter-text, var(--a-text-subtle));
color: var(--ac-textarea-counter-text, var(--__ac-textarea-counter-text, var(--a-text-subtle)));
font-style: italic;
position: absolute;
text-align: left;
@@ -70,7 +81,7 @@
}
.navds-textarea__counter--error {
color: var(--ac-textarea-counter-error-text, var(--a-text-danger));
color: var(--ac-textarea-counter-error-text, var(--__ac-textarea-counter-error-text, var(--a-text-danger)));
}
.navds-textarea--resize .navds-textarea__input {
@@ -81,20 +92,20 @@
Error handling
*/
.navds-textarea--error .navds-textarea__input:not(:hover):not(:focus-visible):not(:disabled) {
box-shadow: 0 0 0 1px var(--ac-textarea-error-border, var(--a-border-danger));
border-color: var(--ac-textarea-error-border, var(--a-border-danger));
box-shadow: 0 0 0 1px var(--ac-textarea-error-border, var(--__ac-textarea-error-border, var(--a-border-danger)));
border-color: var(--ac-textarea-error-border, var(--__ac-textarea-error-border, var(--a-border-danger)));
}
@supports not selector(:focus-visible) {
.navds-textarea--error .navds-textarea__input:not(:hover):not(:focus):not(:disabled) {
box-shadow: 0 0 0 1px var(--ac-textarea-error-border, var(--a-border-danger));
border-color: var(--ac-textarea-error-border, var(--a-border-danger));
box-shadow: 0 0 0 1px var(--ac-textarea-error-border, var(--__ac-textarea-error-border, var(--a-border-danger)));
border-color: var(--ac-textarea-error-border, var(--__ac-textarea-error-border, var(--a-border-danger)));
}
}
.navds-textarea__input:disabled {
background-color: var(--ac-textarea-bg, var(--a-surface-default));
border-color: var(--ac-textarea-border, var(--a-border-default));
background-color: var(--ac-textarea-bg, var(--__ac-textarea-bg, var(--a-surface-default)));
border-color: var(--ac-textarea-border, var(--__ac-textarea-border, var(--a-border-default)));
box-shadow: none;
cursor: not-allowed;
}
+80 -56
View File
@@ -1,72 +1,96 @@
/**
* GuidePanel component
*/
.navds-guide-panel {
--__ac-guide-panel-guide-size: 4rem;
position: relative;
padding-left: var(--a-spacing-10);
padding-top: calc(var(--__ac-guide-panel-guide-size) / 2);
}
.navds-guide-panel__content {
background-color: var(--ac-guide-panel-bg, var(--a-surface-default));
border-radius: var(--a-border-radius-medium);
border: 2px solid var(--ac-guide-panel-border, var(--a-border-action));
min-height: 7.25rem;
padding: var(--a-spacing-6);
padding-left: var(--a-spacing-14);
}
.navds-guide-panel--poster {
padding-left: 0;
padding-top: var(--a-spacing-12);
}
.navds-guide-panel--poster .navds-guide-panel__content {
padding: var(--a-spacing-8);
padding-top: var(--a-spacing-16);
}
.navds-guide-panel .navds-guide {
position: absolute;
top: var(--a-spacing-4);
transform: translateX(-50%);
border: 2px solid var(--ac-guide-panel-border, var(--a-border-action));
}
.navds-guide-panel--poster .navds-guide {
left: 50%;
top: 0;
}
/**
* Guide component
*/
.navds-guide {
display: flex;
align-items: center;
justify-content: center;
border-radius: var(--a-border-radius-full);
}
/* Guide illustration frame */
.navds-guide__illustration {
background: var(--ac-guide-panel-illustration-bg, var(--a-surface-action-subtle));
background: var(--ac-guide-panel-illustration-bg, var(--a-surface-alt-3-subtle));
border: 2px solid var(--ac-guide-panel-border, var(--a-border-alt-3));
border-radius: var(--a-border-radius-full);
overflow: hidden;
position: absolute;
width: var(--__ac-guide-panel-guide-size);
height: var(--__ac-guide-panel-guide-size);
left: 50%;
transform: translate(-50%, -50%);
}
.navds-guide__illustration svg,
.navds-guide__illustration img {
.navds-guide svg,
.navds-guide img {
height: 100%;
width: 100%;
}
/* Illustration sizes */
.navds-guide__illustration--small {
height: 5rem;
width: 5rem;
.navds-guide-panel__content {
background-color: var(--ac-guide-panel-bg, var(--a-surface-default));
border: 2px solid var(--ac-guide-panel-border, var(--a-border-alt-3));
border-radius: var(--a-border-radius-large);
padding: var(--a-spacing-4);
padding-top: var(--a-spacing-12);
}
.navds-guide__illustration--medium {
height: 6rem;
width: 6rem;
@media (min-width: 480px) {
.navds-guide-panel {
--__ac-guide-panel-guide-size: 6.25rem;
}
.navds-guide-panel__content {
padding: var(--a-spacing-8);
padding-top: 4.25rem;
}
}
/* not-poster */
.navds-guide-panel--not-poster {
padding-top: 0;
padding-left: calc(var(--__ac-guide-panel-guide-size) / 2);
}
.navds-guide-panel--not-poster .navds-guide {
left: 0;
top: var(--a-spacing-5);
transform: none;
}
.navds-guide-panel--not-poster .navds-guide-panel__content {
padding: var(--a-spacing-4);
padding-left: var(--a-spacing-10);
min-height: calc(var(--__ac-guide-panel-guide-size) + var(--a-spacing-5) + var(--a-spacing-5));
}
@media (min-width: 480px) {
.navds-guide-panel--not-poster {
--__ac-guide-panel-guide-size: 5rem;
}
.navds-guide-panel--not-poster .navds-guide-panel__content {
padding: var(--a-spacing-6);
padding-left: var(--a-spacing-14);
}
}
/* responsive-poster (on desktop) */
@media (min-width: 480px) {
.navds-guide-panel--responsive-poster {
--__ac-guide-panel-guide-size: 5rem;
padding-top: 0;
padding-left: calc(var(--__ac-guide-panel-guide-size) / 2);
}
.navds-guide-panel--responsive-poster .navds-guide {
left: 0;
top: var(--a-spacing-5);
transform: none;
}
.navds-guide-panel--responsive-poster .navds-guide-panel__content {
padding: var(--a-spacing-6);
padding-left: var(--a-spacing-14);
min-height: calc(var(--__ac-guide-panel-guide-size) + var(--a-spacing-5) + var(--a-spacing-5));
}
}
+1 -2
View File
@@ -1,6 +1,7 @@
@charset "UTF-8";
@import "baseline/index.css";
@import "typography.css";
@import "primitives/index.css";
@import "grid.css";
@import "accordion.css";
@import "alert.css";
@@ -14,7 +15,6 @@
@import "guide-panel.css";
@import "form/index.css";
@import "help-text.css";
@import "hgrid.css";
@import "internalheader.css";
@import "link.css";
@import "loader.css";
@@ -30,7 +30,6 @@
@import "link-panel.css";
@import "read-more.css";
@import "skeleton.css";
@import "stack.css";
@import "stepper.css";
@import "table.css";
@import "tabs.css";
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-css",
"version": "5.2.1",
"version": "5.5.0",
"description": "CSS for NAV Designsystem",
"author": "Aksel | NAV designsystem team",
"keywords": [
@@ -27,7 +27,7 @@
"css:get-version": "node config/get-version.js"
},
"devDependencies": {
"@navikt/ds-tokens": "^5.2.1",
"@navikt/ds-tokens": "^5.5.0",
"cssnano": "6.0.0",
"fast-glob": "3.2.11",
"lodash": "4.17.21",
+117
View File
@@ -0,0 +1,117 @@
.navds-box {
--__ac-box-padding-xs: initial;
--__ac-box-padding-sm: initial;
--__ac-box-padding-md: initial;
--__ac-box-padding-lg: initial;
--__ac-box-padding-xl: initial;
--__ac-box-padding-block-xs: initial;
--__ac-box-padding-inline-xs: initial;
--__ac-box-padding-block-sm: initial;
--__ac-box-padding-inline-sm: initial;
--__ac-box-padding-block-md: initial;
--__ac-box-padding-inline-md: initial;
--__ac-box-padding-block-lg: initial;
--__ac-box-padding-inline-lg: initial;
--__ac-box-padding-block-xl: initial;
--__ac-box-padding-inline-xl: initial;
--__ac-box-padding: var(--__ac-box-padding-xs);
--__ac-box-padding-inline: var(--__ac-box-padding-inline-xs);
--__ac-box-padding-block: var(--__ac-box-padding-block-xs);
--__ac-box-background: initial;
--__ac-box-border-color: initial;
--__ac-box-shadow: initial;
--__ac-box-border-width: initial;
--__ac-box-border-radius-xs: initial;
--__ac-box-border-radius-sm: initial;
--__ac-box-border-radius-md: initial;
--__ac-box-border-radius-lg: initial;
--__ac-box-border-radius-xl: initial;
--__ac-box-border-radius: var(--__ac-box-border-radius-xs);
padding-inline: var(--__ac-box-padding-inline, var(--__ac-box-padding));
padding-block: var(--__ac-box-padding-block, var(--__ac-box-padding));
background-color: var(--__ac-box-background);
border-style: solid;
border-color: var(--__ac-box-border-color);
border-radius: var(--__ac-box-border-radius);
box-shadow: var(--__ac-box-shadow);
border-width: var(--__ac-box-border-width, 0);
}
@media (min-width: 480px) {
.navds-box {
--__ac-box-padding: var(--__ac-box-padding-sm, var(--__ac-box-padding-xs));
--__ac-box-padding-inline: var(--__ac-box-padding-inline-sm, var(--__ac-box-padding-inline-xs));
--__ac-box-padding-block: var(--__ac-box-padding-block-sm, var(--__ac-box-padding-block-xs));
--__ac-box-border-radius: var(--__ac-box-border-radius-sm, var(--__ac-box-border-radius-xs));
}
}
@media (min-width: 768px) {
.navds-box {
--__ac-box-padding: var(--__ac-box-padding-md, var(--__ac-box-padding-sm, var(--__ac-box-padding-xs)));
--__ac-box-padding-inline: var(
--__ac-box-padding-inline-md,
var(--__ac-box-padding-inline-sm, var(--__ac-box-padding-inline-xs))
);
--__ac-box-padding-block: var(
--__ac-box-padding-block-md,
var(--__ac-box-padding-block-sm, var(--__ac-box-padding-block-xs))
);
--__ac-box-border-radius: var(
--__ac-box-border-radius-md,
var(--__ac-box-border-radius-sm, var(--__ac-box-border-radius-xs))
);
}
}
@media (min-width: 1024px) {
.navds-box {
--__ac-box-padding: var(
--__ac-box-padding-lg,
var(--__ac-box-padding-md, var(--__ac-box-padding-sm, var(--__ac-box-padding-xs)))
);
--__ac-box-padding-inline: var(
--__ac-box-padding-inline-lg,
var(--__ac-box-padding-inline-md, var(--__ac-box-padding-inline-sm, var(--__ac-box-padding-inline-xs)))
);
--__ac-box-padding-block: var(
--__ac-box-padding-block-lg,
var(--__ac-box-padding-block-md, var(--__ac-box-padding-block-sm, var(--__ac-box-padding-block-xs)))
);
--__ac-box-border-radius: var(
--__ac-box-border-radius-lg,
var(--__ac-box-border-radius-md, var(--__ac-box-border-radius-sm, var(--__ac-box-border-radius-xs)))
);
}
}
@media (min-width: 1280px) {
.navds-box {
--__ac-box-padding: var(
--__ac-box-padding-xl,
var(--__ac-box-padding-lg, var(--__ac-box-padding-md, var(--__ac-box-padding-sm, var(--__ac-box-padding-xs))))
);
--__ac-box-padding-inline: var(
--__ac-box-padding-inline-xl,
var(
--__ac-box-padding-inline-lg,
var(--__ac-box-padding-inline-md, var(--__ac-box-padding-inline-sm, var(--__ac-box-padding-inline-xs)))
)
);
--__ac-box-padding-block: var(
--__ac-box-padding-block-xl,
var(
--__ac-box-padding-block-lg,
var(--__ac-box-padding-block-md, var(--__ac-box-padding-block-sm, var(--__ac-box-padding-block-xs)))
)
);
--__ac-box-border-radius: var(
--__ac-box-border-radius-xl,
var(
--__ac-box-border-radius-lg,
var(--__ac-box-border-radius-md, var(--__ac-box-border-radius-sm, var(--__ac-box-border-radius-xs)))
)
);
}
}
@@ -11,10 +11,12 @@
--__ac-hgrid-gap-lg: initial;
--__ac-hgrid-gap-xl: initial;
--__ac-hgrid-gap: var(--__ac-hgrid-gap-xs);
--__ac-hgrid-align: initial;
display: grid;
grid-template-columns: var(--__ac-hgrid-columns);
gap: var(--__ac-hgrid-gap);
align-items: var(--__ac-hgrid-align);
}
@media (min-width: 480px) {
+4
View File
@@ -0,0 +1,4 @@
@import "box.css";
@import "hgrid.css";
@import "stack.css";
@import "responsive.css";
@@ -0,0 +1,51 @@
.navds-responsive {
display: none;
}
@media (min-width: 480px) {
.navds-responsive__above--sm {
display: revert;
}
}
@media (max-width: 479px) {
.navds-responsive__below--sm {
display: revert;
}
}
@media (min-width: 768px) {
.navds-responsive__above--md {
display: revert;
}
}
@media (max-width: 767px) {
.navds-responsive__below--md {
display: revert;
}
}
@media (min-width: 1024px) {
.navds-responsive__above--lg {
display: revert;
}
}
@media (max-width: 1023px) {
.navds-responsive__below--lg {
display: revert;
}
}
@media (min-width: 1280px) {
.navds-responsive__above--xl {
display: revert;
}
}
@media (max-width: 1279px) {
.navds-responsive__below--xl {
display: revert;
}
}
File renamed without changes.
+4 -1
View File
@@ -1,11 +1,14 @@
.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--inline {
display: inline-block;
}
.navds-skeleton--has-children {
color: transparent;
}
+2 -2
View File
@@ -156,8 +156,8 @@
},
"guidepanel": {
"--ac-guide-panel-bg": "--a-surface-default",
"--ac-guide-panel-border": "--a-border-action",
"--ac-guide-panel-illustration-bg": "--a-surface-action-subtle"
"--ac-guide-panel-border": "--a-border-alt-3",
"--ac-guide-panel-illustration-bg": "--a-surface-alt-3-subtle"
},
"helptext": {
"--ac-help-text-button-color": "--a-surface-action",
+69 -5
View File
@@ -1,3 +1,13 @@
[data-theme="dark"] {
--__ac-typo-error-text: var(--a-red-300);
--__ac-typo-text-subtle: var(--a-gray-300);
}
[data-theme="light"] {
--__ac-typo-error-text: initial;
--__ac-typo-text-subtle: initial;
}
/* Heading */
.navds-heading {
font-weight: var(--a-font-weight-bold);
@@ -103,6 +113,16 @@
margin-bottom: var(--a-spacing-7);
}
.navds-body-long--large {
font-size: var(--a-font-size-xlarge);
letter-spacing: -0.0013em;
line-height: var(--a-font-line-height-xlarge);
}
.navds-body-long--large.navds-typo--spacing {
margin-bottom: var(--a-spacing-10);
}
.navds-body-long--small {
font-size: var(--a-font-size-medium);
letter-spacing: 0.002em;
@@ -125,6 +145,16 @@
margin-bottom: var(--a-spacing-3);
}
.navds-body-short--large {
font-size: var(--a-font-size-xlarge);
letter-spacing: -0.0013em;
line-height: var(--a-font-line-height-large);
}
.navds-body-short--large.navds-typo--spacing {
margin-bottom: var(--a-spacing-4);
}
.navds-body-short--small {
font-size: var(--a-font-size-medium);
letter-spacing: 0.002em;
@@ -182,11 +212,45 @@
margin-bottom: var(--a-spacing-2);
}
[data-theme="dark"].navds-error-message,
[data-theme="dark"] .navds-error-message {
--a-text-danger: var(--a-red-300);
.navds-error-message {
color: var(--ac-typo-error-text, var(--__ac-typo-error-text, var(--a-text-danger)));
}
.navds-error-message {
color: var(--ac-typo-error-text, var(--a-text-danger));
.navds-typo--truncate {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.navds-typo--semibold {
font-weight: var(--a-font-weight-bold);
}
.navds-typo--align-start {
text-align: start;
}
.navds-typo--align-center {
text-align: center;
}
.navds-typo--align-end {
text-align: end;
}
.navds-typo--visually-hidden {
border: 0 !important;
clip: rect(0, 0, 0, 0) !important;
height: 1px !important;
margin: -1px !important;
overflow: hidden !important;
padding: 0 !important;
top: 0 !important;
position: absolute !important;
white-space: nowrap !important;
width: 1px !important;
}
.navds-typo--color-subtle {
color: var(--__ac-typo-text-subtle, var(--a-text-subtle));
}
+100
View File
@@ -1,5 +1,105 @@
# @navikt/ds-react
## 5.5.0
### Minor Changes
- Box: Ny primitive, erstatter dagens `Panel` ([#2195](https://github.com/navikt/aksel/pull/2195))
### Patch Changes
- Skeleton: Width fungerer nå med inline-variant av Skeleton ([#2273](https://github.com/navikt/aksel/pull/2273))
- Updated dependencies [[`83c9194a4`](https://github.com/navikt/aksel/commit/83c9194a480fd3d184f673815522f230ed5d77bb)]:
- @navikt/ds-tokens@5.5.0
- @navikt/aksel-icons@5.5.0
## 5.4.1
### Patch Changes
- MonthPicker: Fikset kalkulering av fromDate/toDate ([#2269](https://github.com/navikt/aksel/pull/2269))
- Updated dependencies []:
- @navikt/aksel-icons@5.4.1
## 5.4.0
### Minor Changes
- Primitives: Nye komponenter `Show` og `Hide` er lagt til. ([#2222](https://github.com/navikt/aksel/pull/2222))
### Patch Changes
- Search: Kjører nå bare preventDefault ved Escape når `input` inneholder tekst ([#2245](https://github.com/navikt/aksel/pull/2245))
- Updated dependencies []:
- @navikt/aksel-icons@5.4.0
## 5.3.5
### Patch Changes
- :bug: Popover: sjekk at det er et HTML-element som får fokus ([#2258](https://github.com/navikt/aksel/pull/2258))
- Updated dependencies []:
- @navikt/aksel-icons@5.3.5
## 5.3.4
### Patch Changes
- Updated dependencies [[`27dacfdbe`](https://github.com/navikt/aksel/commit/27dacfdbe96a861b19c20d4494485c863d0ee8d9)]:
- @navikt/aksel-icons@5.3.4
## 5.3.3
### Patch Changes
- HGrid: Har nå `align`-prop for bedre kontroll over child-elementer ([#2242](https://github.com/navikt/aksel/pull/2242))
- Updated dependencies []:
- @navikt/aksel-icons@5.3.3
## 5.3.2
### Patch Changes
- Skeleton: Lagt til as-prop for inline brk av Skeleton med span ([#2239](https://github.com/navikt/aksel/pull/2239))
- Updated dependencies []:
- @navikt/aksel-icons@5.3.2
## 5.3.1
### Patch Changes
- Fix bug in monthpicker, only compare year and month for equality on date object ([#2231](https://github.com/navikt/aksel/pull/2231))
- :lipstick: GuidePanel: justert design ([#2227](https://github.com/navikt/aksel/pull/2227))
- :bug: DatePicker: Riktig skriftstørrelse på small input ([#2232](https://github.com/navikt/aksel/pull/2232))
- Updated dependencies []:
- @navikt/aksel-icons@5.3.1
## 5.3.0
### Minor Changes
- Heading: Oppdatert med props `textColor`, `align`, `visuallyHidden`. ([#2211](https://github.com/navikt/aksel/pull/2211))
- Label: Oppdatert med props `textColor` og `visuallyHidden`. ([#2211](https://github.com/navikt/aksel/pull/2211))
- BodyLong, BodyShort, Detail: Oppdatert med props `textColor`,`weight`,`align`, `visuallyHidden` og `truncated`. ([#2211](https://github.com/navikt/aksel/pull/2211))
### Patch Changes
- :wheelchair: Textarea: Skjermleser-spesifikk tekst leses opp sammenhengende ([#2216](https://github.com/navikt/aksel/pull/2216))
- Updated dependencies []:
- @navikt/aksel-icons@5.3.0
## 5.2.1
### Patch Changes
+6 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-react",
"version": "5.2.1",
"version": "5.5.0",
"description": "Aksel react-components for NAV designsystem",
"author": "Aksel | NAV designsystem team",
"license": "MIT",
@@ -32,13 +32,14 @@
"docgen": "yarn ts-node ../../../scripts/docgen.ts",
"create-package-json-pointers-to-esm": "node ../../../scripts/createPackageJsonsWithESMPointers.js",
"clean": "rimraf cjs esm",
"build": "concurrently \"tsc\" \"tsc -p tsconfig.esm.json\" && yarn create-package-json-pointers-to-esm",
"build": "concurrently \"tsc -p tsconfig.build.json\" \"tsc -p tsconfig.esm.json\" && yarn create-package-json-pointers-to-esm",
"watch": "tsc --watch -p tsconfig.esm.json",
"test": "TZ=UTC jest"
},
"dependencies": {
"@floating-ui/react": "0.24.1",
"@navikt/aksel-icons": "^5.2.1",
"@navikt/aksel-icons": "^5.5.0",
"@navikt/ds-tokens": "^5.5.0",
"@radix-ui/react-tabs": "1.0.0",
"@radix-ui/react-toggle-group": "1.0.0",
"clsx": "^1.2.1",
@@ -63,8 +64,8 @@
"rimraf": "3.0.2",
"swr": "^1.1.2",
"ts-jest": "^29.0.0",
"ts-node": "10.9.0",
"typescript": "^4.8.0"
"ts-node": "^10.9.1",
"typescript": "^5.1.6"
},
"peerDependencies": {
"@types/react": "^17.0.30 || ^18.0.0",
+34 -28
View File
@@ -1,6 +1,6 @@
import type { Meta, StoryObj } from "@storybook/react";
import React from "react";
import { Alert } from ".";
import { Alert, AlertProps } from ".";
import { BodyLong, Heading as DsHeading, Link } from "..";
import { within, userEvent } from "@storybook/testing-library";
import { expect } from "@storybook/jest";
@@ -14,7 +14,7 @@ export default meta;
type Story = StoryObj<typeof Alert>;
const variants: Array<"error" | "warning" | "info" | "success"> = [
const variants: AlertProps["variant"][] = [
"error",
"warning",
"info",
@@ -33,24 +33,17 @@ export const Default: Story = {
},
argTypes: {
variant: {
control: {
type: "radio",
},
control: { type: "radio" },
options: ["info", "error", "warning", "success"],
},
size: {
control: {
type: "radio",
},
control: { type: "radio" },
options: ["medium", "small"],
},
closeButton: {
type: "boolean",
},
},
};
export const Small = {
export const Small: Story = {
render: (props) => {
return (
<div className="colgap">
@@ -69,14 +62,10 @@ export const Small = {
</div>
);
},
args: {
closeButton: false,
},
argtypes: {
closeButton: {
type: "boolean",
},
},
};
export const FullWidth = () => {
@@ -160,16 +149,25 @@ export const Links = () => {
);
};
const AlertWithCloseButton = ({ children }: { children?: React.ReactNode }) => {
const AlertWithCloseButton = ({
children,
size,
}: {
size?: "medium" | "small";
children?: React.ReactNode;
}) => {
let [show, setShow] = React.useState(true);
return (
show && (
<Alert variant="success" closeButton onClose={() => setShow(false)}>
{children || "Content"}
</Alert>
)
);
return show ? (
<Alert
variant="warning"
size={size}
closeButton
onClose={() => setShow(false)}
>
{children || "Content"}
</Alert>
) : null;
};
export const WithCloseButton: Story = {
@@ -178,14 +176,22 @@ export const WithCloseButton: Story = {
<div className="colgap">
<AlertWithCloseButton />
<AlertWithCloseButton>
<BodyLong>Ullamco ullamco laborum et commodo sint culpa</BodyLong>
</AlertWithCloseButton>
<AlertWithCloseButton>
<DsHeading spacing size="small" level="3">
Aliquip duis est in commodo pariatur
</DsHeading>
<BodyLong>
Ullamco ullamco laborum et commodo sint culpa cupidatat culpa qui
laboris ex. Labore ex occaecat proident qui qui fugiat magna. Fugiat
sint commodo consequat eu aute.
</BodyLong>
<Link href="#">Id elit esse enim reprehenderit</Link>
</AlertWithCloseButton>
<AlertWithCloseButton>
<AlertWithCloseButton size="small">
<BodyLong>Ullamco ullamco laborum et commodo</BodyLong>
</AlertWithCloseButton>
<AlertWithCloseButton size="small">
<DsHeading spacing size="small" level="3">
Aliquip duis est in commodo pariatur
</DsHeading>
@@ -207,6 +213,6 @@ export const WithCloseButton: Story = {
});
const buttonsAfter = canvas.getAllByTitle("Lukk Alert");
expect(buttonsAfter.length).toBe(2);
expect(buttonsAfter.length).toBe(4);
},
};
+1 -1
View File
@@ -113,7 +113,7 @@ const DateInput = forwardRef<HTMLInputElement, DateInputProps>((props, ref) => {
"navds-date__field-input",
"navds-text-field__input",
"navds-body-short",
`navds-body-${size}`
`navds-body-short--${size}`
)}
size={14}
/>
@@ -1,8 +1,9 @@
/* eslint-disable react-hooks/rules-of-hooks */
import { Meta, StoryObj } from "@storybook/react";
import React, { useId, useState } from "react";
import { useDatepicker, useRangeDatepicker } from "..";
import { Button } from "../..";
import DatePicker from "./DatePicker";
import DatePicker, { DatePickerProps } from "./DatePicker";
const disabledDays = [
new Date("Oct 10 2022"),
@@ -12,20 +13,29 @@ const disabledDays = [
export default {
title: "ds-react/Datepicker",
component: DatePicker,
} satisfies Meta<typeof DatePicker>;
type DefaultStoryProps = DatePickerProps & {
size: "medium" | "small";
openOnFocus: boolean;
inputfield: boolean;
standalone: boolean;
};
export const Default = {
export const Default: StoryObj<DefaultStoryProps> = {
render: (props) => {
const [open, setOpen] = useState(false);
const rangeCtx = useRangeDatepicker({
fromDate: new Date("Aug 23 2020"),
toDate: new Date("Aug 23 2023"),
openOnFocus: props.openOnFocus,
});
const singleCtx = useDatepicker({
fromDate: new Date("Aug 23 2020"),
toDate: new Date("Aug 23 2023"),
openOnFocus: props.openOnFocus,
});
const newProps = {
@@ -44,9 +54,7 @@ export const Default = {
return (
<div>
<Comp
locale={props?.locale}
dropdownCaption={props?.dropdownCaption}
disableWeekends={props?.disableWeekends}
dropdownCaption={props.dropdownCaption}
showWeekNumber={props.showWeekNumber}
mode={props.mode}
{...(props.mode === "single"
@@ -55,6 +63,8 @@ export const Default = {
? rangeCtx.datepickerProps
: {})}
{...newProps}
locale={props.locale}
disableWeekends={props.disableWeekends}
>
{!props.standalone && (
<>
@@ -99,29 +109,23 @@ export const Default = {
dropdownCaption: false,
disableWeekends: false,
showWeekNumber: false,
mode: "single",
openOnFocus: true,
inputfield: true,
standalone: false,
openOnFocus: true,
mode: "single",
},
argTypes: {
size: {
control: {
type: "radio",
options: ["medium", "small"],
},
options: ["medium", "small"],
control: { type: "radio" },
},
locale: {
control: {
type: "radio",
options: ["nb", "nn", "en"],
},
options: ["nb", "nn", "en"],
control: { type: "radio" },
},
mode: {
control: {
type: "radio",
options: ["single", "multiple", "range"],
},
options: ["single", "multiple", "range"],
control: { type: "radio" },
},
},
};
@@ -1,8 +1,8 @@
import cl from "clsx";
import compareAsc from "date-fns/compareAsc";
import compareDesc from "date-fns/compareDesc";
import format from "date-fns/format";
import isSameMonth from "date-fns/isSameMonth";
import compareAsc from "date-fns/compareAsc";
import compareDesc from "date-fns/compareDesc";
import setYear from "date-fns/setYear";
import React, { useEffect, useRef } from "react";
import { useDayPicker } from "react-day-picker";
@@ -21,12 +21,13 @@ interface MonthType {
const disableMonth = (month: Date, fromDate?: Date, toDate?: Date) => {
if (fromDate && toDate) {
return (
compareAsc(month, fromDate) === -1 || compareDesc(month, toDate) === -1
(compareAsc(month, fromDate) === -1 && !isSameMonth(month, fromDate)) ||
(compareDesc(month, toDate) === -1 && !isSameMonth(month, toDate))
);
} else if (fromDate) {
return compareAsc(month, fromDate) === -1;
return compareAsc(month, fromDate) === -1 && !isSameMonth(month, fromDate);
} else if (toDate) {
return compareDesc(month, toDate) === -1;
return compareDesc(month, toDate) === -1 && !isSameMonth(month, toDate);
}
return false;
};
@@ -1,30 +1,21 @@
import { Meta, StoryFn } from "@storybook/react";
import React, { useId, useState } from "react";
import { Button } from "../..";
import { Button, DateInputProps } from "../..";
import { useMonthpicker } from "../hooks";
import MonthPicker from "./MonthPicker";
import MonthPicker, { MonthPickerProps } from "./MonthPicker";
export default {
title: "ds-react/Monthpicker",
component: MonthPicker,
argTypes: {
size: {
control: {
type: "radio",
options: ["medium", "small"],
},
},
locale: {
control: {
type: "radio",
options: ["nb", "nn", "en"],
},
},
},
};
} satisfies Meta<typeof MonthPicker>;
export const Default = () => {
export const Default: StoryFn<{
size: DateInputProps["size"];
locale: MonthPickerProps["locale"];
}> = (props) => {
const { inputProps, monthpickerProps } = useMonthpicker({
disabled: [new Date("Apr 1 2022")],
locale: props.locale,
});
return (
@@ -33,18 +24,29 @@ export const Default = () => {
<MonthPicker.Input
label="Velg måned"
variant="monthpicker"
size={props.size}
{...inputProps}
/>
</MonthPicker>
</div>
);
};
Default.argTypes = {
size: {
options: ["medium", "small"],
control: { type: "radio" },
},
locale: {
options: ["nb", "nn", "en"],
control: { type: "radio" },
},
};
export const dropdownCaption = () => {
return (
<MonthPicker.Standalone
dropdownCaption
fromDate={new Date("Jan 1 2019")}
fromDate={new Date("Feb 10 2019")}
toDate={new Date("Sep 27 2032")}
/>
);
@@ -54,20 +56,16 @@ export const NB = () => <MonthPicker.Standalone locale="nb" />;
export const NN = () => <MonthPicker.Standalone locale="nn" />;
export const EN = () => <MonthPicker.Standalone locale="en" />;
export const DisabledMonths = {
render: (props) => {
return (
<MonthPicker.Standalone
disabled={[
{ from: new Date("Jan 1 2022"), to: new Date("Jul 6 2022") },
{ from: new Date("Apr 2 2023"), to: new Date("Dec 4 2023") },
new Date("Sep 5 2022"),
new Date("Jan 5 2023"),
]}
/>
);
},
};
export const DisabledMonths = () => (
<MonthPicker.Standalone
disabled={[
{ from: new Date("Jan 1 2022"), to: new Date("Jul 6 2022") },
{ from: new Date("Apr 2 2023"), to: new Date("Dec 4 2023") },
new Date("Sep 5 2022"),
new Date("Jan 5 2023"),
]}
/>
);
export const Standalone = () => {
return <MonthPicker.Standalone />;
@@ -28,5 +28,5 @@ export const List = forwardRef(({ className, children, ...rest }, ref) => (
)) as ListType;
List.Item = ListItem;
List.displayName = "Dropdown.Menu.List";
export default List;
+1 -1
View File
@@ -171,7 +171,7 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
{hasMaxLength && (
<>
<span id={maxLengthId} className="navds-sr-only">
Tekstområde med plass til {maxLength} tegn.
{`Tekstområde med plass til ${maxLength} tegn.`}
</span>
<Counter
maxLength={maxLength}
@@ -1,26 +1,18 @@
/* eslint-disable react-hooks/rules-of-hooks */
import { Meta } from "@storybook/react";
import { Meta, StoryFn, StoryObj } from "@storybook/react";
import React, { useState, useId, useMemo } from "react";
import { userEvent, within } from "@storybook/testing-library";
import { Chips, UNSAFE_Combobox, TextField } from "../../index";
import { Chips, UNSAFE_Combobox, ComboboxProps, TextField } from "../../index";
import { expect, jest } from "@storybook/jest";
export default {
title: "ds-react/Combobox",
component: UNSAFE_Combobox,
argTypes: {
isListOpen: {
control: {
type: "boolean",
},
},
isLoading: {
control: {
type: "boolean",
},
},
},
} as Meta;
decorators: [(story) => <div style={{ width: "300px" }}>{story()}</div>],
} satisfies Meta<typeof UNSAFE_Combobox>;
type StoryObject = StoryObj<typeof UNSAFE_Combobox>;
type StoryFunction = StoryFn<typeof UNSAFE_Combobox>;
const options = [
"banana",
@@ -38,55 +30,39 @@ const options = [
"grape fruit",
];
const initialSelectedOptions = ["passion fruit", "grape fruit"];
const DemoContainer = ({
dataTheme,
children,
}: {
children: any;
dataTheme: "dark" | "light";
}) => (
<div data-theme={dataTheme} style={{ width: "300px" }}>
{children}
</div>
);
export const Default = (props) => {
export const Default: StoryFunction = (props) => {
const id = useId();
return (
<DemoContainer dataTheme={props.darkMode}>
<UNSAFE_Combobox
options={props.options}
label="Hva er dine favorittfrukter?"
/* everything under here is optional? */
shouldAutocomplete={props.shouldAutoComplete}
size="medium"
id={id}
/>
</DemoContainer>
);
return <UNSAFE_Combobox {...props} id={id} />;
};
Default.args = {
options,
shouldAutoComplete: true,
label: "Hva er dine favorittfrukter?",
shouldAutocomplete: true,
isLoading: false,
};
Default.argTypes = {
isListOpen: {
control: { type: "boolean" },
},
size: {
options: ["medium", "small"],
defaultValue: "medium",
control: { type: "radio" },
},
};
export function MultiSelect(props) {
export const MultiSelect: StoryFunction = (props) => {
const id = useId();
return (
<DemoContainer dataTheme={props.darkMode}>
<UNSAFE_Combobox
id={id}
label="Komboboks - velg flere"
options={props.options}
isMultiSelect={props.isMultiSelect}
size={props.size}
/>
</DemoContainer>
<UNSAFE_Combobox
id={id}
label="Komboboks - velg flere"
options={props.options}
isMultiSelect={props.isMultiSelect}
size={props.size}
/>
);
}
};
MultiSelect.args = {
options,
@@ -94,41 +70,37 @@ MultiSelect.args = {
size: "medium",
};
export function WithAddNewOptions(props) {
export const WithAddNewOptions: StoryFunction = (props) => {
const id = useId();
return (
<DemoContainer dataTheme={props.darkMode}>
<UNSAFE_Combobox
id={id}
label="Komboboks med mulighet for å legge til nye verdier"
options={props.options}
allowNewValues={props.allowNewValues}
shouldAutocomplete={props.shouldAutoComplete}
/>
</DemoContainer>
<UNSAFE_Combobox
id={id}
label="Komboboks med mulighet for å legge til nye verdier"
options={props.options}
allowNewValues={props.allowNewValues}
shouldAutocomplete={props.shouldAutocomplete}
/>
);
}
};
WithAddNewOptions.args = {
options,
allowNewValues: true,
shouldAutoComplete: true,
shouldAutocomplete: true,
};
export function MultiSelectWithAddNewOptions(props) {
export const MultiSelectWithAddNewOptions: StoryFunction = (props) => {
const id = useId();
return (
<DemoContainer dataTheme={props.darkMode}>
<UNSAFE_Combobox
id={id}
isMultiSelect={props.isMultiSelect}
label="Multiselect komboboks med mulighet for å legge til nye verdier"
options={props.options}
allowNewValues={props.allowNewValues}
/>
</DemoContainer>
<UNSAFE_Combobox
id={id}
isMultiSelect={props.isMultiSelect}
label="Multiselect komboboks med mulighet for å legge til nye verdier"
options={props.options}
allowNewValues={props.allowNewValues}
/>
);
}
};
MultiSelectWithAddNewOptions.args = {
allowNewValues: true,
@@ -137,19 +109,20 @@ MultiSelectWithAddNewOptions.args = {
shouldAutocomplete: false,
};
export const MultiSelectWithExternalChips = (props) => {
const [selectedOptions, setSelectedOptions] = useState<string[]>(
props.selectedOptions
);
export const MultiSelectWithExternalChips: StoryFn<{
controlled: boolean;
options: ComboboxProps["options"];
}> = (props) => {
const [selectedOptions, setSelectedOptions] = useState<string[]>([]);
const [value, setValue] = useState("");
const id = useId();
const toggleSelected = (option) =>
const toggleSelected = (option: string) =>
selectedOptions.includes(option)
? setSelectedOptions(selectedOptions.filter((opt) => opt !== option))
: setSelectedOptions([...selectedOptions, option]);
return (
<DemoContainer dataTheme={props.darkMode}>
<>
{selectedOptions && (
<Chips>
{selectedOptions.map((option) => (
@@ -164,84 +137,85 @@ export const MultiSelectWithExternalChips = (props) => {
</Chips>
)}
<UNSAFE_Combobox
options={options}
options={props.options}
selectedOptions={selectedOptions}
onToggleSelected={(option: string) => toggleSelected(option)}
isListOpen={props.isListOpen}
onToggleSelected={(option) => toggleSelected(option)}
isMultiSelect
value={props.controlled ? value : undefined}
onChange={(event) =>
props.controlled ? setValue(event.currentTarget.value) : undefined
props.controlled
? setValue(event?.currentTarget.value || "")
: undefined
}
label="Komboboks"
size="medium"
error={props.error && "error here"}
id={id}
shouldShowSelectedOptions={false}
/>
</DemoContainer>
</>
);
};
MultiSelectWithExternalChips.args = {
controlled: false,
options,
selectedOptions: [],
};
export function Loading(props) {
export const Loading: StoryFunction = (props) => {
const id = useId();
return (
<DemoContainer dataTheme={props.darkMode}>
<UNSAFE_Combobox
id={id}
label="Komboboks (laster)"
options={[]}
selectedOptions={[]}
isListOpen={props.isListOpen}
isLoading={props.isLoading}
/>
</DemoContainer>
<UNSAFE_Combobox
id={id}
label="Komboboks (laster)"
options={[]}
selectedOptions={[]}
isListOpen={props.isListOpen}
isLoading={props.isLoading}
/>
);
}
};
Loading.args = {
isLoading: true,
isListOpen: true,
};
export function ComboboxWithNoHits(props) {
export const ComboboxWithNoHits: StoryFunction = (props) => {
const id = useId();
const [value, setValue] = useState(props.value);
return (
<DemoContainer dataTheme={props.darkMode}>
<UNSAFE_Combobox
id={id}
label="Komboboks (uten søketreff)"
options={props.options}
value={value}
onChange={(event) => setValue(event.currentTarget.value)}
isListOpen={true}
/>
</DemoContainer>
<UNSAFE_Combobox
id={id}
label="Komboboks (uten søketreff)"
options={props.options}
value={value}
onChange={(event) => setValue(event?.currentTarget.value)}
isListOpen={true}
/>
);
}
};
ComboboxWithNoHits.args = {
options,
value: "Orange",
};
export const Controlled = (props) => {
export const Controlled: StoryFn<{
value: string;
options: string[];
initialSelectedOptions: string[];
}> = (props) => {
const id = useId();
const [value, setValue] = useState(props.value);
const [selectedOptions, setSelectedOptions] = useState(props.selectedOptions);
const [selectedOptions, setSelectedOptions] = useState(
props.initialSelectedOptions
);
const filteredOptions = useMemo(
() => props.options.filter((option) => option.includes(value)),
[props.options, value]
);
const onToggleSelected = (option, isSelected) => {
const onToggleSelected = (option: string, isSelected: boolean) => {
if (isSelected) {
setSelectedOptions([...selectedOptions, option]);
} else {
@@ -250,7 +224,7 @@ export const Controlled = (props) => {
};
return (
<DemoContainer dataTheme={props.darkMode}>
<>
<TextField
label="Overstyr value"
onChange={(event) => setValue(event.target.value)}
@@ -263,23 +237,23 @@ export const Controlled = (props) => {
filteredOptions={filteredOptions}
isMultiSelect
options={props.options}
onChange={(event) => setValue(event.target.value)}
onChange={(event) => setValue(event?.target.value || "")}
onToggleSelected={onToggleSelected}
selectedOptions={selectedOptions}
value={value}
/>
</DemoContainer>
</>
);
};
Controlled.args = {
value: "apple",
options,
selectedOptions: initialSelectedOptions,
initialSelectedOptions: ["passion fruit", "grape fruit"],
};
export const ComboboxSizes = (props) => (
<DemoContainer dataTheme={props.darkMode}>
export const ComboboxSizes = () => (
<>
<UNSAFE_Combobox
label="Hva er dine favorittfrukter?"
description="Medium single-select"
@@ -309,36 +283,29 @@ export const ComboboxSizes = (props) => (
size="small"
allowNewValues
/>
</DemoContainer>
</>
);
ComboboxSizes.args = {
options,
};
export const WithError = {
export const WithError: StoryObject = {
args: {
error: "Du må velge en favorittfrukt.",
isLoading: true,
},
render: (props) => {
const [hasSelectedValue, setHasSelectedValue] = useState(false);
const [isLoading, setIsLoading] = useState(false);
return (
<DemoContainer dataTheme={props.darkMode}>
<UNSAFE_Combobox
filteredOptions={isLoading ? [] : undefined}
options={options}
label="Hva er dine favorittfrukter?"
error={!hasSelectedValue && props.error}
isLoading={isLoading}
onChange={() => {
setIsLoading(true);
setTimeout(() => setIsLoading(false), 2000);
}}
onToggleSelected={(_, isSelected) => setHasSelectedValue(isSelected)}
/>
</DemoContainer>
<UNSAFE_Combobox
filteredOptions={isLoading ? [] : undefined}
options={options}
label="Hva er dine favorittfrukter?"
error={!hasSelectedValue && props.error}
isLoading={isLoading}
onChange={() => {
setIsLoading(true);
setTimeout(() => setIsLoading(false), 2000);
}}
onToggleSelected={(_, isSelected) => setHasSelectedValue(isSelected)}
/>
);
},
};
@@ -347,15 +314,10 @@ function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
export const CancelInputTest = {
render: (props) => {
export const CancelInputTest: StoryObject = {
render: () => {
return (
<DemoContainer dataTheme={props.darkMode}>
<UNSAFE_Combobox
options={options}
label="Hva er dine favorittfrukter?"
/>
</DemoContainer>
<UNSAFE_Combobox options={options} label="Hva er dine favorittfrukter?" />
);
},
play: async ({ canvasElement }) => {
@@ -378,16 +340,14 @@ export const CancelInputTest = {
},
};
export const RemoveSelectedMultiSelectTest = {
render: (props) => {
export const RemoveSelectedMultiSelectTest: StoryObject = {
render: () => {
return (
<DemoContainer dataTheme={props.darkMode}>
<UNSAFE_Combobox
options={options}
label="Hva er dine favorittfrukter?"
isMultiSelect
/>
</DemoContainer>
<UNSAFE_Combobox
options={options}
label="Hva er dine favorittfrukter?"
isMultiSelect
/>
);
},
play: async ({ canvasElement }) => {
@@ -436,16 +396,14 @@ export const RemoveSelectedMultiSelectTest = {
},
};
export const AddWhenAddNewDisabledTest = {
render: (props) => {
export const AddWhenAddNewDisabledTest: StoryObject = {
render: () => {
return (
<DemoContainer dataTheme={props.darkMode}>
<UNSAFE_Combobox
options={options}
label="Hva er dine favorittfrukter?"
isMultiSelect
/>
</DemoContainer>
<UNSAFE_Combobox
options={options}
label="Hva er dine favorittfrukter?"
isMultiSelect
/>
);
},
play: async ({ canvasElement }) => {
@@ -471,7 +429,11 @@ export const AddWhenAddNewDisabledTest = {
},
};
export const TestThatCallbacksOnlyFireWhenExpected = {
export const TestThatCallbacksOnlyFireWhenExpected: StoryObj<{
onChange: ReturnType<typeof jest.fn>;
onClear: ReturnType<typeof jest.fn>;
onToggleSelected: ReturnType<typeof jest.fn>;
}> = {
args: {
onChange: jest.fn(),
onClear: jest.fn(),
@@ -479,13 +441,11 @@ export const TestThatCallbacksOnlyFireWhenExpected = {
},
render: (props) => {
return (
<DemoContainer dataTheme={props.darkMode}>
<UNSAFE_Combobox
options={options}
label="Hva er dine favorittfrukter?"
{...props}
/>
</DemoContainer>
<UNSAFE_Combobox
options={options}
label="Hva er dine favorittfrukter?"
{...props}
/>
);
},
play: async ({ canvasElement, args }) => {
@@ -510,16 +470,10 @@ export const TestThatCallbacksOnlyFireWhenExpected = {
},
};
export const TestHoverAndFocusSwitching = {
render: (props) => {
export const TestHoverAndFocusSwitching: StoryObject = {
render: () => {
return (
<DemoContainer dataTheme={props.darkMode}>
<UNSAFE_Combobox
options={options}
label="Hva er dine favorittfrukter?"
{...props}
/>
</DemoContainer>
<UNSAFE_Combobox options={options} label="Hva er dine favorittfrukter?" />
);
},
play: async ({ canvasElement }) => {
+11 -24
View File
@@ -8,14 +8,7 @@ import React, {
useRef,
useState,
} from "react";
import {
BodyShort,
ErrorMessage,
Label,
mergeRefs,
omit,
useEventListener,
} from "../..";
import { BodyShort, ErrorMessage, Label, mergeRefs, omit } from "../..";
import { FormFieldProps, useFormField } from "../useFormField";
import SearchButton, { SearchButtonType } from "./SearchButton";
@@ -135,7 +128,6 @@ export const Search = forwardRef<HTMLInputElement, SearchProps>(
const searchRef = useRef<HTMLInputElement | null>(null);
const mergedRef = useMemo(() => mergeRefs([searchRef, ref]), [ref]);
const [wrapperRef, setWrapperRef] = useState<HTMLDivElement | null>(null);
const [internalValue, setInternalValue] = useState(defaultValue ?? "");
@@ -156,27 +148,22 @@ export const Search = forwardRef<HTMLInputElement, SearchProps>(
[handleChange, onClear]
);
useEventListener(
"keydown",
useCallback(
(e) => {
if (e.key === "Escape") {
e.preventDefault();
handleClear({ trigger: "Escape", event: e });
}
},
[handleClear]
),
wrapperRef
);
const handleClick = () => {
onSearchClick?.(`${value ?? internalValue}`);
};
return (
<div
ref={setWrapperRef}
onKeyDown={(e) => {
if (e.key !== "Escape") {
return;
}
searchRef.current?.value &&
searchRef.current?.value !== "" &&
e.preventDefault();
handleClear({ trigger: "Escape", event: e });
}}
className={cl(
className,
"navds-form-field",
+1 -1
View File
@@ -2,7 +2,7 @@ import * as React from "react";
import { BodyLong, Grid, Cell, ContentContainer } from "../index";
export default {
title: "ds-react/Grid",
title: "ds-react/Primitives/Grid",
component: { Grid, Cell },
parameters: {
layout: "fullscreen",
@@ -1,34 +0,0 @@
import React, { forwardRef, HTMLAttributes } from "react";
import cl from "clsx";
import { DefaultIllustration } from "./Illustration";
export interface GuideProps
extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
/**
* Custom svg/img element
*/
illustration?: React.ReactNode;
/**
* Predefined size properties for illustration
* @default "medium"
*/
size?: "small" | "medium";
}
const Guide = forwardRef<HTMLDivElement, GuideProps>(
({ className, illustration, size = "medium", color, ...rest }, ref) => {
return (
<div ref={ref} className={cl("navds-guide", className)} {...rest}>
<div
className={cl(
"navds-guide__illustration",
`navds-guide__illustration--${size}`
)}
>
{illustration ?? <DefaultIllustration />}
</div>
</div>
);
}
);
export default Guide;
@@ -1,6 +1,6 @@
import React, { forwardRef, HTMLAttributes } from "react";
import Guide from "./Guide";
import cl from "clsx";
import { DefaultIllustration } from "./Illustration";
export interface GuidePanelProps extends HTMLAttributes<HTMLDivElement> {
/**
@@ -12,14 +12,14 @@ export interface GuidePanelProps extends HTMLAttributes<HTMLDivElement> {
*/
illustration?: React.ReactNode;
/**
* Poster positions guide-illustation above content
* @default false, renders illustation left of content
* Render illustation above content
* @default true on mobile (<480px)
*/
poster?: boolean;
}
/**
* A component that displays a guide panel.
* A component for guiding users on the website
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/guidepanel)
* @see 🏷️ {@link GuidePanelProps}
@@ -34,18 +34,19 @@ export interface GuidePanelProps extends HTMLAttributes<HTMLDivElement> {
* ```
*/
export const GuidePanel = forwardRef<HTMLDivElement, GuidePanelProps>(
(
{ children, className, illustration, poster = false, color, ...rest },
ref
) => (
({ children, className, illustration, poster, ...rest }, ref) => (
<div
{...rest}
ref={ref}
className={cl("navds-guide-panel", className, {
"navds-guide-panel--poster": poster,
"navds-guide-panel--poster": poster === true,
"navds-guide-panel--not-poster": poster === false,
"navds-guide-panel--responsive-poster": poster === undefined,
})}
>
<Guide size={poster ? "medium" : "small"} illustration={illustration} />
<div className="navds-guide">
{illustration ?? <DefaultIllustration />}
</div>
<div className="navds-guide-panel__content">{children}</div>
</div>
)
@@ -20,9 +20,9 @@ export const DefaultIllustration: DefaultIllustrationType = ({
return (
<svg
width="42"
height="64"
viewBox="0 0 42 64"
width="56"
height="85"
viewBox="0 0 56 85"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-label="NAV veileder illustrasjon"
@@ -35,89 +35,65 @@ export const DefaultIllustration: DefaultIllustrationType = ({
<path
fillRule="evenodd"
clipRule="evenodd"
d="M32.8313 30.4421C31.7718 33.868 29.6975 36.7117 27.0391 38.452L27.1752 39.9777L27.1745 40.0397L25.7375 52.6154H16.6236L16.5857 52.3512L14.8238 40.0181L14.8891 38.4756C12.2173 36.7398 10.1312 33.8914 9.06565 30.4564C9.02952 30.4598 8.99291 30.4616 8.95588 30.4616C8.26662 30.4616 7.72058 29.8614 7.72058 29.1343V25.0202C7.72058 24.5328 7.96592 24.1022 8.33526 23.8712C8.9115 16.1905 14.3251 10.1539 20.946 10.1539C27.5491 10.1539 32.9517 16.1579 33.5525 23.8089C33.9838 24.0179 34.2794 24.4845 34.2794 25.0202V29.1343C34.2794 29.8618 33.7341 30.4616 33.0441 30.4616C32.9714 30.4616 32.9003 30.4549 32.8313 30.4421Z"
fill="#F1F1F1"
d="M43.1888 40.4308C41.795 44.9808 39.0663 48.7576 35.5693 51.069L35.7484 53.0952L35.7474 53.1777L33.857 69.8797H21.8679L21.8181 69.5289L19.5004 53.1489L19.5862 51.1002C16.0715 48.795 13.3274 45.0119 11.9257 40.4499C11.8781 40.4544 11.83 40.4566 11.7812 40.4566C10.8745 40.4566 10.1562 39.6595 10.1562 38.6939V33.2298C10.1562 32.5825 10.479 32.0106 10.9648 31.7039C11.7229 21.5028 18.8443 13.4855 27.554 13.4855C36.2401 13.4855 43.3472 21.4596 44.1376 31.6211C44.7049 31.8986 45.0937 32.5184 45.0937 33.2298V38.6939C45.0937 39.66 44.3765 40.4566 43.4687 40.4566C43.3731 40.4566 43.2796 40.4478 43.1888 40.4308Z"
fill="#F7F7F7"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M26.7182 38.8777C26.6663 41.624 24.1261 44.4415 21 44.4415C17.8604 44.4415 15.3116 41.5994 15.2813 38.8419C13.6546 39.2527 11.1714 40.4917 9.12177 42.5623C7.13699 44.5674 5.55884 47.5814 5.55884 49.9194V64H36.4412V49.9194C36.4412 47.5766 34.829 44.5575 32.8075 42.5501C30.7861 40.5427 28.3553 39.3204 26.7182 38.8777Z"
fill="#0056B4"
d="M35.1471 51.6345C35.0789 55.2819 31.7373 59.0239 27.625 59.0239C23.4949 59.0239 20.142 55.2493 20.1022 51.5869C17.9622 52.1325 14.6956 53.7781 11.9995 56.5281C9.38852 59.1912 7.3125 63.1941 7.3125 66.2993V85.0001H47.9375V66.2993C47.9375 63.1878 45.8167 59.178 43.1575 56.5119C40.4983 53.8458 37.3007 52.2225 35.1471 51.6345Z"
fill="#005B82"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M15.1786 38.9372C13.6802 39.4793 11.1664 40.6641 9.2647 42.4632C3.70588 41.2308 1.23529 38.3022 1.23529 38.3022C1.23529 38.3022 6.35673 33.325 6.35982 24.6197V24.6105C6.35982 14.4173 11.8831 7.38464 20.9827 7.38464C30.0836 7.38464 35.6068 14.4173 35.6068 24.6105H35.6396C35.6396 33.3219 40.7647 38.3022 40.7647 38.3022C40.7647 38.3022 38.2941 41.2308 32.7353 42.4616L32.7269 42.4632C30.8901 40.7984 28.2262 39.5144 26.7769 38.9715L26.7785 38.971L26.7209 38.3257L26.7521 38.2722C29.4867 36.5294 31.6086 33.5933 32.6316 30.0454C32.7569 30.1148 32.8983 30.1539 33.048 30.1539C33.5601 30.1539 33.9746 29.6984 33.9746 29.1343V25.0202C33.9746 24.5375 33.6712 24.134 33.2628 24.0275C33.2624 24.0219 33.262 24.0164 33.2616 24.0108C20.3323 25.4483 15.6749 16.616 15.2926 16.6154C15.2926 16.6154 10.9987 19.6923 8.94657 23.3506C8.94657 23.3506 8.6338 24.0412 8.63228 24.0644C8.28095 24.2092 8.03035 24.5821 8.03035 25.0202V29.1343C8.03035 29.6984 8.44586 30.1539 8.95693 30.1539C9.07019 30.1539 9.17868 30.1316 9.27895 30.0908C10.3132 33.6404 12.4486 36.5733 15.1961 38.3046L15.2063 38.3257L15.1804 38.9372H15.1786Z"
fill="#D05C4A"
d="M19.9671 51.7134C17.9959 52.4333 14.6891 54.0068 12.1875 56.3964C4.875 54.7595 1.625 50.87 1.625 50.87C1.625 50.87 8.36213 44.2596 8.3662 32.698V32.6857C8.3662 19.1478 15.6319 9.80762 27.6022 9.80762C39.5742 9.80762 46.8399 19.1478 46.8399 32.6857H46.883C46.883 44.2555 53.625 50.87 53.625 50.87C53.625 50.87 50.375 54.7595 43.0625 56.3942L43.0515 56.3964C40.6353 54.1853 37.1309 52.4799 35.2243 51.7589L35.2265 51.7582L35.1508 50.9012L35.1917 50.8302C38.7891 48.5155 41.5804 44.6159 42.9262 39.904C43.0909 39.9961 43.277 40.048 43.4739 40.048C44.1476 40.048 44.6928 39.4431 44.6928 38.6939V33.2298C44.6928 32.5887 44.2936 32.0528 43.7564 31.9114C43.7559 31.904 43.7554 31.8966 43.7549 31.8892C26.7466 33.7984 20.6199 22.068 20.117 22.0672C20.117 22.0672 14.4686 26.1538 11.769 31.0124C11.769 31.0124 11.3576 31.9296 11.3556 31.9605C10.8934 32.1527 10.5637 32.648 10.5637 33.2298V38.6939C10.5637 39.4431 11.1103 40.048 11.7826 40.048C11.9316 40.048 12.0743 40.0184 12.2062 39.9642C13.5668 44.6785 16.3759 48.5738 19.9901 50.8732L20.0035 50.9012L19.9695 51.7134H19.9671Z"
fill="#F25C5C"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M16.584 26.9976C15.7859 27.062 15.5625 25.8029 15.803 24.9807C15.8482 24.8249 16.1124 24.1154 16.5802 24.1154C17.0473 24.1154 17.2536 24.5032 17.2823 24.5699C17.6259 25.3715 17.4571 26.9268 16.584 26.9976"
fill="#23262a"
d="M21.8159 35.8563C20.766 35.9417 20.4722 34.2696 20.7885 33.1776C20.848 32.9706 21.1956 32.0283 21.8109 32.0283C22.4254 32.0283 22.6968 32.5434 22.7345 32.632C23.1865 33.6965 22.9645 35.7622 21.8159 35.8563"
fill="#262626"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M25.8405 26.9976C26.6386 27.062 26.862 25.8029 26.6215 24.9807C26.5763 24.8249 26.3121 24.1154 25.8444 24.1154C25.3772 24.1154 25.171 24.5032 25.1423 24.5699C24.7987 25.3715 24.9674 26.9268 25.8405 26.9976"
fill="#23262a"
d="M33.9927 35.8563C35.0425 35.9417 35.3364 34.2696 35.0201 33.1776C34.9606 32.9706 34.613 32.0283 33.9977 32.0283C33.3832 32.0283 33.1118 32.5434 33.0741 32.632C32.6221 33.6965 32.8441 35.7622 33.9927 35.8563"
fill="#262626"
/>
<path
d="M21.5081 28.2384C21.9854 28.157 22.3113 28.2081 22.428 28.3669C22.8687 28.9672 22.7277 29.6023 21.9718 30.1237C21.5744 30.3977 21.0273 30.4942 20.7377 30.3521C20.596 30.2826 20.4304 30.3536 20.3677 30.5106C20.3051 30.6676 20.3691 30.8512 20.5107 30.9207C20.9894 31.1555 21.7255 31.0257 22.268 30.6517C23.2953 29.9431 23.5304 28.8837 22.863 27.9743C22.5805 27.59 22.0806 27.5116 21.4228 27.6239C21.2697 27.65 21.1647 27.8088 21.1883 27.9784C21.2118 28.1481 21.355 28.2645 21.5081 28.2384Z"
fill="#23262a"
d="M28.2935 37.5041C28.9213 37.396 29.3501 37.4638 29.5036 37.6748C30.0833 38.4721 29.8979 39.3156 28.9035 40.0081C28.3806 40.372 27.661 40.5001 27.28 40.3114C27.0937 40.2191 26.8758 40.3133 26.7934 40.5218C26.7109 40.7304 26.7951 40.9742 26.9814 41.0665C27.6111 41.3784 28.5794 41.206 29.2931 40.7092C30.6445 39.7682 30.9537 38.3611 30.0758 37.1534C29.7042 36.643 29.0465 36.5389 28.1812 36.688C27.9799 36.7227 27.8418 36.9335 27.8728 37.1589C27.9038 37.3842 28.0921 37.5388 28.2935 37.5041Z"
fill="#262626"
/>
<path
d="M24.9595 32.3642C24.9315 32.4234 24.8672 32.5367 24.7639 32.686C24.589 32.9386 24.3694 33.1919 24.1027 33.4281C23.3079 34.1319 22.2735 34.5389 20.9568 34.5017C19.673 34.4654 18.6432 34.0647 17.8358 33.4185C17.5393 33.1813 17.2946 32.9272 17.0989 32.6739C16.9836 32.5246 16.9115 32.4114 16.88 32.3523C16.8043 32.2104 16.618 32.152 16.464 32.2218C16.31 32.2917 16.2466 32.4634 16.3224 32.6053C16.3681 32.6908 16.4569 32.8304 16.5927 33.0062C16.8156 33.2948 17.0928 33.5826 17.4283 33.8511C18.3398 34.5805 19.5046 35.0338 20.9378 35.0743C22.4302 35.1165 23.6233 34.6471 24.5333 33.8412C24.8376 33.5717 25.0877 33.2832 25.2878 32.9941C25.4095 32.8183 25.4887 32.6787 25.5291 32.5934C25.5977 32.4485 25.5259 32.2796 25.3686 32.2163C25.2113 32.153 25.0282 32.2192 24.9595 32.3642Z"
fill="#23262a"
d="M32.8337 42.9837C32.7968 43.0623 32.7122 43.2128 32.5763 43.411C32.3463 43.7465 32.0574 44.0829 31.7066 44.3966C30.6611 45.3314 29.3002 45.872 27.5683 45.8225C25.8795 45.7743 24.5247 45.2421 23.4626 44.3839C23.0726 44.0688 22.7506 43.7314 22.4933 43.395C22.3415 43.1967 22.2468 43.0463 22.2053 42.9679C22.1056 42.7794 21.8606 42.7018 21.6581 42.7946C21.4555 42.8873 21.3721 43.1153 21.4718 43.3039C21.5318 43.4174 21.6487 43.6029 21.8273 43.8363C22.1206 44.2196 22.4852 44.6018 22.9266 44.9584C24.1256 45.9272 25.6579 46.5292 27.5432 46.583C29.5064 46.6391 31.0759 46.0156 32.273 44.9453C32.6733 44.5874 33.0023 44.2042 33.2656 43.8202C33.4257 43.5867 33.5298 43.4014 33.5829 43.2881C33.6733 43.0955 33.5788 42.8713 33.3719 42.7872C33.165 42.7032 32.924 42.7911 32.8337 42.9837Z"
fill="#262626"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M32.1651 58H21.8343C21.3733 58 21 57.621 21 57.153V51.5143C21 51.0462 21.3733 50.6667 21.8343 50.6667H32.1651C32.6261 50.6667 33 51.0462 33 51.5143V57.153C33 57.621 32.6261 58 32.1651 58"
d="M41.8629 70.5H30.8865C30.3966 70.5 30 70.0974 30 69.6001V63.609C30 63.1117 30.3966 62.7084 30.8865 62.7084H41.8629C42.3527 62.7084 42.75 63.1117 42.75 63.609V69.6001C42.75 70.0974 42.3527 70.5 41.8629 70.5"
fill="white"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M27.6207 51.8307H26.5502C26.4709 51.8307 26.407 51.7671 26.407 51.6882V51.5086C26.407 51.4303 26.4709 51.3661 26.5502 51.3661H27.6207C27.7 51.3661 27.764 51.4303 27.764 51.5086V51.6882C27.764 51.7671 27.7 51.8307 27.6207 51.8307"
fill="#23262a"
d="M37.0345 63.9451H35.8971C35.8128 63.9451 35.7449 63.8775 35.7449 63.7937V63.6029C35.7449 63.5197 35.8128 63.4515 35.8971 63.4515H37.0345C37.1188 63.4515 37.1867 63.5197 37.1867 63.6029V63.7937C37.1867 63.8775 37.1188 63.9451 37.0345 63.9451"
fill="#262626"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M26.7756 51.6667H27.3958V50H26.7756V51.6667Z"
fill="#6A6A6A"
d="M36.1365 63.7708H36.7955V62H36.1365V63.7708Z"
fill="#8F8F8F"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M27.1269 56.6651C25.839 56.6651 24.7947 55.6208 24.7947 54.3327C24.7947 53.0444 25.839 52 27.1269 52C28.4153 52 29.4597 53.0444 29.4597 54.3327C29.4597 55.6208 28.4153 56.6651 27.1269 56.6651Z"
d="M40.5417 65.5H39.6457C39.6457 65.5 39.5839 65.5 39.5621 65.5545L39.0662 67.0725L38.5708 65.5545C38.5489 65.5 38.4868 65.5 38.4868 65.5H36.764C36.7267 65.5 36.6954 65.5311 36.6954 65.5682V66.0837C36.6954 65.6748 36.2603 65.5 36.0055 65.5C35.4349 65.5 35.053 65.8758 34.934 66.4472C34.9276 66.0681 34.8961 65.9323 34.794 65.7932C34.7471 65.7251 34.6793 65.6678 34.6055 65.6204C34.4535 65.5314 34.317 65.5 34.0237 65.5H33.6794C33.6794 65.5 33.6171 65.5 33.5952 65.5545L33.2818 66.331V65.5682C33.2818 65.5311 33.2508 65.5 33.2136 65.5H32.4167C32.4167 65.5 32.3552 65.5 32.3328 65.5545L32.0071 66.362C32.0071 66.362 31.9746 66.4427 32.0489 66.4427H32.3552V67.9813C32.3552 68.0195 32.3853 68.0497 32.4236 68.0497H33.2136C33.2508 68.0497 33.2818 68.0195 33.2818 67.9813V66.4427H33.5898C33.7664 66.4427 33.8039 66.4475 33.8726 66.4796C33.914 66.4952 33.9513 66.5268 33.9716 66.5633C34.0133 66.6417 34.0237 66.7359 34.0237 67.0135V67.9813C34.0237 68.0195 34.0544 68.0497 34.0923 68.0497H34.8494C34.8494 68.0497 34.935 68.0497 34.9688 67.9652L35.1366 67.5505C35.3597 67.863 35.7269 68.0497 36.1833 68.0497H36.283C36.283 68.0497 36.3691 68.0497 36.4032 67.9652L36.6954 67.2415V67.9813C36.6954 68.0195 36.7267 68.0497 36.764 68.0497H37.5368C37.5368 68.0497 37.6221 68.0497 37.6564 67.9652C37.6564 67.9652 37.9655 67.1978 37.9667 67.192H37.9671C37.979 67.1281 37.8983 67.1281 37.8983 67.1281H37.6225V65.8113L38.4904 67.9652C38.5243 68.0497 38.6097 68.0497 38.6097 68.0497H39.5228C39.5228 68.0497 39.6087 68.0497 39.6426 67.9652L40.6048 65.5826C40.6381 65.5 40.5417 65.5 40.5417 65.5V65.5ZM36.6954 67.128H36.1763C35.9696 67.128 35.8015 66.9607 35.8015 66.7538C35.8015 66.5473 35.9696 66.3789 36.1763 66.3789H36.3215C36.5276 66.3789 36.6954 66.5473 36.6954 66.7538V67.128Z"
fill="#C30000"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M23.6667 55.3511L24.1434 54.1712H24.6015L24.1254 55.3511H23.6667Z"
fill="#C30000"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M29.5496 55.3511L30.0202 54.1712H30.2699L29.7993 55.3511H29.5496Z"
fill="#C30000"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M30.4752 55.3511L30.9457 54.1712H31.0783L30.6077 55.3511H30.4752Z"
fill="#C30000"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M29.1165 54.1712H28.7019C28.7019 54.1712 28.6733 54.1712 28.6632 54.1964L28.4337 54.8989L28.2044 54.1964C28.1943 54.1712 28.1656 54.1712 28.1656 54.1712H27.3683C27.3511 54.1712 27.3366 54.1856 27.3366 54.2028V54.4413C27.3366 54.2521 27.1352 54.1712 27.0173 54.1712C26.7533 54.1712 26.5765 54.3451 26.5215 54.6095C26.5185 54.4341 26.5039 54.3713 26.4567 54.3069C26.435 54.2754 26.4036 54.2489 26.3695 54.2269C26.2991 54.1857 26.236 54.1712 26.1003 54.1712H25.9409C25.9409 54.1712 25.9121 54.1712 25.9019 54.1964L25.7569 54.5558V54.2028C25.7569 54.1856 25.7426 54.1712 25.7253 54.1712H25.3566C25.3566 54.1712 25.3281 54.1712 25.3178 54.1964L25.167 54.5701C25.167 54.5701 25.152 54.6074 25.1864 54.6074H25.3281V55.3194C25.3281 55.3371 25.342 55.3511 25.3598 55.3511H25.7253C25.7426 55.3511 25.7569 55.3371 25.7569 55.3194V54.6074H25.8994C25.9812 54.6074 25.9985 54.6097 26.0303 54.6245C26.0495 54.6317 26.0667 54.6464 26.0762 54.6632C26.0954 54.6995 26.1003 54.7431 26.1003 54.8716V55.3194C26.1003 55.3371 26.1145 55.3511 26.132 55.3511H26.4823C26.4823 55.3511 26.5219 55.3511 26.5376 55.312L26.6152 55.1201C26.7185 55.2647 26.8884 55.3511 27.0996 55.3511H27.1458C27.1458 55.3511 27.1856 55.3511 27.2014 55.312L27.3366 54.9771V55.3194C27.3366 55.3371 27.3511 55.3511 27.3683 55.3511H27.726C27.726 55.3511 27.7654 55.3511 27.7813 55.312C27.7813 55.312 27.9243 54.9569 27.9249 54.9542H27.9251C27.9306 54.9246 27.8933 54.9246 27.8933 54.9246H27.7656V54.3153L28.1672 55.312C28.1829 55.3511 28.2225 55.3511 28.2225 55.3511H28.645C28.645 55.3511 28.6847 55.3511 28.7004 55.312L29.1457 54.2094C29.1611 54.1712 29.1165 54.1712 29.1165 54.1712V54.1712ZM27.3366 54.9246H27.0964C27.0007 54.9246 26.9229 54.8472 26.9229 54.7515C26.9229 54.6559 27.0007 54.578 27.0964 54.578H27.1635C27.2589 54.578 27.3366 54.6559 27.3366 54.7515V54.9246Z"
fill="white"
/>
</svg>
);
};
@@ -1,10 +1,12 @@
import React from "react";
import { BodyLong, GuidePanel } from "../index";
import { BodyLong, GuidePanel, VStack } from "../index";
import { Meta } from "@storybook/react";
import { InformationIcon } from "@navikt/aksel-icons";
export default {
title: "ds-react/GuidePanel",
component: GuidePanel,
} as Meta;
} satisfies Meta<typeof GuidePanel>;
const panelText = `Sit sint eu dolore reprehenderit exercitation labore aute anim sit
adipisicing proident. Tempor ipsum ea cupidatat qui esse do veniam
@@ -12,18 +14,16 @@ cupidatat. Excepteur irure reprehenderit esse tempor nisi duis qui ea
enim id.`;
export const Default = {
render: (props) => {
const newProps = props?.colorOverride
render: (props: { poster: boolean; colorOverride: boolean }) => {
const style = props.colorOverride
? {
style: {
["--ac-guide-panel-illustration-bg" as any]: "var(--a-purple-200)",
["--ac-guide-panel-border" as any]: "var(--a-purple-400)",
},
"--ac-guide-panel-illustration-bg": "var(--a-purple-200)",
"--ac-guide-panel-border": "var(--a-purple-400)",
}
: {};
return (
<GuidePanel {...newProps} poster={props?.poster}>
<GuidePanel style={style} poster={props?.poster}>
{panelText}
</GuidePanel>
);
@@ -35,13 +35,34 @@ export const Default = {
},
};
export const Poster = () => <GuidePanel poster>{panelText}</GuidePanel>;
export const PosterVariants = {
render: () => (
<VStack gap="6" align="start">
<GuidePanel>
If you exclude the <code>poster</code> prop, you will get the poster
variant on mobile (&lt;480px) and the non-poster variant otherwise.
</GuidePanel>
<GuidePanel poster>
Use the <code>poster</code> prop to get the poster variant on all
viewports.
</GuidePanel>
<GuidePanel poster={false}>
Set <code>poster=false</code> to get the non-poster variant on all
viewports.
</GuidePanel>
</VStack>
),
parameters: {
chromatic: { viewports: [479, 800] },
},
};
export const ColorOverride = () => (
<GuidePanel
style={{
["--ac-guide-panel-illustration-bg" as any]: "var(--a-purple-200)",
["--ac-guide-panel-border" as any]: "var(--a-purple-400)",
"--ac-guide-panel-illustration-bg": "var(--a-purple-200)",
"--ac-guide-panel-border": "var(--a-purple-400)",
}}
>
{panelText}
@@ -63,3 +84,7 @@ export const Content = () => (
</BodyLong>
</GuidePanel>
);
export const CustomIllustration = () => (
<GuidePanel illustration={<InformationIcon />}>{panelText}</GuidePanel>
);
@@ -1,3 +1,2 @@
export { default as GuidePanel, type GuidePanelProps } from "./GuidePanel";
export { type GuideProps } from "./Guide";
export { DefaultIllustration as GuideDefaultIllustration } from "./Illustration";
+2
View File
@@ -32,6 +32,8 @@ export * from "./toggle-group";
export * from "./tooltip";
export * from "./typography";
export * from "./util";
export * from "./layout/box";
export * from "./layout/stack";
export * from "./layout/grid";
export * from "./layout/content-container";
export * from "./layout/responsive";
@@ -0,0 +1,384 @@
import React, { ReactNode } from "react";
import type { Meta } from "@storybook/react";
import { BodyLong, Detail, Heading } from "../../typography";
import { Box } from "./Box";
import { HGrid, HStack, VStack } from "../..";
import { BackgroundToken, BorderRadiiToken } from "../utilities/types";
import { ChevronRightIcon } from "@navikt/aksel-icons";
export default {
title: "ds-react/Primitives/Box",
component: Box,
} satisfies Meta<typeof Box>;
export const Default = {
render: () => (
<Box>
<BodyLong>
This is inside a box. Deserunt veniam eu fugiat ad est occaecat aliqua
nisi aliquip. Aute amet occaecat ex aliqua irure elit labore pariatur.
Proident pariatur proident pariatur magna consequat velit id commodo
quis sunt tempor ullamco aliquip pariatur.
</BodyLong>
</Box>
),
};
const Card = ({
background,
borderRadius = "xlarge",
children,
}: {
background?: BackgroundToken;
borderRadius?: BorderRadiiToken;
children: ReactNode;
}) => (
<Box
padding="4"
background={background}
borderColor="border-subtle"
borderRadius={borderRadius}
shadow="xsmall"
>
<div style={{ width: "20rem" }}>{children}</div>
</Box>
);
export const AsCard = {
render: () => {
return (
<HStack gap="4" justify="center">
<Card>
<h1>Card one</h1>
<BodyLong>
This is inside a box. Deserunt veniam eu fugiat ad est occaecat
aliqua nisi aliquip. Aute amet occaecat ex aliqua irure elit labore
</BodyLong>
</Card>
<Card>
<h1>Card two</h1>
<BodyLong>
This is inside a box. Deserunt veniam eu fugiat ad est occaecat
aliqua nisi aliquip. Aute amet occaecat ex aliqua irure elit labore
</BodyLong>
</Card>
<Card>
<h1>Card three</h1>
<BodyLong>
This is inside a box. Deserunt veniam eu fugiat ad est occaecat
aliqua nisi aliquip. Aute amet occaecat ex aliqua irure elit labore
</BodyLong>
</Card>
</HStack>
);
},
};
export const ThemingDemo = {
render: () => {
const LinkCard = () => {
return (
<>
<style>
{`
.link-card {
color: var(--navds-color-text-primary);
text-decoration: none;
}
.link-card:hover {
border-color: var(--a-border-action);
box-shadow: var(--a-shadow-small);
}
.link-card:hover .navds-heading {
color: var(--a-text-action);
text-decoration: underline;
}
.link-card:hover .link-card__chevron,
.link-card:focus-within .link-card__chevron {
transform: translateX(4px);
}
.link-card__chevron {
flex-shrink: 0;
font-size: 1.5rem;
transition: transform 200ms;
}
`}
</style>
<Box
as="a"
href="#"
className="link-card"
borderRadius="small"
borderColor="border-default"
padding="4"
onClick={() => alert("Clicked!")}
>
<HStack gap="4" align="center">
<VStack gap="2">
<Heading size="medium">
LinkCard som bruker Box, HStack og VStack
</Heading>
<BodyLong>This truly is inside a box!</BodyLong>
</VStack>
<ChevronRightIcon fontSize={24} className="link-card__chevron" />
</HStack>
</Box>
</>
);
};
const ChatBubble = () => {
return (
<>
<Box
background="surface-neutral-subtle"
shadow="xsmall"
padding="4"
borderRadius="xlarge xlarge xlarge 0"
>
<VStack gap="2">
<Detail>BOX • 01.01.21 14:00</Detail>
<BodyLong>
Hei! Dette er en chatbobble som bruker Box som base!
</BodyLong>
</VStack>
</Box>
</>
);
};
const PricePill = () => {
return (
<>
<style>
{`
.old-price {
text-decoration: line-through;
}
`}
</style>
<HStack>
<Box
background="surface-success-subtle"
shadow="xsmall"
padding="4"
borderRadius="full 0 0 full"
>
<VStack align="center">
<Detail>Episk ny pris</Detail>
<Heading size="medium">889.99 kr</Heading>
</VStack>
</Box>
<Box
background="surface-danger-subtle"
shadow="xsmall"
padding="4"
borderRadius="0 full full 0"
>
<VStack align="center">
<Detail>Førpris</Detail>
<Heading className="old-price" size="medium">
399.99 kr
</Heading>
</VStack>
</Box>
</HStack>
</>
);
};
return (
<VStack gap="8">
<Card>Dette er et Card som bruker Box som base</Card>
<LinkCard />
<ChatBubble />
<PricePill />
</VStack>
);
},
};
export const PaddingBreakpoints = {
render: () => (
<div>
<Box
padding={{ xs: "2", sm: "3", md: "4", lg: "5", xl: "6" }}
borderColor="border-default"
>
<BodyLong>
This is inside a box. Deserunt veniam eu fugiat ad est occaecat aliqua
nisi aliquip. Aute amet occaecat ex aliqua irure elit labore pariatur.
Proident pariatur proident pariatur magna consequat velit id commodo
quis sunt tempor ullamco aliquip pariatur.
</BodyLong>
</Box>
</div>
),
};
export const PaddingBreakpointsInherit1 = {
render: () => (
<div>
<Box
padding={{ xs: "2" }}
paddingInline={{ md: "24 0" }}
borderColor="border-default"
>
<BodyLong>
This is inside a box. Deserunt veniam eu fugiat ad est occaecat aliqua
nisi aliquip. Aute amet occaecat ex aliqua irure elit labore pariatur.
Proident pariatur proident pariatur magna consequat velit id commodo
quis sunt tempor ullamco aliquip pariatur.
</BodyLong>
</Box>
</div>
),
};
export const PaddingBreakpointsInherit2 = {
render: () => (
<div>
<Box
padding={{ xs: "2", sm: "3" }}
paddingInline={{ sm: "4 0", md: "24 0" }}
borderColor="border-default"
>
<BodyLong>
This is inside a box. Deserunt veniam eu fugiat ad est occaecat aliqua
nisi aliquip. Aute amet occaecat ex aliqua irure elit labore pariatur.
Proident pariatur proident pariatur magna consequat velit id commodo
quis sunt tempor ullamco aliquip pariatur.
</BodyLong>
</Box>
</div>
),
};
export const Padding = {
render: () => (
<>
<style>
{`
.navds-box {
width: fit-content;
}
`}
</style>
<VStack align="center">
<Box padding="20" borderColor="border-default">
<BodyLong>Padding all around</BodyLong>
</Box>
<Box padding="1" paddingBlock="20 0" borderColor="border-default">
<BodyLong>Padding to the North</BodyLong>
</Box>
<Box padding="1" paddingInline="0 20" borderColor="border-default">
<BodyLong>Padding to the East</BodyLong>
</Box>
<Box padding="1" paddingBlock="0 20" borderColor="border-default">
<BodyLong>Padding to the South</BodyLong>
</Box>
<Box padding="1" paddingInline="20 0" borderColor="border-default">
<BodyLong>Padding to the West</BodyLong>
</Box>
</VStack>
</>
),
};
export const WithHGrid = () => {
return (
<Box background="bg-subtle" padding="10">
<HGrid
gap="6"
columns={{ xs: "repeat(auto-fit, minmax(10rem, 1fr))", md: 4 }}
>
<Box padding="4" background="bg-default">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec
</Box>
<Box padding="4" background="bg-default">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec
</Box>
<Box padding="4" background="bg-default">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec
</Box>
<Box padding="4" background="bg-default">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec
</Box>
</HGrid>
</Box>
);
};
export const BorderWidth = () => {
return (
<VStack gap="4">
<Box
background="bg-subtle"
padding="10"
borderWidth="2"
borderColor="border-strong"
>
Box
</Box>
<Box
background="bg-subtle"
padding="10"
borderWidth="1 2 3 4"
borderColor="border-strong"
>
Box
</Box>
<Box
background="bg-subtle"
padding="10"
borderWidth="5 2 4 1"
borderColor="border-strong"
borderRadius="large"
>
Box
</Box>
</VStack>
);
};
export const BorderRadius = () => {
return (
<VStack gap="4">
<Box
background="bg-subtle"
padding="10"
borderWidth="2"
borderColor="border-strong"
borderRadius="small medium large xlarge"
>
Box
</Box>
<Box
background="bg-subtle"
padding="10"
borderWidth="2"
borderColor="border-strong"
borderRadius={{
xs: "small medium large xlarge",
md: "medium small large full",
lg: "xlarge large",
}}
>
Box
</Box>
</VStack>
);
};
export const PaddingDemo = () => {
return (
<VStack gap="4">
<Box
background="bg-subtle"
padding="0"
paddingInline={{ xs: "20", lg: "10" }}
>
Box
</Box>
</VStack>
);
};
+148
View File
@@ -0,0 +1,148 @@
import cl from "clsx";
import React, { forwardRef } from "react";
import { OverridableComponent } from "../../util/OverridableComponent";
import { BorderRadiiToken } from "../utilities/types";
import {
SpaceDelimitedAttribute,
ResponsiveProp,
SpacingScale,
getResponsiveProps,
} from "../utilities/css";
import {
BackgroundToken,
BorderColorToken,
ShadowToken,
} from "../utilities/types";
export interface BoxProps extends React.HTMLAttributes<HTMLDivElement> {
/** Background color. Accepts a color token. */
background?: BackgroundToken;
/** Border color. Accepts a color token. */
borderColor?: BorderColorToken;
/** Border radius. Accepts a radius token, or an object of radius tokens for different breakpoints.
* @example
* borderRadius='full'
* borderRadius='0 full large small'
* borderRadius={{xs: 'small large', sm: '0', md: 'large', lg: 'full'}}
*/
borderRadius?: ResponsiveProp<SpaceDelimitedAttribute<BorderRadiiToken>>;
/**
* Border-width. If this is not set there will be no border.
* @example
* borderWidth='2'
* borderWidth='1 2 3 4'
*/
borderWidth?: SpaceDelimitedAttribute<"0" | "1" | "2" | "3" | "4" | "5">;
/** Spacing around children. Accepts a spacing token or an object of spacing tokens for different breakpoints.
* @example
* padding='4'
* padding={{xs: '2', sm: '3', md: '4', lg: '5', xl: '6'}}
*/
padding?: ResponsiveProp<SpacingScale>;
/** Horizontal padding around children. Accepts a spacing token or an object of spacing tokens for different breakpoints.
* @example
* paddingInline='4'
* paddingInline='4 5'
* paddingInline={{xs: '0 32', sm: '3', md: '4 5', lg: '5', xl: '6'}}
*/
paddingInline?: ResponsiveProp<
SpacingScale | `${SpacingScale} ${SpacingScale}`
>;
/** Vertical padding around children. Accepts a spacing token or an object of spacing tokens for different breakpoints.
* @example
* paddingBlock='4'
* paddingBlock='4 5'
* paddingBlock={{xs: '2', sm: '3', md: '4', lg: '5', xl: '6'}}
*/
paddingBlock?: ResponsiveProp<
SpacingScale | `${SpacingScale} ${SpacingScale}`
>;
/** Shadow on box. Accepts a shadow token.
* @example
* shadow='small'
*/
shadow?: ShadowToken;
}
/**
* Foundational Layout-primitive for generic encapsulation & styling.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/primitives/box)
* @see 🏷️ {@link BoxProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
*
* @example
* <Box padding="4">
* <BodyShort>Hei</BodyShort>
* </Box>
*
* @example
* <Box padding={{xs: '2', sm: '3', md: '4', lg: '5', xl: '6'}}>
* <BodyShort>Hei</BodyShort>
* </Box>
*
* @example
* <VStack gap="8">
* <Box padding="4">
* <BodyShort>Hei</BodyShort>
* </Box>
* <Box padding="4">
* <BodyShort>Hei</BodyShort>
* </Box>
* </VStack>
*/
export const Box: OverridableComponent<BoxProps, HTMLDivElement> = forwardRef(
(
{
as: Component = "div",
background,
borderColor,
borderWidth,
borderRadius,
className,
padding,
paddingInline,
paddingBlock,
shadow,
style: _style,
...rest
},
ref
) => {
const style: React.CSSProperties = {
..._style,
"--__ac-box-background": background
? `var(--a-${background})`
: undefined,
"--__ac-box-shadow": shadow ? `var(--a-shadow-${shadow})` : undefined,
"--__ac-box-border-color": borderColor
? `var(--a-${borderColor})`
: undefined,
"--__ac-box-border-width": borderWidth
? borderWidth
.split(" ")
.map((x) => `${x}px`)
.join(" ")
: undefined,
...getResponsiveProps(
"box",
"border-radius",
"border-radius",
borderRadius,
["0"]
),
...getResponsiveProps("box", "padding", "spacing", padding),
...getResponsiveProps("box", "padding-inline", "spacing", paddingInline),
...getResponsiveProps("box", "padding-block", "spacing", paddingBlock),
};
return (
<Component
{...rest}
className={cl("navds-box", className)}
ref={ref}
style={style}
/>
);
}
);
@@ -0,0 +1 @@
export { Box, type BoxProps } from "./Box";
+7 -2
View File
@@ -26,11 +26,15 @@ export interface HGridProps extends HTMLAttributes<HTMLDivElement> {
* gap={{ sm: "2", md: "2", lg: "6", xl: "6"}}
*/
gap?: ResponsiveProp<SpacingScale>;
/**
* Vertical alignment of children. Elements will by default stretch to the height of parent-element.
*/
align?: "start" | "center" | "end";
}
/**
* Horizontal Grid Primitive with dynamic columns and gap based on breakpoints.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/hgrid)
* @see [📝 Documentation](https://aksel.nav.no/komponenter/primitives/hgrid)
* @see 🏷️ {@link HGridProps}
*
* @example
@@ -53,9 +57,10 @@ export interface HGridProps extends HTMLAttributes<HTMLDivElement> {
* </HGrid>
*/
export const HGrid = forwardRef<HTMLDivElement, HGridProps>(
({ className, columns, gap, style, ...rest }, ref) => {
({ className, columns, gap, style, align, ...rest }, ref) => {
const styles: React.CSSProperties = {
...style,
"--__ac-hgrid-align": align,
...getResponsiveProps(`hgrid`, "gap", "spacing", gap),
...getResponsiveValue(`hgrid`, "columns", formatGrid(columns)),
};
@@ -1,5 +1,6 @@
import React from "react";
import { HGrid } from ".";
import { VStack } from "../stack";
const columnsVariants = {
Number: "columnNumber",
@@ -8,7 +9,7 @@ const columnsVariants = {
};
export default {
title: "ds-react/HGrid",
title: "ds-react/Primitives/HGrid",
component: HGrid,
parameters: {
layout: "fullscreen",
@@ -86,12 +87,31 @@ export const DynamicColumns = {
),
};
function Placeholder({ text }) {
export const AlignItems = {
render: () => (
<VStack gap="8">
<HGrid gap="4" columns={2} align="start">
<Placeholder text="start" height="8rem" />
<Placeholder text="auto" height="auto" />
</HGrid>
<HGrid gap="4" columns={2} align="center">
<Placeholder text="center" height="8rem" />
<Placeholder text="auto" height="auto" />
</HGrid>
<HGrid gap="4" columns={2} align="end">
<Placeholder text="end" height="8rem" />
<Placeholder text="auto" height="auto" />
</HGrid>
</VStack>
),
};
function Placeholder({ text, height }: { text: string; height?: string }) {
return (
<div
style={{
background: "var(--a-deepblue-900)",
height: "5rem",
height: height ?? "5rem",
width: "auto",
color: "white",
}}
@@ -0,0 +1,96 @@
import cl from "clsx";
import React, { forwardRef, HTMLAttributes } from "react";
import { BreakpointsAlias } from "../utilities/css";
export interface ResponsiveProps extends HTMLAttributes<HTMLDivElement> {
children: React.ReactNode;
/**
* @example
* above='md'
*/
above?: Exclude<BreakpointsAlias, "xs">;
/**
* @example
* below='md'
*/
below?: Exclude<BreakpointsAlias, "xs">;
/**
* Overrides html-tag
* @default "div"
*/
as?: "div" | "span";
}
const Responsive = forwardRef<
HTMLDivElement,
ResponsiveProps & { variant: "show" | "hide" }
>(
(
{ as: Component = "div", className, above, below, variant, ...rest },
ref
) => {
const aboveProp = variant === "show" ? above : below;
const belowProp = variant === "show" ? below : above;
return (
<Component
{...rest}
ref={ref}
className={cl("navds-responsive", className, {
[`navds-responsive__above--${aboveProp}`]: aboveProp,
[`navds-responsive__below--${belowProp}`]: belowProp,
})}
/>
);
}
);
/**
* Responsive view Primitive to show/hide elements based on breakpoints
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/primitives/hide)
* @see 🏷️ {@link ResponsiveProps}
*
* @example
* <HGrid columns={{ xs: 1, md: 2 }} gap="4">
* <div/>
* <Hide below="md">
* // Only visible above "md"
* </Hide>
* </HGrid>
* @example
* <HGrid columns={{ xs: 1, md: 2 }} gap="4">
* <div/>
* <Hide above="md">
* // Only visible below "md"
* </Hide>
* </HGrid>
*/
export const Hide = forwardRef<HTMLDivElement, ResponsiveProps>(
(props, ref) => <Responsive {...props} ref={ref} variant="hide" />
);
/**
* Responsive view Primitive to show/hide elements based on breakpoints
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/primitives/show)
* @see 🏷️ {@link ResponsiveProps}
*
* @example
* <HGrid columns={{ xs: 1, md: 2 }} gap="4">
* <div/>
* <Show below="md">
* // Only visible below "md"
* </Show>
* </HGrid>
* @example
* <HGrid columns={{ xs: 1, md: 2 }} gap="4">
* <div/>
* <Show above="md">
* // Only visible above "md"
* </Show>
* </HGrid>
*/
export const Show = forwardRef<HTMLDivElement, ResponsiveProps>(
(props, ref) => <Responsive {...props} ref={ref} variant="show" />
);
@@ -0,0 +1,45 @@
import React from "react";
import type { Meta } from "@storybook/react";
import { Hide } from ".";
import { Tag } from "../../tag";
import { VStack } from "../stack";
export default {
title: "ds-react/Primitives/Hide",
component: Hide,
} satisfies Meta<typeof Hide>;
export const Default = {
render: () => (
<VStack gap="12">
<VStack gap="2" align="center">
<Hide above="xl">
<Tag variant="neutral">Visible below xl</Tag>
</Hide>
<Hide above="lg">
<Tag variant="neutral">Visible below lg</Tag>
</Hide>
<Hide above="md">
<Tag variant="neutral">Visible below md</Tag>
</Hide>
<Hide above="sm">
<Tag variant="neutral">Visible below sm</Tag>
</Hide>
</VStack>
<VStack gap="2" align="center">
<Hide below="xl">
<Tag variant="alt3">Visible above xl</Tag>
</Hide>
<Hide below="lg">
<Tag variant="alt3">Visible above lg</Tag>
</Hide>
<Hide below="md">
<Tag variant="alt3">Visible above md</Tag>
</Hide>
<Hide below="sm">
<Tag variant="alt3">Visible above sm</Tag>
</Hide>
</VStack>
</VStack>
),
};
@@ -0,0 +1 @@
export { Show, Hide, type ResponsiveProps } from "./Responsive";
@@ -0,0 +1,45 @@
import React from "react";
import type { Meta } from "@storybook/react";
import { Show } from ".";
import { Tag } from "../../tag";
import { VStack } from "../stack";
export default {
title: "ds-react/Primitives/Show",
component: Show,
} satisfies Meta<typeof Show>;
export const Default = {
render: () => (
<VStack gap="12">
<VStack gap="2" align="center">
<Show above="xl">
<Tag variant="neutral">Visible above xl</Tag>
</Show>
<Show above="lg">
<Tag variant="neutral">Visible above lg</Tag>
</Show>
<Show above="md">
<Tag variant="neutral">Visible above md</Tag>
</Show>
<Show above="sm">
<Tag variant="neutral">Visible above sm</Tag>
</Show>
</VStack>
<VStack gap="2" align="center">
<Show below="xl">
<Tag variant="alt3">Visible below xl</Tag>
</Show>
<Show below="lg">
<Tag variant="alt3">Visible below lg</Tag>
</Show>
<Show below="md">
<Tag variant="alt3">Visible below md</Tag>
</Show>
<Show below="sm">
<Tag variant="alt3">Visible below sm</Tag>
</Show>
</VStack>
</VStack>
),
};
@@ -7,7 +7,7 @@ export type HStackProps = Omit<StackProps, "direction">;
/**
* Layout-primitive for horizontal flexbox
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/Stack)
* @see [📝 Documentation](https://aksel.nav.no/komponenter/primitives/hstack)
* @see 🏷️ {@link HStackProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
*
@@ -3,7 +3,7 @@ import React from "react";
/**
* Layout-primitive for auto-spacing between elements
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/Stack)
* @see [📝 Documentation](https://aksel.nav.no/komponenter/primitives/hstack)
*
* @example
* <HStack gap="8">
@@ -52,14 +52,14 @@ export const Stack: OverridableComponent<StackProps, HTMLDivElement> =
},
ref
) => {
const style = {
const style: React.CSSProperties = {
..._style,
"--__ac-stack-direction": direction,
"--__ac-stack-align": align,
"--__ac-stack-justify": justify,
"--__ac-stack-wrap": wrap ? "wrap" : "nowrap",
...getResponsiveProps(`stack`, "gap", "spacing", gap),
} as React.CSSProperties;
};
return (
<Component
@@ -7,7 +7,7 @@ export type VStackProps = Omit<StackProps, "direction" | "wrap">;
/**
* Layout-primitive for vetical flexbox
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/Stack)
* @see [📝 Documentation](https://aksel.nav.no/komponenter/primitives/vstack)
* @see 🏷️ {@link VStackProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
*
@@ -3,7 +3,7 @@ import type { Meta } from "@storybook/react";
import { HStack, VStack, Spacer } from ".";
export default {
title: "ds-react/Stack",
title: "ds-react/Primitives/Stack",
component: HStack,
} satisfies Meta<typeof HStack>;
+47 -29
View File
@@ -1,4 +1,5 @@
export type BreakpointsAlias = "xs" | "sm" | "md" | "lg" | "xl";
export type SpacingScale =
| "0"
| "05"
@@ -21,43 +22,23 @@ export type SpacingScale =
| "24"
| "32";
type ResponsivePropConfig<T = string> = {
export type SpaceDelimitedAttribute<T extends string> =
| T
| `${T} ${T}`
| `${T} ${T} ${T}`
| `${T} ${T} ${T} ${T}`;
type FixedResponsiveT<T> = {
// eslint-disable-next-line no-unused-vars
[Breakpoint in BreakpointsAlias]?: T;
};
export type ResponsiveProp<T> = T | ResponsivePropConfig<T>;
export type ResponsiveValue<T = string> = undefined | ResponsiveProp<T>;
export function getResponsiveProps<T = string>(
componentName: string,
componentProp: string,
tokenSubgroup: string,
responsiveProp?: ResponsiveProp<T>
) {
if (!responsiveProp) {
return {};
}
if (typeof responsiveProp === "string") {
return {
[`--__ac-${componentName}-${componentProp}-xs`]: `var(--a-${tokenSubgroup}-${responsiveProp})`,
};
}
return Object.fromEntries(
Object.entries(responsiveProp).map(([breakpointAlias, aliasOrScale]) => [
`--__ac-${componentName}-${componentProp}-${breakpointAlias}`,
`var(--a-${tokenSubgroup}-${aliasOrScale})`,
])
);
}
export type ResponsiveProp<T> = T | FixedResponsiveT<T>;
export function getResponsiveValue<T = string>(
componentName: string,
componentProp: string,
responsiveProp?: ResponsiveValue<T>
responsiveProp?: ResponsiveProp<T>
) {
if (!responsiveProp) {
return {};
@@ -76,3 +57,40 @@ export function getResponsiveValue<T = string>(
])
);
}
export function getResponsiveProps<T extends string>(
componentName: string,
componentProp: string,
tokenSubgroup: string,
responsiveProp?: ResponsiveProp<T>,
tokenExceptions: string[] = []
) {
if (!responsiveProp) {
return {};
}
if (typeof responsiveProp === "string") {
return {
[`--__ac-${componentName}-${componentProp}-xs`]: responsiveProp
.split(" ")
.map((x) =>
tokenExceptions.includes(x) ? x : `var(--a-${tokenSubgroup}-${x})`
)
.join(" "),
};
}
return Object.fromEntries(
Object.entries(responsiveProp).map(([breakpointAlias, aliasOrScale]) => {
return [
`--__ac-${componentName}-${componentProp}-${breakpointAlias}`,
aliasOrScale
.split(" ")
.map((x) =>
tokenExceptions.includes(x) ? x : `var(--a-${tokenSubgroup}-${x})`
)
.join(" "),
];
})
);
}
@@ -0,0 +1,14 @@
import bgColors from "@navikt/ds-tokens/src/colors-bg.json";
import surfaceColors from "@navikt/ds-tokens/src/colors-surface.json";
import borderColors from "@navikt/ds-tokens/src/colors-border.json";
import borderRadii from "@navikt/ds-tokens/src/border.json";
import shadows from "@navikt/ds-tokens/src/shadow.json";
export type BackgroundToken =
| keyof typeof bgColors.a
| keyof typeof surfaceColors.a;
export type BorderColorToken = keyof typeof borderColors.a;
export type BorderRadiiToken =
| keyof (typeof borderRadii.a)["border-radius"]
| "0";
export type ShadowToken = keyof typeof shadows.a.shadow;
+1
View File
@@ -69,4 +69,5 @@ export const ListItem = forwardRef<HTMLLIElement, ListItemProps>(
}
);
ListItem.displayName = "List.Item";
export default ListItem;
+1 -1
View File
@@ -192,6 +192,7 @@ export const Modal = forwardRef<HTMLDialogElement, ModalProps>(
const component = (
<dialog
{...rest}
ref={mergedRef}
className={cl("navds-modal", className, {
"navds-modal--polyfilled": needPolyfill,
@@ -213,7 +214,6 @@ export const Modal = forwardRef<HTMLDialogElement, ModalProps>(
? ariaLabelId
: ariaLabelledby
}
{...rest}
>
<ModalContext.Provider
value={{
@@ -16,7 +16,7 @@ export const WithUseRef = () => {
const ref2 = useRef<HTMLDialogElement>(null);
return (
<>
<div>
<Button onClick={() => ref.current?.showModal()}>Open Modal</Button>
<Modal
open={ref.current ? undefined : true /* initially open */}
@@ -80,7 +80,7 @@ export const WithUseRef = () => {
<Button variant="tertiary">Tertiary</Button>
</Modal.Footer>
</Modal>
</>
</div>
);
};
WithUseRef.storyName = "With useRef";
@@ -184,6 +184,7 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
useCallback(
(e: FocusEvent) => {
if (
e.target instanceof HTMLElement &&
![anchorEl, refs?.floating?.current].some((element) =>
element?.contains(e.target as Node)
)
+9
View File
@@ -0,0 +1,9 @@
// eslint-disable-next-line react/no-typos
import "react";
declare module "react" {
interface CSSProperties {
[key: `--ac-${string}`]: string | undefined;
[key: `--__ac-${string}`]: string | undefined;
}
}
+18 -3
View File
@@ -15,6 +15,11 @@ export interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {
* When not inferring width from children, you must specify width
*/
width?: number | string;
/**
* Overrides html-tag
* @default "div"
*/
as?: "div" | "span";
}
/**
@@ -28,11 +33,20 @@ export interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {
*/
export const Skeleton = forwardRef<HTMLDivElement, SkeletonProps>(
(
{ className, children, height, width, style, variant = "text", ...rest },
{
className,
children,
height,
width,
style,
variant = "text",
as: As = "div",
...rest
},
ref
) => {
return (
<div
<As
{...rest}
ref={ref}
className={cl(
@@ -43,13 +57,14 @@ export const Skeleton = forwardRef<HTMLDivElement, SkeletonProps>(
"navds-skeleton--has-children": Boolean(children),
"navds-skeleton--no-height": !height,
"navds-skeleton--no-width": !width,
"navds-skeleton--inline": As === "span",
}
)}
style={{ ...style, width, height }}
aria-hidden
>
{children}
</div>
</As>
);
}
);
@@ -102,7 +102,7 @@ export const NativeText = {
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
magnam? Saepe, eveniet?
</Skeleton>
</h1>
<Skeleton>
@@ -110,9 +110,21 @@ export const NativeText = {
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
magnam? Saepe, eveniet?
</p>
</Skeleton>
</div>
),
};
export const InlineText = {
render: () => (
<BodyLong>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur
voluptas sint dolore <Skeleton width="40px" as="span" variant="text" />{" "}
beatae vero cum officia debitis. Quidem debitis omnis reprehenderit nobis{" "}
<Skeleton as="span">test text</Skeleton> rerum. Nulla, magnam? Saepe,
eveniet?
</BodyLong>
),
};
@@ -14,7 +14,7 @@ export default {
const rowsPerPage = 10;
const queryString = (obj) =>
const queryString = (obj: Record<string, number | string | undefined>) =>
Object.keys(obj)
.filter((key) => obj[key] !== undefined)
.map((key) => key + "=" + obj[key])
@@ -22,11 +22,15 @@ const queryString = (obj) =>
const updateData = async (url: string) => {
const newUrl = new URL(`https://www.example.com/${url}`);
const comparator = (a, b, orderBy) => {
if (b[orderBy] < a[orderBy]) {
const comparator = (
a: Record<string, string | number | null>,
b: Record<string, string | number | null>,
orderBy: string
) => {
if ((b[orderBy] ?? "") < (a[orderBy] ?? "")) {
return -1;
}
if (b[orderBy] > a[orderBy]) {
if ((b[orderBy] ?? "") > (a[orderBy] ?? "")) {
return 1;
}
return 0;
@@ -74,7 +78,14 @@ export const Async = () => {
const { results: people, count } = data;
const columns = [
type ColumnsType = {
key: keyof (typeof people)[0];
name: string;
width: number;
sortable?: boolean;
value?: (person: (typeof people)[0]) => string | undefined;
};
const columns: ColumnsType[] = [
{ key: "name", name: "Name", width: 154 },
{ key: "height", name: "Height", width: 108 },
{ key: "mass", name: "Mass", width: 95 },
@@ -105,7 +116,8 @@ export const Async = () => {
sort={sort}
onSortChange={(sortKey) =>
setSort(
sort?.orderBy === sortKey && sort.direction === "descending"
!sortKey ||
(sort?.orderBy === sortKey && sort.direction === "descending")
? undefined
: {
orderBy: sortKey,
@@ -144,7 +156,7 @@ export const Async = () => {
whiteSpace: "nowrap",
textOverflow: "ellipsis",
}}
title={person[key]}
title={person[key]?.toString()}
key={key}
>
{value ? value(person) : person[key]}
+36 -15
View File
@@ -1,22 +1,21 @@
import React, { forwardRef } from "react";
import cl from "clsx";
import { OverridableComponent } from "../util/OverridableComponent";
import { TypoProps } from "./types";
import { typoClassNames } from "./util";
export interface BodyLongProps
extends React.HTMLAttributes<HTMLParagraphElement> {
extends TypoProps,
React.HTMLAttributes<HTMLParagraphElement> {
/**
* medium: 18px, small: 16px
* large: 20px, medium: 18px, small: 16px
* @default "medium"
*/
size?: "medium" | "small";
size?: "large" | "medium" | "small";
/**
* Paragraph text
* Text
*/
children: React.ReactNode;
/**
* Adds margin-bottom
*/
spacing?: boolean;
}
/**
@@ -28,8 +27,10 @@ export interface BodyLongProps
*
* @example
* ```jsx
* <BodyLong level="1" size="xlarge">
* Pengestøtte når du er syk
* <BodyLong>
* Hvis du ikke bor sammen med begge foreldrene dine,
* kan du ha rett til barnebidrag fra en eller begge foreldre mens du
* fullfører videregående skole eller tilsvarende.
* </BodyLong>
* ```
*/
@@ -38,16 +39,36 @@ export const BodyLong: OverridableComponent<
HTMLParagraphElement
> = forwardRef(
(
{ className, size = "medium", spacing, as: Component = "p", ...rest },
{
className,
size = "medium",
as: Component = "p",
spacing,
truncate,
weight = "regular",
align,
visuallyHidden,
textColor,
...rest
},
ref
) => (
<Component
{...rest}
ref={ref}
className={cl(className, "navds-body-long", {
"navds-body-long--small": size === "small",
"navds-typo--spacing": !!spacing,
})}
className={cl(
className,
"navds-body-long",
`navds-body-long--${size}`,
typoClassNames({
spacing,
truncate,
weight,
align,
visuallyHidden,
textColor,
})
)}
/>
)
);
+34 -15
View File
@@ -1,22 +1,21 @@
import React, { forwardRef } from "react";
import cl from "clsx";
import React, { forwardRef } from "react";
import { OverridableComponent } from "../util/OverridableComponent";
import { TypoProps } from "./types";
import { typoClassNames } from "./util";
export interface BodyShortProps
extends React.HTMLAttributes<HTMLParagraphElement> {
extends TypoProps,
React.HTMLAttributes<HTMLParagraphElement> {
/**
* medium: 18px, small: 16px
* large: 20px, medium: 18px, small: 16px
* @default "medium"
*/
size?: "medium" | "small";
size?: "large" | "medium" | "small";
/**
* Paragraph text
*/
children: React.ReactNode;
/**
* Adds margin-bottom
*/
spacing?: boolean;
}
/**
@@ -28,8 +27,8 @@ export interface BodyShortProps
*
* @example
* ```jsx
* <BodyShort level="1" size="xlarge">
* Pengestøtte når du er syk
* <BodyShort>
* Du må gjøre en filtrering for å se brukere i listen.
* </BodyShort>
* ```
*/
@@ -38,16 +37,36 @@ export const BodyShort: OverridableComponent<
HTMLParagraphElement
> = forwardRef(
(
{ className, size = "medium", spacing, as: Component = "p", ...rest },
{
className,
size = "medium",
as: Component = "p",
spacing,
truncate,
weight = "regular",
align,
visuallyHidden,
textColor,
...rest
},
ref
) => (
<Component
{...rest}
ref={ref}
className={cl(className, "navds-body-short", {
"navds-body-short--small": size === "small",
"navds-typo--spacing": !!spacing,
})}
className={cl(
className,
"navds-body-short",
`navds-body-short--${size}`,
typoClassNames({
spacing,
truncate,
weight,
align,
visuallyHidden,
textColor,
})
)}
/>
)
);
+28 -13
View File
@@ -1,9 +1,12 @@
import React, { forwardRef } from "react";
import cl from "clsx";
import React, { forwardRef } from "react";
import { OverridableComponent } from "../util/OverridableComponent";
import { TypoProps } from "./types";
import { typoClassNames } from "./util";
export interface DetailProps
extends React.HTMLAttributes<HTMLParagraphElement> {
extends TypoProps,
React.HTMLAttributes<HTMLParagraphElement> {
/**
* @deprecated Medium === small
*/
@@ -12,10 +15,6 @@ export interface DetailProps
* Paragraph text
*/
children: React.ReactNode;
/**
* Adds margin-bottom
*/
spacing?: boolean;
/**
* All caps
*/
@@ -31,8 +30,8 @@ export interface DetailProps
*
* @example
* ```jsx
* <Detail level="1" size="xlarge">
* Pengestøtte når du er syk
* <Detail>
* Du må gjøre en filtrering for å se brukere i listen.
* </Detail>
* ```
*/
@@ -45,6 +44,11 @@ export const Detail: OverridableComponent<DetailProps, HTMLParagraphElement> =
spacing,
uppercase,
as: Component = "p",
truncate,
weight = "regular",
align,
visuallyHidden,
textColor,
...rest
},
ref
@@ -52,11 +56,22 @@ export const Detail: OverridableComponent<DetailProps, HTMLParagraphElement> =
<Component
{...rest}
ref={ref}
className={cl(className, "navds-detail", {
"navds-detail--small": size === "small",
"navds-typo--spacing": !!spacing,
"navds-typo--uppercase": !!uppercase,
})}
className={cl(
className,
"navds-detail",
typoClassNames({
spacing,
truncate,
weight,
align,
visuallyHidden,
textColor,
uppercase,
}),
{
"navds-detail--small": size === "small",
}
)}
/>
)
);
@@ -1,9 +1,12 @@
import React, { forwardRef } from "react";
import cl from "clsx";
import { OverridableComponent } from "../util/OverridableComponent";
import { TypoProps } from "./types";
import { typoClassNames } from "./util";
export interface ErrorMessageProps
extends React.HTMLAttributes<HTMLParagraphElement> {
extends Pick<TypoProps, "spacing">,
React.HTMLAttributes<HTMLParagraphElement> {
/**
* medium: 18px, small: 16px
* @default "medium"
@@ -13,10 +16,6 @@ export interface ErrorMessageProps
* Error text
*/
children: React.ReactNode;
/**
* Adds margin-bottom
*/
spacing?: boolean;
}
/**
@@ -28,8 +27,8 @@ export interface ErrorMessageProps
*
* @example
* ```jsx
* <ErrorMessage level="1" size="xlarge">
* Pengestøtte når du er syk
* <ErrorMessage>
* Du må fylle ut: Oppgi årsaken til at du har ventet mer enn 6 måneder med å søke om refusjon
* </ErrorMessage>
* ```
*/
@@ -41,10 +40,17 @@ export const ErrorMessage: OverridableComponent<
<Component
{...rest}
ref={ref}
className={cl("navds-error-message", "navds-label", className, {
"navds-label--small": size === "small",
"navds-typo--spacing": !!spacing,
})}
className={cl(
"navds-error-message",
"navds-label",
className,
typoClassNames({
spacing,
}),
{
"navds-label--small": size === "small",
}
)}
/>
)
);
+32 -12
View File
@@ -1,8 +1,12 @@
import React, { forwardRef } from "react";
import cl from "clsx";
import React, { forwardRef } from "react";
import { OverridableComponent } from "../util/OverridableComponent";
import { TypoProps } from "./types";
import { typoClassNames } from "./util";
export interface HeadingProps extends React.HTMLAttributes<HTMLHeadingElement> {
export interface HeadingProps
extends Pick<TypoProps, "spacing" | "visuallyHidden" | "align" | "textColor">,
React.HTMLAttributes<HTMLHeadingElement> {
/**
* Heading level
* @default "1"
@@ -16,11 +20,6 @@ export interface HeadingProps extends React.HTMLAttributes<HTMLHeadingElement> {
* Heading text
*/
children: React.ReactNode;
/**
* Adds margin-bottom
* @default false
*/
spacing?: boolean;
}
/**
@@ -33,22 +32,43 @@ export interface HeadingProps extends React.HTMLAttributes<HTMLHeadingElement> {
* @example
* ```jsx
* <Heading level="1" size="xlarge">
* Pengestøtte når du er syk
* Hva kan vi hjelpe deg med?
* </Heading>
* ```
*/
export const Heading: OverridableComponent<HeadingProps, HTMLHeadingElement> =
forwardRef(
({ level = "1", size, spacing = false, className, as, ...rest }, ref) => {
(
{
level = "1",
size,
className,
as,
spacing,
align,
visuallyHidden,
textColor,
...rest
},
ref
) => {
let HeadingTag = as ?? (`h${level}` as React.ElementType);
return (
<HeadingTag
{...rest}
ref={ref}
className={cl(className, "navds-heading", `navds-heading--${size}`, {
"navds-typo--spacing": spacing,
})}
className={cl(
className,
"navds-heading",
`navds-heading--${size}`,
typoClassNames({
spacing,
align,
visuallyHidden,
textColor,
})
)}
/>
);
}
@@ -15,6 +15,8 @@ export interface IngressProps
}
/**
* @deprecated Use `<BodyLong size="large" />`
*
* Part of a set of components for displaying text with consistent typography.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/typography)
@@ -23,8 +25,8 @@ export interface IngressProps
*
* @example
* ```jsx
* <Ingress level="1" size="xlarge">
* Pengestøtte når du er syk
* <Ingress>
* Hvis du ikke bor sammen med begge foreldrene dine, kan du ha rett til barnebidrag fra en eller begge foreldre mens du fullfører videregående skole eller tilsvarende.
* </Ingress>
* ```
*/
+28 -13
View File
@@ -1,9 +1,12 @@
import React, { forwardRef } from "react";
import cl from "clsx";
import React, { forwardRef } from "react";
import { OverridableComponent } from "../util/OverridableComponent";
import { TypoProps } from "./types";
import { typoClassNames } from "./util";
export interface LabelProps
extends React.LabelHTMLAttributes<HTMLLabelElement> {
extends Omit<TypoProps, "weight" | "align" | "truncate">,
React.LabelHTMLAttributes<HTMLLabelElement> {
/**
* medium: 18px, small: 16px
* @default "medium"
@@ -13,10 +16,6 @@ export interface LabelProps
* Paragraph text
*/
children: React.ReactNode;
/**
* Adds margin-bottom
*/
spacing?: boolean;
}
/**
@@ -28,24 +27,40 @@ export interface LabelProps
*
* @example
* ```jsx
* <Label level="1" size="xlarge">
* Pengestøtte når du er syk
* <Label>
* Oppgi årsaken til at du har ventet mer enn 6 måneder med å søke om refusjon
* </Label>
* ```
*/
export const Label: OverridableComponent<LabelProps, HTMLLabelElement> =
forwardRef(
(
{ className, size = "medium", spacing, as: Component = "label", ...rest },
{
className,
size = "medium",
as: Component = "label",
spacing,
visuallyHidden,
textColor,
...rest
},
ref
) => (
<Component
{...rest}
ref={ref}
className={cl(className, "navds-label", {
"navds-label--small": size === "small",
"navds-typo--spacing": !!spacing,
})}
className={cl(
className,
"navds-label",
typoClassNames({
spacing,
visuallyHidden,
textColor,
}),
{
"navds-label--small": size === "small",
}
)}
/>
)
);
@@ -1,77 +0,0 @@
import { Meta } from "@storybook/react";
import React from "react";
import { Heading } from "..";
export default {
title: "ds-react/Typography/Heading",
component: Heading,
argTypes: {
size: {
defaultValue: "large",
control: {
type: "radio",
options: ["xlarge", "large", "medium", "small", "xsmall"],
},
},
level: {
defaultValue: "1",
control: {
type: "radio",
options: ["1", "2", "3", "4", "5", "6"],
},
},
},
} as Meta;
const lorem = "Veniam consequat cillum";
export const Default = {
render: (props) => <Heading {...props}>{lorem}</Heading>,
args: {
spacing: false,
},
};
export const Sizes = () => (
<div className="colgap">
<Heading level="1" size="xlarge">
{lorem}
</Heading>
<Heading level="2" size="large">
{lorem}
</Heading>
<Heading level="3" size="medium">
{lorem}
</Heading>
<Heading level="4" size="small">
{lorem}
</Heading>
<Heading level="5" size="xsmall">
{lorem}
</Heading>
</div>
);
export const Spacing = () => (
<div>
<Heading level="1" size="xlarge" spacing>
{lorem}
</Heading>
<Heading level="2" size="large" spacing>
{lorem}
</Heading>
<Heading level="3" size="medium" spacing>
{lorem}
</Heading>
<Heading level="4" size="small" spacing>
{lorem}
</Heading>
<Heading level="5" size="xsmall" spacing>
{lorem}
</Heading>
<Heading level="5" size="xsmall">
{lorem}
</Heading>
</div>
);
@@ -0,0 +1,165 @@
import { expect } from "@storybook/jest";
import type { Meta, StoryObj } from "@storybook/react";
import { within } from "@storybook/testing-library";
import React from "react";
import { BodyLong } from "..";
import { VStack } from "../..";
const meta = {
title: "ds-react/Typography/BodyLong",
component: BodyLong,
decorators: [(story) => <div style={{ maxWidth: "700px" }}>{story()}</div>],
} satisfies Meta<typeof BodyLong>;
export default meta;
type Story = StoryObj<typeof meta>;
const lorem =
"Hvis du ikke bor sammen med begge foreldrene dine, kan du ha rett til barnebidrag fra en eller begge foreldre mens du fullfører videregående skole eller tilsvarende.";
export const Default: Story = {
args: {
spacing: false,
children: lorem,
truncate: false,
visuallyHidden: false,
},
argTypes: {
size: {
control: "radio",
options: ["large", "medium", "small"],
},
weight: {
control: "radio",
options: ["regular", "semibold"],
},
align: {
control: "radio",
options: ["start", "center", "end"],
},
textColor: {
control: "radio",
options: ["default", "subtle"],
},
},
};
export const SizeLarge: Story = {
render: () => (
<VStack gap="4">
<BodyLong size="large">{lorem}</BodyLong>
<BodyLong size="large" weight="semibold">
{lorem}
</BodyLong>
<BodyLong size="large" truncate>
{lorem}
</BodyLong>
</VStack>
),
};
export const SizeMedium: Story = {
render: () => (
<VStack gap="2">
<BodyLong size="medium">{lorem}</BodyLong>
<BodyLong size="medium" weight="semibold">
{lorem}
</BodyLong>
<BodyLong size="medium" truncate>
{lorem}
</BodyLong>
</VStack>
),
};
export const SizeSmall: Story = {
render: () => (
<VStack gap="2">
<BodyLong size="small">{lorem}</BodyLong>
<BodyLong size="small" weight="semibold">
{lorem}
</BodyLong>
<BodyLong size="small" truncate>
{lorem}
</BodyLong>
</VStack>
),
};
export const SpacingLarge: Story = {
render: () => (
<div>
<BodyLong size="large" spacing>
{lorem}
</BodyLong>
<BodyLong size="large" spacing>
{lorem}
</BodyLong>
</div>
),
};
export const SpacingMedium: Story = {
render: () => (
<div>
<BodyLong size="medium" spacing>
{lorem}
</BodyLong>
<BodyLong size="medium" spacing>
{lorem}
</BodyLong>
</div>
),
};
export const SpacingSmall: Story = {
render: () => (
<div>
<BodyLong size="small" spacing>
{lorem}
</BodyLong>
<BodyLong size="small" spacing>
{lorem}
</BodyLong>
</div>
),
};
export const Colors: Story = {
render: () => (
<VStack gap="2">
<BodyLong textColor="default">{lorem}</BodyLong>
<BodyLong textColor="subtle">{lorem}</BodyLong>
</VStack>
),
};
export const Align: Story = {
render: () => (
<VStack gap="2">
<BodyLong align="start">{lorem}</BodyLong>
<BodyLong align="center">{lorem}</BodyLong>
<BodyLong align="end">{lorem}</BodyLong>
</VStack>
),
};
export const OverrideTag: Story = {
render: () => (
<div>
<BodyLong spacing>default bodylong</BodyLong>
<BodyLong as="legend">legend bodylong</BodyLong>
</div>
),
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const defaultBodyLong = canvas.getByText("default bodylong");
const legendBodyLong = canvas.getByText("legend bodylong");
expect(defaultBodyLong.tagName).toEqual("P");
expect(legendBodyLong.tagName).toEqual("LEGEND");
},
};
@@ -0,0 +1,164 @@
import { expect } from "@storybook/jest";
import type { Meta, StoryObj } from "@storybook/react";
import { within } from "@storybook/testing-library";
import React from "react";
import { BodyShort } from "..";
import { VStack } from "../..";
const meta = {
title: "ds-react/Typography/BodyShort",
component: BodyShort,
decorators: [(story) => <div style={{ maxWidth: "200px" }}>{story()}</div>],
} satisfies Meta<typeof BodyShort>;
export default meta;
type Story = StoryObj<typeof meta>;
const lorem = "Du må gjøre en filtrering for å se brukere i listen.";
export const Default: Story = {
args: {
spacing: false,
children: lorem,
truncate: false,
visuallyHidden: false,
},
argTypes: {
size: {
control: "radio",
options: ["large", "medium", "small"],
},
weight: {
control: "radio",
options: ["regular", "semibold"],
},
align: {
control: "radio",
options: ["start", "center", "end"],
},
textColor: {
control: "radio",
options: ["default", "subtle"],
},
},
};
export const SizeLarge: Story = {
render: () => (
<VStack gap="2">
<BodyShort size="large">{lorem}</BodyShort>
<BodyShort size="large" weight="semibold">
{lorem}
</BodyShort>
<BodyShort size="large" truncate>
{lorem}
</BodyShort>
</VStack>
),
};
export const SizeMedium: Story = {
render: () => (
<VStack gap="2">
<BodyShort size="medium">{lorem}</BodyShort>
<BodyShort size="medium" weight="semibold">
{lorem}
</BodyShort>
<BodyShort size="medium" truncate>
{lorem}
</BodyShort>
</VStack>
),
};
export const SizeSmall: Story = {
render: () => (
<VStack gap="2">
<BodyShort size="small">{lorem}</BodyShort>
<BodyShort size="small" weight="semibold">
{lorem}
</BodyShort>
<BodyShort size="small" truncate>
{lorem}
</BodyShort>
</VStack>
),
};
export const SpacingLarge: Story = {
render: () => (
<div>
<BodyShort size="large" spacing>
{lorem}
</BodyShort>
<BodyShort size="large" spacing>
{lorem}
</BodyShort>
</div>
),
};
export const SpacingMedium: Story = {
render: () => (
<div>
<BodyShort size="medium" spacing>
{lorem}
</BodyShort>
<BodyShort size="medium" spacing>
{lorem}
</BodyShort>
</div>
),
};
export const SpacingSmall: Story = {
render: () => (
<div>
<BodyShort size="small" spacing>
{lorem}
</BodyShort>
<BodyShort size="small" spacing>
{lorem}
</BodyShort>
</div>
),
};
export const Colors: Story = {
render: () => (
<VStack gap="2">
<BodyShort textColor="default">{lorem}</BodyShort>
<BodyShort textColor="subtle">{lorem}</BodyShort>
</VStack>
),
};
export const Align: Story = {
render: () => (
<VStack gap="2">
<BodyShort align="start">{lorem}</BodyShort>
<BodyShort align="center">{lorem}</BodyShort>
<BodyShort align="end">{lorem}</BodyShort>
</VStack>
),
};
export const OverrideTag: Story = {
render: () => (
<div>
<BodyShort spacing>default bodyshort</BodyShort>
<BodyShort as="legend">legend bodyshort</BodyShort>
</div>
),
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const defaultBodyShort = canvas.getByText("default bodyshort");
const legendBodyShort = canvas.getByText("legend bodyshort");
expect(defaultBodyShort.tagName).toEqual("P");
expect(legendBodyShort.tagName).toEqual("LEGEND");
},
};
@@ -0,0 +1,88 @@
import { expect } from "@storybook/jest";
import type { Meta, StoryObj } from "@storybook/react";
import { within } from "@storybook/testing-library";
import React from "react";
import { Detail } from "..";
import { VStack } from "../..";
const meta = {
title: "ds-react/Typography/Detail",
component: Detail,
decorators: [(story) => <div style={{ maxWidth: "200px" }}>{story()}</div>],
} satisfies Meta<typeof Detail>;
export default meta;
type Story = StoryObj<typeof meta>;
const lorem = "Du må gjøre en filtrering for å se brukere i listen.";
export const Default: Story = {
args: {
spacing: false,
children: lorem,
truncate: false,
visuallyHidden: false,
},
argTypes: {
weight: {
control: "radio",
options: ["regular", "semibold"],
},
align: {
control: "radio",
options: ["start", "center", "end"],
},
textColor: {
control: "radio",
options: ["default", "subtle"],
},
},
};
export const Spacing: Story = {
render: () => (
<div>
<Detail spacing>{lorem}</Detail>
<Detail spacing>{lorem}</Detail>
</div>
),
};
export const Colors: Story = {
render: () => (
<VStack gap="2">
<Detail textColor="default">{lorem}</Detail>
<Detail textColor="subtle">{lorem}</Detail>
</VStack>
),
};
export const Align: Story = {
render: () => (
<VStack gap="2">
<Detail align="start">{lorem}</Detail>
<Detail align="center">{lorem}</Detail>
<Detail align="end">{lorem}</Detail>
</VStack>
),
};
export const OverrideTag: Story = {
render: () => (
<div>
<Detail spacing>default detail</Detail>
<Detail as="legend">legend detail</Detail>
</div>
),
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const defaultDetail = canvas.getByText("default detail");
const legendDetail = canvas.getByText("legend detail");
expect(defaultDetail.tagName).toEqual("P");
expect(legendDetail.tagName).toEqual("LEGEND");
},
};
@@ -0,0 +1,93 @@
import { expect } from "@storybook/jest";
import type { Meta, StoryObj } from "@storybook/react";
import { within } from "@storybook/testing-library";
import React from "react";
import { ErrorMessage } from "..";
import { VStack } from "../..";
const meta = {
title: "ds-react/Typography/ErrorMessage",
component: ErrorMessage,
} satisfies Meta<typeof ErrorMessage>;
export default meta;
type Story = StoryObj<typeof meta>;
const lorem =
"Du må fylle ut: Oppgi årsaken til at du har ventet mer enn 6 måneder med å søke om refusjon";
export const Default: Story = {
args: {
spacing: false,
children: lorem,
},
argTypes: {
size: {
control: "radio",
options: ["medium", "small"],
},
},
};
export const SizeMedium: Story = {
render: () => (
<VStack gap="2">
<ErrorMessage size="medium">{lorem}</ErrorMessage>
<ErrorMessage size="medium">{lorem}</ErrorMessage>
</VStack>
),
};
export const SizeSmall: Story = {
render: () => (
<VStack gap="2">
<ErrorMessage size="small">{lorem}</ErrorMessage>
<ErrorMessage size="small">{lorem}</ErrorMessage>
</VStack>
),
};
export const SpacingMedium: Story = {
render: () => (
<div>
<ErrorMessage size="medium" spacing>
{lorem}
</ErrorMessage>
<ErrorMessage size="medium" spacing>
{lorem}
</ErrorMessage>
</div>
),
};
export const SpacingSmall: Story = {
render: () => (
<div>
<ErrorMessage size="small" spacing>
{lorem}
</ErrorMessage>
<ErrorMessage size="small" spacing>
{lorem}
</ErrorMessage>
</div>
),
};
export const OverrideTag: Story = {
render: () => (
<div>
<ErrorMessage spacing>default errormessage</ErrorMessage>
<ErrorMessage as="legend">legend errormessage</ErrorMessage>
</div>
),
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const defaultErrorMessage = canvas.getByText("default errormessage");
const legendErrorMessage = canvas.getByText("legend errormessage");
expect(defaultErrorMessage.tagName).toEqual("P");
expect(legendErrorMessage.tagName).toEqual("LEGEND");
},
};
@@ -0,0 +1,143 @@
import type { Meta, StoryObj } from "@storybook/react";
import { expect } from "@storybook/jest";
import { within } from "@storybook/testing-library";
import { default as React } from "react";
import { Heading } from "..";
import { VStack } from "../..";
const meta = {
title: "ds-react/Typography/Heading",
component: Heading,
decorators: [(story) => <div style={{ maxWidth: "300px" }}>{story()}</div>],
} satisfies Meta<typeof Heading>;
export default meta;
type Story = StoryObj<typeof meta>;
const lorem = "Hva kan vi hjelpe deg med?";
export const Default: Story = {
args: {
spacing: false,
children: lorem,
visuallyHidden: false,
},
argTypes: {
size: {
control: "radio",
options: ["xlarge", "large", "medium", "small", "xsmall"],
},
level: {
control: "radio",
options: ["1", "2", "3", "4", "5", "6"],
},
align: {
control: "radio",
options: ["start", "center", "end"],
},
textColor: {
control: "radio",
options: ["default", "subtle"],
},
},
};
export const Sizes: Story = {
render: () => (
<VStack gap="4">
<Heading level="1" size="xlarge">
{lorem}
</Heading>
<Heading level="2" size="large">
{lorem}
</Heading>
<Heading level="3" size="medium">
{lorem}
</Heading>
<Heading level="4" size="small">
{lorem}
</Heading>
<Heading level="5" size="xsmall">
{lorem}
</Heading>
</VStack>
),
};
export const Spacing: Story = {
render: () => (
<div>
<Heading level="1" size="xlarge" spacing>
{lorem}
</Heading>
<Heading level="2" size="large" spacing>
{lorem}
</Heading>
<Heading level="3" size="medium" spacing>
{lorem}
</Heading>
<Heading level="4" size="small" spacing>
{lorem}
</Heading>
<Heading level="5" size="xsmall" spacing>
{lorem}
</Heading>
<Heading level="5" size="xsmall">
{lorem}
</Heading>
</div>
),
};
export const Colors: Story = {
render: () => (
<VStack gap="2">
<Heading level="1" size="large" textColor="default">
{lorem}
</Heading>
<Heading level="2" size="large" textColor="subtle">
{lorem}
</Heading>
</VStack>
),
};
export const Align: Story = {
render: () => (
<VStack gap="2">
<Heading level="1" size="large" align="start">
{lorem}
</Heading>
<Heading level="2" size="large" align="center">
{lorem}
</Heading>
<Heading level="3" size="large" align="end">
{lorem}
</Heading>
</VStack>
),
};
export const OverrideTag: Story = {
render: () => (
<div>
<Heading spacing level="1" size="large">
default heading
</Heading>
<Heading as="legend" size="large">
legend heading
</Heading>
</div>
),
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const defaultHeading = canvas.getByText("default heading");
const legendHeading = canvas.getByText("legend heading");
expect(defaultHeading.tagName).toEqual("H1");
expect(legendHeading.tagName).toEqual("LEGEND");
},
};
Loaded 100 of 274 files, more files were not shown because too many files have changed in this diff. Show more