Compare commits

..
Author SHA1 Message Date
github-actions[bot]andgithub-actions[bot] 8cd6512181 Version Packages (#3474)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-20 14:48:03 +01:00
Halvor Haugan 7e976f9e20 [aksel.nav.no] Add example of ErrorMessage with icon (#3476) 2024-12-20 12:13:30 +01:00
Ken db828bddd3 [Switch] Updated default design to better reflect unchecked state (#3468)
* WIP Switch update

* 💄 Updated Switch to reflect unchecked state better

* 📝 Synced token for switch
2024-12-20 11:27:33 +01:00
443b129fe1 Bugfix/button loading issue in modal (#3252)
* Check loading prop for showing spinner, not widthOverride.

Making this change because widthOverride sometimes gets set to 0 (should also be fixed), meaning this check fails as "falsy".

* Prevent setting width to 0 while showing spinner, to avoid issue in Modals

Checking that width is truthy (not zero) will avoid issue where widthOverride gets set to 0 because the button is not yet rendered.

* Add changeset

* Replace width calculation with just visually hiding label + icon and absolutely positioning the loading icon.

* Update @navikt/core/react/src/button/Button.tsx

* add story for bug case

* We no longer use buttonRef/mergedRef internally, so removed them and set ref directly

* Update @navikt/core/css/button.css

Co-authored-by: Ken <26967723+KenAJoh@users.noreply.github.com>

* Hiding everything except loading spinner is more robust than hiding every specific item.

* In loading-state, the button icon will no longer be able to be the only child (hidden), because of the loader icon. Instead checks for no label.

Could consider :not(:has(:is(.navds-button__icon, .navds-loader))) as well, to be more robust, but it might be overkill.

* Much simpler/easier to read

* Don't need to destructure style, only to add it along with rest.

* Should destructure onKeyUp from props, instead of having it added through filteredProps and then overridden afterwards.

* Quick and easy conversion for darkside

* Unnecessary :is after refactoring

---------

Co-authored-by: Julian Nymark <julian.nymark@nav.no>
Co-authored-by: Ken <26967723+KenAJoh@users.noreply.github.com>
2024-12-20 10:44:04 +01:00
Ken 561fecbcac [Darkside] Updated <Theme /> component (#3467)
* 🚚 Rename and move theme-component

* 🐛 Portal now preserves theme when out of cascade

* 🐛 useThemeInternal missing strict-mode false

* 🐛 Removed unused storybook story

* Update @navikt/core/react/src/theme/Theme.tsx

* 📝 remove commented out code
2024-12-20 09:29:22 +01:00
Ken 00177898f5 [Select] 🐛 Focus-border no longer cancels out error-border. (#3465)
* 🐛 Focus-border no longer cancels out error-border.

* ♻️ Optimize CSS selectors, fix textarea

* 📝 Changeset
2024-12-19 17:20:10 +01:00
Ken 38f5e63008 🐛 Removed default tokens added to tailwind, added opacity-token (#3472) 2024-12-19 16:33:42 +01:00
Halvor Haugan c3d65a681e Make Chromatic workflow fail on errors but not on changes (#3471) 2024-12-19 16:05:07 +01:00
Ken 3025e4eb5c [Darkside] ✨ Now adds version-tokens to tokens css (#3466)
* ✨ Now adds version-tokens to tokens css

* ♻️ Remove redundant exist-check
2024-12-19 15:30:49 +01:00
Ken 043277f79b [Darkside] 💄 New ToggleGroup design (#3460)
* 💄 New ToggleGroup design

* 🐛 Removed hover-state from selected togglegroup in forced-colors mode

* 💄 Add px-gap to elements

* 🐛 Hide divider on both sides when selected
2024-12-19 15:16:03 +01:00
Julian NymarkandHalvor Haugan a2b3936878 Textarea: resize immediately upon receiving resize event (#3463)
* change: add story to demonstrate buggy textarea behaviour inside modal

* use lodash debounce with our own default value for wait

* Revert "use lodash debounce with our own default value for wait"

This reverts commit 7638297765.

* change: add leading to debounce + use it in TextareaAutoSize

* changeset

* changeset + co-author

Co-authored-by: Halvor Haugan <halvor.haugan@nav.no>

---------

Co-authored-by: Halvor Haugan <halvor.haugan@nav.no>
2024-12-19 14:23:39 +01:00
Julian Nymark c90abe7c23 [Darkside] Warning triangle icon in error messages (#3445)
* change: support icon in ErrorMessage + warning icon for textarea error

* change: ignore icon on old CSS + tweaks

* change: do not nest in old css

* wip commit (works nicely)

* clean up css for errormessage, remove it from form.css

* 🐛 tweaks + use icon in Search

* use icon for the rest of our form components

* backport new css to old form.css

* 🔥 remove unnecessary specification bump

* cleaner example story

* changeset

* ♻️ icon -> showIcon

* make flex & gap opt-in with 'icon'

* change: inline ErrorMessageIcon

* change: nest css more

* revert test changes (utility in multiple variants on one for DOM diffing, but probably no longer useful)

* debloat changeset

* mention form components in changeset

* change: typo in changeset

* change: typo in changeset
2024-12-19 14:17:50 +01:00
github-actions[bot]andgithub-actions[bot] ea19081b71 Version Packages (#3454)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-19 11:03:46 +01:00
Ken b9da4fd716 📝 Rename NAV -> Nav (#3470) 2024-12-19 10:08:52 +01:00
Kyrre Havik 858849d743 upkeep: NAVs -> Navs 2024-12-18 15:56:26 +01:00
Ken ae9e6235db [Combobox] Only open dropdown onClick, not onFocus. (#3440)
* ✨ Solves issue where programatic focus to fix error would show dropdown list and hide error

* 🚚 Moved onclick listener for open-state to input, not wrapper

* Update .changeset/forty-rules-ring.md
2024-12-18 15:29:08 +01:00
Julian NymarkandKen f895555ab2 [Darkside] timeline update CSS (#3438)
* change: timeline periods

* update stories for timeline

* change: Timeline pin update

* change: crude variable renaming (--a- -> --ax-)

also likely done with zoom buttons,
a bit of popover styling fix

* change: popover z-index bump

* change: remove unnecessary CSS state :active

* change: z-index fix, correct token usage

* change: remove @supports not selector(:focus-visible)

* change: use proper tokens

* change: can't get focus on popover

* change: remove arrow from popover consumers

* change: only render arrow div when !themeContext

* 💄 Use smaller offset without arrow, use subtleA border for popover

* 💄 Adjusted popover tokens for timeline

---------

Co-authored-by: Ken <ken.aleksander@gmail.com>
2024-12-17 15:37:31 +01:00
Ken 372a14b225 [Referansesider]: Updated CSS import breaking workflow 2024-12-17 14:49:29 +01:00
Ken a82126b893 🐛 Fixed Expandable row cursor (#3462) 2024-12-17 14:35:41 +01:00
KenandHalvor Haugan 06193ae300 Inline Alert: <Link>-components used within avoids re-colororing (#3461)
* 💄 Avoid coloring links whe used in Inline Alert

* 📝 Alert changeset

* Update .changeset/eleven-gorillas-scream.md

Co-authored-by: Halvor Haugan <83693529+HalvorHaugan@users.noreply.github.com>

* 📝 Added link-demo to inline-story

---------

Co-authored-by: Halvor Haugan <83693529+HalvorHaugan@users.noreply.github.com>
2024-12-17 14:35:31 +01:00
Ken b6db2c4ce5 [Darkside] Tag CSS update (#3459)
* ✨ Added darkmode-support to Tag

* 🐛 Update spacing-tokens to new format

* ✨ Added darkmode-support to Tag

* 💄 use canvas-color for text on filled forced color text

* ♻️ Use classNames for tag colors, not data-attrb

* 🐛 Old Tag-css supports new names
2024-12-17 13:18:43 +01:00
Ken d4ee3afb12 [Aksel.nav.no] ✨ Added alpha-category to component-pages 2024-12-17 10:21:31 +01:00
KenandHalvor Haugan 6d6900c08b [Timeline]: Earliest date defaulted to current date when found date was later than current day (#3458)
* 🐛 Timeline startDate defaulted to current Date when later than current day

* 🧪 Added tests

* Update @navikt/core/react/src/timeline/hooks/useTimelineRows.ts

Co-authored-by: Halvor Haugan <83693529+HalvorHaugan@users.noreply.github.com>

* 🔥 Removed old exceptions

* 📝 Changeset

---------

Co-authored-by: Halvor Haugan <83693529+HalvorHaugan@users.noreply.github.com>
2024-12-16 20:40:26 +01:00
Ken 3b43ad51f9 💄 Added outline to OG-image in blog-articles 2024-12-16 16:41:49 +01:00
Ken fe4ad00462 🐛 Incorrect import broke chromatic-build 2024-12-13 18:21:13 +01:00
Ken 2ea0876e50 🐛 CSS-export for /dist did not support /**/-glob 2024-12-13 14:55:34 +01:00
Ken 460c9c3dbd 🐛 Updated ds-css exports to include tokens.json 2024-12-13 14:50:06 +01:00
Ken 88dc43bd50 ♿ CopyButton now tells SR what you are copying (#3455)
* ♿ CopyButton now tells SR what you are copying

* ♻️ Re-use sanitized name for semantic copybutton
2024-12-13 14:37:53 +01:00
KenandHalvor Haugan 2e476ef559 [Darkside] Updated CSS-bundle (#3430)
* V1 of CSS bundler

* V1 of CSS bundler

* ♻️ Added target checking for browser

* ♻️ Remove built in variables added by lightningcss

* Setup bundling of darkside

* 🐛 Fix path resolving in bundle script

* Setup bundling for index

* 🚚 Re-order layering

* ✨ Filter for only components in bundle

* 🚚 Moved token-definition

* 🔥 Removed index.css copy

* ✨ Global build

* ✨ form and primitives build

* ✨ Component build

* ✨ Build versions dir for new setup

* :test_tupe: Added tests for bundle

* 🚚 Move bundle file to config

* 📝 Comments

* ✨ Allow import of darkside directly under ds-css

* 🐛 Use relative import for CSS in storybook

* [Darkside] Updated input-bg in darkmode, added token for opacity (#3441)

* [Darkside]: Update bg-input to be darker in darkmode

* Added opacity-token

* Use token for disabled opacity

* Update @navikt/core/css/darkside/button.darkside.css

* ♻️ De-dupe reading of index.css

* ♻️ Use regex to remove - and space instead of lodash

* 🥅 Throw when bundler fails

* Update @navikt/core/css/config/bundle.darkside.ts

Co-authored-by: Halvor Haugan <83693529+HalvorHaugan@users.noreply.github.com>

* Update @navikt/core/css/config/bundle.darkside.ts

Co-authored-by: Halvor Haugan <83693529+HalvorHaugan@users.noreply.github.com>

* 🏷️ Updated opacity-tokens types, resolved import conflict

---------

Co-authored-by: Halvor Haugan <83693529+HalvorHaugan@users.noreply.github.com>
2024-12-13 13:53:37 +01:00
KenandHalvor Haugan f3542d50d4 [Darkside] Tokens package finishing touches (#3435)
* ✨ Updated exports to allow better darkside support

* ✨ Setup less and scss support for darkside

* ✨ Added static build for tokens

* ✨ Token-config exports

* 🐛 Resolved import conflicts between tailwind and css

* 🐛 Resolved import conflicts between tailwind and css

* ♻️ Refactor Token-setup for better typing

* ♻️ WIP resolve import conflicts2

* ♻️ Avoid importing JSON in react from tokens

* 🐛 Resolve updated imports in referansesider after refactor

* Update @navikt/core/tokens/.gitignore

* Update @navikt/core/tokens/types.ts

Co-authored-by: Halvor Haugan <83693529+HalvorHaugan@users.noreply.github.com>

* 🐛 Removed prefix 'ax' when generating static tokens for js

* 🐛 Resolved export syntax to support less, scss and JS

* 📝 Updated JSDoc to link directly to types

* Update @navikt/core/tokens/darkside/figma/figma-config.types.ts

Co-authored-by: Halvor Haugan <83693529+HalvorHaugan@users.noreply.github.com>

* ♻️ Use colorRole-array as bases for Role array

---------

Co-authored-by: Halvor Haugan <83693529+HalvorHaugan@users.noreply.github.com>
2024-12-13 13:37:42 +01:00
Halvor Haugan 1f9a343afc Combobox: Fix issue where you could select more options than defined in maxSelected (#3434) 2024-12-12 12:59:39 +01:00
Ken f026817dd3 [Darkside] Tailwind darkside file export (#3431)
* ✨ Added darkside export to tailwind package

* 🚚 Move darkside build-script to separate script

* 🐛 Avoid using darkside for website yet
2024-12-12 12:24:04 +01:00
Ken 36190f7657 📝 Update Textfield example for readonly after feedback (#3448) 2024-12-11 16:30:22 +01:00
Ken f12070842a [Darkside]: 🐛 Remove 'state'-tokens from new Box-component 2024-12-11 11:42:48 +01:00
Ken 601e1569f8 [Darkside]: Updated gap between text and icon in Link 2024-12-11 09:25:56 +01:00
Ken f7452d5d0d [Darkside]: Added darkmode-support to Tooltip (#3442) 2024-12-11 09:21:54 +01:00
github-actions[bot]andgithub-actions[bot] 04e65c701c Version Packages (#3439)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-09 15:42:28 +01:00
Halvor Haugan 878ee68e5c ✨ Release i18n support (#3429)
- Merged LanguageProvider into Provider, while also changing the API a bit to make it easier to use (with the help of TS).
- Updated tests for `useI18n()` according to changes in API.
- Chips.Removable: Removed prop `removeLabel`.
- DatePicker/MonthPicker: Added new `translations` prop and deprecated `locale` prop.
- Search: Deprecated prop `clearButtonLabel`.
- Textarea: Deprecated prop `i18n`.
- Timeline: Deprecated prop `axisLabelTemplates`.
- nb/nn/en.ts:
  - Arranged the top level keys alphabetically.
  - Merged `close` in Modal and DatePicker and put it under the `global` key.
  - Changed Search.clear from "Clear" to "Clear field" to make it more... clear 😅
  - Removed Combobox.clear since the clear button has been removed.
  - Made them importable from `@navikt/ds-react`
2024-12-09 15:38:49 +01:00
Ken ade48469dd [Darkside]: Secondary-button defaults to bg-input 2024-12-09 13:43:12 +01:00
Julian NymarkandKen cbea73abda [Darkside] GuidePanel CSS update (#3403)
* GuidePanel initial CSS rewrite

* ✨ new illustration

* change: layout

* change: add speechbubble arrow

* change: dark mode raised for speechbubble arrow

* change: correct stroke path color (actually fill) of path in svg

* change: fine tuned SVG with padding and overlapping paths

* change: exception CSS for FF rendering of speech bubble tail

* change: hardcode calculation as whole pixel value remove FF custom CSS

* change: convert BEM modifiers to simpler CSS data-attributes

* change: display:none for speech bubble tail on old token system

* change: refactor old css to use the attribute selectors

* change: noSVG example (see default story for side-by-side)

* change: rewrite to using only SVG for speechbubble

* change: only looks good in lightmode, no token support / hardcoded

* :refactor: Updated Guidepanel CSS to use SVG

* 🔥 Remove old commented CSS

* 🐛 Fixed cases where mediaqueries would target nesten element instead of itself

* 🗑️ Cleanup of unused code

---------

Co-authored-by: Ken <ken.aleksander@gmail.com>
2024-12-09 12:23:54 +01:00
Ken fd2e65e790 ✨ Stop page-scroll when previewing compoment-examples to reduce noise 2024-12-06 20:44:56 +01:00
Halvor HauganandKen f720562908 Combobox: Removed clear button, deprecated props clearButton/clearButtonLabel, changed maxSelected to number. (#3433)
Co-authored-by: Ken <26967723+KenAJoh@users.noreply.github.com>
2024-12-06 16:33:45 +01:00
KenandHalvor Haugan 5dedfa104a 🐛 Complete CSS-build was included in components.css bundle (#3427)
* 🐛 Complete CSS-build was included in components bundle

* Update .changeset/thick-tools-behave.md

Co-authored-by: Halvor Haugan <83693529+HalvorHaugan@users.noreply.github.com>

---------

Co-authored-by: Halvor Haugan <83693529+HalvorHaugan@users.noreply.github.com>
2024-12-06 16:18:04 +01:00
Ken 0189bd7b4a [Darkside] Table CSS update (#3396)
* ✨ Added darkmode support to table

* 📝 Added comments

* 📝 Added todo

* :refactor: Avoid use of custom animate height function

* :refactor: Use Alpha-token on hover-selected

* :refactor: Remove redundant token-use

* Update @navikt/core/css/table.css

* ♻️ Reverted to animate-component for table animation
2024-12-06 15:49:50 +01:00
Halvor Haugan 119d699ff2 Fix Combobox example 'react-hook-form' (#3436) 2024-12-06 15:01:43 +01:00
272 changed files with 4018 additions and 2609 deletions

No files matched your search

+1 -1
View File
@@ -42,7 +42,7 @@ jobs:
yarn boot
yarn workspace aksel.nav.no build:next
- name: Upload static files to NAV CDN
- name: Upload static files to Nav CDN
uses: nais/deploy/actions/cdn-upload/v2@master
with:
team: designsystem
+1 -1
View File
@@ -74,7 +74,7 @@ jobs:
SANITY_READ_NO_DRAFTS: ${{ secrets.SANITY_READ_NO_DRAFTS }}
run: yarn workspace aksel.nav.no build:next
- name: Upload static files to NAV CDN
- name: Upload static files to Nav CDN
uses: nais/deploy/actions/cdn-upload/v2@master
with:
team: designsystem
+9 -22
View File
@@ -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
+2 -2
View File
@@ -78,7 +78,7 @@ jobs:
if: steps.changesets.outputs.published == 'true'
run: yarn zip:icons
- name: Upload updated icon.zip to NAV CDN
- name: Upload updated icon.zip to Nav CDN
if: steps.changesets.outputs.published == 'true'
uses: nais/deploy/actions/cdn-upload/v2@master
with:
@@ -94,7 +94,7 @@ jobs:
echo "version=$VERSION" >> $GITHUB_ENV
echo "Version of @navikt/ds-css: ${{ env.version }}"
- name: Upload CSS to NAV CDN
- name: Upload CSS to Nav CDN
if: steps.changesets.outputs.published == 'true'
uses: nais/deploy/actions/cdn-upload/v2@master
with:
+2 -2
View File
@@ -11,7 +11,7 @@ import Setup from "./assets/setup.png";
# Getting started
Aksel is the toolbox for product development <a href="https://aksel.nav.no"target="_blank">@NAV</a> (Norwegian Labour and Welfare Administration)
Aksel is the toolbox for product development <a href="https://aksel.nav.no"target="_blank">@Nav</a> (Norwegian Labour and Welfare Administration)
This includes a designsystem, best practices for product-development, principles for user-experience and a blog. <a href="https://aksel.nav.no/god-praksis/artikler/om-aksel" target="_blank">
Read more about Aksel.</a>
@@ -30,7 +30,7 @@ import Setup from "./assets/setup.png";
target="_blank"
className="sb-link"
>Website</a></h3>
<p className="sb-section-item-paragraph">Includes everything you need to get started building and developing digital products for NAV today.</p>
<p className="sb-section-item-paragraph">Includes everything you need to get started building and developing digital products for Nav today.</p>
</div>
<div className="sb-section-item">
+7 -9
View File
@@ -2,11 +2,11 @@ import { withThemeByClassName } from "@storybook/addon-themes";
import { Preview } from "@storybook/react";
import React, { useLayoutEffect } from "react";
// @ts-expect-error - Temporary
import darksideCss from "@navikt/ds-css/darkside/index.css?inline";
import darksideCss from "../@navikt/core/css/darkside/index.css?inline";
// @ts-expect-error - Temporary
import defaultCss from "@navikt/ds-css/index.css?inline";
import { UNSAFE_AkselTheme } from "../@navikt/core/react/src/provider";
import UNSAFE_AkselLanguageProvider from "../@navikt/core/react/src/provider/i18n/LanguageProvider";
import defaultCss from "../@navikt/core/css/index.css?inline";
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";
@@ -29,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
);
@@ -46,9 +46,7 @@ const translations = {
const LanguageDecorator = ({ children, language }) => {
if (language) {
return (
<UNSAFE_AkselLanguageProvider translations={translations[language]}>
{children}
</UNSAFE_AkselLanguageProvider>
<Provider translations={translations[language]}>{children}</Provider>
);
}
return children;
+6
View File
@@ -1,5 +1,11 @@
# @navikt/aksel-icons
## 7.9.0
## 7.8.1
## 7.8.0
## 7.7.0
## 7.6.0
+3 -3
View File
@@ -1,7 +1,7 @@
{
"name": "@navikt/aksel-icons",
"version": "7.7.0",
"author": "Aksel | NAV",
"version": "7.9.0",
"author": "Aksel | Nav",
"homepage": "https://aksel.nav.no/ikoner",
"repository": {
"type": "git",
@@ -10,7 +10,7 @@
},
"keywords": [
"Icons",
"NAV",
"Nav",
"Aksel",
"designsystem",
"react",
+10
View File
@@ -1,5 +1,15 @@
# @navikt/aksel-stylelint
## 7.9.0
## 7.8.1
## 7.8.0
### Minor Changes
- Combobox: Removed clear button, removed tokens staring with `--ac-combobox-clear`, deprecated props `clearButton`/`clearButtonLabel`. ([#3433](https://github.com/navikt/aksel/pull/3433))
## 7.7.0
## 7.6.0
+4 -4
View File
@@ -1,7 +1,7 @@
{
"name": "@navikt/aksel-stylelint",
"version": "7.7.0",
"author": "Aksel | NAV",
"version": "7.9.0",
"author": "Aksel | Nav",
"homepage": "https://aksel.nav.no/grunnleggende/kode/stylelint",
"repository": {
"type": "git",
@@ -35,8 +35,8 @@
"dev": "yarn watch:lint"
},
"devDependencies": {
"@navikt/ds-css": "^7.7.0",
"@navikt/ds-tokens": "^7.7.0",
"@navikt/ds-css": "^7.9.0",
"@navikt/ds-tokens": "^7.9.0",
"concurrently": "9.0.1",
"postcss-selector-parser": "^6.0.13",
"postcss-value-parser": "^4.2.0",
@@ -72,4 +72,8 @@ export const deprecations: DeprecatedList = [
classes: ["navds-list--nested", "navds-list__item-content"],
message: "Removed in v7.1.1",
},
{
classes: ["navds-combobox__button-clear"],
message: "Removed in v7.8.0",
},
];
+21
View File
@@ -1,5 +1,26 @@
# @navikt/aksel
## 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
- Updated dependencies [[`06193ae`](https://github.com/navikt/aksel/commit/06193ae3001cee4b1f411a75d51ab54391483dd7), [`a82126b`](https://github.com/navikt/aksel/commit/a82126b893490b9786d31cb74ba31695b90f8c60)]:
- @navikt/ds-css@7.8.1
## 7.8.0
### Patch Changes
- Updated dependencies [[`f720562`](https://github.com/navikt/aksel/commit/f720562908ccb0c7c62cabd386920d0c1fdcdaf9), [`5dedfa1`](https://github.com/navikt/aksel/commit/5dedfa104a187d23e3028ffa2b4a85e44e206b31)]:
- @navikt/ds-css@7.8.0
## 7.7.0
### Patch Changes
+3 -3
View File
@@ -1,8 +1,8 @@
{
"name": "@navikt/aksel",
"version": "7.7.0",
"version": "7.9.0",
"description": "Aksel command line interface. Handles css-imports, codemods and more",
"author": "Aksel | NAV designsystem team",
"author": "Aksel | Nav designsystem team",
"license": "MIT",
"keywords": [
"Commandline",
@@ -29,7 +29,7 @@
},
"homepage": "https://aksel.nav.no/grunnleggende/kode/kommandolinje",
"dependencies": {
"@navikt/ds-css": "7.7.0",
"@navikt/ds-css": "7.9.0",
"axios": "1.7.4",
"chalk": "4.1.0",
"clipboardy": "^2.3.0",
+33
View File
@@ -1,5 +1,38 @@
# @navikt/ds-css
## 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
- Alert: Link-components used within Alert variant='inline' now preserves default coloring ([#3461](https://github.com/navikt/aksel/pull/3461))
- Table: :fire: Removed cursor 'pointer' when 'ExpandableRow' is disabled. ([#3462](https://github.com/navikt/aksel/pull/3462))
## 7.8.0
### Minor Changes
- Combobox: Removed clear button, removed tokens staring with `--ac-combobox-clear`, deprecated props `clearButton`/`clearButtonLabel`. ([#3433](https://github.com/navikt/aksel/pull/3433))
### Patch Changes
- CSS: Resolved regression where the complete stylesheet was included in scoped 'components.css' file. ([#3427](https://github.com/navikt/aksel/pull/3427))
## 7.7.0
## 7.6.0
+9 -1
View File
@@ -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;
+270
View File
@@ -0,0 +1,270 @@
import browserslist from "browserslist";
import CleanCss from "clean-css";
import fastglob from "fast-glob";
import fs from "fs";
import { Features, browserslistToTargets, bundleAsync } from "lightningcss";
import path from "path";
import {
StyleMappings,
componentsCss,
formCss,
primitivesCss,
} from "../config/_mappings";
import packageJSON from "../package.json";
bundleDarkside();
async function bundleDarkside() {
const buildDir = path.join(__dirname, "..", "dist/darkside");
const darksideDir = path.join(__dirname, "..", "darkside");
/* Make sure every dir is created to make node happy */
[buildDir, `${buildDir}/global`, `${buildDir}/component`].forEach((dir) => {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
});
/**
* Bundles the ./index.css file with LightningCSS.
* @param rootParser: Custom parsers that allows for editing the index.css file before bundling it. This allows removing unwanted CSS from being bundled.
* @returns Parsed CSS file output. Must be valid CSS.
*/
async function bundleCSS(rootParser?: (rootFile: string) => string) {
const { code } = await bundleAsync({
filename: `${darksideDir}/index.css`,
minify: false,
include:
Features.Nesting | Features.MediaRangeSyntax | Features.HexAlphaColors,
drafts: {
customMedia: false,
},
targets: browserslistToTargets(
browserslist(">= 0.5% in NO, safari >= 15.4, iOS >= 15.4, not dead"),
),
resolver: {
read(filePath) {
const file = fs.readFileSync(filePath, "utf8");
if (filePath === `${darksideDir}/index.css` && rootParser) {
return rootParser(file);
}
return file;
},
},
});
let codeString = code.toString();
/**
* LightningCSS adds these tokens to the bundle that we want removed:
* --lightningcss-light: initial;
* --lightningcss-dark: ;
*/
codeString = codeString
.split("\n")
.filter((line) => !line.includes("--lightningcss-"))
.join("\n");
return codeString;
}
/**
* Writes the CSS file to the build directory. Includes a minified version with the .min.css suffix.
* @param file: CSS file content
* @param filePath: Path to the file in the build directory
*/
function writeFile({ file, filePath }: { file: string; filePath: string }) {
fs.writeFileSync(`${buildDir}/${filePath}`, file);
/**
* We use CleanCss package here since we only want it to optimize filesize, not transform any CSS like LightningCSS minifier does.
* This is because we want to keep the CSS as close to the original as possible.
* Since CleanCSS is not part of the PostCSS ecosystem, we use it in replacement for cssnano.
*/
const minifiedCss = new CleanCss({}).minify(file);
if (minifiedCss.errors.length > 0) {
throw new Error(
`Errors found when minifying for ${filePath} CSS. Stopped bundling\n${minifiedCss.errors}`,
);
}
fs.writeFileSync(
`${buildDir}/${filePath.replace(".css", ".min.css")}`,
minifiedCss.styles,
);
}
/* ----------------------------- index.css build ---------------------------- */
await bundleCSS().then((file) => {
writeFile({
file,
filePath: "index.css",
});
});
/* --------------------------- component.css build -------------------------- */
function rootComponentsParser(rootString: string) {
let parsed = rootString
.split("\n")
.filter((line) => {
/* We assume that all components is added under the layer components or layout */
return (
line.endsWith("layer(aksel.components);") ||
line.endsWith("layer(aksel.layout);")
);
})
.join("\n");
/* If one imports this file standalone, we would like to make sure the layering order is included. */
const layerDefinition = rootString
.split("\n")
.find((line) => line.startsWith("@layer"));
if (!layerDefinition) {
throw new Error(
"No layer definition found in index.css. Stopped bundling",
);
}
parsed = layerDefinition + "\n" + parsed;
return parsed;
}
await bundleCSS(rootComponentsParser).then((file) => {
writeFile({
file,
filePath: componentsCss,
});
});
/* ------------------------------ /global build ----------------------------- */
for (const style of StyleMappings.baseline) {
// eslint-disable-next-line no-inner-declarations
function parser(input: string) {
return input
.split("\n")
.filter((line) => line.startsWith("@import"))
.filter((line) =>
line.replace(".darkside.css", ".css").includes(style.main),
)
.join("\n");
}
await bundleCSS(parser).then((file) => {
writeFile({
file,
filePath: `global/${style.main}`,
});
});
}
/* ------------------------------ form build ----------------------------- */
function rootFormParser(input: string) {
return input
.split("\n")
.filter((line) => line.startsWith("@import"))
.filter((line) => line.includes("form/index.css"))
.join("\n");
}
await bundleCSS(rootFormParser).then((file) => {
writeFile({
file,
filePath: `component/${formCss}`,
});
});
/* ------------------------------ Primitives build ----------------------------- */
function rootPrimitivesParser(input: string) {
return input
.split("\n")
.filter((line) => line.startsWith("@import"))
.filter((line) => line.includes("primitives/index.css"))
.join("\n");
}
await bundleCSS(rootPrimitivesParser).then((file) => {
writeFile({
file,
filePath: `component/${primitivesCss}`,
});
});
/* ---------------------------- /component build ---------------------------- */
function componentFiles(): string[] {
const indexFile = fs.readFileSync(`${darksideDir}/index.css`, "utf8");
/* Since forms and primitives is under the same layers, but diffferent files we filter them out to avoid duplicates */
const formLine = rootFormParser(indexFile);
const primitivesLine = rootPrimitivesParser(indexFile);
return indexFile
.split("\n")
.filter((line) => line.startsWith("@import"))
.filter((line) => !formLine.includes(line))
.filter((line) => !primitivesLine.includes(line))
.filter((line) => line.endsWith("layer(aksel.components);"));
}
for (const componentLine of componentFiles()) {
// eslint-disable-next-line no-inner-declarations
function parser(input: string) {
return input
.split("\n")
.filter((line) => line === componentLine)
.join("\n");
}
await bundleCSS(parser).then((file) => {
const componentName = componentLine
/* Matches everything between " */
.match(/".*"/gm)?.[0]
/* Replaces every " with nothing */
.replace(/"/gm, "")
/* Removes start of import-string */
.replace("./", "")
.replace(".darkside.css", ".css");
if (!componentName) {
throw new Error(
`Could not find component name for line: ${componentLine}`,
);
}
const sanitizedName = componentName
/*
* https://regex101.com/r/MAj58n/1
* Removes every - and space
*/
.replace(/[\s-]/g, "")
.replace(".css", "")
.toLowerCase();
writeFile({
file,
filePath: `component/${sanitizedName}.css`,
});
});
}
const version = packageJSON.version;
const files = fastglob.sync("**/*.css", {
cwd: buildDir,
ignore: ["**/version/**"],
});
for (const file of files) {
const css = fs.readFileSync(`${buildDir}/${file}`, "utf-8");
const filename = `${buildDir}/version/${version}/${file}`;
fs.mkdirSync(path.dirname(filename), { recursive: true });
fs.writeFileSync(filename, css);
}
}
+9 -2
View File
@@ -66,7 +66,13 @@ async function bundleComponents() {
const css = fs.readFileSync(indexSrc);
/* Remove @charset, baseline */
const cssString = css.toString().split("\n").slice(2).join("\n");
const cssString = css
.toString()
.split("\n")
.filter((line) => {
return line.startsWith("@import") && !line.includes("baseline");
})
.join("\n");
const result = await postcss([cssImports, combineSelectors]).process(
cssString,
@@ -102,6 +108,7 @@ function buildFragmentFiles() {
const files = fastglob
.sync("*.css", { cwd: ".", ignore: "**/*.min.css" })
.map((fileN) => path.basename(fileN))
.filter((fileName) => !fileName.includes("index.css"))
.map((x) => ({
input: path.resolve(__dirname, `../${x}`),
output: path.resolve(
@@ -154,7 +161,7 @@ async function bundleMinified() {
function copyToVersionFolder() {
const files = fastglob.sync("**/*.css", {
cwd: `./${rootDir}`,
ignore: "**/version/**",
ignore: ["**/version/**", "**/darkside/**"],
});
for (let file of files) {
@@ -0,0 +1,46 @@
import fastglob from "fast-glob";
import path from "path";
import { describe, expect, test } from "vitest";
/**
* Darkside config might have some new files added. We can skip these when checking for equality.
*/
const newFiles = ["theme"];
describe("Check that old and new (darkside) bundle matches", () => {
test("Darkside includes the same files as old bundle", () => {
const oldBundleDir = path.join(__dirname, "../../dist");
const darksideDir = path.join(__dirname, "../../dist/darkside");
const oldFiles = fastglob.sync("**/*.css", {
cwd: oldBundleDir,
ignore: ["**/version/**", "**/darkside/**"],
});
const darksideFiles = fastglob.sync("**/*.css", {
cwd: darksideDir,
ignore: ["**/version/**"],
});
expect(oldFiles.length).toBeGreaterThan(0);
expect(darksideFiles.length).toBeGreaterThan(0);
// Compare file names
oldFiles.forEach((file) => {
expect(darksideFiles).toContain(file);
});
darksideFiles.forEach((file) => {
if (newFiles.find((newFile) => file.includes(newFile))) {
return;
}
expect(oldFiles).toContain(file);
});
/**
* Check that darkside has the same amount of files as old bundle
* (minus the new files * 2 since .min.css is also included)
*/
expect(darksideFiles.length - newFiles.length * 2).toBe(oldFiles.length);
});
});
@@ -1,3 +1,12 @@
/* ------------------------- Global typo-definitions ------------------------ */
body,
:host {
font-family: var(--ax-font-family, "Source Sans 3", "Source Sans Pro", Arial, sans-serif);
line-height: 1.333;
font-size: 1.125rem;
}
/* ---------------------------- Inline utilities ---------------------------- */
[hidden] {
display: none !important;
}
@@ -0,0 +1 @@
@import "../../../tokens/dist/darkside/tokens.css";
+10 -2
View File
@@ -69,7 +69,7 @@
margin-right: var(--__axc-button-icon-margin);
}
&:only-child {
.navds-button--icon-only & {
margin: 0;
}
}
@@ -260,10 +260,14 @@
}
.navds-button:not(.navds-button--loading):where(:disabled, .navds-button--disabled) {
opacity: 0.3;
opacity: var(--ax-opacity-disabled);
}
/* 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;
@@ -31,7 +31,7 @@
&:disabled {
cursor: not-allowed;
opacity: 0.3;
opacity: var(--ax-opacity-disabled);
}
&:disabled:hover {
@@ -74,7 +74,7 @@
.navds-dropdown__item:disabled {
color: var(--ac-dropdown-item-text, var(--a-text-action));
opacity: 0.3;
opacity: var(--ax-opacity-disabled);
background: transparent;
cursor: not-allowed;
}
@@ -28,7 +28,7 @@
}
.navds-combobox--disabled {
opacity: 0.3;
opacity: var(--ax-opacity-disabled);
& .navds-combobox__wrapper {
& *:hover {
@@ -69,7 +69,6 @@
}
}
.navds-combobox__button-clear svg,
.navds-combobox__button-toggle-list svg,
.navds-combobox__list svg {
width: var(--__axc-combobox-icon-size);
@@ -203,19 +202,6 @@
}
}
.navds-combobox__button-clear {
border-radius: var(--ax-border-radius-medium);
color: var(--ax-text-subtle);
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
background: none;
border: none;
font-size: 1rem;
padding: 0;
}
.navds-combobox__input::-webkit-search-cancel-button {
display: none;
}
@@ -231,10 +217,7 @@
border: none;
font-size: 1rem;
padding: 0;
}
.navds-combobox__button-clear,
.navds-combobox__button-toggle-list {
&:hover {
color: var(--ax-text-accent);
@@ -405,10 +388,6 @@
}
@media (forced-colors: active) {
.navds-combobox__button-clear:hover {
color: highlight;
}
.navds-combobox__wrapper-inner:has(.navds-combobox__input:focus-visible) {
outline-color: highlight;
}
@@ -32,7 +32,7 @@
.navds-fieldset:disabled > .navds-fieldset__legend,
.navds-fieldset:disabled > .navds-fieldset__description {
opacity: 0.3;
opacity: var(--ax-opacity-disabled);
}
@media (forced-colors: active) {
@@ -9,21 +9,8 @@
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: 0.3;
opacity: var(--ax-opacity-disabled);
cursor: not-allowed;
}
@@ -41,7 +28,7 @@
.navds-form-field__readonly-icon {
margin-top: var(--ax-spacing-05);
margin-right: var(--ax-spacing-2);
margin-right: var(--ax-spacing-1);
flex-shrink: 0;
align-self: flex-start;
}
@@ -172,7 +172,7 @@
.navds-checkbox--disabled,
.navds-radio--disabled {
opacity: 0.3;
opacity: var(--ax-opacity-disabled);
}
.navds-checkbox--disabled > .navds-checkbox__input,
@@ -81,7 +81,7 @@
font-size: 1.5rem;
.navds-search--disabled & {
opacity: 0.3;
opacity: var(--ax-opacity-disabled);
}
}
@@ -105,6 +105,10 @@
--__axc-button-border-width: 1px;
--__axc-button-border-color: var(--ax-border-default);
&:not(:hover, :active) {
background-color: var(--ax-bg-input);
}
&:hover:not(:disabled) {
--__axc-button-border-color: var(--ax-border-accent-strong);
}
@@ -144,7 +148,7 @@
/* We can't re-use disabled-state for form-fields since opacity multiplies on search-button */
.navds-search--disabled {
.navds-search__input {
opacity: 0.3;
opacity: var(--ax-opacity-disabled);
cursor: not-allowed;
}
}
@@ -169,7 +169,7 @@
}
.navds-switch--disabled:not(.navds-switch--loading) {
opacity: 0.3;
opacity: var(--ax-opacity-disabled);
}
.navds-switch__input:disabled,
@@ -1,20 +1,41 @@
.navds-guide-panel {
--__ac-guide-panel-guide-size: 4rem;
--__axc-guide-panel-guide-size: 3.75rem;
position: relative;
padding-top: calc(var(--__ac-guide-panel-guide-size) / 2);
display: flex;
width: fit-content;
&[data-poster="true"],
&[data-responsive="true"] {
flex-direction: column;
align-items: center;
}
&[data-poster="false"] {
flex-direction: row;
align-items: flex-start;
}
@media (min-width: 480px) {
& {
--__axc-guide-panel-guide-size: 5rem;
}
&[data-responsive="true"] {
flex-direction: row;
align-items: flex-start;
}
}
}
.navds-guide {
background: var(--ac-guide-panel-illustration-bg, var(--a-surface-alt-3-subtle));
border: 2px solid var(--ac-guide-panel-border, var(--a-border-alt-3));
border-radius: var(--a-border-radius-full);
box-sizing: border-box;
border: 2px solid var(--ax-border-info);
border-radius: var(--ax-border-radius-full);
overflow: hidden;
position: absolute;
width: var(--__ac-guide-panel-guide-size);
height: var(--__ac-guide-panel-guide-size);
left: 50%;
transform: translate(-50%, -50%);
width: var(--__axc-guide-panel-guide-size);
height: var(--__axc-guide-panel-guide-size);
flex-shrink: 0;
}
.navds-guide svg,
@@ -24,73 +45,70 @@
}
.navds-guide-panel__content {
background-color: var(--ac-guide-panel-bg, var(--a-surface-default));
border: 2px solid var(--ac-guide-panel-border, var(--a-border-alt-3));
border-radius: var(--a-border-radius-large);
padding: var(--a-spacing-4);
padding-top: var(--a-spacing-12);
}
background-color: var(--ax-bg-raised);
border: 2px solid var(--ax-border-info);
border-radius: var(--ax-border-radius-xlarge);
position: relative;
@media (min-width: 480px) {
.navds-guide-panel {
--__ac-guide-panel-guide-size: 6.25rem;
.navds-guide-panel:is([data-poster="true"], [data-responsive="true"]) > & {
margin-top: var(--ax-spacing-5);
}
.navds-guide-panel__content {
padding: var(--a-spacing-8);
padding-top: 4.25rem;
.navds-guide-panel[data-poster="false"] > & {
margin-left: var(--ax-spacing-5);
}
@media (min-width: 480px) {
.navds-guide-panel[data-responsive="true"] > & {
margin-top: 0;
margin-left: var(--ax-spacing-5);
}
}
}
/* not-poster */
.navds-guide-panel__content-inner {
padding: var(--ax-spacing-3) var(--ax-spacing-4);
border-radius: var(--ax-border-radius-xlarge);
background-color: var(--ax-bg-raised);
position: relative;
height: 100%;
.navds-guide-panel--not-poster {
padding-top: 0;
padding-left: calc(var(--__ac-guide-panel-guide-size) / 2);
}
.navds-guide-panel--not-poster .navds-guide {
left: 0;
top: var(--a-spacing-5);
transform: none;
}
.navds-guide-panel--not-poster .navds-guide-panel__content {
padding: var(--a-spacing-4);
padding-left: var(--a-spacing-10);
min-height: calc(var(--__ac-guide-panel-guide-size) + var(--a-spacing-5) + var(--a-spacing-5));
}
@media (min-width: 480px) {
.navds-guide-panel--not-poster {
--__ac-guide-panel-guide-size: 5rem;
.navds-guide-panel[data-poster="false"] & {
min-height: var(--__axc-guide-panel-guide-size);
}
.navds-guide-panel--not-poster .navds-guide-panel__content {
padding: var(--a-spacing-6);
padding-left: var(--a-spacing-14);
@media (min-width: 480px) {
& {
padding: var(--ax-spacing-4) var(--ax-spacing-5);
}
.navds-guide-panel[data-responsive="true"] & {
min-height: var(--__axc-guide-panel-guide-size);
}
}
}
/* responsive-poster (on desktop) */
.navds-guide-panel__tail {
position: absolute;
z-index: 0;
@media (min-width: 480px) {
.navds-guide-panel--responsive-poster {
--__ac-guide-panel-guide-size: 5rem;
padding-top: 0;
padding-left: calc(var(--__ac-guide-panel-guide-size) / 2);
.navds-guide-panel:is([data-poster="true"], [data-responsive="true"]) & {
left: 50%;
top: calc(var(--ax-spacing-4) * -1 - 2px);
transform: translateX(-48%);
}
.navds-guide-panel--responsive-poster .navds-guide {
left: 0;
top: var(--a-spacing-5);
transform: none;
.navds-guide-panel[data-poster="false"] & {
top: calc(var(--__axc-guide-panel-guide-size) / 2);
left: calc(var(--ax-spacing-5) * -1 - 2px);
transform: translateY(-48%) rotateZ(-90deg) scaleX(-1);
}
.navds-guide-panel--responsive-poster .navds-guide-panel__content {
padding: var(--a-spacing-6);
padding-left: var(--a-spacing-14);
min-height: calc(var(--__ac-guide-panel-guide-size) + var(--a-spacing-5) + var(--a-spacing-5));
@media (min-width: 480px) {
.navds-guide-panel[data-responsive="true"] & {
top: calc(var(--__axc-guide-panel-guide-size) / 2);
left: calc(var(--ax-spacing-5) * -1 - 2px);
transform: translateY(-48%) rotateZ(-90deg) scaleX(-1);
}
}
}
-37
View File
@@ -1,37 +0,0 @@
@charset "UTF-8";
@import "baseline/index.css";
@import "typography.css";
@import "accordion.css";
@import "alert.css";
@import "button.css";
@import "chat.css";
@import "chips.css";
@import "copybutton.css";
@import "dropdown.css";
@import "action-menu.css";
@import "expansioncard.css";
@import "guide-panel.css";
@import "form/index.css";
@import "help-text.css";
@import "internalheader.css";
@import "link.css";
@import "loader.css";
@import "modal.css";
@import "pagination.css";
@import "popover.css";
@import "date.css";
@import "tag.css";
@import "timeline.css";
@import "tooltip.css";
@import "toggle-group.css";
@import "panel.css";
@import "link-panel.css";
@import "read-more.css";
@import "progress-bar.css";
@import "skeleton.css";
@import "stepper.css";
@import "table.css";
@import "tabs.css";
@import "list.css";
@import "primitives/index.css";
+9 -11
View File
@@ -1,23 +1,23 @@
@charset "UTF-8";
/* CSS is ordered by specificity, so that browsers without layers fall backs to good defaults */
@layer aksel.reset, aksel.typography, aksel.theme, aksel.components, aksel.layout, aksel.utilities;
@layer aksel.reset, aksel.theming, aksel.baseline, aksel.print, aksel.typography, aksel.components, aksel.layout;
/* ----------------------------- CSS foundations ---------------------------- */
@import "./baseline/reset.darkside.css" layer(aksel.reset);
@import "./baseline/print.darkside.css" layer(aksel.reset);
@import "./baseline/fonts.darkside.css" layer(aksel.typography);
@import "./typography.darkside.css" layer(aksel.typography);
/* --------------------------------- Theming -------------------------------- */
@import "@navikt/ds-tokens/dist/darkside/tokens.css" layer(aksel.theme);
@import "./baseline/theme.darkside.css" layer(aksel.theme);
@import "./baseline/reset.darkside.css" layer(aksel.reset);
@import "./baseline/tokens.darkside.css" layer(aksel.theming);
@import "./baseline/baseline.darkside.css" layer(aksel.baseline);
@import "./baseline/print.darkside.css" layer(aksel.print);
/* ------------------------------- Components ------------------------------- */
@import "./typography.darkside.css" layer(aksel.components);
@import "./button.darkside.css" layer(aksel.components);
@import "./chips.darkside.css" layer(aksel.components);
/**
* Most components depend on typo-styles, so we import them first.
*
* `./form/index.css` edits the following components:
* - Button
* - Chips
@@ -53,9 +53,7 @@
@import "./table.darkside.css" layer(aksel.components);
@import "./tabs.darkside.css" layer(aksel.components);
@import "./list.darkside.css" layer(aksel.components);
@import "./theme.darkside.css" layer(aksel.components);
/* --------------------------------- Layout --------------------------------- */
@import "./primitives/index.css" layer(aksel.layout);
/* --------------------------------- Utility -------------------------------- */
@import "./baseline/utilities.darkside.css" layer(aksel.utilities);
+2 -2
View File
@@ -2,7 +2,7 @@
color: var(--ax-text-accent);
display: inline-flex;
align-items: center;
gap: var(--ax-spacing-1);
gap: var(--ax-spacing-05);
text-decoration: underline;
text-underline-offset: 0.1em;
text-decoration-thickness: 0.05em;
@@ -43,7 +43,7 @@
}
}
.navds-alert,
.navds-alert:not(.navds-alert--inline),
.navds-confirmation-panel {
& .navds-link {
color: var(--ax-text-default);
+53 -98
View File
@@ -10,43 +10,44 @@
.navds-table__body {
display: table-row-group;
& .navds-table__row--shade-on-hover:not(.navds-table__expandable-row--expansion-disabled):hover {
background-color: var(--ax-bg-neutral-hoverA);
transition: background-color 70ms cubic-bezier(0.2, 0, 0, 1);
}
& .navds-table__row--shade-on-hover.navds-table__row--selected:hover {
background-color: var(--ax-bg-accent-hoverA);
}
}
.navds-table__row {
display: table-row;
}
.navds-table__body .navds-table__row--shade-on-hover:not(.navds-table__expandable-row--expansion-disabled):hover {
background-color: var(--ac-table-row-hover, var(--a-bg-subtle));
}
.navds-table__row--selected {
background-color: var(--ac-table-row-selected, var(--a-surface-action-subtle));
background-color: var(--ax-bg-accent);
}
.navds-table__body .navds-table__row--shade-on-hover.navds-table__row--selected:hover {
background-color: var(--ac-table-row-selected-hover, var(--a-surface-action-subtle-hover));
}
.navds-table--zebra-stripes {
& .navds-table__body :where(.navds-table__row:nth-child(odd):not(.navds-table__row--selected)) {
background-color: var(--ax-bg-neutral);
}
.navds-table--zebra-stripes .navds-table__body :where(.navds-table__row:nth-child(odd):not(.navds-table__row--selected)) {
background-color: var(--ac-table-row-zebra, var(--a-surface-subtle));
}
.navds-table--zebra-stripes
.navds-table__body
:where(.navds-table__expandable-row:nth-child(4n + 1):not(.navds-table__row--selected)) {
background-color: transparent;
& .navds-table__body :where(.navds-table__expandable-row:nth-child(4n + 1):not(.navds-table__row--selected)) {
background-color: transparent;
}
}
.navds-table--zebra-stripes .navds-table__body .navds-table__expanded-row:nth-child(4n) {
background-color: var(--ac-table-row-zebra, var(--a-surface-subtle));
background-color: var(--ax-bg-neutral);
}
.navds-table__header-cell,
.navds-table__data-cell {
display: table-cell;
padding: var(--a-spacing-3) var(--a-spacing-2);
border-bottom: 1px solid var(--ac-table-row-border, var(--a-border-default));
padding: var(--ax-spacing-3) var(--ax-spacing-2);
border-bottom: 1px solid var(--ax-border-default);
text-align: left;
}
@@ -67,7 +68,7 @@
:where(.navds-table__body .navds-table__row--shade-on-hover:hover) .navds-table__header-cell,
:where(.navds-table__body .navds-table__row--shade-on-hover:hover) .navds-table__data-cell {
border-color: var(--ac-table-cell-hover-border, var(--a-border-strong));
border-color: var(--ax-border-strong);
}
:where(.navds-table__expandable-row--open:hover) .navds-table__data-cell {
@@ -76,12 +77,12 @@
.navds-table--large .navds-table__header-cell,
.navds-table--large .navds-table__data-cell {
padding: var(--a-spacing-4) var(--a-spacing-2);
padding: var(--ax-spacing-4) var(--ax-spacing-2);
}
.navds-table--small .navds-table__header-cell,
.navds-table--small .navds-table__data-cell {
padding: var(--a-spacing-1) var(--a-spacing-2);
padding: var(--ax-spacing-1) var(--ax-spacing-2);
}
.navds-table :not(.navds-checkboxes) > .navds-checkbox .navds-checkbox__input {
@@ -103,43 +104,36 @@
.navds-table__sort-button {
appearance: none;
background: none;
color: var(--ac-table-sort-button-text, var(--a-text-action));
color: var(--ax-text-accent);
border: none;
cursor: pointer;
margin: 0;
padding: var(--a-spacing-4) var(--a-spacing-3);
padding: var(--ax-spacing-4) var(--ax-spacing-3);
width: 100%;
display: flex;
gap: var(--a-spacing-2);
gap: var(--ax-spacing-2);
align-items: center;
line-height: inherit;
font-weight: inherit;
}
.navds-table--small .navds-table__sort-button {
padding: var(--a-spacing-2) var(--a-spacing-3);
padding: var(--ax-spacing-2) var(--ax-spacing-3);
}
.navds-table__sort-button:hover {
background-color: var(--ac-table-sort-button-hover-bg, var(--a-bg-subtle));
background-color: var(--ax-bg-neutral-hoverA);
}
.navds-table__sort-button:focus-visible {
outline: none;
box-shadow: inset 0 0 0 2px var(--a-border-focus);
}
@supports not selector(:focus-visible) {
.navds-table__sort-button:focus {
outline: none;
box-shadow: inset 0 0 0 2px var(--a-border-focus);
}
outline: 2px solid var(--ax-border-focus);
outline-offset: -4px;
}
.navds-table__header-cell[aria-sort="ascending"] .navds-table__sort-button,
.navds-table__header-cell[aria-sort="descending"] .navds-table__sort-button {
background-color: var(--ac-table-sort-button-sorted-bg, var(--a-surface-selected));
color: var(--ac-table-sort-button-sorted-text, var(--a-table-sort-button-sorted-text, var(--a-text-action-on-action-subtle)));
background-color: var(--ax-bg-accent-moderate);
color: var(--ax-text-accent-strong);
}
.navds-table__header-cell--align-right .navds-table__sort-button {
@@ -156,7 +150,7 @@
}
.navds-table__expandable-row:not(.navds-table__expandable-row--open) .navds-table__data-cell {
transition: border-bottom-color 190ms cubic-bezier(0.6, 0.04, 0.98, 0.335);
transition: border-bottom-color 150ms cubic-bezier(0.95, 0.05, 0.8, 0.04);
}
.navds-table__expandable-row.navds-table__expandable-row--clickable:not(.navds-table__expandable-row--expansion-disabled):hover {
@@ -168,7 +162,7 @@
}
.navds-table__expandable-row--open .navds-table__header-cell {
border-color: var(--ac-table-row-border, var(--a-border-default));
border-color: var(--ax-border-default);
}
.navds-table__expandable-row--open .navds-table__toggle-expand-cell--open {
@@ -181,11 +175,11 @@
}
.navds-table--large .navds-table__toggle-expand-cell {
padding: 0 var(--a-spacing-2);
padding: 0 var(--ax-spacing-2);
}
.navds-table--small .navds-table__toggle-expand-cell {
padding: var(--a-spacing-1) var(--a-spacing-2);
padding: var(--ax-spacing-1) var(--ax-spacing-2);
}
.navds-table__toggle-expand-button {
@@ -194,93 +188,54 @@
cursor: pointer;
background: transparent;
border: none;
border-radius: var(--a-border-radius-medium);
border-radius: var(--ax-border-radius-medium);
height: 2rem;
width: 2rem;
font-size: 1.5rem;
margin: 0 auto;
transition: background-color 70ms cubic-bezier(0.2, 0, 0, 1);
}
.navds-table__expandable-icon {
transition: transform 150ms ease-in-out;
transition: transform 250ms cubic-bezier(0.2, 0, 0, 1);
}
.navds-table__toggle-expand-cell:hover {
.navds-table__expandable-row:not(.navds-table__expandable-row--expansion-disabled) .navds-table__toggle-expand-cell:hover {
cursor: pointer;
}
.navds-table__toggle-expand-button:hover,
.navds-table__toggle-expand-cell:hover > .navds-table__toggle-expand-button,
.navds-table__expandable-row--clickable:hover .navds-table__toggle-expand-button {
background-color: var(--a-surface-hover);
background-color: var(--ax-bg-neutral-hoverA);
}
.navds-table__toggle-expand-cell--open > :where(.navds-table__toggle-expand-button) :where(.navds-table__expandable-icon) {
transform: translateY(0) rotate(180deg);
}
.navds-table__toggle-expand-button:hover > :where(.navds-table__expandable-icon) {
transform: translateY(1px);
}
.navds-table__toggle-expand-cell--open > .navds-table__toggle-expand-button:hover > :where(.navds-table__expandable-icon) {
transform: translateY(-1px) rotate(180deg);
transform: rotateX(180deg);
}
.navds-table__toggle-expand-button:focus-visible {
outline: none;
box-shadow: var(--a-shadow-focus);
}
@supports not selector(:focus-visible) {
.navds-table__toggle-expand-button:focus {
outline: none;
box-shadow: var(--a-shadow-focus);
}
outline: 2px solid var(--ax-border-focus);
}
.navds-table__expanded-row-cell {
padding: 0;
&:empty {
display: none;
}
}
.navds-table__expanded-row-cell:empty {
display: none;
}
.navds-table__expanded-row-collapse:not([style*="height: 0px;"]) {
border-bottom: 1px solid var(--ac-table-row-border, var(--a-border-default));
/* -------------------------- Table ExpandableRow -------------------------- */
.navds-table__expanded-row-collapse:not([style*="height: 0px;"]),
.navds-table__expanded-row-collapse[style*="transition:"] {
border-bottom: 1px solid var(--ax-border-default);
}
.navds-table__expanded-row-content {
padding: var(--a-spacing-4) calc(var(--a-spacing-2) + 3rem);
padding: var(--ax-spacing-4) calc(var(--ax-spacing-2) + 3rem);
}
.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;
}
padding: var(--ax-spacing-2) calc(var(--ax-spacing-2) + 3rem);
}
+97 -159
View File
@@ -1,194 +1,132 @@
.navds-tag {
--__ac-tag-icon-size: 1.5rem;
--__ac-tag-icon-margin: -2px;
--__axc-tag-icon-size: 1.5rem;
--__axc-tag-icon-margin: -2px;
--__axc-tag-border: ;
--__axc-tag-bg: ;
--__axc-tag-bg-strong: ;
--__axc-tag-text: ;
--__axc-tag-text-strong: ;
border: 1px solid;
border-radius: var(--a-border-radius-small);
border-radius: var(--ax-border-radius-medium);
display: inline-flex;
align-items: center;
justify-content: center;
padding: var(--a-spacing-05) var(--a-spacing-2);
padding: var(--ax-spacing-05) var(--ax-spacing-2);
min-height: 2rem;
line-height: 1;
&:has(.navds-tag__icon--left) {
gap: var(--ax-spacing-05);
}
}
.navds-tag--info,
.navds-tag--alt3 {
--__axc-tag-border: var(--ax-border-info);
--__axc-tag-bg: var(--ax-bg-info-moderateA);
--__axc-tag-bg-strong: var(--ax-bg-info-strong);
--__axc-tag-text: var(--ax-text-info-strong);
--__axc-tag-text-strong: var(--ax-text-info-contrast);
}
.navds-tag--success {
--__axc-tag-border: var(--ax-border-success);
--__axc-tag-bg: var(--ax-bg-success-moderateA);
--__axc-tag-bg-strong: var(--ax-bg-success-strong);
--__axc-tag-text: var(--ax-text-success-strong);
--__axc-tag-text-strong: var(--ax-text-success-contrast);
}
.navds-tag--warning {
--__axc-tag-border: var(--ax-border-warning);
--__axc-tag-bg: var(--ax-bg-warning-moderateA);
--__axc-tag-bg-strong: var(--ax-bg-warning-strong);
--__axc-tag-text: var(--ax-text-warning-strong);
--__axc-tag-text-strong: var(--ax-text-warning-contrast);
}
.navds-tag--error {
--__axc-tag-border: var(--ax-border-danger);
--__axc-tag-bg: var(--ax-bg-danger-moderateA);
--__axc-tag-bg-strong: var(--ax-bg-danger-strong);
--__axc-tag-text: var(--ax-text-danger-strong);
--__axc-tag-text-strong: var(--ax-text-danger-contrast);
}
.navds-tag--neutral {
--__axc-tag-border: var(--ax-border-neutral);
--__axc-tag-bg: var(--ax-bg-neutral-moderateA);
--__axc-tag-bg-strong: var(--ax-bg-neutral-strong);
--__axc-tag-text: var(--ax-text-neutral-strong);
--__axc-tag-text-strong: var(--ax-text-neutral-contrast);
}
.navds-tag--meta-purple,
.navds-tag--alt1 {
--__axc-tag-border: var(--ax-border-meta-purple);
--__axc-tag-bg: var(--ax-bg-meta-purple-moderateA);
--__axc-tag-bg-strong: var(--ax-bg-meta-purple-strong);
--__axc-tag-text: var(--ax-text-meta-purple-strong);
--__axc-tag-text-strong: var(--ax-text-meta-purple-contrast);
}
.navds-tag--meta-lime,
.navds-tag--alt2 {
--__axc-tag-border: var(--ax-border-meta-lime);
--__axc-tag-bg: var(--ax-bg-meta-lime-moderateA);
--__axc-tag-bg-strong: var(--ax-bg-meta-lime-strong);
--__axc-tag-text: var(--ax-text-meta-lime-strong);
--__axc-tag-text-strong: var(--ax-text-meta-lime-contrast);
}
.navds-tag--small {
min-height: 1.5rem;
padding: 0 var(--a-spacing-1-alt);
padding: 0 var(--ax-spacing-1-alt);
--__ac-tag-icon-size: 1.25rem;
--__axc-tag-icon-size: 1.25rem;
}
.navds-tag--xsmall {
min-height: 1.25rem;
padding: 0 var(--a-spacing-1);
padding: 0 var(--ax-spacing-1);
--__ac-tag-icon-size: 1rem;
--__ac-tag-icon-margin: -1px;
}
.navds-tag:has(.navds-tag__icon--left) {
gap: var(--a-spacing-05);
--__axc-tag-icon-size: 1rem;
--__axc-tag-icon-margin: -1px;
}
.navds-tag__icon--left {
font-size: var(--__ac-tag-icon-size);
margin-inline-start: var(--__ac-tag-icon-margin);
font-size: var(--__axc-tag-icon-size);
margin-inline-start: var(--__axc-tag-icon-margin);
display: flex;
}
.navds-tag--error {
border-color: var(--ac-tag-error-border, var(--a-border-danger));
background-color: var(--ac-tag-error-bg, var(--a-surface-danger-subtle));
color: var(--ac-tag-error-text, var(--a-text-default));
.navds-tag--outline {
box-shadow: inset 0 0 0 1px var(--__axc-tag-border);
background: var(--__axc-tag-bg);
color: var(--__axc-tag-text);
}
.navds-tag--error-filled {
border-color: transparent;
background-color: var(--ac-tag-error-filled-bg, var(--a-surface-danger));
color: var(--ac-tag-error-filled-text, var(--a-text-on-danger));
.navds-tag--moderate {
background: var(--__axc-tag-bg);
color: var(--__axc-tag-text);
}
.navds-tag--error-moderate {
border-color: transparent;
background-color: var(--ac-tag-error-moderate-bg, var(--a-surface-danger-moderate));
color: var(--ac-tag-error-moderate-text, var(--a-text-default));
}
.navds-tag--success {
border-color: var(--ac-tag-success-border, var(--a-border-success));
background-color: var(--ac-tag-success-bg, var(--a-surface-success-subtle));
color: var(--ac-tag-success-text, var(--a-text-default));
}
.navds-tag--success-filled {
border-color: transparent;
background-color: var(--ac-tag-success-filled-bg, var(--a-surface-success));
color: var(--ac-tag-success-filled-text, var(--a-text-on-success));
}
.navds-tag--success-moderate {
border-color: transparent;
background-color: var(--ac-tag-success-moderate-bg, var(--a-surface-success-moderate));
color: var(--ac-tag-success-moderate-text, var(--a-text-default));
}
.navds-tag--warning {
border-color: var(--ac-tag-warning-border, var(--a-border-warning));
background-color: var(--ac-tag-warning-bg, var(--a-surface-warning-subtle));
color: var(--ac-tag-warning-text, var(--a-text-default));
}
.navds-tag--warning-filled {
border-color: transparent;
background-color: var(--ac-tag-warning-filled-bg, var(--a-surface-warning));
color: var(--ac-tag-warning-filled-text, var(--a-text-on-warning));
}
.navds-tag--warning-moderate {
border-color: transparent;
background-color: var(--ac-tag-warning-moderate-bg, var(--a-surface-warning-moderate));
color: var(--ac-tag-warning-moderate-text, var(--a-text-default));
}
.navds-tag--info {
border-color: var(--ac-tag-info-border, var(--a-border-info));
background-color: var(--ac-tag-info-bg, var(--a-surface-info-subtle));
color: var(--ac-tag-info-text, var(--a-text-default));
}
.navds-tag--info-filled {
border-color: transparent;
background-color: var(--ac-tag-info-filled-bg, var(--a-surface-info));
color: var(--ac-tag-info-filled-text, var(--a-text-on-info));
}
.navds-tag--info-moderate {
border-color: transparent;
background-color: var(--ac-tag-info-moderate-bg, var(--a-surface-info-moderate));
color: var(--ac-tag-info-moderate-text, var(--a-text-default));
}
.navds-tag--neutral {
border-color: var(--ac-tag-neutral-border, var(--a-border-default));
background-color: var(--ac-tag-neutral-bg, var(--a-surface-neutral-subtle));
color: var(--ac-tag-neutral-text, var(--a-text-default));
}
.navds-tag--neutral-filled {
border-color: transparent;
background-color: var(--ac-tag-neutral-filled-bg, var(--a-surface-neutral));
color: var(--ac-tag-neutral-filled-text, var(--a-text-on-neutral));
}
.navds-tag--neutral-moderate {
border-color: transparent;
background-color: var(--ac-tag-neutral-moderate-bg, var(--a-surface-neutral-moderate));
color: var(--ac-tag-neutral-moderate-text, var(--a-text-default));
}
.navds-tag--alt1 {
border-color: var(--ac-tag-alt-1-border, var(--a-border-alt-1));
background-color: var(--ac-tag-alt-1-bg, var(--a-surface-alt-1-subtle));
color: var(--ac-tag-alt-1-text, var(--a-text-default));
}
.navds-tag--alt1-filled {
border-color: transparent;
background-color: var(--ac-tag-alt-1-filled-bg, var(--a-surface-alt-1));
color: var(--ac-tag-alt-1-filled-text, var(--a-text-on-alt-1));
}
.navds-tag--alt1-moderate {
border-color: transparent;
background-color: var(--ac-tag-alt-1-moderate-bg, var(--a-surface-alt-1-moderate));
color: var(--ac-tag-alt-1-moderate-text, var(--a-text-default));
}
.navds-tag--alt2 {
border-color: var(--ac-tag-alt-2-border, var(--a-border-alt-2));
background-color: var(--ac-tag-alt-2-bg, var(--a-surface-alt-2-subtle));
color: var(--ac-tag-alt-2-text, var(--a-text-default));
}
.navds-tag--alt2-filled {
border-color: transparent;
background-color: var(--ac-tag-alt-2-filled-bg, var(--a-surface-alt-2));
color: var(--ac-tag-alt-2-filled-text, var(--a-text-on-alt-2));
}
.navds-tag--alt2-moderate {
border-color: transparent;
background-color: var(--ac-tag-alt-2-moderate-bg, var(--a-surface-alt-2-moderate));
color: var(--ac-tag-alt-2-moderate-text, var(--a-text-default));
}
.navds-tag--alt3 {
border-color: var(--ac-tag-alt-3-border, var(--a-border-alt-3));
background-color: var(--ac-tag-alt-3-bg, var(--a-surface-alt-3-subtle));
color: var(--ac-tag-alt-3-text, var(--a-text-default));
}
.navds-tag--alt3-filled {
border-color: transparent;
background-color: var(--ac-tag-alt-3-filled-bg, var(--a-surface-alt-3));
color: var(--ac-tag-alt-3-filled-text, var(--a-text-on-alt-3));
}
.navds-tag--alt3-moderate {
border-color: transparent;
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));
.navds-tag--strong {
background: var(--__axc-tag-bg-strong);
color: var(--__axc-tag-text-strong);
}
@media (forced-colors: active) {
.navds-tag {
forced-color-adjust: none;
}
.navds-tag--neutral,
.navds-tag--neutral-moderate {
border-color: canvastext;
color: canvastext;
}
.navds-tag--moderate {
box-shadow: inset 0 0 0 1px var(--__axc-tag-bg-strong);
}
.navds-tag--strong {
color: canvas;
}
}
+119 -212
View File
@@ -12,18 +12,18 @@
height: 1rem;
box-sizing: content-box;
grid-column: 2;
margin-bottom: var(--a-spacing-1);
margin-bottom: var(--ax-spacing-1);
}
.navds-timeline__row-label {
white-space: nowrap;
width: auto;
margin-right: var(--a-spacing-4);
margin-right: var(--ax-spacing-4);
grid-column: 1;
min-height: 1.5rem;
display: flex;
align-items: center;
gap: var(--a-spacing-2);
gap: var(--ax-spacing-2);
}
.navds-timeline__row-label:where(:nth-last-child(2)) {
@@ -32,19 +32,19 @@
.navds-timeline__axislabels-label {
position: absolute;
color: var(--ac-timeline-axislabel-text, var(--a-text-subtle));
color: var(--ax-text-subtle);
white-space: nowrap;
}
.navds-timeline__row {
display: flex;
background: var(--ac-timeline-row-bg, var(--a-surface-subtle));
margin: var(--a-spacing-4) 0;
background: var(--ax-bg-neutral);
margin: var(--ax-spacing-4) 0;
grid-column: 2;
}
.navds-timeline__row--active {
background: var(--ac-timeline-row-active-bg, var(--a-surface-selected));
background: var(--ax-bg-accent-moderateA);
}
.navds-timeline__row:last-of-type {
@@ -62,13 +62,19 @@
list-style-type: none;
}
.navds-timeline__row-periods:focus {
outline: none;
.navds-timeline__period:focus-visible {
z-index: 4;
outline: 2px solid var(--ax-border-focus);
outline-offset: 2px;
&& {
box-shadow: 0 0 0 2px var(--ax-bg-default);
}
}
.navds-timeline__period {
height: 100%;
border-radius: var(--a-border-radius-full);
border-radius: var(--ax-border-radius-full);
position: absolute;
padding: 0;
display: flex;
@@ -79,7 +85,7 @@
}
.navds-timeline__period--inner {
margin: 0 var(--a-spacing-1);
margin: 0 var(--ax-spacing-2);
overflow: hidden;
white-space: nowrap;
text-overflow: clip;
@@ -97,49 +103,83 @@
}
.navds-timeline__period--success {
background: var(--ac-timeline-period-success-bg, var(--a-surface-success-subtle));
box-shadow: inset 0 0 0 1px var(--ac-timeline-period-success-border, var(--a-border-success));
}
background: var(--ax-bg-success-moderate);
border: solid 1px var(--ax-border-success);
color: var(--ax-text-success-icon);
.navds-timeline__period--success.navds-timeline__period--clickable:hover {
background: var(--a-surface-success-subtle-hover);
background: var(--ac-timeline-period-success-bg-hover, var(--a-surface-success-subtle-hover));
&.navds-timeline__period--clickable:hover {
background: var(--ax-bg-success-moderate-hover);
}
&.navds-timeline__period--clickable.navds-timeline__period--selected {
background: var(--ax-bg-success-strong-pressed);
border: none;
color: var(--ax-text-success-contrast);
}
}
.navds-timeline__period--warning {
background: var(--ac-timeline-period-warning-bg, var(--a-surface-warning-subtle));
box-shadow: inset 0 0 0 1px var(--ac-timeline-period-warning-border, var(--a-border-warning));
}
background: var(--ax-bg-warning-moderate);
border: solid 1px var(--ax-border-warning);
color: var(--ax-text-warning-icon);
.navds-timeline__period--warning.navds-timeline__period--clickable:hover {
background: var(--ac-timeline-period-warning-bg-hover, var(--a-surface-warning-subtle-hover));
&.navds-timeline__period--clickable:hover {
background: var(--ax-bg-warning-moderate-hover);
}
&.navds-timeline__period--clickable.navds-timeline__period--selected {
background: var(--ax-bg-warning-strong-pressed);
border: none;
color: var(--ax-text-warning-contrast);
}
}
.navds-timeline__period--danger {
background: var(--ac-timeline-period-danger-bg, var(--a-surface-danger-subtle));
box-shadow: inset 0 0 0 1px var(--ac-timeline-period-danger-border, var(--a-border-danger));
}
background: var(--ax-bg-danger-moderate);
border: solid 1px var(--ax-border-danger);
color: var(--ax-text-danger-icon);
.navds-timeline__period--danger.navds-timeline__period--clickable:hover {
background: var(--ac-timeline-period-danger-bg-hover, var(--a-surface-danger-subtle-hover));
&.navds-timeline__period--clickable:hover {
background: var(--ax-bg-danger-moderate-hover);
}
&.navds-timeline__period--clickable.navds-timeline__period--selected {
background: var(--ax-bg-danger-strong-pressed);
border: none;
color: var(--ax-text-danger-contrast);
}
}
.navds-timeline__period--info {
background: var(--ac-timeline-period-info-bg, var(--a-surface-info-subtle));
box-shadow: inset 0 0 0 1px var(--ac-timeline-period-info-border, var(--a-border-info));
}
background: var(--ax-bg-info-moderate);
border: solid 1px var(--ax-border-info);
color: var(--ax-text-info-icon);
.navds-timeline__period--info.navds-timeline__period--clickable:hover {
background: var(--ac-timeline-period-info-bg-hover, var(--a-surface-info-subtle-hover));
&.navds-timeline__period--clickable:hover {
background: var(--ax-bg-info-moderate-hover);
}
&.navds-timeline__period--clickable.navds-timeline__period--selected {
background: var(--ax-bg-info-strong-pressed);
border: none;
color: var(--ax-text-info-contrast);
}
}
.navds-timeline__period--neutral {
background: var(--ac-timeline-period-neutral-bg, var(--a-bg-subtle));
box-shadow: inset 0 0 0 1px var(--ac-timeline-period-neutral-border, var(--a-border-default));
}
background: var(--ax-bg-neutral-moderate);
border: solid 1px var(--ax-border-neutral);
color: var(--ax-text-neutral-icon);
.navds-timeline__period--neutral.navds-timeline__period--clickable:hover {
background: var(--ac-timeline-period-neutral-bg-hover, var(--a-gray-200));
&.navds-timeline__period--clickable:hover {
background: var(--ax-bg-neutral-moderate-hover);
}
&.navds-timeline__period--clickable.navds-timeline__period--selected {
background: var(--ax-bg-neutral-strong-pressed);
border: none;
color: var(--ax-text-neutral-contrast);
}
}
.navds-timeline__period--connected-both {
@@ -156,11 +196,6 @@
border-top-left-radius: 0;
}
.navds-timeline__period--selected {
box-shadow: inset 0 0 0 2px var(--ac-timeline-period-selected-border, var(--a-border-action-selected));
z-index: 3;
}
.navds-timeline__pin-wrapper {
position: absolute;
grid-column: 2;
@@ -177,68 +212,34 @@
.navds-timeline__pin-button {
border: none;
cursor: pointer;
background: var(--a-surface-default);
box-shadow:
inset 0 0 0 1px var(--ac-timeline-pin-bg, var(--a-surface-danger)),
0 0 0 4px var(--ac-timeline-pin-bg, var(--a-surface-danger)),
0 0 0 5px var(--a-surface-default);
background: var(--ax-bg-default);
box-shadow: inset 0 0 0 4px var(--ax-bg-danger-strong);
z-index: 2;
border-radius: var(--a-border-radius-full);
padding: var(--a-spacing-1);
border-radius: var(--ax-border-radius-full);
padding: var(--ax-spacing-2);
position: relative;
}
.navds-timeline__pin-button::before {
content: "";
inset: 0;
position: absolute;
width: 25px;
height: 25px;
border-radius: var(--a-border-radius-full);
left: calc(-12.5px + 3.5px);
top: calc(-12.5px + 3.5px);
}
.navds-timeline__pin-button:focus-visible {
box-shadow:
inset 0 0 0 1px var(--ac-timeline-pin-bg, var(--a-surface-danger)),
0 0 0 3px var(--ac-timeline-pin-bg, var(--a-surface-danger)),
0 0 0 4px var(--a-surface-default),
0 0 0 6px var(--a-border-focus);
outline: none;
}
.navds-timeline__pin-button:hover {
box-shadow:
inset 0 0 0 1px var(--ac-timeline-pin-bg-hover, var(--a-surface-danger-hover)),
0 0 0 4px var(--ac-timeline-pin-bg-hover, var(--a-surface-danger-hover)),
0 0 0 5px var(--a-surface-default);
}
.navds-timeline__pin-button:hover:focus-visible {
box-shadow:
inset 0 0 0 1px var(--ac-timeline-pin-bg-hover, var(--a-surface-danger-hover)),
0 0 0 3px var(--ac-timeline-pin-bg-hover, var(--a-surface-danger-hover)),
0 0 0 4px var(--a-surface-default),
0 0 0 6px var(--a-border-focus);
}
@supports not selector(:focus-visible) {
.navds-timeline__pin-button:focus {
box-shadow:
inset 0 0 0 1px var(--ac-timeline-pin-bg, var(--a-surface-danger)),
0 0 0 3px var(--ac-timeline-pin-bg, var(--a-surface-danger)),
0 0 0 4px var(--a-surface-default),
0 0 0 6px var(--a-border-focus);
outline: none;
&::before {
content: "";
inset: 0;
position: absolute;
width: 25px;
height: 25px;
border-radius: var(--ax-border-radius-full);
left: calc(-12.5px + 3.5px);
top: calc(-12.5px + 3.5px);
}
.navds-timeline__pin-button:hover:focus {
&:hover {
box-shadow: inset 0 0 0 4px var(--ax-bg-danger-strong-hover);
}
&:focus-visible {
box-shadow:
inset 0 0 0 1px var(--ac-timeline-pin-bg-hover, var(--a-surface-danger-hover)),
0 0 0 3px var(--ac-timeline-pin-bg-hover, var(--a-surface-danger-hover)),
0 0 0 4px var(--a-surface-default),
0 0 0 6px var(--a-border-focus);
inset 0 0 0 4px var(--ax-border-danger-strong),
0 0 0 2px var(--ax-bg-default);
outline: 2px solid var(--ax-border-focus);
outline-offset: 2px;
}
}
@@ -248,11 +249,11 @@
height: calc(100% - var(--navdsc-timeline-pin-size) * 2);
width: 1px;
margin: 0 auto;
background: var(--a-surface-inverted);
background: var(--ax-border-strong);
}
.navds-timeline__zoom {
margin-top: var(--a-spacing-6);
margin-top: var(--ax-spacing-6);
float: right;
display: flex;
list-style-type: none;
@@ -262,54 +263,42 @@
all: unset;
cursor: pointer;
padding: 6px 9px 6px 8px;
border: 1px solid var(--ac-timeline-zoom-border, var(--a-border-default));
border: 1px solid var(--ax-border-default);
border-width: 1px 0 1px 1px;
background: var(--ac-timeline-zoom-bg, var(--a-surface-default));
background: var(--ax-bg-default);
}
.navds-timeline__zoom li:first-child .navds-timeline__zoom-button {
border-radius: var(--a-border-radius-medium) 0 0 var(--a-border-radius-medium);
border-radius: var(--ax-border-radius-medium) 0 0 var(--ax-border-radius-medium);
}
.navds-timeline__zoom li:last-child .navds-timeline__zoom-button {
border-width: 1px;
border-radius: 0 var(--a-border-radius-medium) var(--a-border-radius-medium) 0;
border-radius: 0 var(--ax-border-radius-medium) var(--ax-border-radius-medium) 0;
}
.navds-timeline__zoom li:only-child .navds-timeline__zoom-button {
border-radius: var(--a-border-radius-medium);
border-radius: var(--ax-border-radius-medium);
}
.navds-timeline__zoom-button:not([aria-pressed="true"]):hover {
background: var(--ac-timeline-zoom-bg-hover, var(--a-surface-action-subtle-hover));
background: var(--ax-bg-neutral-moderate-hoverA);
}
.navds-timeline__zoom-button[aria-pressed="true"] {
background: var(--ac-timeline-zoom-selected-bg, var(--a-surface-inverted));
color: var(--ac-timeline-zoom-selected-text, var(--a-text-on-inverted));
}
.navds-timeline__period:focus-visible {
outline: none;
z-index: 4;
box-shadow: 0 0 0 2px var(--a-border-focus);
}
.navds-timeline__period--selected:focus-visible {
box-shadow:
inset 0 0 0 2px var(--ac-timeline-period-selected-border, var(--a-border-action-selected)),
0 0 0 2px var(--a-border-focus);
z-index: 3;
background: var(--ax-bg-neutral-strong-pressed);
border-color: var(--ax-bg-neutral-strong-pressed);
color: var(--ax-text-neutral-contrast);
}
.navds-timeline__zoom li:focus-within {
z-index: var(--a-z-index-focus);
z-index: 5;
}
.navds-timeline__zoom-button:focus-visible {
box-shadow:
0 0 0 1px var(--a-surface-default),
0 0 0 3px var(--a-border-focus);
0 0 0 1px var(--ax-bg-default),
0 0 0 3px var(--ax-border-focus);
border-width: 1px;
}
@@ -318,80 +307,18 @@
padding-right: 6px;
}
@supports not selector(:focus-visible) {
.navds-timeline__period:focus {
outline: none;
z-index: 4;
box-shadow: 0 0 0 2px var(--a-border-focus);
}
.navds-timeline__period--selected:focus {
box-shadow:
inset 0 0 0 2px var(--ac-timeline-period-selected-border, var(--a-border-action-selected)),
0 0 0 2px var(--a-border-focus);
z-index: 3;
}
.navds-timeline__zoom-button:focus {
box-shadow:
0 0 0 1px var(--a-surface-default),
0 0 0 3px var(--a-border-focus);
border-width: 1px;
}
.navds-timeline__zoom li:not(:last-child) .navds-timeline__zoom-button:focus {
margin-right: 2px;
padding-right: 6px;
}
}
/**
* Timeline Popover
*/
.navds-timeline__popover {
z-index: var(--a-z-index-popover);
background-color: var(--ac-popover-bg, var(--a-surface-default));
box-shadow: var(--a-shadow-medium);
z-index: 5;
background-color: var(--ax-bg-raised);
box-shadow: var(--ax-shadow-dialog);
border: 1px solid;
border-color: var(--ac-popover-border, var(--a-border-default));
border-radius: var(--a-border-radius-large);
padding: var(--a-spacing-3);
}
.navds-timeline__popover:focus {
outline: none;
}
.navds-timeline__popover-arrow {
position: absolute;
z-index: -1;
transform: rotate(45deg);
background-color: var(--ac-popover-bg, var(--a-surface-default));
border: 1px solid;
border-color: var(--ac-popover-border, var(--a-border-default));
width: 1rem;
height: 1rem;
}
.navds-timeline__popover[data-placement^="top"] > .navds-timeline__popover-arrow {
border-left-color: transparent;
border-top-color: transparent;
}
.navds-timeline__popover[data-placement^="bottom"] > .navds-timeline__popover-arrow {
border-bottom-color: transparent;
border-right-color: transparent;
}
.navds-timeline__popover[data-placement^="left"] > .navds-timeline__popover-arrow {
border-left-color: transparent;
border-bottom-color: transparent;
}
.navds-timeline__popover[data-placement^="right"] > .navds-timeline__popover-arrow {
border-right-color: transparent;
border-top-color: transparent;
border-color: var(--ax-border-subtleA);
border-radius: var(--ax-border-radius-large);
padding: var(--ax-spacing-4) var(--ax-spacing-5);
}
@media (forced-colors: active) {
@@ -426,24 +353,4 @@
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;
}
}
@@ -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;
+87 -62
View File
@@ -1,81 +1,106 @@
@keyframes tooltipFadeIn {
0% {
opacity: 0;
.navds-tooltip {
z-index: 3000;
background-color: var(--ax-bg-raised);
color: var(--ax-text-default);
border-radius: var(--ax-border-radius-medium);
padding: 0 var(--ax-spacing-1-alt);
align-items: center;
display: flex;
flex-direction: column;
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
animation-duration: 150ms;
text-align: center;
border: 1px solid var(--ax-border-subtleA);
box-shadow: var(--ax-shadow-dialog);
}
.navds-tooltip:where([data-state="open"]):where([data-side="bottom"]) {
animation-name: aksel-tooltip-from-bottom, aksel-tooltip-fade-in;
}
.navds-tooltip:where([data-state="open"]):where([data-side="top"]) {
animation-name: aksel-tooltip-from-top, aksel-tooltip-fade-in;
}
.navds-tooltip:where([data-state="open"]):where([data-side="left"]) {
animation-name: aksel-tooltip-from-left, aksel-tooltip-fade-in;
}
.navds-tooltip:where([data-state="open"]):where([data-side="right"]) {
animation-name: aksel-tooltip-from-right, aksel-tooltip-fade-in;
}
@keyframes aksel-tooltip-from-bottom {
from {
transform: translateY(-4px);
}
100% {
to {
transform: translateY(0);
}
}
@keyframes aksel-tooltip-from-top {
from {
transform: translateY(4px);
}
to {
transform: translateY(0);
}
}
@keyframes aksel-tooltip-from-left {
from {
transform: translateX(4px);
}
to {
transform: translateY(0);
}
}
@keyframes aksel-tooltip-from-right {
from {
transform: translateX(-4px);
}
to {
transform: translateY(0);
}
}
@keyframes aksel-tooltip-fade-in {
from {
opacity: 0.01;
}
to {
opacity: 1;
}
}
.navds-tooltip {
z-index: var(--a-z-index-tooltip);
background-color: var(--ac-tooltip-bg, var(--a-surface-inverted));
color: var(--ac-tooltip-text, var(--a-text-on-inverted));
border-radius: var(--a-border-radius-small);
padding: 0 var(--a-spacing-2);
align-items: center;
filter: drop-shadow(0 2px 4px rgba(0 0 0 / 0.1)) drop-shadow(0 4px 6px rgba(0 0 0 / 0.1));
display: flex;
flex-direction: column;
animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
animation-duration: 0.2s;
animation-name: tooltipFadeIn;
text-align: center;
}
.navds-tooltip__arrow {
height: 0.4375rem;
width: 0.4375rem;
transform: rotate(45deg);
z-index: -1;
background-color: var(--ac-tooltip-bg, var(--a-surface-inverted));
position: absolute;
}
.navds-tooltip__keys {
padding-bottom: var(--a-spacing-1);
padding-bottom: var(--ax-spacing-1);
display: flex;
gap: var(--a-spacing-1);
gap: var(--ax-spacing-1);
}
.navds-tooltip__key {
font-family: var(--a-font-family);
background-color: var(--ac-tooltip-key-bg, var(--a-surface-neutral));
color: var(--ac-tooltip-key-text, var(--a-text-on-inverted));
border-radius: var(--a-border-radius-small);
padding: 0 var(--a-spacing-1);
font-family: var(--ax-font-family);
color: var(--ax-text-default);
padding: 0 var(--ax-spacing-1);
min-width: 1.125rem;
height: 1.125rem;
display: inline-flex;
align-items: center;
justify-content: center;
}
border-radius: var(--ax-border-radius-small);
background: var(--ax-bg-neutral-moderateA);
@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);
@media (forced-colors: active) {
& {
outline: 1px solid;
}
}
}
@@ -1,15 +1,3 @@
/* stylelint-disable csstools/value-no-unknown-custom-properties */
/* ------------------------- Global typo-definitions ------------------------ */
body,
:host {
font-family: "Source Sans 3", "Source Sans Pro", Arial, sans-serif;
line-height: 1.333;
font-size: 1.125rem;
}
/* ----------------------------- Typo-components ---------------------------- */
/* Heading */
.navds-heading {
font-weight: var(--ax-font-weight-bold);
@@ -216,6 +204,18 @@ body,
.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 ------------------------------- */
+2 -22
View File
@@ -50,7 +50,6 @@
border-color: var(--a-border-subtle);
}
.navds-combobox__button-clear svg,
.navds-combobox__button-toggle-list svg,
.navds-combobox__list svg {
width: var(--__ac-combobox-icon-size);
@@ -195,19 +194,6 @@
}
}
.navds-combobox__button-clear {
border-radius: var(--a-border-radius-medium);
color: var(--ac-combobox-clear-icon, var(--a-text-subtle));
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
background: none;
border: none;
font-size: 1rem;
padding: 0;
}
.navds-combobox__input::-webkit-search-cancel-button {
display: none;
}
@@ -225,14 +211,12 @@
padding: 0;
}
.navds-combobox__button-clear:active:hover,
.navds-combobox__button-toggle-list:active:hover {
color: var(--ac-combobox-clear-icon-active, var(--a-text-action));
color: var(--a-text-action);
}
.navds-combobox__button-clear:hover,
.navds-combobox__button-toggle-list:hover {
color: var(--ac-combobox-clear-icon-hover, var(--a-text-action-selected));
color: var(--a-text-action-selected);
}
.navds-combobox__button-toggle-list:focus-visible {
@@ -406,10 +390,6 @@
}
@media (forced-colors: active) {
.navds-combobox__button-clear:hover {
color: highlight;
}
.navds-combobox__wrapper-inner:has(.navds-combobox__input:focus-visible) {
outline-color: highlight;
}
-13
View File
@@ -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;
+5 -1
View File
@@ -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
*/
+30 -19
View File
@@ -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 {
+3 -6
View File
@@ -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 {
+1 -1
View File
@@ -30,7 +30,7 @@
text-decoration: underline;
}
.navds-alert .navds-link,
.navds-alert:not(.navds-alert--inline) .navds-link,
.navds-confirmation-panel .navds-link {
color: var(--a-text-default);
}
+23 -9
View File
@@ -1,8 +1,8 @@
{
"name": "@navikt/ds-css",
"version": "7.7.0",
"description": "CSS for NAV Designsystem",
"author": "Aksel | NAV designsystem team",
"version": "7.9.0",
"description": "CSS for Nav Designsystem",
"author": "Aksel | Nav designsystem team",
"keywords": [
"css"
],
@@ -20,29 +20,43 @@
"type": "git",
"url": "git+https://github.com/navikt/aksel.git"
},
"main": "./dist/index.css",
"scripts": {
"build": "node config/bundle.js",
"build": "node config/bundle.js && yarn build:darkside",
"watch": "nodemon --ignore dist -e css --watch . --exec \"yarn build\"",
"css:get-version": "node config/get-version.js"
"css:get-version": "node config/get-version.js",
"build:darkside": "tsx ./config/bundle.darkside.ts",
"test": "yarn build && vitest run"
},
"devDependencies": {
"@navikt/ds-tokens": "^7.7.0",
"@navikt/ds-tokens": "^7.9.0",
"@types/clean-css": "4.2.11",
"autoprefixer": "^10.4.20",
"browserslist": "^4.24.2",
"clean-css": "5.3.3",
"cssnano": "6.0.0",
"fast-glob": "3.2.11",
"lightningcss": "^1.28.0",
"lodash": "^4.17.21",
"nodemon": "^3.0.1",
"normalize.css": "^8.0.1",
"postcss": "^8.4.31",
"postcss-cli": "^9.0.0",
"postcss-combine-duplicated-selectors": "10.0.3",
"postcss-import": "^14.1.0"
"postcss-import": "^14.1.0",
"tsx": "^4.7.1",
"vitest": "^1.2.2"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
]
],
"main": "./dist/index.css",
"exports": {
".": "./dist/index.css",
"./dist/*": "./dist/*",
"./darkside": "./dist/darkside/index.min.css",
"./tokens.json": "./tokens.json"
}
}
+1 -1
View File
@@ -206,7 +206,7 @@
transition: transform 150ms ease-in-out;
}
.navds-table__toggle-expand-cell:hover {
.navds-table__expandable-row:not(.navds-table__expandable-row--expansion-disabled) .navds-table__toggle-expand-cell:hover {
cursor: pointer;
}
+12 -6
View File
@@ -127,37 +127,43 @@
color: var(--ac-tag-neutral-moderate-text, var(--a-text-default));
}
.navds-tag--alt1 {
.navds-tag--alt1,
.navds-tag--outline.navds-tag--meta-purple {
border-color: var(--ac-tag-alt-1-border, var(--a-border-alt-1));
background-color: var(--ac-tag-alt-1-bg, var(--a-surface-alt-1-subtle));
color: var(--ac-tag-alt-1-text, var(--a-text-default));
}
.navds-tag--alt1-filled {
.navds-tag--alt1-filled,
.navds-tag--strong.navds-tag--meta-purple {
border-color: transparent;
background-color: var(--ac-tag-alt-1-filled-bg, var(--a-surface-alt-1));
color: var(--ac-tag-alt-1-filled-text, var(--a-text-on-alt-1));
}
.navds-tag--alt1-moderate {
.navds-tag--alt1-moderate,
.navds-tag--moderate.navds-tag--meta-purple {
border-color: transparent;
background-color: var(--ac-tag-alt-1-moderate-bg, var(--a-surface-alt-1-moderate));
color: var(--ac-tag-alt-1-moderate-text, var(--a-text-default));
}
.navds-tag--alt2 {
.navds-tag--alt2,
.navds-tag--outline.navds-tag--meta-lime {
border-color: var(--ac-tag-alt-2-border, var(--a-border-alt-2));
background-color: var(--ac-tag-alt-2-bg, var(--a-surface-alt-2-subtle));
color: var(--ac-tag-alt-2-text, var(--a-text-default));
}
.navds-tag--alt2-filled {
.navds-tag--alt2-filled,
.navds-tag--strong.navds-tag--meta-lime {
border-color: transparent;
background-color: var(--ac-tag-alt-2-filled-bg, var(--a-surface-alt-2));
color: var(--ac-tag-alt-2-filled-text, var(--a-text-on-alt-2));
}
.navds-tag--alt2-moderate {
.navds-tag--alt2-moderate,
.navds-tag--moderate.navds-tag--meta-lime {
border-color: transparent;
background-color: var(--ac-tag-alt-2-moderate-bg, var(--a-surface-alt-2-moderate));
color: var(--ac-tag-alt-2-moderate-text, var(--a-text-default));
+3 -6
View File
@@ -387,9 +387,6 @@
"--ac-search-error-border": "--a-border-danger"
},
"combobox": {
"--ac-combobox-clear-icon": "--a-text-subtle",
"--ac-combobox-clear-icon-hover": "--a-text-action-selected",
"--ac-combobox-clear-icon-active": "--a-text-action",
"--ac-combobox-list-bg": "--a-surface-default",
"--ac-combobox-list-text": "--a-text-default",
"--ac-combobox-list-border-color": "--a-border-divider",
@@ -414,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"
},
+12
View File
@@ -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;
+59
View File
@@ -1,5 +1,64 @@
# @navikt/ds-react
## 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
- Combobox: Only open dropdown-list onClick, not onFocus. ([#3440](https://github.com/navikt/aksel/pull/3440))
- Combobox: Fix issue where you could select more options than defined in maxSelected ([#3434](https://github.com/navikt/aksel/pull/3434))
- Timeline: In cases where earliest found date were after current date, timeline-start ended up defaulting to current date. ([#3458](https://github.com/navikt/aksel/pull/3458))
- Updated dependencies []:
- @navikt/ds-tokens@7.8.1
- @navikt/aksel-icons@7.8.1
## 7.8.0
### Minor Changes
- Chips.Removable: Removed prop `removeLabel` ([#3429](https://github.com/navikt/aksel/pull/3429))
- i18n: :sparkles: Implemented i18n support for all components. Components come with support for nb, nn and en locales ([Docs](https://aksel.nav.no/komponenter/core/provider#84d7ea5ec517)) ([#3429](https://github.com/navikt/aksel/pull/3429))
- Combobox: Removed clear button, removed tokens staring with `--ac-combobox-clear`, deprecated props `clearButton`/`clearButtonLabel`. ([#3433](https://github.com/navikt/aksel/pull/3433))
- Combobox: Changed prop `maxSelected` to number ([#3433](https://github.com/navikt/aksel/pull/3433))
- DatePicker/MonthPicker: Added new `translations` prop and deprecated `locale` prop ([#3429](https://github.com/navikt/aksel/pull/3429))
### Patch Changes
- Timeline: Deprecated prop `axisLabelTemplates`. Use [Provider](https://aksel.nav.no/komponenter/core/provider#84d7ea5ec517) if you still need to change the date formats. ([#3429](https://github.com/navikt/aksel/pull/3429))
- Search: Deprecated prop `clearButtonLabel`. Use [Provider](https://aksel.nav.no/komponenter/core/provider#84d7ea5ec517) if you still need to change the label. ([#3429](https://github.com/navikt/aksel/pull/3429))
- Textarea: Deprecated prop `i18n`. Use [Provider](https://aksel.nav.no/komponenter/core/provider#84d7ea5ec517) if you still need to change these texts. ([#3429](https://github.com/navikt/aksel/pull/3429))
- Updated dependencies []:
- @navikt/ds-tokens@7.8.0
- @navikt/aksel-icons@7.8.0
## 7.7.0
### Minor Changes
+14 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-react",
"version": "7.7.0",
"version": "7.9.0",
"description": "React components from the Norwegian Labour and Welfare Administration.",
"author": "Aksel, a team part of the Norwegian Labour and Welfare Administration.",
"license": "MIT",
@@ -8,7 +8,7 @@
"react",
"typescript",
"javascript",
"NAV"
"Nav"
],
"repository": {
"type": "git",
@@ -40,6 +40,16 @@
"default": "./cjs/index.js"
}
},
"./locales": {
"import": {
"types": "./esm/util/i18n/locales/index.d.ts",
"default": "./esm/util/i18n/locales/index.js"
},
"require": {
"types": "./cjs/util/i18n/locales/index.d.ts",
"default": "./cjs/util/i18n/locales/index.js"
}
},
"./Accordion": {
"import": {
"types": "./esm/accordion/index.d.ts",
@@ -604,8 +614,8 @@
"dependencies": {
"@floating-ui/react": "0.25.4",
"@floating-ui/react-dom": "^2.0.9",
"@navikt/aksel-icons": "^7.7.0",
"@navikt/ds-tokens": "^7.7.0",
"@navikt/aksel-icons": "^7.9.0",
"@navikt/ds-tokens": "^7.9.0",
"clsx": "^2.1.0",
"date-fns": "^3.0.0",
"react-day-picker": "8.10.1"
@@ -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(
@@ -96,8 +96,8 @@ export const Inline: StoryFn = () => {
<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.
reprehenderit enim nisi veniam nostrud.{" "}
<Link href="#">Id elit esse enim reprehenderit</Link>
</Alert>
<Alert variant="info" size="small" inline>
Id elit esse enim reprehenderit enim nisi veniam nostrud.
@@ -105,8 +105,8 @@ export const Inline: StoryFn = () => {
<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.
reprehenderit enim nisi veniam nostrud.{" "}
<Link href="#">Id elit esse enim reprehenderit</Link>
</Alert>
</VStack>
);
+20 -50
View File
@@ -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">
+1 -9
View File
@@ -16,11 +16,6 @@ export interface ChipsRemovableProps
* Click callback
*/
onDelete?: () => void;
/**
* Replaces label read for screen-readers
* @default "slett"
*/
removeLabel?: string;
}
export const RemovableChips = forwardRef<
@@ -32,7 +27,6 @@ export const RemovableChips = forwardRef<
children,
variant = "action",
onDelete,
removeLabel,
className,
onClick,
type = "button",
@@ -51,9 +45,7 @@ export const RemovableChips = forwardRef<
className,
`navds-chips__removable--${variant}`,
)}
aria-label={`${children} ${
removeLabel ?? translate("Removable.labelSuffix")
}`}
aria-label={`${children} ${translate("Removable.labelSuffix")}`}
onClick={composeEventHandlers(onClick, onDelete)}
>
<span className="navds-chips__chip-text">{children}</span>
+5 -1
View File
@@ -1,5 +1,9 @@
export { useDateInputContext, DateContext } from "./useDateInputContext";
export { useDateInputContext, DateInputContext } from "./useDateInputContext";
export {
useSharedMonthContext,
SharedMonthProvider,
} from "./useSharedMonthContext";
export {
useDateTranslationContext,
DateTranslationContextProvider,
} from "./useDateTranslationContext";
@@ -1,6 +1,6 @@
import { createContext, useContext } from "react";
interface DateContextContextProps {
interface DateInputContextProps {
/**
* Open state for popover
*/
@@ -19,13 +19,15 @@ interface DateContextContextProps {
defined: boolean;
}
export const DateContext = createContext<DateContextContextProps | null>(null);
export const DateInputContext = createContext<DateInputContextProps | null>(
null,
);
export const useDateInputContext = () => {
const context = useContext(DateContext);
const context = useContext(DateInputContext);
if (!context) {
console.warn("useDateInputContext must be used with DateContext");
console.warn("useDateInputContext must be used with DateInputContext");
}
return context;
@@ -0,0 +1,9 @@
import { createContext } from "../../util/create-context";
import { TFunction } from "../../util/i18n/i18n.context";
interface DateTranslationContextProps {
translate: TFunction<"DatePicker">;
}
export const [DateTranslationContextProvider, useDateTranslationContext] =
createContext<DateTranslationContextProps>();
@@ -5,11 +5,11 @@ 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 } from "../../util/i18n/i18n.context";
import { DateContext } from "../context";
import { useDateLocale, useI18n } from "../../util/i18n/i18n.context";
import { DateInputContext, DateTranslationContextProvider } from "../context";
import { DatePickerInput } from "../parts/DateInput";
import { DateWrapper } from "../parts/DateWrapper";
import { getLocaleFromString } from "../utils";
import { getLocaleFromString, getTranslations } from "../utils";
import DatePickerStandalone from "./DatePickerStandalone";
import Caption from "./parts/Caption";
import DropdownCaption from "./parts/DropdownCaption";
@@ -68,6 +68,7 @@ export const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(
{
children,
locale,
translations,
dropdownCaption,
disabled = [],
disableWeekends = false,
@@ -86,6 +87,11 @@ export const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(
},
ref,
) => {
const translate = useI18n(
"DatePicker",
translations,
getTranslations(locale),
);
const langProviderLocale = useDateLocale();
const ariaId = useId(id);
const [open, setOpen] = useState(_open ?? false);
@@ -151,37 +157,40 @@ export const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(
);
return (
<DateContext.Provider
value={{
open: _open ?? open,
onOpen: () => {
setOpen((x) => !x);
onOpenToggle?.();
},
ariaId,
defined: true,
}}
>
<div
ref={mergedRef}
className={cl("navds-date__wrapper", wrapperClassName)}
<DateTranslationContextProvider translate={translate}>
<DateInputContext.Provider
value={{
open: _open ?? open,
onOpen: () => {
setOpen((x) => !x);
onOpenToggle?.();
},
ariaId,
defined: true,
}}
>
{children}
<DateWrapper
open={_open ?? open}
anchor={wrapperRef}
onClose={() => onClose?.() ?? setOpen(false)}
locale={locale}
variant={mode}
popoverProps={{
id: ariaId,
strategy,
}}
<div
ref={mergedRef}
className={cl("navds-date__wrapper", wrapperClassName)}
>
{DatePickerComponent}
</DateWrapper>
</div>
</DateContext.Provider>
{children}
<DateWrapper
open={_open ?? open}
anchor={wrapperRef}
onClose={() => onClose?.() ?? setOpen(false)}
locale={locale}
translate={translate}
variant={mode}
popoverProps={{
id: ariaId,
strategy,
}}
>
{DatePickerComponent}
</DateWrapper>
</div>
</DateInputContext.Provider>
</DateTranslationContextProvider>
);
},
) as DatePickerComponent;
@@ -3,8 +3,9 @@ import { isWeekend } from "date-fns";
import React, { forwardRef } from "react";
import { DateRange, DayPicker, isMatch } from "react-day-picker";
import { omit } from "../../util";
import { useDateLocale } from "../../util/i18n/i18n.context";
import { getLocaleFromString } from "../utils";
import { useDateLocale, useI18n } from "../../util/i18n/i18n.context";
import { DateTranslationContextProvider } from "../context";
import { getLocaleFromString, getTranslations } from "../utils";
import Caption from "./parts/Caption";
import DropdownCaption from "./parts/DropdownCaption";
import { HeadRow } from "./parts/HeadRow";
@@ -51,6 +52,7 @@ export const DatePickerStandalone: DatePickerStandaloneType = forwardRef<
{
className,
locale,
translations,
dropdownCaption,
disabled = [],
disableWeekends = false,
@@ -64,6 +66,11 @@ export const DatePickerStandalone: DatePickerStandaloneType = forwardRef<
},
ref,
) => {
const translate = useI18n(
"DatePicker",
translations,
getTranslations(locale),
);
const langProviderLocale = useDateLocale();
const [selectedDates, setSelectedDates] = React.useState<
Date | Date[] | DateRange | undefined
@@ -84,41 +91,43 @@ export const DatePickerStandalone: DatePickerStandaloneType = forwardRef<
ref={ref}
className={cl("navds-date__standalone-wrapper", className)}
>
<DayPicker
locale={locale ? getLocaleFromString(locale) : langProviderLocale}
mode={mode}
onSelect={handleSelect}
selected={selected ?? selectedDates}
components={{
Caption: dropdownCaption ? DropdownCaption : Caption,
Head: TableHead,
HeadRow,
WeekNumber,
Row,
}}
className="navds-date"
classNames={{ vhidden: "navds-sr-only" }}
disabled={(day) => {
return (
(disableWeekends && isWeekend(day)) || isMatch(day, disabled)
);
}}
weekStartsOn={1}
initialFocus={false}
modifiers={{
weekend: (day) => disableWeekends && isWeekend(day),
}}
modifiersClassNames={{
weekend: "rdp-day__weekend",
}}
showWeekNumber={showWeekNumber}
onWeekNumberClick={
mode === "multiple" ? onWeekNumberClick : undefined
}
fixedWeeks={fixedWeeks}
showOutsideDays
{...omit(rest, ["children", "id"])}
/>
<DateTranslationContextProvider translate={translate}>
<DayPicker
locale={locale ? getLocaleFromString(locale) : langProviderLocale}
mode={mode}
onSelect={handleSelect}
selected={selected ?? selectedDates}
components={{
Caption: dropdownCaption ? DropdownCaption : Caption,
Head: TableHead,
HeadRow,
WeekNumber,
Row,
}}
className="navds-date"
classNames={{ vhidden: "navds-sr-only" }}
disabled={(day) => {
return (
(disableWeekends && isWeekend(day)) || isMatch(day, disabled)
);
}}
weekStartsOn={1}
initialFocus={false}
modifiers={{
weekend: (day) => disableWeekends && isWeekend(day),
}}
modifiersClassNames={{
weekend: "rdp-day__weekend",
}}
showWeekNumber={showWeekNumber}
onWeekNumberClick={
mode === "multiple" ? onWeekNumberClick : undefined
}
fixedWeeks={fixedWeeks}
showOutsideDays
{...omit(rest, ["children", "id"])}
/>
</DateTranslationContextProvider>
</div>
);
},
@@ -247,7 +247,7 @@ export const Validering = () => {
<DatePicker.Input
error={
error
? "NAV-kontoret er ikke åpent i helger. Velg en annen dag."
? "Nav-kontoret er ikke åpent i helger. Velg en annen dag."
: undefined
}
{...inputProps}
@@ -3,8 +3,7 @@ import { CaptionProps, useDayPicker, useNavigation } from "react-day-picker";
import { ArrowLeftIcon, ArrowRightIcon } from "@navikt/aksel-icons";
import { Button } from "../../../button";
import { Label } from "../../../typography";
import { useI18n } from "../../../util/i18n/i18n.context";
import { getTranslations } from "../../utils";
import { useDateTranslationContext } from "../../context";
import WeekRow from "./WeekRow";
/**
@@ -16,7 +15,7 @@ export const DatePickerCaption = ({ displayMonth, id }: CaptionProps) => {
formatters: { formatCaption },
locale,
} = useDayPicker();
const translate = useI18n("DatePicker", getTranslations(locale.code));
const translate = useDateTranslationContext().translate;
return (
<>
@@ -4,8 +4,8 @@ import { CaptionProps, useDayPicker, useNavigation } from "react-day-picker";
import { ArrowLeftIcon, ArrowRightIcon } from "@navikt/aksel-icons";
import { Button } from "../../../button";
import { Select } from "../../../form/select";
import { useI18n } from "../../../util/i18n/i18n.context";
import { getMonths, getTranslations, getYears } from "../../utils";
import { useDateTranslationContext } from "../../context";
import { getMonths, getYears } from "../../utils";
import WeekRow from "./WeekRow";
/**
@@ -19,7 +19,7 @@ export const DropdownCaption = ({ displayMonth, id }: CaptionProps) => {
formatters: { formatYearCaption, formatMonthCaption, formatCaption },
locale,
} = useDayPicker();
const translate = useI18n("DatePicker", getTranslations(locale.code));
const translate = useDateTranslationContext().translate;
if (!fromDate || !toDate) {
console.warn("Using dropdownCaption required fromDate and toDate");
@@ -2,10 +2,9 @@
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 { useI18n } from "../../../util/i18n/i18n.context";
import { getTranslations } from "../../utils";
import { useDateTranslationContext } from "../../context";
export interface WeekNumberProps {
/** The number of the week. */
@@ -21,14 +20,9 @@ function WeekNumber({
number: weekNumber,
dates,
}: WeekNumberProps): JSX.Element {
const {
onWeekNumberClick,
styles,
classNames,
locale: { code },
} = useDayPicker();
const themeContext = UNSAFE_useAkselTheme(false);
const translate = useI18n("DatePicker", getTranslations(code));
const { onWeekNumberClick, styles, classNames } = useDayPicker();
const themeContext = useThemeInternal(false);
const translate = useDateTranslationContext().translate;
if (!onWeekNumberClick) {
return (
@@ -3,14 +3,13 @@ import { useDayPicker } from "react-day-picker";
import { Show } from "../../../layout/responsive";
import { Detail } from "../../../typography";
import { useId } from "../../../util/hooks";
import { useI18n } from "../../../util/i18n/i18n.context";
import { getTranslations } from "../../utils";
import { useDateTranslationContext } from "../../context";
import { getMonthWeeks } from "../../utils/get-month-weeks";
import WeekNumber from "./WeekNumber";
const WeekRow = ({ displayMonth }: { displayMonth: Date }) => {
const { locale, fixedWeeks, onWeekNumberClick } = useDayPicker();
const translate = useI18n("DatePicker", getTranslations(locale.code));
const translate = useDateTranslationContext().translate;
const labelId = useId();
if (!onWeekNumberClick) {
@@ -1,4 +1,5 @@
import { DateRange, DayPickerBase, Matcher } from "react-day-picker";
import { ComponentTranslation } from "../../util/i18n/i18n.types";
export type SingleMode = {
mode?: "single";
@@ -52,8 +53,15 @@ export interface DatePickerDefaultProps
/**
* Changes datepicker locale
* @default "nb" (norsk bokmål)
* @deprecated Use `<Provider />`-component
*/
locale?: "nb" | "nn" | "en";
/**
* i18n-API for customizing texts and labels.
*
* **NB: If you need to change the language, use [Provider](https://aksel.nav.no/komponenter/core/provider#84d7ea5ec517) instead.**
*/
translations?: ComponentTranslation<"DatePicker">;
/**
* The earliest day to start navigation.
*/
@@ -10,9 +10,7 @@ import { useDayPicker } from "react-day-picker";
import { ArrowLeftIcon, ArrowRightIcon } from "@navikt/aksel-icons";
import { Button } from "../../button";
import { Select } from "../../form/select";
import { useI18n } from "../../util/i18n/i18n.context";
import { useSharedMonthContext } from "../context";
import { getTranslations } from "../utils";
import { useDateTranslationContext, useSharedMonthContext } from "../context";
export const MonthCaption = () => {
const {
@@ -22,7 +20,7 @@ export const MonthCaption = () => {
locale,
} = useDayPicker();
const { hasDropdown, year, toYear } = useSharedMonthContext();
const translate = useI18n("DatePicker", getTranslations(locale.code));
const translate = useDateTranslationContext().translate;
const years: Date[] = [];
@@ -3,11 +3,15 @@ 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 } from "../../util/i18n/i18n.context";
import { DateContext, SharedMonthProvider } from "../context";
import { useDateLocale, useI18n } from "../../util/i18n/i18n.context";
import {
DateInputContext,
DateTranslationContextProvider,
SharedMonthProvider,
} from "../context";
import { MonthPickerInput } from "../parts/DateInput";
import { DateWrapper } from "../parts/DateWrapper";
import { getLocaleFromString } from "../utils";
import { getLocaleFromString, getTranslations } from "../utils";
import MonthCaption from "./MonthCaption";
import MonthPickerStandalone from "./MonthPickerStandalone";
import MonthSelector from "./MonthSelector";
@@ -69,6 +73,7 @@ export const MonthPicker = forwardRef<HTMLDivElement, MonthPickerProps>(
onClose,
onOpenToggle,
locale,
translations,
onMonthSelect,
className,
wrapperClassName,
@@ -79,6 +84,11 @@ export const MonthPicker = forwardRef<HTMLDivElement, MonthPickerProps>(
},
ref,
) => {
const translate = useI18n(
"DatePicker",
translations,
getTranslations(locale),
);
const langProviderLocale = useDateLocale();
const ariaId = useId(id);
const [open, setOpen] = useState(_open ?? false);
@@ -103,61 +113,64 @@ export const MonthPicker = forwardRef<HTMLDivElement, MonthPickerProps>(
}
return (
<DateContext.Provider
value={{
open: _open ?? open,
onOpen: () => {
setOpen((x) => !x);
onOpenToggle?.();
},
ariaId,
defined: true,
}}
>
<div
ref={mergedRef}
className={cl("navds-date__wrapper", wrapperClassName)}
<DateTranslationContextProvider translate={translate}>
<DateInputContext.Provider
value={{
open: _open ?? open,
onOpen: () => {
setOpen((x) => !x);
onOpenToggle?.();
},
ariaId,
defined: true,
}}
>
{children}
<DateWrapper
open={_open ?? open}
anchor={wrapperRef}
onClose={() => onClose?.() ?? setOpen(false)}
locale={locale}
variant="month"
popoverProps={{
id: ariaId,
strategy,
}}
<div
ref={mergedRef}
className={cl("navds-date__wrapper", wrapperClassName)}
>
<DayPickerProvider
initialProps={{
locale: locale
? getLocaleFromString(locale)
: langProviderLocale,
selected: selected ?? selectedMonth,
toDate,
fromDate,
month: selected ?? selectedMonth,
{children}
<DateWrapper
open={_open ?? open}
anchor={wrapperRef}
onClose={() => onClose?.() ?? setOpen(false)}
locale={locale}
translate={translate}
variant="month"
popoverProps={{
id: ariaId,
strategy,
}}
>
<div className={cl("rdp-month", className)}>
<SharedMonthProvider
dropdownCaption={dropdownCaption}
disabled={disabled}
selected={selected ?? selectedMonth}
onSelect={handleSelect}
year={year}
onYearChange={onYearChange}
>
<MonthCaption />
<MonthSelector />
</SharedMonthProvider>
</div>
</DayPickerProvider>
</DateWrapper>
</div>
</DateContext.Provider>
<DayPickerProvider
initialProps={{
locale: locale
? getLocaleFromString(locale)
: langProviderLocale,
selected: selected ?? selectedMonth,
toDate,
fromDate,
month: selected ?? selectedMonth,
}}
>
<div className={cl("rdp-month", className)}>
<SharedMonthProvider
dropdownCaption={dropdownCaption}
disabled={disabled}
selected={selected ?? selectedMonth}
onSelect={handleSelect}
year={year}
onYearChange={onYearChange}
>
<MonthCaption />
<MonthSelector />
</SharedMonthProvider>
</div>
</DayPickerProvider>
</DateWrapper>
</div>
</DateInputContext.Provider>
</DateTranslationContextProvider>
);
},
) as MonthPickerComponent;
@@ -1,8 +1,12 @@
import cl from "clsx";
import React, { forwardRef, useState } from "react";
import { DayPickerProvider } from "react-day-picker";
import { SharedMonthProvider } from "../context";
import { getLocaleFromString } from "../utils";
import { useDateLocale, useI18n } from "../../util/i18n/i18n.context";
import {
DateTranslationContextProvider,
SharedMonthProvider,
} from "../context";
import { getLocaleFromString, getTranslations } from "../utils";
import MonthCaption from "./MonthCaption";
import MonthSelector from "./MonthSelector";
import { MonthPickerProps } from "./types";
@@ -34,7 +38,8 @@ export const MonthPickerStandalone = forwardRef<
disabled = [],
selected,
className,
locale = "nb",
locale,
translations,
onMonthSelect,
defaultSelected,
year,
@@ -42,6 +47,12 @@ export const MonthPickerStandalone = forwardRef<
},
ref,
) => {
const translate = useI18n(
"DatePicker",
translations,
getTranslations(locale),
);
const langProviderLocale = useDateLocale();
const [selectedMonth, setSelectedMonth] = useState<Date | undefined>(
defaultSelected,
);
@@ -58,29 +69,31 @@ export const MonthPickerStandalone = forwardRef<
return (
<div ref={ref} className={cl("navds-date__wrapper", className)}>
<DayPickerProvider
initialProps={{
locale: getLocaleFromString(locale),
selected: selected ?? selectedMonth,
toDate,
fromDate,
month: selected ?? selectedMonth,
}}
>
<div className="navds-date rdp-month">
<SharedMonthProvider
dropdownCaption={dropdownCaption}
disabled={disabled}
selected={selected ?? selectedMonth}
onSelect={handleSelect}
year={year}
onYearChange={onYearChange}
>
<MonthCaption />
<MonthSelector />
</SharedMonthProvider>
</div>
</DayPickerProvider>
<DateTranslationContextProvider translate={translate}>
<DayPickerProvider
initialProps={{
locale: locale ? getLocaleFromString(locale) : langProviderLocale,
selected: selected ?? selectedMonth,
toDate,
fromDate,
month: selected ?? selectedMonth,
}}
>
<div className="navds-date rdp-month">
<SharedMonthProvider
dropdownCaption={dropdownCaption}
disabled={disabled}
selected={selected ?? selectedMonth}
onSelect={handleSelect}
year={year}
onYearChange={onYearChange}
>
<MonthCaption />
<MonthSelector />
</SharedMonthProvider>
</div>
</DayPickerProvider>
</DateTranslationContextProvider>
</div>
);
},
@@ -1,3 +1,4 @@
import { ComponentTranslation } from "../../util/i18n/i18n.types";
import { Matcher } from "../utils";
export interface MonthPickerProps extends React.HTMLAttributes<HTMLDivElement> {
@@ -25,8 +26,15 @@ export interface MonthPickerProps extends React.HTMLAttributes<HTMLDivElement> {
/**
* Changes monthpicker locale
* @default "nb" (norsk bokmål)
* @deprecated Use `<Provider />`-component
*/
locale?: "nb" | "nn" | "en";
/**
* i18n-API for customizing texts and labels.
*
* **NB: If you need to change the language, use [Provider](https://aksel.nav.no/komponenter/core/provider#84d7ea5ec517) instead.**
*/
translations?: ComponentTranslation<"DatePicker">;
/**
* Display dropdown for choosing year. Needs `fromDate` + `toDate` to work.
* @default false
@@ -5,8 +5,7 @@ import { ReadOnlyIcon } from "../../form/ReadOnlyIcon";
import { FormFieldProps, useFormField } from "../../form/useFormField";
import { BodyShort, ErrorMessage, Label } from "../../typography";
import { omit } from "../../util";
import { useI18n } from "../../util/i18n/i18n.context";
import { useDateInputContext } from "../context";
import { useDateInputContext, useDateTranslationContext } from "../context";
export interface DateInputProps
extends FormFieldProps,
@@ -47,7 +46,7 @@ const DateInput = forwardRef<HTMLInputElement, DateInputProps>((props, ref) => {
} = props;
const buttonRef = useRef<HTMLButtonElement>(null);
const translate = useI18n("DatePicker");
const translate = useDateTranslationContext().translate;
const isDatepickerVariant = variant === "datepicker";
@@ -151,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,8 +5,8 @@ import { Modal } from "../../modal";
import { useModalContext } from "../../modal/Modal.context";
import { Popover } from "../../popover";
import { useMedia } from "../../util/hooks";
import { useI18n } from "../../util/i18n/i18n.context";
import { getTranslations } from "../utils";
import { TFunction, useI18n } from "../../util/i18n/i18n.context";
import { getGlobalTranslations } from "../utils";
const variantToLabel = {
single: "chooseDate",
@@ -22,6 +22,7 @@ type DateWrapperProps = {
anchor: HTMLDivElement | null;
/** @deprecated Temporary to support locale prop */
locale: "nb" | "nn" | "en" | undefined;
translate: TFunction<"DatePicker">;
variant: "single" | "multiple" | "range" | "month";
popoverProps: {
id?: string;
@@ -35,10 +36,11 @@ export const DateWrapper = ({
onClose,
anchor,
locale,
translate,
variant,
popoverProps,
}: DateWrapperProps) => {
const translate = useI18n("DatePicker", getTranslations(locale));
const translateGlobal = useI18n("global", getGlobalTranslations(locale));
const modalRef = useRef<HTMLDialogElement>(null);
const isInModal = useModalContext(false) !== undefined;
const hideModal =
@@ -86,7 +88,7 @@ export const DateWrapper = ({
size="small"
type="button"
>
{translate("close")}
{translateGlobal("close")}
</Button>
</div>
</Modal>
+5 -1
View File
@@ -5,7 +5,11 @@ export {
INPUT_DATE_STRING_FORMAT_MONTH,
parseDate,
} from "./parse-date";
export { getLocaleFromString, getTranslations } from "./locale";
export {
getLocaleFromString,
getTranslations,
getGlobalTranslations,
} from "./locale";
export { disableDate } from "./dates-disabled";
export { dateIsInCurrentMonth, isValidDate } from "./check-dates";
+17 -1
View File
@@ -16,7 +16,7 @@ export const getLocaleFromString = (locale: "nb" | "nn" | "en" = "nb") => {
/**
* @private
* Temporary for backwards compatibility with locale prop
* Temporary for backwards compatibility with locale prop. Can be removed when locale prop has been removed.
*/
export const getTranslations = (locale: string | undefined) => {
switch (locale) {
@@ -29,3 +29,19 @@ export const getTranslations = (locale: string | undefined) => {
return undefined;
}
};
/**
* @private
* Temporary for backwards compatibility with locale prop. Can be removed when locale prop has been removed.
*/
export const getGlobalTranslations = (locale: string | undefined) => {
switch (locale) {
case "nn":
return nn_translations.global;
case "en":
case "en-GB":
return en_translations.global;
default:
return undefined;
}
};
@@ -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>
);
@@ -27,21 +27,20 @@ const ComboboxWrapper = ({
const wrapperRef = useRef<HTMLDivElement | null>(null);
const [hasFocusWithin, setHasFocusWithin] = useState(false);
function onFocusInsideWrapper(e) {
function onFocusInsideWrapper(event: React.FocusEvent<HTMLDivElement>) {
if (
!wrapperRef.current?.contains(e.relatedTarget) &&
toggleOpenButtonRef?.current !== e.target
!wrapperRef.current?.contains(event.relatedTarget) &&
toggleOpenButtonRef?.current !== event.target
) {
toggleIsListOpen(true);
setHasFocusWithin(true);
}
}
function onBlurWrapper(e) {
if (!wrapperRef.current?.contains(e.relatedTarget)) {
function onBlurWrapper(event: React.FocusEvent<HTMLDivElement>) {
if (!wrapperRef.current?.contains(event.relatedTarget)) {
toggleIsListOpen(false);
setHasFocusWithin(false);
clearInput(e);
clearInput(event);
}
}
@@ -26,12 +26,12 @@ const FilteredOptions = () => {
const { maxSelected } = useSelectedOptionsContext();
const shouldRenderNonSelectables =
maxSelected?.isLimitReached || // Render maxSelected message
maxSelected.isLimitReached || // Render maxSelected message
isLoading || // Render loading message
(!isLoading && filteredOptions.length === 0 && !allowNewValues); // Render no hits message
const shouldRenderFilteredOptionsList =
(allowNewValues && isValueNew && !maxSelected?.isLimitReached) || // Render add new option
(allowNewValues && isValueNew && !maxSelected.isLimitReached) || // Render add new option
filteredOptions.length > 0; // Render filtered options
return (
@@ -45,7 +45,7 @@ const FilteredOptions = () => {
>
{shouldRenderNonSelectables && (
<div className="navds-combobox__list_non-selectables" role="status">
{maxSelected?.isLimitReached && <MaxSelectedMessage />}
{maxSelected.isLimitReached && <MaxSelectedMessage />}
{isLoading && <LoadingMessage />}
{!isLoading && filteredOptions.length === 0 && !allowNewValues && (
<NoSearchHitsMessage />
@@ -60,7 +60,7 @@ const FilteredOptions = () => {
role="listbox"
className="navds-combobox__list-options"
>
{isValueNew && !maxSelected?.isLimitReached && allowNewValues && (
{isValueNew && !maxSelected.isLimitReached && allowNewValues && (
<AddNewOption />
)}
{filteredOptions.map((option) => (
@@ -39,7 +39,7 @@ const FilteredOptionsItem = ({ option }: { option: ComboboxOption }) => {
const [start, highlight, end] = useTextHighlight(option.label, searchTerm);
const isDisabled = (_option: ComboboxOption) =>
maxSelected?.isLimitReached && !isInList(_option.value, selectedOptions);
maxSelected.isLimitReached && !isInList(_option.value, selectedOptions);
return (
<li
@@ -9,14 +9,7 @@ const MaxSelectedMessage = () => {
inputProps: { id },
} = useInputContext();
const { maxSelected, selectedOptions } = useSelectedOptionsContext();
const translate = useI18n(
"Combobox",
maxSelected?.message ? { maxSelected: maxSelected.message } : undefined,
);
if (!maxSelected) {
return null;
}
const translate = useI18n("Combobox");
return (
<div
@@ -25,7 +18,7 @@ const MaxSelectedMessage = () => {
>
{translate("maxSelected", {
selected: selectedOptions.length,
limit: maxSelected.limit,
limit: maxSelected.limit || 0,
})}
</div>
);
@@ -142,13 +142,13 @@ const FilteredOptionsProvider = ({
}
virtualFocus.resetFocus();
if (newState ?? !isInternalListOpen) {
setHideCaret(!!maxSelected?.isLimitReached);
setHideCaret(maxSelected.isLimitReached);
}
setInternalListOpen((oldState) => newState ?? !oldState);
},
[
virtualFocus,
maxSelected?.isLimitReached,
maxSelected.isLimitReached,
isInternalListOpen,
setHideCaret,
disabled,
@@ -178,7 +178,7 @@ const FilteredOptionsProvider = ({
}
}
const maybeMaxSelectedOptionsId =
maxSelected?.isLimitReached &&
maxSelected.isLimitReached &&
filteredOptionsUtils.getMaxSelectedOptionsId(id);
return (
@@ -188,7 +188,7 @@ const FilteredOptionsProvider = ({
}, [
isListOpen,
isLoading,
maxSelected?.isLimitReached,
maxSelected.isLimitReached,
value,
partialAriaDescribedBy,
shouldAutocomplete,
@@ -93,7 +93,7 @@ const InputProvider = ({ children, value: props }: Props) => {
);
const clearInput = useCallback(
(event: React.PointerEvent | React.KeyboardEvent | React.MouseEvent) => {
(event: React.PointerEvent | React.KeyboardEvent | React.FocusEvent) => {
onClear?.(event);
externalOnChange?.("");
setInternalValue("");
@@ -75,7 +75,7 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
const onEnter = useCallback(
(event: React.KeyboardEvent) => {
const isTextInSelectedOptions = (text: string) =>
const isSelected = (text: string) =>
selectedOptions.some(
(option) =>
option.label.toLocaleLowerCase() === text.toLocaleLowerCase(),
@@ -85,10 +85,10 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
event.preventDefault();
// Selecting a value from the dropdown / FilteredOptions
toggleOption(currentOption, event);
if (!isMultiSelect && !isTextInSelectedOptions(currentOption.label)) {
if (!isMultiSelect && !isSelected(currentOption.label)) {
toggleIsListOpen(false);
}
} else if (isTextInSelectedOptions(value)) {
} else if (isSelected(value)) {
event.preventDefault();
// Trying to set the same value that is already set, so just clearing the input
clearInput(event);
@@ -109,23 +109,23 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
filteredOptionsUtil.normalizeText(value) ===
filteredOptionsUtil.normalizeText(autoCompletedOption?.label ?? "");
let selectedValue: ComboboxOption | undefined;
let optionToToggle: ComboboxOption | undefined;
if (
shouldAutocomplete &&
autoCompletedOption &&
autoCompleteMatchesValue
) {
selectedValue = autoCompletedOption;
optionToToggle = autoCompletedOption;
} else if (allowNewValues && isValueNew) {
selectedValue = { label: value, value };
optionToToggle = { label: value, value };
}
if (!selectedValue) {
if (!optionToToggle) {
return;
}
toggleOption(selectedValue, event);
if (!isMultiSelect && !isTextInSelectedOptions(selectedValue.label)) {
toggleOption(optionToToggle, event);
if (!isMultiSelect && !isSelected(optionToToggle.label)) {
toggleIsListOpen(false);
}
}
@@ -279,7 +279,7 @@ const Input = forwardRef<HTMLInputElement, InputProps>(
value={value}
onBlur={composeEventHandlers(onBlur, virtualFocus.resetFocus)}
onClick={() => {
setHideCaret(!!maxSelected?.isLimitReached);
setHideCaret(maxSelected.isLimitReached);
value !== searchTerm && onChange(value);
}}
onInput={onChangeHandler}
@@ -1,9 +1,7 @@
/* eslint-disable jsx-a11y/no-static-element-interactions */
import cl from "clsx";
import React, { forwardRef } from "react";
import { XMarkIcon } from "@navikt/aksel-icons";
import { useMergeRefs } from "../../../util/hooks";
import { useI18n } from "../../../util/i18n/i18n.context";
import { useFilteredOptionsContext } from "../FilteredOptions/filteredOptionsContext";
import SelectedOptions from "../SelectedOptions/SelectedOptions";
import { useSelectedOptionsContext } from "../SelectedOptions/selectedOptionsContext";
@@ -28,35 +26,31 @@ export const InputController = forwardRef<
>
>((props, ref) => {
const {
clearButton = true,
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- Remove when prop has been removed from ComboboxProps.
clearButton,
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- Remove when prop has been removed from ComboboxProps.
clearButtonLabel,
toggleListButton = true,
inputClassName,
shouldShowSelectedOptions = true,
...rest
} = props;
const {
clearInput,
focusInput,
inputProps,
value,
size = "medium",
inputRef,
toggleOpenButtonRef,
readOnly,
} = useInputContext();
const { activeDecendantId } = useFilteredOptionsContext();
const { activeDecendantId, toggleIsListOpen } = useFilteredOptionsContext();
const { selectedOptions } = useSelectedOptionsContext();
const mergedInputRef = useMergeRefs(inputRef, ref);
const translate = useI18n(
"Combobox",
clearButtonLabel ? { clear: clearButtonLabel } : undefined,
);
return (
// eslint-disable-next-line jsx-a11y/click-events-have-key-events
<div
@@ -64,7 +58,14 @@ export const InputController = forwardRef<
"navds-combobox__wrapper-inner--virtually-unfocused":
activeDecendantId !== undefined,
})}
onClick={focusInput}
onClick={() => {
if (inputProps.disabled || readOnly) {
return;
}
toggleIsListOpen(true);
focusInput();
}}
>
{!shouldShowSelectedOptions ? (
<Input
@@ -86,19 +87,7 @@ export const InputController = forwardRef<
/>
</SelectedOptions>
)}
<div>
{value && clearButton && (
<div
onClick={clearInput}
className="navds-combobox__button-clear"
aria-hidden
title={translate("clear")}
>
<XMarkIcon />
</div>
)}
{toggleListButton && <ToggleListButton ref={toggleOpenButtonRef} />}
</div>
{toggleListButton && <ToggleListButton ref={toggleOpenButtonRef} />}
</div>
);
});
@@ -12,7 +12,7 @@ type SelectedOptionsContextValue = {
removeSelectedOption: (option: ComboboxOption) => void;
prevSelectedOptions?: ComboboxOption[];
selectedOptions: ComboboxOption[];
maxSelected?: ComboboxProps["maxSelected"] & { isLimitReached: boolean };
maxSelected: { limit: number | undefined; isLimitReached: boolean };
setSelectedOptions: (any) => void;
toggleOption: (
option: ComboboxOption,
@@ -101,14 +101,17 @@ const SelectedOptionsProvider = ({
[customOptions, onToggleSelected, removeCustomOption],
);
const maxSelectedLimit =
typeof maxSelected === "object" ? maxSelected.limit : maxSelected;
const isLimitReached =
(!!maxSelected?.limit && selectedOptions.length >= maxSelected.limit) ||
(!isMultiSelect && selectedOptions.length > 0);
!!maxSelectedLimit && selectedOptions.length >= maxSelectedLimit;
const newHideCaret =
isLimitReached || (!isMultiSelect && selectedOptions.length > 0);
// biome-ignore lint/correctness/useExhaustiveDependencies: We explicitly want to run this effect when selectedOptions changes to match the view with the selected options.
useEffect(() => {
setHideCaret(isLimitReached);
}, [isLimitReached, selectedOptions, setHideCaret]);
setHideCaret(newHideCaret);
}, [newHideCaret, selectedOptions, setHideCaret]);
const toggleOption = useCallback(
(
@@ -117,6 +120,8 @@ const SelectedOptionsProvider = ({
) => {
if (isInList(option.value, selectedOptions)) {
removeSelectedOption(option);
} else if (isMultiSelect && isLimitReached) {
return;
} else {
addSelectedOption(option);
}
@@ -129,6 +134,8 @@ const SelectedOptionsProvider = ({
focusInput,
removeSelectedOption,
selectedOptions,
isLimitReached,
isMultiSelect,
],
);
@@ -142,8 +149,8 @@ const SelectedOptionsProvider = ({
selectedOptions,
setSelectedOptions,
toggleOption,
maxSelected: maxSelected && {
...maxSelected,
maxSelected: {
limit: maxSelectedLimit,
isLimitReached,
},
};
@@ -38,16 +38,8 @@ const options = [
"grapefruit",
];
export const Default: StoryFn<
ComboboxProps & { maxSelected?: number; maxSelectedMessage?: string }
> = ({ maxSelected, maxSelectedMessage, ...rest }) => (
<UNSAFE_Combobox
{...rest}
maxSelected={
maxSelected && { limit: maxSelected, message: maxSelectedMessage }
}
id="combobox"
/>
export const Default: StoryFn<ComboboxProps> = (props) => (
<UNSAFE_Combobox {...props} id="combobox" />
);
Default.args = {
options,
@@ -77,16 +69,13 @@ Default.argTypes = {
maxSelected: {
control: { type: "number" },
},
maxSelectedMessage: {
control: { type: "text" },
},
size: {
options: ["medium", "small"],
defaultValue: "medium",
control: { type: "radio" },
},
clearButtonLabel: {
control: { type: "text" },
toggleListButton: {
control: { type: "boolean" },
},
};
@@ -426,7 +415,7 @@ export const MaxSelectedOptions: StoryFn = ({ open }: { open?: boolean }) => {
id="combobox-with-max-selected-options"
label="Komboboks med begrenset antall valg"
options={options}
maxSelected={{ limit: 2 }}
maxSelected={2}
selectedOptions={selectedOptions}
onToggleSelected={(option, isSelected) =>
isSelected
+11 -19
View File
@@ -45,15 +45,11 @@ export interface ComboboxProps
*/
allowNewValues?: boolean;
/**
* Adds a button to clear the input value when not empty.
* NB: Will not clear selected values.
* @default true
* @deprecated The clear button has been removed. This prop has no effect.
*/
clearButton?: boolean;
/**
* Custom name for the clear button. Requires `clearButton` to be `true`.
*
* @default "Tøm"
* @deprecated The clear button has been removed. This prop has no effect.
*/
clearButtonLabel?: string;
/**
@@ -102,7 +98,7 @@ export interface ComboboxProps
* @param event
*/
onClear?: (
event: React.PointerEvent | React.KeyboardEvent | React.MouseEvent,
event: React.PointerEvent | React.KeyboardEvent | React.FocusEvent,
) => void;
/**
* Callback function triggered whenever an option is selected or de-selected.
@@ -124,19 +120,15 @@ export interface ComboboxProps
*/
selectedOptions?: string[] | ComboboxOption[];
/**
* Options for the maximum number of selected options.
* Maximum number of selected options.
* @example maxSelected={3}
*/
maxSelected?: {
/**
* The limit for maximum selected options
*/
limit: number;
/**
* Message to display when the limit for maximum selected options has been reached
* @default "{selected} av maks {limit} er valgt."
*/
message?: string;
};
maxSelected?:
| {
/** @deprecated Provide a number instead of an object */
limit: number;
}
| number;
/**
* Set to `true` to enable inline autocomplete.
*
@@ -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>
);
@@ -2,8 +2,6 @@ import { Meta, StoryObj } from "@storybook/react";
import { expect, userEvent, within } from "@storybook/test";
import React, { useRef } from "react";
import { VStack } from "../../layout/stack";
import UNSAFE_AkselLanguageProvider from "../../provider/i18n/LanguageProvider";
import nn from "../../util/i18n/locales/nn";
import { ErrorSummary } from "./ErrorSummary";
export default {
@@ -136,18 +134,3 @@ export const Chromatic: Story = {
chromatic: { disable: false },
},
};
export const ProvidedTranslations: Story = {
render: () => {
return (
<UNSAFE_AkselLanguageProvider translations={nn}>
<ErrorSummary size="small">
<ErrorSummary.Item href="#1">Checkbox må fylles ut</ErrorSummary.Item>
<ErrorSummary.Item href="#2">
Tekstfeltet må ha en godkjent e-post
</ErrorSummary.Item>
</ErrorSummary>
</UNSAFE_AkselLanguageProvider>
);
},
};
@@ -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>
@@ -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>
);
@@ -1,7 +1,8 @@
import { Meta, StoryFn } from "@storybook/react";
import React, { useState } from "react";
import VStack from "../../layout/stack/VStack";
import UNSAFE_AkselLanguageProvider from "../../provider/i18n/LanguageProvider";
import { Provider } from "../../provider";
import en from "../../util/i18n/locales/en";
import FormProgress, { FormProgressProps } from "./FormProgress";
export default {
@@ -27,7 +28,7 @@ export const Default: StoryFn<ControllableProps> = (props) => (
Saksopplysninger
</FormProgress.Step>
<FormProgress.Step interactive={false}>
Søknadstekst for en veldig spesifikk prosess i NAV som har lang tekst
Søknadstekst for en veldig spesifikk prosess i Nav som har lang tekst
</FormProgress.Step>
<FormProgress.Step href="#">Vedlegg</FormProgress.Step>
<FormProgress.Step href="#">Oppsummering</FormProgress.Step>
@@ -41,14 +42,12 @@ Default.args = { activeStep: 2, totalSteps: 7, interactiveSteps: true };
export const ProvidedTranslations: StoryFn = () => {
const translations = {
FormProgress: {
step: "Step {activeStep} of {totalSteps}",
showAllSteps: "Show all steps",
hideAllSteps: "Hide all steps",
step: "Step {activeStep}/{totalSteps}",
},
};
return (
<UNSAFE_AkselLanguageProvider translations={translations}>
<Provider locale={en} translations={translations}>
<FormProgress activeStep={2} totalSteps={7} interactiveSteps>
<FormProgress.Step href="#" completed>
Start søknad
@@ -58,19 +57,19 @@ export const ProvidedTranslations: StoryFn = () => {
Saksopplysninger
</FormProgress.Step>
<FormProgress.Step interactive={false}>
Søknadstekst for en veldig spesifikk prosess i NAV som har lang tekst
Søknadstekst for en veldig spesifikk prosess i Nav som har lang tekst
</FormProgress.Step>
<FormProgress.Step href="#">Vedlegg</FormProgress.Step>
<FormProgress.Step href="#">Oppsummering</FormProgress.Step>
<FormProgress.Step href="#">Innsending</FormProgress.Step>
</FormProgress>
</UNSAFE_AkselLanguageProvider>
</Provider>
);
};
export const DefaultTranslations: StoryFn = () => {
return (
<UNSAFE_AkselLanguageProvider>
<Provider>
<FormProgress activeStep={2} totalSteps={7} interactiveSteps>
<FormProgress.Step href="#" completed>
Start søknad
@@ -80,22 +79,22 @@ export const DefaultTranslations: StoryFn = () => {
Saksopplysninger
</FormProgress.Step>
<FormProgress.Step interactive={false}>
Søknadstekst for en veldig spesifikk prosess i NAV som har lang tekst
Søknadstekst for en veldig spesifikk prosess i Nav som har lang tekst
</FormProgress.Step>
<FormProgress.Step href="#">Vedlegg</FormProgress.Step>
<FormProgress.Step href="#">Oppsummering</FormProgress.Step>
<FormProgress.Step href="#">Innsending</FormProgress.Step>
</FormProgress>
</UNSAFE_AkselLanguageProvider>
</Provider>
);
};
export const ComponentTranslations: StoryFn = () => {
const globalTranslations = {
FormProgress: {
step: "Step {activeStep} of {totalSteps}",
showAllSteps: "Show all steps",
hideAllSteps: "Hide all steps",
step: "Step {activeStep}/{totalSteps}",
showAllSteps: "Show all",
hideAllSteps: "Hide all",
},
};
const translations = {
@@ -104,7 +103,7 @@ export const ComponentTranslations: StoryFn = () => {
hideAllSteps: "Fela öll skref",
};
return (
<UNSAFE_AkselLanguageProvider translations={globalTranslations}>
<Provider locale={en} translations={globalTranslations}>
<FormProgress
translations={translations}
activeStep={2}
@@ -119,13 +118,13 @@ export const ComponentTranslations: StoryFn = () => {
Saksopplysninger
</FormProgress.Step>
<FormProgress.Step interactive={false}>
Søknadstekst for en veldig spesifikk prosess i NAV som har lang tekst
Søknadstekst for en veldig spesifikk prosess i Nav som har lang tekst
</FormProgress.Step>
<FormProgress.Step href="#">Vedlegg</FormProgress.Step>
<FormProgress.Step href="#">Oppsummering</FormProgress.Step>
<FormProgress.Step href="#">Innsending</FormProgress.Step>
</FormProgress>
</UNSAFE_AkselLanguageProvider>
</Provider>
);
};
@@ -7,7 +7,7 @@ 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";
@@ -52,7 +52,8 @@ export interface SearchProps
onSearchClick?: (value: string) => void;
/**
* Sets the `aria-label` for the clear button.
* @default "Tøm"
* @default "Tøm feltet"
* @deprecated Use `<Provider />`-component
*/
clearButtonLabel?: string;
/**
@@ -91,7 +92,7 @@ interface SearchComponent
* @example
* ```jsx
* <form role="search">
* <Search label="Søk alle NAV sine sider" variant="primary" />
* <Search label="Søk alle Nav sine sider" variant="primary" />
* </form>
* ```
*/
@@ -124,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);
@@ -262,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>
@@ -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>
+1 -10
View File
@@ -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
@@ -54,6 +54,7 @@ export interface TextareaProps
UNSAFE_autoScrollbar?: boolean;
/**
* i18n-translations for counter-text
* @deprecated Use `<Provider />`-component
*/
i18n?: {
/** @default tegn igjen */
@@ -192,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,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.
Loaded 100 of 272 files, more files were not shown because too many files have changed in this diff. Show more