diff --git a/.changeset/brave-berries-kneel.md b/.changeset/brave-berries-kneel.md new file mode 100644 index 0000000000..36c21bcf2c --- /dev/null +++ b/.changeset/brave-berries-kneel.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +**breadcrumbs**: use `` internally diff --git a/.changeset/brave-ties-suffer.md b/.changeset/brave-ties-suffer.md new file mode 100644 index 0000000000..601f9797c0 --- /dev/null +++ b/.changeset/brave-ties-suffer.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +**suggestion**: various changes to chip styling. You no longer need to pass a class to `` diff --git a/.changeset/breezy-badgers-remain.md b/.changeset/breezy-badgers-remain.md new file mode 100644 index 0000000000..f1c0bd9851 --- /dev/null +++ b/.changeset/breezy-badgers-remain.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +**input**: add support for `[aria-readonly='true']` diff --git a/.changeset/calm-weeks-rescue.md b/.changeset/calm-weeks-rescue.md new file mode 100644 index 0000000000..80749b1307 --- /dev/null +++ b/.changeset/calm-weeks-rescue.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +**card**: fix deeply nested anchors in headings causing navigation diff --git a/.changeset/clever-knives-sip.md b/.changeset/clever-knives-sip.md new file mode 100644 index 0000000000..d285941266 --- /dev/null +++ b/.changeset/clever-knives-sip.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +**link**: don't set `:visited` color and set default `border-radius` to 0 diff --git a/.changeset/config.json b/.changeset/config.json index 0e7cc82223..ad227e9470 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -12,7 +12,8 @@ "@digdir/designsystemet", "@digdir/designsystemet-css", "@digdir/designsystemet-types", - "@digdir/designsystemet-react" + "@digdir/designsystemet-react", + "@digdir/designsystemet-web" ] ], "linked": [], diff --git a/.changeset/famous-books-hunt.md b/.changeset/famous-books-hunt.md new file mode 100644 index 0000000000..d2b340e422 --- /dev/null +++ b/.changeset/famous-books-hunt.md @@ -0,0 +1,7 @@ +--- +"@digdir/designsystemet-css": patch +--- + +**field**: add new css variables: + `--dsc-field-counter-over: '%d tegn for mye';` + `--dsc-field-counter-under: '%d tegn igjen';` diff --git a/.changeset/flat-bees-sniff.md b/.changeset/flat-bees-sniff.md new file mode 100644 index 0000000000..ba667088f3 --- /dev/null +++ b/.changeset/flat-bees-sniff.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +First implementation on `@digdir/designsystemet-web` diff --git a/.changeset/gentle-eagles-cry.md b/.changeset/gentle-eagles-cry.md new file mode 100644 index 0000000000..91415a2e66 --- /dev/null +++ b/.changeset/gentle-eagles-cry.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +**ToggleGroup**: change internal DOM diff --git a/.changeset/late-ants-juggle.md b/.changeset/late-ants-juggle.md new file mode 100644 index 0000000000..97a7277917 --- /dev/null +++ b/.changeset/late-ants-juggle.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +**dialog**: style `.ds-dialog button[command='close']:empty::before` with X-icon diff --git a/.changeset/long-moose-join.md b/.changeset/long-moose-join.md new file mode 100644 index 0000000000..2af791d48c --- /dev/null +++ b/.changeset/long-moose-join.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": "patch" +--- + +**toggle-group**: remove `--dsc-togglegroup-text-color`, as this was not used diff --git a/.changeset/loud-ligers-battle.md b/.changeset/loud-ligers-battle.md new file mode 100644 index 0000000000..b10698bde3 --- /dev/null +++ b/.changeset/loud-ligers-battle.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +**card**: fix issues with deeply nested heading links diff --git a/.changeset/moody-horses-laugh.md b/.changeset/moody-horses-laugh.md new file mode 100644 index 0000000000..413f0013c2 --- /dev/null +++ b/.changeset/moody-horses-laugh.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +**toggle-group**: add styling for new DOM structure introduced in `@digdir/designsystemet-web` diff --git a/.changeset/neat-boats-learn.md b/.changeset/neat-boats-learn.md new file mode 100644 index 0000000000..69e6b6c199 --- /dev/null +++ b/.changeset/neat-boats-learn.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +**pagination**: use `` internally diff --git a/.changeset/nice-kings-sneeze.md b/.changeset/nice-kings-sneeze.md new file mode 100644 index 0000000000..8e2781eaa0 --- /dev/null +++ b/.changeset/nice-kings-sneeze.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +**popover**: add `--dsc-popover-placement` with default value `top` diff --git a/.changeset/odd-days-complain.md b/.changeset/odd-days-complain.md new file mode 100644 index 0000000000..dc77485fe7 --- /dev/null +++ b/.changeset/odd-days-complain.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +**field**: add styling for `` counter diff --git a/.changeset/old-eyes-listen.md b/.changeset/old-eyes-listen.md new file mode 100644 index 0000000000..7bdb26a352 --- /dev/null +++ b/.changeset/old-eyes-listen.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Add `suppressHydrationWarning` to various components. This is to support `@digdir/designsystemet-web` being used internally. diff --git a/.changeset/quiet-crabs-call.md b/.changeset/quiet-crabs-call.md new file mode 100644 index 0000000000..be0e402456 --- /dev/null +++ b/.changeset/quiet-crabs-call.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +**fieldset**: add `--dsc-fieldset-gap` with default value `var(--ds-size-4)` diff --git a/.changeset/real-worms-act.md b/.changeset/real-worms-act.md new file mode 100644 index 0000000000..48993f2b05 --- /dev/null +++ b/.changeset/real-worms-act.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +**field**: use `` internally diff --git a/.changeset/rich-ravens-remain.md b/.changeset/rich-ravens-remain.md new file mode 100644 index 0000000000..ffc3daae3f --- /dev/null +++ b/.changeset/rich-ravens-remain.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +**tooltip**: add `--dsc-tooltip-placement` with default value `top` diff --git a/.changeset/rude-yaks-refuse.md b/.changeset/rude-yaks-refuse.md new file mode 100644 index 0000000000..123a474cfc --- /dev/null +++ b/.changeset/rude-yaks-refuse.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +**tabs**: add support for `` diff --git a/.changeset/silent-coins-begin.md b/.changeset/silent-coins-begin.md new file mode 100644 index 0000000000..fe594c3822 --- /dev/null +++ b/.changeset/silent-coins-begin.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +**Tabs**: use `` and related web components internally diff --git a/.changeset/silent-needles-smash.md b/.changeset/silent-needles-smash.md new file mode 100644 index 0000000000..4f11e3ed4a --- /dev/null +++ b/.changeset/silent-needles-smash.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +**ErrorSummary**: use `` internally, and deprecate `asChild`, since we now recommend to use our web component diff --git a/.changeset/silver-monkeys-hammer.md b/.changeset/silver-monkeys-hammer.md new file mode 100644 index 0000000000..0620ccffbc --- /dev/null +++ b/.changeset/silver-monkeys-hammer.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +**breadcrumbs**: don't remove underline on `a[aria-current='page']`, but on `li:last-child a` diff --git a/.changeset/small-baboons-grin.md b/.changeset/small-baboons-grin.md new file mode 100644 index 0000000000..55ae5cae5e --- /dev/null +++ b/.changeset/small-baboons-grin.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +**RovingFocus**: deprecate component. This will be removed in the next major version diff --git a/.changeset/stupid-tigers-judge.md b/.changeset/stupid-tigers-judge.md new file mode 100644 index 0000000000..2ffafc7763 --- /dev/null +++ b/.changeset/stupid-tigers-judge.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +**tooltip**: use `[data-tooltip]` from `@digdir/designsystemet-web` internally diff --git a/.changeset/swift-planes-admire.md b/.changeset/swift-planes-admire.md new file mode 100644 index 0000000000..d52e98914b --- /dev/null +++ b/.changeset/swift-planes-admire.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +**details**: use `
` and `` internally diff --git a/.changeset/ten-crabs-wave.md b/.changeset/ten-crabs-wave.md new file mode 100644 index 0000000000..b5bf261fd6 --- /dev/null +++ b/.changeset/ten-crabs-wave.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +**dialog**: deprecate `data-command="close"`. Use command="close" and commandfor="DIALOG-ID" instead. diff --git a/.changeset/twenty-wasps-do.md b/.changeset/twenty-wasps-do.md new file mode 100644 index 0000000000..9667fd25a3 --- /dev/null +++ b/.changeset/twenty-wasps-do.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +**dropdown**: add `--dsc-dropdown-placement` with default value `bottom` diff --git a/.changeset/unlucky-ties-laugh.md b/.changeset/unlucky-ties-laugh.md new file mode 100644 index 0000000000..1bf4c687c6 --- /dev/null +++ b/.changeset/unlucky-ties-laugh.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +added class `ds-floating`, which is used on floating elements internally diff --git a/.changeset/wet-crabs-kneel.md b/.changeset/wet-crabs-kneel.md new file mode 100644 index 0000000000..90fbb8f875 --- /dev/null +++ b/.changeset/wet-crabs-kneel.md @@ -0,0 +1,7 @@ +--- +"@digdir/designsystemet-css": patch +--- + +**pagination**: +- add `--dsc-pagination-ellipsis` with default value `'\2026'` +- set `--dsc-pagination-label: 'Bla i sider';` if language is `'nn'`, `'nb'` or `'no'` diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 451bab5caa..46a9698f5d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,8 +4,8 @@ on: pull_request: paths: - .github/workflows/test.yml - - 'packages/**' - - 'apps/storybook/**' + - "packages/**" + - "apps/storybook/**" permissions: checks: write @@ -45,12 +45,12 @@ jobs: - name: Install Playwright browsers if: steps.playwright-cache.outputs.cache-hit != 'true' - run: pnpm exec playwright install --with-deps chromium + run: pnpm exec playwright install --with-deps chromium firefox webkit working-directory: apps/storybook - name: Install Playwright system dependencies (if cached) if: steps.playwright-cache.outputs.cache-hit == 'true' - run: pnpm exec playwright install-deps chromium + run: pnpm exec playwright install-deps chromium firefox webkit working-directory: apps/storybook - name: Build @@ -58,12 +58,13 @@ jobs: - name: Types run: pnpm types:react - + - name: Test Web + run: pnpm test:web - name: Run Storybook tests run: pnpm --filter @web/storybook vitest - name: Test run: pnpm test - - name: 'Report Coverage' + - name: "Report Coverage" if: success() || failure() uses: davelosert/vitest-coverage-report-action@15b5b41bb7d36796d89f4bf482b09529c53f3446 # v2.9.2 with: @@ -72,11 +73,11 @@ jobs: uses: mikepenz/action-junit-report@74626db7353a25a20a72816467ebf035f674c5f8 # v6.2.0 if: success() || failure() with: - report_paths: 'test-report.xml' + report_paths: "test-report.xml" detailed_summary: true check_name: Unit Test Report check_annotations: true - check_title_template: '{{FILE_NAME}} / {{TEST_NAME}}' + check_title_template: "{{FILE_NAME}} / {{TEST_NAME}}" - name: Test CLI (create tokens, then build the theme) run: pnpm test:cli @@ -85,16 +86,16 @@ jobs: uses: jacobtomlinson/gha-find-replace@f1069b438f125e5395d84d1c6fd3b559a7880cb5 # v3.0.5 if: success() || failure() with: - include: 'apps/storybook/test-report.xml' - find: '../../' - replace: '' + include: "apps/storybook/test-report.xml" + find: "../../" + replace: "" regex: false - name: Publish Storybook test report uses: mikepenz/action-junit-report@74626db7353a25a20a72816467ebf035f674c5f8 # v6.2.0 if: success() || failure() with: - report_paths: 'apps/storybook/test-report.xml' + report_paths: "apps/storybook/test-report.xml" detailed_summary: true check_name: Storybook Test Report check_annotations: true - check_title_template: '{{FILE_NAME}} / {{TEST_NAME}}' + check_title_template: "{{FILE_NAME}} / {{TEST_NAME}}" diff --git a/apps/storybook/.storybook/main.ts b/apps/storybook/.storybook/main.ts index b8e4b7f683..88774187ca 100644 --- a/apps/storybook/.storybook/main.ts +++ b/apps/storybook/.storybook/main.ts @@ -1,4 +1,4 @@ -import path, { dirname as nodeDirname, resolve } from 'node:path'; +import path from 'node:path'; import { fileURLToPath } from 'node:url'; import type { StorybookConfig } from '@storybook/react-vite'; import * as R from 'ramda'; @@ -6,7 +6,7 @@ import type { PropItem } from 'react-docgen-typescript'; import { defineConfig, mergeConfig } from 'vite'; const __filename = fileURLToPath(import.meta.url); -const __dirname = nodeDirname(__filename); +const __dirname = path.dirname(__filename); const dirname = typeof __dirname !== 'undefined' @@ -35,7 +35,7 @@ const config: StorybookConfig = { /* If in prod, use docgen-typescript, locally use docgen */ reactDocgen: 'react-docgen-typescript', reactDocgenTypescriptOptions: { - include: [resolve(dirname, '../../../packages/react/**/**.tsx')], // <- This is the important line. + include: [path.resolve(dirname, '../../../packages/react/**/**.tsx')], // <- This is the important line. shouldExtractLiteralValuesFromEnum: true, shouldRemoveUndefinedFromOptional: true, propFilter: (prop: PropItem) => { @@ -52,6 +52,9 @@ const config: StorybookConfig = { '../../../packages/*/!(node_modules)/**/*.mdx', '../../../packages/*/!(node_modules)/**/*.@(stories|chromatic).@(ts|tsx)', ], + features: { + developmentModeForBuild: true, // Make axe not run too early (see https://storybook.js.org/docs/writing-tests/accessibility-testing#the-addon-panel-does-not-show-expected-violations) + }, experimental_indexers: (existingIndexers) => { /* * The following is required in order to process .chromatic.tsx with the default indexer @@ -87,7 +90,7 @@ const config: StorybookConfig = { options: { strictMode: true, builder: { - viteConfigPath: resolve(dirname, '../../../vite.config.ts'), + viteConfigPath: path.resolve(dirname, '../../../vite.config.ts'), }, }, }, @@ -99,6 +102,7 @@ const config: StorybookConfig = { chromatic: { excludeFromDocsStories: true, excludeFromSidebar: options.configType === 'PRODUCTION', + exitOnceUploaded: true, // Exit Storybook once Chromatic stories are uploaded, to speed up CI builds. ...tagOptions?.chromatic, }, }; diff --git a/apps/storybook/.storybook/vitest.setup.ts b/apps/storybook/.storybook/vitest.setup.ts index ea170b0462..47959f4fe3 100644 --- a/apps/storybook/.storybook/vitest.setup.ts +++ b/apps/storybook/.storybook/vitest.setup.ts @@ -2,6 +2,18 @@ import * as a11yAddonAnnotations from '@storybook/addon-a11y/preview'; import { setProjectAnnotations } from '@storybook/react-vite'; import * as projectAnnotations from './preview'; +// Speed up by using instant animations/transitions during testing +document.head.appendChild( + Object.assign(document.createElement('style'), { + textContent: `*, *::before, *::after { + transition-duration: 0ms !important; + animation-duration: 0ms !important; + transition-delay: 0ms !important; + animation-delay: 0ms !important; + }`, + }), +); + // This is an important step to apply the right configuration when testing your stories. // More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations setProjectAnnotations([a11yAddonAnnotations, projectAnnotations]); diff --git a/apps/storybook/vitest.config.ts b/apps/storybook/vitest.config.ts index 94091598f5..1f126a70eb 100644 --- a/apps/storybook/vitest.config.ts +++ b/apps/storybook/vitest.config.ts @@ -27,6 +27,7 @@ export default mergeConfig(viteConfig, { provider: playwright(), headless: true, }, + testTimeout: 10000, setupFiles: ['./.storybook/vitest.setup.ts'], reporters: [ 'default', diff --git a/apps/themebuilder/app/_components/color-preview/color-preview.tsx b/apps/themebuilder/app/_components/color-preview/color-preview.tsx index 06319c4945..3786c4a09d 100644 --- a/apps/themebuilder/app/_components/color-preview/color-preview.tsx +++ b/apps/themebuilder/app/_components/color-preview/color-preview.tsx @@ -56,6 +56,7 @@ export const ColorPreview = () => {
{t('colorPreview.view')}
setView(value as ViewType)} diff --git a/apps/themebuilder/app/_components/config-paste/config-paste.tsx b/apps/themebuilder/app/_components/config-paste/config-paste.tsx index 9a0e2fe28d..35cdc26409 100644 --- a/apps/themebuilder/app/_components/config-paste/config-paste.tsx +++ b/apps/themebuilder/app/_components/config-paste/config-paste.tsx @@ -74,14 +74,14 @@ export function ConfigPaste() { {configText && ( diff --git a/apps/themebuilder/app/_components/previews/previews.tsx b/apps/themebuilder/app/_components/previews/previews.tsx index f229f3131a..133d7f67fb 100644 --- a/apps/themebuilder/app/_components/previews/previews.tsx +++ b/apps/themebuilder/app/_components/previews/previews.tsx @@ -36,6 +36,7 @@ export const Previews = () => { <>
setTheme(v as keyof typeof themes)} > @@ -47,6 +48,7 @@ export const Previews = () => { setColorScheme(v as ColorScheme)} > diff --git a/apps/www/app/_components/banner/banner.tsx b/apps/www/app/_components/banner/banner.tsx index 7110236b36..070d028c19 100644 --- a/apps/www/app/_components/banner/banner.tsx +++ b/apps/www/app/_components/banner/banner.tsx @@ -1,4 +1,7 @@ -import type { HeadingProps } from '@digdir/designsystemet-react'; +import type { + HeadingProps, + ParagraphProps, +} from '@digdir/designsystemet-react'; import { Heading, Paragraph } from '@digdir/designsystemet-react'; import cl from 'clsx/lite'; import type { HTMLAttributes, ReactNode } from 'react'; @@ -33,7 +36,7 @@ const BannerHeading = ({ className, ...props }: BannerHeadingProps) => { ); }; -type BannerIngressProps = HTMLAttributes; +type BannerIngressProps = ParagraphProps; const BannerIngress = ({ className, ...props }: BannerIngressProps) => { return ( diff --git a/apps/www/app/_components/blog-card/blog-card.tsx b/apps/www/app/_components/blog-card/blog-card.tsx index 97fc046082..afd2b9ab8e 100644 --- a/apps/www/app/_components/blog-card/blog-card.tsx +++ b/apps/www/app/_components/blog-card/blog-card.tsx @@ -1,6 +1,7 @@ import { Card, CardBlock, + type CardProps, Heading, Paragraph, Tag, @@ -21,7 +22,7 @@ type BlogCardProps = { tagText?: string; tagColor?: 'brand1' | 'brand2' | 'brand3'; level?: 2 | 3; -} & Omit, 'color'>; +} & Omit; export const BlogCard = ({ title, diff --git a/apps/www/app/_components/css-attributes/css-attributes.tsx b/apps/www/app/_components/css-attributes/css-attributes.tsx index 497708995f..edbc1dee47 100644 --- a/apps/www/app/_components/css-attributes/css-attributes.tsx +++ b/apps/www/app/_components/css-attributes/css-attributes.tsx @@ -1,4 +1,8 @@ -import { Paragraph, Table } from '@digdir/designsystemet-react'; +import { + Paragraph, + Table, + type TableProps, +} from '@digdir/designsystemet-react'; import cl from 'clsx'; import { forwardRef } from 'react'; import { useTranslation } from 'react-i18next'; @@ -7,7 +11,7 @@ type CssAttributesProps = { vars: { [key: string]: string; }; -} & React.HTMLAttributes; +} & TableProps; export const CssAttributes = forwardRef( function CssAttributes({ vars, className, ...rest }, ref) { diff --git a/apps/www/app/_components/css-variables/css-variables.tsx b/apps/www/app/_components/css-variables/css-variables.tsx index a9bd72cbc9..cb59acc3a6 100644 --- a/apps/www/app/_components/css-variables/css-variables.tsx +++ b/apps/www/app/_components/css-variables/css-variables.tsx @@ -1,4 +1,8 @@ -import { Paragraph, Table } from '@digdir/designsystemet-react'; +import { + Paragraph, + Table, + type TableProps, +} from '@digdir/designsystemet-react'; import cl from 'clsx'; import { forwardRef } from 'react'; import { useTranslation } from 'react-i18next'; @@ -7,7 +11,7 @@ type CssVariablesProps = { vars: { [key: string]: string; }; -} & React.HTMLAttributes; +} & TableProps; export const CssVariables = forwardRef( function CssVariables({ vars, className, ...rest }, ref) { diff --git a/apps/www/app/_components/fundamentals-card/fundamentals-card.module.css b/apps/www/app/_components/fundamentals-card/fundamentals-card.module.css index 6fb4a63cee..3e461e6ea2 100644 --- a/apps/www/app/_components/fundamentals-card/fundamentals-card.module.css +++ b/apps/www/app/_components/fundamentals-card/fundamentals-card.module.css @@ -23,6 +23,10 @@ :has(:focus-visible) & { transition: none; } + + & a { + color: inherit; + } } .iconContainer { diff --git a/apps/www/app/_components/fundamentals-card/fundamentals-card.tsx b/apps/www/app/_components/fundamentals-card/fundamentals-card.tsx index dacc28ce4a..98a78bd61f 100644 --- a/apps/www/app/_components/fundamentals-card/fundamentals-card.tsx +++ b/apps/www/app/_components/fundamentals-card/fundamentals-card.tsx @@ -2,7 +2,7 @@ import { Card, Heading, Paragraph } from '@digdir/designsystemet-react'; import cl from 'clsx/lite'; import type * as React from 'react'; -import { Link } from 'react-router'; +import { RRLink } from '../link'; import classes from './fundamentals-card.module.css'; export interface FundamentalsCardProps { @@ -37,7 +37,7 @@ const FundamentalsCard = ({
- {title} + {title} {description} diff --git a/apps/www/app/_components/image/image.tsx b/apps/www/app/_components/image/image.tsx index 57bab7a3b0..9779601cd9 100644 --- a/apps/www/app/_components/image/image.tsx +++ b/apps/www/app/_components/image/image.tsx @@ -28,18 +28,14 @@ const Image = ({ }; const closeFullImage = () => { - if (dialogRef.current) { - dialogRef.current.close(); - } + dialogRef.current?.close(); }; useEffect(() => { const dialog = dialogRef.current; if (dialog) { - const handleClick = () => { - dialog.close(); - }; + const handleClick = () => dialog.close(); dialog.addEventListener('click', handleClick); diff --git a/apps/www/app/_components/live-component/live-components.tsx b/apps/www/app/_components/live-component/live-components.tsx index 9d358e508e..b7dc3eea63 100644 --- a/apps/www/app/_components/live-component/live-components.tsx +++ b/apps/www/app/_components/live-component/live-components.tsx @@ -6,12 +6,14 @@ import { prettify } from 'htmlfy'; import { themes } from 'prism-react-renderer'; import { type ComponentType, + createElement, type KeyboardEvent, useEffect, useId, useRef, useState, } from 'react'; +import { renderToString } from 'react-dom/server'; import { useTranslation } from 'react-i18next'; import { LiveEditor, @@ -70,7 +72,7 @@ type ContextValue = { type EditorProps = { live: ContextValue; - html: HTMLElement | null; + html: string; id?: string; hidden?: boolean; }; @@ -82,13 +84,15 @@ const Editor = ({ live, html, id, hidden }: EditorProps) => { const [resetCount, setResetCount] = useState(0); const [showHTML, setShowHTML] = useState(false); const [copied, setCopied] = useState(''); - const rawHtml = prettify( - html?.innerHTML.toString() || 'Unable to parse html', - { - tag_wrap: 63, - content_wrap: 70, - }, + // Truncate SVGs to to reduce noise + const truncatedHtml = (html || 'Unable to parse html').replace( + /]*>[\s\S]*?<\/svg>/gi, + '', ); + const rawHtml = prettify(truncatedHtml, { + tag_wrap: 63, + content_wrap: 70, + }); const setupEditorTabIndex = () => { const preEl = wrapperRef.current?.querySelector( @@ -247,11 +251,42 @@ const Editor = ({ live, html, id, hidden }: EditorProps) => { ); }; const EditorWithLive = withLive(Editor) as ComponentType<{ - html: HTMLElement | null; + html: string; id?: string; hidden?: boolean; }>; +/** + * Hidden component that captures the SSR HTML using renderToString. + * This gives us the HTML that React produces before hydration, + * rather than the DOM after client-side rendering. + */ +type HtmlCaptureProps = { + live: ContextValue; + onHtmlCapture: (html: string) => void; +}; + +const HtmlCapture = ({ live, onHtmlCapture }: HtmlCaptureProps) => { + const Element = live.element; + + useEffect(() => { + if (Element) { + try { + const html = renderToString(createElement(Element)); + onHtmlCapture(html); + } catch { + onHtmlCapture('Unable to render HTML'); + } + } + }, [Element, onHtmlCapture]); + + return null; +}; + +const HtmlCaptureWithLive = withLive(HtmlCapture) as ComponentType<{ + onHtmlCapture: (html: string) => void; +}>; + export const LiveComponent = ({ story, layout = 'centered', @@ -264,7 +299,7 @@ export const LiveComponent = ({ 'light', ); const [useInverted, setUseInverted] = useState(false); - const [html, setHtml] = useState(null); + const [html, setHtml] = useState(''); const previewColorScheme = useInverted ? invertedColorScheme : colorScheme; const editorId = useId(); @@ -311,6 +346,8 @@ export const LiveComponent = ({ noInline theme={colorScheme === 'dark' ? themes.vsDark : themes.vsLight} > + {/* Hidden component that captures SSR HTML using renderToString */} +
( + h1: (props: HeadingProps) => ( ), - h2: (props: JSX.IntrinsicElements['h2']) => ( + h2: (props: HeadingProps) => ( ), - h3: (props: JSX.IntrinsicElements['h3']) => ( + h3: (props: HeadingProps) => ( ), - h4: (props: JSX.IntrinsicElements['h4']) => ( + h4: (props: HeadingProps) => ( ), - h5: (props: JSX.IntrinsicElements['h5']) => ( + h5: (props: HeadingProps) => ( ), - h6: (props: JSX.IntrinsicElements['h6']) => ( + h6: (props: HeadingProps) => ( ), - ol: (props: JSX.IntrinsicElements['ol']) => , - ul: (props: JSX.IntrinsicElements['ul']) => , + ol: (props: ListOrderedProps) => , + ul: (props: ListUnorderedProps) => , hr: (props: JSX.IntrinsicElements['hr']) => , Image, ResponsiveIframe, Contributors, ColorInfoTable, p: (props: ParagraphProps) => , - Link: ({ href, ...props }: JSX.IntrinsicElements['a']) => ( + Link: ({ href, ...props }: LinkProps) => ( {props.children} ), - a: ({ href, ...props }: JSX.IntrinsicElements['a']) => ( + a: ({ href, ...props }: LinkProps) => ( {props.children} diff --git a/apps/www/app/_components/navigation-card/navigation-card.tsx b/apps/www/app/_components/navigation-card/navigation-card.tsx index 17209cd14c..f6c1fdcd8b 100644 --- a/apps/www/app/_components/navigation-card/navigation-card.tsx +++ b/apps/www/app/_components/navigation-card/navigation-card.tsx @@ -1,8 +1,7 @@ -import { Card, Heading, Paragraph } from '@digdir/designsystemet-react'; +import { Card, Heading, Link, Paragraph } from '@digdir/designsystemet-react'; import cl from 'clsx/lite'; import type * as React from 'react'; - -import { Link } from 'react-router'; +import { Link as RouterLink } from 'react-router'; import classes from './navigation-card.module.css'; export interface NavigationCardProps { @@ -15,7 +14,7 @@ export interface NavigationCardProps { level?: 2 | 3; } -const NavigationCard = ({ +export const NavigationCard = ({ title, color = 'red', icon, @@ -35,7 +34,9 @@ const NavigationCard = ({
- {title} + + {title} + @@ -45,5 +46,3 @@ const NavigationCard = ({ ); }; - -export { NavigationCard }; diff --git a/apps/www/app/_components/react-component-props/react-component-props.tsx b/apps/www/app/_components/react-component-props/react-component-props.tsx index 530d6f4971..e26b9981b0 100644 --- a/apps/www/app/_components/react-component-props/react-component-props.tsx +++ b/apps/www/app/_components/react-component-props/react-component-props.tsx @@ -11,7 +11,7 @@ type ReactComponentProps = { export const ReactComponentDocs = forwardRef< HTMLTableElement, ReactComponentProps ->(function CssVariables({ docs, ...rest }, ref) { +>(function ReactComponentDocs({ docs, ...rest }, ref) { if (!docs || docs.length === 0) { return null; } diff --git a/apps/www/app/content/components/breadcrumbs/en/code.mdx b/apps/www/app/content/components/breadcrumbs/en/code.mdx index 90cab2cc00..629fa65986 100644 --- a/apps/www/app/content/components/breadcrumbs/en/code.mdx +++ b/apps/www/app/content/components/breadcrumbs/en/code.mdx @@ -41,58 +41,42 @@ If you put both a `Breadcrumbs.Link` and a `Breadcrumbs.List` directly in `Bread ## HTML -The class name `ds-breadcrumbs` is placed on a `