mirror of
https://github.com/navikt/aksel.git
synced 2026-10-15 10:12:03 +00:00
Compare commits
21
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
99465ddbeb | ||
|
|
25305ebba0 | ||
|
|
ef3464c96c | ||
|
|
0480d785c4 | ||
|
|
ef5e671cfe | ||
|
|
fa156773e0 | ||
|
|
137b4c49c1 | ||
|
|
1fb72241fe | ||
|
|
42470baaaf | ||
|
|
8cd6512181 | ||
|
|
7e976f9e20 | ||
|
|
db828bddd3 | ||
|
|
443b129fe1 | ||
|
|
561fecbcac | ||
|
|
00177898f5 | ||
|
|
38f5e63008 | ||
|
|
c3d65a681e | ||
|
|
3025e4eb5c | ||
|
|
043277f79b | ||
|
|
a2b3936878 | ||
|
|
c90abe7c23 |
No files matched your search
+14
-10
@@ -1,31 +1,35 @@
|
||||
# Changesets
|
||||
|
||||
For versjonering bruker vi løsningen [Changesets](https://github.com/changesets/changesets) for [versjonering](https://semver.org/) og publisering av pakker.
|
||||
Vi bruker [Changesets](https://github.com/changesets/changesets) for [versjonering](https://semver.org/) og publisering av pakker.
|
||||
|
||||
## Howto
|
||||
## Lage ny versjon
|
||||
|
||||
- For å lage en ny versjons-entry: `yarn changeset`
|
||||
- Velg pakkene som skal versjoneres med `arrowkeys` + `Space`
|
||||
1. `yarn changeset`
|
||||
2. Svar på spørsmålene som kommer opp:
|
||||
|
||||
`🦋 Which packages would you like to include?`
|
||||
|
||||
Trykk `Space` for å velge pakkene som skal versjoneres, for så trykke `Enter` for å gå videre.
|
||||
Trykk `Space` for å velge pakkene som skal versjoneres, trykk så `Enter` for å gå videre.
|
||||
|
||||
`🦋 Which packages should have a major bump?`
|
||||
|
||||
Trykk `Enter` for å gå videre _*eller*_ velg pakkene som skal marjor-bumpes med `arrowkeys` + `Space`
|
||||
Trykk `Enter` for å gå videre _eller_ velg pakkene som skal marjor-bumpes med `arrowkeys` + `Space`.
|
||||
|
||||
`🦋 Which packages should have a minor bump?`
|
||||
|
||||
Trykk `Enter` for å gå videre _*eller*_ velg pakkene som skal marjor-bumpes med `arrowkeys` + `Space`
|
||||
Trykk `Enter` for å gå videre _eller_ velg pakkene som skal minor-bumpes med `arrowkeys` + `Space`.
|
||||
|
||||
Hvis du ikke velger major eller minor, så blir pakkene få en patch-bump
|
||||
Hvis du ikke velger major eller minor, så vil pakkene få en patch-bump.
|
||||
|
||||
- Commit og push.
|
||||
`Please enter a summary for this change`
|
||||
|
||||
Skriv inn en kort beskrivelse av endringen på formatet `<Komponent>: <gitmoji?> <Beskrivelse>`, f.eks. "Button: ✨ Add feature xyz".
|
||||
|
||||
3. Commit og push.
|
||||
|
||||
## Fixed versjonering
|
||||
|
||||
Alle base-pakkene våre har `fixed versjonering`. Dette tilsier at en bump på en av disse vil bumpe alle til samme versjon
|
||||
Alle base-pakkene våre har `fixed versjonering`. Dette betyr at en bump på en av disse vil bumpe alle til samme versjon
|
||||
|
||||
```sh
|
||||
"@navikt/ds-react",
|
||||
|
||||
@@ -47,12 +47,12 @@ jobs:
|
||||
- name: Chromatic
|
||||
uses: chromaui/action@latest
|
||||
id: chromatic_tests
|
||||
continue-on-error: true
|
||||
continue-on-error: false
|
||||
with:
|
||||
autoAcceptChanges: "main"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
||||
exitZeroOnChanges: false
|
||||
exitZeroOnChanges: true
|
||||
buildScriptName: "build:storybook-chromatic"
|
||||
onlyChanged: true
|
||||
untraced: "**/package.json|yarn.lock|**/*.md"
|
||||
@@ -62,14 +62,14 @@ jobs:
|
||||
STORYBOOK_GITHUB_SHA: ${{ github.sha }}
|
||||
|
||||
- name: Get commit sha
|
||||
if: "!contains(github.event.head_commit.message, '[ci skip]') && github.event_name != 'push'"
|
||||
if: github.event_name != 'push' && !contains(github.event.head_commit.message, '[ci skip]')
|
||||
id: vars
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
|
||||
|
||||
- name: Find Comment
|
||||
if: "!contains(github.event.head_commit.message, '[ci skip]') && github.event_name != 'push'"
|
||||
if: github.event_name != 'push' && !contains(github.event.head_commit.message, '[ci skip]')
|
||||
uses: peter-evans/find-comment@v2
|
||||
id: fc
|
||||
with:
|
||||
@@ -78,19 +78,7 @@ jobs:
|
||||
body-includes: Storybook demo
|
||||
|
||||
- name: Create or update comment
|
||||
if: steps.chromatic_tests.outcome == 'success' && !contains(github.event.head_commit.message, '[ci skip]') && github.event_name != 'push'
|
||||
uses: peter-evans/create-or-update-comment@v3
|
||||
with:
|
||||
comment-id: ${{ steps.fc.outputs.comment-id }}
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
body: |
|
||||
## [Storybook demo](${{steps.chromatic_tests.outputs.storybookUrl}})
|
||||
|
||||
[${{ steps.vars.outputs.sha_short }}](https://github.com/navikt/aksel/commit/${{ steps.vars.outputs.sha_short }}) | ${{steps.chromatic_tests.outputs.componentCount}} komponenter | ${{steps.chromatic_tests.outputs.specCount}} stories
|
||||
edit-mode: replace
|
||||
|
||||
- name: Create or update failed comment
|
||||
if: steps.chromatic_tests.outcome != 'success' && !contains(github.event.head_commit.message, '[ci skip]') && github.event_name != 'push'
|
||||
if: github.event_name != 'push' && !contains(github.event.head_commit.message, '[ci skip]')
|
||||
uses: peter-evans/create-or-update-comment@v3
|
||||
with:
|
||||
comment-id: ${{ steps.fc.outputs.comment-id }}
|
||||
@@ -98,10 +86,9 @@ jobs:
|
||||
body: |
|
||||
## [Storybook demo](${{steps.chromatic_tests.outputs.storybookUrl}}) / [Chromatic](${{steps.chromatic_tests.outputs.url}})
|
||||
|
||||
### 📝 Endringer til review: ${{steps.chromatic_tests.outputs.changeCount}}
|
||||
${{ steps.chromatic_tests.outputs.changeCount > 0 && format('### 📝 Changes to review: {0}', steps.chromatic_tests.outputs.changeCount) || '' }}
|
||||
${{ steps.chromatic_tests.outputs.errorCount > 0 && format('### ❌ Stories with errors: {0}', steps.chromatic_tests.outputs.errorCount) || '' }}
|
||||
${{ steps.chromatic_tests.outputs.interactionTestFailuresCount > 0 && format('### ❌ Failed interaction tests: {0}', steps.chromatic_tests.outputs.interactionTestFailuresCount) || '' }}
|
||||
|
||||
${{ steps.chromatic_tests.outputs.errorCount > 0 && format('### ❌ Stories med feil: {0}', steps.chromatic_tests.outputs.errorCount) || '' }}
|
||||
${{ steps.chromatic_tests.outputs.interactionTestFailuresCount > 0 && format('### ❌ Feilede interaksjonstester: {0}', steps.chromatic_tests.outputs.interactionTestFailuresCount) || '' }}
|
||||
|
||||
[${{ steps.vars.outputs.sha_short }}](https://github.com/navikt/aksel/commit/${{ steps.vars.outputs.sha_short }}) | ${{steps.chromatic_tests.outputs.componentCount}} komponenter | ${{steps.chromatic_tests.outputs.specCount}} stories
|
||||
[${{ steps.vars.outputs.sha_short }}](https://github.com/navikt/aksel/commit/${{ steps.vars.outputs.sha_short }}) | ${{steps.chromatic_tests.outputs.componentCount}} components | ${{steps.chromatic_tests.outputs.specCount}} stories
|
||||
edit-mode: replace
|
||||
@@ -5,10 +5,8 @@ import React, { useLayoutEffect } from "react";
|
||||
import darksideCss from "../@navikt/core/css/darkside/index.css?inline";
|
||||
// @ts-expect-error - Temporary
|
||||
import defaultCss from "../@navikt/core/css/index.css?inline";
|
||||
import {
|
||||
Provider,
|
||||
UNSAFE_AkselTheme,
|
||||
} from "../@navikt/core/react/src/provider";
|
||||
import { Provider } from "../@navikt/core/react/src/provider";
|
||||
import { Theme } from "../@navikt/core/react/src/theme";
|
||||
import en from "../@navikt/core/react/src/util/i18n/locales/en";
|
||||
import nb from "../@navikt/core/react/src/util/i18n/locales/nb";
|
||||
import nn from "../@navikt/core/react/src/util/i18n/locales/nn";
|
||||
@@ -31,9 +29,9 @@ const ModeDecorator = ({ children, mode, theme }) => {
|
||||
}, [mode]);
|
||||
|
||||
return mode === "darkside" ? (
|
||||
<UNSAFE_AkselTheme theme={theme || undefined} hasBackground={false}>
|
||||
<Theme theme={theme || undefined} hasBackground={false}>
|
||||
{children}
|
||||
</UNSAFE_AkselTheme>
|
||||
</Theme>
|
||||
) : (
|
||||
children
|
||||
);
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# @navikt/aksel-icons
|
||||
|
||||
## 7.9.1
|
||||
|
||||
## 7.9.0
|
||||
|
||||
## 7.8.1
|
||||
|
||||
## 7.8.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Aksel icons
|
||||
|
||||
800+ open source icons made by Aksel, NAVs designsystem-team
|
||||
800+ open source icons made by Aksel, Nav's design system team.
|
||||
|
||||
- Designed for 24x24px
|
||||
- Available in React and SVG
|
||||
@@ -30,7 +30,7 @@ Tip: Use the `title` prop for accessible icons.
|
||||
|
||||
### Sizing
|
||||
|
||||
Each icons `width` and `height` is default `1em`. This allows you to use the native `fontSize`-prop to adjust sizing. We recommend using at least 1.5rem/24px for best possible visual representation.
|
||||
Each icon's `width` and `height` is default `1em`. This allows you to use the native `fontSize`-prop to adjust sizing. We recommend using at least 1.5rem/24px for the best possible visual representation.
|
||||
|
||||
```jsx
|
||||
<StarIcon fontSize="1.5rem" />
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
# Aksel Icons plugin
|
||||
|
||||
Pluginen gir deg mulighet til å se gjennom og hente ut alle ikonene i fra ikonpakken `@navikt/aksel-icons`. Du slipper da å hente nye oppdateringer fra Figma Community.
|
||||
Pluginen gir deg mulighet til å se gjennom og hente ut alle ikonene fra ikonpakken `@navikt/aksel-icons`. Du slipper da å hente nye oppdateringer fra Figma Community.
|
||||
|
||||
Referer til [ikon-dokumentasjonen](https://aksel.nav.no/ikoner) for å se alle ikonene.
|
||||
Gå til [ikon-dokumentasjonen](https://aksel.nav.no/ikoner) for å se alle ikonene.
|
||||
Har du ønsker om nye ikoner, eller ønsker å bidra med å lage nye, lag et issue på [GitHub-repoet for designsystemet](https://github.com/navikt/aksel).
|
||||
|
||||
## Quickstart
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/aksel-icons",
|
||||
"version": "7.8.1",
|
||||
"version": "7.9.1",
|
||||
"author": "Aksel | Nav",
|
||||
"homepage": "https://aksel.nav.no/ikoner",
|
||||
"repository": {
|
||||
@@ -87,6 +87,6 @@
|
||||
"tsx": "^4.7.1",
|
||||
"typescript": "5.5.4",
|
||||
"unified": "10.1.2",
|
||||
"vitest": "^1.2.2"
|
||||
"vitest": "^2.1.8"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
# @navikt/aksel-stylelint
|
||||
|
||||
## 7.9.1
|
||||
|
||||
## 7.9.0
|
||||
|
||||
## 7.8.1
|
||||
|
||||
## 7.8.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/aksel-stylelint",
|
||||
"version": "7.8.1",
|
||||
"version": "7.9.1",
|
||||
"author": "Aksel | Nav",
|
||||
"homepage": "https://aksel.nav.no/grunnleggende/kode/stylelint",
|
||||
"repository": {
|
||||
@@ -35,8 +35,8 @@
|
||||
"dev": "yarn watch:lint"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@navikt/ds-css": "^7.8.1",
|
||||
"@navikt/ds-tokens": "^7.8.1",
|
||||
"@navikt/ds-css": "^7.9.1",
|
||||
"@navikt/ds-tokens": "^7.9.1",
|
||||
"concurrently": "9.0.1",
|
||||
"postcss-selector-parser": "^6.0.13",
|
||||
"postcss-value-parser": "^4.2.0",
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# @navikt/aksel
|
||||
|
||||
## 7.9.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`25305eb`](https://github.com/navikt/aksel/commit/25305ebba04a37e6315bc37bfabb39f04f83f146)]:
|
||||
- @navikt/ds-css@7.9.1
|
||||
|
||||
## 7.9.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`db828bd`](https://github.com/navikt/aksel/commit/db828bddd393ba1d03d8e68fe80c9211da43e54a), [`0017789`](https://github.com/navikt/aksel/commit/00177898f55573a682a43819b08304c1f60a732a), [`c90abe7`](https://github.com/navikt/aksel/commit/c90abe7c23e2520e5131d138f3193a4de0e28b9d), [`0017789`](https://github.com/navikt/aksel/commit/00177898f55573a682a43819b08304c1f60a732a)]:
|
||||
- @navikt/ds-css@7.9.0
|
||||
|
||||
## 7.8.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/aksel",
|
||||
"version": "7.8.1",
|
||||
"version": "7.9.1",
|
||||
"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": "7.8.1",
|
||||
"@navikt/ds-css": "7.9.1",
|
||||
"axios": "1.7.4",
|
||||
"chalk": "4.1.0",
|
||||
"clipboardy": "^2.3.0",
|
||||
@@ -46,7 +46,7 @@
|
||||
"devDependencies": {
|
||||
"rimraf": "6.0.1",
|
||||
"typescript": "5.5.4",
|
||||
"vitest": "^1.2.2"
|
||||
"vitest": "^2.1.8"
|
||||
},
|
||||
"sideEffects": false,
|
||||
"engines": {
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# @navikt/ds-css
|
||||
|
||||
## 7.9.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Link: :bug: Use inside Alert got wrong text-color while focused or active. ([#3489](https://github.com/navikt/aksel/pull/3489))
|
||||
|
||||
## 7.9.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- ErrorSummary: :sparkles: new prop to prefix error with a warning icon. ([#3445](https://github.com/navikt/aksel/pull/3445))
|
||||
All form components: replace dot with warning icon in error message.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Switch: Update switch to better reflect unchecked state. ([#3468](https://github.com/navikt/aksel/pull/3468))
|
||||
|
||||
- Select: :bug: Focus-border no longer cancels out error-border. ([#3465](https://github.com/navikt/aksel/pull/3465))
|
||||
|
||||
- Textarea: :bug: Focus-border no longer cancels out error-border. ([#3465](https://github.com/navikt/aksel/pull/3465))
|
||||
|
||||
## 7.8.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# Aksel styling
|
||||
|
||||
CSS for NAVs designsystem.
|
||||
CSS for Nav's design system.
|
||||
|
||||
- Css tokens (Colors, border, shadows etc)
|
||||
- Component-styling for `@navikt/ds-react` packages
|
||||
- Css tokens (Colors, border, shadows etc.)
|
||||
- Component styling for `@navikt/ds-react` packages
|
||||
- Normalize.css v8
|
||||
- Font-loading
|
||||
- Font loading
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -16,7 +16,7 @@ CSS for NAVs designsystem.
|
||||
|
||||
## Usage
|
||||
|
||||
Import styles once to make it accessible for your entire project. Typically you will add the following line to your root .tsx file.
|
||||
Import styles once to make it accessible for your entire project. Typically you will add the following line to your root .tsx file:
|
||||
|
||||
```javascript
|
||||
import "@navikt/ds-css";
|
||||
@@ -26,7 +26,7 @@ function App() {
|
||||
}
|
||||
```
|
||||
|
||||
But you can import it in a .css-file
|
||||
But you can import it in a .css-file as well:
|
||||
|
||||
```css
|
||||
@import "@navikt/ds-css";
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
margin-right: var(--ac-button-icon-margin);
|
||||
}
|
||||
|
||||
.navds-button__icon:only-child {
|
||||
.navds-button--icon-only .navds-button__icon {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -497,6 +497,10 @@
|
||||
}
|
||||
|
||||
/* Loader overrides */
|
||||
.navds-button .navds-loader {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.navds-button .navds-loader .navds-loader__foreground {
|
||||
stroke: var(--ac-button-loader-stroke, currentColor);
|
||||
}
|
||||
@@ -506,6 +510,10 @@
|
||||
stroke: var(--ac-button-primary-loader-stroke-bg, rgb(255 255 255 / 0.3));
|
||||
}
|
||||
|
||||
.navds-button--loading > :not(.navds-loader) {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-button:not(.navds-button--loading):where(:disabled, .navds-button--disabled) {
|
||||
opacity: 1;
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
margin-right: var(--__axc-button-icon-margin);
|
||||
}
|
||||
|
||||
&:only-child {
|
||||
.navds-button--icon-only & {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
@@ -264,6 +264,10 @@
|
||||
}
|
||||
|
||||
/* Loader overrides */
|
||||
.navds-button .navds-loader {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.navds-button .navds-loader .navds-loader__foreground {
|
||||
stroke: currentColor;
|
||||
}
|
||||
@@ -273,6 +277,10 @@
|
||||
stroke: rgb(255 255 255 / 0.3);
|
||||
}
|
||||
|
||||
.navds-button--loading > :not(.navds-loader) {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
.navds-button:not(.navds-button--loading):where(:disabled, .navds-button--disabled) {
|
||||
opacity: 1;
|
||||
|
||||
@@ -9,19 +9,6 @@
|
||||
color: var(--ax-text-subtle);
|
||||
}
|
||||
|
||||
.navds-form-field .navds-error-message,
|
||||
.navds-fieldset .navds-error-message,
|
||||
.navds-file-item .navds-error-message {
|
||||
display: flex;
|
||||
gap: var(--ax-spacing-2);
|
||||
}
|
||||
|
||||
.navds-form-field .navds-error-message::before,
|
||||
.navds-fieldset .navds-error-message::before,
|
||||
.navds-file-item .navds-error-message::before {
|
||||
content: "•";
|
||||
}
|
||||
|
||||
.navds-form-field--disabled {
|
||||
opacity: var(--ax-opacity-disabled);
|
||||
cursor: not-allowed;
|
||||
|
||||
@@ -13,11 +13,10 @@
|
||||
border-radius: var(--ax-border-radius-medium);
|
||||
background-color: transparent;
|
||||
box-shadow: inset 0 0 0 1px var(--ax-border-default);
|
||||
padding: var(--ax-spacing-1);
|
||||
gap: var(--ax-spacing-1);
|
||||
display: inline-grid;
|
||||
grid-auto-flow: column;
|
||||
grid-auto-columns: 1fr;
|
||||
gap: 1px;
|
||||
}
|
||||
|
||||
/* Button */
|
||||
@@ -26,13 +25,14 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: var(--ax-spacing-1) var(--ax-spacing-3);
|
||||
min-height: 2.5rem;
|
||||
min-height: 3rem;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
color: var(--ax-text-default);
|
||||
border-radius: var(--ax-border-radius-small);
|
||||
border-radius: var(--ax-border-radius-medium);
|
||||
min-width: fit-content;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--ax-bg-accent-moderate-hoverA);
|
||||
@@ -42,12 +42,23 @@
|
||||
&:focus-visible {
|
||||
outline: 2px solid var(--ax-border-focus);
|
||||
outline-offset: 2px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&[aria-checked="true"] {
|
||||
&[data-selected="true"] {
|
||||
background-color: var(--ax-bg-accent-strong-pressed);
|
||||
color: var(--ax-text-accent-contrast);
|
||||
}
|
||||
|
||||
&:not([data-selected="true"], :first-child, &[data-selected="true"] + &)::before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 1px;
|
||||
height: 50%;
|
||||
background-color: var(--ax-border-subtleA);
|
||||
left: -1px;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
.navds-toggle-group__button-inner {
|
||||
@@ -70,7 +81,7 @@
|
||||
background-color: var(--ax-bg-neutral-moderate-hoverA);
|
||||
}
|
||||
|
||||
&[aria-checked="true"] {
|
||||
&[data-selected="true"] {
|
||||
background-color: var(--ax-bg-neutral-strong-pressed);
|
||||
color: var(--ax-text-neutral-contrast);
|
||||
}
|
||||
@@ -80,7 +91,7 @@
|
||||
.navds-toggle-group--small {
|
||||
& .navds-toggle-group__button {
|
||||
padding: var(--ax-spacing-05) var(--ax-spacing-3);
|
||||
min-height: 1.5rem;
|
||||
min-height: 2rem;
|
||||
}
|
||||
|
||||
& .navds-toggle-group__button-inner > svg {
|
||||
@@ -94,14 +105,13 @@
|
||||
border: 2px solid transparent;
|
||||
}
|
||||
|
||||
.navds-toggle-group__button[aria-checked="true"]:hover,
|
||||
.navds-toggle-group__button:hover {
|
||||
background-color: highlighttext;
|
||||
color: highlight;
|
||||
outline: 1px solid highlight;
|
||||
}
|
||||
|
||||
.navds-toggle-group__button[aria-checked="true"] {
|
||||
.navds-toggle-group__button[data-selected="true"] {
|
||||
background-color: selecteditem;
|
||||
color: selecteditemtext;
|
||||
forced-color-adjust: none;
|
||||
|
||||
@@ -204,6 +204,18 @@
|
||||
|
||||
.navds-error-message {
|
||||
color: var(--ax-text-danger);
|
||||
|
||||
&.navds-error-message--show-icon {
|
||||
display: flex;
|
||||
gap: var(--ax-spacing-1);
|
||||
|
||||
& svg {
|
||||
margin-top: 0.15em;
|
||||
flex: 0 0 auto;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------- Utilities ------------------------------- */
|
||||
|
||||
@@ -17,19 +17,6 @@
|
||||
color: var(--ac-form-description, var(--__ac-form-description, var(--a-text-subtle)));
|
||||
}
|
||||
|
||||
.navds-form-field .navds-error-message,
|
||||
.navds-fieldset .navds-error-message,
|
||||
.navds-file-item .navds-error-message {
|
||||
display: flex;
|
||||
gap: var(--a-spacing-2);
|
||||
}
|
||||
|
||||
.navds-form-field .navds-error-message::before,
|
||||
.navds-fieldset .navds-error-message::before,
|
||||
.navds-file-item .navds-error-message::before {
|
||||
content: "•";
|
||||
}
|
||||
|
||||
.navds-form-field--disabled {
|
||||
opacity: 0.3;
|
||||
cursor: not-allowed;
|
||||
|
||||
@@ -73,11 +73,15 @@
|
||||
/**
|
||||
Error handling
|
||||
*/
|
||||
.navds-select--error > * select:not(:hover, :focus, :disabled) {
|
||||
.navds-select--error > * .navds-select__input:not(:hover, :disabled) {
|
||||
box-shadow: 0 0 0 1px var(--ac-select-error-border, var(--a-surface-danger));
|
||||
border-color: var(--ac-select-error-border, var(--a-surface-danger));
|
||||
}
|
||||
|
||||
.navds-select--error .navds-select__input:focus {
|
||||
box-shadow: var(--a-shadow-focus);
|
||||
}
|
||||
|
||||
/**
|
||||
Disabled
|
||||
*/
|
||||
|
||||
@@ -72,12 +72,15 @@
|
||||
.navds-switch__track {
|
||||
width: 2.75rem;
|
||||
height: 1.5rem;
|
||||
background-color: var(--ac-switch-bg, var(--a-surface-neutral));
|
||||
background-color: var(--ac-switch-bg, var(--a-surface-default));
|
||||
border: 2px solid var(--a-border-default);
|
||||
position: absolute;
|
||||
top: var(--a-spacing-3);
|
||||
left: 0;
|
||||
border-radius: var(--a-border-radius-full);
|
||||
transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-property: background-color, border-color;
|
||||
transition-duration: 100ms;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.navds-switch--small > .navds-switch__track {
|
||||
@@ -92,18 +95,20 @@
|
||||
|
||||
.navds-switch__input:checked ~ .navds-switch__track {
|
||||
background-color: var(--ac-switch-checked-bg, var(--a-surface-action-selected));
|
||||
border-color: var(--ac-switch-checked-bg, var(--a-surface-action-selected));
|
||||
}
|
||||
|
||||
.navds-switch__input:hover ~ .navds-switch__track {
|
||||
background-color: var(--ac-switch-hover-bg, var(--a-surface-neutral-hover));
|
||||
background-color: var(--ac-switch-hover-bg, var(--a-surface-subtle));
|
||||
}
|
||||
|
||||
.navds-switch__input:hover:checked ~ .navds-switch__track {
|
||||
.navds-switch__input:hover:checked:not(:disabled) ~ .navds-switch__track {
|
||||
background-color: var(--ac-switch-checked-hover-bg, var(--a-surface-action-selected-hover));
|
||||
border-color: var(--ac-switch-checked-hover-bg, var(--a-surface-action-selected-hover));
|
||||
}
|
||||
|
||||
.navds-switch__input:disabled ~ .navds-switch__track {
|
||||
background-color: var(--ac-switch-bg, var(--a-surface-neutral));
|
||||
background-color: var(--ac-switch-bg, var(--a-surface-default));
|
||||
}
|
||||
|
||||
.navds-switch__input:checked:disabled ~ .navds-switch__track {
|
||||
@@ -129,15 +134,15 @@
|
||||
|
||||
/* Thumb */
|
||||
.navds-switch__thumb {
|
||||
background-color: var(--ac-switch-thumb-bg, var(--a-surface-default));
|
||||
background-color: var(--ac-switch-thumb-bg, var(--a-surface-neutral));
|
||||
color: var(--ac-switch-thumb-icon, var(--a-icon-subtle));
|
||||
border-radius: var(--a-border-radius-full);
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
width: 1.125rem;
|
||||
height: 1.125rem;
|
||||
position: absolute;
|
||||
transform: translateX(0);
|
||||
left: var(--a-spacing-05);
|
||||
top: var(--a-spacing-05);
|
||||
left: 0.0625rem;
|
||||
top: 0.0625rem;
|
||||
transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -147,6 +152,11 @@
|
||||
.navds-switch__input:checked ~ .navds-switch__track > .navds-switch__thumb {
|
||||
transform: translateX(1.25rem);
|
||||
color: var(--ac-switch-thumb-icon-checked, var(--a-icon-action-selected));
|
||||
background-color: var(--a-surface-default);
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.navds-switch__input:checked ~ .navds-switch__track .navds-switch__checkmark {
|
||||
@@ -195,6 +205,7 @@
|
||||
.navds-switch--readonly > .navds-switch__input:checked ~ .navds-switch__track,
|
||||
.navds-switch--readonly > .navds-switch__input:checked:hover ~ .navds-switch__track {
|
||||
background-color: var(--a-surface-neutral-moderate);
|
||||
border-color: var(--a-border-subtle);
|
||||
}
|
||||
|
||||
.navds-switch--readonly > .navds-switch__label-wrapper,
|
||||
@@ -212,12 +223,12 @@
|
||||
}
|
||||
|
||||
.navds-switch--readonly .navds-switch__thumb {
|
||||
background-color: var(--a-surface-subtle);
|
||||
box-shadow: 0 0 0 2px var(--a-border-default);
|
||||
background-color: var(--a-surface-neutral);
|
||||
}
|
||||
|
||||
.navds-switch--readonly > .navds-switch__input:checked ~ .navds-switch__track > .navds-switch__thumb {
|
||||
color: var(--a-icon-subtle);
|
||||
color: var(--a-icon-on-neutral);
|
||||
background-color: var(--a-surface-neutral);
|
||||
}
|
||||
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
@@ -237,7 +248,9 @@
|
||||
}
|
||||
|
||||
.navds-switch__thumb,
|
||||
.navds-switch--readonly .navds-switch__thumb {
|
||||
.navds-switch--readonly .navds-switch__thumb,
|
||||
.navds-switch__input:checked ~ .navds-switch__track > .navds-switch__thumb,
|
||||
.navds-switch--readonly .navds-switch__input:checked ~ .navds-switch__track > .navds-switch__thumb {
|
||||
background-color: fieldtext;
|
||||
}
|
||||
|
||||
@@ -246,11 +259,8 @@
|
||||
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--disabled:not(.navds-switch--loading) .navds-switch__input:checked ~ .navds-switch__track > .navds-switch__thumb {
|
||||
background-color: graytext;
|
||||
}
|
||||
|
||||
.navds-switch__input:focus-visible ~ .navds-switch__track {
|
||||
@@ -264,6 +274,7 @@
|
||||
|
||||
.navds-switch--disabled:not(.navds-switch--loading) .navds-switch__thumb {
|
||||
background-color: graytext;
|
||||
border-color: graytext;
|
||||
}
|
||||
|
||||
.navds-switch--disabled:not(.navds-switch--loading) .navds-switch__track {
|
||||
|
||||
@@ -111,16 +111,13 @@
|
||||
/**
|
||||
Error handling
|
||||
*/
|
||||
.navds-textarea--error .navds-textarea__input:not(:hover, :focus-visible, :disabled) {
|
||||
.navds-textarea--error .navds-textarea__input:not(:hover, :disabled) {
|
||||
box-shadow: 0 0 0 1px var(--ac-textarea-error-border, var(--__ac-textarea-error-border, var(--a-border-danger)));
|
||||
border-color: var(--ac-textarea-error-border, var(--__ac-textarea-error-border, var(--a-border-danger)));
|
||||
}
|
||||
|
||||
@supports not selector(:focus-visible) {
|
||||
.navds-textarea--error .navds-textarea__input:not(:hover, :focus, :disabled) {
|
||||
box-shadow: 0 0 0 1px var(--ac-textarea-error-border, var(--__ac-textarea-error-border, var(--a-border-danger)));
|
||||
border-color: var(--ac-textarea-error-border, var(--__ac-textarea-error-border, var(--a-border-danger)));
|
||||
}
|
||||
.navds-textarea--error .navds-textarea__input:focus-visible {
|
||||
box-shadow: var(--a-shadow-focus);
|
||||
}
|
||||
|
||||
.navds-textarea__input:disabled {
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.navds-alert:not(.navds-alert--inline) .navds-link,
|
||||
.navds-alert:not(.navds-alert--inline) .navds-link:not(:active, :focus-visible),
|
||||
.navds-confirmation-panel .navds-link {
|
||||
color: var(--a-text-default);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-css",
|
||||
"version": "7.8.1",
|
||||
"version": "7.9.1",
|
||||
"description": "CSS for Nav Designsystem",
|
||||
"author": "Aksel | Nav designsystem team",
|
||||
"keywords": [
|
||||
@@ -28,7 +28,7 @@
|
||||
"test": "yarn build && vitest run"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@navikt/ds-tokens": "^7.8.1",
|
||||
"@navikt/ds-tokens": "^7.9.1",
|
||||
"@types/clean-css": "4.2.11",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"browserslist": "^4.24.2",
|
||||
@@ -44,7 +44,7 @@
|
||||
"postcss-combine-duplicated-selectors": "10.0.3",
|
||||
"postcss-import": "^14.1.0",
|
||||
"tsx": "^4.7.1",
|
||||
"vitest": "^1.2.2"
|
||||
"vitest": "^2.1.8"
|
||||
},
|
||||
"browserslist": [
|
||||
">0.2%",
|
||||
|
||||
@@ -411,11 +411,11 @@
|
||||
},
|
||||
"switch": {
|
||||
"--ac-switch-action": "--a-surface-action-selected",
|
||||
"--ac-switch-bg": "--a-surface-neutral",
|
||||
"--ac-switch-bg": "--a-surface-default",
|
||||
"--ac-switch-checked-bg": "--a-surface-action-selected",
|
||||
"--ac-switch-hover-bg": "--a-surface-neutral-hover",
|
||||
"--ac-switch-hover-bg": "--a-surface-subtle",
|
||||
"--ac-switch-checked-hover-bg": "--a-surface-action-selected-hover",
|
||||
"--ac-switch-thumb-bg": "--a-surface-default",
|
||||
"--ac-switch-thumb-bg": "--a-surface-neutral",
|
||||
"--ac-switch-thumb-icon": "--a-icon-subtle",
|
||||
"--ac-switch-thumb-icon-checked": "--a-icon-action-selected"
|
||||
},
|
||||
|
||||
@@ -216,6 +216,18 @@
|
||||
color: var(--ac-typo-error-text, var(--__ac-typo-error-text, var(--a-text-danger)));
|
||||
}
|
||||
|
||||
.navds-error-message.navds-error-message--show-icon {
|
||||
display: flex;
|
||||
gap: var(--a-spacing-1);
|
||||
}
|
||||
|
||||
.navds-error-message.navds-error-message--show-icon svg {
|
||||
margin-top: 0.15em;
|
||||
flex: 0 0 auto;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
.navds-typo--truncate {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
scripts/*.backup
|
||||
@@ -1,5 +1,32 @@
|
||||
# @navikt/ds-react
|
||||
|
||||
## 7.9.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@7.9.1
|
||||
- @navikt/aksel-icons@7.9.1
|
||||
|
||||
## 7.9.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- ErrorSummary: :sparkles: new prop to prefix error with a warning icon. ([#3445](https://github.com/navikt/aksel/pull/3445))
|
||||
All form components: replace dot with warning icon in error message.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Button: Fix edge-case where setting "loading={true}" in a Modal caused the button to get 0 width and not show spinner ([#3252](https://github.com/navikt/aksel/pull/3252))
|
||||
|
||||
- Switch: Update switch to better reflect unchecked state. ([#3468](https://github.com/navikt/aksel/pull/3468))
|
||||
|
||||
- Textarea: resize immediately upon receiving resize event (eg. inside modal opening). ([#3463](https://github.com/navikt/aksel/pull/3463))
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@7.9.0
|
||||
- @navikt/aksel-icons@7.9.0
|
||||
|
||||
## 7.8.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Aksel React-components
|
||||
|
||||
React-components for NAVs designsystem.
|
||||
React-components for Nav's design system.
|
||||
|
||||
- Uses styling defined in `@navikt/ds-css`
|
||||
- All components implemented with React.forwardRef!
|
||||
- All components are implemented with React.forwardRef!
|
||||
- Most components extend native html-elements.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-react",
|
||||
"version": "7.8.1",
|
||||
"version": "7.9.1",
|
||||
"description": "React components from the Norwegian Labour and Welfare Administration.",
|
||||
"author": "Aksel, a team part of the Norwegian Labour and Welfare Administration.",
|
||||
"license": "MIT",
|
||||
@@ -603,10 +603,11 @@
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"scripts": {
|
||||
"docgen": "yarn tsx ../../../scripts/docgen.ts",
|
||||
"docgen": "tsx ../../../scripts/docgen.ts",
|
||||
"i18n-jsdoc": "tsx ./scripts/addJsdocToLocales.ts",
|
||||
"write-packagejson": "echo '{\"type\": \"module\"}' > esm/package.json",
|
||||
"clean": "rimraf cjs esm",
|
||||
"build": "concurrently \"tsc -p tsconfig.build.json\" \"tsc -p tsconfig.esm.json && tsc-alias -p tsconfig.esm.json && yarn write-packagejson\" ",
|
||||
"build": "yarn i18n-jsdoc && concurrently \"tsc -p tsconfig.build.json\" \"tsc -p tsconfig.esm.json && tsc-alias -p tsconfig.esm.json && yarn write-packagejson\" && yarn i18n-jsdoc --cleanup",
|
||||
"watch": "tsc --watch -p tsconfig.esm.json",
|
||||
"test": "TZ=UTC vitest run -c tests/vitest.config.ts",
|
||||
"test:watch": "vitest watch"
|
||||
@@ -614,20 +615,23 @@
|
||||
"dependencies": {
|
||||
"@floating-ui/react": "0.25.4",
|
||||
"@floating-ui/react-dom": "^2.0.9",
|
||||
"@navikt/aksel-icons": "^7.8.1",
|
||||
"@navikt/ds-tokens": "^7.8.1",
|
||||
"@navikt/aksel-icons": "^7.9.1",
|
||||
"@navikt/ds-tokens": "^7.9.1",
|
||||
"clsx": "^2.1.0",
|
||||
"date-fns": "^3.0.0",
|
||||
"react-day-picker": "8.10.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/dom": "9.3.4",
|
||||
"@testing-library/jest-dom": "^5.16.0",
|
||||
"@testing-library/react": "^15.0.7",
|
||||
"@testing-library/user-event": "^14.2.0",
|
||||
"@testing-library/dom": "10.4.0",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.1.0",
|
||||
"@testing-library/user-event": "^14.5.2",
|
||||
"@types/jscodeshift": "^0.11.11",
|
||||
"aksel": "workspace:^",
|
||||
"concurrently": "9.0.1",
|
||||
"fast-glob": "3.2.11",
|
||||
"jsdom": "24.0.0",
|
||||
"jscodeshift": "^0.15.1",
|
||||
"jsdom": "25.0.1",
|
||||
"react-dom": "^18.0.0",
|
||||
"react-router-dom": "^6.3.0",
|
||||
"rimraf": "6.0.1",
|
||||
@@ -635,7 +639,7 @@
|
||||
"tsc-alias": "1.8.8",
|
||||
"tsx": "^4.19.1",
|
||||
"typescript": "5.5.4",
|
||||
"vitest": "^1.2.2"
|
||||
"vitest": "^2.1.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": ">=17.0.30",
|
||||
@@ -645,5 +649,6 @@
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"_comment": "The 'aksel' dependency tells yarn to install the root deps when installing deps for this package. Helps make it possible to contribute without access to GPR."
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import fs from "fs";
|
||||
import jscodeshift from "jscodeshift";
|
||||
|
||||
const j = jscodeshift.withParser("ts");
|
||||
const file = "src/util/i18n/locales/nb.ts";
|
||||
const backup = "scripts/nb.backup";
|
||||
|
||||
function addJsdoc() {
|
||||
if (fs.existsSync(backup)) {
|
||||
// If last build failed, we need to restore the file so that we don't create duplicate JSDoc
|
||||
console.info(
|
||||
`WARNING: Restoring backup of ${file} - Uncommitted changes will be lost!`,
|
||||
);
|
||||
fs.copyFileSync(backup, file);
|
||||
}
|
||||
|
||||
fs.copyFileSync(file, backup); // Create a copy of the original file that we can restore afterwards
|
||||
|
||||
const code = fs.readFileSync(file, "utf-8");
|
||||
const parsedCode = j(code);
|
||||
const defaultExport = parsedCode.find(j.ExportDefaultDeclaration);
|
||||
const keys = defaultExport.find(j.ObjectProperty);
|
||||
keys
|
||||
.filter((key) => key.value.value.type === "StringLiteral")
|
||||
.forEach((key) => {
|
||||
// @ts-expect-error It works, doesn't it?
|
||||
const value = key.value.value.value;
|
||||
const foundCommentBlock = key.value.comments?.find(
|
||||
(comment) => comment.type === "CommentBlock",
|
||||
);
|
||||
if (foundCommentBlock) {
|
||||
foundCommentBlock.value = `${foundCommentBlock.value}\n* @default "${value}" `;
|
||||
} else {
|
||||
key.value.comments = [
|
||||
...(key.value.comments || []),
|
||||
{
|
||||
type: "CommentBlock",
|
||||
value: `* @default "${value}" `,
|
||||
leading: true,
|
||||
trailing: false,
|
||||
},
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
const modifiedCode = parsedCode.toSource();
|
||||
fs.writeFileSync(file, modifiedCode);
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
fs.copyFileSync(backup, file);
|
||||
fs.unlinkSync(backup);
|
||||
}
|
||||
|
||||
if (process.argv.includes("--cleanup")) {
|
||||
cleanup();
|
||||
} else {
|
||||
addJsdoc();
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef, useContext } from "react";
|
||||
import { UNSAFE_useAkselTheme } from "../provider";
|
||||
import { useThemeInternal } from "../theme/Theme";
|
||||
import { BodyLong } from "../typography";
|
||||
import { AccordionItemContext } from "./AccordionItem";
|
||||
|
||||
@@ -16,7 +16,7 @@ const AccordionContent = forwardRef<HTMLDivElement, AccordionContentProps>(
|
||||
({ children, className, ...rest }, ref) => {
|
||||
const context = useContext(AccordionItemContext);
|
||||
|
||||
const themeContext = UNSAFE_useAkselTheme(false);
|
||||
const themeContext = useThemeInternal(false);
|
||||
|
||||
if (context === null) {
|
||||
console.error(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef, useContext } from "react";
|
||||
import { ChevronDownIcon } from "@navikt/aksel-icons";
|
||||
import { UNSAFE_useAkselTheme } from "../provider";
|
||||
import { useThemeInternal } from "../theme/Theme";
|
||||
import { Heading } from "../typography";
|
||||
import { composeEventHandlers } from "../util/composeEventHandlers";
|
||||
import { AccordionContext } from "./AccordionContext";
|
||||
@@ -20,7 +20,7 @@ const AccordionHeader = forwardRef<HTMLButtonElement, AccordionHeaderProps>(
|
||||
const itemContext = useContext(AccordionItemContext);
|
||||
const accordionContext = useContext(AccordionContext);
|
||||
|
||||
const themeContext = UNSAFE_useAkselTheme(false);
|
||||
const themeContext = useThemeInternal(false);
|
||||
|
||||
if (itemContext === null) {
|
||||
console.error(
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
} from "@navikt/aksel-icons";
|
||||
import { Button } from "../button";
|
||||
import { BodyLong } from "../typography";
|
||||
import { useI18n } from "../util/i18n/i18n.context";
|
||||
import { useI18n } from "../util/i18n/i18n.hooks";
|
||||
|
||||
export interface AlertProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
/**
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef, useRef, useState } from "react";
|
||||
import React, { forwardRef } from "react";
|
||||
import { Loader } from "../loader";
|
||||
import { Label } from "../typography";
|
||||
import { omit } from "../util";
|
||||
import { composeEventHandlers } from "../util/composeEventHandlers";
|
||||
import { useClientLayoutEffect } from "../util/hooks";
|
||||
import { useMergeRefs } from "../util/hooks/useMergeRefs";
|
||||
import { OverridableComponent } from "../util/types";
|
||||
|
||||
export interface ButtonProps
|
||||
@@ -74,37 +72,18 @@ export const Button: OverridableComponent<ButtonProps, HTMLButtonElement> =
|
||||
size = "medium",
|
||||
loading = false,
|
||||
disabled,
|
||||
style,
|
||||
icon,
|
||||
iconPosition = "left",
|
||||
onKeyUp,
|
||||
...rest
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const buttonRef = useRef<HTMLButtonElement | null>(null);
|
||||
const [widthOverride, setWidthOverride] = useState<number>();
|
||||
|
||||
const mergedRef = useMergeRefs(buttonRef, ref);
|
||||
|
||||
useClientLayoutEffect(() => {
|
||||
if (loading) {
|
||||
const requestID = window.requestAnimationFrame(() => {
|
||||
setWidthOverride(
|
||||
buttonRef?.current?.getBoundingClientRect()?.width,
|
||||
);
|
||||
});
|
||||
return () => {
|
||||
setWidthOverride(undefined);
|
||||
cancelAnimationFrame(requestID);
|
||||
};
|
||||
}
|
||||
}, [loading, children]);
|
||||
|
||||
const filterProps: React.ButtonHTMLAttributes<HTMLButtonElement> =
|
||||
disabled ?? widthOverride ? omit(rest, ["href"]) : rest;
|
||||
disabled || loading ? omit(rest, ["href"]) : rest;
|
||||
|
||||
const handleKeyUp = (e: React.KeyboardEvent<HTMLButtonElement>) => {
|
||||
if (e.key === " " && !disabled && !widthOverride) {
|
||||
if (e.key === " " && !disabled && !loading) {
|
||||
e.currentTarget.click();
|
||||
}
|
||||
};
|
||||
@@ -113,41 +92,32 @@ export const Button: OverridableComponent<ButtonProps, HTMLButtonElement> =
|
||||
<Component
|
||||
{...(Component !== "button" ? { role: "button" } : {})}
|
||||
{...filterProps}
|
||||
ref={mergedRef}
|
||||
onKeyUp={composeEventHandlers(filterProps.onKeyUp, handleKeyUp)}
|
||||
ref={ref}
|
||||
onKeyUp={composeEventHandlers(onKeyUp, handleKeyUp)}
|
||||
className={cl(
|
||||
className,
|
||||
"navds-button",
|
||||
`navds-button--${variant}`,
|
||||
`navds-button--${size}`,
|
||||
{
|
||||
"navds-button--loading": widthOverride,
|
||||
"navds-button--loading": loading,
|
||||
"navds-button--icon-only": !!icon && !children,
|
||||
"navds-button--disabled": disabled ?? widthOverride,
|
||||
"navds-button--disabled": disabled ?? loading,
|
||||
},
|
||||
)}
|
||||
style={{
|
||||
...style,
|
||||
width: widthOverride,
|
||||
}}
|
||||
disabled={disabled ?? widthOverride ? true : undefined}
|
||||
disabled={disabled ?? loading ? true : undefined}
|
||||
>
|
||||
{widthOverride ? (
|
||||
<Loader size={size} />
|
||||
) : (
|
||||
<>
|
||||
{icon && iconPosition === "left" && (
|
||||
<span className="navds-button__icon">{icon}</span>
|
||||
)}
|
||||
{children && (
|
||||
<Label as="span" size={size === "medium" ? "medium" : "small"}>
|
||||
{children}
|
||||
</Label>
|
||||
)}
|
||||
{icon && iconPosition === "right" && (
|
||||
<span className="navds-button__icon">{icon}</span>
|
||||
)}
|
||||
</>
|
||||
{icon && iconPosition === "left" && (
|
||||
<span className="navds-button__icon">{icon}</span>
|
||||
)}
|
||||
{loading && <Loader size={size} />}
|
||||
{children && (
|
||||
<Label as="span" size={size === "medium" ? "medium" : "small"}>
|
||||
{children}
|
||||
</Label>
|
||||
)}
|
||||
{icon && iconPosition === "right" && (
|
||||
<span className="navds-button__icon">{icon}</span>
|
||||
)}
|
||||
</Component>
|
||||
);
|
||||
|
||||
@@ -2,6 +2,8 @@ import { StoryObj } from "@storybook/react";
|
||||
import React from "react";
|
||||
import { StarIcon as BaseStarIcon } from "@navikt/aksel-icons";
|
||||
import { HStack, VStack } from "../layout/stack";
|
||||
import { Modal } from "../modal";
|
||||
import { BodyLong } from "../typography";
|
||||
import { Button } from "./index";
|
||||
|
||||
export default {
|
||||
@@ -154,6 +156,51 @@ export const DisabledAsLink: Story = {
|
||||
render: () => <ButtonGrid disabled href="#" as="a" />,
|
||||
};
|
||||
|
||||
export const InsideModal: Story = {
|
||||
render: () => {
|
||||
const ref = React.useRef<HTMLDialogElement>(null);
|
||||
|
||||
return (
|
||||
<div className="py-16">
|
||||
<Button onClick={() => ref.current?.showModal()}>Åpne modal</Button>
|
||||
|
||||
<Modal ref={ref} header={{ heading: "Overskrift" }}>
|
||||
<Modal.Body>
|
||||
<BodyLong>
|
||||
Culpa aliquip ut cupidatat laborum minim quis ex in aliqua. Qui
|
||||
incididunt dolor do ad ut. Incididunt eiusmod nostrud deserunt
|
||||
duis laborum. Proident aute culpa qui nostrud velit adipisicing
|
||||
minim. Consequat aliqua aute dolor do sit Lorem nisi mollit velit.
|
||||
Aliqua exercitation non minim minim pariatur sunt laborum ipsum.
|
||||
Exercitation nostrud est laborum magna non non aliqua qui esse.
|
||||
</BodyLong>
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
<Button loading type="button" onClick={() => ref.current?.close()}>
|
||||
Primær
|
||||
</Button>
|
||||
<Button
|
||||
loading
|
||||
type="button"
|
||||
variant="secondary"
|
||||
onClick={() => ref.current?.close()}
|
||||
>
|
||||
Sekundær
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="tertiary"
|
||||
onClick={() => ref.current?.close()}
|
||||
>
|
||||
Tertiær
|
||||
</Button>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export const Chromatic: Story = {
|
||||
render: () => (
|
||||
<VStack gap="6" align="center">
|
||||
|
||||
@@ -2,7 +2,7 @@ import cl from "clsx";
|
||||
import React, { forwardRef } from "react";
|
||||
import { XMarkIcon } from "@navikt/aksel-icons";
|
||||
import { composeEventHandlers } from "../util/composeEventHandlers";
|
||||
import { useI18n } from "../util/i18n/i18n.context";
|
||||
import { useI18n } from "../util/i18n/i18n.hooks";
|
||||
|
||||
export interface ChipsRemovableProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
|
||||
@@ -10,7 +10,7 @@ import { CheckmarkIcon, FilesIcon } from "@navikt/aksel-icons";
|
||||
import { Label } from "../typography";
|
||||
import { composeEventHandlers } from "../util/composeEventHandlers";
|
||||
import copy from "../util/copy";
|
||||
import { useI18n } from "../util/i18n/i18n.context";
|
||||
import { useI18n } from "../util/i18n/i18n.hooks";
|
||||
|
||||
export interface CopyButtonProps
|
||||
extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "children"> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createContext } from "../../util/create-context";
|
||||
import { TFunction } from "../../util/i18n/i18n.context";
|
||||
import { TFunction } from "../../util/i18n/i18n.types";
|
||||
|
||||
interface DateTranslationContextProps {
|
||||
translate: TFunction<"DatePicker">;
|
||||
|
||||
@@ -5,7 +5,7 @@ import { DateRange, DayPicker, isMatch } from "react-day-picker";
|
||||
import { omit } from "../../util";
|
||||
import { useId } from "../../util/hooks";
|
||||
import { useMergeRefs } from "../../util/hooks/useMergeRefs";
|
||||
import { useDateLocale, useI18n } from "../../util/i18n/i18n.context";
|
||||
import { useDateLocale, useI18n } from "../../util/i18n/i18n.hooks";
|
||||
import { DateInputContext, DateTranslationContextProvider } from "../context";
|
||||
import { DatePickerInput } from "../parts/DateInput";
|
||||
import { DateWrapper } from "../parts/DateWrapper";
|
||||
|
||||
@@ -3,7 +3,7 @@ import { isWeekend } from "date-fns";
|
||||
import React, { forwardRef } from "react";
|
||||
import { DateRange, DayPicker, isMatch } from "react-day-picker";
|
||||
import { omit } from "../../util";
|
||||
import { useDateLocale, useI18n } from "../../util/i18n/i18n.context";
|
||||
import { useDateLocale, useI18n } from "../../util/i18n/i18n.hooks";
|
||||
import { DateTranslationContextProvider } from "../context";
|
||||
import { getLocaleFromString, getTranslations } from "../utils";
|
||||
import Caption from "./parts/Caption";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { act, render, screen } from "@testing-library/react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import React from "react";
|
||||
import { describe, test } from "vitest";
|
||||
@@ -23,9 +23,6 @@ describe("Render datepicker", () => {
|
||||
test("Should not crash when e.target is window", async () => {
|
||||
render(<App />);
|
||||
|
||||
// eslint-disable-next-line testing-library/no-unnecessary-act -- https://kentcdodds.com/blog/fix-the-not-wrapped-in-act-warning
|
||||
await act(async () => {
|
||||
await userEvent.click(screen.getByText("Velg dato"));
|
||||
});
|
||||
await userEvent.click(screen.getByText("Velg dato"));
|
||||
});
|
||||
});
|
||||
@@ -2,7 +2,7 @@
|
||||
import React from "react";
|
||||
import { Button as RDPButton, useDayPicker } from "react-day-picker";
|
||||
import { Button } from "../../../button";
|
||||
import { UNSAFE_useAkselTheme } from "../../../provider";
|
||||
import { useThemeInternal } from "../../../theme/Theme";
|
||||
import { Detail } from "../../../typography";
|
||||
import { useDateTranslationContext } from "../../context";
|
||||
|
||||
@@ -21,7 +21,7 @@ function WeekNumber({
|
||||
dates,
|
||||
}: WeekNumberProps): JSX.Element {
|
||||
const { onWeekNumberClick, styles, classNames } = useDayPicker();
|
||||
const themeContext = UNSAFE_useAkselTheme(false);
|
||||
const themeContext = useThemeInternal(false);
|
||||
const translate = useDateTranslationContext().translate;
|
||||
|
||||
if (!onWeekNumberClick) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { differenceInCalendarDays, isWeekend } from "date-fns";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { DayClickEventHandler, isMatch } from "react-day-picker";
|
||||
import { useDateLocale } from "../../util/i18n/i18n.context";
|
||||
import { useDateLocale } from "../../util/i18n/i18n.hooks";
|
||||
import { DatePickerProps } from "../datepicker/DatePicker";
|
||||
import { DateInputProps } from "../parts/DateInput";
|
||||
import {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useCallback, useMemo, useState } from "react";
|
||||
import { useDateLocale } from "../../util/i18n/i18n.context";
|
||||
import { useDateLocale } from "../../util/i18n/i18n.hooks";
|
||||
import { MonthPickerProps } from "../monthpicker/types";
|
||||
import { DateInputProps } from "../parts/DateInput";
|
||||
import {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
/* eslint-disable testing-library/no-unnecessary-act -- https://kentcdodds.com/blog/fix-the-not-wrapped-in-act-warning */
|
||||
import { act, render, screen } from "@testing-library/react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import React from "react";
|
||||
import { describe, expect, test } from "vitest";
|
||||
@@ -29,10 +28,8 @@ describe("Writing in input sets correct values", () => {
|
||||
|
||||
const fraInput = screen.getByRole("textbox", { name: "Fra" });
|
||||
const tilInput = screen.getByRole("textbox", { name: "Til" });
|
||||
await act(async () => {
|
||||
await userEvent.type(fraInput, "03.08.2022");
|
||||
await userEvent.type(tilInput, "03.08.2022");
|
||||
});
|
||||
await userEvent.type(fraInput, "03.08.2022");
|
||||
await userEvent.type(tilInput, "03.08.2022");
|
||||
const res = screen.getByTitle("res");
|
||||
expect(res.innerHTML).toEqual(
|
||||
JSON.stringify({
|
||||
@@ -47,10 +44,8 @@ describe("Writing in input sets correct values", () => {
|
||||
|
||||
const fraInput = screen.getByRole("textbox", { name: "Fra" });
|
||||
const tilInput = screen.getByRole("textbox", { name: "Til" });
|
||||
await act(async () => {
|
||||
await userEvent.type(fraInput, "03.08.2022");
|
||||
await userEvent.type(tilInput, "02.08.2022");
|
||||
});
|
||||
await userEvent.type(fraInput, "03.08.2022");
|
||||
await userEvent.type(tilInput, "02.08.2022");
|
||||
const res = screen.getByTitle("res");
|
||||
expect(res.innerHTML).toEqual(
|
||||
JSON.stringify({
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
} from "date-fns";
|
||||
import React, { useState } from "react";
|
||||
import { DateRange, isMatch } from "react-day-picker";
|
||||
import { useDateLocale } from "../../util/i18n/i18n.context";
|
||||
import { useDateLocale } from "../../util/i18n/i18n.hooks";
|
||||
import { DatePickerProps } from "../datepicker/DatePicker";
|
||||
import { DateInputProps } from "../parts/DateInput";
|
||||
import {
|
||||
|
||||
@@ -3,7 +3,7 @@ import React, { forwardRef, useState } from "react";
|
||||
import { DayPickerProvider } from "react-day-picker";
|
||||
import { useId } from "../../util/hooks";
|
||||
import { useMergeRefs } from "../../util/hooks/useMergeRefs";
|
||||
import { useDateLocale, useI18n } from "../../util/i18n/i18n.context";
|
||||
import { useDateLocale, useI18n } from "../../util/i18n/i18n.hooks";
|
||||
import {
|
||||
DateInputContext,
|
||||
DateTranslationContextProvider,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef, useState } from "react";
|
||||
import { DayPickerProvider } from "react-day-picker";
|
||||
import { useDateLocale, useI18n } from "../../util/i18n/i18n.context";
|
||||
import { useDateLocale, useI18n } from "../../util/i18n/i18n.hooks";
|
||||
import {
|
||||
DateTranslationContextProvider,
|
||||
SharedMonthProvider,
|
||||
|
||||
@@ -150,7 +150,11 @@ const DateInput = forwardRef<HTMLInputElement, DateInputProps>((props, ref) => {
|
||||
aria-relevant="additions removals"
|
||||
aria-live="polite"
|
||||
>
|
||||
{showErrorMsg && <ErrorMessage size={size}>{props.error}</ErrorMessage>}
|
||||
{showErrorMsg && (
|
||||
<ErrorMessage size={size} showIcon>
|
||||
{props.error}
|
||||
</ErrorMessage>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -5,7 +5,8 @@ import { Modal } from "../../modal";
|
||||
import { useModalContext } from "../../modal/Modal.context";
|
||||
import { Popover } from "../../popover";
|
||||
import { useMedia } from "../../util/hooks";
|
||||
import { TFunction, useI18n } from "../../util/i18n/i18n.context";
|
||||
import { useI18n } from "../../util/i18n/i18n.hooks";
|
||||
import { TFunction } from "../../util/i18n/i18n.types";
|
||||
import { getGlobalTranslations } from "../utils";
|
||||
|
||||
const variantToLabel = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef, useContext } from "react";
|
||||
import { ChevronDownIcon } from "@navikt/aksel-icons";
|
||||
import { useI18n } from "../util/i18n/i18n.context";
|
||||
import { useI18n } from "../util/i18n/i18n.hooks";
|
||||
import { ExpansionCardContext } from "./context";
|
||||
|
||||
export interface ExpansionCardHeaderProps
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import { PadlockLockedFillIcon } from "@navikt/aksel-icons";
|
||||
import { useI18n } from "../util/i18n/i18n.context";
|
||||
import { useI18n } from "../util/i18n/i18n.hooks";
|
||||
|
||||
export const ReadOnlyIcon = () => (
|
||||
<PadlockLockedFillIcon
|
||||
|
||||
@@ -71,7 +71,11 @@ export const Combobox = forwardRef<
|
||||
aria-relevant="additions removals"
|
||||
aria-live="polite"
|
||||
>
|
||||
{showErrorMsg && <ErrorMessage size={size}>{error}</ErrorMessage>}
|
||||
{showErrorMsg && (
|
||||
<ErrorMessage size={size} showIcon>
|
||||
{error}
|
||||
</ErrorMessage>
|
||||
)}
|
||||
</div>
|
||||
</ComboboxWrapper>
|
||||
);
|
||||
|
||||
@@ -2,7 +2,7 @@ import cl from "clsx";
|
||||
import React from "react";
|
||||
import { PlusIcon } from "@navikt/aksel-icons";
|
||||
import { BodyShort, Label } from "../../../typography";
|
||||
import { useI18n } from "../../../util/i18n/i18n.context";
|
||||
import { useI18n } from "../../../util/i18n/i18n.hooks";
|
||||
import { useInputContext } from "../Input/Input.context";
|
||||
import { useSelectedOptionsContext } from "../SelectedOptions/selectedOptionsContext";
|
||||
import { isInList, toComboboxOption } from "../combobox-utils";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import { Loader } from "../../../loader";
|
||||
import { useI18n } from "../../../util/i18n/i18n.context";
|
||||
import { useI18n } from "../../../util/i18n/i18n.hooks";
|
||||
import { useInputContext } from "../Input/Input.context";
|
||||
import filteredOptionsUtil from "./filtered-options-util";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { useI18n } from "../../../util/i18n/i18n.context";
|
||||
import { useI18n } from "../../../util/i18n/i18n.hooks";
|
||||
import { useInputContext } from "../Input/Input.context";
|
||||
import { useSelectedOptionsContext } from "../SelectedOptions/selectedOptionsContext";
|
||||
import filteredOptionsUtil from "./filtered-options-util";
|
||||
|
||||
@@ -91,7 +91,11 @@ export const ConfirmationPanel = forwardRef<
|
||||
</Checkbox>
|
||||
</div>
|
||||
<div className="navds-form-field__error" id={errorId} role="alert">
|
||||
{showErrorMsg && <ErrorMessage size={size}>{props.error}</ErrorMessage>}
|
||||
{showErrorMsg && (
|
||||
<ErrorMessage size={size} showIcon>
|
||||
{props.error}
|
||||
</ErrorMessage>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -3,7 +3,7 @@ import React, { HTMLAttributes, forwardRef, useRef } from "react";
|
||||
import { BodyShort, Heading } from "../../typography";
|
||||
import { composeEventHandlers } from "../../util/composeEventHandlers";
|
||||
import { useMergeRefs } from "../../util/hooks";
|
||||
import { useI18n } from "../../util/i18n/i18n.context";
|
||||
import { useI18n } from "../../util/i18n/i18n.hooks";
|
||||
import ErrorSummaryItem from "./ErrorSummaryItem";
|
||||
|
||||
export interface ErrorSummaryProps
|
||||
|
||||
@@ -113,7 +113,9 @@ export const Fieldset = forwardRef<HTMLFieldSetElement, FieldsetProps>(
|
||||
className="navds-fieldset__error"
|
||||
>
|
||||
{showErrorMsg && (
|
||||
<ErrorMessage size={size}>{props.error}</ErrorMessage>
|
||||
<ErrorMessage size={size} showIcon>
|
||||
{props.error}
|
||||
</ErrorMessage>
|
||||
)}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Button } from "../../../../button";
|
||||
import { BodyShort, ErrorMessage, Label } from "../../../../typography";
|
||||
import { composeEventHandlers } from "../../../../util/composeEventHandlers";
|
||||
import { useId } from "../../../../util/hooks";
|
||||
import { useI18n } from "../../../../util/i18n/i18n.context";
|
||||
import { useI18n } from "../../../../util/i18n/i18n.hooks";
|
||||
import { omit } from "../../../../util/omit";
|
||||
import { useFormField } from "../../../useFormField";
|
||||
import { useFileUploadTranslation } from "../../FileUpload.context";
|
||||
@@ -177,7 +177,7 @@ const Dropzone = forwardRef<HTMLInputElement, FileUploadDropzoneProps>(
|
||||
aria-relevant="additions removals"
|
||||
aria-live="polite"
|
||||
>
|
||||
{showErrorMsg && <ErrorMessage>{error}</ErrorMessage>}
|
||||
{showErrorMsg && <ErrorMessage showIcon>{error}</ErrorMessage>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -3,7 +3,7 @@ import React, { MouseEvent, forwardRef } from "react";
|
||||
import { ExclamationmarkTriangleIcon } from "@navikt/aksel-icons";
|
||||
import { BodyShort } from "../../../../typography";
|
||||
import { OverridableComponent } from "../../../../util";
|
||||
import { useI18n } from "../../../../util/i18n/i18n.context";
|
||||
import { useI18n } from "../../../../util/i18n/i18n.hooks";
|
||||
import { ComponentTranslation } from "../../../../util/i18n/i18n.types";
|
||||
import { useFileUploadTranslation } from "../../FileUpload.context";
|
||||
import { FileItem } from "./Item.types";
|
||||
|
||||
@@ -6,7 +6,7 @@ import { HStack } from "../../layout/stack";
|
||||
import { ProgressBar } from "../../progress-bar";
|
||||
import { Stepper, StepperStepProps } from "../../stepper";
|
||||
import { BodyShort } from "../../typography";
|
||||
import { useI18n } from "../../util/i18n/i18n.context";
|
||||
import { useI18n } from "../../util/i18n/i18n.hooks";
|
||||
import { ComponentTranslation } from "../../util/i18n/i18n.types";
|
||||
|
||||
export interface FormProgressProps
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef } from "react";
|
||||
import { Link } from "../../link";
|
||||
import { useI18n } from "../../util/i18n/i18n.context";
|
||||
import { useI18n } from "../../util/i18n/i18n.hooks";
|
||||
import { OverridableComponent } from "../../util/types";
|
||||
|
||||
export interface FormSummaryEditProps
|
||||
|
||||
@@ -7,11 +7,11 @@ import React, {
|
||||
} from "react";
|
||||
import { MagnifyingGlassIcon, XMarkIcon } from "@navikt/aksel-icons";
|
||||
import { Button } from "../../button";
|
||||
import { UNSAFE_useAkselTheme } from "../../provider";
|
||||
import { useThemeInternal } from "../../theme/Theme";
|
||||
import { BodyShort, ErrorMessage, Label } from "../../typography";
|
||||
import { omit } from "../../util";
|
||||
import { useMergeRefs } from "../../util/hooks/useMergeRefs";
|
||||
import { useI18n } from "../../util/i18n/i18n.context";
|
||||
import { useI18n } from "../../util/i18n/i18n.hooks";
|
||||
import { FormFieldProps, useFormField } from "../useFormField";
|
||||
import SearchButton, { SearchButtonType } from "./SearchButton";
|
||||
import { SearchContext } from "./context";
|
||||
@@ -125,7 +125,7 @@ export const Search = forwardRef<HTMLInputElement, SearchProps>(
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
const themeContext = UNSAFE_useAkselTheme(false);
|
||||
const themeContext = useThemeInternal(false);
|
||||
|
||||
const searchRef = useRef<HTMLInputElement | null>(null);
|
||||
const mergedRef = useMergeRefs(searchRef, ref);
|
||||
@@ -263,7 +263,9 @@ export const Search = forwardRef<HTMLInputElement, SearchProps>(
|
||||
aria-live="polite"
|
||||
>
|
||||
{showErrorMsg && (
|
||||
<ErrorMessage size={size}>{props.error}</ErrorMessage>
|
||||
<ErrorMessage size={size} showIcon>
|
||||
{props.error}
|
||||
</ErrorMessage>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import React, { forwardRef, useContext } from "react";
|
||||
import { MagnifyingGlassIcon } from "@navikt/aksel-icons";
|
||||
import { Button, ButtonProps } from "../../button";
|
||||
import { composeEventHandlers } from "../../util/composeEventHandlers";
|
||||
import { useI18n } from "../../util/i18n/i18n.context";
|
||||
import { useI18n } from "../../util/i18n/i18n.hooks";
|
||||
import { SearchContext } from "./context";
|
||||
|
||||
export interface SearchButtonProps
|
||||
|
||||
@@ -151,7 +151,9 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>(
|
||||
aria-live="polite"
|
||||
>
|
||||
{showErrorMsg && (
|
||||
<ErrorMessage size={size}>{props.error}</ErrorMessage>
|
||||
<ErrorMessage size={size} showIcon>
|
||||
{props.error}
|
||||
</ErrorMessage>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,6 @@ import React, {
|
||||
useState,
|
||||
} from "react";
|
||||
import { Loader } from "../../loader";
|
||||
import { UNSAFE_useAkselTheme } from "../../provider";
|
||||
import { BodyShort } from "../../typography";
|
||||
import { omit } from "../../util";
|
||||
import { ReadOnlyIconWithTitle } from "../ReadOnlyIcon";
|
||||
@@ -69,8 +68,6 @@ export const Switch = forwardRef<HTMLInputElement, SwitchProps>(
|
||||
defaultChecked ?? checkedProp ?? false,
|
||||
);
|
||||
|
||||
const themeContext = UNSAFE_useAkselTheme(false);
|
||||
|
||||
useEffect(() => {
|
||||
checkedProp !== undefined && setChecked(checkedProp);
|
||||
}, [checkedProp]);
|
||||
@@ -121,13 +118,7 @@ export const Switch = forwardRef<HTMLInputElement, SwitchProps>(
|
||||
<Loader
|
||||
size="xsmall"
|
||||
aria-live="polite"
|
||||
variant={
|
||||
checked
|
||||
? "interaction"
|
||||
: themeContext
|
||||
? "inverted"
|
||||
: "neutral"
|
||||
}
|
||||
variant={checked ? "interaction" : "inverted"}
|
||||
/>
|
||||
) : (
|
||||
<svg
|
||||
|
||||
@@ -193,7 +193,9 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
aria-live="polite"
|
||||
>
|
||||
{showErrorMsg && (
|
||||
<ErrorMessage size={size}>{props.error}</ErrorMessage>
|
||||
<ErrorMessage size={size} showIcon>
|
||||
{props.error}
|
||||
</ErrorMessage>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@ import cl from "clsx";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { BodyShort } from "../../typography";
|
||||
import debounce from "../../util/debounce";
|
||||
import { useI18n } from "../../util/i18n/i18n.context";
|
||||
import { useI18n } from "../../util/i18n/i18n.hooks";
|
||||
import type { TextareaProps } from "./Textarea";
|
||||
|
||||
interface Props {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Meta, StoryFn, StoryObj } from "@storybook/react";
|
||||
import { expect, userEvent, within } from "@storybook/test";
|
||||
import React, { useState } from "react";
|
||||
import { Button } from "../../button";
|
||||
import { VStack } from "../../layout/stack";
|
||||
import { Modal } from "../../modal";
|
||||
import { Textarea } from "./index";
|
||||
|
||||
@@ -74,6 +75,24 @@ export const WithError: StoryFn = () => {
|
||||
size="small"
|
||||
/>
|
||||
|
||||
<VStack
|
||||
style={{
|
||||
maxWidth: "400px",
|
||||
}}
|
||||
gap="4"
|
||||
>
|
||||
<Textarea
|
||||
label="Ipsum enim quis culpa"
|
||||
error="Consectetur labore velit eiusmod Lorem ut nostrud mollit labore ullamco laboris laboris in."
|
||||
/>
|
||||
|
||||
<Textarea
|
||||
label="Ipsum enim quis culpa"
|
||||
error="Consectetur labore velit eiusmod Lorem ut nostrud mollit labore ullamco laboris laboris in."
|
||||
size="small"
|
||||
/>
|
||||
</VStack>
|
||||
|
||||
<Textarea
|
||||
label="Ipsum enim quis culpa"
|
||||
error="Consectetur labore velit eiusmod Lorem ut nostrud mollit labore ullamco laboris laboris in."
|
||||
@@ -207,6 +226,27 @@ AutoScrollbar.argTypes = {
|
||||
minRows: { type: "number" },
|
||||
};
|
||||
|
||||
export const InsideModal: StoryFn<typeof Textarea> = () => {
|
||||
const ref = React.useRef<HTMLDialogElement>(null);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button onClick={() => ref.current?.showModal()}>Open modal</Button>
|
||||
<React.StrictMode>
|
||||
<Modal
|
||||
ref={ref}
|
||||
header={{ heading: "Skjema" }}
|
||||
aria-label="Modal med textarea"
|
||||
>
|
||||
<Modal.Body>
|
||||
<Textarea label="Har du noen tilbakemeldinger?" />
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
</React.StrictMode>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
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.
|
||||
|
||||
@@ -127,7 +127,9 @@ export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
|
||||
aria-live="polite"
|
||||
>
|
||||
{showErrorMsg && (
|
||||
<ErrorMessage size={size}>{props.error}</ErrorMessage>
|
||||
<ErrorMessage size={size} showIcon>
|
||||
{props.error}
|
||||
</ErrorMessage>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import cl from "clsx";
|
||||
import React, { HTMLAttributes, forwardRef } from "react";
|
||||
import { UNSAFE_useAkselTheme } from "../provider";
|
||||
import { useThemeInternal } from "../theme/Theme";
|
||||
import { DefaultIllustration } from "./Illustration";
|
||||
import { DarksideGudiepanelIllustration } from "./Illustration.darkside";
|
||||
|
||||
@@ -37,7 +37,7 @@ export interface GuidePanelProps extends HTMLAttributes<HTMLDivElement> {
|
||||
*/
|
||||
export const GuidePanel = forwardRef<HTMLDivElement, GuidePanelProps>(
|
||||
({ children, className, illustration, poster, ...rest }, ref) => {
|
||||
const themeContext = UNSAFE_useAkselTheme(false);
|
||||
const themeContext = useThemeInternal(false);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { useI18n } from "../util/i18n/i18n.context";
|
||||
import { useI18n } from "../util/i18n/i18n.hooks";
|
||||
|
||||
export const DarksideGudiepanelIllustration = () => {
|
||||
const translate = useI18n("GuidePanel");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { useI18n } from "../util/i18n/i18n.context";
|
||||
import { useI18n } from "../util/i18n/i18n.hooks";
|
||||
|
||||
export const DefaultIllustration = () => {
|
||||
const translate = useI18n("GuidePanel");
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef, useRef, useState } from "react";
|
||||
import { Popover, PopoverProps } from "../popover";
|
||||
import { UNSAFE_useAkselTheme } from "../provider";
|
||||
import { useThemeInternal } from "../theme/Theme";
|
||||
import { composeEventHandlers } from "../util/composeEventHandlers";
|
||||
import { useMergeRefs } from "../util/hooks/useMergeRefs";
|
||||
import { useI18n } from "../util/i18n/i18n.context";
|
||||
import { useI18n } from "../util/i18n/i18n.hooks";
|
||||
import { HelpTextIcon } from "./HelpTextIcon";
|
||||
|
||||
export interface HelpTextProps
|
||||
@@ -52,7 +52,7 @@ export const HelpText = forwardRef<HTMLButtonElement, HelpTextProps>(
|
||||
const buttonRef = useRef<HTMLButtonElement | null>(null);
|
||||
const mergedRef = useMergeRefs(buttonRef, ref);
|
||||
const [open, setOpen] = useState(false);
|
||||
const themeContext = UNSAFE_useAkselTheme(false);
|
||||
const themeContext = useThemeInternal(false);
|
||||
const translate = useI18n("HelpText");
|
||||
|
||||
const titleWithFallback = title || translate("title");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import cl from "clsx";
|
||||
import React, { HTMLAttributes, forwardRef } from "react";
|
||||
import { UNSAFE_AkselTheme, UNSAFE_useAkselTheme } from "../provider";
|
||||
import { Theme, useThemeInternal } from "../theme/Theme";
|
||||
import { OverridableComponent } from "../util/types";
|
||||
import InternalHeaderButton, {
|
||||
InternalHeaderButtonProps,
|
||||
@@ -78,20 +78,20 @@ interface InternalHeaderComponent
|
||||
* ```
|
||||
*/
|
||||
export const InternalHeader = forwardRef(({ className, ...rest }, ref) => {
|
||||
const themeContext = UNSAFE_useAkselTheme(false);
|
||||
const themeContext = useThemeInternal(false);
|
||||
|
||||
/*
|
||||
* Component is always in "dark" mode, so we manually override global theme.
|
||||
*/
|
||||
if (themeContext) {
|
||||
return (
|
||||
<UNSAFE_AkselTheme theme="dark" asChild>
|
||||
<Theme theme="dark" asChild>
|
||||
<header
|
||||
{...rest}
|
||||
ref={ref}
|
||||
className={cl("navds-internalheader", className)}
|
||||
/>
|
||||
</UNSAFE_AkselTheme>
|
||||
</Theme>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import cl from "clsx";
|
||||
import React from "react";
|
||||
import { UNSAFE_useAkselTheme } from "../../provider";
|
||||
import { Slot } from "../../slot/Slot";
|
||||
import { useThemeInternal } from "../../theme/Theme";
|
||||
import { getResponsiveProps, getResponsiveValue } from "../utilities/css";
|
||||
import { ResponsiveProp, SpacingScale } from "../utilities/types";
|
||||
|
||||
@@ -252,7 +252,7 @@ export const BasePrimitive = ({
|
||||
flexShrink,
|
||||
gridColumn,
|
||||
}: BasePrimitiveProps) => {
|
||||
const themeContext = UNSAFE_useAkselTheme(false);
|
||||
const themeContext = useThemeInternal(false);
|
||||
const prefix = themeContext ? "ax" : "a";
|
||||
|
||||
const style: React.CSSProperties = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef } from "react";
|
||||
import { UNSAFE_useAkselTheme } from "../../provider";
|
||||
import { Slot } from "../../slot/Slot";
|
||||
import { useThemeInternal } from "../../theme/Theme";
|
||||
import { getResponsiveProps } from "../utilities/css";
|
||||
import { ResponsiveProp, SpacingScale } from "../utilities/types";
|
||||
|
||||
@@ -81,7 +81,7 @@ export const Bleed = forwardRef<HTMLDivElement, BleedProps>(
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const themeContext = UNSAFE_useAkselTheme(false);
|
||||
const themeContext = useThemeInternal(false);
|
||||
const prefix = themeContext ? "ax" : "a";
|
||||
|
||||
let style: React.CSSProperties = {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef } from "react";
|
||||
import { type BorderRadiusKeys } from "@navikt/ds-tokens/types";
|
||||
import { UNSAFE_useAkselTheme } from "../../provider";
|
||||
import { Slot } from "../../slot/Slot";
|
||||
import { useThemeInternal } from "../../theme/Theme";
|
||||
import { omit } from "../../util";
|
||||
import { OverridableComponent } from "../../util/types";
|
||||
import BasePrimitive, {
|
||||
@@ -109,7 +109,7 @@ export const BoxComponent: OverridableComponent<BoxProps, HTMLDivElement> =
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const themeContext = UNSAFE_useAkselTheme(false);
|
||||
const themeContext = useThemeInternal(false);
|
||||
|
||||
if (
|
||||
process.env.NODE_ENV !== "production" &&
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef } from "react";
|
||||
import { UNSAFE_useAkselTheme } from "../../provider";
|
||||
import { Slot } from "../../slot/Slot";
|
||||
import { useThemeInternal } from "../../theme/Theme";
|
||||
import { OverridableComponent, omit } from "../../util";
|
||||
import BasePrimitive, {
|
||||
PRIMITIVE_PROPS,
|
||||
@@ -78,7 +78,7 @@ export const HGrid: OverridableComponent<HGridProps, HTMLDivElement> =
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const themeContext = UNSAFE_useAkselTheme(false);
|
||||
const themeContext = useThemeInternal(false);
|
||||
const prefix = themeContext ? "ax" : "a";
|
||||
|
||||
const styles: React.CSSProperties = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef } from "react";
|
||||
import { UNSAFE_useAkselTheme } from "../../provider";
|
||||
import { useThemeInternal } from "../../theme/Theme";
|
||||
import { OverridableComponent } from "../../util";
|
||||
import { BackgroundColorToken } from "../utilities/types";
|
||||
import { PageBlock } from "./parts/PageBlock";
|
||||
@@ -54,7 +54,7 @@ export const PageComponent: OverridableComponent<PageProps, HTMLElement> =
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const themeContext = UNSAFE_useAkselTheme(false);
|
||||
const themeContext = useThemeInternal(false);
|
||||
|
||||
if (process.env.NODE_ENV !== "production" && themeContext && background) {
|
||||
console.warn(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import cl from "clsx";
|
||||
import React, { HTMLAttributes, forwardRef } from "react";
|
||||
import { UNSAFE_useAkselTheme } from "../../provider";
|
||||
import { Slot } from "../../slot/Slot";
|
||||
import { useThemeInternal } from "../../theme/Theme";
|
||||
import { omit } from "../../util";
|
||||
import { OverridableComponent } from "../../util/types";
|
||||
import BasePrimitive, {
|
||||
@@ -84,7 +84,7 @@ export const Stack: OverridableComponent<StackProps, HTMLDivElement> =
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const themeContext = UNSAFE_useAkselTheme(false);
|
||||
const themeContext = useThemeInternal(false);
|
||||
const prefix = themeContext ? "ax" : "a";
|
||||
|
||||
const style: React.CSSProperties = {
|
||||
|
||||
@@ -2,7 +2,7 @@ import cl from "clsx";
|
||||
import React, { SVGProps, forwardRef } from "react";
|
||||
import { omit } from "../util";
|
||||
import { useId } from "../util/hooks";
|
||||
import { useI18n } from "../util/i18n/i18n.context";
|
||||
import { useI18n } from "../util/i18n/i18n.hooks";
|
||||
|
||||
export interface LoaderProps extends Omit<SVGProps<SVGSVGElement>, "ref"> {
|
||||
/**
|
||||
|
||||
@@ -2,7 +2,7 @@ import cl from "clsx";
|
||||
import React, { forwardRef } from "react";
|
||||
import { XMarkIcon } from "@navikt/aksel-icons";
|
||||
import { Button } from "../button";
|
||||
import { useI18n } from "../util/i18n/i18n.context";
|
||||
import { useI18n } from "../util/i18n/i18n.hooks";
|
||||
import { useModalContext } from "./Modal.context";
|
||||
|
||||
export interface ModalHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
|
||||
@@ -2,8 +2,8 @@ import cl from "clsx";
|
||||
import React, { forwardRef, useRef } from "react";
|
||||
import { ChevronRightIcon } from "@navikt/aksel-icons";
|
||||
import { useModalContext } from "../../modal/Modal.context";
|
||||
import { UNSAFE_useAkselTheme } from "../../provider";
|
||||
import { Slot } from "../../slot/Slot";
|
||||
import { useThemeInternal } from "../../theme/Theme";
|
||||
import { OverridableComponent, useId } from "../../util";
|
||||
import { composeEventHandlers } from "../../util/composeEventHandlers";
|
||||
import { createContext } from "../../util/create-context";
|
||||
@@ -736,7 +736,7 @@ export const ActionMenuRadioItem = forwardRef<
|
||||
{ children, className, onSelect, ...rest }: ActionMenuRadioItemProps,
|
||||
ref,
|
||||
) => {
|
||||
const themeContext = UNSAFE_useAkselTheme(false);
|
||||
const themeContext = useThemeInternal(false);
|
||||
|
||||
return (
|
||||
<Menu.RadioItem
|
||||
|
||||
@@ -3,7 +3,7 @@ import React, { forwardRef } from "react";
|
||||
import { ChevronLeftIcon, ChevronRightIcon } from "@navikt/aksel-icons";
|
||||
import { BodyShort, Heading } from "../typography";
|
||||
import { useId } from "../util";
|
||||
import { useI18n } from "../util/i18n/i18n.context";
|
||||
import { useI18n } from "../util/i18n/i18n.hooks";
|
||||
import PaginationItem, {
|
||||
PaginationItemProps,
|
||||
PaginationItemType,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef } from "react";
|
||||
import { Button, ButtonProps } from "../button";
|
||||
import { UNSAFE_useAkselTheme } from "../provider";
|
||||
import { useThemeInternal } from "../theme/Theme";
|
||||
import { OverridableComponent } from "../util/types";
|
||||
|
||||
export interface PaginationItemProps extends ButtonProps {
|
||||
@@ -40,7 +40,7 @@ export const Item: PaginationItemType = forwardRef(
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const themeContext = UNSAFE_useAkselTheme(false);
|
||||
const themeContext = useThemeInternal(false);
|
||||
|
||||
return (
|
||||
<Button
|
||||
|
||||
@@ -11,7 +11,7 @@ import React, { HTMLAttributes, forwardRef, useContext, useRef } from "react";
|
||||
import { DateInputContext } from "../date/context";
|
||||
import { useModalContext } from "../modal/Modal.context";
|
||||
import { DismissableLayer } from "../overlays/dismissablelayer/DismissableLayer";
|
||||
import { UNSAFE_useAkselTheme } from "../provider";
|
||||
import { useThemeInternal } from "../theme/Theme";
|
||||
import { useClientLayoutEffect } from "../util/hooks";
|
||||
import { useMergeRefs } from "../util/hooks/useMergeRefs";
|
||||
import PopoverContent, { PopoverContentType } from "./PopoverContent";
|
||||
@@ -125,7 +125,7 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
|
||||
const chosenStrategy = userStrategy ?? (isInModal ? "fixed" : "absolute");
|
||||
const chosenFlip = isInDatepicker ? false : _flip;
|
||||
|
||||
const themeContext = UNSAFE_useAkselTheme(false);
|
||||
const themeContext = useThemeInternal(false);
|
||||
|
||||
const {
|
||||
update,
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { HTMLAttributes, forwardRef } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { useProvider } from "../provider/Provider";
|
||||
import { Slot } from "../slot/Slot";
|
||||
import { Theme, useThemeInternal } from "../theme/Theme";
|
||||
import { AsChildProps } from "../util/types";
|
||||
|
||||
interface PortalBaseProps extends HTMLAttributes<HTMLDivElement> {
|
||||
@@ -15,11 +16,27 @@ export type PortalProps = PortalBaseProps & AsChildProps;
|
||||
|
||||
export const Portal = forwardRef<HTMLDivElement, PortalProps>(
|
||||
({ rootElement, asChild, ...rest }, ref) => {
|
||||
const themeContext = useThemeInternal(false);
|
||||
const contextRoot = useProvider()?.rootElement;
|
||||
const root = rootElement ?? contextRoot ?? globalThis?.document?.body;
|
||||
|
||||
const Component = asChild ? Slot : "div";
|
||||
|
||||
/**
|
||||
* Portal can be mounted outside of theme-classNames.
|
||||
* If a theme is present, we want to make sure that theme cascades to portaled element.
|
||||
*/
|
||||
if (themeContext) {
|
||||
return root
|
||||
? ReactDOM.createPortal(
|
||||
<Theme theme={themeContext.theme} asChild hasBackground={false}>
|
||||
<Component ref={ref} data-aksel-portal="" {...rest} />
|
||||
</Theme>,
|
||||
root,
|
||||
)
|
||||
: null;
|
||||
}
|
||||
|
||||
return root
|
||||
? ReactDOM.createPortal(
|
||||
<Component ref={ref} data-aksel-portal="" {...rest} />,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import cl from "clsx";
|
||||
import React, { HTMLAttributes, forwardRef, useEffect, useRef } from "react";
|
||||
import { useI18n } from "../util/i18n/i18n.context";
|
||||
import { useI18n } from "../util/i18n/i18n.hooks";
|
||||
|
||||
interface ProgressBarPropsBase
|
||||
extends Omit<HTMLAttributes<HTMLDivElement>, "role"> {
|
||||
|
||||
@@ -1,6 +1,2 @@
|
||||
"use client";
|
||||
export { default as Provider, type ProviderProps } from "./Provider";
|
||||
export {
|
||||
AkselTheme as UNSAFE_AkselTheme,
|
||||
useAkselTheme as UNSAFE_useAkselTheme,
|
||||
} from "./theme/AkselTheme";
|
||||
@@ -1,70 +0,0 @@
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef } from "react";
|
||||
import { Slot } from "../../slot/Slot";
|
||||
import { createContext } from "../../util/create-context";
|
||||
|
||||
type AkselThemeContext = {
|
||||
/**
|
||||
* Color theme
|
||||
* @default "light"
|
||||
*/
|
||||
theme?: "light" | "dark";
|
||||
/**
|
||||
* Brand volume
|
||||
* @default "low"
|
||||
* This is experimental and subject to changes
|
||||
*/
|
||||
volume?: "high" | "low";
|
||||
};
|
||||
|
||||
const [ThemeProvider, useAkselTheme] = createContext<AkselThemeContext>({
|
||||
errorMessage: "useAkselTheme must be used within AkselThemeProvider",
|
||||
hookName: "useAkselTheme",
|
||||
name: "AkselThemeProvider",
|
||||
providerName: "AkselThemeProvider",
|
||||
});
|
||||
|
||||
type AkselThemeProps = {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
hasBackground?: boolean;
|
||||
/* TODO: Handle this correctly with types */
|
||||
asChild?: boolean;
|
||||
} & AkselThemeContext;
|
||||
|
||||
const AkselTheme = forwardRef<HTMLDivElement, AkselThemeProps>(
|
||||
(props: AkselThemeProps, ref) => {
|
||||
const context = useAkselTheme(false);
|
||||
|
||||
const {
|
||||
children,
|
||||
className,
|
||||
asChild = false,
|
||||
theme = context?.theme ?? "light",
|
||||
volume = context?.volume ?? "low",
|
||||
hasBackground: hasBackgroundProp = true,
|
||||
} = props;
|
||||
|
||||
const isRoot = context === undefined;
|
||||
|
||||
const hasBackground =
|
||||
hasBackgroundProp ?? (isRoot || props.theme !== undefined);
|
||||
|
||||
const SlotElement = asChild ? Slot : "div";
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={theme} volume={volume}>
|
||||
<SlotElement
|
||||
ref={ref}
|
||||
className={cl("navds-theme", className, theme)}
|
||||
data-background={hasBackground}
|
||||
data-volume={volume}
|
||||
>
|
||||
{children}
|
||||
</SlotElement>
|
||||
</ThemeProvider>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export { AkselTheme, useAkselTheme };
|
||||
@@ -1,7 +1,6 @@
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef } from "react";
|
||||
import { ChevronDownIcon } from "@navikt/aksel-icons";
|
||||
import { UNSAFE_useAkselTheme } from "../provider";
|
||||
import { BodyLong } from "../typography";
|
||||
import { composeEventHandlers } from "../util/composeEventHandlers";
|
||||
import { useControllableState } from "../util/hooks/useControllableState";
|
||||
@@ -75,8 +74,6 @@ export const ReadMore = forwardRef<HTMLButtonElement, ReadMoreProps>(
|
||||
onChange: onOpenChange,
|
||||
});
|
||||
|
||||
const themeContext = UNSAFE_useAkselTheme(false);
|
||||
|
||||
const typoSize = size === "small" ? "small" : "medium";
|
||||
|
||||
return (
|
||||
@@ -87,7 +84,7 @@ export const ReadMore = forwardRef<HTMLButtonElement, ReadMoreProps>(
|
||||
className,
|
||||
{ "navds-read-more--open": _open },
|
||||
)}
|
||||
data-volume={themeContext?.volume}
|
||||
data-volume="low"
|
||||
>
|
||||
<button
|
||||
{...rest}
|
||||
|
||||
@@ -3,7 +3,6 @@ import { fn } from "@storybook/test";
|
||||
import React from "react";
|
||||
import { ReadMore } from ".";
|
||||
import { VStack } from "../layout/stack";
|
||||
import { UNSAFE_AkselTheme } from "../provider";
|
||||
|
||||
export default {
|
||||
title: "ds-react/ReadMore",
|
||||
@@ -68,17 +67,15 @@ export const Open: Story = {
|
||||
|
||||
export const BrandVolumeLow: Story = {
|
||||
render: () => (
|
||||
<UNSAFE_AkselTheme volume="low">
|
||||
<VStack gap="4">
|
||||
<ReadMore size="large" header={Default.args?.header}>
|
||||
{Content}
|
||||
</ReadMore>
|
||||
<ReadMore header={Default.args?.header}>{Content}</ReadMore>
|
||||
<ReadMore size="small" header={Default.args?.header}>
|
||||
{Content}
|
||||
</ReadMore>
|
||||
</VStack>
|
||||
</UNSAFE_AkselTheme>
|
||||
<VStack gap="4">
|
||||
<ReadMore size="large" header={Default.args?.header}>
|
||||
{Content}
|
||||
</ReadMore>
|
||||
<ReadMore header={Default.args?.header}>{Content}</ReadMore>
|
||||
<ReadMore size="small" header={Default.args?.header}>
|
||||
{Content}
|
||||
</ReadMore>
|
||||
</VStack>
|
||||
),
|
||||
args: {
|
||||
...Default.args,
|
||||
@@ -86,22 +83,6 @@ export const BrandVolumeLow: Story = {
|
||||
},
|
||||
};
|
||||
|
||||
export const BrandVolumeHigh: Story = {
|
||||
render: () => (
|
||||
<UNSAFE_AkselTheme volume="high">
|
||||
<VStack gap="4">
|
||||
<ReadMore size="large" header={Default.args?.header}>
|
||||
{Content}
|
||||
</ReadMore>
|
||||
<ReadMore header={Default.args?.header}>{Content}</ReadMore>
|
||||
<ReadMore size="small" header={Default.args?.header}>
|
||||
{Content}
|
||||
</ReadMore>
|
||||
</VStack>
|
||||
</UNSAFE_AkselTheme>
|
||||
),
|
||||
};
|
||||
|
||||
export const Chromatic: Story = {
|
||||
render: (...props) => {
|
||||
return (
|
||||
@@ -135,10 +116,6 @@ export const Chromatic: Story = {
|
||||
<h2>BrandVolumeLow</h2>
|
||||
{BrandVolumeLow?.render?.(...props)}
|
||||
</div>
|
||||
<div>
|
||||
<h2>BrandVolumeHigh</h2>
|
||||
{BrandVolumeHigh?.render?.(...props)}
|
||||
</div>
|
||||
</VStack>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -4,7 +4,7 @@ import { ChevronDownIcon } from "@navikt/aksel-icons";
|
||||
import { composeEventHandlers } from "../util/composeEventHandlers";
|
||||
import { useId } from "../util/hooks";
|
||||
import { useControllableState } from "../util/hooks/useControllableState";
|
||||
import { useI18n } from "../util/i18n/i18n.context";
|
||||
import { useI18n } from "../util/i18n/i18n.hooks";
|
||||
import AnimateHeight from "./AnimateHeight";
|
||||
import DataCell from "./DataCell";
|
||||
import Row, { RowProps } from "./Row";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { act, fireEvent, render, screen } from "@testing-library/react";
|
||||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import React from "react";
|
||||
import { describe, expect, test } from "vitest";
|
||||
@@ -154,19 +154,11 @@ describe("Tabs", () => {
|
||||
expect(screen.getByTestId("tab2")).toHaveFocus();
|
||||
|
||||
/* Move focus to tabPanel */
|
||||
// eslint-disable-next-line testing-library/no-unnecessary-act
|
||||
await act(async () => {
|
||||
/* Tablist handles tabbing with setTimeout, so we need to use act */
|
||||
await userEvent.tab();
|
||||
});
|
||||
|
||||
await userEvent.tab();
|
||||
expect(screen.getByTestId("tabpanel1")).toHaveFocus();
|
||||
/* Move focus back to tablist, now tab1 should have focus */
|
||||
|
||||
// eslint-disable-next-line testing-library/no-unnecessary-act
|
||||
await act(async () => {
|
||||
await userEvent.tab({ shift: true });
|
||||
});
|
||||
/* Move focus back to tablist, now tab1 should have focus */
|
||||
await userEvent.tab({ shift: true });
|
||||
expect(screen.getByTestId("tab1")).toHaveFocus();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef } from "react";
|
||||
import { Slot } from "../slot/Slot";
|
||||
import { createContext } from "../util/create-context";
|
||||
import { AsChildProps } from "../util/types";
|
||||
|
||||
type ThemeContext = {
|
||||
/**
|
||||
* Color theme
|
||||
* @default "light"
|
||||
*/
|
||||
theme: "light" | "dark";
|
||||
};
|
||||
|
||||
const [ThemeProvider, useThemeInternal] = createContext<ThemeContext>({
|
||||
hookName: "useTheme",
|
||||
name: "ThemeProvider",
|
||||
providerName: "ThemeProvider",
|
||||
});
|
||||
|
||||
type ThemeProps = {
|
||||
className?: string;
|
||||
hasBackground?: boolean;
|
||||
} & ThemeContext &
|
||||
AsChildProps;
|
||||
|
||||
const Theme = forwardRef<HTMLDivElement, ThemeProps>(
|
||||
(props: ThemeProps, ref) => {
|
||||
const context = useThemeInternal(false);
|
||||
|
||||
const {
|
||||
children,
|
||||
className,
|
||||
asChild = false,
|
||||
theme = context?.theme ?? "light",
|
||||
hasBackground: hasBackgroundProp = true,
|
||||
} = props;
|
||||
|
||||
const isRoot = context === undefined;
|
||||
|
||||
const hasBackground =
|
||||
hasBackgroundProp ?? (isRoot && props.theme !== undefined);
|
||||
|
||||
const SlotElement = asChild ? Slot : "div";
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<SlotElement
|
||||
ref={ref}
|
||||
className={cl("navds-theme", className, theme)}
|
||||
data-background={hasBackground}
|
||||
>
|
||||
{children}
|
||||
</SlotElement>
|
||||
</ThemeProvider>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export { Theme, useThemeInternal };
|
||||
@@ -0,0 +1,2 @@
|
||||
"use client";
|
||||
export { Theme } from "./Theme";
|
||||
@@ -16,7 +16,8 @@ import {
|
||||
} from "date-fns";
|
||||
import React from "react";
|
||||
import { Detail } from "../typography/Detail";
|
||||
import { TFunction, useDateLocale, useI18n } from "../util/i18n/i18n.context";
|
||||
import { useDateLocale, useI18n } from "../util/i18n/i18n.hooks";
|
||||
import { TFunction } from "../util/i18n/i18n.types";
|
||||
import { useTimelineContext } from "./hooks/useTimelineContext";
|
||||
import { isVisible } from "./utils";
|
||||
import { horizontalPositionAndWidth } from "./utils/calc";
|
||||
|
||||
Loaded 100 of 150 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user