From df0da9a5d4f4e8f3bad958578c710795c3f05289 Mon Sep 17 00:00:00 2001 From: Eirik Backer Date: Thu, 24 Oct 2024 09:55:51 +0200 Subject: [PATCH] feat: relative sizing (#2541) Work on #2508 Minor adjustments will be done in #2665 --------- Co-authored-by: Michael Marszalek --- .changeset/fair-beds-destroy.md | 6 + packages/css/accordion.css | 15 +- packages/css/alert.css | 19 - packages/css/avatar.css | 18 +- packages/css/badge.css | 25 +- packages/css/base/base.css | 94 +- packages/css/breadcrumbs.css | 16 - packages/css/button.css | 43 +- packages/css/card.css | 12 +- packages/css/chip.css | 21 +- packages/css/dropdown.css | 39 +- packages/css/error-summary.css | 1 + packages/css/heading.css | 11 +- packages/css/helptext.css | 10 - packages/css/index.css | 105 ++ packages/css/input.css | 41 +- packages/css/label.css | 15 - packages/css/list.css | 14 - packages/css/pagination.css | 20 +- packages/css/paragraph.css | 56 +- packages/css/popover.css | 14 - packages/css/search.css | 2 +- packages/css/spinner.css | 21 +- packages/css/table.css | 17 - packages/css/tabs.css | 27 +- packages/css/tag.css | 19 +- packages/css/tooltip.css | 3 +- packages/css/validation-message.css | 21 - .../src/components/Alert/Alert.stories.tsx | 2 +- packages/react/src/components/Alert/Alert.tsx | 7 +- .../src/components/Avatar/Avatar.test.tsx | 1 - .../react/src/components/Avatar/Avatar.tsx | 5 +- packages/react/src/components/Badge/Badge.tsx | 7 +- .../components/Breadcrumbs/Breadcrumbs.tsx | 4 +- .../react/src/components/Button/Button.mdx | 18 +- .../src/components/Button/Button.stories.tsx | 50 +- .../react/src/components/Button/Button.tsx | 6 +- .../src/components/Card/Card.stories.tsx | 101 +- packages/react/src/components/Chip/Chips.tsx | 4 +- .../src/components/Dropdown/Dropdown.tsx | 39 +- .../src/components/Dropdown/DropdownItem.tsx | 9 +- .../components/ErrorSummary/ErrorSummary.tsx | 11 +- .../ErrorSummary/ErrorSummaryHeading.tsx | 21 +- .../ErrorSummary/ErrorSummaryList.tsx | 7 +- .../react/src/components/Heading/Heading.tsx | 7 +- .../src/components/HelpText/HelpText.tsx | 19 +- packages/react/src/components/Label/Label.tsx | 4 +- packages/react/src/components/List/Lists.tsx | 4 +- .../src/components/Modal/Modal.stories.tsx | 16 +- packages/react/src/components/Modal/Modal.tsx | 1 - .../Pagination/Pagination.stories.tsx | 8 +- .../src/components/Pagination/Pagination.tsx | 26 +- .../Pagination/PaginationButton.tsx | 8 +- .../components/Pagination/PaginationList.tsx | 2 +- .../src/components/Paragraph/Paragraph.tsx | 5 +- .../react/src/components/Popover/Popover.tsx | 6 +- .../src/components/Table/Table.stories.tsx | 213 ++-- packages/react/src/components/Table/Table.tsx | 6 +- packages/react/src/components/Tabs/Tabs.tsx | 8 +- .../react/src/components/Tabs/TabsPanel.tsx | 2 +- packages/react/src/components/Tag/Tag.tsx | 6 +- .../components/ToggleGroup/ToggleGroup.tsx | 21 +- .../ToggleGroup/ToggleGroupItem.tsx | 3 +- .../ToggleGroup/useToggleGroupitem.ts | 3 - .../components/Tooltip/Tooltip.stories.tsx | 15 +- .../react/src/components/Tooltip/Tooltip.tsx | 2 +- .../ValidationMessage/ValidationMessage.tsx | 4 +- .../src/components/form/Combobox/Combobox.tsx | 2 +- .../react/src/components/form/Input/Input.tsx | 6 +- .../src/components/form/Search/Search.tsx | 3 +- .../src/components/form/Select/Select.tsx | 3 +- .../form/Textarea/Textarea.stories.tsx | 1 - .../src/components/form/Textarea/Textarea.tsx | 3 +- .../components/form/Textfield/Textfield.tsx | 3 +- .../react/src/components/form/useFormField.ts | 3 +- .../loaders/Spinner/Spinner.test.tsx | 8 - .../components/loaders/Spinner/Spinner.tsx | 4 +- .../react/src/{types/Portal.ts => types.ts} | 2 + packages/react/stories/testing.stories.tsx | 911 +++++++++++++++++- 79 files changed, 1431 insertions(+), 904 deletions(-) create mode 100644 .changeset/fair-beds-destroy.md rename packages/react/src/{types/Portal.ts => types.ts} (84%) diff --git a/.changeset/fair-beds-destroy.md b/.changeset/fair-beds-destroy.md new file mode 100644 index 0000000000..68c96596f7 --- /dev/null +++ b/.changeset/fair-beds-destroy.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +CSS: base sizing on font-size so all components can have all sizes, and naturally inherits size from context diff --git a/packages/css/accordion.css b/packages/css/accordion.css index ea7e8e5fe1..cb0cb3a665 100644 --- a/packages/css/accordion.css +++ b/packages/css/accordion.css @@ -8,7 +8,8 @@ --dsc-accordion-heading-background--hover: var(--ds-color-neutral-surface-default); --dsc-accordion-heading-background--open: var(--ds-color-neutral-background-subtle); --dsc-accordion-heading-background: var(--ds-color-neutral-background-default); - --dsc-accordion-padding: var(--ds-spacing-4); + --dsc-accordion-padding: var(--ds-spacing-2) var(--ds-spacing-4); + --dsc-accordion-size: var(--ds-sizing-14); &[data-border] > * { border: var(--dsc-accordion-border); @@ -65,16 +66,18 @@ box-sizing: border-box; & > :is(summary, u-summary) { + align-items: center; background: var(--dsc-accordion-heading-background); box-sizing: border-box; cursor: pointer; + display: flex; list-style: none; + min-height: var(--dsc-accordion-size); + gap: var(--dsc-accordion-chevron-gap); outline: none; - padding-block: var(--dsc-accordion-padding); - padding-inline: calc(var(--dsc-accordion-padding) + var(--dsc-accordion-chevron-size) + var(--dsc-accordion-chevron-gap)) var(--dsc-accordion-padding); + padding: var(--dsc-accordion-padding); @composes ds-focus from './base/base.css'; - @composes ds-body-text--sm from './base/base.css'; &:focus-visible { position: relative; /* Ensure foucs outline renders on top */ @@ -84,11 +87,9 @@ background: currentcolor; border-radius: var(--ds-border-radius-md); content: ''; + flex-shrink: 0; height: var(--dsc-accordion-chevron-size); mask: 50% / contain no-repeat var(--dsc-accordion-chevron-url); - 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" */ - width: var(--dsc-accordion-chevron-size); } } diff --git a/packages/css/alert.css b/packages/css/alert.css index 4868a9d0c4..fe28d6aaae 100644 --- a/packages/css/alert.css +++ b/packages/css/alert.css @@ -18,8 +18,6 @@ padding-inline: calc(var(--dsc-alert-padding) + var(--dsc-alert-icon-size) + var(--dsc-alert-gap)) var(--dsc-alert-padding); position: relative; - @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 */ { background: var(--dsc-alert-icon-color); @@ -55,21 +53,4 @@ --dsc-alert-icon-color: var(--ds-color-danger-text-subtle); --dsc-alert-icon-url: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M7.74 2.47a.75.75 0 0 1 .53-.22h7.46a.75.75 0 0 1 .53.22l5.27 5.27c.14.14.22.33.22.53v7.46a.75.75 0 0 1-.22.53l-5.27 5.27a.75.75 0 0 1-.53.22H8.27a.75.75 0 0 1-.53-.22l-5.27-5.27a.75.75 0 0 1-.22-.53V8.27a.75.75 0 0 1 .22-.53zm1.29 5.5a.75.75 0 0 0-1.06 1.06L10.94 12l-2.97 2.97a.75.75 0 1 0 1.06 1.06L12 13.06l2.97 2.97a.75.75 0 1 0 1.06-1.06L13.06 12l2.97-2.97a.75.75 0 0 0-1.06-1.06L12 10.94z'/%3E%3C/svg%3E"); } - - /** - * Sizes - */ - &[data-size='sm'] { - --dsc-alert-icon-size: var(--ds-sizing-6); - --dsc-alert-padding: var(--ds-spacing-5); - - @composes ds-body-text--sm from './base/base.css'; - } - - &[data-size='lg'] { - --dsc-alert-icon-size: var(--ds-sizing-8); - --dsc-alert-padding: var(--ds-spacing-7); - - @composes ds-body-text--lg from './base/base.css'; - } } diff --git a/packages/css/avatar.css b/packages/css/avatar.css index 0f17adc12a..3e37c02b1a 100644 --- a/packages/css/avatar.css +++ b/packages/css/avatar.css @@ -12,6 +12,7 @@ box-sizing: border-box; color: var(--dsc-avatar-color); display: inline-flex; + font-weight: var(--ds-font-weight-medium); height: var(--dsc-avatar-size); justify-content: center; overflow: hidden; @@ -19,8 +20,6 @@ text-transform: uppercase; user-select: none; - @composes ds-body-text--xs from './base/base.css'; - &:not(:has(> img)) { padding: var(--dsc-avatar-padding); } @@ -79,31 +78,20 @@ --dsc-avatar-color: var(--ds-color-brand3-contrast-default); } + /* TODO: Sizes */ &[data-size='xs'] { - --dsc-avatar-size: var(--ds-sizing-7); - --dsc-avatar-padding: var(--ds-spacing-1); - - @composes ds-body-text--xs from './base/base.css'; + font-size: var(--ds-body-xs-font-size); } &[data-size='sm'] { - --dsc-avatar-size: var(--ds-sizing-9); - --dsc-avatar-padding: var(--ds-spacing-1); - @composes ds-heading-text--2xs from './base/base.css'; } &[data-size='md'] { - --dsc-avatar-size: var(--ds-sizing-12); - --dsc-avatar-padding: var(--ds-spacing-2); - @composes ds-heading-text--sm from './base/base.css'; } &[data-size='lg'] { - --dsc-avatar-size: var(--ds-sizing-15); - --dsc-avatar-padding: var(--ds-spacing-2); - @composes ds-heading-text--md from './base/base.css'; } } diff --git a/packages/css/badge.css b/packages/css/badge.css index 6d171b3bf8..704c304062 100644 --- a/packages/css/badge.css +++ b/packages/css/badge.css @@ -6,10 +6,9 @@ box-sizing: border-box; display: inline-flex; + line-height: var(--ds-line-height-sm); position: relative; - @composes ds-body-text--short-sm from './base/base.css'; - &::before { content: attr(data-count); background: var(--dsc-badge-background); @@ -23,26 +22,8 @@ place-items: center; } - &[data-size='sm'] { - --dsc-badge-size: var(--ds-sizing-3); - --dsc-badge-padding: 0 var(--ds-spacing-1); - - @composes ds-body-text--short-xs from './base/base.css'; - - &[data-count] { - --dsc-badge-size: var(--ds-sizing-5); - } - } - - &[data-size='lg'] { - --dsc-badge-size: var(--ds-sizing-4); - --dsc-badge-padding: 0 var(--ds-spacing-2); - - @composes ds-body-text--short-md from './base/base.css'; - - &[data-count] { - --dsc-badge-size: var(--ds-sizing-7); - } + &:not([data-size]) { + font-size: var(--ds-font-size-minus-1); /* Default to small when size is not defined */ } &[data-color='info'] { diff --git a/packages/css/base/base.css b/packages/css/base/base.css index 62863d5826..37ce955b0f 100644 --- a/packages/css/base/base.css +++ b/packages/css/base/base.css @@ -17,6 +17,14 @@ --dsc-focus-border-width: 3px; /* Default focus border width */ --dsc-focus-boxShadow: 0 0 0 var(--dsc-focus-border-width) var(--ds-color-focus-inner); --dsc-focus-outline: var(--ds-color-focus-outer) solid var(--dsc-focus-border-width); + --ds-font-size-minus-1: max(.9em, .875rem); /* Default to 90% of font-size, but minimum 14px */ + --ds-font-size-plus-1: 1.1em; /* Default to 110% */ + + /* font-size adjustments if supporting round() */ + @supports (width: round(down, .1em, 1px)) { + --ds-font-size-minus-1: round(down, max(.9em, .875rem), 0.0625rem); /* Default to 90% of font-size, but minimum 14px */ + --ds-font-size-plus-1: round(down, 1.1em, 0.0625rem); /* Default to 110% */ + } color: var(--ds-color-neutral-text-default); background-color: var(--ds-color-neutral-background-default); @@ -42,114 +50,44 @@ outline-offset: var(--dsc-focus-border-width); } -/** Body typography */ -.ds-body-text--xs { +[data-size='xs'] { font-weight: var(--ds-body-xs-font-weight); line-height: var(--ds-body-xs-line-height); font-size: var(--ds-body-xs-font-size); letter-spacing: var(--ds-body-xs-letter-spacing); } -.ds-body-text--sm { +[data-size='sm'] { font-weight: var(--ds-body-sm-font-weight); line-height: var(--ds-body-sm-line-height); font-size: var(--ds-body-sm-font-size); letter-spacing: var(--ds-body-sm-letter-spacing); } -.ds-body-text--md { +/* Setting default font on not :root/ to ensure 1rem is still 16px */ +body, +[data-size='md'] { font-weight: var(--ds-body-md-font-weight); line-height: var(--ds-body-md-line-height); font-size: var(--ds-body-md-font-size); letter-spacing: var(--ds-body-md-letter-spacing); } -.ds-body-text--lg { +[data-size='lg'] { font-weight: var(--ds-body-lg-font-weight); line-height: var(--ds-body-lg-line-height); font-size: var(--ds-body-lg-font-size); letter-spacing: var(--ds-body-lg-letter-spacing); } -.ds-body-text--xl { +[data-size='xl'] { font-weight: var(--ds-body-xl-font-weight); line-height: var(--ds-body-xl-line-height); font-size: var(--ds-body-xl-font-size); letter-spacing: var(--ds-body-xl-letter-spacing); } -.ds-body-text--long-xs { - font-weight: var(--ds-body-long-xs-font-weight); - line-height: var(--ds-body-long-xs-line-height); - font-size: var(--ds-body-long-xs-font-size); - letter-spacing: var(--ds-body-long-xs-letter-spacing); -} - -.ds-body-text--long-sm { - font-weight: var(--ds-body-long-sm-font-weight); - line-height: var(--ds-body-long-sm-line-height); - font-size: var(--ds-body-long-sm-font-size); - letter-spacing: var(--ds-body-long-sm-letter-spacing); -} - -.ds-body-text--long-md { - font-weight: var(--ds-body-long-md-font-weight); - line-height: var(--ds-body-long-md-line-height); - font-size: var(--ds-body-long-md-font-size); - letter-spacing: var(--ds-body-long-md-letter-spacing); -} - -.ds-body-text--long-lg { - font-weight: var(--ds-body-long-lg-font-weight); - line-height: var(--ds-body-long-lg-line-height); - font-size: var(--ds-body-long-lg-font-size); - letter-spacing: var(--ds-body-long-lg-letter-spacing); -} - -.ds-body-text--long-xl { - font-weight: var(--ds-body-long-xl-font-weight); - line-height: var(--ds-body-long-xl-line-height); - font-size: var(--ds-body-long-xl-font-size); - letter-spacing: var(--ds-body-long-xl-letter-spacing); -} - -.ds-body-text--short-xs { - font-weight: var(--ds-body-short-xs-font-weight); - line-height: var(--ds-body-short-xs-line-height); - font-size: var(--ds-body-short-xs-font-size); - letter-spacing: var(--ds-body-short-xs-letter-spacing); -} - -.ds-body-text--short-sm { - font-weight: var(--ds-body-short-sm-font-weight); - line-height: var(--ds-body-short-sm-line-height); - font-size: var(--ds-body-short-sm-font-size); - letter-spacing: var(--ds-body-short-sm-letter-spacing); -} - -.ds-body-text--short-md { - font-weight: var(--ds-body-short-md-font-weight); - line-height: var(--ds-body-short-md-line-height); - font-size: var(--ds-body-short-md-font-size); - letter-spacing: var(--ds-body-short-md-letter-spacing); -} - -.ds-body-text--short-lg { - font-weight: var(--ds-body-short-lg-font-weight); - line-height: var(--ds-body-short-lg-line-height); - font-size: var(--ds-body-short-lg-font-size); - letter-spacing: var(--ds-body-short-lg-letter-spacing); -} - -.ds-body-text--short-xl { - font-weight: var(--ds-body-short-xl-font-weight); - line-height: var(--ds-body-short-xl-line-height); - font-size: var(--ds-body-short-xl-font-size); - letter-spacing: var(--ds-body-short-xl-letter-spacing); -} - /** Heading */ - .ds-heading-text--2xs { font-weight: var(--ds-heading-2xs-font-weight); line-height: var(--ds-heading-2xs-line-height); @@ -199,6 +137,7 @@ letter-spacing: var(--ds-heading-2xl-letter-spacing); } +/* TODO: Maybe remove label sizes after sync with design */ .ds-label--md { font-size: var(--ds-label-md-font-size); font-weight: var(--ds-label-md-font-weight); @@ -227,6 +166,7 @@ letter-spacing: var(--ds-label-lg-letter-spacing); } +/* TODO: Maybe remove validation sizes after sync with design */ .ds-validation-message--xs { font-weight: var(--ds-validation-message-xs-font-weight); line-height: var(--ds-validation-message-xs-line-height); diff --git a/packages/css/breadcrumbs.css b/packages/css/breadcrumbs.css index 851f4d2dda..fb778a47d0 100644 --- a/packages/css/breadcrumbs.css +++ b/packages/css/breadcrumbs.css @@ -3,22 +3,6 @@ --dsc-breadcrumbs-chevron-size: var(--ds-sizing-6); --dsc-breadcrumbs-icon-url: 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"); - @composes ds-body-text--md from './base/base.css'; - - &[data-size='sm'] { - --dsc-breadcrumbs-spacing: var(--ds-spacing-1); - --dsc-breadcrumbs-chevron-size: var(--ds-sizing-5); - - @composes ds-body-text--sm from './base/base.css'; - } - - &[data-size='lg'] { - --dsc-breadcrumbs-spacing: var(--ds-spacing-3); - --dsc-breadcrumbs-chevron-size: var(--ds-sizing-7); - - @composes ds-body-text--lg from './base/base.css'; - } - & > :is(ol, ul) { display: flex; flex-wrap: wrap; diff --git a/packages/css/button.css b/packages/css/button.css index 86815edcd5..7b01cc64b9 100644 --- a/packages/css/button.css +++ b/packages/css/button.css @@ -5,13 +5,9 @@ --dsc-button-color: var(--ds-color-accent-contrast-default); --dsc-button-font-size: var(--ds-font-size-5); --dsc-button-gap: var(--ds-spacing-2); - --dsc-button-padding-block: var(--ds-spacing-2); - --dsc-button-padding-inline: var(--ds-spacing-4); + --dsc-button-padding: var(--ds-spacing-2) var(--ds-spacing-4); --dsc-button-size: var(--ds-sizing-12); - @composes ds-body-text--short-md from './base/base.css'; - @composes ds-focus from './base/base.css'; - align-items: center; background: var(--dsc-button-background); border-radius: var(--ds-border-radius-default); @@ -20,19 +16,27 @@ color: var(--dsc-button-color); cursor: pointer; font-family: inherit; + font-weight: var(--ds-font-weight-medium); gap: var(--dsc-button-gap); justify-content: center; + line-height: var(--ds-line-height-sm); min-height: var(--dsc-button-size); min-width: var(--dsc-button-size); outline: none; - padding: var(--dsc-button-padding-block) var(--dsc-button-padding-inline); + padding: var(--dsc-button-padding); text-align: inherit; text-decoration: none; - font-weight: var(--ds-font-weight-medium); - & svg, - & img { + @composes ds-focus from './base/base.css'; + + &:not([data-size]) { + font-size: inherit; /* Ensure inheriting font-size when @@ -102,15 +102,15 @@ AccentPressed.parameters = { export const Neutral: StoryFn = () => ( <> @@ -131,15 +131,15 @@ NeutralPressed.parameters = { export const Danger: StoryFn = () => ( <> @@ -175,7 +175,7 @@ export const AsLink: StoryFn = () => ( ); @@ -184,10 +184,10 @@ export const TextAndIcon: StoryFn = () => ( <> @@ -209,25 +209,25 @@ export const Loading: StoryFn = () => ( export const Icons: StoryFn = () => ( <> - - - @@ -237,12 +237,12 @@ export const IconOnly: StoryFn = () => ( <> @@ -252,7 +252,7 @@ export const IconOnly: StoryFn = () => ( variant='tertiary' aria-label='Innstillinger' > - + @@ -267,13 +267,13 @@ IconOnly.parameters = { export const IconsOnlyPrimary: StoryFn = () => ( <> ); diff --git a/packages/react/src/components/Button/Button.tsx b/packages/react/src/components/Button/Button.tsx index c39c955474..a3cff1f39d 100644 --- a/packages/react/src/components/Button/Button.tsx +++ b/packages/react/src/components/Button/Button.tsx @@ -2,6 +2,7 @@ import { Slot, Slottable } from '@radix-ui/react-slot'; import cl from 'clsx/lite'; import { forwardRef } from 'react'; import type { ButtonHTMLAttributes } from 'react'; +import type { Size } from '../../types'; import { Spinner } from '../loaders/Spinner'; export type ButtonProps = { @@ -16,9 +17,8 @@ export type ButtonProps = { color?: 'accent' | 'neutral' | 'danger'; /** * Size - * @default md */ - size?: 'sm' | 'md' | 'lg'; + size?: Size; /** Toggle icon only styling, pass icon as children * @default false */ @@ -53,7 +53,7 @@ export const Button = forwardRef( color = 'accent', icon = false, loading = false, - size = 'md', + size, variant = 'primary', ...rest }, diff --git a/packages/react/src/components/Card/Card.stories.tsx b/packages/react/src/components/Card/Card.stories.tsx index 0eed2ccaff..7fad0635ef 100644 --- a/packages/react/src/components/Card/Card.stories.tsx +++ b/packages/react/src/components/Card/Card.stories.tsx @@ -6,13 +6,16 @@ import cat5 from '@assets/img/cats/Cat 5.jpg'; import { PlusIcon, TrashFillIcon } from '@navikt/aksel-icons'; import type { Meta, StoryFn } from '@storybook/react'; -import { Card } from '.'; -import { Button } from '../Button'; -import { Heading } from '../Heading'; -import { Label } from '../Label'; -import { Paragraph } from '../Paragraph'; -import { Select } from '../form/Select'; -import { Textfield } from '../form/Textfield'; +import { + Button, + Card, + Field, + Heading, + Label, + Paragraph, + Select, + Textfield, +} from '../../'; type Story = StoryFn; @@ -34,9 +37,7 @@ export default { export const Preview: Story = (args) => ( - - Card Neutral - + Card Neutral Most provide as with carried business are much better more the perfected designer. Writing slightly explain desk unable at supposedly about this @@ -56,9 +57,7 @@ export const Variants: StoryFn = () => ( katt - - Card Neutral - + Card Neutral Most provide as with carried business are much better more the perfected designer. Writing slightly explain desk unable at supposedly @@ -71,9 +70,7 @@ export const Variants: StoryFn = () => ( katt - - Card Subtle - + Card Subtle Most provide as with carried business are much better more the perfected designer. Writing slightly explain desk unable at supposedly @@ -86,9 +83,7 @@ export const Variants: StoryFn = () => ( katter - - Card First - + Card First Most provide as with carried business are much better more the perfected designer. Writing slightly explain desk unable at supposedly @@ -101,9 +96,7 @@ export const Variants: StoryFn = () => ( katt - - Card Second - + Card Second Most provide as with carried business are much better more the perfected designer. Writing slightly explain desk unable at supposedly @@ -116,9 +109,7 @@ export const Variants: StoryFn = () => ( katt - - Card Third - + Card Third Most provide as with carried business are much better more the perfected designer. Writing slightly explain desk unable at supposedly @@ -136,9 +127,7 @@ export const Media: Story = () => ( katt - - Card Neutral - + Card Neutral Most provide as with carried business are much better more the perfected designer. Writing slightly explain desk unable at supposedly @@ -148,9 +137,7 @@ export const Media: Story = () => ( - - Card Neutral - + Card Neutral Most provide as with carried business are much better more the perfected designer. Writing slightly explain desk unable at supposedly @@ -177,7 +164,7 @@ export const Video: Story = () => ( > - + ( alignItems: 'center', }} > - - Rolle 1 - + Rolle 1 Modal subtittel - + Modal header @@ -94,9 +94,7 @@ export const BackdropClose: StoryFn = () => { Open Modal - - Modal med backdropClose og en veldig lang tittel - + Modal med backdropClose og en veldig lang tittel Lorem ipsum dolor sit, amet consectetur adipisicing elit. Blanditiis doloremque obcaecati assumenda odio ducimus sunt et. @@ -113,7 +111,7 @@ export const WithHeaderAndFooter: StoryFn = () => ( Her er det også divider - Vi kan legge divider under header + Vi kan legge divider under header @@ -152,7 +150,7 @@ export const ModalWithForm: StoryFn = () => { Open Modal setInput('')} backdropClose> - + Modal med skjema = () => ( Open Modal - + Modal med en veldig lang bredde @@ -210,7 +208,7 @@ export const ModalWithCombobox: StoryFn = () => { Open Modal - Modal med combobox + Modal med combobox diff --git a/packages/react/src/components/Modal/Modal.tsx b/packages/react/src/components/Modal/Modal.tsx index cf7dfbeb97..686ff41a29 100644 --- a/packages/react/src/components/Modal/Modal.tsx +++ b/packages/react/src/components/Modal/Modal.tsx @@ -20,7 +20,6 @@ export type ModalProps = { backdropClose?: boolean; /** * Callback that is called when the modal is closed. - * @default undefined */ onClose?: () => void; asChild?: boolean; diff --git a/packages/react/src/components/Pagination/Pagination.stories.tsx b/packages/react/src/components/Pagination/Pagination.stories.tsx index f77596f8a8..399d3997f6 100644 --- a/packages/react/src/components/Pagination/Pagination.stories.tsx +++ b/packages/react/src/components/Pagination/Pagination.stories.tsx @@ -2,13 +2,16 @@ import { useArgs } from '@storybook/preview-api'; import type { Meta, StoryFn } from '@storybook/react'; import { Pagination, type UsePaginationProps, usePagination } from '.'; +import type { Size } from '../../types'; export default { title: 'Komponenter/Pagination', component: Pagination, } as Meta; -export const Preview: StoryFn = (args) => { +export const Preview: StoryFn = ( + args, +) => { const [, updateArgs] = useArgs(); const { pages, nextButtonProps, prevButtonProps } = usePagination({ ...args, @@ -16,7 +19,7 @@ export const Preview: StoryFn = (args) => { }); return ( - + @@ -41,6 +44,7 @@ export const Preview: StoryFn = (args) => { }; Preview.args = { + size: 'md', currentPage: 4, setCurrentPage: console.log, // Added to include in storybook args onChange: console.log, // Open console to see this event diff --git a/packages/react/src/components/Pagination/Pagination.tsx b/packages/react/src/components/Pagination/Pagination.tsx index 42ed4ecd78..b607abeb03 100644 --- a/packages/react/src/components/Pagination/Pagination.tsx +++ b/packages/react/src/components/Pagination/Pagination.tsx @@ -1,11 +1,8 @@ import { Slot } from '@radix-ui/react-slot'; import cl from 'clsx/lite'; -import { createContext, forwardRef } from 'react'; +import { forwardRef } from 'react'; import type { HTMLAttributes } from 'react'; - -export const PaginationContext = createContext({ - size: 'md' as NonNullable, -}); +import type { Size } from '../../types'; export type PaginationProps = { /** @@ -16,7 +13,7 @@ export type PaginationProps = { /** Sets the size of the component * @default md */ - size?: 'sm' | 'md' | 'lg'; + size?: Size; /** * Change the default rendered element for the one passed as a child, merging their props and behavior. * @default false @@ -30,7 +27,7 @@ export const Pagination = forwardRef( 'aria-label': ariaLabel = 'Sidenavigering', asChild, className, - size = 'md', + size, ...rest }, ref, @@ -38,14 +35,13 @@ export const Pagination = forwardRef( const Component = asChild ? Slot : 'nav'; return ( - - - + ); }, ); diff --git a/packages/react/src/components/Pagination/PaginationButton.tsx b/packages/react/src/components/Pagination/PaginationButton.tsx index aa579cb133..871adc9188 100644 --- a/packages/react/src/components/Pagination/PaginationButton.tsx +++ b/packages/react/src/components/Pagination/PaginationButton.tsx @@ -1,9 +1,7 @@ -import { type AriaAttributes, forwardRef, useContext } from 'react'; +import { type AriaAttributes, forwardRef } from 'react'; import { Button, type ButtonProps } from '../Button/Button'; -import { PaginationContext } from './Pagination'; - export type PaginationButtonProps = { /** * Toggle button as active @@ -16,7 +14,5 @@ export const PaginationButton = forwardRef< HTMLButtonElement, PaginationButtonProps >(function PaginationButton(rest, ref) { - const { size } = useContext(PaginationContext); - - return + +); + +Preview.args = { + content: 'Tooltip text', + placement: 'top', }; export const Placement: Story = { diff --git a/packages/react/src/components/Tooltip/Tooltip.tsx b/packages/react/src/components/Tooltip/Tooltip.tsx index f7c1757632..fa25841e54 100644 --- a/packages/react/src/components/Tooltip/Tooltip.tsx +++ b/packages/react/src/components/Tooltip/Tooltip.tsx @@ -23,7 +23,7 @@ import type { } from 'react'; import { Fragment, cloneElement, forwardRef, useRef, useState } from 'react'; -import type { PortalProps } from '../../types/Portal'; +import type { PortalProps } from '../../types'; export type TooltipProps = { /** diff --git a/packages/react/src/components/ValidationMessage/ValidationMessage.tsx b/packages/react/src/components/ValidationMessage/ValidationMessage.tsx index f6c1871c9f..2b72268979 100644 --- a/packages/react/src/components/ValidationMessage/ValidationMessage.tsx +++ b/packages/react/src/components/ValidationMessage/ValidationMessage.tsx @@ -2,11 +2,11 @@ import { Slot } from '@radix-ui/react-slot'; import cl from 'clsx/lite'; import type { HTMLAttributes } from 'react'; import { forwardRef } from 'react'; +import type { Size } from '../../types'; export type ValidationMessageProps = { /** * Changes text sizing - * @default md */ size?: 'xs' | 'sm' | 'md' | 'lg'; /** Toggle error color */ @@ -23,7 +23,7 @@ export const ValidationMessage = forwardRef< HTMLParagraphElement, ValidationMessageProps >(function ValidationMessage( - { size = 'md', className, asChild, error = true, ...rest }, + { size, className, asChild, error = true, ...rest }, ref, ) { const Component = asChild ? Slot : 'div'; diff --git a/packages/react/src/components/form/Combobox/Combobox.tsx b/packages/react/src/components/form/Combobox/Combobox.tsx index c790cec1d6..f43a41c8ff 100644 --- a/packages/react/src/components/form/Combobox/Combobox.tsx +++ b/packages/react/src/components/form/Combobox/Combobox.tsx @@ -4,7 +4,7 @@ import cl from 'clsx/lite'; import { forwardRef, useEffect, useRef, useState } from 'react'; import type { InputHTMLAttributes, ReactNode } from 'react'; -import type { PortalProps } from '../../../types/Portal'; +import type { PortalProps } from '../../../types'; import { omit, useDebounceCallback } from '../../../utilities'; import { Spinner } from '../../loaders/Spinner'; import type { FormFieldProps } from '../useFormField'; diff --git a/packages/react/src/components/form/Input/Input.tsx b/packages/react/src/components/form/Input/Input.tsx index f1aea063a0..579a3f9456 100644 --- a/packages/react/src/components/form/Input/Input.tsx +++ b/packages/react/src/components/form/Input/Input.tsx @@ -1,14 +1,14 @@ import cl from 'clsx/lite'; import type { InputHTMLAttributes } from 'react'; import { forwardRef } from 'react'; +import type { Size } from '../../../types'; type InputAttr = InputHTMLAttributes; export type InputProps = { /** * Changes field size and paddings - * @default md */ - size?: 'sm' | 'md' | 'lg'; + size?: Size; /** Supported `input` types */ type?: InputAttr['type']; /** Exposes the HTML `size` attribute. @@ -33,7 +33,7 @@ export type InputProps = { * ``` */ export const Input = forwardRef(function Input( - { type = 'text', size = 'md', htmlSize, className, onClick, ...rest }, + { type = 'text', size, htmlSize, className, onClick, ...rest }, ref, ) { return ( diff --git a/packages/react/src/components/form/Search/Search.tsx b/packages/react/src/components/form/Search/Search.tsx index 9a8eb92b1f..e5e77d2c12 100644 --- a/packages/react/src/components/form/Search/Search.tsx +++ b/packages/react/src/components/form/Search/Search.tsx @@ -4,6 +4,7 @@ import cl from 'clsx/lite'; import type { ChangeEvent, InputHTMLAttributes, ReactNode } from 'react'; import { forwardRef, useCallback, useRef, useState } from 'react'; +import type { Size } from '../../../types'; import { omit } from '../../../utilities'; import { Button } from '../../Button/Button'; import { Label } from '../../Label'; @@ -23,7 +24,7 @@ export type SearchProps = { * Changes field size and paddings * @default md */ - size?: 'sm' | 'md' | 'lg'; + size?: Size; /** Variant * @default 'simple' */ diff --git a/packages/react/src/components/form/Select/Select.tsx b/packages/react/src/components/form/Select/Select.tsx index 39f44dc070..fdcc88a69a 100644 --- a/packages/react/src/components/form/Select/Select.tsx +++ b/packages/react/src/components/form/Select/Select.tsx @@ -1,13 +1,14 @@ import cl from 'clsx/lite'; import { forwardRef } from 'react'; import type { SelectHTMLAttributes } from 'react'; +import type { Size } from '../../../types'; export type SelectProps = { /** * Defines the size of the select. * @default md **/ - size?: 'sm' | 'md' | 'lg'; + size?: Size; /** Defines if the select is readOnly * @default false */ diff --git a/packages/react/src/components/form/Textarea/Textarea.stories.tsx b/packages/react/src/components/form/Textarea/Textarea.stories.tsx index 9472b2dfbf..c56d59d4d3 100644 --- a/packages/react/src/components/form/Textarea/Textarea.stories.tsx +++ b/packages/react/src/components/form/Textarea/Textarea.stories.tsx @@ -62,7 +62,6 @@ export const Preview: Story = { export const FullWidth: Story = { args: { - rows: 10, cols: 40, id: 'my-textarea', }, diff --git a/packages/react/src/components/form/Textarea/Textarea.tsx b/packages/react/src/components/form/Textarea/Textarea.tsx index 979ae5c6fe..5887fc26e1 100644 --- a/packages/react/src/components/form/Textarea/Textarea.tsx +++ b/packages/react/src/components/form/Textarea/Textarea.tsx @@ -1,13 +1,14 @@ import cl from 'clsx/lite'; import type { TextareaHTMLAttributes } from 'react'; import { forwardRef } from 'react'; +import type { Size } from '../../../types'; export type TextareaProps = { /** * Defines the size of the select. * @default md **/ - size?: 'sm' | 'md' | 'lg'; + size?: Size; } & TextareaHTMLAttributes; /** Textarea field diff --git a/packages/react/src/components/form/Textfield/Textfield.tsx b/packages/react/src/components/form/Textfield/Textfield.tsx index 11336bad66..69702b6538 100644 --- a/packages/react/src/components/form/Textfield/Textfield.tsx +++ b/packages/react/src/components/form/Textfield/Textfield.tsx @@ -3,6 +3,7 @@ import cl from 'clsx/lite'; import type { InputHTMLAttributes, ReactNode } from 'react'; import { forwardRef, useId, useState } from 'react'; +import type { Size } from '../../../types'; import { omit } from '../../../utilities'; import { Label } from '../../Label'; import { Paragraph } from '../../Paragraph'; @@ -22,7 +23,7 @@ export type TextfieldProps = { * Changes field size and paddings * @default md */ - size?: 'sm' | 'md' | 'lg'; + size?: Size; /** Prefix for field. */ prefix?: string; /** Suffix for field. */ diff --git a/packages/react/src/components/form/useFormField.ts b/packages/react/src/components/form/useFormField.ts index e866b08233..7c4ab727c1 100644 --- a/packages/react/src/components/form/useFormField.ts +++ b/packages/react/src/components/form/useFormField.ts @@ -2,6 +2,7 @@ import cl from 'clsx/lite'; import { useContext, useId } from 'react'; import type { HTMLAttributes, InputHTMLAttributes, ReactNode } from 'react'; +import type { Size } from '../../types'; import { FieldsetContext } from './Fieldset/FieldsetContext'; export type FormFieldProps = { @@ -23,7 +24,7 @@ export type FormFieldProps = { * Changes field size and paddings * @default md */ - size?: 'sm' | 'md' | 'lg'; + size?: Size; } & Pick, 'aria-describedby'>; export type FormField = { diff --git a/packages/react/src/components/loaders/Spinner/Spinner.test.tsx b/packages/react/src/components/loaders/Spinner/Spinner.test.tsx index ac7c6cc49e..2c21afe4d3 100644 --- a/packages/react/src/components/loaders/Spinner/Spinner.test.tsx +++ b/packages/react/src/components/loaders/Spinner/Spinner.test.tsx @@ -7,14 +7,6 @@ beforeAll(() => { }); describe('spinner', (): void => { - it('should render with default medium size', (): void => { - render(); - expect(screen.getByTitle('Loading').parentElement).toHaveAttribute( - 'data-size', - 'md', - ); - }); - it('should render with title "loading', (): void => { render(); expect(screen.getByTitle('Loading')).toBeInTheDocument(); diff --git a/packages/react/src/components/loaders/Spinner/Spinner.tsx b/packages/react/src/components/loaders/Spinner/Spinner.tsx index 93ea490ae6..f2d8a7fe41 100644 --- a/packages/react/src/components/loaders/Spinner/Spinner.tsx +++ b/packages/react/src/components/loaders/Spinner/Spinner.tsx @@ -8,8 +8,6 @@ export type SpinnerProps = { title: string; /** * Spinner size - * - * @default md */ size?: '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl'; /** @@ -23,7 +21,7 @@ export type SpinnerProps = { export const Spinner = ({ title, color = 'neutral', - size = 'md', + size, className, ...rest }: SpinnerProps): JSX.Element => { diff --git a/packages/react/src/types/Portal.ts b/packages/react/src/types.ts similarity index 84% rename from packages/react/src/types/Portal.ts rename to packages/react/src/types.ts index 09ba9044b0..a70d2ef8e1 100644 --- a/packages/react/src/types/Portal.ts +++ b/packages/react/src/types.ts @@ -1,3 +1,5 @@ +export type Size = 'sm' | 'md' | 'lg'; + export type PortalProps = { /** * Portals the floating element outside of the app root and into the body. diff --git a/packages/react/stories/testing.stories.tsx b/packages/react/stories/testing.stories.tsx index 4c96b74d79..373546a5da 100644 --- a/packages/react/stories/testing.stories.tsx +++ b/packages/react/stories/testing.stories.tsx @@ -1,16 +1,44 @@ +import { PrinterSmallIcon } from '@navikt/aksel-icons'; import type { Meta, StoryFn } from '@storybook/react'; +import { useState } from 'react'; import { + Accordion, + Alert, + Avatar, + Badge, + Breadcrumbs, Button, + Card, Checkbox, Chip, Combobox, + Dropdown, + ErrorSummary, + Field, + Heading, + HelpText, + Input, + Label, + Link, + List, + Modal, + Pagination, + Paragraph, + Popover, Radio, Select, + Spinner, Switch, + Table, + Tabs, Tag, Textfield, -} from '../src/components'; + ToggleGroup, + Tooltip, + ValidationMessage, + usePagination, +} from '../src'; export default { title: 'Testing', @@ -127,3 +155,884 @@ LargeCol.args = { size: 'lg', direction: 'column', }; + +export const Sizes: StoryFn = () => { + const [currentPage, setCurrentPage] = useState(4); + const { pages, nextButtonProps, prevButtonProps } = usePagination({ + currentPage, + onChange: console.log, // Open console to see this event + totalPages: 10, + showPages: 7, + setCurrentPage, + }); + + return ( +
+
14px
+
16px
+
18px
+
24px
+ + + + Hvem kan registrere seg i Frivillighetsregisteret? + + + For å kunne bli registrert i Frivillighetsregisteret, må + organisasjonen drive frivillig virksomhet. Det er bare foreninger, + stiftelser og aksjeselskap som kan registreres. Virksomheten kan + ikke dele ut midler til fysiske personer. Virksomheten må ha et + styre. + + + + + + + Hvem kan registrere seg i Frivillighetsregisteret? + + + For å kunne bli registrert i Frivillighetsregisteret, må + organisasjonen drive frivillig virksomhet. Det er bare foreninger, + stiftelser og aksjeselskap som kan registreres. Virksomheten kan + ikke dele ut midler til fysiske personer. Virksomheten må ha et + styre. + + + + + + + Hvem kan registrere seg i Frivillighetsregisteret? + + + For å kunne bli registrert i Frivillighetsregisteret, må + organisasjonen drive frivillig virksomhet. Det er bare foreninger, + stiftelser og aksjeselskap som kan registreres. Virksomheten kan + ikke dele ut midler til fysiske personer. Virksomheten må ha et + styre. + + + + + + + Hvem kan registrere seg i Frivillighetsregisteret? + + + For å kunne bli registrert i Frivillighetsregisteret, må + organisasjonen drive frivillig virksomhet. Det er bare foreninger, + stiftelser og aksjeselskap som kan registreres. Virksomheten kan + ikke dele ut midler til fysiske personer. Virksomheten må ha et + styre. + + + + Dette er en alert + Dette er en alert + Dette er en alert + Dette er en alert +
+ + JD + +
+
+ + JD + +
+
+ + JD + +
+
+ + JD + +
+ + + + + + + + Nivå 1 + + + Nivå 2 + + + Nivå 3 + + + + + + + Nivå 1 + + + Nivå 2 + + + Nivå 3 + + + + + + + Nivå 1 + + + Nivå 2 + + + Nivå 3 + + + + + + + Nivå 1 + + + Nivå 2 + + + Nivå 3 + + + +
+ +
+
+ +
+
+ +
+
+ +
+ + Card Neutral + + Most provide as with carried business are much better more the + perfected designer. Writing slightly explain desk unable at supposedly + about this + + + + Card Neutral + + Most provide as with carried business are much better more the + perfected designer. Writing slightly explain desk unable at supposedly + about this + + + + Card Neutral + + Most provide as with carried business are much better more the + perfected designer. Writing slightly explain desk unable at supposedly + about this + + + + Card Neutral + + Most provide as with carried business are much better more the + perfected designer. Writing slightly explain desk unable at supposedly + about this + + +
+ Radio + Check + Knapp +
+
+ Radio + Check + Knapp +
+
+ Radio + Check + Knapp +
+
+ Radio + Check + Knapp +
+
+ + Dropdown + + Heading 1 + + Button 1.1 + Button 1.2 + + + +
+
+ + Dropdown + + Heading 1 + + Button 1.1 + Button 1.2 + + + +
+
+ + Dropdown + + Heading 1 + + Button 1.1 + Button 1.2 + + + +
+
+ + Dropdown + + Heading 1 + + Button 1.1 + Button 1.2 + + + +
+ + + For å gå videre må du rette opp følgende feil: + + + + Fødselsdato kan ikke være etter år 2005 + + E-post må være gyldig + + + + + For å gå videre må du rette opp følgende feil: + + + + Fødselsdato kan ikke være etter år 2005 + + E-post må være gyldig + + + + + For å gå videre må du rette opp følgende feil: + + + + Fødselsdato kan ikke være etter år 2005 + + E-post må være gyldig + + + + + For å gå videre må du rette opp følgende feil: + + + + Fødselsdato kan ikke være etter år 2005 + + E-post må være gyldig + + + + + + + En feil + + + + + En feil + + + + + En feil + + + + + En feil + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mer tekst + + + Mer tekst + + + Mer tekst + + + Mer tekst + +
+ Lenke +
+
+ Lenke +
+
+ Lenke +
+
+ Lenke +
+ + List Item 1 + List Item 2 + List Item 3 + + + List Item 1 + List Item 2 + List Item 3 + + + List Item 1 + List Item 2 + List Item 3 + + + List Item 1 + List Item 2 + List Item 3 + + + + + +
+ + Open Modal + + + Modal header + + + Lorem ipsum dolor sit, amet consectetur adipisicing elit. + Blanditiis doloremque obcaecati assumenda odio ducimus sunt et. + + + +
+
+ + Open Modal + + + Modal header + + + Lorem ipsum dolor sit, amet consectetur adipisicing elit. + Blanditiis doloremque obcaecati assumenda odio ducimus sunt et. + + + +
+
+ + Open Modal + + + Modal header + + + Lorem ipsum dolor sit, amet consectetur adipisicing elit. + Blanditiis doloremque obcaecati assumenda odio ducimus sunt et. + + + +
+
+ + Open Modal + + + Modal header + + + Lorem ipsum dolor sit, amet consectetur adipisicing elit. + Blanditiis doloremque obcaecati assumenda odio ducimus sunt et. + + + +
+ + + + + Forrige + + + {pages.map(({ page, itemKey, buttonProps }) => ( + + + {page} + + + ))} + + + Neste + + + + + + + + + Forrige + + + {pages.map(({ page, itemKey, buttonProps }) => ( + + + {page} + + + ))} + + + Neste + + + + + + + + + Forrige + + + {pages.map(({ page, itemKey, buttonProps }) => ( + + + {page} + + + ))} + + + Neste + + + + + + + + + Forrige + + + {pages.map(({ page, itemKey, buttonProps }) => ( + + + {page} + + + ))} + + + Neste + + + + +
+ + My popup + popover content + +
+
+ + My popup + popover content + +
+
+ + My popup + popover content + +
+
+ + My popup + popover content + +
+ + + + Header 1 + Header 2 + Header 3 + + + + + Cell 1 + Cell 2 + Cell 3 + + + Cell 4 + Cell 5 + Cell 6 + + +
+ + + + Header 1 + Header 2 + Header 3 + + + + + Cell 1 + Cell 2 + Cell 3 + + + Cell 4 + Cell 5 + Cell 6 + + +
+ + + + Header 1 + Header 2 + Header 3 + + + + + Cell 1 + Cell 2 + Cell 3 + + + Cell 4 + Cell 5 + Cell 6 + + +
+ + + + Header 1 + Header 2 + Header 3 + + + + + Cell 1 + Cell 2 + Cell 3 + + + Cell 4 + Cell 5 + Cell 6 + + +
+ + + Tab 1 + Tab 2 + Tab 3 + + content 1 + content 2 + content 3 + + + + Tab 1 + Tab 2 + Tab 3 + + content 1 + content 2 + content 3 + + + + Tab 1 + Tab 2 + Tab 3 + + content 1 + content 2 + content 3 + + + + Tab 1 + Tab 2 + Tab 3 + + content 1 + content 2 + content 3 + + Tag + Tag + Tag + Tag + + Innboks + Utkast + Arkiv + + + Innboks + Utkast + Arkiv + + + Innboks + Utkast + Arkiv + + + Innboks + Utkast + Arkiv + +
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ ); +};