Compare commits

..
Author SHA1 Message Date
github-actions[bot]andgithub-actions[bot] e5ecd66a57 Version Packages (#2732)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-19 10:11:11 +01:00
Ken 78817fef45 [Aksel.nav.no] Uxtweaks-card på forside (#2735)
* 🎉 Uxtweaks-panel på forsiden til Aksel

* 🎨 Flyttet uxtweaks-box til under god-praksis panel

* 🎨 Panel har nå aside med role presentation

Dette gjør at skjermlesere hopper over 'complementary' og kommer rett til heading

* 💄 Oppdatert heading-tekst
2024-02-16 16:38:46 +01:00
Halvor Haugan 38357b1a2e Oppdatering av eksemplene på Skeleton (#2734) 2024-02-16 13:14:43 +01:00
KenandHalvor Haugan 65c17db2e5 Oppdatert Modal Context til nytt createContext-api (#2714)
* ♻️ Oppdatert hvordan ModalContext leveres

* 🏷️ onBeforeClose krever nå boolean

* ♻️ Undo rename av Modal.types for å unngå conflict

* 📝 Changeset

* 🔥 Fjernet unødvendig story-oppdatering

* 🐛 Fikset forwardRef i createContext

I tilfellene der ref blir sendt inn som en context-value, ble den tidligere slettet av React (native oppførsel)
ForwardRef lar oss beholde ref og sende den inn som context-value

* Endring av strict

* null -> undefined

---------

Co-authored-by: Halvor Haugan <halvor.haugan@nav.no>
2024-02-15 19:40:46 +01:00
Halvor Haugan 59e88773d1 🎨 prettier 2024-02-15 09:37:23 +01:00
Ken f175d0f781 🧪 ToggleGroup test (#2728) 2024-02-14 16:50:09 +01:00
Ken 18419f7d98 Stories refactor (delvis) for chromatic (#2721)
* ♻️ Oppdatert Accordion-story

* ♻️ Oppdatert Chat-story

* 🐛 Chromatic story var slått av

* 🎉 ♻️ Typo-stories oppdatert for chromatic

* ♻️ Tokens-stories

* ♻️ Oppdatert Table-stories
2024-02-14 09:43:10 +01:00
Ken f63a7ec36d 📄 Oppdatert License timestamp fra 2023 -> 2024 2024-02-09 09:44:55 +01:00
Halvor Haugan 107489bd3f [aksel.nav.no] 🔥 Fjern noAmps fra InlineCode (#2719) 2024-02-08 15:11:43 +01:00
github-actions[bot]andgithub-actions[bot] 792962592f Version Packages (#2720)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-08 13:08:21 +01:00
Ken 4a02a1987c Deprecate Panel (#2712)
* ⚰️ Markert Panel som deprecated

* 📝 Changeset

* 📝 JSDOC var feil for border på Box

* 🐛 📝 JSDoc manglet border-radius
2024-02-08 11:46:20 +01:00
Ken 700943b4a5 [ci skip] ♻️ Refaktorert Button-story 2024-02-07 20:31:25 +01:00
Ken 521c982457 🚚 Oppdatert imports til direkteimports og ikke fra root-index (#2715) 2024-02-07 16:17:17 +01:00
Ken 8c17099087 🔥 Fjernet hyphen på blogg-headings (#2711)
* 🔥 Fjernet hyphen på blogg-headings

* 🎨 Bare hyphens på mobil
2024-02-07 13:42:58 +01:00
Ken 29241a7153 ⚡ Refaktorert alert-stories for mindre chromatic-tester (#2709)
* ⚡ refaktorert alert-stories for mindre chromatic-tester

* 🐛 Fikset imports
2024-02-07 13:42:26 +01:00
github-actions[bot]andgithub-actions[bot] 7e4ee40a7f Version Packages (#2708)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-02-07 12:26:07 +01:00
Halvor Haugan 2be97970d6 Date/MonthPicker: Justeringer JSDOC og eksempel-desc (#2704) 2024-02-07 09:42:37 +01:00
Halvor Haugan 5b3c1f33c4 Eksterne typer kommer nå med i docgen (#2705) 2024-02-07 09:30:27 +01:00
KenandHalvor Haugan f44ff44410 Bytter ut FloatingPortal med egen implementasjon (#2697)
* 🎉 Egen Portal-komponent

* 🎨 Portal og Overlay exportert i root

* ♻️ Tooltip bruker egen Portal

* 📝 Changeset

* 🔥 Fjernet ID på Portal-element

* 🎉 Ny type WithAsChild

* ♻️ Mer robust sjekk for conditional elements i WithAsChild

* 📝 WithAsChild JSDOC

* 📝 WithAsChild JSDOC 2

* Update .changeset/lovely-points-heal.md

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

* ♻️ Fikset kommentarer fra git-pr

---------

Co-authored-by: Halvor Haugan <83693529+HalvorHaugan@users.noreply.github.com>
2024-02-06 18:02:00 +01:00
Ken 855669538e ⚡ Kjører bare release-workflow når nødvendige filer er endret (#2701) 2024-02-06 18:01:43 +01:00
96 changed files with 2003 additions and 1318 deletions

No files matched your search

+3
View File
@@ -2,6 +2,9 @@ name: Release
on:
push:
paths:
- ".changeset/**"
- "@navikt/**"
branches:
- main
workflow_dispatch:
+1 -1
View File
@@ -10,7 +10,7 @@ export const parameters = {
"Getting started",
"ds-react",
["Primitives"],
["Default"],
["Default", "Controls"],
"Aksel-icons",
],
},
+6
View File
@@ -1,5 +1,11 @@
# @navikt/aksel-icons
## 5.18.2
## 5.18.1
## 5.18.0
## 5.17.5
## 5.17.4
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/aksel-icons",
"version": "5.17.5",
"version": "5.18.2",
"author": "Aksel | NAV",
"homepage": "https://aksel.nav.no/ikoner",
"repository": {
+6
View File
@@ -1,5 +1,11 @@
# @navikt/aksel-stylelint
## 5.18.2
## 5.18.1
## 5.18.0
## 5.17.5
## 5.17.4
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/aksel-stylelint",
"version": "5.17.5",
"version": "5.18.2",
"author": "Aksel | NAV",
"homepage": "https://aksel.nav.no/grunnleggende/kode/stylelint",
"repository": {
@@ -35,8 +35,8 @@
"dev": "yarn watch:lint"
},
"devDependencies": {
"@navikt/ds-css": "^5.17.5",
"@navikt/ds-tokens": "^5.17.5",
"@navikt/ds-css": "^5.18.2",
"@navikt/ds-tokens": "^5.18.2",
"@types/jest": "^29.0.0",
"concurrently": "7.2.1",
"copyfiles": "2.4.1",
+21
View File
@@ -1,5 +1,26 @@
# @navikt/aksel
## 5.18.2
### Patch Changes
- Updated dependencies []:
- @navikt/ds-css@5.18.2
## 5.18.1
### Patch Changes
- Updated dependencies []:
- @navikt/ds-css@5.18.1
## 5.18.0
### Patch Changes
- Updated dependencies []:
- @navikt/ds-css@5.18.0
## 5.17.5
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/aksel",
"version": "5.17.5",
"version": "5.18.2",
"description": "Aksel command line interface. Handles css-imports, codemods and more",
"author": "Aksel | NAV designsystem team",
"license": "MIT",
@@ -29,7 +29,7 @@
},
"homepage": "https://aksel.nav.no/grunnleggende/kode/kommandolinje",
"dependencies": {
"@navikt/ds-css": "5.17.5",
"@navikt/ds-css": "5.18.2",
"axios": "1.6.0",
"chalk": "4.1.0",
"clipboardy": "^2.3.0",
+6
View File
@@ -1,5 +1,11 @@
# @navikt/ds-css
## 5.18.2
## 5.18.1
## 5.18.0
## 5.17.5
### Patch Changes
+1 -1
View File
@@ -144,7 +144,7 @@
transform: translate(var(--a-spacing-1-alt));
pointer-events: none;
/* Fixed edcase where when using in shadow-dom, svg will not center */
/* Fixed edcase where when using in shadow-dom, svg will not center */
display: flex;
align-items: center;
}
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-css",
"version": "5.17.5",
"version": "5.18.2",
"description": "CSS for NAV Designsystem",
"author": "Aksel | NAV designsystem team",
"keywords": [
@@ -27,7 +27,7 @@
"css:get-version": "node config/get-version.js"
},
"devDependencies": {
"@navikt/ds-tokens": "^5.17.5",
"@navikt/ds-tokens": "^5.18.2",
"cssnano": "6.0.0",
"fast-glob": "3.2.11",
"lodash": "4.17.21",
+32
View File
@@ -1,5 +1,37 @@
# @navikt/ds-react
## 5.18.2
### Patch Changes
- Modal: Oppdatert intern håntering av context i komponent ([#2714](https://github.com/navikt/aksel/pull/2714))
- Updated dependencies []:
- @navikt/ds-tokens@5.18.2
- @navikt/aksel-icons@5.18.2
## 5.18.1
### Patch Changes
- Panel: Komponent er nå markert som deprecated. Bruk `Box` i fremtiden. ([#2712](https://github.com/navikt/aksel/pull/2712))
- Updated dependencies []:
- @navikt/ds-tokens@5.18.1
- @navikt/aksel-icons@5.18.1
## 5.18.0
### Minor Changes
- Portal: Ny komponent `Portal` som lar deg enkelt bruke `createPortal`, også på serversiden ([#2697](https://github.com/navikt/aksel/pull/2697))
### Patch Changes
- Updated dependencies []:
- @navikt/ds-tokens@5.18.0
- @navikt/aksel-icons@5.18.0
## 5.17.5
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-react",
"version": "5.17.5",
"version": "5.18.2",
"description": "Aksel react-components for NAV designsystem",
"author": "Aksel | NAV designsystem team",
"license": "MIT",
@@ -38,8 +38,8 @@
},
"dependencies": {
"@floating-ui/react": "0.25.4",
"@navikt/aksel-icons": "^5.17.5",
"@navikt/ds-tokens": "^5.17.5",
"@navikt/aksel-icons": "^5.18.2",
"@navikt/ds-tokens": "^5.18.2",
"@radix-ui/react-tabs": "1.0.0",
"@radix-ui/react-toggle-group": "1.0.0",
"clsx": "^1.2.1",
@@ -1,6 +1,6 @@
import { StoryObj } from "@storybook/react";
import React, { useState } from "react";
import { Accordion, AccordionProps } from ".";
import { Table } from "..";
import AccordionContent from "./AccordionContent";
import AccordionHeader from "./AccordionHeader";
import AccordionItem from "./AccordionItem";
@@ -13,13 +13,15 @@ export default {
AccordionContent,
AccordionHeader,
},
parameters: {
chromatic: { disable: true },
},
decorators: [
(Story) => (
<div
style={{
width: "600px",
minHeight: "100vh",
padding: "10rem 0",
display: "flex",
flexDirection: "column",
gap: "1rem",
@@ -29,25 +31,10 @@ export default {
</div>
),
],
argTypes: {
variant: {
options: ["default", "neutral"],
control: { type: "select" },
},
headingSize: {
options: ["large", "medium", "small", "xsmall"],
control: { type: "select" },
},
size: {
options: ["large", "medium", "small"],
control: { type: "select" },
},
nItems: {
control: { type: "number" },
},
},
};
type Story = StoryObj<typeof Accordion>;
const Content = () => (
<Accordion.Content>
Magna aliquip aliquip fugiat nostrud nostrud velit pariatur veniam officia
@@ -103,22 +90,34 @@ const Item = (props) => {
);
};
export const Default = {
render: ({ nItems, ...props }) => {
export const Controls: Story = {
render: ({ ...props }) => {
return (
<div style={{ width: 500 }}>
<Accordion {...props}>
{[...Array(nItems ? nItems : 2)].map((_, y) => (
{[...Array(4)].map((_, y) => (
<Item key={y} {...props} />
))}
</Accordion>
</div>
);
},
argTypes: {
variant: {
options: ["default", "neutral"],
control: { type: "select" },
},
headingSize: {
options: ["large", "medium", "small", "xsmall"],
control: { type: "select" },
},
size: {
options: ["large", "medium", "small"],
control: { type: "select" },
},
},
args: {
controlled: false,
nItems: 2,
variant: "default",
headingSize: "medium",
size: "medium",
@@ -126,37 +125,31 @@ export const Default = {
},
};
export const DefaultOpen = {
render: ({ nItems, openItems, ...props }) => {
export const DefaultOpen: Story = {
render: () => {
return (
<div style={{ width: 500 }}>
<Accordion {...props}>
{[...Array(nItems ? nItems : 2)].map((_, y) => (
<Item key={y} defaultOpen={openItems.includes(y)} {...props} />
<Accordion>
{[...Array(4)].map((_, y) => (
<Item key={y} defaultOpen={y === 2} />
))}
</Accordion>
</div>
);
},
args: {
openItems: [1, 2],
controlled: false,
nItems: 5,
variant: "neutral",
headingSize: "large",
},
};
export const Variants = {
export const Variants: Story = {
render: () => {
return (
<div style={{ width: 500 }} className="colgap">
<h3>Default</h3>
<Accordion>
{[...Array(2)].map((_, y) => (
<Item key={y} defaultOpen />
))}
</Accordion>
<h3>Neutral</h3>
<Accordion variant="neutral">
{[...Array(2)].map((_, y) => (
<Item key={y} defaultOpen />
@@ -167,96 +160,32 @@ export const Variants = {
},
};
export const Controlled = (props) => {
const [open, setOpen] = useState(false);
const [open2, setOpen2] = useState(false);
return (
<div style={{ width: 500 }}>
<Accordion {...props}>
<Accordion.Item open={open}>
<Accordion.Header onClick={() => setOpen(!open)}>
Accordion header text
</Accordion.Header>
<Content />
</Accordion.Item>
<Accordion.Item open={open2}>
<Accordion.Header onClick={() => setOpen2(!open2)}>
Accordion header text
</Accordion.Header>
<Content />
</Accordion.Item>
</Accordion>
</div>
);
};
export const WithTable = {
render: (props) => {
const ExampleTable = () => {
return (
<Table>
<Table.Header>
<Table.Row>
<Table.HeaderCell>ID</Table.HeaderCell>
<Table.HeaderCell>Fornavn</Table.HeaderCell>
<Table.HeaderCell>Etternavn</Table.HeaderCell>
<Table.HeaderCell>Rolle</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
<Table.Row>
<Table.HeaderCell>1</Table.HeaderCell>
<Table.DataCell>Jean-Luc</Table.DataCell>
<Table.DataCell>Picard</Table.DataCell>
<Table.DataCell>Kaptein</Table.DataCell>
</Table.Row>
<Table.Row>
<Table.HeaderCell>2</Table.HeaderCell>
<Table.DataCell>William</Table.DataCell>
<Table.DataCell>Riker</Table.DataCell>
<Table.DataCell>Kommandør</Table.DataCell>
</Table.Row>
<Table.Row>
<Table.HeaderCell>3</Table.HeaderCell>
<Table.DataCell>Geordi</Table.DataCell>
<Table.DataCell>La Forge</Table.DataCell>
<Table.DataCell>Sjefsingeniør</Table.DataCell>
</Table.Row>
</Table.Body>
</Table>
);
};
const ContentWithTable = () => {
return (
<Accordion.Content>
<ExampleTable />
</Accordion.Content>
);
};
export const ControlledState: Story = {
render: () => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const [open, setOpen] = useState(false);
// eslint-disable-next-line react-hooks/rules-of-hooks
const [open2, setOpen2] = useState(false);
return (
<div style={{ width: 500 }}>
<Accordion {...props}>
<Accordion.Item>
<Accordion.Header>Table of people</Accordion.Header>
<ContentWithTable />
<Accordion>
<Accordion.Item open={open}>
<Accordion.Header onClick={() => setOpen(!open)}>
Accordion header text
</Accordion.Header>
<Content />
</Accordion.Item>
<Accordion.Item>
<Accordion.Header>Table of people</Accordion.Header>
<ContentWithTable />
<Accordion.Item open={open2}>
<Accordion.Header onClick={() => setOpen2(!open2)}>
Accordion header text
</Accordion.Header>
<Content />
</Accordion.Item>
</Accordion>
</div>
);
},
args: {
variant: "default",
headingSize: "large",
indent: false,
},
};
const SingleHeaderAccordion = ({
@@ -269,9 +198,11 @@ const SingleHeaderAccordion = ({
<Accordion.Header>{`${size} size + ${headingSize} heading`}</Accordion.Header>
<Accordion.Content>a</Accordion.Content>
</Accordion.Item>
<Accordion.Item>
<Accordion.Item open>
<Accordion.Header>{`${size} size + ${headingSize} heading`}</Accordion.Header>
<Accordion.Content>a</Accordion.Content>
<Accordion.Content>
lorem ipsum dolor sit amet, consectetur adipiscing elit.
</Accordion.Content>
</Accordion.Item>
</Accordion>
);
@@ -285,18 +216,73 @@ const headingSizes: AccordionProps["headingSize"][] = [
"xsmall",
];
export const Size = (props) => (
<div style={{ width: 500 }} className="colgap">
{sizes.map((size) => (
<SingleHeaderAccordion key={size} size={size} {...props} />
))}
</div>
);
export const Size: Story = {
render: () => (
<div style={{ width: 500 }} className="colgap">
{sizes.map((size) => (
<SingleHeaderAccordion key={size} size={size} />
))}
</div>
),
};
export const HeadingSize = (props) => (
<div style={{ width: 500 }} className="colgap">
{headingSizes.map((size) => (
<SingleHeaderAccordion key={size} headingSize={size} {...props} />
))}
</div>
);
export const HeadingSize: Story = {
render: () => (
<div style={{ width: 500 }} className="colgap">
{headingSizes.map((size) => (
<SingleHeaderAccordion key={size} headingSize={size} />
))}
</div>
),
};
export const Indent: Story = {
render: () => {
return (
<div style={{ width: 500 }} className="colgap">
<h3>No indent</h3>
<Accordion indent>
{[...Array(2)].map((_, y) => (
<Item key={y} defaultOpen />
))}
</Accordion>
<h3>Indent</h3>
<Accordion indent={false}>
{[...Array(2)].map((_, y) => (
<Item key={y} defaultOpen />
))}
</Accordion>
</div>
);
},
};
export const Chromatic: Story = {
render: (...props) => (
<div>
<div>
<h2>Variants</h2>
{Variants.render?.(...props)}
</div>
<div>
<h2>Size</h2>
{Size.render?.(...props)}
</div>
<div>
<h2>HeadingSize</h2>
{HeadingSize.render?.(...props)}
</div>
<div>
<h2>DefaultOpen</h2>
{DefaultOpen.render?.(...props)}
</div>
<div>
<h2>Indent</h2>
{Indent.render?.(...props)}
</div>
</div>
),
parameters: {
chromatic: { disable: false },
},
};
+202 -113
View File
@@ -1,12 +1,16 @@
import type { Meta, StoryObj } from "@storybook/react";
import { expect, userEvent, within } from "@storybook/test";
import React from "react";
import { Alert, AlertProps } from ".";
import { BodyLong, Heading as DsHeading, Link } from "..";
import { VStack } from "../layout/stack";
import { Link } from "../link";
import { BodyLong, Heading as DsHeading } from "../typography";
import Alert, { AlertProps } from "./Alert";
const meta: Meta<typeof Alert> = {
title: "ds-react/Alert",
component: Alert,
parameters: {
chromatic: { disable: true },
},
};
export default meta;
@@ -20,12 +24,13 @@ const variants: AlertProps["variant"][] = [
"success",
];
export const Default: Story = {
export const Controls: Story = {
render: (props) => <Alert {...props} />,
args: {
children: "Id elit esse enim reprehenderit enim nisi veniam nostrud.",
fullWidth: false,
inline: false,
variant: "info",
size: "medium",
closeButton: false,
@@ -42,43 +47,18 @@ export const Default: Story = {
},
};
export const Small: Story = {
render: (props) => {
return (
<div className="colgap">
{variants.map((variant, i) => (
<Alert
key={variant}
variant={variant}
size="small"
closeButton={props.closeButton}
>
{new Array(i + 1).fill(
"Id elit esse enim reprehenderit enim nisi veniam nostrud.",
)}
</Alert>
))}
</div>
);
},
args: {
closeButton: false,
},
};
export const FullWidth = () => {
export const Variants = () => {
return (
<div className="colgap">
{variants.map((variant, i) => (
<Alert key={variant} variant={variant} fullWidth>
<Alert key={variant} variant={variant}>
{new Array(i + 1).fill(
"Id elit esse enim reprehenderit enim nisi veniam nostrud.",
)}
</Alert>
))}
{variants.map((variant, i) => (
<Alert key={variant} variant={variant} fullWidth size="small">
<Alert key={variant} variant={variant} size="small">
{new Array(i + 1).fill(
"Id elit esse enim reprehenderit enim nisi veniam nostrud.",
)}
@@ -88,24 +68,42 @@ export const FullWidth = () => {
);
};
export const FullWidth = () => {
return (
<VStack gap="4">
<Alert variant="info" fullWidth>
Id elit esse enim reprehenderit enim nisi veniam nostrud.
</Alert>
<Alert variant="info" fullWidth size="small">
Id elit esse enim reprehenderit enim nisi veniam nostrud.
</Alert>
</VStack>
);
};
export const Inline = () => {
return (
<div className="colgap">
{variants.map((variant, i) => (
<Alert key={variant} variant={variant} inline>
{new Array(i + 1).fill(
"Id elit esse enim reprehenderit enim nisi veniam nostrud.",
)}
</Alert>
))}
{variants.map((variant, i) => (
<Alert key={variant} variant={variant} inline size="small">
{new Array(i + 1).fill(
"Id elit esse enim reprehenderit enim nisi veniam nostrud.",
)}
</Alert>
))}
</div>
<VStack gap="4">
<h2>Inline</h2>
<Alert variant="info" inline>
Id elit esse enim reprehenderit enim nisi veniam nostrud.
</Alert>
<Alert variant="info" inline>
Id elit esse enim reprehenderit enim nisi veniam nostrud. Id elit esse
enim reprehenderit enim nisi veniam nostrud. Id elit esse enim
reprehenderit enim nisi veniam nostrud. Id elit esse enim reprehenderit
enim nisi veniam nostrud.
</Alert>
<Alert variant="info" size="small" inline>
Id elit esse enim reprehenderit enim nisi veniam nostrud.
</Alert>
<Alert variant="info" size="small" inline>
Id elit esse enim reprehenderit enim nisi veniam nostrud. Id elit esse
enim reprehenderit enim nisi veniam nostrud. Id elit esse enim
reprehenderit enim nisi veniam nostrud. Id elit esse enim reprehenderit
enim nisi veniam nostrud.
</Alert>
</VStack>
);
};
@@ -136,82 +134,173 @@ export const Heading = () => {
);
};
export const Links = () => {
return (
<div className="colgap">
{variants.map((variant) => (
<Alert key={variant} variant={variant}>
<Link href="#">Id elit esse enim reprehenderit</Link>
</Alert>
))}
</div>
);
};
const AlertWithCloseButton = ({
children,
size,
}: {
size?: "medium" | "small";
children?: React.ReactNode;
}) => {
const [show, setShow] = React.useState(true);
return show ? (
<Alert
variant="warning"
size={size}
closeButton
onClose={() => setShow(false)}
>
{children || "Content"}
</Alert>
) : null;
};
export const WithCloseButton: Story = {
export const CloseButton: Story = {
render: () => {
return (
<div className="colgap">
<AlertWithCloseButton />
<AlertWithCloseButton>
<BodyLong>Ullamco ullamco laborum et commodo sint culpa</BodyLong>
</AlertWithCloseButton>
<AlertWithCloseButton>
<DsHeading spacing size="small" level="3">
Aliquip duis est in commodo pariatur
<VStack gap="4">
<h2>CloseButton</h2>
<Alert variant="info" closeButton>
Id elit esse enim reprehenderit enim nisi veniam nostrud.
</Alert>
<Alert variant="info" closeButton>
Id elit esse enim reprehenderit enim nisi veniam nostrud. Id elit esse
enim reprehenderit enim nisi veniam nostrud. Id elit esse enim
reprehenderit enim nisi veniam nostrud. Id elit esse enim
reprehenderit enim nisi veniam nostrud.
</Alert>
<Alert size="small" variant="info" closeButton>
Id elit esse enim reprehenderit enim nisi veniam nostrud.
</Alert>
<Alert size="small" variant="info" closeButton>
Id elit esse enim reprehenderit enim nisi veniam nostrud. Id elit esse
enim reprehenderit enim nisi veniam nostrud. Id elit esse enim
reprehenderit enim nisi veniam nostrud. Id elit esse enim
reprehenderit enim nisi veniam nostrud.
</Alert>
<Alert variant="info" closeButton>
<DsHeading size="small" level="3">
Id elit esse enim reprehenderit
</DsHeading>
<BodyLong>
Ullamco ullamco laborum et commodo sint culpa cupidatat culpa qui
laboris ex. Labore ex occaecat proident qui qui fugiat magna. Fugiat
sint commodo consequat eu aute.
Id elit esse enim reprehenderit enim nisi veniam nostrud.
</BodyLong>
</AlertWithCloseButton>
<AlertWithCloseButton size="small">
<BodyLong>Ullamco ullamco laborum et commodo</BodyLong>
</AlertWithCloseButton>
<AlertWithCloseButton size="small">
<DsHeading spacing size="small" level="3">
Aliquip duis est in commodo pariatur
</Alert>
<Alert variant="info" closeButton size="small">
<DsHeading size="xsmall" level="3">
Id elit esse enim reprehenderit
</DsHeading>
<BodyLong>
Ullamco ullamco laborum et commodo sint culpa cupidatat culpa qui
laboris ex. Labore ex occaecat proident qui qui fugiat magna. Fugiat
sint commodo consequat eu aute.
Id elit esse enim reprehenderit enim nisi veniam nostrud.
</BodyLong>
</AlertWithCloseButton>
</div>
</Alert>
</VStack>
);
},
play: async ({ canvasElement, step }) => {
const canvas = within(canvasElement);
const buttons = canvas.getAllByTitle("Lukk Alert");
};
await step("click button", async () => {
await userEvent.click(buttons[0]);
});
export const Chromatic: Story = {
render: () => (
<VStack gap="6">
<VStack gap="2">
<h2>Variant</h2>
{variants.map((variant, i) => (
<Alert key={variant} variant={variant}>
{new Array(i + 1).fill(
"Id elit esse enim reprehenderit enim nisi veniam nostrud.",
)}
</Alert>
))}
</VStack>
<VStack gap="2">
<h2>Small</h2>
<Alert variant="info" size="small">
Id elit esse enim reprehenderit enim nisi veniam nostrud.
</Alert>
<Alert variant="info" size="small">
Id elit esse enim reprehenderit enim nisi veniam nostrud. Id elit esse
enim reprehenderit enim nisi veniam nostrud. Id elit esse enim
reprehenderit enim nisi veniam nostrud. Id elit esse enim
reprehenderit enim nisi veniam nostrud.
</Alert>
</VStack>
<VStack gap="2">
<h2>FullWidth</h2>
<Alert variant="info" fullWidth>
Id elit esse enim reprehenderit enim nisi veniam nostrud.
</Alert>
<Alert variant="info" size="small" fullWidth>
Id elit esse enim reprehenderit enim nisi veniam nostrud.
</Alert>
</VStack>
<VStack gap="2">
<h2>Inline</h2>
<Alert variant="info" inline>
Id elit esse enim reprehenderit enim nisi veniam nostrud.
</Alert>
<Alert variant="info" inline>
Id elit esse enim reprehenderit enim nisi veniam nostrud. Id elit esse
enim reprehenderit enim nisi veniam nostrud. Id elit esse enim
reprehenderit enim nisi veniam nostrud. Id elit esse enim
reprehenderit enim nisi veniam nostrud.
</Alert>
<Alert variant="info" size="small" inline>
Id elit esse enim reprehenderit enim nisi veniam nostrud.
</Alert>
<Alert variant="info" size="small" inline>
Id elit esse enim reprehenderit enim nisi veniam nostrud. Id elit esse
enim reprehenderit enim nisi veniam nostrud. Id elit esse enim
reprehenderit enim nisi veniam nostrud. Id elit esse enim
reprehenderit enim nisi veniam nostrud.
</Alert>
</VStack>
<VStack gap="2">
<h2>Heading</h2>
<Alert variant="info">
<DsHeading size="small" level="3">
Id elit esse enim reprehenderit
</DsHeading>
<BodyLong>
Id elit esse enim reprehenderit enim nisi veniam nostrud.
</BodyLong>
</Alert>
<Alert variant="info" size="small">
<DsHeading size="xsmall" level="3">
Id elit esse enim reprehenderit
</DsHeading>
<BodyLong size="small">
Id elit esse enim reprehenderit enim nisi veniam nostrud.
</BodyLong>
</Alert>
</VStack>
<VStack gap="2">
<h2>CloseButton</h2>
<Alert variant="info" closeButton>
Id elit esse enim reprehenderit enim nisi veniam nostrud.
</Alert>
<Alert variant="info" closeButton>
Id elit esse enim reprehenderit enim nisi veniam nostrud. Id elit esse
enim reprehenderit enim nisi veniam nostrud. Id elit esse enim
reprehenderit enim nisi veniam nostrud. Id elit esse enim
reprehenderit enim nisi veniam nostrud.
</Alert>
<Alert size="small" variant="info" closeButton>
Id elit esse enim reprehenderit enim nisi veniam nostrud.
</Alert>
<Alert size="small" variant="info" closeButton>
Id elit esse enim reprehenderit enim nisi veniam nostrud. Id elit esse
enim reprehenderit enim nisi veniam nostrud. Id elit esse enim
reprehenderit enim nisi veniam nostrud. Id elit esse enim
reprehenderit enim nisi veniam nostrud.
</Alert>
<Alert variant="info" closeButton>
<DsHeading size="small" level="3">
Id elit esse enim reprehenderit
</DsHeading>
<BodyLong>
Id elit esse enim reprehenderit enim nisi veniam nostrud.
</BodyLong>
</Alert>
<Alert variant="info" size="small" closeButton>
<DsHeading size="xsmall" level="3">
Id elit esse enim reprehenderit
</DsHeading>
<BodyLong size="small">
Id elit esse enim reprehenderit enim nisi veniam nostrud.
</BodyLong>
</Alert>
</VStack>
const buttonsAfter = canvas.getAllByTitle("Lukk Alert");
expect(buttonsAfter.length).toBe(4);
<VStack gap="2">
<h2>Links</h2>
{variants.map((variant) => (
<Alert key={variant} variant={variant}>
<Link href="#">Id elit esse enim reprehenderit</Link>
</Alert>
))}
</VStack>
</VStack>
),
parameters: {
chromatic: { disable: false },
},
};
+96 -193
View File
@@ -1,15 +1,21 @@
import { StoryObj } from "@storybook/react";
import React from "react";
import { StarIcon } from "@navikt/aksel-icons";
import { StarIcon as BaseStarIcon } from "@navikt/aksel-icons";
import { HStack, VStack } from "../layout/stack";
import { Button } from "./index";
export default {
title: "ds-react/Button",
component: Button,
parameters: {
chromatic: { delay: 600 },
chromatic: { disable: true },
},
};
type Story = StoryObj<typeof Button>;
const StarIcon = () => <BaseStarIcon aria-hidden />;
const variants: (
| "primary"
| "secondary"
@@ -28,17 +34,7 @@ const variants: (
"tertiary-neutral",
];
const varSwitch = {
primary: "Primary",
secondary: "Secondary",
tertiary: "Tertiary",
danger: "Danger",
"primary-neutral": "Primary",
"secondary-neutral": "Secondary",
"tertiary-neutral": "Tertiary",
};
export const Default = {
export const Controls: Story = {
render: (props) => {
return (
<Button
@@ -57,7 +53,7 @@ export const Default = {
icon: false,
loading: false,
iconPosition: "left",
children: "Knapp",
children: "Button",
variant: "primary",
size: "medium",
},
@@ -91,192 +87,99 @@ export const Default = {
},
};
export const Small = () => (
<div className="rowgap">
{variants.map((variant) => (
<Button key={variant} variant={variant} size="small">
{varSwitch[variant]}
</Button>
))}
</div>
);
export const XSmall = () => (
<div className="rowgap">
{variants.map((variant) => (
<Button key={variant} variant={variant} size="xsmall">
{varSwitch[variant]}
</Button>
))}
</div>
);
export const Link = () => (
<div className="rowgap">
{variants.map((variant) => (
<Button key={variant} variant={variant} as="a" href="#thecakeisalie">
{varSwitch[variant]}
</Button>
))}
</div>
);
export const Loading = {
render: () => (
<div className="colgap chromatic-ignore">
<div className="rowgap">
{variants.map((variant) => (
<Button key={variant} variant={variant} loading>
{varSwitch[variant]}
function ButtonGrid(props: any) {
return (
<VStack gap="2">
{variants.map((variant) => (
<HStack gap="2" key={variant}>
<Button variant={variant} {...props}>
Button
</Button>
))}
</div>
<div className="rowgap">
{variants.map((variant) => (
<Button key={variant} variant={variant} loading size="small">
{varSwitch[variant]}
<Button variant={variant} {...props} icon={<StarIcon />}>
Button
</Button>
))}
</div>
<div className="rowgap">
{variants.map((variant) => (
<Button key={variant} variant={variant} loading size="xsmall">
{varSwitch[variant]}
</Button>
))}
</div>
</div>
),
parameters: {
chromatic: { disableSnapshot: true },
},
};
export const Icon = () => (
<div className="colgap ">
<div className="rowgap">
{variants.map((variant) => (
<Button
key={variant}
variant={variant}
icon={<StarIcon title="Stjerne" />}
/>
))}
</div>
<div className="rowgap">
{variants.map((variant) => (
<Button
key={variant}
variant={variant}
size="small"
icon={<StarIcon title="Stjerne" />}
/>
))}
</div>
<div className="rowgap">
{variants.map((variant) => (
<Button
key={variant}
variant={variant}
size="xsmall"
icon={<StarIcon title="Stjerne" />}
/>
))}
</div>
</div>
);
export const IconWText = () => (
<div className="colgap">
<div className="rowgap">
{variants.map((variant, i) => (
<Button
key={variant}
variant={variant}
icon={<StarIcon title="Stjerne" />}
iconPosition={i % 2 ? "left" : "right"}
>
{varSwitch[variant]}
</Button>
))}
</div>
<div className="rowgap">
{variants.map((variant, i) => (
<Button
key={variant}
variant={variant}
size="small"
icon={<StarIcon title="Stjerne" />}
iconPosition={i % 2 ? "left" : "right"}
>
{varSwitch[variant]}
</Button>
))}
</div>
<div className="rowgap">
{variants.map((variant, i) => (
<Button
key={variant}
variant={variant}
size="xsmall"
icon={<StarIcon title="Stjerne" />}
iconPosition={i % 2 ? "left" : "right"}
>
{varSwitch[variant]}
</Button>
))}
</div>
</div>
);
export const Disabled = () => (
<div className="colgap">
<div className="rowgap">
{variants.map((variant) => (
<Button key={variant} variant={variant} disabled>
{varSwitch[variant]}
</Button>
))}
</div>
<div className="rowgap">
{variants.map((variant) => (
<Button key={variant} variant={variant} disabled as="a" href="#">
{varSwitch[variant]}
</Button>
))}
</div>
</div>
);
export const LoadingWithAs = {
render: () => (
<div className="colgap chromatic-ignore">
<div className="rowgap">
{variants.map((variant) => (
<Button key={variant} variant={variant} loading size="small">
{varSwitch[variant]}
</Button>
))}
</div>
<div className="rowgap">
{variants.map((variant) => (
<Button
key={variant}
variant={variant}
loading
size="small"
as="a"
href="#"
{...props}
icon={<StarIcon />}
iconPosition="right"
>
{varSwitch[variant]}
Button
</Button>
))}
</div>
</div>
),
<Button variant={variant} {...props} icon={<StarIcon />} />
</HStack>
))}
</VStack>
);
}
export const Medium: Story = {
render: () => <ButtonGrid size="medium" />,
};
export const Small: Story = {
render: () => <ButtonGrid size="small" />,
};
export const XSmall: Story = {
render: () => <ButtonGrid size="xsmall" />,
};
export const AsLink: Story = {
render: () => (
<VStack gap="4">
<Button href="#" as="a">
Button as a-tag
</Button>
<Button href="#" as="a" disabled>
Disabled Button as a-tag
</Button>
</VStack>
),
};
export const Loading: Story = {
render: () => <ButtonGrid loading />,
};
export const LoadingAsLink: Story = {
render: () => <ButtonGrid loading href="#" as="a" />,
};
export const Disabled: Story = {
render: () => <ButtonGrid disabled />,
};
export const DisabledAsLink: Story = {
render: () => <ButtonGrid disabled href="#" as="a" />,
};
export const Chromatic: Story = {
render: () => (
<VStack gap="6" align="center">
<div>
<h2>Medium</h2>
<ButtonGrid size="medium" />
</div>
<div>
<h2>Small</h2>
<ButtonGrid size="small" />
</div>
<div>
<h2>XSmall</h2>
<ButtonGrid size="xsmall" />
</div>
<div>
<h2>As Link</h2>
<ButtonGrid as="a" href="#" />
</div>
<div>
<h2>Disabled</h2>
<ButtonGrid disabled />
</div>
</VStack>
),
parameters: {
chromatic: { disableSnapshot: true },
chromatic: { disable: false },
},
};
+284 -206
View File
@@ -1,6 +1,6 @@
import { Meta } from "@storybook/react";
import { Meta, StoryObj } from "@storybook/react";
import React from "react";
import { Chat } from "../index";
import { Chat, VStack } from "../index";
import { POSITIONS, SIZES } from "./Chat";
export default {
@@ -30,9 +30,14 @@ export default {
options: SIZES,
},
},
parameters: {
chromatic: { disable: true },
},
} satisfies Meta<typeof Chat>;
export const Default = {
type Story = StoryObj<typeof Chat>;
export const Controls: Story = {
render: (props) => {
return (
<Chat {...props}>
@@ -55,219 +60,292 @@ export const Default = {
},
};
export const Small = () => (
<Chat avatar="ON" name="Ola Normann" timestamp="01.01.21 14:00" size="small">
<Chat.Bubble>
Aute minim nisi sunt mollit duis sunt nulla minim non proident.
</Chat.Bubble>
<Chat.Bubble>Tempor fugiat amet eu sint in in ullamco.</Chat.Bubble>
<Chat.Bubble>
Adipisicing laborum est eu laborum est sit in commodo enim sint laboris
labore nisi ut.
</Chat.Bubble>
</Chat>
);
export const Size: Story = {
render: () => (
<VStack gap="4">
<h3>Medium</h3>
<Chat
avatar="ON"
name="Ola Normann"
timestamp="01.01.21 14:00"
size="medium"
>
<Chat.Bubble>
Aute minim nisi sunt mollit duis sunt nulla minim non proident.
</Chat.Bubble>
<Chat.Bubble>Tempor fugiat amet eu sint in in ullamco.</Chat.Bubble>
<Chat.Bubble>
Adipisicing laborum est eu laborum est sit in commodo enim sint
laboris labore nisi ut.
</Chat.Bubble>
</Chat>
<h3>Small</h3>
<Chat
avatar="ON"
name="Ola Normann"
timestamp="01.01.21 14:00"
size="small"
>
<Chat.Bubble>
Aute minim nisi sunt mollit duis sunt nulla minim non proident.
</Chat.Bubble>
<Chat.Bubble>Tempor fugiat amet eu sint in in ullamco.</Chat.Bubble>
<Chat.Bubble>
Adipisicing laborum est eu laborum est sit in commodo enim sint
laboris labore nisi ut.
</Chat.Bubble>
</Chat>
</VStack>
),
};
export const Colors = () => (
<Chat
avatar="NAV"
name="NAV"
timestamp="01.01.21 14:00"
avatarBgColor="var(--a-surface-alt-1-subtle)"
backgroundColor="var(--a-surface-warning-subtle)"
>
<Chat.Bubble>
Aute minim nisi sunt mollit duis sunt nulla minim non proident.
</Chat.Bubble>
<Chat.Bubble backgroundColor="lightYellow">
Tempor fugiat amet eu sint in in ullamco.
</Chat.Bubble>
<Chat.Bubble>
Adipisicing laborum est eu laborum est sit in commodo enim sint laboris
labore nisi ut.
</Chat.Bubble>
</Chat>
);
export const Variants: Story = {
render: () => (
<VStack gap="4">
<h3>Info</h3>
<Chat avatar="NAV" name="NAV" timestamp="01.01.21 14:00" variant="info">
<Chat.Bubble>
Aute minim nisi sunt mollit duis sunt nulla minim non proident.
</Chat.Bubble>
</Chat>
<h3>Neutral</h3>
<Chat
avatar="KN"
name="Kari Nordmann"
timestamp="01.01.21 14:03"
variant="neutral"
position="right"
>
<Chat.Bubble>Tempor fugiat amet eu sint in in ullamco.</Chat.Bubble>
</Chat>
<h3>Subtle</h3>
<Chat
avatar="ON"
name="Ola Nordmann"
timestamp="01.01.21 14:07"
variant="subtle"
position="right"
>
<Chat.Bubble>
Adipisicing laborum est eu laborum est sit in commodo enim sint
laboris labore nisi ut.
</Chat.Bubble>
</Chat>
</VStack>
),
};
export const Variants = () => (
<div className="colgap">
<Chat avatar="NAV" name="NAV" timestamp="01.01.21 14:00" variant="info">
export const Position: Story = {
render: () => (
<VStack gap="4">
<h3>Default</h3>
<Chat avatar="ON" name="Ola Normann" timestamp="01.01.21 14:00">
<Chat.Bubble>
Adipisicing laborum est eu laborum est sit in commodo enim sint
laboris labore nisi ut.
</Chat.Bubble>
</Chat>
<h3>Right</h3>
<Chat
avatar="KH"
name="Kari Høyli"
timestamp="01.01.21 14:32"
position="right"
variant="info"
>
<Chat.Bubble>
Reprehenderit pariatur officia exercitation laboris.
</Chat.Bubble>
<Chat.Bubble>
Enim velit deserunt do quis. Eu fugiat magna esse dolore ad sunt sit
est dolore incididunt. Occaecat cupidatat magna.
</Chat.Bubble>
</Chat>
<h3>Left</h3>
<Chat
position="left"
avatar="ON"
name="Ola Normann"
timestamp="01.01.21 15:00"
>
<Chat.Bubble>
Exercitation irure Lorem cupidatat culpa anim cillum esse ullamco qui
dolore laborum et Lorem. Labore sunt duis id Lorem voluptate commodo
ea esse. Dolore esse aliqua proident ea ad commodo ut dolore voluptate
labore sunt aute.
</Chat.Bubble>
</Chat>
</VStack>
),
};
export const ToptextPosition: Story = {
render: () => (
<VStack gap="4">
<h3>Right</h3>
<Chat
avatar="ON"
name="Ola Normann"
timestamp="01.01.21 14:00"
toptextPosition="right"
>
<Chat.Bubble>
Adipisicing laborum est eu laborum est sit in commodo enim sint
laboris labore nisi ut.
</Chat.Bubble>
</Chat>
<h3>Left</h3>
<Chat avatar="ON" name="Ola Normann" timestamp="01.01.21 15:00">
<Chat.Bubble toptextPosition="left">
Exercitation irure Lorem cupidatat culpa anim cillum esse ullamco qui
dolore laborum et Lorem. Labore sunt duis id Lorem voluptate commodo
ea esse. Dolore esse aliqua proident ea ad commodo ut dolore voluptate
labore sunt aute.
</Chat.Bubble>
</Chat>
<h3>Left</h3>
<Chat
name="Kari Høyli"
timestamp="01.01.21 14:32"
position="right"
toptextPosition="left"
>
<Chat.Bubble>
Reprehenderit pariatur officia exercitation laboris.
</Chat.Bubble>
<Chat.Bubble>
Enim velit deserunt do quis. Eu fugiat magna esse dolore ad sunt sit
est dolore incididunt. Occaecat cupidatat magna.
</Chat.Bubble>
</Chat>
<h3>Right</h3>
<Chat
name="Kari Høyli"
timestamp="01.01.21 14:32"
position="right"
toptextPosition="right"
>
<Chat.Bubble>
Reprehenderit pariatur officia exercitation laboris.
</Chat.Bubble>
<Chat.Bubble>
Enim velit deserunt do quis. Eu fugiat magna esse dolore ad sunt sit
est dolore incididunt. Occaecat cupidatat magna.
</Chat.Bubble>
</Chat>
</VStack>
),
};
export const Avatar: Story = {
render: () => (
<Chat avatar={<Illustration />}>
<Chat.Bubble>
Aute minim nisi sunt mollit duis sunt nulla minim non proident.
</Chat.Bubble>
</Chat>
<Chat
avatar="KN"
name="Kari Nordmann"
timestamp="01.01.21 14:03"
variant="neutral"
position="right"
>
<Chat.Bubble>Tempor fugiat amet eu sint in in ullamco.</Chat.Bubble>
</Chat>
<Chat
avatar="ON"
name="Ola Nordmann"
timestamp="01.01.21 14:07"
variant="subtle"
position="right"
>
<Chat.Bubble>
Adipisicing laborum est eu laborum est sit in commodo enim sint laboris
labore nisi ut.
</Chat.Bubble>
</Chat>
</div>
);
),
};
export const Position = () => (
<div className="colgap">
<Chat avatar="ON" name="Ola Normann" timestamp="01.01.21 14:00">
<Chat.Bubble>
Adipisicing laborum est eu laborum est sit in commodo enim sint laboris
labore nisi ut.
</Chat.Bubble>
</Chat>
<Chat
avatar="KH"
name="Kari Høyli"
timestamp="01.01.21 14:32"
position="right"
variant="info"
>
<Chat.Bubble>
Reprehenderit pariatur officia exercitation laboris.
</Chat.Bubble>
<Chat.Bubble>
Enim velit deserunt do quis. Eu fugiat magna esse dolore ad sunt sit est
dolore incididunt. Occaecat cupidatat magna.
</Chat.Bubble>
</Chat>
<Chat avatar="ON" name="Ola Normann" timestamp="01.01.21 15:00">
<Chat.Bubble>
Exercitation irure Lorem cupidatat culpa anim cillum esse ullamco qui
dolore laborum et Lorem. Labore sunt duis id Lorem voluptate commodo ea
esse. Dolore esse aliqua proident ea ad commodo ut dolore voluptate
labore sunt aute.
</Chat.Bubble>
</Chat>
</div>
);
function Illustration() {
return (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 54 93">
<path
fill="#e7e5e2"
d="M14 50.7C15 52.3 17.9 81 26.5 81S39 51.8 39 50.3c-13.2-7.6-25 .4-25 .4z"
/>
<path
fill="#5c4378"
d="M38.7 50.2c6 2.9 15.3 10.9 15.3 18.3V93H0V68.5c0-7.1 8.5-14.8 14.5-18-.3.2-.5.3-.5.3 1 1.7 3.8 9.2 12.4 9.2C35 60 39 51.9 39 50.4c-.1-.1-.2-.2-.3-.2z"
/>
<path
fill="#d2242a"
d="M46.7 76H31.2c-.7 0-1.3-.6-1.2-1.3v-8.5c0-.7.6-1.3 1.3-1.3h15.5c.7 0 1.3.6 1.3 1.3v8.5c-.1.7-.7 1.3-1.4 1.3"
/>
<path
fill="#fff"
d="M42.9 71c0 2.1-1.7 3.8-3.8 3.8-2.1 0-3.8-1.7-3.8-3.8s1.7-3.8 3.8-3.8c2.1 0 3.8 1.7 3.8 3.8m-8.7 1.7h-.7l.8-1.9h.7l-.8 1.9zm9.3 0H43l.8-1.9h.5l-.8 1.9zm1.2 0h-.2l.8-1.9h.2l-.8 1.9z"
/>
<path
fill="#c52d35"
d="M36.2 72.7h.6s.1 0 .1-.1v-1.8s0-.1-.1-.1h-.6s-.1 0-.1.1l-.2.6v.1h.2l.1 1.2c0-.1 0 0 0 0"
/>
<path
fill="#c52d35"
d="M37.5 72.7h.6s.1 0 .1-.1v-1.8s0-.1-.1-.1h-.9s-.1 0-.1.1l-.2.6-.1.1h.5c.1 0 .2.1.2.2v1c-.1-.1-.1 0 0 0m2.6-1.9h-.6s-.1 0-.1.1v1.8s0 .1.1.1h.6s.1 0 .1-.1l.2-.6V72h-.2l-.1-1.2"
/>
<path
fill="#c52d35"
d="M37.7 72.7h.4s.1 0 .1-.1l.2-.6v-.1h-.2c0 .1-.5.8-.5.8zm3.9-1.9h.7s.1 0 0 .1l-.7 1.8H41l.6-1.9"
/>
<path
fill="#c52d35"
d="M40.8 70.8h-1c-.1 0 .3.1.3.1l.7 1.7s0 .1.1.1h.6l-.7-1.9m-1.3.6v.4s-.1-.4-.3-.4c-.3 0-.3.2-.3.3 0 .1.1.3.2.3h.5l-.3.7H39c-.2 0-.9-.3-.9-.9 0-.6.5-1 .9-1 .2-.1.5.2.5.6 0-.1 0-.1 0 0z"
/>
<path
fill="#5a1f57"
d="M39.9 66.7h-1.6c-.1 0-.2-.1-.2-.2v-.3c0-.1.1-.2.2-.2h1.6c.1 0 .2.1.2.2v.3c0 .2-.1.2-.2.2"
/>
<path fill="#c2b5cf" d="M38.7 66.5h.9V64h-.9v2.5z" />
<path
fill="#e7e5e2"
d="M47.2 35.3C44.7 45.6 36.6 53.1 27 53.1S9.3 45.6 6.8 35.3c-.2.1-.5.1-.8.1-1.1 0-2-.8-2-1.7v-7c0-1 .9-1.7 2-1.7h.2C7.7 13.1 16.4 4 27 4c10.6 0 19.3 9.1 20.8 21h.2c1.1 0 2 .8 2 1.7v7c0 1-.9 1.7-2 1.7-.3 0-.5 0-.8-.1z"
/>
<path
fill="#635e59"
d="M19 27.6c-1.4.1-1.9-2-1.4-3.4.1-.3.6-1.5 1.4-1.5.8 0 1.2.7 1.3.8.6 1.4.3 4-1.3 4.1m16.2 0c1.4.1 1.9-2 1.4-3.4-.1-.3-.6-1.5-1.4-1.5-.8 0-1.2.7-1.3.8-.6 1.4-.3 4 1.3 4.1"
/>
<path
fill="#d1bfa3"
d="M26.8 34.6c-.4 0-.7-.1-1-.2-.3-.1-.4-.4-.3-.7.1-.3.4-.4.7-.3.5.2 1.5.1 2.2-.4.7-.4 1.1-1 1.2-1.5.1-.4-.1-.9-.4-1.3-.2-.2-.8-.2-1.6-.1-.3 0-.5-.1-.6-.4 0-.3.1-.5.4-.6 1.2-.2 2.1 0 2.6.6.5.7.8 1.4.6 2.1-.1.8-.7 1.6-1.7 2.2-.6.3-1.4.6-2.1.6z"
/>
<path
fill="#593a32"
d="M27.1 42.1h-.3c-5.3-.2-7.3-4.1-7.4-4.3-.1-.3 0-.6.2-.7.2-.1.6 0 .7.2.1.1 1.9 3.6 6.6 3.8 4.7.2 6.4-3.7 6.4-3.7.1-.3.4-.4.7-.3.3.1.4.4.3.7-.1 0-2.1 4.3-7.2 4.3z"
/>
<path
fill="#f6b873"
d="M6.6 30.7c.1-.1.1-.2.1-.3v-2c-.1-5.6 1.8-8.1 3.4-10.1 0 0-1 4.3-.3 3.4 3.8-5 21.4-1.6 25-8.1.5 3.6-4.1 4.6-4.1 4.6 3.7.7 6.9-.8 7.7-2.5.3 1.4-.6 2.4-1.9 3.4 4.5-.9 4.6-4 4.6-4 .6 4.1 5.3 2.5 5.3 9.3v6c0 .3.2.6.5.6h.5c.3 0 .5-.3.5-.6V26c.3-15.6-8.5-26-20.6-26C15.9 0 5 10.4 5 24.1v6.3c0 .4.2.6.5.6h.6c.2 0 .3-.1.5-.3"
/>
<path
fill="#f6b873"
d="M25.9 43.4c-4.4 0-8-1.4-8-3.2s3.6-3.2 8-3.2 8 1.4 8 3.2c0 1.8-3.6 3.2-8 3.2m.8-9.4c-2.9 0-4.7.7-8.8 2.1-12.7 4.6-11.6-14-11.6-14C3.4 46 18.6 52 26.5 52c8.1 0 24.1-8.1 21-30 0 0 .4 17.1-12.9 13.8-3.7-.9-5-1.8-7.9-1.8z"
/>
</svg>
);
}
export const ToptextPosition = () => (
<div className="colgap">
<Chat
avatar="ON"
name="Ola Normann"
timestamp="01.01.21 14:00"
toptextPosition="right"
>
<Chat.Bubble>
Adipisicing laborum est eu laborum est sit in commodo enim sint laboris
labore nisi ut.
</Chat.Bubble>
</Chat>
<Chat
name="Kari Høyli"
timestamp="01.01.21 14:32"
position="right"
variant="info"
toptextPosition="left"
>
<Chat.Bubble>
Reprehenderit pariatur officia exercitation laboris.
</Chat.Bubble>
<Chat.Bubble>
Enim velit deserunt do quis. Eu fugiat magna esse dolore ad sunt sit est
dolore incididunt. Occaecat cupidatat magna.
</Chat.Bubble>
</Chat>
<Chat avatar="ON" name="Ola Normann" timestamp="01.01.21 15:00">
<Chat.Bubble toptextPosition="right">
Exercitation irure Lorem cupidatat culpa anim cillum esse ullamco qui
dolore laborum et Lorem. Labore sunt duis id Lorem voluptate commodo ea
esse. Dolore esse aliqua proident ea ad commodo ut dolore voluptate
labore sunt aute.
</Chat.Bubble>
</Chat>
</div>
);
export const Avatar = () => (
<Chat avatar={<Illustration />} timestamp="01.01.21 14:00">
<Chat.Bubble>
Aute minim nisi sunt mollit duis sunt nulla minim non proident.
</Chat.Bubble>
<Chat.Bubble>Tempor fugiat amet eu sint in in ullamco.</Chat.Bubble>
<Chat.Bubble>
Adipisicing laborum est eu laborum est sit in commodo enim sint laboris
labore nisi ut.
</Chat.Bubble>
</Chat>
);
const Illustration = () => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 54 93">
<path
fill="#e7e5e2"
d="M14 50.7C15 52.3 17.9 81 26.5 81S39 51.8 39 50.3c-13.2-7.6-25 .4-25 .4z"
/>
<path
fill="#5c4378"
d="M38.7 50.2c6 2.9 15.3 10.9 15.3 18.3V93H0V68.5c0-7.1 8.5-14.8 14.5-18-.3.2-.5.3-.5.3 1 1.7 3.8 9.2 12.4 9.2C35 60 39 51.9 39 50.4c-.1-.1-.2-.2-.3-.2z"
/>
<path
fill="#d2242a"
d="M46.7 76H31.2c-.7 0-1.3-.6-1.2-1.3v-8.5c0-.7.6-1.3 1.3-1.3h15.5c.7 0 1.3.6 1.3 1.3v8.5c-.1.7-.7 1.3-1.4 1.3"
/>
<path
fill="#fff"
d="M42.9 71c0 2.1-1.7 3.8-3.8 3.8-2.1 0-3.8-1.7-3.8-3.8s1.7-3.8 3.8-3.8c2.1 0 3.8 1.7 3.8 3.8m-8.7 1.7h-.7l.8-1.9h.7l-.8 1.9zm9.3 0H43l.8-1.9h.5l-.8 1.9zm1.2 0h-.2l.8-1.9h.2l-.8 1.9z"
/>
<path
fill="#c52d35"
d="M36.2 72.7h.6s.1 0 .1-.1v-1.8s0-.1-.1-.1h-.6s-.1 0-.1.1l-.2.6v.1h.2l.1 1.2c0-.1 0 0 0 0"
/>
<path
fill="#c52d35"
d="M37.5 72.7h.6s.1 0 .1-.1v-1.8s0-.1-.1-.1h-.9s-.1 0-.1.1l-.2.6-.1.1h.5c.1 0 .2.1.2.2v1c-.1-.1-.1 0 0 0m2.6-1.9h-.6s-.1 0-.1.1v1.8s0 .1.1.1h.6s.1 0 .1-.1l.2-.6V72h-.2l-.1-1.2"
/>
<path
fill="#c52d35"
d="M37.7 72.7h.4s.1 0 .1-.1l.2-.6v-.1h-.2c0 .1-.5.8-.5.8zm3.9-1.9h.7s.1 0 0 .1l-.7 1.8H41l.6-1.9"
/>
<path
fill="#c52d35"
d="M40.8 70.8h-1c-.1 0 .3.1.3.1l.7 1.7s0 .1.1.1h.6l-.7-1.9m-1.3.6v.4s-.1-.4-.3-.4c-.3 0-.3.2-.3.3 0 .1.1.3.2.3h.5l-.3.7H39c-.2 0-.9-.3-.9-.9 0-.6.5-1 .9-1 .2-.1.5.2.5.6 0-.1 0-.1 0 0z"
/>
<path
fill="#5a1f57"
d="M39.9 66.7h-1.6c-.1 0-.2-.1-.2-.2v-.3c0-.1.1-.2.2-.2h1.6c.1 0 .2.1.2.2v.3c0 .2-.1.2-.2.2"
/>
<path fill="#c2b5cf" d="M38.7 66.5h.9V64h-.9v2.5z" />
<path
fill="#e7e5e2"
d="M47.2 35.3C44.7 45.6 36.6 53.1 27 53.1S9.3 45.6 6.8 35.3c-.2.1-.5.1-.8.1-1.1 0-2-.8-2-1.7v-7c0-1 .9-1.7 2-1.7h.2C7.7 13.1 16.4 4 27 4c10.6 0 19.3 9.1 20.8 21h.2c1.1 0 2 .8 2 1.7v7c0 1-.9 1.7-2 1.7-.3 0-.5 0-.8-.1z"
/>
<path
fill="#635e59"
d="M19 27.6c-1.4.1-1.9-2-1.4-3.4.1-.3.6-1.5 1.4-1.5.8 0 1.2.7 1.3.8.6 1.4.3 4-1.3 4.1m16.2 0c1.4.1 1.9-2 1.4-3.4-.1-.3-.6-1.5-1.4-1.5-.8 0-1.2.7-1.3.8-.6 1.4-.3 4 1.3 4.1"
/>
<path
fill="#d1bfa3"
d="M26.8 34.6c-.4 0-.7-.1-1-.2-.3-.1-.4-.4-.3-.7.1-.3.4-.4.7-.3.5.2 1.5.1 2.2-.4.7-.4 1.1-1 1.2-1.5.1-.4-.1-.9-.4-1.3-.2-.2-.8-.2-1.6-.1-.3 0-.5-.1-.6-.4 0-.3.1-.5.4-.6 1.2-.2 2.1 0 2.6.6.5.7.8 1.4.6 2.1-.1.8-.7 1.6-1.7 2.2-.6.3-1.4.6-2.1.6z"
/>
<path
fill="#593a32"
d="M27.1 42.1h-.3c-5.3-.2-7.3-4.1-7.4-4.3-.1-.3 0-.6.2-.7.2-.1.6 0 .7.2.1.1 1.9 3.6 6.6 3.8 4.7.2 6.4-3.7 6.4-3.7.1-.3.4-.4.7-.3.3.1.4.4.3.7-.1 0-2.1 4.3-7.2 4.3z"
/>
<path
fill="#f6b873"
d="M6.6 30.7c.1-.1.1-.2.1-.3v-2c-.1-5.6 1.8-8.1 3.4-10.1 0 0-1 4.3-.3 3.4 3.8-5 21.4-1.6 25-8.1.5 3.6-4.1 4.6-4.1 4.6 3.7.7 6.9-.8 7.7-2.5.3 1.4-.6 2.4-1.9 3.4 4.5-.9 4.6-4 4.6-4 .6 4.1 5.3 2.5 5.3 9.3v6c0 .3.2.6.5.6h.5c.3 0 .5-.3.5-.6V26c.3-15.6-8.5-26-20.6-26C15.9 0 5 10.4 5 24.1v6.3c0 .4.2.6.5.6h.6c.2 0 .3-.1.5-.3"
/>
<path
fill="#f6b873"
d="M25.9 43.4c-4.4 0-8-1.4-8-3.2s3.6-3.2 8-3.2 8 1.4 8 3.2c0 1.8-3.6 3.2-8 3.2m.8-9.4c-2.9 0-4.7.7-8.8 2.1-12.7 4.6-11.6-14-11.6-14C3.4 46 18.6 52 26.5 52c8.1 0 24.1-8.1 21-30 0 0 .4 17.1-12.9 13.8-3.7-.9-5-1.8-7.9-1.8z"
/>
</svg>
);
export const Chromatic: Story = {
render: (...props) => (
<div>
<div>
<h2>Size</h2>
{Size.render?.(...props)}
</div>
<div>
<h2>Variants</h2>
{Variants.render?.(...props)}
</div>
<div>
<h2>Position</h2>
{Position.render?.(...props)}
</div>
<div>
<h2>Toptext</h2>
{ToptextPosition.render?.(...props)}
</div>
<div>
<h2>Avatar</h2>
{Avatar.render?.(...props)}
</div>
</div>
),
parameters: {
chromatic: { disable: false },
},
};
@@ -2,8 +2,12 @@
import { Meta, StoryObj } from "@storybook/react";
import isSameDay from "date-fns/isSameDay";
import React, { useId, useState } from "react";
import { useDatepicker, useRangeDatepicker } from "..";
import { BodyLong, Button, HGrid, Modal, VStack } from "../..";
import { Button } from "../../button";
import { HGrid } from "../../layout/grid";
import { VStack } from "../../layout/stack";
import Modal from "../../modal/Modal";
import { BodyLong } from "../../typography";
import { useDatepicker, useRangeDatepicker } from "../hooks";
import DatePicker, { DatePickerProps } from "./DatePicker";
const disabledDays = [
@@ -53,7 +53,7 @@ export interface UseDatepickerOptions
* Allows input of with 'yy' year format.
* @default true
* @Note Decision between 20th and 21st century is based on before(todays year - 80) ? 21st : 20th.
* In 2023 this equals to 1943 - 2042
* In 2024 this equals to 1944 - 2043
*/
allowTwoDigitYear?: boolean;
/**
@@ -39,7 +39,7 @@ export interface UseMonthPickerOptions
* Allows input of with 'yy' year format.
* @default true
* @Note Decision between 20th and 21st century is based on before(todays year - 80) ? 21st : 20th.
* In 2023 this equals to 1943 - 2042
* In 2024 this equals to 1944 - 2043
*/
allowTwoDigitYear?: boolean;
/**
@@ -1,8 +1,9 @@
import { Meta, StoryFn } from "@storybook/react";
import setYear from "date-fns/setYear";
import React, { useId, useState } from "react";
import { Button, DateInputProps } from "../..";
import { Button } from "../../button";
import { useMonthpicker } from "../hooks";
import { DateInputProps } from "../parts/DateInput";
import MonthPicker from "./MonthPicker";
import { MonthPickerProps } from "./types";
@@ -15,7 +15,7 @@ export interface DateInputProps
*/
label: React.ReactNode;
/**
* Shows label and description for screenreaders-only
* Shows label and description for screen readers only
* @default false
*/
hideLabel?: boolean;
@@ -1,8 +1,8 @@
import cl from "clsx";
import React, { useContext, useRef } from "react";
import React, { useRef } from "react";
import { Button } from "../../button";
import { Modal } from "../../modal";
import { ModalContext } from "../../modal/ModalContext";
import { useModalContext } from "../../modal/Modal.context";
import { Popover } from "../../popover";
import { useMedia } from "../../util/hooks";
import { modalCloseButtonLabel, modalLabel } from "../utils/labels";
@@ -30,7 +30,7 @@ export const DateWrapper = ({
popoverProps,
}: DateWrapperProps) => {
const modalRef = useRef<HTMLDialogElement>(null);
const isInModal = useContext(ModalContext) !== null;
const isInModal = useModalContext(false) !== undefined;
const hideModal =
useMedia("screen and (min-width: 768px)", true) && !isInModal;
@@ -1,7 +1,7 @@
import { Meta } from "@storybook/react";
import React, { useState } from "react";
import { Dropdown } from "..";
import { Button } from "../button";
import Dropdown from "./Dropdown";
export default {
title: "ds-react/Dropdown",
@@ -1,6 +1,6 @@
import { Meta } from "@storybook/react";
import React from "react";
import { ErrorSummary } from "..";
import { ErrorSummary } from "./ErrorSummary";
export default {
title: "ds-react/Errorsummary",
@@ -66,10 +66,10 @@ export interface SearchProps
* Exposes the HTML size attribute
*/
htmlSize?: number | string;
/*
/*
* Exposes role attribute
*/
role?: string
role?: string;
}
interface SearchComponent
@@ -210,7 +210,7 @@ export const Search = forwardRef<HTMLInputElement, SearchProps>(
value={value ?? internalValue}
onChange={(e) => handleChange(e.target.value)}
type="search"
role={role ?? 'searchbox'}
role={role ?? "searchbox"}
className={cl(
className,
"navds-search__input",
@@ -1,6 +1,6 @@
import { Meta } from "@storybook/react";
import React, { useState } from "react";
import { Link } from "../..";
import { Link } from "../../link";
import { ConfirmationPanel } from "../index";
export default {
@@ -1,6 +1,7 @@
import { Meta, StoryFn, StoryObj } from "@storybook/react";
import React, { useEffect, useRef } from "react";
import { BodyLong, Heading, HelpText } from "..";
import { BodyLong, Heading } from "../typography";
import HelpText from "./HelpText";
const meta: Meta<typeof HelpText> = {
title: "ds-react/HelpText",
+1
View File
@@ -10,6 +10,7 @@ export * from "./expansion-card";
export * from "./form";
export * from "./grid";
export * from "./guide-panel";
export * from "./overlays";
export * from "./help-text";
export * from "./internal-header";
export * from "./link";
@@ -6,7 +6,8 @@ import {
MenuGridIcon,
} from "@navikt/aksel-icons";
import { BodyLong, BodyShort, Detail } from "@navikt/ds-react";
import { Dropdown, InternalHeader } from "..";
import { Dropdown } from "../dropdown";
import InternalHeader from "./InternalHeader";
export default {
title: "ds-react/InternalHeader",
@@ -1,7 +1,8 @@
import type { Meta } from "@storybook/react";
import React from "react";
import { Box, HStack, VStack } from "../..";
import { BodyLong } from "../../typography";
import { Box } from "../box";
import { HStack, VStack } from "../stack";
import { Bleed } from "./Bleed";
export default {
@@ -1,8 +1,9 @@
import type { Meta } from "@storybook/react";
import React, { ReactNode } from "react";
import { ChevronRightIcon } from "@navikt/aksel-icons";
import { HGrid, HStack, VStack } from "../..";
import { BodyLong, Detail, Heading } from "../../typography";
import { HGrid } from "../grid";
import { HStack, VStack } from "../stack";
import { BackgroundToken, BorderRadiiToken } from "../utilities/types";
import { Box } from "./Box";
@@ -1,6 +1,9 @@
import type { Meta, StoryObj } from "@storybook/react";
import React from "react";
import { Box, HGrid, Hide, Show, VStack } from "../..";
import { Box } from "../box";
import { HGrid } from "../grid";
import { Hide, Show } from "../responsive";
import { VStack } from "../stack";
import { Content } from "./Content";
import { FilterCard } from "./Filter";
import { Header } from "./Header";
@@ -13,6 +16,7 @@ const meta = {
title: "kitchen sink/navno-sidemal",
parameters: {
layout: "fullscreen",
chromatic: { disable: true },
},
} satisfies Meta;
@@ -1,6 +1,6 @@
import { Meta } from "@storybook/react";
import React from "react";
import { LinkPanel } from "..";
import LinkPanel from "./LinkPanel";
export default {
title: "ds-react/LinkPanel",
@@ -1,11 +1,9 @@
import React from "react";
import { PlusCircleFillIcon } from "@navikt/aksel-icons";
import {
BodyLong,
Alert as DsAlert,
ConfirmationPanel as DsConfirmationPanel,
Link,
} from "../..";
import { Alert } from "../../alert";
import { ConfirmationPanel } from "../../form";
import { BodyLong } from "../../typography";
import Link from "../Link";
import { RandomIcon } from "./RandomIcon";
export default {
@@ -139,37 +137,37 @@ const DemoLink = () => (
export const Icon = () => <DemoLink />;
export const Alert = () => {
export const InAlert = () => {
return (
<div className="colgap">
<DsAlert variant="info">
<Alert variant="info">
<DemoLink />
</DsAlert>
<DsAlert variant="success">
</Alert>
<Alert variant="success">
<DemoLink />
</DsAlert>
<DsAlert variant="warning">
</Alert>
<Alert variant="warning">
<DemoLink />
</DsAlert>
<DsAlert variant="error">
</Alert>
<Alert variant="error">
<DemoLink />
</DsAlert>
</Alert>
</div>
);
};
export const ConfirmationPanel = () => {
export const InConfirmationPanel = () => {
return (
<div className="colgap">
<DsConfirmationPanel label="demo">
<ConfirmationPanel label="demo">
<DemoLink />
</DsConfirmationPanel>
<DsConfirmationPanel checked label="demo">
</ConfirmationPanel>
<ConfirmationPanel checked label="demo">
<DemoLink />
</DsConfirmationPanel>
<DsConfirmationPanel error="demo" label="demo">
</ConfirmationPanel>
<ConfirmationPanel error="demo" label="demo">
<DemoLink />
</DsConfirmationPanel>
</ConfirmationPanel>
</div>
);
};
+2 -1
View File
@@ -6,7 +6,8 @@ import {
HeadHeartIcon,
RecycleIcon,
} from "@navikt/aksel-icons";
import { List, VStack } from "..";
import { VStack } from "../layout/stack";
import List from "./List";
export default {
title: "ds-react/List",
@@ -1,6 +1,6 @@
import { Meta } from "@storybook/react";
import React from "react";
import { Loader, LoaderProps } from "..";
import Loader, { LoaderProps } from "./Loader";
export default {
title: "ds-react/Loader",
@@ -0,0 +1,13 @@
import React from "react";
import { createContext } from "../util/create-context";
interface ModalContextProps {
closeHandler?: React.MouseEventHandler<HTMLButtonElement>;
ref: React.RefObject<HTMLDialogElement>;
}
export const [ModalContextProvider, useModalContext] =
createContext<ModalContextProps>({
name: "ModalContext",
errorMessage: "<Modal.Header> must be used within a <Modal>",
});
+6 -8
View File
@@ -8,8 +8,8 @@ import { Detail, Heading } from "../typography";
import { composeEventHandlers } from "../util/composeEventHandlers";
import { useId } from "../util/hooks";
import { useMergeRefs } from "../util/hooks/useMergeRefs";
import { ModalContextProvider, useModalContext } from "./Modal.context";
import ModalBody from "./ModalBody";
import { ModalContext } from "./ModalContext";
import ModalFooter from "./ModalFooter";
import ModalHeader from "./ModalHeader";
import { getCloseHandler, useBodyScrollLock } from "./ModalUtils";
@@ -98,7 +98,7 @@ export const Modal = forwardRef<HTMLDialogElement, ModalProps>(
const portalNode = useFloatingPortalNode({ root: rootElement });
const dateContext = useContext(DateContext);
const modalContext = useContext(ModalContext);
const modalContext = useModalContext(false);
if (modalContext && !dateContext) {
console.error("Modals should not be nested");
}
@@ -185,11 +185,9 @@ export const Modal = forwardRef<HTMLDialogElement, ModalProps>(
onClick={composeEventHandlers(onClick, handleModalClick)}
aria-labelledby={mergedAriaLabelledBy}
>
<ModalContext.Provider
value={{
closeHandler: getCloseHandler(modalRef, header, onBeforeClose),
ref: modalRef,
}}
<ModalContextProvider
closeHandler={getCloseHandler(modalRef, header, onBeforeClose)}
ref={modalRef}
>
{header && (
<ModalHeader>
@@ -208,7 +206,7 @@ export const Modal = forwardRef<HTMLDialogElement, ModalProps>(
)}
{children}
</ModalContext.Provider>
</ModalContextProvider>
</dialog>
);
@@ -1,7 +0,0 @@
import React from "react";
interface ModalContextProps {
closeHandler?: React.MouseEventHandler<HTMLButtonElement>;
ref: React.RefObject<HTMLDialogElement>;
}
export const ModalContext = React.createContext<ModalContextProps | null>(null);
+3 -7
View File
@@ -1,8 +1,8 @@
import cl from "clsx";
import React, { forwardRef, useContext } from "react";
import React, { forwardRef } from "react";
import { XMarkIcon } from "@navikt/aksel-icons";
import { Button } from "../button";
import { ModalContext } from "./ModalContext";
import { useModalContext } from "./Modal.context";
export interface ModalHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
children?: React.ReactNode;
@@ -15,11 +15,7 @@ export interface ModalHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
const ModalHeader = forwardRef<HTMLDivElement, ModalHeaderProps>(
({ children, className, closeButton = true, ...rest }, ref) => {
const context = useContext(ModalContext);
if (context === null) {
console.error("<Modal.Header> has to be used within a <Modal>");
return null;
}
const context = useModalContext();
return (
<div {...rest} ref={ref} className={cl("navds-modal__header", className)}>
@@ -1,9 +1,11 @@
import { Meta, StoryFn } from "@storybook/react";
import React, { useRef, useState } from "react";
import { FileIcon } from "@navikt/aksel-icons";
import { BodyLong, Button, Heading, Tooltip } from "..";
import { Button } from "../button";
import { Checkbox, CheckboxGroup } from "../form/checkbox";
import { VStack } from "../layout/stack";
import { Tooltip } from "../tooltip";
import { BodyLong, Heading } from "../typography";
import Modal from "./Modal";
const meta: Meta<typeof Modal> = {
+2
View File
@@ -0,0 +1,2 @@
export { Portal } from "./portal/Portal";
export type { PortalProps } from "./portal/Portal";
@@ -0,0 +1,99 @@
import React from "react";
import { Box } from "../../layout/box";
import { Provider } from "../../provider";
import { Portal } from "./Portal";
export default {
title: "Utilities/Portal",
parameters: {
chromatic: { disable: true },
},
};
export const Default = () => {
return (
<Box background="surface-neutral-subtle" border>
<h1>In regular DOM tree</h1>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Temporibus
necessitatibus quis esse nesciunt est velit voluptatibus. Distinctio eum
commodi tempora unde. Nulla vel tempora incidunt? Voluptatem molestias
impedit commodi. Tenetur!
</p>
<Portal>
<h1>Inside Portal to different DOM tree</h1>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Temporibus
necessitatibus quis esse nesciunt est velit voluptatibus. Distinctio
eum commodi tempora unde. Nulla vel tempora incidunt? Voluptatem
molestias impedit commodi. Tenetur!
</p>
</Portal>
</Box>
);
};
export const CustomPortalRoot = () => {
const [portalContainer, setPortalContainer] =
React.useState<HTMLDivElement | null>(null);
return (
<Box background="surface-neutral-subtle">
<Box background="surface-alt-1-subtle">
<h1>Tree A</h1>
<Portal rootElement={portalContainer}>
<p>This is mounted to Tree B, while created inside Tree A</p>
</Portal>
</Box>
<Box background="surface-alt-3-subtle" ref={setPortalContainer}>
<h1>Tree B</h1>
</Box>
</Box>
);
};
export const CustomPortalRootFromProvider = () => {
const [portalContainer, setPortalContainer] =
React.useState<HTMLDivElement>();
return (
<Provider rootElement={portalContainer}>
<Box background="surface-neutral-subtle">
<Box background="surface-alt-1-subtle">
<h1>Tree A</h1>
<Portal>
<p>This is mounted to Tree B, while created inside Tree A</p>
</Portal>
</Box>
<Box background="surface-alt-3-subtle" ref={setPortalContainer}>
<h1>Tree B</h1>
</Box>
</Box>
</Provider>
);
};
export const AsChild = () => {
return (
<Box background="surface-neutral-subtle" border>
<h1>In regular DOM tree</h1>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Temporibus
necessitatibus quis esse nesciunt est velit voluptatibus. Distinctio eum
commodi tempora unde. Nulla vel tempora incidunt? Voluptatem molestias
impedit commodi. Tenetur!
</p>
<Portal asChild>
<div data-this-is-the-child>
<h1>Inside Portal to different DOM tree</h1>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Temporibus
necessitatibus quis esse nesciunt est velit voluptatibus. Distinctio
eum commodi tempora unde. Nulla vel tempora incidunt? Voluptatem
molestias impedit commodi. Tenetur!
</p>
</div>
</Portal>
</Box>
);
};
@@ -0,0 +1,32 @@
import React, { HTMLAttributes, forwardRef } from "react";
import ReactDOM from "react-dom";
import { useProvider } from "../../provider";
import { Slot } from "../../util/Slot";
import { AsChildProps } from "../../util/types";
interface PortalBaseProps extends HTMLAttributes<HTMLDivElement> {
/**
* An optional container where the portaled content should be appended.
*/
rootElement?: HTMLElement | null;
}
export type PortalProps = PortalBaseProps & AsChildProps;
export const Portal = forwardRef<HTMLDivElement, PortalProps>(
({ rootElement, asChild, ...rest }, ref) => {
const contextRoot = useProvider()?.rootElement;
const root = rootElement ?? contextRoot ?? globalThis?.document?.body;
const Component = asChild ? Slot : "div";
return root
? ReactDOM.createPortal(
<Component ref={ref} data-aksel-portal="" {...rest} />,
root,
)
: null;
},
);
export default Portal;
+9 -16
View File
@@ -2,6 +2,9 @@ import cl from "clsx";
import React, { forwardRef } from "react";
import { OverridableComponent } from "../util/types";
/**
* @deprecated Use Box with padding and border instead
*/
export interface PanelProps extends React.HTMLAttributes<HTMLElement> {
/**
* Panel content
@@ -17,23 +20,13 @@ export interface PanelProps extends React.HTMLAttributes<HTMLElement> {
export type PanelType = OverridableComponent<PanelProps, HTMLElement>;
/**
* A component that displays a bordered panel with heading and body.
*
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/panel)
* @see 🏷️ {@link PanelProps}
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
*
* @example
* ```jsx
* <Panel border>
* <Heading spacing level="2" size="large">
* Søk om økonomisk sosialhjelp
* </Heading>
* <BodyLong>
* Du kan søke om det du trenger økonomisk støtte til.
* </BodyLong>
* </Panel>
* @deprecated
* Use Box with padding and border instead
* ```
* <Box padding="4" borderRadius="small" />
* <Box padding="4" borderWidth="1" borderRadius="small" />
* ```
* Component will be removed in a future major release
*/
export const Panel: PanelType = forwardRef(
(
@@ -1,63 +0,0 @@
import { Meta } from "@storybook/react";
import React from "react";
import { Panel } from "../index";
export default {
title: "ds-react/Panel",
component: Panel,
argTypes: {
border: {
defaultValue: true,
control: {
type: "boolean",
},
},
},
} as Meta;
export const Default = {
render: (props) => {
return (
<Panel {...props}>
Eu quis exercitation voluptate ex. Aute irure esse occaecat minim
cupidatat velit minim duis sint culpa anim laboris. Consectetur nulla eu
commodo ea culpa velit commodo incididunt sunt ipsum. Amet anim
adipisicing minim ipsum do. Non laborum culpa reprehenderit est sint
officia quis excepteur. Fugiat eiusmod eiusmod commodo incididunt nisi
minim ex eu cupidatat quis ex. Lorem irure ea ea enim consectetur ea
aliqua cupidatat. Officia aute veniam aute exercitation ipsum aliqua
adipisicing. Est aliqua ad ullamco aute nostrud amet ea adipisicing
consequat id officia irure pariatur. Eu mollit amet culpa culpa velit.
</Panel>
);
},
};
export const Border = () => {
return (
<div className="colgap">
<Panel>
Eu quis exercitation voluptate ex. Aute irure esse occaecat minim
cupidatat velit minim duis sint culpa anim laboris. Consectetur nulla eu
commodo ea culpa velit commodo incididunt sunt ipsum. Amet anim
adipisicing minim ipsum do. Non laborum culpa reprehenderit est sint
officia quis excepteur. Fugiat eiusmod eiusmod commodo incididunt nisi
minim ex eu cupidatat quis ex. Lorem irure ea ea enim consectetur ea
aliqua cupidatat. Officia aute veniam aute exercitation ipsum aliqua
adipisicing. Est aliqua ad ullamco aute nostrud amet ea adipisicing
consequat id officia irure pariatur. Eu mollit amet culpa culpa velit.
</Panel>
<Panel border>
Eu quis exercitation voluptate ex. Aute irure esse occaecat minim
cupidatat velit minim duis sint culpa anim laboris. Consectetur nulla eu
commodo ea culpa velit commodo incididunt sunt ipsum. Amet anim
adipisicing minim ipsum do. Non laborum culpa reprehenderit est sint
officia quis excepteur. Fugiat eiusmod eiusmod commodo incididunt nisi
minim ex eu cupidatat quis ex. Lorem irure ea ea enim consectetur ea
aliqua cupidatat. Officia aute veniam aute exercitation ipsum aliqua
adipisicing. Est aliqua ad ullamco aute nostrud amet ea adipisicing
consequat id officia irure pariatur. Eu mollit amet culpa culpa velit.
</Panel>
</div>
);
};
+2 -2
View File
@@ -18,7 +18,7 @@ import React, {
useRef,
} from "react";
import { DateContext } from "../date/context";
import { ModalContext } from "../modal/ModalContext";
import { useModalContext } from "../modal/Modal.context";
import { useClientLayoutEffect, useEventListener } from "../util/hooks";
import { useMergeRefs } from "../util/hooks/useMergeRefs";
import PopoverContent, { PopoverContentType } from "./PopoverContent";
@@ -126,7 +126,7 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
ref,
) => {
const arrowRef = useRef<HTMLDivElement | null>(null);
const isInModal = useContext(ModalContext) !== null;
const isInModal = useModalContext(false) !== undefined;
const isInDatepicker = useContext(DateContext) !== null;
const chosenStrategy = userStrategy ?? (isInModal ? "fixed" : "absolute");
const chosenFlip = isInDatepicker ? false : _flip;
@@ -1,6 +1,6 @@
import { Meta } from "@storybook/react";
import React, { useState } from "react";
import { BodyLong } from "..";
import { BodyLong } from "../typography";
import Stepper from "./Stepper";
const meta: Meta<typeof Stepper> = {
@@ -1,16 +1,27 @@
import React, { useState } from "react";
import { Table, TableProps } from "../";
import { Alert, Button, Checkbox, CheckboxGroup, Link } from "../..";
import { Button } from "../../button";
import { Checkbox } from "../../form";
import { VStack } from "../../layout/stack";
import {
Expandable,
ExpandableLarge,
ExpandableSmall,
} from "./table-2-expandable.stories";
export default {
title: "ds-react/Table",
component: Table,
parameters: {
chromatic: { disable: true },
},
};
interface Props extends TableProps {
button?: boolean;
shadeOnHover?: boolean;
}
const TableComponent = ({ button, shadeOnHover, ...rest }: Props) => (
<Table {...rest}>
<Table.Header>
@@ -89,75 +100,59 @@ export const Buttons = () => <TableComponent size="small" button />;
export const WithDivs = () => {
return (
<>
<Alert variant="warning">
Obs! Hvis man skal bygge tabeller uten å bruke vanlig {"<tabell> "}
-markup er det svært viktig at man supplerer elementene med{" "}
<Link href="https://www.w3.org/TR/wai-aria-practices-1.1/examples/table/table.html">
riktige
</Link>{" "}
role-attributter og display-stiler for å bevare den semantiske verdien i
tabellene. Vi anbefaler fortsatt å ikke ta i bruk denne metoden hvis
mulig, da nettleseren ikke kan tolke tabellen like bra uten riktig
markup.
</Alert>
<div className="navds-table" role="table">
<div className="navds-table__header" role="rowgroup">
<div className="navds-table__row" role="row">
<div className="navds-table__header-cell" role="columnheader">
Fornavn
</div>
<div className="navds-table__header-cell" role="columnheader">
Etternavn
</div>
<div className="navds-table__header-cell" role="columnheader">
Rolle
</div>
<div className="navds-table" role="table">
<div className="navds-table__header" role="rowgroup">
<div className="navds-table__row" role="row">
<div className="navds-table__header-cell" role="columnheader">
Fornavn
</div>
</div>
<div className="navds-table__body" role="rowgroup">
<div className="navds-table__row" role="row">
<div className="navds-table__data-cell" role="cell">
Jean-Luc
</div>
<div className="navds-table__data-cell" role="cell">
Picard
</div>
<div className="navds-table__data-cell" role="cell">
Kaptein
</div>
<div className="navds-table__header-cell" role="columnheader">
Etternavn
</div>
<div className="navds-table__row" role="row">
<div className="navds-table__data-cell" role="cell">
William
</div>
<div className="navds-table__data-cell" role="cell">
Riker
</div>
<div className="navds-table__data-cell" role="cell">
Kommandør
</div>
</div>
<div className="navds-table__row" role="row">
<div className="navds-table__data-cell" role="cell">
Geordi
</div>
<div className="navds-table__data-cell" role="cell">
La Forge
</div>
<div className="navds-table__data-cell" role="cell">
Sjefsingeniør
</div>
<div className="navds-table__header-cell" role="columnheader">
Rolle
</div>
</div>
</div>
</>
<div className="navds-table__body" role="rowgroup">
<div className="navds-table__row" role="row">
<div className="navds-table__data-cell" role="cell">
Jean-Luc
</div>
<div className="navds-table__data-cell" role="cell">
Picard
</div>
<div className="navds-table__data-cell" role="cell">
Kaptein
</div>
</div>
<div className="navds-table__row" role="row">
<div className="navds-table__data-cell" role="cell">
William
</div>
<div className="navds-table__data-cell" role="cell">
Riker
</div>
<div className="navds-table__data-cell" role="cell">
Kommandør
</div>
</div>
<div className="navds-table__row" role="row">
<div className="navds-table__data-cell" role="cell">
Geordi
</div>
<div className="navds-table__data-cell" role="cell">
La Forge
</div>
<div className="navds-table__data-cell" role="cell">
Sjefsingeniør
</div>
</div>
</div>
</div>
);
};
export const Selection = () => <SelectionTable />;
export const SelectionSmall = () => <SelectionTable size="small" />;
const SelectionTable = ({ size = "medium" }: { size?: "small" | "medium" }) => {
const useToggleList = (initialState) => {
const [list, setList] = useState(initialState);
@@ -182,7 +177,7 @@ const SelectionTable = ({ size = "medium" }: { size?: "small" | "medium" }) => {
<Table.DataCell>
<Checkbox
size={size}
checked={selectedRows.includes("all")}
indeterminate
onChange={() => toggleSelectedRow("all")}
>
Select all
@@ -212,12 +207,12 @@ const SelectionTable = ({ size = "medium" }: { size?: "small" | "medium" }) => {
<Table.DataCell>USA</Table.DataCell>
<Table.DataCell>38</Table.DataCell>
</Table.Row>
<Table.Row selected={selectedRows.includes("2")}>
<Table.Row selected>
<Table.DataCell>
<Checkbox
size={size}
hideLabel
checked={selectedRows.includes("2")}
checked
onChange={() => toggleSelectedRow("2")}
aria-labelledby={`x_r2-${size}`}
>
@@ -231,36 +226,67 @@ const SelectionTable = ({ size = "medium" }: { size?: "small" | "medium" }) => {
<Table.DataCell>Denmark</Table.DataCell>
<Table.DataCell>11</Table.DataCell>
</Table.Row>
<Table.Row selected={selectedRows.includes("3")}>
<Table.DataCell>
<CheckboxGroup legend="velg flere felt" hideLegend>
<Checkbox
size={size}
hideLabel
checked={selectedRows.includes("3")}
onChange={() => toggleSelectedRow("3")}
aria-labelledby={`x_r3-${size}`}
>
{" "}
</Checkbox>
<Checkbox
size={size}
hideLabel
checked={selectedRows.includes("3")}
onChange={() => toggleSelectedRow("3")}
aria-labelledby={`x_r3-${size}`}
>
{" "}
</Checkbox>
</CheckboxGroup>
</Table.DataCell>
<Table.HeaderCell scope="row" colSpan={4}>
<span id={`x_r3-${size}`}>
Don&apos;t stack multiple checkboxes
</span>
</Table.HeaderCell>
</Table.Row>
</Table.Body>
</Table>
);
};
export const Selection = () => <SelectionTable />;
export const SelectionSmall = () => <SelectionTable size="small" />;
export const Chromatic = {
render: () => (
<VStack gap="8">
<div>
<h3>Default</h3>
<Default />
<h3>Zebra</h3>
<Zebra />
</div>
<div>
<h3>Large</h3>
<SizeLarge />
</div>
<div>
<h3>Medium</h3>
<SizeMedium />
</div>
<div>
<h3>Small</h3>
<SizeSmall />
</div>
<div>
<h3>With Buttons</h3>
<Buttons />
</div>
<div>
<h3>Custom with divs</h3>
<WithDivs />
</div>
<div>
<h3>Selection</h3>
<Selection />
</div>
<div>
<h3>Selection small</h3>
<SelectionSmall />
</div>
<h2>Expandable</h2>
<div>
<h3>Large</h3>
<ExpandableLarge />
</div>
<div>
<h3>Medium</h3>
<Expandable />
</div>
<div>
<h3>Small</h3>
<ExpandableSmall />
</div>
</VStack>
),
parameters: {
chromatic: { disable: false },
},
};
@@ -1,10 +1,15 @@
import React, { useState } from "react";
import { Table } from "..";
import { Button, Checkbox, Link } from "../..";
import { Button } from "../../button";
import { Checkbox } from "../../form";
import { Link } from "../../link";
import Table from "../Table";
export default {
title: "ds-react/Table",
component: Table,
parameters: {
chromatic: { disable: true },
},
};
export const Expandable = () => {
@@ -25,6 +30,7 @@ export const Expandable = () => {
content={row.content}
key={row.name}
togglePlacement="right"
defaultOpen
>
{columns.map(({ key }) => (
<Table.DataCell key={key}>{row[key]}</Table.DataCell>
@@ -50,7 +56,7 @@ export const ExpandableLarge = () => {
</Table.Header>
<Table.Body>
{data.slice(0, 1).map((row) => (
<Table.ExpandableRow content={row.content} key={row.name}>
<Table.ExpandableRow defaultOpen content={row.content} key={row.name}>
{columns.map(({ key }) => (
<Table.DataCell key={key}>{row[key]}</Table.DataCell>
))}
@@ -87,7 +93,7 @@ export const ExpandableSmall = () => {
</Table.Header>
<Table.Body>
{data.slice(0, 1).map((row) => (
<Table.ExpandableRow content={row.content} key={row.name}>
<Table.ExpandableRow defaultOpen content={row.content} key={row.name}>
{columns.map(({ key }) => (
<Table.DataCell key={key}>{row[key]}</Table.DataCell>
))}
@@ -235,36 +241,6 @@ const data = [
},
];
export const ExpandableOpen = () => {
return (
<Table zebraStripes>
<Table.Header>
<Table.Row>
{columns.map(({ key, name }) => (
<Table.HeaderCell key={key}>{name}</Table.HeaderCell>
))}
<Table.HeaderCell />
</Table.Row>
</Table.Header>
<Table.Body>
{data.map((row) => (
<Table.ExpandableRow
expansionDisabled={row.animal === "Sel"}
content={row.content}
key={row.name}
togglePlacement="right"
defaultOpen
>
{columns.map(({ key }) => (
<Table.DataCell key={key}>{row[key]}</Table.DataCell>
))}
</Table.ExpandableRow>
))}
</Table.Body>
</Table>
);
};
export const ClickableRow = () => {
const [isRowOpen1, setIsRowOpen1] = useState(false);
const [isRowOpen2, setIsRowOpen2] = useState(false);
@@ -1,14 +1,16 @@
import React, { useState } from "react";
import useSWR from "swr";
import { Loader, Pagination, SortState } from "../..";
import { Table } from "../index";
import { Loader } from "../../loader";
import { Pagination } from "../../pagination";
import Table from "../Table";
import { SortState } from "../types";
import peopleJson from "./people.json";
export default {
title: "ds-react/Table",
component: Table,
parameters: {
chromatic: { delay: 500 },
chromatic: { disable: true },
},
};
@@ -1,10 +1,13 @@
import { expect, fn, userEvent, within } from "@storybook/test";
import React from "react";
import { Table } from "../..";
import Table from "../../Table";
export default {
title: "ds-react/Table/Tests",
component: Table,
parameters: {
chromatic: { disable: true },
},
};
export const ClickableRowTest = {
+109
View File
@@ -0,0 +1,109 @@
import { fireEvent, render, screen } from "@testing-library/react";
import React from "react";
import { Tabs } from "./Tabs";
const TestTabs = ({
value,
onChange,
defaultValue,
selectionFollowsFocus,
loop,
iconPosition,
}: any) => (
<Tabs
value={value}
onChange={onChange}
defaultValue={defaultValue}
selectionFollowsFocus={selectionFollowsFocus}
loop={loop}
iconPosition={iconPosition}
>
<Tabs.List data-testid="tablist">
<Tabs.Tab value="tab1" data-testid="tab1" label="Tab 1" />
<Tabs.Tab value="tab2" data-testid="tab2" label="Tab 2" />
<Tabs.Tab value="tab3" data-testid="tab3" label="Tab 3" />
</Tabs.List>
<Tabs.Panel value="tab1" data-testid="tabpanel1">
Tabpanel 1
</Tabs.Panel>
<Tabs.Panel value="tab2" data-testid="tabpanel2">
Tabpanel 2
</Tabs.Panel>
<Tabs.Panel value="tab3" data-testid="tabpanel3">
Tabpanel 3
</Tabs.Panel>
</Tabs>
);
describe("Tabs", () => {
test("sets default value correctly", () => {
render(<TestTabs defaultValue="tab2" />);
const tab = screen.getByTestId("tab2");
const panel = screen.getByTestId("tabpanel2");
expect(tab).toHaveAttribute("aria-selected", "true");
expect(panel).toHaveTextContent("Tabpanel 2");
});
test("label-connection between tab and tabpanel is correct", async () => {
render(<TestTabs defaultValue="tab2" />);
const tab = screen.getByTestId("tab2");
const panel = screen.getByTestId("tabpanel2");
const controlsId = tab.getAttribute("aria-controls");
const panelLabelledBy = panel.getAttribute("aria-labelledby");
expect(controlsId).toEqual(panel.id);
expect(tab.id).toEqual(panelLabelledBy);
});
test("sets correct attributes on active tab", () => {
render(<TestTabs defaultValue="tab2" />);
const tab = screen.getByTestId("tab2");
expect(tab).toHaveAttribute("aria-selected", "true");
expect(tab).toHaveAttribute("role", "tab");
expect(tab).toHaveAttribute("aria-controls");
expect(tab).toHaveAttribute("tabindex", "-1");
});
test("sets correct attributes on idle tab", () => {
render(<TestTabs defaultValue="tab2" />);
const tab = screen.getByTestId("tab1");
expect(tab).toHaveAttribute("aria-selected", "false");
expect(tab).toHaveAttribute("role", "tab");
expect(tab).toHaveAttribute("aria-controls");
expect(tab).toHaveAttribute("tabindex", "-1");
});
test("sets correct attributes on active tabpanel", () => {
render(<TestTabs defaultValue="tab2" />);
const panel = screen.getByTestId("tabpanel2");
expect(panel).toHaveAttribute("aria-labelledby");
expect(panel).toHaveAttribute("role", "tabpanel");
expect(panel).toHaveAttribute("tabindex", "0");
expect(panel).toHaveTextContent("Tabpanel 2");
expect(panel).toHaveStyle({ display: "block" });
});
test("sets correct attributes on idle tabpanel", () => {
render(<TestTabs defaultValue="tab1" />);
const panel = screen.getByTestId("tabpanel2");
expect(panel).toHaveAttribute("aria-labelledby");
expect(panel).toHaveAttribute("role", "tabpanel");
expect(panel).toHaveAttribute("tabindex", "0");
expect(panel).toBeEmptyDOMElement();
expect(panel).toHaveStyle({ display: "none" });
});
test("sets tabindex to 0 when focused", () => {
render(<TestTabs defaultValue="tab2" />);
const tab = screen.getByTestId("tab2");
fireEvent.focus(tab);
expect(tab).toHaveAttribute("tabindex", "0");
});
});
@@ -0,0 +1,54 @@
import { fireEvent, render, screen } from "@testing-library/react";
import React from "react";
import { ToggleGroup } from "./ToggleGroup";
const TestToggleGroup = ({ value, onChange, defaultValue }: any) => (
<ToggleGroup value={value} onChange={onChange} defaultValue={defaultValue}>
<ToggleGroup.Item value="toggle1" data-testid="toggle1">
Toggle 1
</ToggleGroup.Item>
<ToggleGroup.Item value="toggle2" data-testid="toggle2">
Toggle 2
</ToggleGroup.Item>
<ToggleGroup.Item value="toggle3" data-testid="toggle3">
Toggle 3
</ToggleGroup.Item>
</ToggleGroup>
);
describe("ToggleGroup", () => {
test("sets default value correctly", () => {
render(<TestToggleGroup defaultValue="toggle2" />);
const toggle = screen.getByTestId("toggle2");
expect(toggle).toHaveAttribute("aria-checked", "true");
});
test("sets correct attributes on active toggle", () => {
render(<TestToggleGroup defaultValue="toggle2" />);
const toggle = screen.getByTestId("toggle2");
expect(toggle).toHaveAttribute("aria-checked", "true");
expect(toggle).toHaveAttribute("role", "radio");
expect(toggle).toHaveAttribute("type", "button");
expect(toggle).toHaveAttribute("tabindex", "-1");
});
test("sets correct attributes on idle toggle", () => {
render(<TestToggleGroup defaultValue="toggle1" />);
const toggle = screen.getByTestId("toggle2");
expect(toggle).toHaveAttribute("aria-checked", "false");
expect(toggle).toHaveAttribute("role", "radio");
expect(toggle).toHaveAttribute("type", "button");
expect(toggle).toHaveAttribute("tabindex", "-1");
});
test("sets tabindex to 0 when focused", () => {
render(<TestToggleGroup defaultValue="toggle2" />);
const toggle = screen.getByTestId("toggle2");
fireEvent.focus(toggle);
expect(toggle).toHaveAttribute("tabindex", "0");
});
});
+7 -17
View File
@@ -1,5 +1,4 @@
import {
FloatingPortal,
autoUpdate,
arrow as flArrow,
flip,
@@ -13,15 +12,9 @@ import {
useInteractions,
} from "@floating-ui/react";
import cl from "clsx";
import React, {
HTMLAttributes,
cloneElement,
forwardRef,
useContext,
useRef,
} from "react";
import { ModalContext } from "../modal/ModalContext";
import { useProvider } from "../provider";
import React, { HTMLAttributes, cloneElement, forwardRef, useRef } from "react";
import { useModalContext } from "../modal/Modal.context";
import Portal from "../overlays/portal/Portal";
import { Detail } from "../typography";
import { useId } from "../util/hooks";
import { useControllableState } from "../util/hooks/useControllableState";
@@ -122,11 +115,8 @@ export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
});
const arrowRef = useRef<HTMLDivElement | null>(null);
const modalContext = useContext(ModalContext);
const providerRootElement = useProvider()?.rootElement;
const rootElement = modalContext
? modalContext.ref.current
: providerRootElement;
const modalContext = useModalContext(false);
const rootElement = modalContext ? modalContext.ref.current : undefined;
const {
x,
@@ -199,7 +189,7 @@ export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
: children?.props["aria-describedby"],
}),
)}
<FloatingPortal root={rootElement}>
<Portal rootElement={rootElement}>
{_open && (
<div
{...getFloatingProps({
@@ -253,7 +243,7 @@ export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
)}
</div>
)}
</FloatingPortal>
</Portal>
</>
);
},
@@ -1,6 +1,9 @@
import { Meta } from "@storybook/react";
import React from "react";
import { Alert, Button, Search, Tooltip } from "..";
import { Alert } from "../alert";
import { Button } from "../button";
import { Search } from "../form";
import Tooltip from "./Tooltip";
export default {
title: "ds-react/Tooltip",
@@ -1,13 +1,16 @@
import type { Meta, StoryObj } from "@storybook/react";
import { expect, within } from "@storybook/test";
import React from "react";
import { BodyLong } from "..";
import { VStack } from "../..";
import { VStack } from "../../layout/stack";
import BodyLong from "../BodyLong";
const meta = {
title: "ds-react/Typography/BodyLong",
component: BodyLong,
decorators: [(story) => <div style={{ maxWidth: "700px" }}>{story()}</div>],
parameters: {
chromatic: { disable: true },
},
} satisfies Meta<typeof BodyLong>;
export default meta;
@@ -17,7 +20,7 @@ type Story = StoryObj<typeof meta>;
const lorem =
"Hvis du ikke bor sammen med begge foreldrene dine, kan du ha rett til barnebidrag fra en eller begge foreldre mens du fullfører videregående skole eller tilsvarende.";
export const Default: Story = {
export const Controls: Story = {
args: {
spacing: false,
children: lorem,
@@ -162,3 +165,46 @@ export const OverrideTag: Story = {
expect(legendBodyLong.tagName).toEqual("LEGEND");
},
};
export const Chromatic: Story = {
render: (...props) => (
<div>
<div>
<h2>Large</h2>
<h3>Size</h3>
{SizeLarge.render?.(...props)}
<h3>Spacing</h3>
{SpacingLarge.render?.(...props)}
</div>
<div>
<h2>Medium</h2>
<h3>Size</h3>
{SizeMedium.render?.(...props)}
<h3>Spacing</h3>
{SpacingMedium.render?.(...props)}
</div>
<div>
<h2>Small</h2>
<h3>Size</h3>
{SizeSmall.render?.(...props)}
<h3>Spacing</h3>
{SpacingSmall.render?.(...props)}
</div>
<div>
<h2>Colors</h2>
{Colors.render?.(...props)}
</div>
<div>
<h2>Align</h2>
{Align.render?.(...props)}
</div>
<div>
<h2>Override Tag</h2>
{OverrideTag.render?.(...props)}
</div>
</div>
),
parameters: {
chromatic: { disable: false },
},
};
@@ -1,13 +1,16 @@
import type { Meta, StoryObj } from "@storybook/react";
import { expect, within } from "@storybook/test";
import React from "react";
import { BodyShort } from "..";
import { VStack } from "../..";
import { VStack } from "../../layout/stack";
import { BodyShort } from "../BodyShort";
const meta = {
title: "ds-react/Typography/BodyShort",
component: BodyShort,
decorators: [(story) => <div style={{ maxWidth: "200px" }}>{story()}</div>],
decorators: [(story) => <div style={{ maxWidth: "250px" }}>{story()}</div>],
parameters: {
chromatic: { disable: true },
},
} satisfies Meta<typeof BodyShort>;
export default meta;
@@ -16,7 +19,7 @@ type Story = StoryObj<typeof meta>;
const lorem = "Du må gjøre en filtrering for å se brukere i listen.";
export const Default: Story = {
export const Controls: Story = {
args: {
spacing: false,
children: lorem,
@@ -161,3 +164,46 @@ export const OverrideTag: Story = {
expect(legendBodyShort.tagName).toEqual("LEGEND");
},
};
export const Chromatic: Story = {
render: (...props) => (
<div>
<div>
<h2>Large</h2>
<h3>Size</h3>
{SizeLarge.render?.(...props)}
<h3>Spacing</h3>
{SpacingLarge.render?.(...props)}
</div>
<div>
<h2>Medium</h2>
<h3>Size</h3>
{SizeMedium.render?.(...props)}
<h3>Spacing</h3>
{SpacingMedium.render?.(...props)}
</div>
<div>
<h2>Small</h2>
<h3>Size</h3>
{SizeSmall.render?.(...props)}
<h3>Spacing</h3>
{SpacingSmall.render?.(...props)}
</div>
<div>
<h2>Colors</h2>
{Colors.render?.(...props)}
</div>
<div>
<h2>Align</h2>
{Align.render?.(...props)}
</div>
<div>
<h2>Override Tag</h2>
{OverrideTag.render?.(...props)}
</div>
</div>
),
parameters: {
chromatic: { disable: false },
},
};
@@ -1,13 +1,16 @@
import type { Meta, StoryObj } from "@storybook/react";
import { expect, within } from "@storybook/test";
import React from "react";
import { Detail } from "..";
import { VStack } from "../..";
import { VStack } from "../../layout/stack";
import Detail from "../Detail";
const meta = {
title: "ds-react/Typography/Detail",
component: Detail,
decorators: [(story) => <div style={{ maxWidth: "200px" }}>{story()}</div>],
parameters: {
chromatic: { disable: true },
},
} satisfies Meta<typeof Detail>;
export default meta;
@@ -16,7 +19,7 @@ type Story = StoryObj<typeof meta>;
const lorem = "Du må gjøre en filtrering for å se brukere i listen.";
export const Default: Story = {
export const Controls: Story = {
args: {
spacing: false,
children: lorem,
@@ -85,3 +88,29 @@ export const OverrideTag: Story = {
expect(legendDetail.tagName).toEqual("LEGEND");
},
};
export const Chromatic: Story = {
render: (...props) => (
<div>
<div>
<h2>Spacing</h2>
{Spacing.render?.(...props)}
</div>
<div>
<h2>Colors</h2>
{Colors.render?.(...props)}
</div>
<div>
<h2>Align</h2>
{Align.render?.(...props)}
</div>
<div>
<h2>Override Tag</h2>
{OverrideTag.render?.(...props)}
</div>
</div>
),
parameters: {
chromatic: { disable: false },
},
};
@@ -1,12 +1,15 @@
import type { Meta, StoryObj } from "@storybook/react";
import { expect, within } from "@storybook/test";
import React from "react";
import { ErrorMessage } from "..";
import { VStack } from "../..";
import { VStack } from "../../layout/stack";
import ErrorMessage from "../ErrorMessage";
const meta = {
title: "ds-react/Typography/ErrorMessage",
component: ErrorMessage,
parameters: {
chromatic: { disable: true },
},
} satisfies Meta<typeof ErrorMessage>;
export default meta;
@@ -16,7 +19,7 @@ type Story = StoryObj<typeof meta>;
const lorem =
"Du må fylle ut: Oppgi årsaken til at du har ventet mer enn 6 måneder med å søke om refusjon";
export const Default: Story = {
export const Controls: Story = {
args: {
spacing: false,
children: lorem,
@@ -90,3 +93,31 @@ export const OverrideTag: Story = {
expect(legendErrorMessage.tagName).toEqual("LEGEND");
},
};
export const Chromatic: Story = {
render: (...props) => (
<div>
<div>
<h2>Medium</h2>
<h3>Size</h3>
{SizeMedium.render?.(...props)}
<h3>Spacing</h3>
{SpacingMedium.render?.(...props)}
</div>
<div>
<h2>Small</h2>
<h3>Size</h3>
{SizeSmall.render?.(...props)}
<h3>Spacing</h3>
{SpacingSmall.render?.(...props)}
</div>
<div>
<h2>Override Tag</h2>
{OverrideTag.render?.(...props)}
</div>
</div>
),
parameters: {
chromatic: { disable: false },
},
};
@@ -1,13 +1,16 @@
import type { Meta, StoryObj } from "@storybook/react";
import { expect, within } from "@storybook/test";
import { default as React } from "react";
import { Heading } from "..";
import { VStack } from "../..";
import { VStack } from "../../layout/stack";
import Heading from "../Heading";
const meta = {
title: "ds-react/Typography/Heading",
component: Heading,
decorators: [(story) => <div style={{ maxWidth: "300px" }}>{story()}</div>],
parameters: {
chromatic: { disable: true },
},
} satisfies Meta<typeof Heading>;
export default meta;
@@ -16,7 +19,7 @@ type Story = StoryObj<typeof meta>;
const lorem = "Hva kan vi hjelpe deg med?";
export const Default: Story = {
export const Controls: Story = {
args: {
spacing: false,
children: lorem,
@@ -139,3 +142,29 @@ export const OverrideTag: Story = {
expect(legendHeading.tagName).toEqual("LEGEND");
},
};
export const Chromatic: Story = {
render: (...props) => (
<div>
<div>
<h2>Sizes</h2>
{Sizes.render?.(...props)}
</div>
<div>
<h2>Colors</h2>
{Colors.render?.(...props)}
</div>
<div>
<h2>Align</h2>
{Align.render?.(...props)}
</div>
<div>
<h2>Override Tag</h2>
{OverrideTag.render?.(...props)}
</div>
</div>
),
parameters: {
chromatic: { disable: false },
},
};
@@ -1,50 +0,0 @@
import type { Meta, StoryObj } from "@storybook/react";
import { expect, within } from "@storybook/test";
import React from "react";
import { Ingress } from "..";
const meta = {
title: "ds-react/Typography/deprecated/Ingress",
component: Ingress,
} satisfies Meta<typeof Ingress>;
export default meta;
type Story = StoryObj<typeof meta>;
const lorem =
"Hvis du ikke bor sammen med begge foreldrene dine, kan du ha rett til barnebidrag fra en eller begge foreldre mens du fullfører videregående skole eller tilsvarende.";
export const Default: Story = {
args: {
spacing: false,
children: lorem,
},
};
export const Spacing: Story = {
render: () => (
<div>
<Ingress spacing>{lorem}</Ingress>
<Ingress spacing>{lorem}</Ingress>
</div>
),
};
export const OverrideTag: Story = {
render: () => (
<div>
<Ingress spacing>default ingress</Ingress>
<Ingress as="legend">legend ingress</Ingress>
</div>
),
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const defaultIngress = canvas.getByText("default ingress");
const legendIngress = canvas.getByText("legend ingress");
expect(defaultIngress.tagName).toEqual("P");
expect(legendIngress.tagName).toEqual("LEGEND");
},
};
@@ -1,13 +1,16 @@
import type { Meta, StoryObj } from "@storybook/react";
import { expect, within } from "@storybook/test";
import React from "react";
import { Label } from "..";
import { VStack } from "../..";
import { VStack } from "../../layout/stack";
import Label from "../Label";
const meta = {
title: "ds-react/Typography/Label",
component: Label,
decorators: [(story) => <div style={{ maxWidth: "400px" }}>{story()}</div>],
parameters: {
chromatic: { disable: true },
},
} satisfies Meta<typeof Label>;
export default meta;
@@ -17,7 +20,7 @@ type Story = StoryObj<typeof meta>;
const lorem =
"Oppgi årsaken til at du har ventet mer enn 6 måneder med å søke om refusjon";
export const Default: Story = {
export const Controls: Story = {
args: {
spacing: false,
children: lorem,
@@ -95,3 +98,35 @@ export const OverrideTag: Story = {
expect(legendLabel.tagName).toEqual("LEGEND");
},
};
export const Chromatic: Story = {
render: (...props) => (
<div>
<div>
<h2>Medium</h2>
<h3>Size</h3>
{SizeMedium.render?.(...props)}
<h3>Spacing</h3>
{SpacingMedium.render?.(...props)}
</div>
<div>
<h2>Small</h2>
<h3>Size</h3>
{SizeSmall.render?.(...props)}
<h3>Spacing</h3>
{SpacingSmall.render?.(...props)}
</div>
<div>
<h2>Colors</h2>
{Colors.render?.(...props)}
</div>
<div>
<h2>Override Tag</h2>
{OverrideTag.render?.(...props)}
</div>
</div>
),
parameters: {
chromatic: { disable: false },
},
};
+4 -2
View File
@@ -20,10 +20,12 @@ export const Slot = React.forwardRef<HTMLElement, SlotProps>(
}
if (React.Children.count(children) > 1) {
console.error(
const error = new Error(
"Aksel: Components using 'asChild' expects to recieve a single React element child.",
);
return React.Children.only(null);
error.name = "SlotError";
Error.captureStackTrace?.(error, Slot);
throw error;
}
return null;
+26 -15
View File
@@ -6,6 +6,7 @@
*/
import React, {
createContext as createReactContext,
forwardRef,
useContext as useReactContext,
} from "react";
@@ -19,11 +20,6 @@ export interface CreateContextOptions<T> {
type ProviderProps<T> = T & { children: React.ReactNode };
export type CreateContextReturn<T> = [
(contextValues: ProviderProps<T>) => React.JSX.Element,
() => T,
];
function getErrorMessage(hook: string, provider: string) {
return `${hook} returned \`undefined\`. Seems you forgot to wrap component within ${provider}`;
}
@@ -39,17 +35,30 @@ export function createContext<T>(options: CreateContextOptions<T> = {}) {
const Context = createReactContext<T | undefined>(defaultValue);
function Provider({ children, ...context }: ProviderProps<T>) {
// Only re-memoize when prop values change
// eslint-disable-next-line react-hooks/exhaustive-deps
const value = React.useMemo(() => context, Object.values(context)) as T;
return <Context.Provider value={value}>{children}</Context.Provider>;
}
/**
* We use forwardRef to allow `ref` to be used as a regular context value
* @see https://reactjs.org/docs/forwarding-refs.html#forwarding-refs-to-dom-components
*/
const Provider = forwardRef(
({ children, ...context }: ProviderProps<T>, ref) => {
// Only re-memoize when prop values change
// eslint-disable-next-line react-hooks/exhaustive-deps
const value = React.useMemo(() => context, Object.values(context)) as T;
function useContext() {
return (
<Context.Provider value={ref ? { ...value, ref } : value}>
{children}
</Context.Provider>
);
},
);
function useContext<S extends boolean = true>(
strict: S = true as S,
): Context<S, T> {
const context = useReactContext(Context);
if (!context) {
if (!context && strict) {
const error = new Error(
errorMessage ?? getErrorMessage(hookName, providerName),
);
@@ -58,10 +67,12 @@ export function createContext<T>(options: CreateContextOptions<T> = {}) {
throw error;
}
return context;
return context as Context<S, T>;
}
Context.displayName = name;
return [Provider, useContext] as CreateContextReturn<T>;
return [Provider, useContext] as const;
}
type Context<S, T> = S extends true ? T : T | undefined;
@@ -0,0 +1,37 @@
export type AsChildProps =
| {
children: React.ReactElement | false | null;
/**
* Renders the component and its child as a single element,
* merging the props of the component with the props of the child.
*
* @example
* ```tsx
* <Component asChild data-prop>
* <ChildComponent data-child />
* </Component>
*
* // Renders
* <MergedComponent data-prop data-child />
* ```
*/
asChild: true;
}
| {
children: React.ReactNode;
/**
* Renders the component and its child as a single element,
* merging the props of the component with the props of the child.
*
* @example
* ```tsx
* <Component asChild data-prop>
* <ChildComponent data-child />
* </Component>
*
* // Renders
* <MergedComponent data-prop data-child />
* ```
*/
asChild?: false;
};
@@ -1 +1,2 @@
export type { OverridableComponent } from "./OverridableComponent";
export type { AsChildProps } from "./AsChildProps";
+6
View File
@@ -1,5 +1,11 @@
# @navikt/ds-tailwind
## 5.18.2
## 5.18.1
## 5.18.0
## 5.17.5
## 5.17.4
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-tailwind",
"version": "5.17.5",
"version": "5.18.2",
"description": "Tailwind config based on @navikt/ds-tokens",
"author": "Aksel | NAV designsystem team",
"keywords": [
@@ -24,7 +24,7 @@
"directory": "@navikt/core/tailwind"
},
"devDependencies": {
"@navikt/ds-tokens": "^5.17.5",
"@navikt/ds-tokens": "^5.18.2",
"@types/jest": "^29.0.0",
"color": "4.2.3",
"jest": "^29.0.0",
+6
View File
@@ -1,5 +1,11 @@
# @navikt/ds-tokens
## 5.18.2
## 5.18.1
## 5.18.0
## 5.17.5
## 5.17.4
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-tokens",
"version": "5.17.5",
"version": "5.18.2",
"description": "Design-tokens for NAV designsystem",
"author": "Aksel | NAV designsystem team",
"keywords": [
@@ -3,6 +3,9 @@ import React from "react";
export default {
title: "ds-tokens/Border-radius",
parameters: {
chromatic: { disable: true },
},
} as Meta;
const Border = ({ token }) => (
@@ -24,3 +27,18 @@ export const Medium = () => <Border token="var(--a-border-radius-medium)" />;
export const Large = () => <Border token="var(--a-border-radius-large)" />;
export const XLarge = () => <Border token="var(--a-border-radius-xlarge)" />;
export const Full = () => <Border token="var(--a-border-radius-full)" />;
export const Chromatic = {
render: () => (
<div className="colgap">
<Small />
<Medium />
<Large />
<XLarge />
<Full />
</div>
),
parameters: {
chromatic: { disable: false },
},
};
@@ -6,6 +6,10 @@ export default {
title: "ds-tokens/Colors",
} as Meta;
/**
* @note No need to create single Chromatic-story since we want to keep global and semantic colors separated
*/
const ColorGroups = ({ prefix }: { prefix: string }) => (
<div>
{Object.entries(tokens)
@@ -3,6 +3,9 @@ import React from "react";
export default {
title: "ds-tokens/Shadows",
parameters: {
chromatic: { disable: true },
},
} as Meta;
const Shadow = ({ token }) => (
@@ -27,3 +30,20 @@ export const Focus = () => <Shadow token="var(--a-shadow-focus)" />;
export const FocusInverted = () => (
<Shadow token="var(--a-shadow-focus-inverted)" />
);
export const Chromatic = {
render: () => (
<div className="colgap">
<XSmall />
<Small />
<Medium />
<Large />
<XLarge />
<Focus />
<FocusInverted />
</div>
),
parameters: {
chromatic: { disable: false },
},
};
+144 -134
View File
@@ -1,5 +1,15 @@
# Changelog
## 5.18
### @navikt/ds-react
- Modal: Oppdatert intern håntering av context i komponent ([#2714](https://github.com/navikt/aksel/pull/2714))
* Panel: Komponent er nå markert som deprecated. Bruk `Box` i fremtiden. ([#2712](https://github.com/navikt/aksel/pull/2712))
- Portal: Ny komponent `Portal` som lar deg enkelt bruke `createPortal`, også på serversiden ([#2697](https://github.com/navikt/aksel/pull/2697))
## 5.17
### @navikt/ds-css
@@ -28,32 +38,32 @@
## 5.16
### @navikt/ds-css
### @navikt/aksel-icons
- :sparkles: Combobox: Mulighet for å begrense hvor mange valg bruker kan ta ([#2260](https://github.com/navikt/aksel/pull/2260))
- Ikoner: Nytt ikon `LocationPin` ✨ ([#2672](https://github.com/navikt/aksel/pull/2672))
### @navikt/ds-tailwind
- Tailwind: La til ny `maxWidth` for text ([#2652](https://github.com/navikt/aksel/pull/2652))
### @navikt/ds-css
- :sparkles: Combobox: Mulighet for å begrense hvor mange valg bruker kan ta ([#2260](https://github.com/navikt/aksel/pull/2260))
### @navikt/ds-react
- :sparkles: Combobox: Mulighet for å begrense hvor mange valg bruker kan ta ([#2260](https://github.com/navikt/aksel/pull/2260))
### @navikt/aksel-icons
- Ikoner: Nytt ikon `LocationPin` ✨ ([#2672](https://github.com/navikt/aksel/pull/2672))
## 5.15
### @navikt/ds-react
- HelpText: HelpText-state ble ikke riktig oppdatert ved klikk ([#2643](https://github.com/navikt/aksel/pull/2643))
### @navikt/aksel-icons
- Ikoner: Synket ikoner med Figma. Lagt til nytt ikon `FigureChild` ([#2629](https://github.com/navikt/aksel/pull/2629))
### @navikt/ds-react
- HelpText: HelpText-state ble ikke riktig oppdatert ved klikk ([#2643](https://github.com/navikt/aksel/pull/2643))
## 5.14
### @navikt/ds-css
@@ -80,6 +90,10 @@
- Page: Lagt til ny bakgrunnsfarge `surface-subtle` og ny maksbredde på Page.Block `text` ([#2572](https://github.com/navikt/aksel/pull/2572))
### @navikt/ds-tokens
- Tokens: Ny token `--a-text-width-max: 576px` ([#2572](https://github.com/navikt/aksel/pull/2572))
### @navikt/ds-react
- Accordion.Item, Dropdown, ReadMore og Tooltip: Har en ny prop `onOpenChange?: (open: boolean) => void;` som forteller nå-state når `open`-state endrer seg. Dette vil være nyttig hvis man ikke bruker controlled-state, men fortsatt ønsker å vite om komponenten er `open` eller ikke (f.eks logging). ([#2585](https://github.com/navikt/aksel/pull/2585))
@@ -88,12 +102,12 @@
* Page: Lagt til ny bakgrunnsfarge `surface-subtle` og ny maksbredde på Page.Block `text` ([#2572](https://github.com/navikt/aksel/pull/2572))
### @navikt/ds-tokens
- Tokens: Ny token `--a-text-width-max: 576px` ([#2572](https://github.com/navikt/aksel/pull/2572))
## 5.12
### @navikt/aksel-icons
- Ikoner: Oppdatert ikonpakke med diverse bugdfixes og oppdateringer av stroke ([#2538](https://github.com/navikt/aksel/pull/2538))
### @navikt/aksel-stylelint
- Stylelint: Støtter nå stylelint v16 ([#2591](https://github.com/navikt/aksel/pull/2591))
@@ -114,11 +128,11 @@
* Datepicker: Lukk-knapp i modal har nå type button for å unngå form-submition ([#2568](https://github.com/navikt/aksel/pull/2568))
## 5.11
### @navikt/aksel-icons
- Ikoner: Oppdatert ikonpakke med diverse bugdfixes og oppdateringer av stroke ([#2538](https://github.com/navikt/aksel/pull/2538))
## 5.11
- Ikoner: Nytt ikon `PushPin` ([#2503](https://github.com/navikt/aksel/pull/2503))
### @navikt/ds-css
@@ -160,12 +174,12 @@
- :wheelchair: Textarea: Forsinkelse ved live-opplesning av gjenstående tegn ([#2502](https://github.com/navikt/aksel/pull/2502))
### @navikt/aksel-icons
- Ikoner: Nytt ikon `PushPin` ([#2503](https://github.com/navikt/aksel/pull/2503))
## 5.10
### @navikt/ds-tailwind
- typescript types for tailwind preset ([#2486](https://github.com/navikt/aksel/pull/2486))
### @navikt/ds-css
- :bug: Textarea: Teller flyttet ut av tekstfeltet for å unngå overlapp og misforståelser ([#2483](https://github.com/navikt/aksel/pull/2483))
@@ -174,10 +188,6 @@
- Primitives: Ny komponent `Page` og `Page.Block` ([#2456](https://github.com/navikt/aksel/pull/2456))
### @navikt/ds-tailwind
- typescript types for tailwind preset ([#2486](https://github.com/navikt/aksel/pull/2486))
### @navikt/ds-react
- Gjør lukknapp i Alert til type button ([#2497](https://github.com/navikt/aksel/pull/2497))
@@ -240,6 +250,10 @@
## 5.7
### @navikt/aksel-icons
- Ikoner: Nye ikoner `ChevronLeftFirstCircle` og `ChevronRightLastCircle` ([#2365](https://github.com/navikt/aksel/pull/2365))
### @navikt/ds-css
- :lipstick: Chips.Toggle: Ikon i uvalgt tilstand ([#2395](https://github.com/navikt/aksel/pull/2395))
@@ -256,6 +270,10 @@
- :lipstick: CopyButton: Justert padding, gap og animasjon ([#2355](https://github.com/navikt/aksel/pull/2355))
### @navikt/ds-tokens
- Ny spacing token på 0.375rem ([#2370](https://github.com/navikt/aksel/pull/2370))
### @navikt/ds-react
- :lipstick: Chips.Toggle: Ikon i uvalgt tilstand ([#2395](https://github.com/navikt/aksel/pull/2395))
@@ -276,15 +294,15 @@
- :lipstick: CopyButton: Justert padding, gap og animasjon ([#2355](https://github.com/navikt/aksel/pull/2355))
### @navikt/ds-tokens
- Ny spacing token på 0.375rem ([#2370](https://github.com/navikt/aksel/pull/2370))
## 5.6
### @navikt/aksel-icons
- Ikoner: Nye ikoner `ChevronLeftFirstCircle` og `ChevronRightLastCircle` ([#2365](https://github.com/navikt/aksel/pull/2365))
- Ikoner: SVG export setter nå `height="1em"`, `width="1em"` og `fill="currentColor"`. ([#2300](https://github.com/navikt/aksel/pull/2300))
## 5.6
- Ikoner: Nye ikoner `book` og `books` ([#2313](https://github.com/navikt/aksel/pull/2313))
* Ikoner: Nye ikoner `ClipboardCheckmark` og `ClipboardLink` ([#2307](https://github.com/navikt/aksel/pull/2307))
### @navikt/ds-css
@@ -306,6 +324,10 @@
- MonthPicker: Tilpasset padding og sizing på mobil. ([#2311](https://github.com/navikt/aksel/pull/2311))
### @navikt/ds-tokens
- Tokens: Tilbyr nå token literals for typer, tidligere string literals ([#2342](https://github.com/navikt/aksel/pull/2342))
### @navikt/ds-react
- Datepicker: Popover legger seg nå ikke ovenfor input ([#2349](https://github.com/navikt/aksel/pull/2349))
@@ -332,18 +354,6 @@
- Remove tabIndex="-1" on Popover to fix VoiceOver navigation issue inside Popover ([#2303](https://github.com/navikt/aksel/pull/2303))
### @navikt/ds-tokens
- Tokens: Tilbyr nå token literals for typer, tidligere string literals ([#2342](https://github.com/navikt/aksel/pull/2342))
### @navikt/aksel-icons
- Ikoner: SVG export setter nå `height="1em"`, `width="1em"` og `fill="currentColor"`. ([#2300](https://github.com/navikt/aksel/pull/2300))
- Ikoner: Nye ikoner `book` og `books` ([#2313](https://github.com/navikt/aksel/pull/2313))
* Ikoner: Nye ikoner `ClipboardCheckmark` og `ClipboardLink` ([#2307](https://github.com/navikt/aksel/pull/2307))
## 5.5
### @navikt/ds-css
@@ -352,16 +362,16 @@
* Skeleton: Width fungerer nå med inline-variant av Skeleton ([#2273](https://github.com/navikt/aksel/pull/2273))
### @navikt/ds-tokens
- Box: Ny primitive, erstatter dagens `Panel` ([#2195](https://github.com/navikt/aksel/pull/2195))
### @navikt/ds-react
- Box: Ny primitive, erstatter dagens `Panel` ([#2195](https://github.com/navikt/aksel/pull/2195))
* Skeleton: Width fungerer nå med inline-variant av Skeleton ([#2273](https://github.com/navikt/aksel/pull/2273))
### @navikt/ds-tokens
- Box: Ny primitive, erstatter dagens `Panel` ([#2195](https://github.com/navikt/aksel/pull/2195))
## 5.4
### @navikt/ds-css
@@ -370,6 +380,10 @@
* ErrorSummary: Har nå 8px border-radius ([#2256](https://github.com/navikt/aksel/pull/2256))
### @navikt/ds-tokens
- Tokens: `data-theme="light"` vil nå tilbakestille theming ([#2238](https://github.com/navikt/aksel/pull/2238))
### @navikt/ds-react
- MonthPicker: Fikset kalkulering av fromDate/toDate ([#2269](https://github.com/navikt/aksel/pull/2269))
@@ -378,12 +392,12 @@
- Search: Kjører nå bare preventDefault ved Escape når `input` inneholder tekst ([#2245](https://github.com/navikt/aksel/pull/2245))
### @navikt/ds-tokens
- Tokens: `data-theme="light"` vil nå tilbakestille theming ([#2238](https://github.com/navikt/aksel/pull/2238))
## 5.3
### @navikt/aksel-icons
- :bug: SVG import map er nå riktig path ([#2250](https://github.com/navikt/aksel/pull/2250))
### @navikt/ds-css
- Alert: 12px -> 8px gap mellom tekst og ikon ved `size="small"` ([#2240](https://github.com/navikt/aksel/pull/2240))
@@ -420,11 +434,11 @@
* :wheelchair: Textarea: Skjermleser-spesifikk tekst leses opp sammenhengende ([#2216](https://github.com/navikt/aksel/pull/2216))
## 5.2
### @navikt/aksel-icons
- :bug: SVG import map er nå riktig path ([#2250](https://github.com/navikt/aksel/pull/2250))
## 5.2
- Ikoner: Oppdatert ikonpakke ([#2197](https://github.com/navikt/aksel/pull/2197))
### @navikt/ds-css
@@ -442,10 +456,6 @@
- Hovering over combobox dropdown will move selection/focus in the list, so we don't end up with a split focus, and reversely when moving focus while hovering ([#2193](https://github.com/navikt/aksel/pull/2193))
### @navikt/aksel-icons
- Ikoner: Oppdatert ikonpakke ([#2197](https://github.com/navikt/aksel/pull/2197))
## 5.1
### @navikt/ds-css
@@ -481,6 +491,16 @@
* Table: Alle størrelser har justert padding. Small-size table bruker nå også standard typografi-størrelse (18px). ([#2178](https://github.com/navikt/aksel/pull/2178))
### @navikt/ds-tokens
- ConfirmationPanel: Fikset opplesing av feilmelding ([#2199](https://github.com/navikt/aksel/pull/2199))
- Tokens: `--a-icon-alt-3` er nå i synk med figma ([#2199](https://github.com/navikt/aksel/pull/2199))
* Gray: Gråfarger er nå mindre varme ([#2092](https://github.com/navikt/aksel/pull/2092))
* Action: Selected-varianter av action er nå 'blue' ('deepblue' før) ([#2092](https://github.com/navikt/aksel/pull/2092))
### @navikt/ds-react
- ConfirmationPanel: Fikset opplesing av feilmelding ([#2199](https://github.com/navikt/aksel/pull/2199))
@@ -497,16 +517,6 @@
* Table: Har lagt til ny size: 'large'. ([#2178](https://github.com/navikt/aksel/pull/2178))
### @navikt/ds-tokens
- ConfirmationPanel: Fikset opplesing av feilmelding ([#2199](https://github.com/navikt/aksel/pull/2199))
- Tokens: `--a-icon-alt-3` er nå i synk med figma ([#2199](https://github.com/navikt/aksel/pull/2199))
* Gray: Gråfarger er nå mindre varme ([#2092](https://github.com/navikt/aksel/pull/2092))
* Action: Selected-varianter av action er nå 'blue' ('deepblue' før) ([#2092](https://github.com/navikt/aksel/pull/2092))
## 4.12
### @navikt/ds-css
@@ -655,28 +665,28 @@
## 4.4
### @navikt/ds-css
- :lipstick: Chat: fjernet border, satt avatar svg til 24x24px, byttet om "subtle" og "neutral" ([#2077](https://github.com/navikt/aksel/pull/2077))
* Shadow-tokens er oppdatert: Datepicker har nå ikke border, Modal bruker shadow-xlarge, LinkCard bruker shadow-xsmall ([PR](https://github.com/navikt/aksel/pull/2041))
### @navikt/ds-tailwind
- Shadow-tokens er oppdatert ([PR](https://github.com/navikt/aksel/pull/2041))
- Oppdatert text-subtle og icon-subtle tokens til 700-skala (tidligere 600). ([PR](https://github.com/navikt/aksel/pull/2036))
### @navikt/ds-css
- :lipstick: Chat: fjernet border, satt avatar svg til 24x24px, byttet om "subtle" og "neutral" ([#2077](https://github.com/navikt/aksel/pull/2077))
* Shadow-tokens er oppdatert: Datepicker har nå ikke border, Modal bruker shadow-xlarge, LinkCard bruker shadow-xsmall ([PR](https://github.com/navikt/aksel/pull/2041))
### @navikt/ds-tokens
- Shadow-tokens er oppdatert til mer tydeligere varianter ([PR](https://github.com/navikt/aksel/pull/2041))
### @navikt/ds-react
- Textarea: Fikset i18n for counter ([`718b3204d`](https://github.com/navikt/aksel/commit/718b3204d8714c4fc515dcad484424214bdc0c77))
* Fikset klassenavn brukt for popover i Datepicker og Monthpicker ([PR](https://github.com/navikt/aksel/pull/2041))
### @navikt/ds-tokens
- Shadow-tokens er oppdatert til mer tydeligere varianter ([PR](https://github.com/navikt/aksel/pull/2041))
## 4.3
### @navikt/ds-css
@@ -701,10 +711,18 @@
## 4.1
### @navikt/aksel-icons
- Nye ikoner `ChevronRightLast` og `ChevronLeftLast` ([PR](https://github.com/navikt/aksel/pull/2054))
### @navikt/aksel-stylelint
- Deprecated klassenavn `navds-chips--icon-left` ([PR](https://github.com/navikt/aksel/pull/2035))
### @navikt/ds-tailwind
- :tada: Fargetokens for datavisualisering. ([PR](https://github.com/navikt/aksel/pull/2032))
### @navikt/ds-css
- Readmore: setter nå eksplisitt color for å ikke arve text-subtle fra parent. ([PR](https://github.com/navikt/aksel/pull/2049))
@@ -715,10 +733,12 @@
- Alle description-felter på fieldsets har nå `text-subtle` som farge. ([PR](https://github.com/navikt/aksel/pull/2036))
### @navikt/ds-tailwind
### @navikt/ds-tokens
- :tada: Fargetokens for datavisualisering. ([PR](https://github.com/navikt/aksel/pull/2032))
- Oppdatert text-subtle og icon-subtle tokens til 700-skala (tidligere 600). ([PR](https://github.com/navikt/aksel/pull/2036))
### @navikt/ds-react
- Fikset JSDom-problemer ved testing av Timeline
@@ -743,16 +763,6 @@
- Accordion: La til `indent`-prop ([PR](https://github.com/navikt/aksel/pull/2027))
### @navikt/ds-tokens
- :tada: Fargetokens for datavisualisering. ([PR](https://github.com/navikt/aksel/pull/2032))
- Oppdatert text-subtle og icon-subtle tokens til 700-skala (tidligere 600). ([PR](https://github.com/navikt/aksel/pull/2036))
### @navikt/aksel-icons
- Nye ikoner `ChevronRightLast` og `ChevronLeftLast` ([PR](https://github.com/navikt/aksel/pull/2054))
## 4.0
### @navikt/aksel
@@ -805,6 +815,10 @@
## 3.2
### @navikt/aksel-icons
- Nye ikoner `FileParagraph` og `FilePlus` ([PR](https://github.com/navikt/aksel/pull/1998))
### @navikt/ds-css
- Datepicker: Fikset small-variant av datepicker-input. ([PR](https://github.com/navikt/aksel/pull/1993))
@@ -823,10 +837,6 @@
* Ny komponent CopyButton! Erstatter `CopyToClipboard` som nå er tagget som deprecated ([PR](https://github.com/navikt/aksel/pull/1982))
### @navikt/aksel-icons
- Nye ikoner `FileParagraph` og `FilePlus` ([PR](https://github.com/navikt/aksel/pull/1998))
## 3.1
### @navikt/ds-css
@@ -859,6 +869,16 @@
## 2.9
### @navikt/aksel-icons
- Oppdatert Statusikoner til å være tydeligere og mer konsistente. ([PR](https://github.com/navikt/aksel/pull/1959))
* Fikset `CheckmarkIcon`-bug
- Fikset `CheckmarkCircleIcon`-bug ([PR](https://github.com/navikt/aksel/pull/1956))
* Nye ikoner `BulletList` og `NumberList` ([PR](https://github.com/navikt/aksel/pull/1950))
### @navikt/aksel
- :truck: Flyttet Codemods fra `@navikt/ds-codemods` -> `@navikt/aksel`. `@navikt/ds-codemods` regnes nå som deprecated ([PR](https://github.com/navikt/aksel/pull/1952))
@@ -871,17 +891,19 @@
- ExpansionCard: Støtter nå `aria-labelledby` i tillegg til `aria-label` ([PR](https://github.com/navikt/aksel/pull/1944))
## 2.8
### @navikt/aksel-icons
- Oppdatert Statusikoner til å være tydeligere og mer konsistente. ([PR](https://github.com/navikt/aksel/pull/1959))
- :tada: Nye ikoner `HandKnot` og `HandKnotFilled` ([PR](https://github.com/navikt/aksel/pull/1928))
* Fikset `CheckmarkIcon`-bug
* Oppdatert `InformationSquare`-ikon ([PR](https://github.com/navikt/aksel/pull/1921))
- Fikset `CheckmarkCircleIcon`-bug ([PR](https://github.com/navikt/aksel/pull/1956))
- Oppdatert `VideoSlack`, `Questionmark` og `Information`-ikoner ([PR](https://github.com/navikt/aksel/pull/1909))
* Nye ikoner `BulletList` og `NumberList` ([PR](https://github.com/navikt/aksel/pull/1950))
* Nye ikoner `VideoSlash` og `VideoSlashFill`
## 2.8
- Fikset Sourcemap-bug
### @navikt/ds-css
@@ -917,26 +939,8 @@
* Ny komponent ExpansionCard! ([PR](https://github.com/navikt/aksel/pull/1820))
### @navikt/aksel-icons
- :tada: Nye ikoner `HandKnot` og `HandKnotFilled` ([PR](https://github.com/navikt/aksel/pull/1928))
* Oppdatert `InformationSquare`-ikon ([PR](https://github.com/navikt/aksel/pull/1921))
- Oppdatert `VideoSlack`, `Questionmark` og `Information`-ikoner ([PR](https://github.com/navikt/aksel/pull/1909))
* Nye ikoner `VideoSlash` og `VideoSlashFill`
- Fikset Sourcemap-bug
## 2.7
### @navikt/ds-css
- Tabs: La til focus-markering for Tabs.Panel ([PR](https://github.com/navikt/aksel/pull/1863))
* ToggleGroup: Fikset token-bug
### @navikt/aksel-icons
- Nye ikoner `CaretUpDownFilledDown`, `CaretUpDownFilledUp`, `CloudDown`, `CloudDownFill`, `CloudUp`, `CloudUpFill`, `HddDown`, `HddDownFill`, `HddUp`, `HddUpFill`, `Inbox`, `InboxDown`, `InboxDownFill`, `InboxFill`, `InboxUp`, `InboxUpFill`, `ShoppingBasket`, `ShoppingBasketFill`
@@ -945,6 +949,12 @@
- Ny ikonpakke med for core icons 3! `@navikt/aksel-icons` ([PR](https://github.com/navikt/aksel/pull/1847))
### @navikt/ds-css
- Tabs: La til focus-markering for Tabs.Panel ([PR](https://github.com/navikt/aksel/pull/1863))
* ToggleGroup: Fikset token-bug
## 2.6
### @navikt/ds-react
@@ -959,14 +969,14 @@
- Breakpoint-tokens er lagt til. Overskriver native tailwind-breakpoints ([PR](https://github.com/navikt/aksel/pull/1832))
### @navikt/ds-react
- List: Refaktorert nestede lister
### @navikt/ds-tokens
- Breakpoint-tokens lagt til ([PR](https://github.com/navikt/aksel/pull/1832))
### @navikt/ds-react
- List: Refaktorert nestede lister
## 2.4
### @navikt/ds-css
@@ -1001,24 +1011,28 @@
- Button: `Neutral`-variant.
### @navikt/ds-react
- ToggleGroup: `neutral`-variant ([PR](https://github.com/navikt/aksel/pull/1789))
- Button: `neutral`-variant ([PR](https://github.com/navikt/aksel/pull/1789))
### @navikt/ds-tokens
- Justeringer av semantiske fargetokens, statusfarger nå mer tydelig ([PR](https://github.com/navikt/aksel/pull/1787))
- Oppdatert neutral-tokens ([PR](https://github.com/navikt/aksel/pull/1789))
### @navikt/ds-react
- ToggleGroup: `neutral`-variant ([PR](https://github.com/navikt/aksel/pull/1789))
- Button: `neutral`-variant ([PR](https://github.com/navikt/aksel/pull/1789))
## 2.1
### @navikt/ds-css
- TextField: `small`-variant har nå 8px horisontal padding (før 4px)
### @navikt/ds-tokens
- Fikset feil danger-hover token ([PR](https://github.com/navikt/aksel/pull/1665))
### @navikt/ds-react
- Datepicker: Fikset rekkefølge på `onValidate` og `onRangeChange` i useRangepicker-hook
@@ -1035,12 +1049,12 @@
- Datepicker/Monthpicker: år med 2 siffer i input fungerer nå
### @navikt/ds-tokens
- Fikset feil danger-hover token ([PR](https://github.com/navikt/aksel/pull/1665))
## 2.0
### @navikt/ds-tailwind
- Alle token er oppdatert til nytt format. ([Guide](https://aksel.nav.no/grunnleggende/kode/migrering#h76f47744d112))
### @navikt/ds-css
- Radio: Fikset default visuell error-state ([PR](https://github.com/navikt/aksel/pull/1737))
@@ -1053,7 +1067,7 @@
* Tokens: Alle komponenter bruker nå semantiske tokens for som standard, med innebygd støtte for komponent-spesifikke tokens.
### @navikt/ds-tailwind
### @navikt/ds-tokens
- Alle token er oppdatert til nytt format. ([Guide](https://aksel.nav.no/grunnleggende/kode/migrering#h76f47744d112))
@@ -1075,10 +1089,6 @@
* Fonter blir bruk i all typografi blir nå lastet fra CDN
### @navikt/ds-tokens
- Alle token er oppdatert til nytt format. ([Guide](https://aksel.nav.no/grunnleggende/kode/migrering#h76f47744d112))
## 1.5
### @navikt/ds-css
+1 -1
View File
@@ -1,6 +1,6 @@
# MIT License
Copyright 2023 NAV (Arbeids- og velferdsdirektoratet) - The Norwegian Labour and Welfare Administration
Copyright 2024 NAV (Arbeids- og velferdsdirektoratet) - The Norwegian Labour and Welfare Administration
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the "Software"),
+5 -5
View File
@@ -16,10 +16,10 @@
"playroom"
],
"dependencies": {
"@navikt/aksel-icons": "^5.17.5",
"@navikt/ds-css": "^5.17.5",
"@navikt/ds-react": "^5.17.5",
"@navikt/ds-tailwind": "^5.17.5",
"@navikt/ds-tokens": "^5.17.5"
"@navikt/aksel-icons": "^5.18.2",
"@navikt/ds-css": "^5.18.2",
"@navikt/ds-react": "^5.18.2",
"@navikt/ds-tailwind": "^5.18.2",
"@navikt/ds-tokens": "^5.18.2"
}
}
@@ -41,7 +41,7 @@ const Latest = ({ block }: LatestArticlesProps) => {
return (
<>
<Heading level="2" size="xlarge" className="mb-10 text-deepblue-800">
<Heading level="2" size="xlarge" className="mb-7 text-deepblue-800">
Siste fra Aksel
</Heading>
@@ -81,10 +81,6 @@ p.override-text-no-max {
color: inherit;
}
[id] > code > .inline-code-amp {
display: none;
}
/* Not in tailwindcss yet: https://github.com/tailwindlabs/tailwindcss/discussions/11486 */
.text-wrap-balance {
text-wrap: balance;
@@ -1,18 +1,8 @@
const InlineCode = (
props: React.HTMLAttributes<HTMLElement> & { noAmps?: boolean },
props: Pick<React.HTMLAttributes<HTMLElement>, "children">,
) => (
<code className="rounded-sm bg-surface-neutral-subtle px-1 py-05 font-mono text-sm font-semibold">
{!props?.noAmps && (
<span aria-hidden className="inline-code-amp">
`
</span>
)}
<span>{props.children}</span>
{!props?.noAmps && (
<span aria-hidden className="inline-code-amp">
`
</span>
)}
{props.children}
</code>
);
@@ -118,7 +118,7 @@ const serializers: Partial<PortableTextReactComponents> = {
},
marks: {
kbd: ({ text }) => <KBD>{text}</KBD>,
code: ({ text }) => <InlineCode noAmps>{text}</InlineCode>,
code: ({ text }) => <InlineCode>{text}</InlineCode>,
link: ({ text, value: { href } }: PortableTextMarkComponentProps<any>) => {
if (!href) {
return <span>{text}</span>;
@@ -0,0 +1,44 @@
import NextLink from "next/link";
import { HTMLAttributes } from "react";
import { BodyLong, Box, Heading, Link, Page } from "@navikt/ds-react";
interface UxTweaksProps extends HTMLAttributes<HTMLDivElement> {
/**
* Link to UXTweaks
*/
href: string;
/**
* Time in minutes to complete the survey
*/
length: number;
}
export const UxTweaks = ({ href, length, ...rest }: UxTweaksProps) => {
return (
<Page.Block width="md" {...rest}>
<Box
padding="6"
borderRadius="xlarge"
borderWidth="1"
borderColor="border-subtle"
className="space-y-3 bg-violet-50"
as="aside"
role="presentation"
>
<Heading
level="2"
size="medium"
id="uxtweaks-aside"
className="text-aksel-heading"
>
Vil du hjelpe oss å forbedre Aksel?
</Heading>
<BodyLong>{`Testen er anonym og tar ca ${length} minutter.`}</BodyLong>
<Link as={NextLink} href={href} target="_blank">
Delta i testen
</Link>
</Box>
</Page.Block>
);
};
@@ -44,5 +44,5 @@ export const Demo = {
export const args = {
index: 7,
desc: "Før du belger å bruke range, vurder om to enkelte datepickere for start/slutt-dato ville vært bedre. Range fungerer bedre for korte perioder innenfor en måned.",
desc: "Før du velger å bruke range, vurder om to separate datepickere i single mode er bedre. Range fungerer best for korte perioder innenfor en måned.",
};
@@ -32,5 +32,5 @@ export const Demo = {
export const args = {
index: 10,
desc: "Prop allowTwoDigitYear legger til støtte for 'yy'-format. Tilgjengelig year-range vil være fra 1943-2042 (2023).",
desc: "Prop 'allowTwoDigitYear' legger til støtte for 'yy'-format. Tilgjengelig year-range vil være 80 år bakover og 19 år framover. I 2024 tilsvarer det 1944-2043.",
};
@@ -1,15 +1,15 @@
import { Skeleton } from "@navikt/ds-react";
import { Box, Skeleton } from "@navikt/ds-react";
import { withDsExample } from "@/web/examples/withDsExample";
const Example = () => {
return (
<div className="w-56 rounded-lg p-6 shadow-xsmall ">
<Box padding="6" borderRadius="large" shadow="xsmall" className="w-56">
<Skeleton variant="circle" width={60} height={60} />
<Skeleton variant="text" width="100%" />
<Skeleton variant="text" width="100%" />
<Skeleton variant="text" width="100%" />
<Skeleton variant="text" width="80%" />
</div>
</Box>
);
};
@@ -20,4 +20,5 @@ export const Demo = {
export const args = {
index: 3,
desc: "Bruk av children vil gi en grå blokk som ofte ikke ligner på det faktiske elementet. Derfor anbefaler vi å manuelt bygge elementet ved hjelp av flere skeletons og 'height' + 'width'.",
};
@@ -32,5 +32,6 @@ export const Demo = {
};
export const args = {
index: 5,
index: 0,
desc: "I de fleste tilfellene vil du bruke 'width' og 'height' for å manuelt bygge opp en visuell representasjon av elementet du skal emulere. Disse settes da rett på style, slik at px, rem eller f.eks. '100%' fungerer.",
};
@@ -1,19 +1,20 @@
import { Heading, Skeleton } from "@navikt/ds-react";
import { Heading, Skeleton, VStack } from "@navikt/ds-react";
import { withDsExample } from "@/web/examples/withDsExample";
const Example = () => {
return (
<div className="grid w-48 gap-2">
<VStack gap="2">
<Skeleton variant="text" width="100%" />
{/* 'as'-prop kan brukes på all typografien vår med Skeleton */}
<Heading as={Skeleton} size="xlarge" width="100%">
Placeholder
</Heading>
<div style={{ fontSize: "5rem" }}>
<Skeleton variant="text" width="100%" />
</div>
</div>
</VStack>
);
};
@@ -1,9 +1,9 @@
import { Skeleton } from "@navikt/ds-react";
import { Skeleton, VStack } from "@navikt/ds-react";
import { withDsExample } from "@/web/examples/withDsExample";
const Example = () => {
return (
<div className="grid w-48 gap-2">
<VStack gap="2" className="w-48">
{/* variant="text" kan endre størelse med justering av font-size */}
<Skeleton variant="text" width="60%" />
@@ -11,7 +11,7 @@ const Example = () => {
<Skeleton variant="circle" width={60} height={60} />
<Skeleton variant="rectangle" width="100%" height={30} />
<Skeleton variant="rounded" width="100%" height={40} />
</div>
</VStack>
);
};
@@ -25,4 +25,5 @@ export const Demo = {
export const args = {
index: 1,
desc: "'text' (standard) representerer en enkel linje med tekst. 'circle', 'rectangle' og 'rounded' gir forskjellig visuell representasjon av elementet.",
};
+67 -54
View File
@@ -9,12 +9,13 @@ import {
PlayFillIcon,
} from "@navikt/aksel-icons";
import {
Bleed,
BodyLong,
Box,
Button,
HGrid,
Heading,
Page,
VStack,
useClientLayoutEffect,
} from "@navikt/ds-react";
import GodPraksisCardSimple from "@/cms/cards/GodPraksisCardSimple";
@@ -28,6 +29,7 @@ import { contributorsAll } from "@/sanity/queries";
import { AkselTemaT, NextPageT } from "@/types";
import { userPrefersReducedMotion } from "@/utils";
import { IntroCards } from "@/web/IntroCards";
import { UxTweaks } from "@/web/Uxtweaks";
import { AkselCubeAnimated } from "@/web/aksel-cube/AkselCube";
import { SEO } from "@/web/seo/SEO";
@@ -234,64 +236,75 @@ const Forside = ({ page, tema, blocks }: PageProps["props"]) => {
<Box background="surface-subtle" paddingBlock="0 32">
{/* God praksis */}
<Page.Block width="2xl" gutters>
<Box
background="surface-default"
borderWidth="1"
borderColor="border-subtle"
borderRadius="xlarge"
paddingBlock={{ xs: "12", sm: "20" }}
paddingInline={{ xs: "4", sm: "12" }}
className="-translate-y-48 sm:-translate-y-32"
>
{!reducedMotion && (
<Button
variant="tertiary-neutral"
size="small"
className="absolute right-2 top-2"
icon={
pause ? (
<PlayFillIcon title="Start animasjon" />
) : (
<PauseFillIcon title="Stopp animasjon" />
)
}
onClick={() => {
setPause(!pause);
localStorage.setItem(
"pause-animations",
JSON.stringify(!pause),
);
}}
/>
)}
<Box paddingInline={{ xs: "2", sm: "6" }} paddingBlock="0 12">
<Heading
level="2"
size="xlarge"
className="text-deepblue-700"
spacing
>
God praksis
</Heading>
<BodyLong size="large" className="max-w-3xl">
{page?.god_praksis_intro ??
"Alle som jobber med produktutvikling i NAV sitter på kunnskap og erfaring som er nyttig for andre. Derfor deler vi god praksis med hverandre her."}
</BodyLong>
<Page.Block
width="2xl"
gutters
className="-translate-y-48 sm:-translate-y-32"
>
<HGrid columns="1fr" gap="16">
<Box
background="surface-default"
borderWidth="1"
borderColor="border-subtle"
borderRadius="xlarge"
paddingBlock={{ xs: "12", sm: "16" }}
paddingInline={{ xs: "4", sm: "12" }}
className="relative"
>
<VStack gap="12">
{!reducedMotion && (
<Button
variant="tertiary-neutral"
size="small"
className="absolute right-2 top-2"
icon={
pause ? (
<PlayFillIcon title="Start animasjon" />
) : (
<PauseFillIcon title="Stopp animasjon" />
)
}
onClick={() => {
setPause(!pause);
localStorage.setItem(
"pause-animations",
JSON.stringify(!pause),
);
}}
/>
)}
<Box paddingInline={{ xs: "2", sm: "6" }}>
<Heading
level="2"
size="xlarge"
className="text-deepblue-700"
spacing
>
God praksis
</Heading>
<BodyLong size="large" className="max-w-3xl">
{page?.god_praksis_intro ??
"Alle som jobber med produktutvikling i NAV sitter på kunnskap og erfaring som er nyttig for andre. Derfor deler vi god praksis med hverandre her."}
</BodyLong>
</Box>
<ul className="grid gap-x-8 md:grid-cols-2 xl:grid-cols-3">
{tema.map((t) => (
<GodPraksisCardSimple key={t._id} node={t} />
))}
</ul>
</VStack>
</Box>
<UxTweaks
href="https://study.uxtweak.com/treetest/onFDOBRUT19G3KNNNa7DD"
length={3}
/>
<ul className="grid gap-x-8 md:grid-cols-2 xl:grid-cols-3">
{tema.map((t) => (
<GodPraksisCardSimple key={t._id} node={t} />
))}
</ul>
</Box>
<Bleed marginBlock={{ xs: "24", sm: "12" }} asChild>
<Box paddingInline={{ xs: "2", lg: "18" }}>
<FrontpageBlock blocks={blocks} />
</Box>
</Bleed>
</HGrid>
</Page.Block>
</Box>
</main>
@@ -101,7 +101,7 @@ const Page = ({ blogg, morePosts, publishDate }: PageProps["props"]) => {
<Heading
level="1"
size="xlarge"
className="text-wrap-balance mt-1 break-words text-5xl leading-[1.2] text-deepblue-800 [hyphens:_auto]"
className="text-wrap-balance mt-1 hyphens-auto break-words text-5xl leading-[1.2] text-deepblue-800 md:hyphens-none"
>
{blogg.heading}
</Heading>
@@ -3,6 +3,7 @@ import { StructureResolver } from "sanity/desk";
import {
CircleSlashIcon,
ComponentIcon,
EyeIcon,
FileTextIcon,
ImageIcon,
LightBulbIcon,
@@ -10,7 +11,6 @@ import {
PencilBoardIcon,
RectangleSectionsIcon,
TokenIcon,
EyeIcon,
} from "@navikt/aksel-icons";
import {
SANITY_API_VERSION,
@@ -62,7 +62,7 @@ export const block = {
title: "Inline-Kode",
value: "code",
icon: () => <CodeIcon aria-label="Kode" />,
component: ({ children }) => <InlineCode noAmps>{children}</InlineCode>,
component: ({ children }) => <InlineCode>{children}</InlineCode>,
},
{
title: "KBD",
+11 -25
View File
@@ -7,20 +7,12 @@ const options: docgen.ParserOptions = {
shouldRemoveUndefinedFromOptional: true,
propFilter: (prop) => {
if (prop.name === "className") return true;
if (prop.declarations !== undefined && prop.declarations.length > 0) {
const hasPropAdditionalDescription = prop.declarations.some(
(declaration) => {
return (
!declaration.fileName.includes("node_modules") ||
declaration.name === "RefAttributes"
);
},
);
return hasPropAdditionalDescription;
if (prop.name === "className" || prop.parent?.name === "RefAttributes") {
return true;
}
if (prop.parent?.fileName.includes("/node_modules/@types/react/")) {
return false;
}
return true;
},
};
@@ -36,7 +28,7 @@ const genDocs = () => {
!x.toLowerCase().includes("pictogram"),
);
const res: any[] = [];
const res: docgen.ComponentDoc[][] = [];
const fails: string[] = [];
files.forEach((file) => {
@@ -50,17 +42,11 @@ const genDocs = () => {
console.log({ Documented: res.length, fails });
const cleaned = res.flat().reduce(
(old, cur) => [
...old,
{
filePath: cur.filePath,
displayName: cur.displayName,
props: cur.props,
},
],
[],
);
const cleaned = res.flat().map((file) => ({
filePath: file.filePath,
displayName: file.displayName,
props: file.props,
}));
writeFileSync(`_docs.json`, JSON.stringify(cleaned, null, 2));
};
+17 -17
View File
@@ -3449,7 +3449,7 @@ __metadata:
languageName: node
linkType: hard
"@navikt/aksel-icons@^5.17.4, @navikt/aksel-icons@workspace:@navikt/aksel-icons":
"@navikt/aksel-icons@^5.18.1, @navikt/aksel-icons@workspace:@navikt/aksel-icons":
version: 0.0.0-use.local
resolution: "@navikt/aksel-icons@workspace:@navikt/aksel-icons"
dependencies:
@@ -3476,8 +3476,8 @@ __metadata:
version: 0.0.0-use.local
resolution: "@navikt/aksel-stylelint@workspace:@navikt/aksel-stylelint"
dependencies:
"@navikt/ds-css": ^5.17.4
"@navikt/ds-tokens": ^5.17.4
"@navikt/ds-css": ^5.18.1
"@navikt/ds-tokens": ^5.18.1
"@types/jest": ^29.0.0
concurrently: 7.2.1
copyfiles: 2.4.1
@@ -3495,7 +3495,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@navikt/aksel@workspace:@navikt/aksel"
dependencies:
"@navikt/ds-css": 5.17.4
"@navikt/ds-css": 5.18.1
"@types/inquirer": ^9.0.3
"@types/jest": ^29.0.0
axios: 1.6.0
@@ -3519,11 +3519,11 @@ __metadata:
languageName: unknown
linkType: soft
"@navikt/ds-css@*, @navikt/ds-css@5.17.4, @navikt/ds-css@^5.17.4, @navikt/ds-css@^5.9.2, @navikt/ds-css@workspace:@navikt/core/css":
"@navikt/ds-css@*, @navikt/ds-css@5.18.1, @navikt/ds-css@^5.18.1, @navikt/ds-css@^5.9.2, @navikt/ds-css@workspace:@navikt/core/css":
version: 0.0.0-use.local
resolution: "@navikt/ds-css@workspace:@navikt/core/css"
dependencies:
"@navikt/ds-tokens": ^5.17.4
"@navikt/ds-tokens": ^5.18.1
cssnano: 6.0.0
fast-glob: 3.2.11
lodash: 4.17.21
@@ -3536,13 +3536,13 @@ __metadata:
languageName: unknown
linkType: soft
"@navikt/ds-react@*, @navikt/ds-react@^5.17.4, @navikt/ds-react@^5.9.2, @navikt/ds-react@workspace:@navikt/core/react":
"@navikt/ds-react@*, @navikt/ds-react@^5.18.1, @navikt/ds-react@^5.9.2, @navikt/ds-react@workspace:@navikt/core/react":
version: 0.0.0-use.local
resolution: "@navikt/ds-react@workspace:@navikt/core/react"
dependencies:
"@floating-ui/react": 0.25.4
"@navikt/aksel-icons": ^5.17.4
"@navikt/ds-tokens": ^5.17.4
"@navikt/aksel-icons": ^5.18.1
"@navikt/ds-tokens": ^5.18.1
"@radix-ui/react-tabs": 1.0.0
"@radix-ui/react-toggle-group": 1.0.0
"@testing-library/dom": 8.13.0
@@ -3576,11 +3576,11 @@ __metadata:
languageName: unknown
linkType: soft
"@navikt/ds-tailwind@^5.17.4, @navikt/ds-tailwind@workspace:@navikt/core/tailwind":
"@navikt/ds-tailwind@^5.18.1, @navikt/ds-tailwind@workspace:@navikt/core/tailwind":
version: 0.0.0-use.local
resolution: "@navikt/ds-tailwind@workspace:@navikt/core/tailwind"
dependencies:
"@navikt/ds-tokens": ^5.17.4
"@navikt/ds-tokens": ^5.18.1
"@types/jest": ^29.0.0
color: 4.2.3
jest: ^29.0.0
@@ -3592,7 +3592,7 @@ __metadata:
languageName: unknown
linkType: soft
"@navikt/ds-tokens@^5.17.4, @navikt/ds-tokens@workspace:@navikt/core/tokens":
"@navikt/ds-tokens@^5.18.1, @navikt/ds-tokens@workspace:@navikt/core/tokens":
version: 0.0.0-use.local
resolution: "@navikt/ds-tokens@workspace:@navikt/core/tokens"
dependencies:
@@ -8842,11 +8842,11 @@ __metadata:
version: 0.0.0-use.local
resolution: "aksel.nav.no@workspace:aksel.nav.no"
dependencies:
"@navikt/aksel-icons": ^5.17.4
"@navikt/ds-css": ^5.17.4
"@navikt/ds-react": ^5.17.4
"@navikt/ds-tailwind": ^5.17.4
"@navikt/ds-tokens": ^5.17.4
"@navikt/aksel-icons": ^5.18.1
"@navikt/ds-css": ^5.18.1
"@navikt/ds-react": ^5.18.1
"@navikt/ds-tailwind": ^5.18.1
"@navikt/ds-tokens": ^5.18.1
languageName: unknown
linkType: soft