diff --git a/.stylelintrc.mjs b/.stylelintrc.mjs deleted file mode 100644 index 1b8f451167..0000000000 --- a/.stylelintrc.mjs +++ /dev/null @@ -1,19 +0,0 @@ -/** @type {import('stylelint').Config} */ -export default { - extends: ['stylelint-config-standard'], - rules: { - 'declaration-block-no-redundant-longhand-properties': null, - 'media-feature-range-notation': 'prefix', - 'custom-property-pattern': null, - 'selector-class-pattern': [ - '(^[a-z][a-zA-Z0-9]+)|([a-z]+)$', - { - severity: 'warning', - message: 'Its recommened to use camelCase or kebab-case', - }, - ], - 'alpha-value-notation': 'number', - 'font-family-name-quotes': 'always-unless-keyword', - 'at-rule-no-unknown': [true, { ignoreAtRules: ['composes'] }], // Allows `@composes classname from './file.css'` directive - }, -}; diff --git a/.vscode/settings.json b/.vscode/settings.json index 54ff9f1077..b71e719a32 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,9 +9,8 @@ "editor.defaultFormatter": "biomejs.biome", "css.customData": ["./.vscode/css-data.json"], "[css]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "biomejs.biome" }, - "prettier.prettierPath": "./node_modules/prettier", "typescript.tsdk": "node_modules/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true, "cssvar.files": [ @@ -21,9 +20,9 @@ ], "html-css-class-completion.includeGlobPattern": "packages/css/**/*.{css,html}", "[github-actions-workflow]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "biomejs.biome" }, "[html]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "biomejs.biome" } } diff --git a/apps/storefront/app/bloggen/_components/Card/BlogCard.module.css b/apps/storefront/app/bloggen/_components/Card/BlogCard.module.css index e251f12e28..f06ae9bca0 100644 --- a/apps/storefront/app/bloggen/_components/Card/BlogCard.module.css +++ b/apps/storefront/app/bloggen/_components/Card/BlogCard.module.css @@ -1,5 +1,5 @@ .image { - aspect-ratio: 16/9; + aspect-ratio: 16 / 9; } @media screen and (min-width: 1024px) { diff --git a/apps/storefront/components/ComponentCard/ComponentCard.module.css b/apps/storefront/components/ComponentCard/ComponentCard.module.css index 2789d1bdf1..bcc52f1793 100644 --- a/apps/storefront/components/ComponentCard/ComponentCard.module.css +++ b/apps/storefront/components/ComponentCard/ComponentCard.module.css @@ -6,9 +6,7 @@ border-radius: var(--ds-border-radius-md); box-shadow: var(--ds-shadow-xs); text-decoration: none; - transition: - 0.2s transform ease-in-out, - 0.2s box-shadow ease-in-out; + transition: 0.2s transform ease-in-out, 0.2s box-shadow ease-in-out; } .card:hover { diff --git a/apps/storefront/components/NavigationCard/NavigationCard.module.css b/apps/storefront/components/NavigationCard/NavigationCard.module.css index b55ff4bc73..93baf2e0ff 100644 --- a/apps/storefront/components/NavigationCard/NavigationCard.module.css +++ b/apps/storefront/components/NavigationCard/NavigationCard.module.css @@ -6,9 +6,7 @@ text-decoration: none; box-shadow: var(--ds-shadow-sm); border-radius: 8px; - transition: - 0.2s transform, - 0.2s box-shadow; + transition: 0.2s transform, 0.2s box-shadow; position: relative; z-index: 2; height: 100%; diff --git a/apps/storefront/components/Tokens/TokenColor/TokenColor.module.css b/apps/storefront/components/Tokens/TokenColor/TokenColor.module.css index 7414764e29..fdd96a4159 100644 --- a/apps/storefront/components/Tokens/TokenColor/TokenColor.module.css +++ b/apps/storefront/components/Tokens/TokenColor/TokenColor.module.css @@ -25,9 +25,7 @@ opacity: 1; background-image: repeating-linear-gradient(45deg, var(--color) 25%, transparent 25%, transparent 75%, var(--color) 75%, var(--color)), repeating-linear-gradient(45deg, var(--color) 25%, #e5e5f7 25%, #e5e5f7 75%, var(--color) 75%, var(--color)); - background-position: - 0 0, - 10px 10px; + background-position: 0 0, 10px 10px; border-radius: var(--ds-border-radius-md); background-size: 20px 20px; height: 64px; diff --git a/apps/theme/components/ColorPicker/ColorPicker.module.css b/apps/theme/components/ColorPicker/ColorPicker.module.css index 4894a216cb..86541c6824 100644 --- a/apps/theme/components/ColorPicker/ColorPicker.module.css +++ b/apps/theme/components/ColorPicker/ColorPicker.module.css @@ -11,9 +11,7 @@ height: 48px; width: 150px; padding-left: 12px; - transition: - 0.04s border, - 0.04s outline; + transition: 0.04s border, 0.04s outline; border: solid 1px var(--ds-color-neutral-border-default); border-radius: var(--ds-border-radius-md); background-color: var(--ds-color-neutral-background-default); diff --git a/biome.jsonc b/biome.jsonc index 4779896680..0b3fabe921 100644 --- a/biome.jsonc +++ b/biome.jsonc @@ -83,6 +83,14 @@ "ignore": [] }, + "css": { + "formatter": { + "enabled": true, + "indentWidth": 2, + "quoteStyle": "single" + } + }, + "overrides": [ { "include": ["**/*.css"], "formatter": { "lineWidth": 160 } }, { diff --git a/package.json b/package.json index 87f70b997f..6053379154 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "build:storybook": "yarn workspace @designsystemet/storybook build", "build:storefront": "yarn workspace storefront build", "start:storefront": "yarn workspace storefront start", - "lint-style": "stylelint \"**/*.css\"", "types": "yarn workspaces foreach -Ap --topological-dev --no-private run types", "types:react": "yarn workspace @digdir/designsystemet-react types", "types:storefront": "yarn workspace storefront types", @@ -47,7 +46,6 @@ "@vitest/coverage-v8": "^2.0.5", "@vitest/expect": "^2.0.5", "copyfiles": "^2.4.1", - "stylelint-config-standard": "^36.0.1", "typescript": "^5.5.4", "typescript-plugin-css-modules": "^5.1.0", "vite": "^5.3.6", diff --git a/packages/css/accordion.css b/packages/css/accordion.css index 4855227122..8501cbbf33 100644 --- a/packages/css/accordion.css +++ b/packages/css/accordion.css @@ -87,9 +87,7 @@ mask: 50% / contain no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5.97 9.47a.75.75 0 0 1 1.06 0L12 14.44l4.97-4.97a.75.75 0 1 1 1.06 1.06l-5.5 5.5a.75.75 0 0 1-1.06 0l-5.5-5.5a.75.75 0 0 1 0-1.06'/%3E%3C/svg%3E"); position: absolute; - margin-inline: calc( - (var(--dsc-accordion-chevron-size) + var(--dsc-accordion-chevron-gap)) * -1 - ); /* Using margin instead of top/left to avoid position: relative and to support dir="rtl" */ + margin-inline: calc((var(--dsc-accordion-chevron-size) + var(--dsc-accordion-chevron-gap)) * -1); /* Using margin instead of top/left to avoid position: relative and to support dir="rtl" */ width: var(--dsc-accordion-chevron-size); } @@ -119,15 +117,14 @@ } @media (prefers-reduced-motion: no-preference) { - interpolate-size: allow-keywords; /* stylelint-disable-line property-no-unknown */ + /* biome-ignore lint/correctness/noUnknownProperty: */ + interpolate-size: allow-keywords; } &::part(details-content) { block-size: 0; overflow-y: clip; - transition: - content-visibility 400ms allow-discrete, - height 400ms; + transition: content-visibility 400ms allow-discrete, height 400ms; } &[open]::part(details-content) { diff --git a/packages/css/alert.css b/packages/css/alert.css index e6f400e797..777df2c92a 100644 --- a/packages/css/alert.css +++ b/packages/css/alert.css @@ -19,25 +19,23 @@ @composes ds-body-text--md from './base/base.css'; - & > :is(h1,h2,h3,h4,h5,h6):first-child::before, /* If Alert starts with Heading, align icon to this */ - &:not(:has(> :is(h1,h2,h3,h4,h5,h6):first-child))::before /* If there is no Heading, align icon to Alert itself */ { + & > :is(h1, h2, h3, h4, h5, h6):first-child::before /* If Alert starts with Heading, align icon to this */, + &:not(:has(> :is(h1, h2, h3, h4, h5, h6):first-child))::before /* If there is no Heading, align icon to Alert itself */ { background-color: var(--dsc-alert-icon-color); content: ''; display: block; height: var(--dsc-alert-icon-size); - margin-inline: calc( - (var(--dsc-alert-icon-size) + var(--dsc-alert-gap)) * -1 - ); /* Using margin instead of top/left to avoid position: relative and to support dir="rtl" */ + margin-inline: calc((var(--dsc-alert-icon-size) + var(--dsc-alert-gap)) * -1); /* Using margin instead of top/left to avoid position: relative and to support dir="rtl" */ - mask: var(--dsc-alert-icon-url) center/contain no-repeat; + mask: var(--dsc-alert-icon-url) center / contain no-repeat; position: absolute; translate: 0 calc((1lh - var(--dsc-alert-icon-size)) / 2); /* Center icon to line height */ width: var(--dsc-alert-icon-size); } /** - * Colors - */ + * Colors + */ &[data-color='warning'] { --dsc-alert-border-color: var(--ds-color-warning-border-default); --dsc-alert-icon-color: var(--ds-color-warning-text-subtle); @@ -60,8 +58,8 @@ } /** - * Sizes - */ + * Sizes + */ &[data-size='sm'] { --dsc-alert-icon-size: var(--ds-sizing-6); --dsc-alert-padding: var(--ds-spacing-5); diff --git a/packages/css/base/base.css b/packages/css/base/base.css index 1b1cb382d8..5961d7efa3 100644 --- a/packages/css/base/base.css +++ b/packages/css/base/base.css @@ -30,13 +30,13 @@ } /** -* Focus outline that can be composed if it needs a specific selector -*/ + * Focus outline that can be composed if it needs a specific selector + */ .ds-focus--visible { /** - * We use both box-shadow and outline to ensure that the focus style is visible, - * in case box-shadow is overridden. - */ + * We use both box-shadow and outline to ensure that the focus style is visible, + * in case box-shadow is overridden. + */ box-shadow: var(--dsc-focus-boxShadow); outline: var(--dsc-focus-outline); outline-offset: var(--dsc-focus-border-width); diff --git a/packages/css/button.css b/packages/css/button.css index cb58b69ac1..abcc45436a 100644 --- a/packages/css/button.css +++ b/packages/css/button.css @@ -64,8 +64,8 @@ } /** - * Variants - */ + * Variants + */ &[data-variant='secondary'] { --dsc-button-background--active: var(--ds-color-accent-surface-hover); --dsc-button-background--hover: var(--ds-color-accent-surface-default); @@ -87,8 +87,8 @@ } /** - * Colors - */ + * Colors + */ &[data-color='neutral'] { --dsc-button-background--active: var(--ds-color-neutral-base-active); --dsc-button-background--hover: var(--ds-color-neutral-base-hover); @@ -142,8 +142,8 @@ } /** - * States - */ + * States + */ @media (hover: hover) and (pointer: fine) { /* Only use hover for non-touch devices to prevent sticky-hovering, using :where to prevent adding specificity */ diff --git a/packages/css/card.css b/packages/css/card.css index 0aa93ad616..d6a3f56c93 100644 --- a/packages/css/card.css +++ b/packages/css/card.css @@ -21,7 +21,7 @@ @composes ds-paragraph from './paragraph.css'; /* Must be after all: unset */ /* Style link in heading, or heading when Card is anchor */ - :is(h1, h2, h3, h4, h5, h6) a:any-link, /* Using :any-link to target both a and a:visited */ + :is(h1, h2, h3, h4, h5, h6) a:any-link /* Using :any-link to target both a and a:visited */, &:is(a:any-link, button, [role='button']) :is(h1, h2, h3, h4, h5, h6) { color: inherit; outline: 0; diff --git a/packages/css/checkbox.css b/packages/css/checkbox.css index e83d7becb2..a41b9b45f2 100644 --- a/packages/css/checkbox.css +++ b/packages/css/checkbox.css @@ -161,9 +161,7 @@ .ds-checkbox:not(.ds-checkbox--readonly) .ds-checkbox__input:hover:not(:checked, :disabled, :focus-visible) { --dsc-checkbox-border-color: var(--ds-color-accent-border-strong); - box-shadow: - var(--dsc-checkbox-border__hover), - inset 0 0 0 2px var(--dsc-checkbox-border-color); + box-shadow: var(--dsc-checkbox-border__hover), inset 0 0 0 2px var(--dsc-checkbox-border-color); } .ds-checkbox:not(.ds-checkbox--readonly) .ds-checkbox__input:indeterminate:hover:not(:focus-visible) { diff --git a/packages/css/chip.css b/packages/css/chip.css index ab677be1ab..39ae6b91d3 100644 --- a/packages/css/chip.css +++ b/packages/css/chip.css @@ -49,7 +49,7 @@ content: ''; height: var(--dsc-chip-icon-size); margin: 0 calc(var(--gap) * -1) 0 var(--gap); - mask: center/contain no-repeat + mask: center / contain no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='1em' height='1em' fill='none' viewBox='0 0 24 24' focusable='false' role='img'%3E%3Cpath fill='currentColor' d='M6.53 5.47a.75.75 0 0 0-1.06 1.06L10.94 12l-5.47 5.47a.75.75 0 1 0 1.06 1.06L12 13.06l5.47 5.47a.75.75 0 1 0 1.06-1.06L13.06 12l5.47-5.47a.75.75 0 0 0-1.06-1.06L12 10.94z'%3E%3C/path%3E%3C/svg%3E"); width: var(--dsc-chip-icon-size); } @@ -86,7 +86,7 @@ &[type='checkbox']:checked { background: currentcolor; - mask: center/cover no-repeat + mask: center / cover no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M24 0H0v24h24V0Zm-4.44 8.56a1.5 1.5 0 0 0-2.12-2.12L10 13.88l-3.44-3.44a1.5 1.5 0 0 0-2.12 2.12l4.5 4.5a1.5 1.5 0 0 0 2.12 0l8.5-8.5Z'/%3E%3C/svg%3E"); } } diff --git a/packages/css/combobox.css b/packages/css/combobox.css index bbc7420ca2..d3865a6d73 100644 --- a/packages/css/combobox.css +++ b/packages/css/combobox.css @@ -167,8 +167,8 @@ } /** - * Apply a focus outline on an element when it is focused with keyboard - */ + * Apply a focus outline on an element when it is focused with keyboard + */ .ds-combobox__input__wrapper:has(input:focus) { --dsc-focus-border-width: 3px; diff --git a/packages/css/fieldset.css b/packages/css/fieldset.css index fe5969709a..6413d4a5dd 100644 --- a/packages/css/fieldset.css +++ b/packages/css/fieldset.css @@ -28,7 +28,7 @@ content: ''; background: currentcolor; height: var(--dsc-fieldset-icon-size); - mask: center/contain no-repeat + mask: center / contain no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M12 2.25A4.75 4.75 0 0 0 7.25 7v2.25H7A1.75 1.75 0 0 0 5.25 11v9c0 .41.34.75.75.75h12a.75.75 0 0 0 .75-.75v-9A1.75 1.75 0 0 0 17 9.25h-.25V7A4.75 4.75 0 0 0 12 2.25m3.25 7V7a3.25 3.25 0 0 0-6.5 0v2.25zM12 13a1.5 1.5 0 0 0-.75 2.8V17a.75.75 0 0 0 1.5 0v-1.2A1.5 1.5 0 0 0 12 13'/%3E%3C/svg%3E"); width: var(--dsc-fieldset-icon-size); } diff --git a/packages/css/helptext.css b/packages/css/helptext.css index 4cc3167bd7..9901e869dd 100644 --- a/packages/css/helptext.css +++ b/packages/css/helptext.css @@ -23,9 +23,7 @@ mask-image: var(--dsc-helptext-icon-url); mask-position: center; mask-repeat: no-repeat; - mask-size: - var(--dsc-helptext-icon-size) var(--dsc-helptext-icon-size), - cover; + mask-size: var(--dsc-helptext-icon-size) var(--dsc-helptext-icon-size), cover; scale: 1.1; /* Hide tiny half pixel rendeing bug */ width: 100%; height: 100%; diff --git a/packages/css/index.css b/packages/css/index.css index 98eb113623..fb3406a6e7 100644 --- a/packages/css/index.css +++ b/packages/css/index.css @@ -1,4 +1,4 @@ -@charset "UTF-8"; +@charset 'UTF-8'; @layer ds.reset, ds.base, ds.typography, ds.theme, ds.components; diff --git a/packages/css/link.css b/packages/css/link.css index 53e9460dbd..49c14d47c8 100644 --- a/packages/css/link.css +++ b/packages/css/link.css @@ -20,8 +20,8 @@ } /** - * Colors - */ + * Colors + */ &[data-color='neutral'] { --dsc-link-background--active: var(--ds-color-neutral-surface-default); --dsc-link-color--active: var(--ds-color-neutral-text-subtle); @@ -31,8 +31,8 @@ } /** - * States - */ + * States + */ &:visited { color: var(--dsc-link-color--visited); } diff --git a/packages/css/modal.css b/packages/css/modal.css index 6c0129239b..0d5e619900 100644 --- a/packages/css/modal.css +++ b/packages/css/modal.css @@ -26,9 +26,7 @@ } &[open] { - animation: - slide-in 300ms ease-in-out, - fade-in 300ms ease-in-out; + animation: slide-in 300ms ease-in-out, fade-in 300ms ease-in-out; } &:has(> .ds-modal__block) { @@ -61,7 +59,7 @@ background: currentcolor; height: var(--ds-spacing-6); width: var(--ds-spacing-6); - mask: center/contain no-repeat + mask: center / contain no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='1em' height='1em' fill='none' viewBox='0 0 24 24' focusable='false' role='img'%3E%3Cpath fill='currentColor' d='M6.53 5.47a.75.75 0 0 0-1.06 1.06L10.94 12l-5.47 5.47a.75.75 0 1 0 1.06 1.06L12 13.06l5.47 5.47a.75.75 0 1 0 1.06-1.06L13.06 12l5.47-5.47a.75.75 0 0 0-1.06-1.06L12 10.94z'%3E%3C/path%3E%3C/svg%3E"); } } diff --git a/packages/css/pagination.css b/packages/css/pagination.css index f12a218230..1aeaa07260 100644 --- a/packages/css/pagination.css +++ b/packages/css/pagination.css @@ -16,7 +16,7 @@ content: ''; background: currentcolor; height: var(--dsc-pagination-chevron-size); - mask: center/contain no-repeat + mask: center / contain no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24'%3E%3Cpath d='M9.47 5.97a.75.75 0 0 1 1.06 0l5.5 5.5a.75.75 0 0 1 0 1.06l-5.5 5.5a.75.75 0 1 1-1.06-1.06L14.44 12 9.47 7.03a.75.75 0 0 1 0-1.06'/%3E%3C/svg%3E"); width: var(--dsc-pagination-chevron-size); } diff --git a/packages/css/radio.css b/packages/css/radio.css index d3240d316d..0756e1888a 100644 --- a/packages/css/radio.css +++ b/packages/css/radio.css @@ -132,15 +132,11 @@ .ds-radio:not(.ds-radio--readonly) > .ds-radio__input:hover:not(:checked, :disabled, :focus-visible) { --dsc-radio-border-color: var(--ds-color-accent-border-strong); - box-shadow: - var(--dsc-radio-border__hover), - inset 0 0 0 2px var(--dsc-radio-border-color); + box-shadow: var(--dsc-radio-border__hover), inset 0 0 0 2px var(--dsc-radio-border-color); } .ds-radio:not(.ds-radio--readonly) > .ds-radio__input:hover:checked:not(:disabled, :focus-visible) { - box-shadow: - var(--dsc-radio-border__hover), - inset 0 0 0 var(--dsc-radio-box_shadow-size) var(--dsc-radio-border-color); + box-shadow: var(--dsc-radio-border__hover), inset 0 0 0 var(--dsc-radio-box_shadow-size) var(--dsc-radio-border-color); } } diff --git a/packages/css/table.css b/packages/css/table.css index a719b4919a..2d433b180e 100644 --- a/packages/css/table.css +++ b/packages/css/table.css @@ -63,8 +63,8 @@ } /** - * Sorting - */ + * Sorting + */ & > thead > tr > [aria-sort] { cursor: pointer; padding: 0; @@ -90,7 +90,7 @@ content: ''; display: inline-block; height: var(--dsc-table-sort-size); - mask: center/contain no-repeat + mask: center / contain no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12.53 4.47a.75.75 0 0 0-1.06 0l-3.5 3.5a.75.75 0 0 0 1.06 1.06L12 6.06l2.97 2.97a.75.75 0 1 0 1.06-1.06zm-3.5 10.5a.75.75 0 0 0-1.06 1.06l3.5 3.5a.75.75 0 0 0 1.06 0l3.5-3.5a.75.75 0 1 0-1.06-1.06L12 17.94z'/%3E%3C/svg%3E"); vertical-align: middle; width: var(--dsc-table-sort-size); @@ -111,8 +111,8 @@ } /** - * Sizes - */ + * Sizes + */ &[data-size='sm'] { --dsc-table-padding: var(--ds-spacing-1) var(--ds-spacing-3); @@ -126,8 +126,8 @@ } /** - * Configurations - */ + * Configurations + */ &[data-border] { --dsc-table-border-radius: min(1rem, var(--ds-border-radius-md)); @@ -153,8 +153,8 @@ } /** - * States - */ + * States + */ @media (hover: hover) and (pointer: fine) { &[data-hover] > tbody > tr:hover > :is(th, td) { background: var(--dsc-table-background--hover); diff --git a/packages/react/src/components/Breadcrumbs/Breadcrumbs.test.tsx b/packages/react/src/components/Breadcrumbs/Breadcrumbs.test.tsx index dff199e5bc..c83a22f7dc 100644 --- a/packages/react/src/components/Breadcrumbs/Breadcrumbs.test.tsx +++ b/packages/react/src/components/Breadcrumbs/Breadcrumbs.test.tsx @@ -5,27 +5,25 @@ import { Breadcrumbs } from './'; const renderWithRoot = (props?: BreadcrumbsProps) => render( - <> - - - Nivå 3 - - - - Nivå 1 - - - Nivå 2 - - - Nivå 3 - - - Nivå 4 - - - - , + + + Nivå 3 + + + + Nivå 1 + + + Nivå 2 + + + Nivå 3 + + + Nivå 4 + + + , ); describe('Breadcrumbs', () => { diff --git a/packages/react/src/components/form/Combobox/Option/Option.tsx b/packages/react/src/components/form/Combobox/Option/Option.tsx index 0fe8a93868..54fafd1af7 100644 --- a/packages/react/src/components/form/Combobox/Option/Option.tsx +++ b/packages/react/src/components/form/Combobox/Option/Option.tsx @@ -50,6 +50,7 @@ const ComboboxOption = memo(