mirror of
https://github.com/navikt/aksel.git
synced 2026-10-13 01:02:02 +00:00
Compare commits
80
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5ecd66a57 | ||
|
|
78817fef45 | ||
|
|
38357b1a2e | ||
|
|
65c17db2e5 | ||
|
|
59e88773d1 | ||
|
|
f175d0f781 | ||
|
|
18419f7d98 | ||
|
|
f63a7ec36d | ||
|
|
107489bd3f | ||
|
|
792962592f | ||
|
|
4a02a1987c | ||
|
|
700943b4a5 | ||
|
|
521c982457 | ||
|
|
8c17099087 | ||
|
|
29241a7153 | ||
|
|
7e4ee40a7f | ||
|
|
2be97970d6 | ||
|
|
5b3c1f33c4 | ||
|
|
f44ff44410 | ||
|
|
855669538e | ||
|
|
3d830dc123 | ||
|
|
dcca2a9560 | ||
|
|
26fb028f07 | ||
|
|
d928769d6f | ||
|
|
e96d33d13e | ||
|
|
00ebe1c18b | ||
|
|
53be894ad0 | ||
|
|
614946097e | ||
|
|
74ac20ea7c | ||
|
|
d299137774 | ||
|
|
304f6d6a12 | ||
|
|
bf6952c2b2 | ||
|
|
7705dd4ae5 | ||
|
|
d9ce1299d9 | ||
|
|
0890eed59e | ||
|
|
dbd7150762 | ||
|
|
58933e2584 | ||
|
|
86279919c8 | ||
|
|
8866572e69 | ||
|
|
a1accdbd95 | ||
|
|
fdfdebfa99 | ||
|
|
56abe568e2 | ||
|
|
34acbb87a5 | ||
|
|
fd479e3160 | ||
|
|
03ca21b4f6 | ||
|
|
e7804297bf | ||
|
|
a246c9d707 | ||
|
|
d3fb3d4d96 | ||
|
|
d734d3071b | ||
|
|
8d97bba1fe | ||
|
|
eff9b5ecce | ||
|
|
71fc90b301 | ||
|
|
e1d5e1b505 | ||
|
|
45d4f6c478 | ||
|
|
2564e84b9c | ||
|
|
e5637c64a8 | ||
|
|
82a1f32542 | ||
|
|
a8d4b1e23e | ||
|
|
d50ebebad6 | ||
|
|
e292e83128 | ||
|
|
23c472e60b | ||
|
|
058e012c26 | ||
|
|
ffce1f75ae | ||
|
|
46e5ffb6e4 | ||
|
|
d9696b3617 | ||
|
|
df1efb2748 | ||
|
|
2b23f6ab91 | ||
|
|
01d422b01f | ||
|
|
8936db096f | ||
|
|
b66ad3673b | ||
|
|
16eff2ce93 | ||
|
|
bdc0815dd7 | ||
|
|
4c5cdb22e9 | ||
|
|
a1e74fa9bd | ||
|
|
d5e5a6c64f | ||
|
|
11e3a18526 | ||
|
|
930c772bd6 | ||
|
|
ade5d59392 | ||
|
|
d90fe26e26 | ||
|
|
13b148aab6 |
No files matched your search
@@ -11,6 +11,10 @@ on:
|
||||
paths:
|
||||
- "@navikt/**"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
visual_regression_test:
|
||||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'ignore-chromatic') }}
|
||||
@@ -55,7 +59,9 @@ jobs:
|
||||
exitZeroOnChanges: false
|
||||
buildScriptName: "build:storybook"
|
||||
onlyChanged: true
|
||||
untraced: "**/package.json|yarn.lock|**/*.md"
|
||||
externals: \@navikt/core/css/**/*.css
|
||||
traceChanged: true
|
||||
env:
|
||||
STORYBOOK_GITHUB_SHA: ${{ github.sha }}
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@ name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- ".changeset/**"
|
||||
- "@navikt/**"
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
name: Redeploy Naisjob (update-article-views)
|
||||
on:
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
execute:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
packages: "write"
|
||||
contents: "read"
|
||||
id-token: "write"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- uses: denoland/setup-deno@v1
|
||||
with:
|
||||
deno-version: v1.x
|
||||
- name: Restore cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: ${{ runner.os }}-build-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-
|
||||
- name: add tokens to .env
|
||||
run: |
|
||||
echo "SANITY_WRITE_KEY=${{ secrets.SANITY_UTILITY_WRITE }}" >> scripts/article-views/.env
|
||||
- uses: nais/docker-build-push@v0
|
||||
id: docker-push
|
||||
with:
|
||||
team: designsystem
|
||||
push_image: true
|
||||
dockerfile: scripts/article-views/Dockerfile.update-article-views
|
||||
project_id: ${{ vars.NAIS_MANAGEMENT_PROJECT_ID }}
|
||||
identity_provider: ${{ secrets.NAIS_WORKLOAD_IDENTITY_PROVIDER }}
|
||||
- name: start naisjob prod-gcp
|
||||
uses: nais/deploy/actions/deploy@master
|
||||
env:
|
||||
APIKEY: ${{ secrets.NAIS_DEPLOY_APIKEY }}
|
||||
RESOURCE: scripts/article-views/nais-update-views-job.yml
|
||||
CLUSTER: prod-gcp
|
||||
IMAGE: ${{ steps.docker-push.outputs.image }}
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
**/nais-dev.yaml
|
||||
**/nais-prod.yaml
|
||||
**/nais*.yaml
|
||||
**/nais*.yml
|
||||
**/codemod/**/tests/**/*.js
|
||||
node_modules
|
||||
.next
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import { mergeConfig } from "vite";
|
||||
import turbosnap from "vite-plugin-turbosnap";
|
||||
|
||||
module.exports = {
|
||||
export default {
|
||||
staticDirs: ["./public"],
|
||||
|
||||
stories: () => [
|
||||
|
||||
@@ -10,7 +10,7 @@ export const parameters = {
|
||||
"Getting started",
|
||||
"ds-react",
|
||||
["Primitives"],
|
||||
["Default"],
|
||||
["Default", "Controls"],
|
||||
"Aksel-icons",
|
||||
],
|
||||
},
|
||||
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"dbaeumer.vscode-eslint",
|
||||
"denoland.vscode-deno",
|
||||
"esbenp.prettier-vscode",
|
||||
"github.vscode-github-actions",
|
||||
"ms-playwright.playwright",
|
||||
"sanity-io.vscode-sanity",
|
||||
"stylelint.vscode-stylelint",
|
||||
"vunguyentuan.vscode-css-variables",
|
||||
"bradlc.vscode-tailwindcss"
|
||||
]
|
||||
}
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"cssVariables.lookupFiles": ["@navikt/core/css/dist/index.css"],
|
||||
"eslint.problems.shortenToSingleLine": true,
|
||||
"deno.enablePaths": ["scripts/article-views", "scripts/changelog"],
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"deno.lint": true,
|
||||
"files.watcherExclude": {
|
||||
"**/.yarn/**": true,
|
||||
"**/dist": true,
|
||||
"**/esm": true,
|
||||
"**/cjs": true
|
||||
},
|
||||
"playwright.reuseBrowser": true,
|
||||
"typescript.tsdk": "node_modules/typescript/lib"
|
||||
}
|
||||
@@ -1,5 +1,29 @@
|
||||
# @navikt/aksel-icons
|
||||
|
||||
## 5.18.2
|
||||
|
||||
## 5.18.1
|
||||
|
||||
## 5.18.0
|
||||
|
||||
## 5.17.5
|
||||
|
||||
## 5.17.4
|
||||
|
||||
## 5.17.3
|
||||
|
||||
## 5.17.2
|
||||
|
||||
## 5.17.1
|
||||
|
||||
## 5.17.0
|
||||
|
||||
## 5.16.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Ikoner: Nytt ikon `LocationPin` ✨ ([#2672](https://github.com/navikt/aksel/pull/2672))
|
||||
|
||||
## 5.15.1
|
||||
|
||||
## 5.15.0
|
||||
|
||||
@@ -13,23 +13,23 @@
|
||||
"dependencies": {
|
||||
"@navikt/ds-css": "*",
|
||||
"@navikt/ds-react": "*",
|
||||
"fuse.js": "^6.6.2",
|
||||
"fuse.js": "^7.0.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@figma/plugin-typings": "^1.62.0",
|
||||
"@svgr/core": "^6.5.1",
|
||||
"@figma/plugin-typings": "^1.84.0",
|
||||
"@svgr/core": "^8.1.0",
|
||||
"@types/node": "^18.15.11",
|
||||
"@types/postcss-url": "^10.0.0",
|
||||
"@types/postcss-url": "^10.0.4",
|
||||
"@types/react": "^18.0.0",
|
||||
"@types/react-dom": "^18.0.0",
|
||||
"@vitejs/plugin-react": "^3.1.0",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"postcss": "^8.4.31",
|
||||
"postcss-url": "^10.1.3",
|
||||
"typescript": "^5.1.6",
|
||||
"vite": "^4.5.1",
|
||||
"vite-plugin-singlefile": "^0.13.3",
|
||||
"vite-plugin-svgr": "^2.4.0"
|
||||
"vite": "^5.0.12",
|
||||
"vite-plugin-singlefile": "^1.0.0",
|
||||
"vite-plugin-svgr": "^4.2.0"
|
||||
}
|
||||
}
|
||||
@@ -170,7 +170,7 @@ const App = () => {
|
||||
className="icon-classname icon-button"
|
||||
>
|
||||
<T
|
||||
font-size="2rem"
|
||||
fontSize="2rem"
|
||||
title={i.id}
|
||||
id={`icon-id-${i.id}`}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.58075 5.58058C10.0215 3.13981 13.9788 3.13981 16.4196 5.58058C18.829 7.98999 18.7208 11.7547 16.3826 14.4592C15.8985 15.0192 14.6522 16.5427 13.5371 17.9135C12.9773 18.6017 12.4472 19.2555 12.0572 19.7371L12.0002 19.8075L11.9432 19.7371C11.5531 19.2555 11.0231 18.6017 10.4633 17.9135C9.34813 16.5427 8.1019 15.0192 7.61778 14.4592C5.27952 11.7547 5.17135 7.98999 7.58075 5.58058ZM12.0002 21C12.5836 21.4713 12.5836 21.4713 12.5837 21.4712L12.0002 21ZM11.4167 21.4712L11.416 21.4704L11.2433 21.2567C11.1321 21.1193 10.9723 20.9217 10.7775 20.6811C10.3879 20.2 9.85856 19.5472 9.29965 18.8601C8.17735 17.4805 6.9487 15.9788 6.48307 15.4403C3.72084 12.2453 3.46216 7.57786 6.52009 4.51992C9.54666 1.49336 14.4537 1.49336 17.4802 4.51992C20.5382 7.57786 20.2795 12.2453 17.5173 15.4403C17.0516 15.9788 15.823 17.4805 14.7007 18.8601C14.1418 19.5472 13.6125 20.2 13.2229 20.6811C13.0281 20.9217 12.8682 21.1193 12.7571 21.2567L12.5837 21.4712C12.4413 21.6475 12.2268 21.75 12.0002 21.75C11.7736 21.75 11.5591 21.6475 11.4167 21.4712ZM12.0002 21L11.4167 21.4712C11.4167 21.4713 11.4168 21.4713 12.0002 21ZM9.75 10C9.75 8.75736 10.7574 7.75 12 7.75C13.2426 7.75 14.25 8.75736 14.25 10C14.25 11.2426 13.2426 12.25 12 12.25C10.7574 12.25 9.75 11.2426 9.75 10ZM12 6.25C9.92893 6.25 8.25 7.92893 8.25 10C8.25 12.0711 9.92893 13.75 12 13.75C14.0711 13.75 15.75 12.0711 15.75 10C15.75 7.92893 14.0711 6.25 12 6.25Z" fill="#23262A"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,13 @@
|
||||
name: LocationPin
|
||||
category: Transportation
|
||||
sub_category: Travel
|
||||
keywords:
|
||||
- kart
|
||||
- pin
|
||||
- sted
|
||||
- map
|
||||
- location
|
||||
- lokasjon
|
||||
variant: Stroke
|
||||
updated_at: 26.01.2024
|
||||
created_at: 07.03.2023
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.7572 21.2567C12.8684 21.1193 13.0282 20.9217 13.223 20.6811C13.6126 20.2 14.1419 19.5472 14.7008 18.8601C15.8231 17.4805 17.0518 15.9788 17.5174 15.4403C20.2796 12.2453 20.5383 7.57786 17.4804 4.51992C14.4538 1.49336 9.54679 1.49336 6.52022 4.51992C3.46229 7.57786 3.72097 12.2453 6.4832 15.4403C6.94883 15.9788 8.17749 17.4805 9.29978 18.8601C9.85869 19.5472 10.388 20.2 10.7776 20.6811C10.9724 20.9217 11.1323 21.1193 11.2434 21.2567L11.4162 21.4704L11.4168 21.4712C11.5592 21.6475 11.7737 21.75 12.0003 21.75C12.2269 21.75 12.4414 21.6475 12.5838 21.4712L12.7572 21.2567ZM12 6.25C9.92893 6.25 8.25 7.92893 8.25 10C8.25 12.0711 9.92893 13.75 12 13.75C14.0711 13.75 15.75 12.0711 15.75 10C15.75 7.92893 14.0711 6.25 12 6.25Z" fill="#23262A"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 900 B |
@@ -0,0 +1,13 @@
|
||||
name: LocationPinFill
|
||||
category: Transportation
|
||||
sub_category: Travel
|
||||
keywords:
|
||||
- kart
|
||||
- pin
|
||||
- sted
|
||||
- map
|
||||
- location
|
||||
- lokasjon
|
||||
variant: Fill
|
||||
updated_at: 26.01.2024
|
||||
created_at: 07.03.2023
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/aksel-icons",
|
||||
"version": "5.15.1",
|
||||
"version": "5.18.2",
|
||||
"author": "Aksel | NAV",
|
||||
"homepage": "https://aksel.nav.no/ikoner",
|
||||
"repository": {
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# @navikt/aksel-stylelint
|
||||
|
||||
## 5.18.2
|
||||
|
||||
## 5.18.1
|
||||
|
||||
## 5.18.0
|
||||
|
||||
## 5.17.5
|
||||
|
||||
## 5.17.4
|
||||
|
||||
## 5.17.3
|
||||
|
||||
## 5.17.2
|
||||
|
||||
## 5.17.1
|
||||
|
||||
## 5.17.0
|
||||
|
||||
## 5.16.0
|
||||
|
||||
## 5.15.1
|
||||
|
||||
## 5.15.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/aksel-stylelint",
|
||||
"version": "5.15.1",
|
||||
"version": "5.18.2",
|
||||
"author": "Aksel | NAV",
|
||||
"homepage": "https://aksel.nav.no/grunnleggende/kode/stylelint",
|
||||
"repository": {
|
||||
@@ -35,8 +35,8 @@
|
||||
"dev": "yarn watch:lint"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@navikt/ds-css": "^5.15.1",
|
||||
"@navikt/ds-tokens": "^5.15.1",
|
||||
"@navikt/ds-css": "^5.18.2",
|
||||
"@navikt/ds-tokens": "^5.18.2",
|
||||
"@types/jest": "^29.0.0",
|
||||
"concurrently": "7.2.1",
|
||||
"copyfiles": "2.4.1",
|
||||
|
||||
@@ -1,5 +1,75 @@
|
||||
# @navikt/aksel
|
||||
|
||||
## 5.18.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-css@5.18.2
|
||||
|
||||
## 5.18.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-css@5.18.1
|
||||
|
||||
## 5.18.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-css@5.18.0
|
||||
|
||||
## 5.17.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`dcca2a956`](https://github.com/navikt/aksel/commit/dcca2a95600152cb84c3b79ba5bb3894ac63e881)]:
|
||||
- @navikt/ds-css@5.17.5
|
||||
|
||||
## 5.17.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-css@5.17.4
|
||||
|
||||
## 5.17.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-css@5.17.3
|
||||
|
||||
## 5.17.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`fdfdebfa9`](https://github.com/navikt/aksel/commit/fdfdebfa99e594099bcea7b5addde9cdabc727a7)]:
|
||||
- @navikt/ds-css@5.17.2
|
||||
|
||||
## 5.17.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-css@5.17.1
|
||||
|
||||
## 5.17.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`d3fb3d4d9`](https://github.com/navikt/aksel/commit/d3fb3d4d962fac028e7d803dc7c50315d48b4987)]:
|
||||
- @navikt/ds-css@5.17.0
|
||||
|
||||
## 5.16.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`23c472e60`](https://github.com/navikt/aksel/commit/23c472e60b03fa07a82ac5eed9298b535f8e341c)]:
|
||||
- @navikt/ds-css@5.16.0
|
||||
|
||||
## 5.15.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/aksel",
|
||||
"version": "5.15.1",
|
||||
"version": "5.18.2",
|
||||
"description": "Aksel command line interface. Handles css-imports, codemods and more",
|
||||
"author": "Aksel | NAV designsystem team",
|
||||
"license": "MIT",
|
||||
@@ -29,7 +29,7 @@
|
||||
},
|
||||
"homepage": "https://aksel.nav.no/grunnleggende/kode/kommandolinje",
|
||||
"dependencies": {
|
||||
"@navikt/ds-css": "5.15.1",
|
||||
"@navikt/ds-css": "5.18.2",
|
||||
"axios": "1.6.0",
|
||||
"chalk": "4.1.0",
|
||||
"clipboardy": "^2.3.0",
|
||||
|
||||
@@ -1,5 +1,41 @@
|
||||
# @navikt/ds-css
|
||||
|
||||
## 5.18.2
|
||||
|
||||
## 5.18.1
|
||||
|
||||
## 5.18.0
|
||||
|
||||
## 5.17.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ExpansionCard: Padding-top for Content er justert opp 8px (medium) og 4px (small) ([#2699](https://github.com/navikt/aksel/pull/2699))
|
||||
|
||||
## 5.17.4
|
||||
|
||||
## 5.17.3
|
||||
|
||||
## 5.17.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Checkbox: I noen edgecaser ved bruk av shadow-dom ble ikke checkmark sentert i Checkbox ([#2682](https://github.com/navikt/aksel/pull/2682))
|
||||
|
||||
## 5.17.1
|
||||
|
||||
## 5.17.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Høykontrast: Komponenter støtter nå standard høykontrast-modus på Windows ([#2680](https://github.com/navikt/aksel/pull/2680))
|
||||
|
||||
## 5.16.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- :sparkles: Combobox: Mulighet for å begrense hvor mange valg bruker kan ta ([#2260](https://github.com/navikt/aksel/pull/2260))
|
||||
|
||||
## 5.15.1
|
||||
|
||||
## 5.15.0
|
||||
|
||||
@@ -74,7 +74,8 @@
|
||||
}
|
||||
|
||||
.navds-accordion__header:focus-visible {
|
||||
outline: none;
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 3px;
|
||||
box-shadow: var(--a-shadow-focus);
|
||||
border-radius: var(--a-border-radius-large);
|
||||
}
|
||||
@@ -185,3 +186,17 @@
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-accordion__header {
|
||||
border: 1px solid buttonborder;
|
||||
background-color: canvas;
|
||||
color: canvastext;
|
||||
}
|
||||
|
||||
.navds-accordion__header:hover {
|
||||
background-color: canvas;
|
||||
border: 1px solid highlight;
|
||||
color: highlight;
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@
|
||||
font-size: 1.5rem;
|
||||
align-self: flex-start;
|
||||
height: var(--a-font-line-height-xlarge);
|
||||
background: radial-gradient(circle, var(--a-surface-default) 50%, 0, transparent);
|
||||
background: radial-gradient(circle, var(--a-surface-default) 47%, 0, transparent);
|
||||
}
|
||||
|
||||
.navds-alert--small > .navds-alert__icon {
|
||||
@@ -64,7 +64,7 @@
|
||||
}
|
||||
|
||||
.navds-alert--warning > .navds-alert__icon {
|
||||
background: radial-gradient(circle at 50% 57%, var(--a-surface-default) 32%, 0, transparent);
|
||||
background: radial-gradient(circle at 50% 57%, var(--a-surface-default) 30%, 0, transparent);
|
||||
color: var(--ac-alert-icon-warning-color, var(--a-icon-warning));
|
||||
}
|
||||
|
||||
@@ -99,3 +99,11 @@
|
||||
flex-flow: row nowrap;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-alert {
|
||||
border: 1px solid canvastext;
|
||||
background-color: canvas;
|
||||
color: canvastext;
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,8 @@
|
||||
}
|
||||
|
||||
.navds-button:focus-visible {
|
||||
outline: none;
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
box-shadow: var(--a-shadow-focus);
|
||||
}
|
||||
|
||||
@@ -129,6 +130,16 @@
|
||||
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)));
|
||||
}
|
||||
@media (forced-colors: active) {
|
||||
.navds-button.navds-button--primary {
|
||||
background-color: highlight;
|
||||
color: highlighttext;
|
||||
}
|
||||
|
||||
.navds-button.navds-button--primary span {
|
||||
forced-color-adjust: none;
|
||||
}
|
||||
}
|
||||
|
||||
.navds-button--primary:hover {
|
||||
background-color: var(--ac-button-primary-hover-bg, var(--__ac-button-primary-hover-bg, var(--a-surface-action-hover)));
|
||||
@@ -139,10 +150,17 @@
|
||||
}
|
||||
|
||||
.navds-button--primary:focus-visible {
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
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);
|
||||
}
|
||||
@media (forced-colors: active) {
|
||||
.navds-button--primary:focus-visible {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
@supports not selector(:focus-visible) {
|
||||
.navds-button--primary:focus {
|
||||
@@ -478,6 +496,7 @@
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
/* Loader overrides */
|
||||
.navds-button .navds-loader .navds-loader__foreground {
|
||||
stroke: var(--ac-button-loader-stroke, currentColor);
|
||||
}
|
||||
@@ -486,3 +505,36 @@
|
||||
.navds-button--danger .navds-loader .navds-loader__background {
|
||||
stroke: var(--ac-button-primary-loader-stroke-bg, rgb(255 255 255 / 0.3));
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-button:not(.navds-button--loading):where(:disabled, .navds-button--disabled) {
|
||||
opacity: 1;
|
||||
color: GrayText;
|
||||
}
|
||||
|
||||
.navds-button {
|
||||
border: 1px solid transparent;
|
||||
color: ButtonText;
|
||||
background-color: ButtonFace;
|
||||
}
|
||||
|
||||
.navds-button:hover {
|
||||
background-color: highlighttext;
|
||||
border-color: highlight;
|
||||
color: highlight;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.navds-button:hover span {
|
||||
forced-color-adjust: none;
|
||||
}
|
||||
|
||||
.navds-button .navds-loader .navds-loader__foreground {
|
||||
stroke: canvas;
|
||||
}
|
||||
|
||||
.navds-button--primary .navds-loader .navds-loader__background,
|
||||
.navds-button--danger .navds-loader .navds-loader__background {
|
||||
stroke: canvastext;
|
||||
}
|
||||
}
|
||||
@@ -105,3 +105,16 @@
|
||||
.navds-chat--right .navds-chat__top-text--left {
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-chat__bubble,
|
||||
.navds-chat__avatar {
|
||||
border: 1px solid canvastext;
|
||||
background-color: canvas;
|
||||
color: canvastext;
|
||||
}
|
||||
|
||||
.navds-chat__avatar svg {
|
||||
forced-color-adjust: none;
|
||||
}
|
||||
}
|
||||
@@ -191,3 +191,44 @@
|
||||
.navds-chips--small .navds-chips--icon-right {
|
||||
padding-right: var(--a-spacing-05);
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-chips__chip {
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.navds-chips__chip:hover {
|
||||
background-color: highlighttext;
|
||||
color: highlight;
|
||||
}
|
||||
|
||||
.navds-chips__chip:focus-visible {
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.navds-chips__chip:where([aria-pressed="true"], :active, :hover) > span {
|
||||
forced-color-adjust: none;
|
||||
}
|
||||
|
||||
.navds-chips__toggle:active {
|
||||
background-color: highlight;
|
||||
color: highlighttext;
|
||||
}
|
||||
|
||||
.navds-chips__toggle[aria-pressed="true"] {
|
||||
background-color: selecteditem;
|
||||
color: selecteditemtext;
|
||||
border: 1px solid selecteditem;
|
||||
}
|
||||
|
||||
.navds-chips__toggle[aria-pressed="true"]:hover {
|
||||
background-color: selecteditemtext;
|
||||
color: selecteditem;
|
||||
}
|
||||
|
||||
.navds-chips__toggle[aria-pressed="true"]:active {
|
||||
background-color: highlight;
|
||||
color: highlighttext;
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,21 @@
|
||||
place-content: center;
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-copybutton {
|
||||
background-color: ButtonFace;
|
||||
border-color: ButtonText;
|
||||
border: solid 1px ButtonText;
|
||||
color: ButtonText;
|
||||
}
|
||||
|
||||
.navds-copybutton.navds-copybutton:focus-visible {
|
||||
box-shadow: none;
|
||||
outline: 2px solid highlight;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.navds-copybutton--icon-right {
|
||||
--__ac-copybutton-padding: var(--a-spacing-3) var(--a-spacing-4) var(--a-spacing-3) var(--a-spacing-5);
|
||||
}
|
||||
@@ -201,3 +216,10 @@
|
||||
cursor: not-allowed;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-copybutton:where(:disabled) {
|
||||
opacity: 1;
|
||||
border-color: GrayText;
|
||||
}
|
||||
}
|
||||
@@ -58,13 +58,15 @@
|
||||
}
|
||||
|
||||
.navds-dropdown__item:focus-visible {
|
||||
outline: none;
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: -2px;
|
||||
box-shadow: inset 0 0 0 2px var(--a-border-focus);
|
||||
}
|
||||
|
||||
@supports not selector(:focus-visible) {
|
||||
.navds-dropdown__item:focus {
|
||||
outline: none;
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: -2px;
|
||||
box-shadow: inset 0 0 0 2px var(--a-border-focus);
|
||||
}
|
||||
}
|
||||
@@ -75,3 +77,14 @@
|
||||
background: transparent;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-dropdown__item:hover {
|
||||
color: highlight;
|
||||
}
|
||||
|
||||
.navds-dropdown__item:disabled {
|
||||
opacity: 1;
|
||||
color: graytext;
|
||||
}
|
||||
}
|
||||
@@ -145,13 +145,13 @@
|
||||
}
|
||||
|
||||
.navds-expansioncard__header-button:focus-visible {
|
||||
outline: none;
|
||||
outline: 3px solid transparent;
|
||||
box-shadow: var(--a-shadow-focus);
|
||||
}
|
||||
|
||||
@supports not selector(:focus-visible) {
|
||||
.navds-expansioncard__header-button:focus {
|
||||
outline: none;
|
||||
outline: 3px solid transparent;
|
||||
box-shadow: var(--a-shadow-focus);
|
||||
}
|
||||
}
|
||||
@@ -177,7 +177,7 @@
|
||||
* Content *
|
||||
*************************/
|
||||
.navds-expansioncard__content {
|
||||
--__ac-expansioncard-padding-block: var(--a-spacing-3);
|
||||
--__ac-expansioncard-padding-block: var(--a-spacing-5);
|
||||
|
||||
border-end-end-radius: var(--__ac-expansioncard-border-radius);
|
||||
border-end-start-radius: var(--__ac-expansioncard-border-radius);
|
||||
@@ -187,6 +187,10 @@
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.navds-expansioncard--small .navds-expansioncard__content {
|
||||
--__ac-expansioncard-padding-block: var(--a-spacing-4);
|
||||
}
|
||||
|
||||
.navds-expansioncard__content--closed {
|
||||
display: none;
|
||||
}
|
||||
@@ -221,3 +225,11 @@
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-expansioncard:hover {
|
||||
--__ac-expansioncard-border-color: highlight;
|
||||
|
||||
outline: 1px solid highlight;
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,8 @@
|
||||
|
||||
.navds-combobox--error
|
||||
.navds-text-field__input:not(:hover):not(:disabled):not(.navds-combobox__wrapper-inner--virtually-unfocused):focus-within {
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
box-shadow:
|
||||
0 0 0 1px var(--ac-combobox-error-border, var(--a-border-danger)),
|
||||
var(--a-shadow-focus);
|
||||
@@ -74,7 +76,6 @@
|
||||
}
|
||||
|
||||
.navds-combobox__input {
|
||||
z-index: 1;
|
||||
flex: 1;
|
||||
border: none;
|
||||
padding: 0;
|
||||
@@ -95,10 +96,13 @@
|
||||
0 0 0 1px var(--a-surface-default) inset,
|
||||
var(--a-shadow-focus);
|
||||
box-shadow: var(--a-shadow-focus);
|
||||
outline: 3px solid transparent;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.navds-combobox__wrapper-inner:has(.navds-combobox__input:focus-visible).navds-combobox__wrapper-inner--virtually-unfocused {
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@supports not selector(:focus-visible) {
|
||||
@@ -113,10 +117,13 @@
|
||||
0 0 0 1px var(--a-surface-default) inset,
|
||||
var(--a-shadow-focus);
|
||||
box-shadow: var(--a-shadow-focus);
|
||||
outline: 3px solid transparent;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.navds-combobox__wrapper-inner:has(.navds-combobox__input:focus).navds-combobox__wrapper-inner--virtually-unfocused {
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,10 +133,13 @@
|
||||
0 0 0 1px var(--a-surface-default) inset,
|
||||
var(--a-shadow-focus);
|
||||
box-shadow: var(--a-shadow-focus);
|
||||
outline: 3px solid transparent;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.navds-combobox--focused .navds-combobox__wrapper-inner.navds-combobox__wrapper-inner--virtually-unfocused {
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,7 +218,7 @@
|
||||
height: 1.25rem;
|
||||
}
|
||||
|
||||
/* dropdown list */
|
||||
/* dropdown & non selectable dropdown items */
|
||||
|
||||
.navds-combobox__list {
|
||||
max-height: 290px;
|
||||
@@ -216,20 +226,16 @@
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 9999;
|
||||
z-index: var(--a-z-index-popover);
|
||||
top: calc(100% + var(--a-spacing-2));
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
border: 1px solid var(--ac-combobox-list-border-color, var(--a-border-divider));
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
padding: 0;
|
||||
box-shadow: var(--a-shadow-small);
|
||||
border-radius: var(--a-border-radius-medium);
|
||||
gap: var(--a-spacing-1) 0;
|
||||
background-color: var(--ac-combobox-list-bg, var(--a-surface-default));
|
||||
color: var(--ac-combobox-list-text, var(--a-text-default));
|
||||
gap: var(--a-spacing-1) 0;
|
||||
}
|
||||
|
||||
.navds-combobox__list--closed {
|
||||
@@ -241,34 +247,70 @@
|
||||
width: 1.5rem;
|
||||
}
|
||||
|
||||
.navds-combobox__list_non-selectables {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.navds-combobox__list-item,
|
||||
.navds-combobox__list-item__no-options,
|
||||
.navds-combobox__list-item__new-option {
|
||||
.navds-combobox__list-item--loading,
|
||||
.navds-combobox__list-item--no-options,
|
||||
.navds-combobox__list-item--new-option,
|
||||
.navds-combobox__list-item--max-selected {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: var(--a-spacing-3);
|
||||
width: 100%;
|
||||
background-color: var(--ac-combobox-list-item-bg, var(--a-surface-default));
|
||||
scroll-margin-top: 50px;
|
||||
}
|
||||
|
||||
.navds-form-field--small .navds-combobox__list-item,
|
||||
.navds-form-field--small .navds-combobox__list-item__no-options,
|
||||
.navds-form-field--small .navds-combobox__list-item__new-option {
|
||||
.navds-form-field--small .navds-combobox__list-item--loading,
|
||||
.navds-form-field--small .navds-combobox__list-item--no-options,
|
||||
.navds-form-field--small .navds-combobox__list-item--new-option,
|
||||
.navds-form-field--small .navds-combobox__list-item--max-selected {
|
||||
padding: calc(var(--a-spacing-3) / 2) var(--a-spacing-2);
|
||||
}
|
||||
|
||||
.navds-combobox__list-item--loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: var(--a-spacing-3);
|
||||
background-color: var(--ac-combobox-list-item-loading-bg, var(--a-surface-default));
|
||||
}
|
||||
|
||||
.navds-combobox__list-item--max-selected {
|
||||
background: var(--ac-combobox-list-item-max-selected-bg, var(--a-surface-info-subtle));
|
||||
border-start-start-radius: calc(var(--a-border-radius-medium) - 1px);
|
||||
border-start-end-radius: calc(var(--a-border-radius-medium) - 1px);
|
||||
border: 1px solid var(--ac-combobox-list-item-max-selected-border, var(--a-border-info));
|
||||
margin-bottom: calc(var(--a-spacing-1) * -1);
|
||||
}
|
||||
|
||||
.navds-combobox__list_non-selectables:hover {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/* ul-list and selectable li-items */
|
||||
|
||||
.navds-combobox__list-options {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
display: inherit;
|
||||
flex-direction: inherit;
|
||||
gap: inherit;
|
||||
background-color: inherit;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.navds-combobox__list-item--focus,
|
||||
.navds-combobox__list--with-hover .navds-combobox__list-item:hover {
|
||||
.navds-combobox__list--with-hover
|
||||
.navds-combobox__list-item:not([data-no-focus="true"], .navds-combobox__list-item--new-option):hover {
|
||||
background-color: var(--ac-combobox-list-item-hover-bg, var(--a-surface-hover));
|
||||
cursor: pointer;
|
||||
border-left: 4px solid var(--ac-combobox-list-item-hover-border-left, var(--a-border-strong));
|
||||
@@ -280,6 +322,11 @@
|
||||
padding-left: calc(var(--a-spacing-2) - 4px);
|
||||
}
|
||||
|
||||
.navds-combobox__list-item[data-no-focus="true"] {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.navds-combobox__list-item--selected {
|
||||
background-color: var(--ac-combobox-list-item-selected-bg, var(--a-surface-selected));
|
||||
}
|
||||
@@ -295,7 +342,7 @@
|
||||
padding-left: calc(var(--a-spacing-3) - 4px);
|
||||
}
|
||||
|
||||
.navds-combobox__list-item__new-option {
|
||||
.navds-combobox__list-item--new-option {
|
||||
border-bottom: 1px solid var(--a-border-divider);
|
||||
background: var(--a-surface-neutral-subtle);
|
||||
cursor: pointer;
|
||||
@@ -303,12 +350,12 @@
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.navds-combobox__list--with-hover .navds-combobox__list-item__new-option:hover {
|
||||
.navds-combobox__list--with-hover .navds-combobox__list-item--new-option:hover {
|
||||
border-bottom: 1px solid var(--a-border-divider);
|
||||
background: var(--a-surface-neutral-subtle-hover);
|
||||
}
|
||||
|
||||
.navds-combobox__list-item__new-option--focus {
|
||||
.navds-combobox__list-item--new-option--focus {
|
||||
box-shadow:
|
||||
var(--a-shadow-focus) inset,
|
||||
var(--a-border-action) 0 0 0 5px inset;
|
||||
@@ -332,3 +379,49 @@
|
||||
gap: var(--a-spacing-1);
|
||||
}
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-combobox__button-clear:hover {
|
||||
color: highlight;
|
||||
}
|
||||
|
||||
.navds-combobox__wrapper-inner:has(.navds-combobox__input:focus-visible) {
|
||||
outline-color: highlight;
|
||||
}
|
||||
|
||||
.navds-combobox__list-item--focus,
|
||||
.navds-combobox__list--with-hover
|
||||
.navds-combobox__list-item:not([data-no-focus="true"], .navds-combobox__list-item--new-option):hover {
|
||||
border-left-color: highlight;
|
||||
color: highlight;
|
||||
}
|
||||
|
||||
.navds-combobox__list-item[data-no-focus="true"] {
|
||||
opacity: 1;
|
||||
color: graytext;
|
||||
}
|
||||
|
||||
.navds-combobox__list-item--selected {
|
||||
background-color: selecteditem;
|
||||
color: selecteditemtext;
|
||||
}
|
||||
|
||||
.navds-combobox__list-item--selected > * {
|
||||
forced-color-adjust: none;
|
||||
}
|
||||
|
||||
.navds-combobox__list-item--selected.navds-combobox__list-item--focus,
|
||||
.navds-combobox__list--with-hover .navds-combobox__list-item--selected:hover {
|
||||
border-left-color: highlight;
|
||||
color: highlight;
|
||||
}
|
||||
|
||||
.navds-combobox__list--with-hover .navds-combobox__list-item--new-option:hover {
|
||||
color: highlight;
|
||||
}
|
||||
|
||||
.navds-combobox__list-item--new-option--focus {
|
||||
outline: 2px solid highlight;
|
||||
outline-offset: -3px;
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
background-color: var(--ac-confirmation-panel-bg, var(--a-surface-warning-subtle));
|
||||
transition: background-color linear 100ms;
|
||||
justify-self: stretch;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.navds-confirmation-panel__content {
|
||||
@@ -23,3 +24,26 @@
|
||||
border-color: var(--ac-confirmation-panel-error-border, var(--a-border-danger));
|
||||
background-color: var(--ac-confirmation-panel-error-bg, var(--a-surface-danger-subtle));
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-confirmation-panel__inner::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
border-left: 8px solid;
|
||||
border-color: orange;
|
||||
forced-color-adjust: none;
|
||||
border-start-start-radius: calc(var(--a-border-radius-medium) - 1px);
|
||||
border-end-start-radius: calc(var(--a-border-radius-medium) - 1px);
|
||||
}
|
||||
|
||||
.navds-confirmation-panel--checked .navds-confirmation-panel__inner::before {
|
||||
border-color: green;
|
||||
}
|
||||
|
||||
.navds-confirmation-panel--error .navds-confirmation-panel__inner::before {
|
||||
border-color: red;
|
||||
}
|
||||
}
|
||||
@@ -42,3 +42,10 @@
|
||||
.navds-fieldset:disabled > .navds-fieldset__description {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-fieldset:disabled > .navds-fieldset__legend,
|
||||
.navds-fieldset:disabled > .navds-fieldset__description {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@@ -51,3 +51,9 @@
|
||||
flex-shrink: 0;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-form-field--disabled {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@@ -72,6 +72,8 @@
|
||||
|
||||
.navds-checkbox__input:focus-visible + .navds-checkbox__label::before,
|
||||
.navds-radio__input:focus-visible + .navds-radio__label::before {
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
box-shadow:
|
||||
0 0 0 2px var(--ac-radio-checkbox-border, var(--a-border-default)),
|
||||
0 0 0 2px var(--ac-radio-checkbox-bg, var(--a-surface-default)),
|
||||
@@ -81,6 +83,8 @@
|
||||
@supports not selector(:focus-visible) {
|
||||
.navds-checkbox__input:focus + .navds-checkbox__label::before,
|
||||
.navds-radio__input:focus + .navds-radio__label::before {
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
box-shadow:
|
||||
0 0 0 2px var(--ac-radio-checkbox-border, var(--a-border-default)),
|
||||
0 0 0 4px var(--a-border-focus);
|
||||
@@ -139,6 +143,10 @@
|
||||
height: 1.5rem;
|
||||
transform: translate(var(--a-spacing-1-alt));
|
||||
pointer-events: none;
|
||||
|
||||
/* Fixed edcase where when using in shadow-dom, svg will not center */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.navds-checkbox--small .navds-checkbox__input:checked + .navds-checkbox__label > .navds-checkbox__icon {
|
||||
@@ -352,3 +360,81 @@
|
||||
.navds-checkbox--readonly > .navds-checkbox__input:indeterminate + .navds-checkbox__label::after {
|
||||
background-color: var(--a-icon-subtle);
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-checkbox__input:focus-visible + .navds-checkbox__label::before,
|
||||
.navds-radio__input:focus-visible + .navds-radio__label::before {
|
||||
outline-color: highlight;
|
||||
}
|
||||
|
||||
.navds-checkbox,
|
||||
.navds-radio {
|
||||
--__ac-radio-checkbox-high-contrast-bg: field;
|
||||
--__ac-radio-checkbox-high-contrast-text: fieldtext;
|
||||
--__ac-radio-checkbox-high-contrast-highlight: highlight;
|
||||
}
|
||||
|
||||
.navds-checkbox__label::before,
|
||||
.navds-radio__label::before {
|
||||
border: 1px solid var(--__ac-radio-checkbox-high-contrast-text);
|
||||
background-color: var(--__ac-radio-checkbox-high-contrast-bg);
|
||||
}
|
||||
|
||||
.navds-checkbox__input:checked + .navds-checkbox__label > .navds-checkbox__icon {
|
||||
color: var(--__ac-radio-checkbox-high-contrast-text);
|
||||
}
|
||||
|
||||
.navds-checkbox__input:indeterminate + .navds-checkbox__label::after {
|
||||
background-color: var(--__ac-radio-checkbox-high-contrast-text);
|
||||
}
|
||||
|
||||
.navds-radio__input:checked + .navds-radio__label::before {
|
||||
border: 1px solid var(--__ac-radio-checkbox-high-contrast-text);
|
||||
outline: 3px solid var(--__ac-radio-checkbox-high-contrast-bg);
|
||||
outline-offset: -4px;
|
||||
background-color: var(--__ac-radio-checkbox-high-contrast-text);
|
||||
}
|
||||
|
||||
.navds-radio__input:checked:focus-visible + .navds-radio__label::before {
|
||||
border: 1px solid var(--__ac-radio-checkbox-high-contrast-bg);
|
||||
outline: 2px solid highlight;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
:not(.navds-checkbox--readonly) > .navds-checkbox__input:hover:not(:disabled) + .navds-checkbox__label,
|
||||
:not(.navds-radio--readonly) > .navds-radio__input:hover:not(:disabled) + .navds-radio__label {
|
||||
color: highlight;
|
||||
}
|
||||
|
||||
.navds-checkbox__input:focus-visible + .navds-checkbox__label::before {
|
||||
outline: 2px solid var(--__ac-radio-checkbox-high-contrast-highlight);
|
||||
}
|
||||
|
||||
.navds-checkbox--readonly > .navds-checkbox__input:checked + .navds-checkbox__label::before {
|
||||
border: 1px solid var(--__ac-radio-checkbox-high-contrast-text);
|
||||
background-color: var(--__ac-radio-checkbox-high-contrast-bg);
|
||||
}
|
||||
|
||||
.navds-checkbox--readonly > .navds-checkbox__input:indeterminate + .navds-checkbox__label::after {
|
||||
background-color: var(--__ac-radio-checkbox-high-contrast-text);
|
||||
}
|
||||
|
||||
.navds-radio--readonly > .navds-radio__input:checked + .navds-radio__label::before {
|
||||
border: 1px solid var(--__ac-radio-checkbox-high-contrast-text);
|
||||
outline: 3px solid var(--__ac-radio-checkbox-high-contrast-bg);
|
||||
outline-offset: -4px;
|
||||
background-color: var(--__ac-radio-checkbox-high-contrast-text);
|
||||
}
|
||||
|
||||
.navds-checkbox--disabled,
|
||||
.navds-radio--disabled {
|
||||
opacity: 1;
|
||||
|
||||
--__ac-radio-checkbox-high-contrast-bg: field;
|
||||
--__ac-radio-checkbox-high-contrast-text: graytext;
|
||||
}
|
||||
|
||||
:is(.navds-checkbox--disabled, .navds-radio--disabled) :is(.navds-checkbox__label, .navds-radio__label) {
|
||||
color: graytext;
|
||||
}
|
||||
}
|
||||
@@ -99,14 +99,14 @@
|
||||
}
|
||||
|
||||
.navds-search__button-clear:focus-visible {
|
||||
outline: 2px solid transparent;
|
||||
box-shadow: var(--a-shadow-focus);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@supports not selector(:focus-visible) {
|
||||
.navds-search__button-clear:focus {
|
||||
outline: 2px solid transparent;
|
||||
box-shadow: var(--a-shadow-focus);
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,3 +216,13 @@
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-modal {
|
||||
outline: 2px solid transparent;
|
||||
}
|
||||
|
||||
.navds-search__button-clear:hover {
|
||||
color: highlight;
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,21 @@
|
||||
padding-right: 2rem;
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-select__input.navds-select__input.navds-select__input {
|
||||
background-color: ButtonFace;
|
||||
border-color: ButtonText;
|
||||
color: ButtonText;
|
||||
forced-color-adjust: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.navds-select__input.navds-select__input.navds-select__input:focus-visible {
|
||||
outline: 2px solid highlight;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.navds-select__input:hover {
|
||||
border-color: var(--ac-select-hover-bg, var(--a-border-action));
|
||||
cursor: pointer;
|
||||
@@ -46,6 +61,12 @@
|
||||
color: var(--ac-select-text, var(--a-text-default));
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-select__chevron {
|
||||
color: ButtonText;
|
||||
}
|
||||
}
|
||||
|
||||
.navds-form-field--small .navds-select__input {
|
||||
min-height: 2rem;
|
||||
padding: 0 var(--a-spacing-8) 0 var(--a-spacing-2);
|
||||
|
||||
@@ -111,6 +111,8 @@
|
||||
}
|
||||
|
||||
.navds-switch__input:focus-visible ~ .navds-switch__track {
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
box-shadow:
|
||||
0 0 0 1px var(--a-surface-default),
|
||||
var(--a-shadow-focus);
|
||||
@@ -118,6 +120,7 @@
|
||||
|
||||
@supports not selector(:focus-visible) {
|
||||
.navds-switch__input:focus ~ .navds-switch__track {
|
||||
outline: 2px solid transparent;
|
||||
box-shadow:
|
||||
0 0 0 1px var(--a-surface-default),
|
||||
var(--a-shadow-focus);
|
||||
@@ -218,3 +221,49 @@
|
||||
transform: translateX(1.25rem);
|
||||
}
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-switch__input:hover ~ .navds-switch__label-wrapper,
|
||||
.navds-switch__label-wrapper:hover {
|
||||
color: highlight;
|
||||
}
|
||||
|
||||
.navds-switch__thumb,
|
||||
.navds-switch--readonly .navds-switch__thumb {
|
||||
background-color: fieldtext;
|
||||
}
|
||||
|
||||
.navds-switch__input:checked ~ .navds-switch__track > .navds-switch__thumb,
|
||||
.navds-switch--readonly .navds-switch__input:checked ~ .navds-switch__track > .navds-switch__thumb {
|
||||
color: field;
|
||||
}
|
||||
|
||||
.navds-switch__track {
|
||||
width: calc(2.75rem + 4px);
|
||||
height: calc(1.5rem + 4px);
|
||||
top: var(--a-spacing-3);
|
||||
border: 2px solid fieldtext;
|
||||
}
|
||||
|
||||
.navds-switch__input:focus-visible ~ .navds-switch__track {
|
||||
outline: 2px solid highlight;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.navds-switch--disabled:not(.navds-switch--loading) {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.navds-switch--disabled:not(.navds-switch--loading) .navds-switch__thumb {
|
||||
background-color: graytext;
|
||||
}
|
||||
|
||||
.navds-switch--disabled:not(.navds-switch--loading) .navds-switch__track {
|
||||
border-color: graytext;
|
||||
}
|
||||
|
||||
.navds-switch--disabled:not(.navds-switch--loading) .navds-switch__label-wrapper,
|
||||
.navds-switch--disabled:not(.navds-switch--loading) .navds-switch__label-wrapper:hover {
|
||||
color: graytext !important;
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,8 @@
|
||||
}
|
||||
|
||||
.navds-text-field__input:focus-visible {
|
||||
outline: none;
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
box-shadow: var(--a-shadow-focus);
|
||||
}
|
||||
|
||||
@@ -101,3 +102,10 @@
|
||||
.navds-text-field__input[type="search"]::-webkit-search-results-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-text-field__input {
|
||||
background-color: field;
|
||||
color: fieldtext;
|
||||
}
|
||||
}
|
||||
@@ -52,13 +52,15 @@
|
||||
}
|
||||
|
||||
.navds-textarea__input:focus-visible {
|
||||
outline: none;
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
box-shadow: var(--a-shadow-focus);
|
||||
}
|
||||
|
||||
@supports not selector(:focus-visible) {
|
||||
.navds-textarea__input:focus {
|
||||
outline: none;
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
box-shadow: var(--a-shadow-focus);
|
||||
}
|
||||
}
|
||||
@@ -141,3 +143,10 @@
|
||||
border-color: var(--a-border-subtle);
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-textarea__input {
|
||||
background-color: field;
|
||||
color: fieldtext;
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
}
|
||||
|
||||
.navds-help-text__button:focus-visible {
|
||||
outline: none;
|
||||
outline: 2px solid transparent;
|
||||
box-shadow:
|
||||
0 0 0 1px var(--a-border-focus),
|
||||
inset 0 0 0 1px var(--a-border-focus);
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
@supports not selector(:focus-visible) {
|
||||
.navds-help-text__button:focus {
|
||||
outline: none;
|
||||
outline: 2px solid transparent;
|
||||
box-shadow:
|
||||
0 0 0 1px var(--a-border-focus),
|
||||
inset 0 0 0 1px var(--a-border-focus);
|
||||
@@ -64,3 +64,17 @@
|
||||
display: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-help-text__button:where(:hover, :focus-visible, [aria-expanded="true"]) > .navds-help-text__icon {
|
||||
display: inherit;
|
||||
}
|
||||
|
||||
.navds-help-text__button:hover > .navds-help-text__icon {
|
||||
color: highlight;
|
||||
}
|
||||
|
||||
.navds-help-text__button:where(:hover, :focus-visible, [aria-expanded="true"]) > .navds-help-text__icon--filled {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,27 @@
|
||||
--navds-internalheader-focus: inset 0 0 0 2px var(--a-border-focus-on-inverted);
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-internalheader {
|
||||
background-color: ButtonFace;
|
||||
border-color: ButtonText;
|
||||
border: solid 1px ButtonText;
|
||||
color: ButtonText;
|
||||
}
|
||||
|
||||
.navds-internalheader a:focus-visible {
|
||||
box-shadow: none;
|
||||
outline: 2px solid highlight;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.navds-internalheader .navds-internalheader__button:focus-visible {
|
||||
box-shadow: none;
|
||||
outline: 2px solid highlight;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.navds-internalheader__title {
|
||||
border: none;
|
||||
overflow: visible;
|
||||
|
||||
@@ -18,14 +18,16 @@
|
||||
}
|
||||
|
||||
.navds-link-panel:focus-visible {
|
||||
outline: 3px solid transparent;
|
||||
outline-offset: 2px;
|
||||
box-shadow: var(--a-shadow-focus);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@supports not selector(:focus-visible) {
|
||||
.navds-link-panel:focus {
|
||||
outline: 3px solid transparent;
|
||||
outline-offset: 2px;
|
||||
box-shadow: var(--a-shadow-focus);
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
}
|
||||
|
||||
.navds-link:focus-visible {
|
||||
outline: none;
|
||||
outline: 2px solid transparent;
|
||||
color: var(--ac-link-focus-text, var(--a-text-on-action));
|
||||
text-decoration: none;
|
||||
background-color: var(--ac-link-focus-bg, var(--a-border-focus));
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
@supports not selector(:focus-visible) {
|
||||
.navds-link:focus {
|
||||
outline: none;
|
||||
outline: 2px solid transparent;
|
||||
color: var(--ac-link-focus-text, var(--a-text-on-action));
|
||||
text-decoration: none;
|
||||
background-color: var(--ac-link-focus-bg, var(--a-border-focus));
|
||||
@@ -54,7 +54,7 @@
|
||||
}
|
||||
|
||||
.navds-link:active {
|
||||
outline: none;
|
||||
outline: 2px solid transparent;
|
||||
color: var(--ac-link-active-text, var(--a-text-on-action));
|
||||
text-decoration: none;
|
||||
background-color: var(--ac-link-active-bg, var(--a-border-focus));
|
||||
|
||||
@@ -111,3 +111,9 @@
|
||||
stroke-dashoffset: -120px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-loader__background {
|
||||
stroke: canvastext;
|
||||
}
|
||||
}
|
||||
@@ -168,3 +168,9 @@
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-modal {
|
||||
outline: 2px solid transparent;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-css",
|
||||
"version": "5.15.1",
|
||||
"version": "5.18.2",
|
||||
"description": "CSS for NAV Designsystem",
|
||||
"author": "Aksel | NAV designsystem team",
|
||||
"keywords": [
|
||||
@@ -27,7 +27,7 @@
|
||||
"css:get-version": "node config/get-version.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@navikt/ds-tokens": "^5.15.1",
|
||||
"@navikt/ds-tokens": "^5.18.2",
|
||||
"cssnano": "6.0.0",
|
||||
"fast-glob": "3.2.11",
|
||||
"lodash": "4.17.21",
|
||||
|
||||
@@ -59,3 +59,26 @@
|
||||
border-right-color: transparent;
|
||||
border-top-color: transparent;
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-popover[data-placement^="top"] > .navds-popover__arrow {
|
||||
border-left-color: canvas;
|
||||
border-top-color: canvas;
|
||||
}
|
||||
|
||||
/* prettier-ignore */
|
||||
.navds-popover[data-placement^="bottom"] > .navds-popover__arrow {
|
||||
border-bottom-color: canvas;
|
||||
border-right-color: canvas;
|
||||
}
|
||||
|
||||
.navds-popover[data-placement^="left"] > .navds-popover__arrow {
|
||||
border-left-color: canvas;
|
||||
border-bottom-color: canvas;
|
||||
}
|
||||
|
||||
.navds-popover[data-placement^="right"] > .navds-popover__arrow {
|
||||
border-right-color: canvas;
|
||||
border-top-color: canvas;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,21 @@
|
||||
padding: var(--a-spacing-05) var(--a-spacing-1) var(--a-spacing-05) var(--a-spacing-05);
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-read-more__button {
|
||||
background-color: ButtonFace;
|
||||
border-color: ButtonText;
|
||||
border: solid 1px ButtonText;
|
||||
color: ButtonText;
|
||||
}
|
||||
|
||||
.navds-read-more__button.navds-read-more__button:focus-visible {
|
||||
box-shadow: none;
|
||||
outline: 2px solid highlight;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.navds-read-more__button:hover {
|
||||
background-color: var(--ac-read-more-hover-bg, var(--a-surface-hover));
|
||||
}
|
||||
|
||||
Vendored
+8
@@ -57,3 +57,11 @@
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-skeleton {
|
||||
forced-color-adjust: none;
|
||||
background-color: var(--a-surface-neutral);
|
||||
animation-duration: 2s;
|
||||
}
|
||||
}
|
||||
@@ -70,6 +70,41 @@
|
||||
margin: calc(var(--navds-stepper-border-width) * -1) calc(var(--navds-stepper-border-width) * -1) 1.75rem;
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-stepper__step {
|
||||
background-color: ButtonFace;
|
||||
color: ButtonText;
|
||||
}
|
||||
|
||||
.navds-stepper__circle.navds-stepper__circle {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.navds-stepper__step .navds-stepper__circle {
|
||||
forced-color-adjust: none;
|
||||
background-color: ButtonText;
|
||||
border-color: ButtonText;
|
||||
color: ButtonFace;
|
||||
}
|
||||
|
||||
.navds-stepper__step.navds-stepper__step:focus-visible {
|
||||
box-shadow: none;
|
||||
outline: 2px solid highlight;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.navds-stepper__step.navds-stepper__step--active .navds-stepper__circle {
|
||||
forced-color-adjust: none;
|
||||
background-color: highlight;
|
||||
border-color: highlighttext;
|
||||
color: highlighttext;
|
||||
}
|
||||
|
||||
.navds-stepper__line {
|
||||
background-color: ButtonText;
|
||||
}
|
||||
}
|
||||
|
||||
button.navds-stepper__step {
|
||||
appearance: none;
|
||||
border: none;
|
||||
|
||||
@@ -264,3 +264,29 @@
|
||||
.navds-table--small .navds-table__expanded-row-content {
|
||||
padding: var(--a-spacing-2) calc(var(--a-spacing-2) + 3rem);
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-date.navds-date button.rdp-day_selected {
|
||||
forced-color-adjust: none;
|
||||
background-color: highlight;
|
||||
color: highlighttext;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.navds-date.navds-date button {
|
||||
color: buttontext;
|
||||
forced-color-adjust: none;
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.navds-date button:focus-visible {
|
||||
color: buttontext;
|
||||
forced-color-adjust: none;
|
||||
outline: 2px solid highlight;
|
||||
}
|
||||
|
||||
.navds-date.navds-date button.rdp-day_disabled {
|
||||
color: GrayText;
|
||||
}
|
||||
}
|
||||
@@ -63,14 +63,15 @@
|
||||
}
|
||||
|
||||
.navds-tabs__tab:focus-visible {
|
||||
outline: none;
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: -2px;
|
||||
box-shadow: inset var(--a-shadow-focus);
|
||||
color: var(--ac-tabs-focus-text, var(--a-text-default));
|
||||
}
|
||||
|
||||
@supports not selector(:focus-visible) {
|
||||
.navds-tabs__tab:focus {
|
||||
outline: none;
|
||||
outline: 2px solid transparent;
|
||||
box-shadow: inset var(--a-shadow-focus);
|
||||
color: var(--ac-tabs-focus-text, var(--a-text-default));
|
||||
}
|
||||
@@ -117,13 +118,29 @@
|
||||
}
|
||||
|
||||
.navds-tabs__tabpanel:focus-visible {
|
||||
outline: none;
|
||||
outline: 2px solid transparent;
|
||||
box-shadow: inset 0 0 0 2px var(--a-border-focus);
|
||||
}
|
||||
|
||||
@supports not selector(:focus-visible) {
|
||||
.navds-tabs__tabpanel:focus {
|
||||
outline: none;
|
||||
outline: 2px solid transparent;
|
||||
box-shadow: inset 0 0 0 2px var(--a-border-focus);
|
||||
}
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-tabs__tab[aria-selected="true"] {
|
||||
border-bottom: 3px solid canvastext;
|
||||
padding-block-end: calc(var(--a-spacing-3) - 3px);
|
||||
}
|
||||
|
||||
.navds-tabs__tab--small[aria-selected="true"] {
|
||||
padding-block-end: calc(var(--a-spacing-1-alt) - 3px);
|
||||
}
|
||||
|
||||
.navds-tabs__tab-icon--top[aria-selected="true"],
|
||||
.navds-tabs__tab--small.navds-tabs__tab-icon--top[aria-selected="true"] {
|
||||
padding-block-end: calc(var(--a-spacing-1) - 3px);
|
||||
}
|
||||
}
|
||||
@@ -180,3 +180,15 @@
|
||||
background-color: var(--ac-tag-alt-3-moderate-bg, var(--a-surface-alt-3-moderate));
|
||||
color: var(--ac-tag-alt-3-moderate-text, var(--a-text-default));
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-tag {
|
||||
forced-color-adjust: none;
|
||||
}
|
||||
|
||||
.navds-tag--neutral,
|
||||
.navds-tag--neutral-moderate {
|
||||
border-color: canvastext;
|
||||
color: canvastext;
|
||||
}
|
||||
}
|
||||
@@ -393,3 +393,57 @@
|
||||
border-right-color: transparent;
|
||||
border-top-color: transparent;
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-timeline__period:focus {
|
||||
outline: 2px solid highlight;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.navds-timeline__period--success,
|
||||
.navds-timeline__period--warning,
|
||||
.navds-timeline__period--info,
|
||||
.navds-timeline__period--neutral,
|
||||
.navds-timeline__period--danger {
|
||||
forced-color-adjust: none;
|
||||
}
|
||||
|
||||
.navds-timeline__row {
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.navds-timeline__pin-wrapper::before {
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.navds-timeline__pin-button {
|
||||
outline: 4px solid transparent;
|
||||
}
|
||||
|
||||
.navds-timeline__pin-button:focus,
|
||||
.navds-timeline__pin-button:focus-visible {
|
||||
outline: 4px solid highlight;
|
||||
outline-offset: 2px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.navds-timeline__popover[data-placement^="top"] > .navds-timeline__popover-arrow {
|
||||
border-left-color: canvas;
|
||||
border-top-color: canvas;
|
||||
}
|
||||
|
||||
.navds-timeline__popover[data-placement^="bottom"] > .navds-timeline__popover-arrow {
|
||||
border-bottom-color: canvas;
|
||||
border-right-color: canvas;
|
||||
}
|
||||
|
||||
.navds-timeline__popover[data-placement^="left"] > .navds-timeline__popover-arrow {
|
||||
border-left-color: canvas;
|
||||
border-bottom-color: canvas;
|
||||
}
|
||||
|
||||
.navds-timeline__popover[data-placement^="right"] > .navds-timeline__popover-arrow {
|
||||
border-right-color: canvas;
|
||||
border-top-color: canvas;
|
||||
}
|
||||
}
|
||||
@@ -65,7 +65,8 @@
|
||||
}
|
||||
|
||||
.navds-toggle-group__button:focus-visible {
|
||||
outline: none;
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 1px;
|
||||
box-shadow:
|
||||
0 0 0 1px var(--a-surface-default),
|
||||
0 0 0 4px var(--a-border-focus);
|
||||
@@ -73,7 +74,8 @@
|
||||
|
||||
@supports not selector(:focus-visible) {
|
||||
.navds-toggle-group__button:focus {
|
||||
outline: none;
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 1px;
|
||||
box-shadow:
|
||||
0 0 0 1px var(--a-surface-default),
|
||||
0 0 0 4px var(--a-border-focus);
|
||||
@@ -144,3 +146,32 @@
|
||||
.navds-toggle-group--small > .navds-toggle-group__button > .navds-toggle-group__button-inner > svg {
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-toggle-group {
|
||||
border: 2px solid transparent;
|
||||
}
|
||||
|
||||
.navds-toggle-group__button:hover {
|
||||
color: highlight;
|
||||
}
|
||||
|
||||
.navds-toggle-group__button[aria-checked="true"],
|
||||
.navds-toggle-group__button[aria-pressed="true"] {
|
||||
background-color: selecteditem;
|
||||
color: selecteditemtext;
|
||||
}
|
||||
|
||||
.navds-toggle-group__button[aria-checked="true"] > *,
|
||||
.navds-toggle-group__button[aria-pressed="true"] > * {
|
||||
forced-color-adjust: none;
|
||||
}
|
||||
|
||||
.navds-toggle-group__button:active {
|
||||
background-color: none !important;
|
||||
}
|
||||
|
||||
.navds-toggle-group__button:focus-visible {
|
||||
outline-color: highlight;
|
||||
}
|
||||
}
|
||||
@@ -392,6 +392,8 @@
|
||||
"--ac-combobox-list-item-loading-bg": "--a-surface-default",
|
||||
"--ac-combobox-list-item-hover-border-left": "--a-border-strong",
|
||||
"--ac-combobox-list-item-selected-hover-border-left": "--a-border-focus",
|
||||
"--ac-combobox-list-item-max-selected-bg": "--a-surface-info-subtle",
|
||||
"--ac-combobox-list-item-max-selected-border": "--a-border-info",
|
||||
"--ac-combobox-error-border": "--a-border-danger"
|
||||
},
|
||||
"select": {
|
||||
|
||||
@@ -51,3 +51,31 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-tooltip {
|
||||
--__a-tooltip-high-contrast-border: 1px solid transparent;
|
||||
|
||||
border: var(--__a-tooltip-high-contrast-border);
|
||||
}
|
||||
|
||||
.navds-tooltip[data-side="top"] .navds-tooltip__arrow {
|
||||
border-bottom: var(--__a-tooltip-high-contrast-border);
|
||||
border-right: var(--__a-tooltip-high-contrast-border);
|
||||
}
|
||||
|
||||
.navds-tooltip[data-side="right"] .navds-tooltip__arrow {
|
||||
border-bottom: var(--__a-tooltip-high-contrast-border);
|
||||
border-left: var(--__a-tooltip-high-contrast-border);
|
||||
}
|
||||
|
||||
.navds-tooltip[data-side="bottom"] .navds-tooltip__arrow {
|
||||
border-left: var(--__a-tooltip-high-contrast-border);
|
||||
border-top: var(--__a-tooltip-high-contrast-border);
|
||||
}
|
||||
|
||||
.navds-tooltip[data-side="left"] .navds-tooltip__arrow {
|
||||
border-top: var(--__a-tooltip-high-contrast-border);
|
||||
border-right: var(--__a-tooltip-high-contrast-border);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,113 @@
|
||||
# @navikt/ds-react
|
||||
|
||||
## 5.18.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Modal: Oppdatert intern håntering av context i komponent ([#2714](https://github.com/navikt/aksel/pull/2714))
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.18.2
|
||||
- @navikt/aksel-icons@5.18.2
|
||||
|
||||
## 5.18.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Panel: Komponent er nå markert som deprecated. Bruk `Box` i fremtiden. ([#2712](https://github.com/navikt/aksel/pull/2712))
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.18.1
|
||||
- @navikt/aksel-icons@5.18.1
|
||||
|
||||
## 5.18.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Portal: Ny komponent `Portal` som lar deg enkelt bruke `createPortal`, også på serversiden ([#2697](https://github.com/navikt/aksel/pull/2697))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.18.0
|
||||
- @navikt/aksel-icons@5.18.0
|
||||
|
||||
## 5.17.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.17.5
|
||||
- @navikt/aksel-icons@5.17.5
|
||||
|
||||
## 5.17.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Bleed: `marginInline='full'` og `reflectivePadding` kan nå brukes sammen. ([#2695](https://github.com/navikt/aksel/pull/2695))
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.17.4
|
||||
- @navikt/aksel-icons@5.17.4
|
||||
|
||||
## 5.17.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- :bug: Textarea: maxLength virker nå selv om man sender inn onChange uten å sende inn value ([#2690](https://github.com/navikt/aksel/pull/2690))
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.17.3
|
||||
- @navikt/aksel-icons@5.17.3
|
||||
|
||||
## 5.17.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- :bug: Textarea: Sett riktig høyde når brukt i Modal + StrictMode ([#2679](https://github.com/navikt/aksel/pull/2679))
|
||||
|
||||
- DatePicker: Knapper fikk ikke riktig aria-label ([#2678](https://github.com/navikt/aksel/pull/2678))
|
||||
|
||||
- Textarea: debounce ResizeObserver for å unngå feilmelding ([#2685](https://github.com/navikt/aksel/pull/2685))
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.17.2
|
||||
- @navikt/aksel-icons@5.17.2
|
||||
|
||||
## 5.17.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Eksponer variabelen "role" i Search-komponenten ([#2667](https://github.com/navikt/aksel/pull/2667))
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.17.1
|
||||
- @navikt/aksel-icons@5.17.1
|
||||
|
||||
## 5.17.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Høykontrast: Komponenter støtter nå standard høykontrast-modus på Windows ([#2680](https://github.com/navikt/aksel/pull/2680))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.17.0
|
||||
- @navikt/aksel-icons@5.17.0
|
||||
|
||||
## 5.16.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- :sparkles: Combobox: Mulighet for å begrense hvor mange valg bruker kan ta ([#2260](https://github.com/navikt/aksel/pull/2260))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`eff9b5ecc`](https://github.com/navikt/aksel/commit/eff9b5ecce2817e3823ce61be7635359eec98451)]:
|
||||
- @navikt/aksel-icons@5.16.0
|
||||
- @navikt/ds-tokens@5.16.0
|
||||
|
||||
## 5.15.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-react",
|
||||
"version": "5.15.1",
|
||||
"version": "5.18.2",
|
||||
"description": "Aksel react-components for NAV designsystem",
|
||||
"author": "Aksel | NAV designsystem team",
|
||||
"license": "MIT",
|
||||
@@ -38,8 +38,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@floating-ui/react": "0.25.4",
|
||||
"@navikt/aksel-icons": "^5.15.1",
|
||||
"@navikt/ds-tokens": "^5.15.1",
|
||||
"@navikt/aksel-icons": "^5.18.2",
|
||||
"@navikt/ds-tokens": "^5.18.2",
|
||||
"@radix-ui/react-tabs": "1.0.0",
|
||||
"@radix-ui/react-toggle-group": "1.0.0",
|
||||
"clsx": "^1.2.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { StoryObj } from "@storybook/react";
|
||||
import React, { useState } from "react";
|
||||
import { Accordion, AccordionProps } from ".";
|
||||
import { Table } from "..";
|
||||
import AccordionContent from "./AccordionContent";
|
||||
import AccordionHeader from "./AccordionHeader";
|
||||
import AccordionItem from "./AccordionItem";
|
||||
@@ -13,13 +13,15 @@ export default {
|
||||
AccordionContent,
|
||||
AccordionHeader,
|
||||
},
|
||||
parameters: {
|
||||
chromatic: { disable: true },
|
||||
},
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<div
|
||||
style={{
|
||||
width: "600px",
|
||||
minHeight: "100vh",
|
||||
padding: "10rem 0",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "1rem",
|
||||
@@ -29,25 +31,10 @@ export default {
|
||||
</div>
|
||||
),
|
||||
],
|
||||
argTypes: {
|
||||
variant: {
|
||||
options: ["default", "neutral"],
|
||||
control: { type: "select" },
|
||||
},
|
||||
headingSize: {
|
||||
options: ["large", "medium", "small", "xsmall"],
|
||||
control: { type: "select" },
|
||||
},
|
||||
size: {
|
||||
options: ["large", "medium", "small"],
|
||||
control: { type: "select" },
|
||||
},
|
||||
nItems: {
|
||||
control: { type: "number" },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
type Story = StoryObj<typeof Accordion>;
|
||||
|
||||
const Content = () => (
|
||||
<Accordion.Content>
|
||||
Magna aliquip aliquip fugiat nostrud nostrud velit pariatur veniam officia
|
||||
@@ -103,22 +90,34 @@ const Item = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const Default = {
|
||||
render: ({ nItems, ...props }) => {
|
||||
export const Controls: Story = {
|
||||
render: ({ ...props }) => {
|
||||
return (
|
||||
<div style={{ width: 500 }}>
|
||||
<Accordion {...props}>
|
||||
{[...Array(nItems ? nItems : 2)].map((_, y) => (
|
||||
{[...Array(4)].map((_, y) => (
|
||||
<Item key={y} {...props} />
|
||||
))}
|
||||
</Accordion>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
argTypes: {
|
||||
variant: {
|
||||
options: ["default", "neutral"],
|
||||
control: { type: "select" },
|
||||
},
|
||||
headingSize: {
|
||||
options: ["large", "medium", "small", "xsmall"],
|
||||
control: { type: "select" },
|
||||
},
|
||||
size: {
|
||||
options: ["large", "medium", "small"],
|
||||
control: { type: "select" },
|
||||
},
|
||||
},
|
||||
|
||||
args: {
|
||||
controlled: false,
|
||||
nItems: 2,
|
||||
variant: "default",
|
||||
headingSize: "medium",
|
||||
size: "medium",
|
||||
@@ -126,37 +125,31 @@ export const Default = {
|
||||
},
|
||||
};
|
||||
|
||||
export const DefaultOpen = {
|
||||
render: ({ nItems, openItems, ...props }) => {
|
||||
export const DefaultOpen: Story = {
|
||||
render: () => {
|
||||
return (
|
||||
<div style={{ width: 500 }}>
|
||||
<Accordion {...props}>
|
||||
{[...Array(nItems ? nItems : 2)].map((_, y) => (
|
||||
<Item key={y} defaultOpen={openItems.includes(y)} {...props} />
|
||||
<Accordion>
|
||||
{[...Array(4)].map((_, y) => (
|
||||
<Item key={y} defaultOpen={y === 2} />
|
||||
))}
|
||||
</Accordion>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
args: {
|
||||
openItems: [1, 2],
|
||||
controlled: false,
|
||||
nItems: 5,
|
||||
variant: "neutral",
|
||||
headingSize: "large",
|
||||
},
|
||||
};
|
||||
|
||||
export const Variants = {
|
||||
export const Variants: Story = {
|
||||
render: () => {
|
||||
return (
|
||||
<div style={{ width: 500 }} className="colgap">
|
||||
<h3>Default</h3>
|
||||
<Accordion>
|
||||
{[...Array(2)].map((_, y) => (
|
||||
<Item key={y} defaultOpen />
|
||||
))}
|
||||
</Accordion>
|
||||
<h3>Neutral</h3>
|
||||
<Accordion variant="neutral">
|
||||
{[...Array(2)].map((_, y) => (
|
||||
<Item key={y} defaultOpen />
|
||||
@@ -167,96 +160,32 @@ export const Variants = {
|
||||
},
|
||||
};
|
||||
|
||||
export const Controlled = (props) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [open2, setOpen2] = useState(false);
|
||||
|
||||
return (
|
||||
<div style={{ width: 500 }}>
|
||||
<Accordion {...props}>
|
||||
<Accordion.Item open={open}>
|
||||
<Accordion.Header onClick={() => setOpen(!open)}>
|
||||
Accordion header text
|
||||
</Accordion.Header>
|
||||
<Content />
|
||||
</Accordion.Item>
|
||||
<Accordion.Item open={open2}>
|
||||
<Accordion.Header onClick={() => setOpen2(!open2)}>
|
||||
Accordion header text
|
||||
</Accordion.Header>
|
||||
<Content />
|
||||
</Accordion.Item>
|
||||
</Accordion>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const WithTable = {
|
||||
render: (props) => {
|
||||
const ExampleTable = () => {
|
||||
return (
|
||||
<Table>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell>ID</Table.HeaderCell>
|
||||
<Table.HeaderCell>Fornavn</Table.HeaderCell>
|
||||
<Table.HeaderCell>Etternavn</Table.HeaderCell>
|
||||
<Table.HeaderCell>Rolle</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell>1</Table.HeaderCell>
|
||||
<Table.DataCell>Jean-Luc</Table.DataCell>
|
||||
<Table.DataCell>Picard</Table.DataCell>
|
||||
<Table.DataCell>Kaptein</Table.DataCell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell>2</Table.HeaderCell>
|
||||
<Table.DataCell>William</Table.DataCell>
|
||||
<Table.DataCell>Riker</Table.DataCell>
|
||||
<Table.DataCell>Kommandør</Table.DataCell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell>3</Table.HeaderCell>
|
||||
<Table.DataCell>Geordi</Table.DataCell>
|
||||
<Table.DataCell>La Forge</Table.DataCell>
|
||||
<Table.DataCell>Sjefsingeniør</Table.DataCell>
|
||||
</Table.Row>
|
||||
</Table.Body>
|
||||
</Table>
|
||||
);
|
||||
};
|
||||
|
||||
const ContentWithTable = () => {
|
||||
return (
|
||||
<Accordion.Content>
|
||||
<ExampleTable />
|
||||
</Accordion.Content>
|
||||
);
|
||||
};
|
||||
export const ControlledState: Story = {
|
||||
render: () => {
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
const [open, setOpen] = useState(false);
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
const [open2, setOpen2] = useState(false);
|
||||
|
||||
return (
|
||||
<div style={{ width: 500 }}>
|
||||
<Accordion {...props}>
|
||||
<Accordion.Item>
|
||||
<Accordion.Header>Table of people</Accordion.Header>
|
||||
<ContentWithTable />
|
||||
<Accordion>
|
||||
<Accordion.Item open={open}>
|
||||
<Accordion.Header onClick={() => setOpen(!open)}>
|
||||
Accordion header text
|
||||
</Accordion.Header>
|
||||
<Content />
|
||||
</Accordion.Item>
|
||||
<Accordion.Item>
|
||||
<Accordion.Header>Table of people</Accordion.Header>
|
||||
<ContentWithTable />
|
||||
<Accordion.Item open={open2}>
|
||||
<Accordion.Header onClick={() => setOpen2(!open2)}>
|
||||
Accordion header text
|
||||
</Accordion.Header>
|
||||
<Content />
|
||||
</Accordion.Item>
|
||||
</Accordion>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
args: {
|
||||
variant: "default",
|
||||
headingSize: "large",
|
||||
indent: false,
|
||||
},
|
||||
};
|
||||
|
||||
const SingleHeaderAccordion = ({
|
||||
@@ -269,9 +198,11 @@ const SingleHeaderAccordion = ({
|
||||
<Accordion.Header>{`${size} size + ${headingSize} heading`}</Accordion.Header>
|
||||
<Accordion.Content>a</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
<Accordion.Item>
|
||||
<Accordion.Item open>
|
||||
<Accordion.Header>{`${size} size + ${headingSize} heading`}</Accordion.Header>
|
||||
<Accordion.Content>a</Accordion.Content>
|
||||
<Accordion.Content>
|
||||
lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
</Accordion.Content>
|
||||
</Accordion.Item>
|
||||
</Accordion>
|
||||
);
|
||||
@@ -285,18 +216,73 @@ const headingSizes: AccordionProps["headingSize"][] = [
|
||||
"xsmall",
|
||||
];
|
||||
|
||||
export const Size = (props) => (
|
||||
<div style={{ width: 500 }} className="colgap">
|
||||
{sizes.map((size) => (
|
||||
<SingleHeaderAccordion key={size} size={size} {...props} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
export const Size: Story = {
|
||||
render: () => (
|
||||
<div style={{ width: 500 }} className="colgap">
|
||||
{sizes.map((size) => (
|
||||
<SingleHeaderAccordion key={size} size={size} />
|
||||
))}
|
||||
</div>
|
||||
),
|
||||
};
|
||||
|
||||
export const HeadingSize = (props) => (
|
||||
<div style={{ width: 500 }} className="colgap">
|
||||
{headingSizes.map((size) => (
|
||||
<SingleHeaderAccordion key={size} headingSize={size} {...props} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
export const HeadingSize: Story = {
|
||||
render: () => (
|
||||
<div style={{ width: 500 }} className="colgap">
|
||||
{headingSizes.map((size) => (
|
||||
<SingleHeaderAccordion key={size} headingSize={size} />
|
||||
))}
|
||||
</div>
|
||||
),
|
||||
};
|
||||
|
||||
export const Indent: Story = {
|
||||
render: () => {
|
||||
return (
|
||||
<div style={{ width: 500 }} className="colgap">
|
||||
<h3>No indent</h3>
|
||||
<Accordion indent>
|
||||
{[...Array(2)].map((_, y) => (
|
||||
<Item key={y} defaultOpen />
|
||||
))}
|
||||
</Accordion>
|
||||
<h3>Indent</h3>
|
||||
<Accordion indent={false}>
|
||||
{[...Array(2)].map((_, y) => (
|
||||
<Item key={y} defaultOpen />
|
||||
))}
|
||||
</Accordion>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const Chromatic: Story = {
|
||||
render: (...props) => (
|
||||
<div>
|
||||
<div>
|
||||
<h2>Variants</h2>
|
||||
{Variants.render?.(...props)}
|
||||
</div>
|
||||
<div>
|
||||
<h2>Size</h2>
|
||||
{Size.render?.(...props)}
|
||||
</div>
|
||||
<div>
|
||||
<h2>HeadingSize</h2>
|
||||
{HeadingSize.render?.(...props)}
|
||||
</div>
|
||||
<div>
|
||||
<h2>DefaultOpen</h2>
|
||||
{DefaultOpen.render?.(...props)}
|
||||
</div>
|
||||
<div>
|
||||
<h2>Indent</h2>
|
||||
{Indent.render?.(...props)}
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
parameters: {
|
||||
chromatic: { disable: false },
|
||||
},
|
||||
};
|
||||
@@ -1,12 +1,16 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { expect, userEvent, within } from "@storybook/test";
|
||||
import React from "react";
|
||||
import { Alert, AlertProps } from ".";
|
||||
import { BodyLong, Heading as DsHeading, Link } from "..";
|
||||
import { VStack } from "../layout/stack";
|
||||
import { Link } from "../link";
|
||||
import { BodyLong, Heading as DsHeading } from "../typography";
|
||||
import Alert, { AlertProps } from "./Alert";
|
||||
|
||||
const meta: Meta<typeof Alert> = {
|
||||
title: "ds-react/Alert",
|
||||
component: Alert,
|
||||
parameters: {
|
||||
chromatic: { disable: true },
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
@@ -20,12 +24,13 @@ const variants: AlertProps["variant"][] = [
|
||||
"success",
|
||||
];
|
||||
|
||||
export const Default: Story = {
|
||||
export const Controls: Story = {
|
||||
render: (props) => <Alert {...props} />,
|
||||
|
||||
args: {
|
||||
children: "Id elit esse enim reprehenderit enim nisi veniam nostrud.",
|
||||
fullWidth: false,
|
||||
inline: false,
|
||||
variant: "info",
|
||||
size: "medium",
|
||||
closeButton: false,
|
||||
@@ -42,43 +47,18 @@ export const Default: Story = {
|
||||
},
|
||||
};
|
||||
|
||||
export const Small: Story = {
|
||||
render: (props) => {
|
||||
return (
|
||||
<div className="colgap">
|
||||
{variants.map((variant, i) => (
|
||||
<Alert
|
||||
key={variant}
|
||||
variant={variant}
|
||||
size="small"
|
||||
closeButton={props.closeButton}
|
||||
>
|
||||
{new Array(i + 1).fill(
|
||||
"Id elit esse enim reprehenderit enim nisi veniam nostrud.",
|
||||
)}
|
||||
</Alert>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
args: {
|
||||
closeButton: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const FullWidth = () => {
|
||||
export const Variants = () => {
|
||||
return (
|
||||
<div className="colgap">
|
||||
{variants.map((variant, i) => (
|
||||
<Alert key={variant} variant={variant} fullWidth>
|
||||
<Alert key={variant} variant={variant}>
|
||||
{new Array(i + 1).fill(
|
||||
"Id elit esse enim reprehenderit enim nisi veniam nostrud.",
|
||||
)}
|
||||
</Alert>
|
||||
))}
|
||||
{variants.map((variant, i) => (
|
||||
<Alert key={variant} variant={variant} fullWidth size="small">
|
||||
<Alert key={variant} variant={variant} size="small">
|
||||
{new Array(i + 1).fill(
|
||||
"Id elit esse enim reprehenderit enim nisi veniam nostrud.",
|
||||
)}
|
||||
@@ -88,24 +68,42 @@ export const FullWidth = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export const FullWidth = () => {
|
||||
return (
|
||||
<VStack gap="4">
|
||||
<Alert variant="info" fullWidth>
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
<Alert variant="info" fullWidth size="small">
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
</VStack>
|
||||
);
|
||||
};
|
||||
|
||||
export const Inline = () => {
|
||||
return (
|
||||
<div className="colgap">
|
||||
{variants.map((variant, i) => (
|
||||
<Alert key={variant} variant={variant} inline>
|
||||
{new Array(i + 1).fill(
|
||||
"Id elit esse enim reprehenderit enim nisi veniam nostrud.",
|
||||
)}
|
||||
</Alert>
|
||||
))}
|
||||
{variants.map((variant, i) => (
|
||||
<Alert key={variant} variant={variant} inline size="small">
|
||||
{new Array(i + 1).fill(
|
||||
"Id elit esse enim reprehenderit enim nisi veniam nostrud.",
|
||||
)}
|
||||
</Alert>
|
||||
))}
|
||||
</div>
|
||||
<VStack gap="4">
|
||||
<h2>Inline</h2>
|
||||
<Alert variant="info" inline>
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
<Alert variant="info" inline>
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud. Id elit esse
|
||||
enim reprehenderit enim nisi veniam nostrud. Id elit esse enim
|
||||
reprehenderit enim nisi veniam nostrud. Id elit esse enim reprehenderit
|
||||
enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
<Alert variant="info" size="small" inline>
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
<Alert variant="info" size="small" inline>
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud. Id elit esse
|
||||
enim reprehenderit enim nisi veniam nostrud. Id elit esse enim
|
||||
reprehenderit enim nisi veniam nostrud. Id elit esse enim reprehenderit
|
||||
enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
</VStack>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -136,82 +134,173 @@ export const Heading = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export const Links = () => {
|
||||
return (
|
||||
<div className="colgap">
|
||||
{variants.map((variant) => (
|
||||
<Alert key={variant} variant={variant}>
|
||||
<Link href="#">Id elit esse enim reprehenderit</Link>
|
||||
</Alert>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const AlertWithCloseButton = ({
|
||||
children,
|
||||
size,
|
||||
}: {
|
||||
size?: "medium" | "small";
|
||||
children?: React.ReactNode;
|
||||
}) => {
|
||||
const [show, setShow] = React.useState(true);
|
||||
|
||||
return show ? (
|
||||
<Alert
|
||||
variant="warning"
|
||||
size={size}
|
||||
closeButton
|
||||
onClose={() => setShow(false)}
|
||||
>
|
||||
{children || "Content"}
|
||||
</Alert>
|
||||
) : null;
|
||||
};
|
||||
|
||||
export const WithCloseButton: Story = {
|
||||
export const CloseButton: Story = {
|
||||
render: () => {
|
||||
return (
|
||||
<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
|
||||
<VStack gap="4">
|
||||
<h2>CloseButton</h2>
|
||||
<Alert variant="info" closeButton>
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
<Alert variant="info" closeButton>
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud. Id elit esse
|
||||
enim reprehenderit enim nisi veniam nostrud. Id elit esse enim
|
||||
reprehenderit enim nisi veniam nostrud. Id elit esse enim
|
||||
reprehenderit enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
<Alert size="small" variant="info" closeButton>
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
<Alert size="small" variant="info" closeButton>
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud. Id elit esse
|
||||
enim reprehenderit enim nisi veniam nostrud. Id elit esse enim
|
||||
reprehenderit enim nisi veniam nostrud. Id elit esse enim
|
||||
reprehenderit enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
<Alert variant="info" closeButton>
|
||||
<DsHeading size="small" level="3">
|
||||
Id elit esse enim reprehenderit
|
||||
</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.
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud.
|
||||
</BodyLong>
|
||||
</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
|
||||
</Alert>
|
||||
<Alert variant="info" closeButton size="small">
|
||||
<DsHeading size="xsmall" level="3">
|
||||
Id elit esse enim reprehenderit
|
||||
</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.
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud.
|
||||
</BodyLong>
|
||||
</AlertWithCloseButton>
|
||||
</div>
|
||||
</Alert>
|
||||
</VStack>
|
||||
);
|
||||
},
|
||||
play: async ({ canvasElement, step }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const buttons = canvas.getAllByTitle("Lukk Alert");
|
||||
};
|
||||
|
||||
await step("click button", async () => {
|
||||
await userEvent.click(buttons[0]);
|
||||
});
|
||||
export const Chromatic: Story = {
|
||||
render: () => (
|
||||
<VStack gap="6">
|
||||
<VStack gap="2">
|
||||
<h2>Variant</h2>
|
||||
{variants.map((variant, i) => (
|
||||
<Alert key={variant} variant={variant}>
|
||||
{new Array(i + 1).fill(
|
||||
"Id elit esse enim reprehenderit enim nisi veniam nostrud.",
|
||||
)}
|
||||
</Alert>
|
||||
))}
|
||||
</VStack>
|
||||
<VStack gap="2">
|
||||
<h2>Small</h2>
|
||||
<Alert variant="info" size="small">
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
<Alert variant="info" size="small">
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud. Id elit esse
|
||||
enim reprehenderit enim nisi veniam nostrud. Id elit esse enim
|
||||
reprehenderit enim nisi veniam nostrud. Id elit esse enim
|
||||
reprehenderit enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
</VStack>
|
||||
<VStack gap="2">
|
||||
<h2>FullWidth</h2>
|
||||
<Alert variant="info" fullWidth>
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
<Alert variant="info" size="small" fullWidth>
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
</VStack>
|
||||
<VStack gap="2">
|
||||
<h2>Inline</h2>
|
||||
<Alert variant="info" inline>
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
<Alert variant="info" inline>
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud. Id elit esse
|
||||
enim reprehenderit enim nisi veniam nostrud. Id elit esse enim
|
||||
reprehenderit enim nisi veniam nostrud. Id elit esse enim
|
||||
reprehenderit enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
<Alert variant="info" size="small" inline>
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
<Alert variant="info" size="small" inline>
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud. Id elit esse
|
||||
enim reprehenderit enim nisi veniam nostrud. Id elit esse enim
|
||||
reprehenderit enim nisi veniam nostrud. Id elit esse enim
|
||||
reprehenderit enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
</VStack>
|
||||
<VStack gap="2">
|
||||
<h2>Heading</h2>
|
||||
<Alert variant="info">
|
||||
<DsHeading size="small" level="3">
|
||||
Id elit esse enim reprehenderit
|
||||
</DsHeading>
|
||||
<BodyLong>
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud.
|
||||
</BodyLong>
|
||||
</Alert>
|
||||
<Alert variant="info" size="small">
|
||||
<DsHeading size="xsmall" level="3">
|
||||
Id elit esse enim reprehenderit
|
||||
</DsHeading>
|
||||
<BodyLong size="small">
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud.
|
||||
</BodyLong>
|
||||
</Alert>
|
||||
</VStack>
|
||||
<VStack gap="2">
|
||||
<h2>CloseButton</h2>
|
||||
<Alert variant="info" closeButton>
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
<Alert variant="info" closeButton>
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud. Id elit esse
|
||||
enim reprehenderit enim nisi veniam nostrud. Id elit esse enim
|
||||
reprehenderit enim nisi veniam nostrud. Id elit esse enim
|
||||
reprehenderit enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
<Alert size="small" variant="info" closeButton>
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
<Alert size="small" variant="info" closeButton>
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud. Id elit esse
|
||||
enim reprehenderit enim nisi veniam nostrud. Id elit esse enim
|
||||
reprehenderit enim nisi veniam nostrud. Id elit esse enim
|
||||
reprehenderit enim nisi veniam nostrud.
|
||||
</Alert>
|
||||
<Alert variant="info" closeButton>
|
||||
<DsHeading size="small" level="3">
|
||||
Id elit esse enim reprehenderit
|
||||
</DsHeading>
|
||||
<BodyLong>
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud.
|
||||
</BodyLong>
|
||||
</Alert>
|
||||
<Alert variant="info" size="small" closeButton>
|
||||
<DsHeading size="xsmall" level="3">
|
||||
Id elit esse enim reprehenderit
|
||||
</DsHeading>
|
||||
<BodyLong size="small">
|
||||
Id elit esse enim reprehenderit enim nisi veniam nostrud.
|
||||
</BodyLong>
|
||||
</Alert>
|
||||
</VStack>
|
||||
|
||||
const buttonsAfter = canvas.getAllByTitle("Lukk Alert");
|
||||
expect(buttonsAfter.length).toBe(4);
|
||||
<VStack gap="2">
|
||||
<h2>Links</h2>
|
||||
{variants.map((variant) => (
|
||||
<Alert key={variant} variant={variant}>
|
||||
<Link href="#">Id elit esse enim reprehenderit</Link>
|
||||
</Alert>
|
||||
))}
|
||||
</VStack>
|
||||
</VStack>
|
||||
),
|
||||
parameters: {
|
||||
chromatic: { disable: false },
|
||||
},
|
||||
};
|
||||
@@ -1,15 +1,21 @@
|
||||
import { StoryObj } from "@storybook/react";
|
||||
import React from "react";
|
||||
import { StarIcon } from "@navikt/aksel-icons";
|
||||
import { StarIcon as BaseStarIcon } from "@navikt/aksel-icons";
|
||||
import { HStack, VStack } from "../layout/stack";
|
||||
import { Button } from "./index";
|
||||
|
||||
export default {
|
||||
title: "ds-react/Button",
|
||||
component: Button,
|
||||
parameters: {
|
||||
chromatic: { delay: 600 },
|
||||
chromatic: { disable: true },
|
||||
},
|
||||
};
|
||||
|
||||
type Story = StoryObj<typeof Button>;
|
||||
|
||||
const StarIcon = () => <BaseStarIcon aria-hidden />;
|
||||
|
||||
const variants: (
|
||||
| "primary"
|
||||
| "secondary"
|
||||
@@ -28,17 +34,7 @@ const variants: (
|
||||
"tertiary-neutral",
|
||||
];
|
||||
|
||||
const varSwitch = {
|
||||
primary: "Primary",
|
||||
secondary: "Secondary",
|
||||
tertiary: "Tertiary",
|
||||
danger: "Danger",
|
||||
"primary-neutral": "Primary",
|
||||
"secondary-neutral": "Secondary",
|
||||
"tertiary-neutral": "Tertiary",
|
||||
};
|
||||
|
||||
export const Default = {
|
||||
export const Controls: Story = {
|
||||
render: (props) => {
|
||||
return (
|
||||
<Button
|
||||
@@ -57,7 +53,7 @@ export const Default = {
|
||||
icon: false,
|
||||
loading: false,
|
||||
iconPosition: "left",
|
||||
children: "Knapp",
|
||||
children: "Button",
|
||||
variant: "primary",
|
||||
size: "medium",
|
||||
},
|
||||
@@ -91,192 +87,99 @@ export const Default = {
|
||||
},
|
||||
};
|
||||
|
||||
export const Small = () => (
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} size="small">
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
export const XSmall = () => (
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} size="xsmall">
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
export const Link = () => (
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} as="a" href="#thecakeisalie">
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
export const Loading = {
|
||||
render: () => (
|
||||
<div className="colgap chromatic-ignore">
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} loading>
|
||||
{varSwitch[variant]}
|
||||
function ButtonGrid(props: any) {
|
||||
return (
|
||||
<VStack gap="2">
|
||||
{variants.map((variant) => (
|
||||
<HStack gap="2" key={variant}>
|
||||
<Button variant={variant} {...props}>
|
||||
Button
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} loading size="small">
|
||||
{varSwitch[variant]}
|
||||
<Button variant={variant} {...props} icon={<StarIcon />}>
|
||||
Button
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} loading size="xsmall">
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
},
|
||||
};
|
||||
|
||||
export const Icon = () => (
|
||||
<div className="colgap ">
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button
|
||||
key={variant}
|
||||
variant={variant}
|
||||
icon={<StarIcon title="Stjerne" />}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button
|
||||
key={variant}
|
||||
variant={variant}
|
||||
size="small"
|
||||
icon={<StarIcon title="Stjerne" />}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button
|
||||
key={variant}
|
||||
variant={variant}
|
||||
size="xsmall"
|
||||
icon={<StarIcon title="Stjerne" />}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const IconWText = () => (
|
||||
<div className="colgap">
|
||||
<div className="rowgap">
|
||||
{variants.map((variant, i) => (
|
||||
<Button
|
||||
key={variant}
|
||||
variant={variant}
|
||||
icon={<StarIcon title="Stjerne" />}
|
||||
iconPosition={i % 2 ? "left" : "right"}
|
||||
>
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<div className="rowgap">
|
||||
{variants.map((variant, i) => (
|
||||
<Button
|
||||
key={variant}
|
||||
variant={variant}
|
||||
size="small"
|
||||
icon={<StarIcon title="Stjerne" />}
|
||||
iconPosition={i % 2 ? "left" : "right"}
|
||||
>
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<div className="rowgap">
|
||||
{variants.map((variant, i) => (
|
||||
<Button
|
||||
key={variant}
|
||||
variant={variant}
|
||||
size="xsmall"
|
||||
icon={<StarIcon title="Stjerne" />}
|
||||
iconPosition={i % 2 ? "left" : "right"}
|
||||
>
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const Disabled = () => (
|
||||
<div className="colgap">
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} disabled>
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} disabled as="a" href="#">
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const LoadingWithAs = {
|
||||
render: () => (
|
||||
<div className="colgap chromatic-ignore">
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button key={variant} variant={variant} loading size="small">
|
||||
{varSwitch[variant]}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<div className="rowgap">
|
||||
{variants.map((variant) => (
|
||||
<Button
|
||||
key={variant}
|
||||
variant={variant}
|
||||
loading
|
||||
size="small"
|
||||
as="a"
|
||||
href="#"
|
||||
{...props}
|
||||
icon={<StarIcon />}
|
||||
iconPosition="right"
|
||||
>
|
||||
{varSwitch[variant]}
|
||||
Button
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
<Button variant={variant} {...props} icon={<StarIcon />} />
|
||||
</HStack>
|
||||
))}
|
||||
</VStack>
|
||||
);
|
||||
}
|
||||
|
||||
export const Medium: Story = {
|
||||
render: () => <ButtonGrid size="medium" />,
|
||||
};
|
||||
|
||||
export const Small: Story = {
|
||||
render: () => <ButtonGrid size="small" />,
|
||||
};
|
||||
|
||||
export const XSmall: Story = {
|
||||
render: () => <ButtonGrid size="xsmall" />,
|
||||
};
|
||||
|
||||
export const AsLink: Story = {
|
||||
render: () => (
|
||||
<VStack gap="4">
|
||||
<Button href="#" as="a">
|
||||
Button as a-tag
|
||||
</Button>
|
||||
<Button href="#" as="a" disabled>
|
||||
Disabled Button as a-tag
|
||||
</Button>
|
||||
</VStack>
|
||||
),
|
||||
};
|
||||
|
||||
export const Loading: Story = {
|
||||
render: () => <ButtonGrid loading />,
|
||||
};
|
||||
|
||||
export const LoadingAsLink: Story = {
|
||||
render: () => <ButtonGrid loading href="#" as="a" />,
|
||||
};
|
||||
|
||||
export const Disabled: Story = {
|
||||
render: () => <ButtonGrid disabled />,
|
||||
};
|
||||
|
||||
export const DisabledAsLink: Story = {
|
||||
render: () => <ButtonGrid disabled href="#" as="a" />,
|
||||
};
|
||||
|
||||
export const Chromatic: Story = {
|
||||
render: () => (
|
||||
<VStack gap="6" align="center">
|
||||
<div>
|
||||
<h2>Medium</h2>
|
||||
<ButtonGrid size="medium" />
|
||||
</div>
|
||||
<div>
|
||||
<h2>Small</h2>
|
||||
<ButtonGrid size="small" />
|
||||
</div>
|
||||
<div>
|
||||
<h2>XSmall</h2>
|
||||
<ButtonGrid size="xsmall" />
|
||||
</div>
|
||||
<div>
|
||||
<h2>As Link</h2>
|
||||
<ButtonGrid as="a" href="#" />
|
||||
</div>
|
||||
<div>
|
||||
<h2>Disabled</h2>
|
||||
<ButtonGrid disabled />
|
||||
</div>
|
||||
</VStack>
|
||||
),
|
||||
parameters: {
|
||||
chromatic: { disableSnapshot: true },
|
||||
chromatic: { disable: false },
|
||||
},
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Meta } from "@storybook/react";
|
||||
import { Meta, StoryObj } from "@storybook/react";
|
||||
import React from "react";
|
||||
import { Chat } from "../index";
|
||||
import { Chat, VStack } from "../index";
|
||||
import { POSITIONS, SIZES } from "./Chat";
|
||||
|
||||
export default {
|
||||
@@ -30,9 +30,14 @@ export default {
|
||||
options: SIZES,
|
||||
},
|
||||
},
|
||||
parameters: {
|
||||
chromatic: { disable: true },
|
||||
},
|
||||
} satisfies Meta<typeof Chat>;
|
||||
|
||||
export const Default = {
|
||||
type Story = StoryObj<typeof Chat>;
|
||||
|
||||
export const Controls: Story = {
|
||||
render: (props) => {
|
||||
return (
|
||||
<Chat {...props}>
|
||||
@@ -55,219 +60,292 @@ export const Default = {
|
||||
},
|
||||
};
|
||||
|
||||
export const Small = () => (
|
||||
<Chat avatar="ON" name="Ola Normann" timestamp="01.01.21 14:00" size="small">
|
||||
<Chat.Bubble>
|
||||
Aute minim nisi sunt mollit duis sunt nulla minim non proident.
|
||||
</Chat.Bubble>
|
||||
<Chat.Bubble>Tempor fugiat amet eu sint in in ullamco.</Chat.Bubble>
|
||||
<Chat.Bubble>
|
||||
Adipisicing laborum est eu laborum est sit in commodo enim sint laboris
|
||||
labore nisi ut.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
);
|
||||
export const Size: Story = {
|
||||
render: () => (
|
||||
<VStack gap="4">
|
||||
<h3>Medium</h3>
|
||||
<Chat
|
||||
avatar="ON"
|
||||
name="Ola Normann"
|
||||
timestamp="01.01.21 14:00"
|
||||
size="medium"
|
||||
>
|
||||
<Chat.Bubble>
|
||||
Aute minim nisi sunt mollit duis sunt nulla minim non proident.
|
||||
</Chat.Bubble>
|
||||
<Chat.Bubble>Tempor fugiat amet eu sint in in ullamco.</Chat.Bubble>
|
||||
<Chat.Bubble>
|
||||
Adipisicing laborum est eu laborum est sit in commodo enim sint
|
||||
laboris labore nisi ut.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
<h3>Small</h3>
|
||||
<Chat
|
||||
avatar="ON"
|
||||
name="Ola Normann"
|
||||
timestamp="01.01.21 14:00"
|
||||
size="small"
|
||||
>
|
||||
<Chat.Bubble>
|
||||
Aute minim nisi sunt mollit duis sunt nulla minim non proident.
|
||||
</Chat.Bubble>
|
||||
<Chat.Bubble>Tempor fugiat amet eu sint in in ullamco.</Chat.Bubble>
|
||||
<Chat.Bubble>
|
||||
Adipisicing laborum est eu laborum est sit in commodo enim sint
|
||||
laboris labore nisi ut.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
</VStack>
|
||||
),
|
||||
};
|
||||
|
||||
export const Colors = () => (
|
||||
<Chat
|
||||
avatar="NAV"
|
||||
name="NAV"
|
||||
timestamp="01.01.21 14:00"
|
||||
avatarBgColor="var(--a-surface-alt-1-subtle)"
|
||||
backgroundColor="var(--a-surface-warning-subtle)"
|
||||
>
|
||||
<Chat.Bubble>
|
||||
Aute minim nisi sunt mollit duis sunt nulla minim non proident.
|
||||
</Chat.Bubble>
|
||||
<Chat.Bubble backgroundColor="lightYellow">
|
||||
Tempor fugiat amet eu sint in in ullamco.
|
||||
</Chat.Bubble>
|
||||
<Chat.Bubble>
|
||||
Adipisicing laborum est eu laborum est sit in commodo enim sint laboris
|
||||
labore nisi ut.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
);
|
||||
export const Variants: Story = {
|
||||
render: () => (
|
||||
<VStack gap="4">
|
||||
<h3>Info</h3>
|
||||
<Chat avatar="NAV" name="NAV" timestamp="01.01.21 14:00" variant="info">
|
||||
<Chat.Bubble>
|
||||
Aute minim nisi sunt mollit duis sunt nulla minim non proident.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
<h3>Neutral</h3>
|
||||
<Chat
|
||||
avatar="KN"
|
||||
name="Kari Nordmann"
|
||||
timestamp="01.01.21 14:03"
|
||||
variant="neutral"
|
||||
position="right"
|
||||
>
|
||||
<Chat.Bubble>Tempor fugiat amet eu sint in in ullamco.</Chat.Bubble>
|
||||
</Chat>
|
||||
<h3>Subtle</h3>
|
||||
<Chat
|
||||
avatar="ON"
|
||||
name="Ola Nordmann"
|
||||
timestamp="01.01.21 14:07"
|
||||
variant="subtle"
|
||||
position="right"
|
||||
>
|
||||
<Chat.Bubble>
|
||||
Adipisicing laborum est eu laborum est sit in commodo enim sint
|
||||
laboris labore nisi ut.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
</VStack>
|
||||
),
|
||||
};
|
||||
|
||||
export const Variants = () => (
|
||||
<div className="colgap">
|
||||
<Chat avatar="NAV" name="NAV" timestamp="01.01.21 14:00" variant="info">
|
||||
export const Position: Story = {
|
||||
render: () => (
|
||||
<VStack gap="4">
|
||||
<h3>Default</h3>
|
||||
<Chat avatar="ON" name="Ola Normann" timestamp="01.01.21 14:00">
|
||||
<Chat.Bubble>
|
||||
Adipisicing laborum est eu laborum est sit in commodo enim sint
|
||||
laboris labore nisi ut.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
<h3>Right</h3>
|
||||
<Chat
|
||||
avatar="KH"
|
||||
name="Kari Høyli"
|
||||
timestamp="01.01.21 14:32"
|
||||
position="right"
|
||||
variant="info"
|
||||
>
|
||||
<Chat.Bubble>
|
||||
Reprehenderit pariatur officia exercitation laboris.
|
||||
</Chat.Bubble>
|
||||
<Chat.Bubble>
|
||||
Enim velit deserunt do quis. Eu fugiat magna esse dolore ad sunt sit
|
||||
est dolore incididunt. Occaecat cupidatat magna.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
<h3>Left</h3>
|
||||
<Chat
|
||||
position="left"
|
||||
avatar="ON"
|
||||
name="Ola Normann"
|
||||
timestamp="01.01.21 15:00"
|
||||
>
|
||||
<Chat.Bubble>
|
||||
Exercitation irure Lorem cupidatat culpa anim cillum esse ullamco qui
|
||||
dolore laborum et Lorem. Labore sunt duis id Lorem voluptate commodo
|
||||
ea esse. Dolore esse aliqua proident ea ad commodo ut dolore voluptate
|
||||
labore sunt aute.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
</VStack>
|
||||
),
|
||||
};
|
||||
|
||||
export const ToptextPosition: Story = {
|
||||
render: () => (
|
||||
<VStack gap="4">
|
||||
<h3>Right</h3>
|
||||
<Chat
|
||||
avatar="ON"
|
||||
name="Ola Normann"
|
||||
timestamp="01.01.21 14:00"
|
||||
toptextPosition="right"
|
||||
>
|
||||
<Chat.Bubble>
|
||||
Adipisicing laborum est eu laborum est sit in commodo enim sint
|
||||
laboris labore nisi ut.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
<h3>Left</h3>
|
||||
<Chat avatar="ON" name="Ola Normann" timestamp="01.01.21 15:00">
|
||||
<Chat.Bubble toptextPosition="left">
|
||||
Exercitation irure Lorem cupidatat culpa anim cillum esse ullamco qui
|
||||
dolore laborum et Lorem. Labore sunt duis id Lorem voluptate commodo
|
||||
ea esse. Dolore esse aliqua proident ea ad commodo ut dolore voluptate
|
||||
labore sunt aute.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
<h3>Left</h3>
|
||||
<Chat
|
||||
name="Kari Høyli"
|
||||
timestamp="01.01.21 14:32"
|
||||
position="right"
|
||||
toptextPosition="left"
|
||||
>
|
||||
<Chat.Bubble>
|
||||
Reprehenderit pariatur officia exercitation laboris.
|
||||
</Chat.Bubble>
|
||||
<Chat.Bubble>
|
||||
Enim velit deserunt do quis. Eu fugiat magna esse dolore ad sunt sit
|
||||
est dolore incididunt. Occaecat cupidatat magna.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
<h3>Right</h3>
|
||||
<Chat
|
||||
name="Kari Høyli"
|
||||
timestamp="01.01.21 14:32"
|
||||
position="right"
|
||||
toptextPosition="right"
|
||||
>
|
||||
<Chat.Bubble>
|
||||
Reprehenderit pariatur officia exercitation laboris.
|
||||
</Chat.Bubble>
|
||||
<Chat.Bubble>
|
||||
Enim velit deserunt do quis. Eu fugiat magna esse dolore ad sunt sit
|
||||
est dolore incididunt. Occaecat cupidatat magna.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
</VStack>
|
||||
),
|
||||
};
|
||||
|
||||
export const Avatar: Story = {
|
||||
render: () => (
|
||||
<Chat avatar={<Illustration />}>
|
||||
<Chat.Bubble>
|
||||
Aute minim nisi sunt mollit duis sunt nulla minim non proident.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
<Chat
|
||||
avatar="KN"
|
||||
name="Kari Nordmann"
|
||||
timestamp="01.01.21 14:03"
|
||||
variant="neutral"
|
||||
position="right"
|
||||
>
|
||||
<Chat.Bubble>Tempor fugiat amet eu sint in in ullamco.</Chat.Bubble>
|
||||
</Chat>
|
||||
<Chat
|
||||
avatar="ON"
|
||||
name="Ola Nordmann"
|
||||
timestamp="01.01.21 14:07"
|
||||
variant="subtle"
|
||||
position="right"
|
||||
>
|
||||
<Chat.Bubble>
|
||||
Adipisicing laborum est eu laborum est sit in commodo enim sint laboris
|
||||
labore nisi ut.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
</div>
|
||||
);
|
||||
),
|
||||
};
|
||||
|
||||
export const Position = () => (
|
||||
<div className="colgap">
|
||||
<Chat avatar="ON" name="Ola Normann" timestamp="01.01.21 14:00">
|
||||
<Chat.Bubble>
|
||||
Adipisicing laborum est eu laborum est sit in commodo enim sint laboris
|
||||
labore nisi ut.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
<Chat
|
||||
avatar="KH"
|
||||
name="Kari Høyli"
|
||||
timestamp="01.01.21 14:32"
|
||||
position="right"
|
||||
variant="info"
|
||||
>
|
||||
<Chat.Bubble>
|
||||
Reprehenderit pariatur officia exercitation laboris.
|
||||
</Chat.Bubble>
|
||||
<Chat.Bubble>
|
||||
Enim velit deserunt do quis. Eu fugiat magna esse dolore ad sunt sit est
|
||||
dolore incididunt. Occaecat cupidatat magna.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
<Chat avatar="ON" name="Ola Normann" timestamp="01.01.21 15:00">
|
||||
<Chat.Bubble>
|
||||
Exercitation irure Lorem cupidatat culpa anim cillum esse ullamco qui
|
||||
dolore laborum et Lorem. Labore sunt duis id Lorem voluptate commodo ea
|
||||
esse. Dolore esse aliqua proident ea ad commodo ut dolore voluptate
|
||||
labore sunt aute.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
</div>
|
||||
);
|
||||
function Illustration() {
|
||||
return (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 54 93">
|
||||
<path
|
||||
fill="#e7e5e2"
|
||||
d="M14 50.7C15 52.3 17.9 81 26.5 81S39 51.8 39 50.3c-13.2-7.6-25 .4-25 .4z"
|
||||
/>
|
||||
<path
|
||||
fill="#5c4378"
|
||||
d="M38.7 50.2c6 2.9 15.3 10.9 15.3 18.3V93H0V68.5c0-7.1 8.5-14.8 14.5-18-.3.2-.5.3-.5.3 1 1.7 3.8 9.2 12.4 9.2C35 60 39 51.9 39 50.4c-.1-.1-.2-.2-.3-.2z"
|
||||
/>
|
||||
<path
|
||||
fill="#d2242a"
|
||||
d="M46.7 76H31.2c-.7 0-1.3-.6-1.2-1.3v-8.5c0-.7.6-1.3 1.3-1.3h15.5c.7 0 1.3.6 1.3 1.3v8.5c-.1.7-.7 1.3-1.4 1.3"
|
||||
/>
|
||||
<path
|
||||
fill="#fff"
|
||||
d="M42.9 71c0 2.1-1.7 3.8-3.8 3.8-2.1 0-3.8-1.7-3.8-3.8s1.7-3.8 3.8-3.8c2.1 0 3.8 1.7 3.8 3.8m-8.7 1.7h-.7l.8-1.9h.7l-.8 1.9zm9.3 0H43l.8-1.9h.5l-.8 1.9zm1.2 0h-.2l.8-1.9h.2l-.8 1.9z"
|
||||
/>
|
||||
<path
|
||||
fill="#c52d35"
|
||||
d="M36.2 72.7h.6s.1 0 .1-.1v-1.8s0-.1-.1-.1h-.6s-.1 0-.1.1l-.2.6v.1h.2l.1 1.2c0-.1 0 0 0 0"
|
||||
/>
|
||||
<path
|
||||
fill="#c52d35"
|
||||
d="M37.5 72.7h.6s.1 0 .1-.1v-1.8s0-.1-.1-.1h-.9s-.1 0-.1.1l-.2.6-.1.1h.5c.1 0 .2.1.2.2v1c-.1-.1-.1 0 0 0m2.6-1.9h-.6s-.1 0-.1.1v1.8s0 .1.1.1h.6s.1 0 .1-.1l.2-.6V72h-.2l-.1-1.2"
|
||||
/>
|
||||
<path
|
||||
fill="#c52d35"
|
||||
d="M37.7 72.7h.4s.1 0 .1-.1l.2-.6v-.1h-.2c0 .1-.5.8-.5.8zm3.9-1.9h.7s.1 0 0 .1l-.7 1.8H41l.6-1.9"
|
||||
/>
|
||||
<path
|
||||
fill="#c52d35"
|
||||
d="M40.8 70.8h-1c-.1 0 .3.1.3.1l.7 1.7s0 .1.1.1h.6l-.7-1.9m-1.3.6v.4s-.1-.4-.3-.4c-.3 0-.3.2-.3.3 0 .1.1.3.2.3h.5l-.3.7H39c-.2 0-.9-.3-.9-.9 0-.6.5-1 .9-1 .2-.1.5.2.5.6 0-.1 0-.1 0 0z"
|
||||
/>
|
||||
<path
|
||||
fill="#5a1f57"
|
||||
d="M39.9 66.7h-1.6c-.1 0-.2-.1-.2-.2v-.3c0-.1.1-.2.2-.2h1.6c.1 0 .2.1.2.2v.3c0 .2-.1.2-.2.2"
|
||||
/>
|
||||
<path fill="#c2b5cf" d="M38.7 66.5h.9V64h-.9v2.5z" />
|
||||
<path
|
||||
fill="#e7e5e2"
|
||||
d="M47.2 35.3C44.7 45.6 36.6 53.1 27 53.1S9.3 45.6 6.8 35.3c-.2.1-.5.1-.8.1-1.1 0-2-.8-2-1.7v-7c0-1 .9-1.7 2-1.7h.2C7.7 13.1 16.4 4 27 4c10.6 0 19.3 9.1 20.8 21h.2c1.1 0 2 .8 2 1.7v7c0 1-.9 1.7-2 1.7-.3 0-.5 0-.8-.1z"
|
||||
/>
|
||||
<path
|
||||
fill="#635e59"
|
||||
d="M19 27.6c-1.4.1-1.9-2-1.4-3.4.1-.3.6-1.5 1.4-1.5.8 0 1.2.7 1.3.8.6 1.4.3 4-1.3 4.1m16.2 0c1.4.1 1.9-2 1.4-3.4-.1-.3-.6-1.5-1.4-1.5-.8 0-1.2.7-1.3.8-.6 1.4-.3 4 1.3 4.1"
|
||||
/>
|
||||
<path
|
||||
fill="#d1bfa3"
|
||||
d="M26.8 34.6c-.4 0-.7-.1-1-.2-.3-.1-.4-.4-.3-.7.1-.3.4-.4.7-.3.5.2 1.5.1 2.2-.4.7-.4 1.1-1 1.2-1.5.1-.4-.1-.9-.4-1.3-.2-.2-.8-.2-1.6-.1-.3 0-.5-.1-.6-.4 0-.3.1-.5.4-.6 1.2-.2 2.1 0 2.6.6.5.7.8 1.4.6 2.1-.1.8-.7 1.6-1.7 2.2-.6.3-1.4.6-2.1.6z"
|
||||
/>
|
||||
<path
|
||||
fill="#593a32"
|
||||
d="M27.1 42.1h-.3c-5.3-.2-7.3-4.1-7.4-4.3-.1-.3 0-.6.2-.7.2-.1.6 0 .7.2.1.1 1.9 3.6 6.6 3.8 4.7.2 6.4-3.7 6.4-3.7.1-.3.4-.4.7-.3.3.1.4.4.3.7-.1 0-2.1 4.3-7.2 4.3z"
|
||||
/>
|
||||
<path
|
||||
fill="#f6b873"
|
||||
d="M6.6 30.7c.1-.1.1-.2.1-.3v-2c-.1-5.6 1.8-8.1 3.4-10.1 0 0-1 4.3-.3 3.4 3.8-5 21.4-1.6 25-8.1.5 3.6-4.1 4.6-4.1 4.6 3.7.7 6.9-.8 7.7-2.5.3 1.4-.6 2.4-1.9 3.4 4.5-.9 4.6-4 4.6-4 .6 4.1 5.3 2.5 5.3 9.3v6c0 .3.2.6.5.6h.5c.3 0 .5-.3.5-.6V26c.3-15.6-8.5-26-20.6-26C15.9 0 5 10.4 5 24.1v6.3c0 .4.2.6.5.6h.6c.2 0 .3-.1.5-.3"
|
||||
/>
|
||||
<path
|
||||
fill="#f6b873"
|
||||
d="M25.9 43.4c-4.4 0-8-1.4-8-3.2s3.6-3.2 8-3.2 8 1.4 8 3.2c0 1.8-3.6 3.2-8 3.2m.8-9.4c-2.9 0-4.7.7-8.8 2.1-12.7 4.6-11.6-14-11.6-14C3.4 46 18.6 52 26.5 52c8.1 0 24.1-8.1 21-30 0 0 .4 17.1-12.9 13.8-3.7-.9-5-1.8-7.9-1.8z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export const ToptextPosition = () => (
|
||||
<div className="colgap">
|
||||
<Chat
|
||||
avatar="ON"
|
||||
name="Ola Normann"
|
||||
timestamp="01.01.21 14:00"
|
||||
toptextPosition="right"
|
||||
>
|
||||
<Chat.Bubble>
|
||||
Adipisicing laborum est eu laborum est sit in commodo enim sint laboris
|
||||
labore nisi ut.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
<Chat
|
||||
name="Kari Høyli"
|
||||
timestamp="01.01.21 14:32"
|
||||
position="right"
|
||||
variant="info"
|
||||
toptextPosition="left"
|
||||
>
|
||||
<Chat.Bubble>
|
||||
Reprehenderit pariatur officia exercitation laboris.
|
||||
</Chat.Bubble>
|
||||
<Chat.Bubble>
|
||||
Enim velit deserunt do quis. Eu fugiat magna esse dolore ad sunt sit est
|
||||
dolore incididunt. Occaecat cupidatat magna.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
<Chat avatar="ON" name="Ola Normann" timestamp="01.01.21 15:00">
|
||||
<Chat.Bubble toptextPosition="right">
|
||||
Exercitation irure Lorem cupidatat culpa anim cillum esse ullamco qui
|
||||
dolore laborum et Lorem. Labore sunt duis id Lorem voluptate commodo ea
|
||||
esse. Dolore esse aliqua proident ea ad commodo ut dolore voluptate
|
||||
labore sunt aute.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const Avatar = () => (
|
||||
<Chat avatar={<Illustration />} timestamp="01.01.21 14:00">
|
||||
<Chat.Bubble>
|
||||
Aute minim nisi sunt mollit duis sunt nulla minim non proident.
|
||||
</Chat.Bubble>
|
||||
<Chat.Bubble>Tempor fugiat amet eu sint in in ullamco.</Chat.Bubble>
|
||||
<Chat.Bubble>
|
||||
Adipisicing laborum est eu laborum est sit in commodo enim sint laboris
|
||||
labore nisi ut.
|
||||
</Chat.Bubble>
|
||||
</Chat>
|
||||
);
|
||||
|
||||
const Illustration = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 54 93">
|
||||
<path
|
||||
fill="#e7e5e2"
|
||||
d="M14 50.7C15 52.3 17.9 81 26.5 81S39 51.8 39 50.3c-13.2-7.6-25 .4-25 .4z"
|
||||
/>
|
||||
<path
|
||||
fill="#5c4378"
|
||||
d="M38.7 50.2c6 2.9 15.3 10.9 15.3 18.3V93H0V68.5c0-7.1 8.5-14.8 14.5-18-.3.2-.5.3-.5.3 1 1.7 3.8 9.2 12.4 9.2C35 60 39 51.9 39 50.4c-.1-.1-.2-.2-.3-.2z"
|
||||
/>
|
||||
<path
|
||||
fill="#d2242a"
|
||||
d="M46.7 76H31.2c-.7 0-1.3-.6-1.2-1.3v-8.5c0-.7.6-1.3 1.3-1.3h15.5c.7 0 1.3.6 1.3 1.3v8.5c-.1.7-.7 1.3-1.4 1.3"
|
||||
/>
|
||||
<path
|
||||
fill="#fff"
|
||||
d="M42.9 71c0 2.1-1.7 3.8-3.8 3.8-2.1 0-3.8-1.7-3.8-3.8s1.7-3.8 3.8-3.8c2.1 0 3.8 1.7 3.8 3.8m-8.7 1.7h-.7l.8-1.9h.7l-.8 1.9zm9.3 0H43l.8-1.9h.5l-.8 1.9zm1.2 0h-.2l.8-1.9h.2l-.8 1.9z"
|
||||
/>
|
||||
<path
|
||||
fill="#c52d35"
|
||||
d="M36.2 72.7h.6s.1 0 .1-.1v-1.8s0-.1-.1-.1h-.6s-.1 0-.1.1l-.2.6v.1h.2l.1 1.2c0-.1 0 0 0 0"
|
||||
/>
|
||||
<path
|
||||
fill="#c52d35"
|
||||
d="M37.5 72.7h.6s.1 0 .1-.1v-1.8s0-.1-.1-.1h-.9s-.1 0-.1.1l-.2.6-.1.1h.5c.1 0 .2.1.2.2v1c-.1-.1-.1 0 0 0m2.6-1.9h-.6s-.1 0-.1.1v1.8s0 .1.1.1h.6s.1 0 .1-.1l.2-.6V72h-.2l-.1-1.2"
|
||||
/>
|
||||
<path
|
||||
fill="#c52d35"
|
||||
d="M37.7 72.7h.4s.1 0 .1-.1l.2-.6v-.1h-.2c0 .1-.5.8-.5.8zm3.9-1.9h.7s.1 0 0 .1l-.7 1.8H41l.6-1.9"
|
||||
/>
|
||||
<path
|
||||
fill="#c52d35"
|
||||
d="M40.8 70.8h-1c-.1 0 .3.1.3.1l.7 1.7s0 .1.1.1h.6l-.7-1.9m-1.3.6v.4s-.1-.4-.3-.4c-.3 0-.3.2-.3.3 0 .1.1.3.2.3h.5l-.3.7H39c-.2 0-.9-.3-.9-.9 0-.6.5-1 .9-1 .2-.1.5.2.5.6 0-.1 0-.1 0 0z"
|
||||
/>
|
||||
<path
|
||||
fill="#5a1f57"
|
||||
d="M39.9 66.7h-1.6c-.1 0-.2-.1-.2-.2v-.3c0-.1.1-.2.2-.2h1.6c.1 0 .2.1.2.2v.3c0 .2-.1.2-.2.2"
|
||||
/>
|
||||
<path fill="#c2b5cf" d="M38.7 66.5h.9V64h-.9v2.5z" />
|
||||
<path
|
||||
fill="#e7e5e2"
|
||||
d="M47.2 35.3C44.7 45.6 36.6 53.1 27 53.1S9.3 45.6 6.8 35.3c-.2.1-.5.1-.8.1-1.1 0-2-.8-2-1.7v-7c0-1 .9-1.7 2-1.7h.2C7.7 13.1 16.4 4 27 4c10.6 0 19.3 9.1 20.8 21h.2c1.1 0 2 .8 2 1.7v7c0 1-.9 1.7-2 1.7-.3 0-.5 0-.8-.1z"
|
||||
/>
|
||||
<path
|
||||
fill="#635e59"
|
||||
d="M19 27.6c-1.4.1-1.9-2-1.4-3.4.1-.3.6-1.5 1.4-1.5.8 0 1.2.7 1.3.8.6 1.4.3 4-1.3 4.1m16.2 0c1.4.1 1.9-2 1.4-3.4-.1-.3-.6-1.5-1.4-1.5-.8 0-1.2.7-1.3.8-.6 1.4-.3 4 1.3 4.1"
|
||||
/>
|
||||
<path
|
||||
fill="#d1bfa3"
|
||||
d="M26.8 34.6c-.4 0-.7-.1-1-.2-.3-.1-.4-.4-.3-.7.1-.3.4-.4.7-.3.5.2 1.5.1 2.2-.4.7-.4 1.1-1 1.2-1.5.1-.4-.1-.9-.4-1.3-.2-.2-.8-.2-1.6-.1-.3 0-.5-.1-.6-.4 0-.3.1-.5.4-.6 1.2-.2 2.1 0 2.6.6.5.7.8 1.4.6 2.1-.1.8-.7 1.6-1.7 2.2-.6.3-1.4.6-2.1.6z"
|
||||
/>
|
||||
<path
|
||||
fill="#593a32"
|
||||
d="M27.1 42.1h-.3c-5.3-.2-7.3-4.1-7.4-4.3-.1-.3 0-.6.2-.7.2-.1.6 0 .7.2.1.1 1.9 3.6 6.6 3.8 4.7.2 6.4-3.7 6.4-3.7.1-.3.4-.4.7-.3.3.1.4.4.3.7-.1 0-2.1 4.3-7.2 4.3z"
|
||||
/>
|
||||
<path
|
||||
fill="#f6b873"
|
||||
d="M6.6 30.7c.1-.1.1-.2.1-.3v-2c-.1-5.6 1.8-8.1 3.4-10.1 0 0-1 4.3-.3 3.4 3.8-5 21.4-1.6 25-8.1.5 3.6-4.1 4.6-4.1 4.6 3.7.7 6.9-.8 7.7-2.5.3 1.4-.6 2.4-1.9 3.4 4.5-.9 4.6-4 4.6-4 .6 4.1 5.3 2.5 5.3 9.3v6c0 .3.2.6.5.6h.5c.3 0 .5-.3.5-.6V26c.3-15.6-8.5-26-20.6-26C15.9 0 5 10.4 5 24.1v6.3c0 .4.2.6.5.6h.6c.2 0 .3-.1.5-.3"
|
||||
/>
|
||||
<path
|
||||
fill="#f6b873"
|
||||
d="M25.9 43.4c-4.4 0-8-1.4-8-3.2s3.6-3.2 8-3.2 8 1.4 8 3.2c0 1.8-3.6 3.2-8 3.2m.8-9.4c-2.9 0-4.7.7-8.8 2.1-12.7 4.6-11.6-14-11.6-14C3.4 46 18.6 52 26.5 52c8.1 0 24.1-8.1 21-30 0 0 .4 17.1-12.9 13.8-3.7-.9-5-1.8-7.9-1.8z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
export const Chromatic: Story = {
|
||||
render: (...props) => (
|
||||
<div>
|
||||
<div>
|
||||
<h2>Size</h2>
|
||||
{Size.render?.(...props)}
|
||||
</div>
|
||||
<div>
|
||||
<h2>Variants</h2>
|
||||
{Variants.render?.(...props)}
|
||||
</div>
|
||||
<div>
|
||||
<h2>Position</h2>
|
||||
{Position.render?.(...props)}
|
||||
</div>
|
||||
<div>
|
||||
<h2>Toptext</h2>
|
||||
{ToptextPosition.render?.(...props)}
|
||||
</div>
|
||||
<div>
|
||||
<h2>Avatar</h2>
|
||||
{Avatar.render?.(...props)}
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
parameters: {
|
||||
chromatic: { disable: false },
|
||||
},
|
||||
};
|
||||
@@ -11,7 +11,6 @@ import { DateWrapper } from "../parts/DateWrapper";
|
||||
import { getLocaleFromString, labels } from "../utils";
|
||||
import DatePickerStandalone from "./DatePickerStandalone";
|
||||
import Caption from "./parts/Caption";
|
||||
import DayButton from "./parts/DayButton";
|
||||
import DropdownCaption from "./parts/DropdownCaption";
|
||||
import { HeadRow } from "./parts/HeadRow";
|
||||
import Row from "./parts/Row";
|
||||
@@ -124,7 +123,6 @@ export const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(
|
||||
HeadRow,
|
||||
WeekNumber,
|
||||
Row,
|
||||
Day: DayButton,
|
||||
}}
|
||||
className={cl("navds-date", className)}
|
||||
classNames={{
|
||||
|
||||
@@ -5,7 +5,6 @@ import { DateRange, DayPicker, isMatch } from "react-day-picker";
|
||||
import { omit } from "../../util";
|
||||
import { getLocaleFromString, labels } from "../utils";
|
||||
import Caption from "./parts/Caption";
|
||||
import DayButton from "./parts/DayButton";
|
||||
import DropdownCaption from "./parts/DropdownCaption";
|
||||
import { HeadRow } from "./parts/HeadRow";
|
||||
import Row from "./parts/Row";
|
||||
@@ -94,7 +93,6 @@ export const DatePickerStandalone: DatePickerStandaloneType = forwardRef<
|
||||
HeadRow,
|
||||
WeekNumber,
|
||||
Row,
|
||||
Day: DayButton,
|
||||
}}
|
||||
className="navds-date"
|
||||
classNames={{ vhidden: "navds-sr-only" }}
|
||||
|
||||
@@ -2,8 +2,12 @@
|
||||
import { Meta, StoryObj } from "@storybook/react";
|
||||
import isSameDay from "date-fns/isSameDay";
|
||||
import React, { useId, useState } from "react";
|
||||
import { useDatepicker, useRangeDatepicker } from "..";
|
||||
import { BodyLong, Button, HGrid, Modal, VStack } from "../..";
|
||||
import { Button } from "../../button";
|
||||
import { HGrid } from "../../layout/grid";
|
||||
import { VStack } from "../../layout/stack";
|
||||
import Modal from "../../modal/Modal";
|
||||
import { BodyLong } from "../../typography";
|
||||
import { useDatepicker, useRangeDatepicker } from "../hooks";
|
||||
import DatePicker, { DatePickerProps } from "./DatePicker";
|
||||
|
||||
const disabledDays = [
|
||||
@@ -27,13 +31,13 @@ export const Default: StoryObj<DefaultStoryProps> = {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const rangeCtx = useRangeDatepicker({
|
||||
fromDate: new Date("Aug 23 2020"),
|
||||
toDate: new Date("Aug 23 2023"),
|
||||
fromDate: new Date("Aug 23 2023"),
|
||||
toDate: new Date("Aug 23 2029"),
|
||||
});
|
||||
|
||||
const singleCtx = useDatepicker({
|
||||
fromDate: new Date("Aug 23 2020"),
|
||||
toDate: new Date("Aug 23 2023"),
|
||||
toDate: new Date("Aug 23 2029"),
|
||||
});
|
||||
|
||||
const newProps = {
|
||||
@@ -42,7 +46,7 @@ export const Default: StoryObj<DefaultStoryProps> = {
|
||||
open,
|
||||
onClose: () => setOpen(false),
|
||||
fromDate: new Date("Aug 23 2020"),
|
||||
toDate: new Date("Aug 23 2023"),
|
||||
toDate: new Date("Aug 23 2029"),
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { getUnixTime } from "date-fns";
|
||||
import React from "react";
|
||||
import { Day, useDayPicker } from "react-day-picker";
|
||||
import { useDayPicker } from "react-day-picker";
|
||||
import { Hide } from "../../../layout/responsive";
|
||||
import DayButton from "./DayButton";
|
||||
import WeekNumber from "./WeekNumber";
|
||||
|
||||
/**
|
||||
@@ -37,7 +38,7 @@ function Row(props: RowProps): JSX.Element {
|
||||
style={styles.cell}
|
||||
key={getUnixTime(date)}
|
||||
>
|
||||
<Day displayMonth={props.displayMonth} date={date} />
|
||||
<DayButton displayMonth={props.displayMonth} date={date} />
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
|
||||
@@ -53,7 +53,7 @@ export interface UseDatepickerOptions
|
||||
* Allows input of with 'yy' year format.
|
||||
* @default true
|
||||
* @Note Decision between 20th and 21st century is based on before(todays year - 80) ? 21st : 20th.
|
||||
* In 2023 this equals to 1943 - 2042
|
||||
* In 2024 this equals to 1944 - 2043
|
||||
*/
|
||||
allowTwoDigitYear?: boolean;
|
||||
/**
|
||||
|
||||
@@ -39,7 +39,7 @@ export interface UseMonthPickerOptions
|
||||
* Allows input of with 'yy' year format.
|
||||
* @default true
|
||||
* @Note Decision between 20th and 21st century is based on before(todays year - 80) ? 21st : 20th.
|
||||
* In 2023 this equals to 1943 - 2042
|
||||
* In 2024 this equals to 1944 - 2043
|
||||
*/
|
||||
allowTwoDigitYear?: boolean;
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Meta, StoryFn } from "@storybook/react";
|
||||
import setYear from "date-fns/setYear";
|
||||
import React, { useId, useState } from "react";
|
||||
import { Button, DateInputProps } from "../..";
|
||||
import { Button } from "../../button";
|
||||
import { useMonthpicker } from "../hooks";
|
||||
import { DateInputProps } from "../parts/DateInput";
|
||||
import MonthPicker from "./MonthPicker";
|
||||
import { MonthPickerProps } from "./types";
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ export interface DateInputProps
|
||||
*/
|
||||
label: React.ReactNode;
|
||||
/**
|
||||
* Shows label and description for screenreaders-only
|
||||
* Shows label and description for screen readers only
|
||||
* @default false
|
||||
*/
|
||||
hideLabel?: boolean;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import cl from "clsx";
|
||||
import React, { useContext, useRef } from "react";
|
||||
import React, { useRef } from "react";
|
||||
import { Button } from "../../button";
|
||||
import { Modal } from "../../modal";
|
||||
import { ModalContext } from "../../modal/ModalContext";
|
||||
import { useModalContext } from "../../modal/Modal.context";
|
||||
import { Popover } from "../../popover";
|
||||
import { useMedia } from "../../util/hooks";
|
||||
import { modalCloseButtonLabel, modalLabel } from "../utils/labels";
|
||||
@@ -30,7 +30,7 @@ export const DateWrapper = ({
|
||||
popoverProps,
|
||||
}: DateWrapperProps) => {
|
||||
const modalRef = useRef<HTMLDialogElement>(null);
|
||||
const isInModal = useContext(ModalContext) !== null;
|
||||
const isInModal = useModalContext(false) !== undefined;
|
||||
const hideModal =
|
||||
useMedia("screen and (min-width: 768px)", true) && !isInModal;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Meta } from "@storybook/react";
|
||||
import React, { useState } from "react";
|
||||
import { Dropdown } from "..";
|
||||
import { Button } from "../button";
|
||||
import Dropdown from "./Dropdown";
|
||||
|
||||
export default {
|
||||
title: "ds-react/Dropdown",
|
||||
|
||||
@@ -3,6 +3,7 @@ import React, { forwardRef, useState } from "react";
|
||||
import { BodyShort, ErrorMessage, Label } from "../typography";
|
||||
import { omit } from "../util";
|
||||
import TextareaAutosize from "../util/TextareaAutoSize";
|
||||
import { composeEventHandlers } from "../util/composeEventHandlers";
|
||||
import { useId } from "../util/hooks";
|
||||
import { ReadOnlyIcon } from "./ReadOnlyIcon";
|
||||
import Counter from "./TextareaCounter";
|
||||
@@ -102,7 +103,7 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
const maxLengthId = useId();
|
||||
const hasMaxLength = maxLength !== undefined && maxLength > 0;
|
||||
|
||||
const [controlledValue, setControlledValue] = useState<string>(
|
||||
const [uncontrolledValue, setUncontrolledValue] = useState(
|
||||
props?.defaultValue ?? "",
|
||||
);
|
||||
|
||||
@@ -161,11 +162,12 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
<TextareaAutosize
|
||||
{...omit(rest, ["error", "errorId", "size"])}
|
||||
{...inputProps}
|
||||
onChange={(e) =>
|
||||
props.onChange
|
||||
? props.onChange(e)
|
||||
: setControlledValue(e.target.value)
|
||||
}
|
||||
onChange={composeEventHandlers(
|
||||
props.onChange,
|
||||
props.value === undefined
|
||||
? (e) => setUncontrolledValue(e.target.value)
|
||||
: undefined,
|
||||
)}
|
||||
minRows={getMinRows()}
|
||||
autoScrollbar={UNSAFE_autoScrollbar}
|
||||
ref={ref}
|
||||
@@ -184,7 +186,7 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
</span>
|
||||
<Counter
|
||||
maxLength={maxLength}
|
||||
currentLength={props.value?.length ?? controlledValue?.length}
|
||||
currentLength={props.value?.length ?? uncontrolledValue.length}
|
||||
size={size}
|
||||
i18n={i18n}
|
||||
/>
|
||||
|
||||
@@ -89,7 +89,7 @@ export const Combobox = forwardRef<
|
||||
"navds-combobox__wrapper-inner navds-text-field__input",
|
||||
{
|
||||
"navds-combobox__wrapper-inner--virtually-unfocused":
|
||||
activeDecendantId !== null,
|
||||
activeDecendantId !== undefined,
|
||||
},
|
||||
)}
|
||||
onClick={focusInput}
|
||||
|
||||
@@ -43,6 +43,7 @@ const ComboboxProvider = forwardRef<HTMLInputElement, ComboboxProps>(
|
||||
isMultiSelect,
|
||||
onToggleSelected,
|
||||
selectedOptions,
|
||||
maxSelected,
|
||||
options,
|
||||
value,
|
||||
onChange,
|
||||
@@ -71,6 +72,7 @@ const ComboboxProvider = forwardRef<HTMLInputElement, ComboboxProps>(
|
||||
allowNewValues,
|
||||
isMultiSelect,
|
||||
selectedOptions,
|
||||
maxSelected,
|
||||
onToggleSelected,
|
||||
options,
|
||||
}}
|
||||
|
||||
@@ -57,7 +57,6 @@ const ComboboxWrapper = ({
|
||||
)}
|
||||
onFocus={onFocusInsideWrapper}
|
||||
onBlur={onBlurWrapper}
|
||||
tabIndex={-1}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -27,111 +27,150 @@ const FilteredOptions = () => {
|
||||
activeDecendantId,
|
||||
virtualFocus,
|
||||
} = useFilteredOptionsContext();
|
||||
const { isMultiSelect, selectedOptions, toggleOption } =
|
||||
const { isMultiSelect, selectedOptions, toggleOption, maxSelected } =
|
||||
useSelectedOptionsContext();
|
||||
|
||||
const isDisabled = (option) =>
|
||||
maxSelected?.isLimitReached && !selectedOptions.includes(option);
|
||||
|
||||
const shouldRenderNonSelectables =
|
||||
maxSelected?.isLimitReached || // Render maxSelected message
|
||||
isLoading || // Render loading message
|
||||
(!isLoading && filteredOptions.length === 0); // Render no hits message
|
||||
|
||||
const shouldRenderFilteredOptionsList =
|
||||
(allowNewValues && isValueNew && !maxSelected?.isLimitReached) || // Render add new option
|
||||
filteredOptions.length > 0; // Render filtered options
|
||||
|
||||
return (
|
||||
<ul
|
||||
ref={setFilteredOptionsRef}
|
||||
<div
|
||||
className={cl("navds-combobox__list", {
|
||||
"navds-combobox__list--closed": !isListOpen,
|
||||
"navds-combobox__list--with-hover": isMouseLastUsedInputDevice,
|
||||
})}
|
||||
id={filteredOptionsUtil.getFilteredOptionsId(id)}
|
||||
role="listbox"
|
||||
tabIndex={-1}
|
||||
>
|
||||
{isLoading && (
|
||||
<li
|
||||
className="navds-combobox__list-item--loading"
|
||||
role="option"
|
||||
aria-selected={false}
|
||||
id={filteredOptionsUtil.getIsLoadingId(id)}
|
||||
data-no-focus="true"
|
||||
>
|
||||
<Loader aria-label="Søker..." />
|
||||
</li>
|
||||
{shouldRenderNonSelectables && (
|
||||
<div className="navds-combobox__list_non-selectables" role="status">
|
||||
{maxSelected?.isLimitReached && (
|
||||
<div
|
||||
className="navds-combobox__list-item--max-selected"
|
||||
id={filteredOptionsUtil.getMaxSelectedOptionsId(id)}
|
||||
>
|
||||
{maxSelected.message ??
|
||||
`${selectedOptions.length} av ${maxSelected.limit} er valgt.`}
|
||||
</div>
|
||||
)}
|
||||
{isLoading && (
|
||||
<div
|
||||
className="navds-combobox__list-item--loading"
|
||||
id={filteredOptionsUtil.getIsLoadingId(id)}
|
||||
>
|
||||
<Loader title="Søker..." />
|
||||
</div>
|
||||
)}
|
||||
{!isLoading && filteredOptions.length === 0 && (
|
||||
<div
|
||||
className="navds-combobox__list-item--no-options"
|
||||
id={filteredOptionsUtil.getNoHitsId(id)}
|
||||
>
|
||||
Ingen søketreff
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{isValueNew && allowNewValues && (
|
||||
<li
|
||||
tabIndex={-1}
|
||||
onMouseMove={() => {
|
||||
if (
|
||||
activeDecendantId !== filteredOptionsUtil.getAddNewOptionId(id)
|
||||
) {
|
||||
virtualFocus.moveFocusToElement(
|
||||
filteredOptionsUtil.getAddNewOptionId(id),
|
||||
);
|
||||
setIsMouseLastUsedInputDevice(true);
|
||||
}
|
||||
}}
|
||||
onPointerUp={(event) => {
|
||||
toggleOption(value, event);
|
||||
if (!isMultiSelect && !selectedOptions.includes(value))
|
||||
toggleIsListOpen(false);
|
||||
}}
|
||||
id={filteredOptionsUtil.getAddNewOptionId(id)}
|
||||
className={cl("navds-combobox__list-item__new-option", {
|
||||
"navds-combobox__list-item__new-option--focus":
|
||||
activeDecendantId === filteredOptionsUtil.getAddNewOptionId(id),
|
||||
})}
|
||||
role="option"
|
||||
aria-selected={false}
|
||||
|
||||
{shouldRenderFilteredOptionsList && (
|
||||
<ul
|
||||
ref={setFilteredOptionsRef}
|
||||
role="listbox"
|
||||
className="navds-combobox__list-options"
|
||||
>
|
||||
<PlusIcon aria-hidden />
|
||||
<BodyShort size={size}>
|
||||
Legg til{" "}
|
||||
<Label as="span" size={size}>
|
||||
“{value}”
|
||||
</Label>
|
||||
</BodyShort>
|
||||
</li>
|
||||
{isValueNew && !maxSelected?.isLimitReached && allowNewValues && (
|
||||
<li
|
||||
tabIndex={-1}
|
||||
onMouseMove={() => {
|
||||
if (
|
||||
activeDecendantId !==
|
||||
filteredOptionsUtil.getAddNewOptionId(id)
|
||||
) {
|
||||
virtualFocus.moveFocusToElement(
|
||||
filteredOptionsUtil.getAddNewOptionId(id),
|
||||
);
|
||||
setIsMouseLastUsedInputDevice(true);
|
||||
}
|
||||
}}
|
||||
onPointerUp={(event) => {
|
||||
toggleOption(value, event);
|
||||
if (!isMultiSelect && !selectedOptions.includes(value))
|
||||
toggleIsListOpen(false);
|
||||
}}
|
||||
id={filteredOptionsUtil.getAddNewOptionId(id)}
|
||||
className={cl(
|
||||
"navds-combobox__list-item navds-combobox__list-item--new-option",
|
||||
{
|
||||
"navds-combobox__list-item--new-option--focus":
|
||||
activeDecendantId ===
|
||||
filteredOptionsUtil.getAddNewOptionId(id),
|
||||
},
|
||||
)}
|
||||
role="option"
|
||||
aria-selected={false}
|
||||
>
|
||||
<PlusIcon aria-hidden />
|
||||
<BodyShort size={size}>
|
||||
Legg til{" "}
|
||||
<Label as="span" size={size}>
|
||||
“{value}”
|
||||
</Label>
|
||||
</BodyShort>
|
||||
</li>
|
||||
)}
|
||||
{filteredOptions.map((option) => (
|
||||
<li
|
||||
className={cl("navds-combobox__list-item", {
|
||||
"navds-combobox__list-item--focus":
|
||||
activeDecendantId ===
|
||||
filteredOptionsUtil.getOptionId(id, option),
|
||||
"navds-combobox__list-item--selected":
|
||||
selectedOptions.includes(option),
|
||||
})}
|
||||
data-no-focus={isDisabled(option) || undefined}
|
||||
id={filteredOptionsUtil.getOptionId(id, option)}
|
||||
key={option}
|
||||
tabIndex={-1}
|
||||
onMouseMove={() => {
|
||||
if (
|
||||
activeDecendantId !==
|
||||
filteredOptionsUtil.getOptionId(id, option)
|
||||
) {
|
||||
virtualFocus.moveFocusToElement(
|
||||
filteredOptionsUtil.getOptionId(id, option),
|
||||
);
|
||||
setIsMouseLastUsedInputDevice(true);
|
||||
}
|
||||
}}
|
||||
onPointerUp={(event) => {
|
||||
if (isDisabled(option)) {
|
||||
return;
|
||||
}
|
||||
toggleOption(option, event);
|
||||
if (!isMultiSelect && !selectedOptions.includes(option)) {
|
||||
toggleIsListOpen(false);
|
||||
}
|
||||
}}
|
||||
role="option"
|
||||
aria-selected={selectedOptions.includes(option)}
|
||||
aria-disabled={isDisabled(option) || undefined}
|
||||
>
|
||||
<BodyShort size={size}>{option}</BodyShort>
|
||||
{selectedOptions.includes(option) && <CheckmarkIcon />}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
{!isLoading && filteredOptions.length === 0 && (
|
||||
<li
|
||||
className="navds-combobox__list-item__no-options"
|
||||
role="option"
|
||||
aria-selected={false}
|
||||
id={filteredOptionsUtil.getNoHitsId(id)}
|
||||
data-no-focus="true"
|
||||
>
|
||||
Ingen søketreff
|
||||
</li>
|
||||
)}
|
||||
{filteredOptions.map((option) => (
|
||||
<li
|
||||
className={cl("navds-combobox__list-item", {
|
||||
"navds-combobox__list-item--focus":
|
||||
activeDecendantId === filteredOptionsUtil.getOptionId(id, option),
|
||||
"navds-combobox__list-item--selected":
|
||||
selectedOptions.includes(option),
|
||||
})}
|
||||
id={filteredOptionsUtil.getOptionId(id, option)}
|
||||
key={option}
|
||||
tabIndex={-1}
|
||||
onMouseMove={() => {
|
||||
if (
|
||||
activeDecendantId !== filteredOptionsUtil.getOptionId(id, option)
|
||||
) {
|
||||
virtualFocus.moveFocusToElement(
|
||||
filteredOptionsUtil.getOptionId(id, option),
|
||||
);
|
||||
setIsMouseLastUsedInputDevice(true);
|
||||
}
|
||||
}}
|
||||
onPointerUp={(event) => {
|
||||
toggleOption(option, event);
|
||||
if (!isMultiSelect && !selectedOptions.includes(option))
|
||||
toggleIsListOpen(false);
|
||||
}}
|
||||
role="option"
|
||||
aria-selected={selectedOptions.includes(option)}
|
||||
>
|
||||
<BodyShort size={size}>{option}</BodyShort>
|
||||
{selectedOptions.includes(option) && <CheckmarkIcon />}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -7,8 +7,11 @@ const isPartOfText = (value, text) =>
|
||||
const isValueInList = (value, list) =>
|
||||
list?.find((listItem) => normalizeText(value) === normalizeText(listItem));
|
||||
|
||||
const getMatchingValuesFromList = (value, list) =>
|
||||
list?.filter((listItem) => isPartOfText(value, listItem));
|
||||
const getMatchingValuesFromList = (value, list, alwaysIncluded) =>
|
||||
list?.filter(
|
||||
(listItem) =>
|
||||
isPartOfText(value, listItem) || alwaysIncluded.includes(listItem),
|
||||
);
|
||||
|
||||
const getFilteredOptionsId = (comboboxId: string) =>
|
||||
`${comboboxId}-filtered-options`;
|
||||
@@ -25,6 +28,9 @@ const getIsLoadingId = (comboboxId: string) => `${comboboxId}-is-loading`;
|
||||
|
||||
const getNoHitsId = (comboboxId: string) => `${comboboxId}-no-hits`;
|
||||
|
||||
const getMaxSelectedOptionsId = (comboboxId: string) =>
|
||||
`${comboboxId}-max-selected-options`;
|
||||
|
||||
export default {
|
||||
normalizeText,
|
||||
isPartOfText,
|
||||
@@ -35,4 +41,5 @@ export default {
|
||||
getOptionId,
|
||||
getIsLoadingId,
|
||||
getNoHitsId,
|
||||
getMaxSelectedOptionsId,
|
||||
};
|
||||
@@ -9,6 +9,7 @@ import React, {
|
||||
} from "react";
|
||||
import { useClientLayoutEffect, usePrevious } from "../../../util/hooks";
|
||||
import { useInputContext } from "../Input/inputContext";
|
||||
import { useSelectedOptionsContext } from "../SelectedOptions/selectedOptionsContext";
|
||||
import { useCustomOptionsContext } from "../customOptionsContext";
|
||||
import { ComboboxProps } from "../types";
|
||||
import filteredOptionsUtils from "./filtered-options-util";
|
||||
@@ -70,6 +71,7 @@ export const FilteredOptionsProvider = ({
|
||||
setSearchTerm,
|
||||
shouldAutocomplete,
|
||||
} = useInputContext();
|
||||
const { selectedOptions, maxSelected } = useSelectedOptionsContext();
|
||||
|
||||
const [isInternalListOpen, setInternalListOpen] = useState(false);
|
||||
const { customOptions } = useCustomOptionsContext();
|
||||
@@ -79,8 +81,18 @@ export const FilteredOptionsProvider = ({
|
||||
return externalFilteredOptions;
|
||||
}
|
||||
const opts = [...customOptions, ...options];
|
||||
return filteredOptionsUtils.getMatchingValuesFromList(searchTerm, opts);
|
||||
}, [customOptions, externalFilteredOptions, options, searchTerm]);
|
||||
return filteredOptionsUtils.getMatchingValuesFromList(
|
||||
searchTerm,
|
||||
opts,
|
||||
selectedOptions,
|
||||
);
|
||||
}, [
|
||||
customOptions,
|
||||
externalFilteredOptions,
|
||||
options,
|
||||
searchTerm,
|
||||
selectedOptions,
|
||||
]);
|
||||
|
||||
const previousSearchTerm = usePrevious(searchTerm);
|
||||
|
||||
@@ -154,10 +166,17 @@ export const FilteredOptionsProvider = ({
|
||||
activeOption = filteredOptionsUtils.getIsLoadingId(id);
|
||||
}
|
||||
}
|
||||
return cl(activeOption, partialAriaDescribedBy) || undefined;
|
||||
const maybeMaxSelectedOptionsId =
|
||||
maxSelected?.isLimitReached &&
|
||||
filteredOptionsUtils.getMaxSelectedOptionsId(id);
|
||||
return (
|
||||
cl(activeOption, maybeMaxSelectedOptionsId, partialAriaDescribedBy) ||
|
||||
undefined
|
||||
);
|
||||
}, [
|
||||
isListOpen,
|
||||
isLoading,
|
||||
maxSelected?.isLimitReached,
|
||||
value,
|
||||
partialAriaDescribedBy,
|
||||
shouldAutocomplete,
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { Dispatch, SetStateAction, useState } from "react";
|
||||
import { useState } from "react";
|
||||
|
||||
export type VirtualFocusType = {
|
||||
activeElement: HTMLElement | undefined;
|
||||
getElementById: (id: string) => HTMLElement | undefined;
|
||||
isFocusOnTheTop: boolean;
|
||||
isFocusOnTheBottom: boolean;
|
||||
setIndex: Dispatch<SetStateAction<number>>;
|
||||
isFocusOnTheTop: () => boolean;
|
||||
isFocusOnTheBottom: () => boolean;
|
||||
moveFocusUp: () => void;
|
||||
moveFocusDown: () => void;
|
||||
moveFocusToElement: (id: string) => void;
|
||||
@@ -16,57 +15,77 @@ export type VirtualFocusType = {
|
||||
const useVirtualFocus = (
|
||||
containerRef: HTMLElement | null,
|
||||
): VirtualFocusType => {
|
||||
const [index, setIndex] = useState(-1);
|
||||
|
||||
const listOfAllChildren: HTMLElement[] = containerRef?.children
|
||||
? Array.prototype.slice.call(containerRef?.children)
|
||||
: [];
|
||||
const elementsAbleToReceiveFocus = listOfAllChildren.filter(
|
||||
(child) => child.getAttribute("data-no-focus") !== "true",
|
||||
const [activeElement, setActiveElement] = useState<HTMLElement | undefined>(
|
||||
undefined,
|
||||
);
|
||||
|
||||
const activeElement = elementsAbleToReceiveFocus[index];
|
||||
const getElementById = (id: string) =>
|
||||
listOfAllChildren.find((element) => element.id === id);
|
||||
const isFocusOnTheTop = index === 0;
|
||||
const isFocusOnTheBottom = index === elementsAbleToReceiveFocus.length - 1;
|
||||
|
||||
const scrollToOption = (newIndex: number) => {
|
||||
const indexOfElementToScrollTo = Math.min(
|
||||
Math.max(newIndex, 0),
|
||||
containerRef?.children.length || 0,
|
||||
const getListOfAllChildren = (): HTMLElement[] =>
|
||||
Array.from(containerRef?.children ?? []) as HTMLElement[];
|
||||
const getElementsAbleToReceiveFocus = () =>
|
||||
getListOfAllChildren().filter(
|
||||
(child) => child.getAttribute("data-no-focus") !== "true",
|
||||
);
|
||||
if (containerRef?.children[indexOfElementToScrollTo]) {
|
||||
const child = containerRef.children[indexOfElementToScrollTo];
|
||||
const { top, bottom } = child.getBoundingClientRect();
|
||||
const parentRect = containerRef.getBoundingClientRect();
|
||||
if (top < parentRect.top || bottom > parentRect.bottom) {
|
||||
child.scrollIntoView({ block: "nearest" });
|
||||
}
|
||||
|
||||
const getElementById = (id: string) =>
|
||||
getListOfAllChildren().find((element) => element.id === id);
|
||||
const isFocusOnTheTop = () =>
|
||||
activeElement
|
||||
? getElementsAbleToReceiveFocus().indexOf(activeElement) === 0
|
||||
: false;
|
||||
const isFocusOnTheBottom = () => {
|
||||
const elementsAbleToReceiveFocus = getElementsAbleToReceiveFocus();
|
||||
return activeElement
|
||||
? elementsAbleToReceiveFocus.indexOf(activeElement) ===
|
||||
elementsAbleToReceiveFocus.length - 1
|
||||
: false;
|
||||
};
|
||||
|
||||
const _moveFocusAndScrollTo = (_element?: HTMLElement) => {
|
||||
setActiveElement(_element);
|
||||
_element?.scrollIntoView?.({ block: "nearest" });
|
||||
};
|
||||
|
||||
const moveFocusUp = () => {
|
||||
if (!activeElement) {
|
||||
return;
|
||||
}
|
||||
const elementsAbleToReceiveFocus = getElementsAbleToReceiveFocus();
|
||||
const _currentIndex = elementsAbleToReceiveFocus.indexOf(activeElement);
|
||||
const elementAbove = elementsAbleToReceiveFocus[_currentIndex - 1];
|
||||
if (_currentIndex === 0) {
|
||||
setActiveElement(undefined);
|
||||
} else {
|
||||
_moveFocusAndScrollTo(elementAbove);
|
||||
}
|
||||
};
|
||||
|
||||
const _moveFocusAndScrollTo = (_index: number) => {
|
||||
setIndex(_index);
|
||||
scrollToOption(_index);
|
||||
const moveFocusDown = () => {
|
||||
const elementsAbleToReceiveFocus = getElementsAbleToReceiveFocus();
|
||||
if (!activeElement) {
|
||||
_moveFocusAndScrollTo(elementsAbleToReceiveFocus[0]);
|
||||
return;
|
||||
}
|
||||
const _currentIndex = elementsAbleToReceiveFocus.indexOf(activeElement);
|
||||
if (_currentIndex === elementsAbleToReceiveFocus.length - 1) {
|
||||
return;
|
||||
} else {
|
||||
_moveFocusAndScrollTo(elementsAbleToReceiveFocus[_currentIndex + 1]);
|
||||
}
|
||||
};
|
||||
const moveFocusUp = () => _moveFocusAndScrollTo(Math.max(index - 1, -1));
|
||||
const moveFocusDown = () =>
|
||||
_moveFocusAndScrollTo(
|
||||
Math.min(index + 1, elementsAbleToReceiveFocus.length - 1),
|
||||
|
||||
const moveFocusToTop = () => _moveFocusAndScrollTo(undefined);
|
||||
const moveFocusToBottom = () => {
|
||||
const elementsAbleToReceiveFocus = getElementsAbleToReceiveFocus();
|
||||
return _moveFocusAndScrollTo(
|
||||
elementsAbleToReceiveFocus[elementsAbleToReceiveFocus.length - 1],
|
||||
);
|
||||
const moveFocusToTop = () => _moveFocusAndScrollTo(-1);
|
||||
const moveFocusToBottom = () =>
|
||||
_moveFocusAndScrollTo(elementsAbleToReceiveFocus.length - 1);
|
||||
};
|
||||
const moveFocusToElement = (id: string) => {
|
||||
const thisElement = elementsAbleToReceiveFocus.find(
|
||||
(_element) => _element.getAttribute("id") === id,
|
||||
const _element = getElementsAbleToReceiveFocus().find(
|
||||
(_focusableElement) => _focusableElement.getAttribute("id") === id,
|
||||
);
|
||||
const indexOfElement = thisElement
|
||||
? elementsAbleToReceiveFocus.indexOf(thisElement)
|
||||
: -1;
|
||||
if (indexOfElement >= 0) {
|
||||
setIndex(indexOfElement);
|
||||
if (_element) {
|
||||
setActiveElement(_element);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -75,7 +94,6 @@ const useVirtualFocus = (
|
||||
getElementById,
|
||||
isFocusOnTheTop,
|
||||
isFocusOnTheBottom,
|
||||
setIndex,
|
||||
moveFocusUp,
|
||||
moveFocusDown,
|
||||
moveFocusToElement,
|
||||
|
||||
@@ -101,9 +101,11 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||
onEnter(e);
|
||||
break;
|
||||
case "Home":
|
||||
toggleIsListOpen(false);
|
||||
virtualFocus.moveFocusToTop();
|
||||
break;
|
||||
case "End":
|
||||
toggleIsListOpen(true);
|
||||
virtualFocus.moveFocusToBottom();
|
||||
break;
|
||||
default:
|
||||
@@ -135,7 +137,7 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||
// Otherwise ignore keystrokes, so it doesn't interfere with text editing
|
||||
if (isListOpen && activeDecendantId) {
|
||||
e.preventDefault();
|
||||
if (virtualFocus.isFocusOnTheTop) {
|
||||
if (virtualFocus.isFocusOnTheTop()) {
|
||||
toggleIsListOpen(false);
|
||||
}
|
||||
virtualFocus.moveFocusUp();
|
||||
|
||||
@@ -8,7 +8,7 @@ import React, {
|
||||
import { usePrevious } from "../../../util/hooks";
|
||||
import { useInputContext } from "../Input/inputContext";
|
||||
import { useCustomOptionsContext } from "../customOptionsContext";
|
||||
import { ComboboxProps } from "../types";
|
||||
import { ComboboxProps, MaxSelected } from "../types";
|
||||
|
||||
type SelectedOptionsContextType = {
|
||||
addSelectedOption: (option: string) => void;
|
||||
@@ -16,6 +16,7 @@ type SelectedOptionsContextType = {
|
||||
removeSelectedOption: (option: string) => void;
|
||||
prevSelectedOptions?: string[];
|
||||
selectedOptions: string[];
|
||||
maxSelected?: MaxSelected & { isLimitReached: boolean };
|
||||
setSelectedOptions: (any) => void;
|
||||
toggleOption: (
|
||||
option: string,
|
||||
@@ -39,6 +40,7 @@ export const SelectedOptionsProvider = ({
|
||||
| "options"
|
||||
| "selectedOptions"
|
||||
| "onToggleSelected"
|
||||
| "maxSelected"
|
||||
>;
|
||||
}) => {
|
||||
const { clearInput, focusInput } = useInputContext();
|
||||
@@ -54,6 +56,7 @@ export const SelectedOptionsProvider = ({
|
||||
selectedOptions: externalSelectedOptions,
|
||||
onToggleSelected,
|
||||
options,
|
||||
maxSelected,
|
||||
} = value;
|
||||
const [internalSelectedOptions, setSelectedOptions] = useState<string[]>([]);
|
||||
const selectedOptions = useMemo(
|
||||
@@ -129,6 +132,9 @@ export const SelectedOptionsProvider = ({
|
||||
|
||||
const prevSelectedOptions = usePrevious<string[]>(selectedOptions);
|
||||
|
||||
const isLimitReached =
|
||||
!!maxSelected?.limit && selectedOptions.length >= maxSelected.limit;
|
||||
|
||||
const selectedOptionsState = {
|
||||
addSelectedOption,
|
||||
isMultiSelect,
|
||||
@@ -137,6 +143,10 @@ export const SelectedOptionsProvider = ({
|
||||
selectedOptions,
|
||||
setSelectedOptions,
|
||||
toggleOption,
|
||||
maxSelected: maxSelected && {
|
||||
...maxSelected,
|
||||
isLimitReached,
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Meta, StoryFn, StoryObj } from "@storybook/react";
|
||||
import { expect, fn, userEvent, within } from "@storybook/test";
|
||||
import React, { useId, useMemo, useState } from "react";
|
||||
import React, { useId, useMemo, useRef, useState } from "react";
|
||||
import { Chips, ComboboxProps, TextField, UNSAFE_Combobox } from "../../index";
|
||||
|
||||
export default {
|
||||
@@ -37,11 +37,16 @@ Default.args = {
|
||||
label: "Hva er dine favorittfrukter?",
|
||||
shouldAutocomplete: true,
|
||||
isLoading: false,
|
||||
isMultiSelect: false,
|
||||
allowNewValues: false,
|
||||
};
|
||||
Default.argTypes = {
|
||||
isListOpen: {
|
||||
control: { type: "boolean" },
|
||||
},
|
||||
maxSelected: {
|
||||
control: { type: "number" },
|
||||
},
|
||||
size: {
|
||||
options: ["medium", "small"],
|
||||
defaultValue: "medium",
|
||||
@@ -284,6 +289,36 @@ export const ComboboxSizes = () => (
|
||||
</>
|
||||
);
|
||||
|
||||
export const MaxSelectedOptions: StoryFunction = () => {
|
||||
const id = useId();
|
||||
const [value, setValue] = useState<string | undefined>("");
|
||||
const [selectedOptions, setSelectedOptions] = useState([
|
||||
options[0],
|
||||
options[1],
|
||||
]);
|
||||
const comboboxRef = useRef<HTMLInputElement>(null);
|
||||
return (
|
||||
<UNSAFE_Combobox
|
||||
id={id}
|
||||
label="Komboboks med begrenset antall valg"
|
||||
options={options}
|
||||
maxSelected={{ limit: 2 }}
|
||||
selectedOptions={selectedOptions}
|
||||
onToggleSelected={(option, isSelected) =>
|
||||
isSelected
|
||||
? setSelectedOptions([...selectedOptions, option])
|
||||
: setSelectedOptions(selectedOptions.filter((o) => o !== option))
|
||||
}
|
||||
isMultiSelect
|
||||
allowNewValues
|
||||
isListOpen={comboboxRef.current ? undefined : true}
|
||||
value={value}
|
||||
onChange={(event) => setValue(event?.target.value)}
|
||||
ref={comboboxRef}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const WithError: StoryFunction = (props) => {
|
||||
const [hasSelectedValue, setHasSelectedValue] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
@@ -74,9 +74,7 @@ describe("Render combobox", () => {
|
||||
it("Should show loading icon when loading (used for async search)", async () => {
|
||||
render(<App options={[]} isListOpen isLoading />);
|
||||
|
||||
expect(
|
||||
await screen.findByRole("option", { name: "venter..." }),
|
||||
).toBeInTheDocument();
|
||||
expect(await screen.findByText("Søker...")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
import React, { ChangeEvent, InputHTMLAttributes } from "react";
|
||||
import { FormFieldProps } from "../useFormField";
|
||||
|
||||
export type MaxSelected = {
|
||||
/**
|
||||
* The limit for maximum selected options
|
||||
*/
|
||||
limit: number;
|
||||
/**
|
||||
* Override the message to display when the limit for maximum selected options has been reached
|
||||
*/
|
||||
message?: string;
|
||||
};
|
||||
|
||||
export interface ComboboxProps
|
||||
extends FormFieldProps,
|
||||
Omit<InputHTMLAttributes<HTMLInputElement>, "size" | "onChange" | "value"> {
|
||||
@@ -97,6 +108,10 @@ export interface ComboboxProps
|
||||
* e.g. for a filter, where options can be toggled elsewhere/programmatically.
|
||||
*/
|
||||
selectedOptions?: string[];
|
||||
/**
|
||||
* Options for the maximum number of selected options.
|
||||
*/
|
||||
maxSelected?: MaxSelected;
|
||||
/**
|
||||
* Set to "true" to enable inline autocomplete.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Meta } from "@storybook/react";
|
||||
import React from "react";
|
||||
import { ErrorSummary } from "..";
|
||||
import { ErrorSummary } from "./ErrorSummary";
|
||||
|
||||
export default {
|
||||
title: "ds-react/Errorsummary",
|
||||
|
||||
@@ -66,6 +66,10 @@ export interface SearchProps
|
||||
* Exposes the HTML size attribute
|
||||
*/
|
||||
htmlSize?: number | string;
|
||||
/*
|
||||
* Exposes role attribute
|
||||
*/
|
||||
role?: string;
|
||||
}
|
||||
|
||||
interface SearchComponent
|
||||
@@ -114,6 +118,7 @@ export const Search = forwardRef<HTMLInputElement, SearchProps>(
|
||||
onChange,
|
||||
onSearchClick,
|
||||
htmlSize,
|
||||
role,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
@@ -205,7 +210,7 @@ export const Search = forwardRef<HTMLInputElement, SearchProps>(
|
||||
value={value ?? internalValue}
|
||||
onChange={(e) => handleChange(e.target.value)}
|
||||
type="search"
|
||||
role="searchbox"
|
||||
role={role ?? "searchbox"}
|
||||
className={cl(
|
||||
className,
|
||||
"navds-search__input",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Meta } from "@storybook/react";
|
||||
import React, { useState } from "react";
|
||||
import { Link } from "../..";
|
||||
import { Link } from "../../link";
|
||||
import { ConfirmationPanel } from "../index";
|
||||
|
||||
export default {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Meta, StoryFn, StoryObj } from "@storybook/react";
|
||||
import { expect, userEvent, within } from "@storybook/test";
|
||||
import React, { useState } from "react";
|
||||
import { Button } from "../../button";
|
||||
import { Modal } from "../../modal";
|
||||
import { Textarea } from "../index";
|
||||
|
||||
const meta: Meta<typeof Textarea> = {
|
||||
@@ -124,6 +126,24 @@ export const Resize: StoryFn = () => {
|
||||
return <Textarea resize label="Ipsum enim quis culpa" />;
|
||||
};
|
||||
|
||||
export const OnChange: StoryFn = () => {
|
||||
return (
|
||||
<Textarea
|
||||
label="Ipsum enim quis culpa"
|
||||
onChange={console.log}
|
||||
maxLength={50}
|
||||
/>
|
||||
);
|
||||
};
|
||||
OnChange.play = async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const input = canvas.getByLabelText("Ipsum enim quis culpa");
|
||||
userEvent.click(input);
|
||||
await userEvent.type(input, "Aute fugiat ut culpa");
|
||||
const text = canvas.getByText("30 tegn igjen");
|
||||
expect(text).toBeVisible();
|
||||
};
|
||||
|
||||
export const Controlled: StoryFn = () => {
|
||||
const [value, setValue] = useState("");
|
||||
return (
|
||||
@@ -186,3 +206,20 @@ AutoScrollbar.argTypes = {
|
||||
maxRows: { type: "number" },
|
||||
minRows: { type: "number" },
|
||||
};
|
||||
|
||||
export const ModalStrictMode: StoryFn<typeof Textarea> = () => {
|
||||
// Story added after fixing an issue where TextareaAutoSize would reach max re-renders
|
||||
// and set the height to 2px when used in StrictMode in a Modal that is initially open.
|
||||
return (
|
||||
<React.StrictMode>
|
||||
<Modal open>
|
||||
<Modal.Body>
|
||||
<Textarea label="Har du noen tilbakemeldinger?" />
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
</React.StrictMode>
|
||||
);
|
||||
};
|
||||
ModalStrictMode.parameters = {
|
||||
chromatic: { disable: true }, // Not reproducable in Chromatic
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Meta, StoryFn, StoryObj } from "@storybook/react";
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { BodyLong, Heading, HelpText } from "..";
|
||||
import { BodyLong, Heading } from "../typography";
|
||||
import HelpText from "./HelpText";
|
||||
|
||||
const meta: Meta<typeof HelpText> = {
|
||||
title: "ds-react/HelpText",
|
||||
|
||||
@@ -10,6 +10,7 @@ export * from "./expansion-card";
|
||||
export * from "./form";
|
||||
export * from "./grid";
|
||||
export * from "./guide-panel";
|
||||
export * from "./overlays";
|
||||
export * from "./help-text";
|
||||
export * from "./internal-header";
|
||||
export * from "./link";
|
||||
|
||||
@@ -6,7 +6,8 @@ import {
|
||||
MenuGridIcon,
|
||||
} from "@navikt/aksel-icons";
|
||||
import { BodyLong, BodyShort, Detail } from "@navikt/ds-react";
|
||||
import { Dropdown, InternalHeader } from "..";
|
||||
import { Dropdown } from "../dropdown";
|
||||
import InternalHeader from "./InternalHeader";
|
||||
|
||||
export default {
|
||||
title: "ds-react/InternalHeader",
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import type { Meta } from "@storybook/react";
|
||||
import React from "react";
|
||||
import { Box, HStack, VStack } from "../..";
|
||||
import { BodyLong } from "../../typography";
|
||||
import { Box } from "../box";
|
||||
import { HStack, VStack } from "../stack";
|
||||
import { Bleed } from "./Bleed";
|
||||
|
||||
export default {
|
||||
@@ -272,6 +273,19 @@ export const Full = {
|
||||
</Bleed>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box
|
||||
className="maxWidth"
|
||||
background="surface-alt-1-subtle"
|
||||
padding="10"
|
||||
>
|
||||
<Box background="surface-alt-2-subtle" padding="10">
|
||||
<Bleed marginInline="full" reflectivePadding asChild>
|
||||
<Box background="surface-success-subtle">
|
||||
<BodyLong>full + reflectivePadding</BodyLong>
|
||||
</Box>
|
||||
</Bleed>
|
||||
</Box>
|
||||
</Box>
|
||||
</VStack>
|
||||
</>
|
||||
),
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import type { Meta } from "@storybook/react";
|
||||
import React, { ReactNode } from "react";
|
||||
import { ChevronRightIcon } from "@navikt/aksel-icons";
|
||||
import { HGrid, HStack, VStack } from "../..";
|
||||
import { BodyLong, Detail, Heading } from "../../typography";
|
||||
import { HGrid } from "../grid";
|
||||
import { HStack, VStack } from "../stack";
|
||||
import { BackgroundToken, BorderRadiiToken } from "../utilities/types";
|
||||
import { Box } from "./Box";
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import React from "react";
|
||||
import { Box, HGrid, Hide, Show, VStack } from "../..";
|
||||
import { Box } from "../box";
|
||||
import { HGrid } from "../grid";
|
||||
import { Hide, Show } from "../responsive";
|
||||
import { VStack } from "../stack";
|
||||
import { Content } from "./Content";
|
||||
import { FilterCard } from "./Filter";
|
||||
import { Header } from "./Header";
|
||||
@@ -13,6 +16,7 @@ const meta = {
|
||||
title: "kitchen sink/navno-sidemal",
|
||||
parameters: {
|
||||
layout: "fullscreen",
|
||||
chromatic: { disable: true },
|
||||
},
|
||||
} satisfies Meta;
|
||||
|
||||
|
||||
@@ -44,6 +44,9 @@ const translateTokenStringToCSS = (
|
||||
if (componentProp === "margin-inline" && x === "full") {
|
||||
const width = 100 / arr.length;
|
||||
return `calc((100vw - ${width}%)/-2)`;
|
||||
} else if (componentProp === "padding-inline" && x === "full") {
|
||||
const width = 100 / arr.length;
|
||||
return `calc((100vw - ${width}%)/2)`;
|
||||
}
|
||||
|
||||
let output = `var(--a-${tokenSubgroup}-${x})`;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Meta } from "@storybook/react";
|
||||
import React from "react";
|
||||
import { LinkPanel } from "..";
|
||||
import LinkPanel from "./LinkPanel";
|
||||
|
||||
export default {
|
||||
title: "ds-react/LinkPanel",
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import React from "react";
|
||||
import { PlusCircleFillIcon } from "@navikt/aksel-icons";
|
||||
import {
|
||||
BodyLong,
|
||||
Alert as DsAlert,
|
||||
ConfirmationPanel as DsConfirmationPanel,
|
||||
Link,
|
||||
} from "../..";
|
||||
import { Alert } from "../../alert";
|
||||
import { ConfirmationPanel } from "../../form";
|
||||
import { BodyLong } from "../../typography";
|
||||
import Link from "../Link";
|
||||
import { RandomIcon } from "./RandomIcon";
|
||||
|
||||
export default {
|
||||
@@ -139,37 +137,37 @@ const DemoLink = () => (
|
||||
|
||||
export const Icon = () => <DemoLink />;
|
||||
|
||||
export const Alert = () => {
|
||||
export const InAlert = () => {
|
||||
return (
|
||||
<div className="colgap">
|
||||
<DsAlert variant="info">
|
||||
<Alert variant="info">
|
||||
<DemoLink />
|
||||
</DsAlert>
|
||||
<DsAlert variant="success">
|
||||
</Alert>
|
||||
<Alert variant="success">
|
||||
<DemoLink />
|
||||
</DsAlert>
|
||||
<DsAlert variant="warning">
|
||||
</Alert>
|
||||
<Alert variant="warning">
|
||||
<DemoLink />
|
||||
</DsAlert>
|
||||
<DsAlert variant="error">
|
||||
</Alert>
|
||||
<Alert variant="error">
|
||||
<DemoLink />
|
||||
</DsAlert>
|
||||
</Alert>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const ConfirmationPanel = () => {
|
||||
export const InConfirmationPanel = () => {
|
||||
return (
|
||||
<div className="colgap">
|
||||
<DsConfirmationPanel label="demo">
|
||||
<ConfirmationPanel label="demo">
|
||||
<DemoLink />
|
||||
</DsConfirmationPanel>
|
||||
<DsConfirmationPanel checked label="demo">
|
||||
</ConfirmationPanel>
|
||||
<ConfirmationPanel checked label="demo">
|
||||
<DemoLink />
|
||||
</DsConfirmationPanel>
|
||||
<DsConfirmationPanel error="demo" label="demo">
|
||||
</ConfirmationPanel>
|
||||
<ConfirmationPanel error="demo" label="demo">
|
||||
<DemoLink />
|
||||
</DsConfirmationPanel>
|
||||
</ConfirmationPanel>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -6,7 +6,8 @@ import {
|
||||
HeadHeartIcon,
|
||||
RecycleIcon,
|
||||
} from "@navikt/aksel-icons";
|
||||
import { List, VStack } from "..";
|
||||
import { VStack } from "../layout/stack";
|
||||
import List from "./List";
|
||||
|
||||
export default {
|
||||
title: "ds-react/List",
|
||||
|
||||
Loaded 100 of 367 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user