Compare commits

...
Author SHA1 Message Date
Ken 9102781d5c Lerna versionbump [ci skip] 2022-07-20 13:49:42 +02:00
Ken 4405c89d5f la til riktige transforms i codemod 2022-07-20 13:46:38 +02:00
Ken 309cd0fba3 fikset readme 2022-07-20 13:43:20 +02:00
Ken 5f1ca61501 Lerna versionbump [ci skip] 2022-07-20 13:16:20 +02:00
Ken a75622752e fikset pagination prop-error 2022-07-20 13:08:04 +02:00
Ken 62a00f745c fikset pagination codemod 2022-07-20 12:43:57 +02:00
Ken 7b946d76ac Merge branch 'master' into big-one-oh 2022-07-20 12:22:02 +02:00
Ken 0e42521c90 oppdatert gap button xsmall 2022-07-08 14:06:18 +02:00
Ken 95e5891b27 yarn lock 2022-07-08 13:16:56 +02:00
Ken 9230adaa89 Animert expandableRow 2022-07-08 13:15:39 +02:00
Ken 1885f0e935 Lokal versjon av react-animate-height (#1603) 2022-07-08 12:55:43 +02:00
Ken c718348749 Merge branch 'master' into big-one-oh 2022-07-08 10:55:09 +02:00
Andreas NordahlandKen 2166a7933f read more 1.0 (#1601)
* read more 1.0

* fikset small readmore

* fjernet ubrukt css

Co-authored-by: Ken <ken.aleksander@gmail.com>
2022-07-08 10:50:23 +02:00
Andreas Nordahl 70ba56e218 confirmation panel input ref (#1602) 2022-07-08 10:33:36 +02:00
69a21190b0 Button 1.0 (#1600)
Co-authored-by: Ken <26967723+KenAJoh@users.noreply.github.com>
Co-authored-by: Ken <ken.aleksander@gmail.com>
2022-07-08 10:32:07 +02:00
Andreas Nordahl 72c52f6cda remove renderContentWhenClosed prop (#1593)
* remove renderContentWhenClosed prop

* fix default controlled accordion story
2022-07-06 13:38:26 +02:00
Andreas Nordahl ae297ee3fd Merge branch 'master' into big-one-oh 2022-07-04 15:22:22 +02:00
Andreas Nordahl e3ce3d0a28 Merge branch 'master' into big-one-oh 2022-07-04 11:03:41 +02:00
Ken d4cf0d2b1e yarn lock 2022-07-01 14:07:45 +02:00
Ken 60f1397043 Lerna versionbump [ci skip] 2022-07-01 13:43:45 +02:00
Ken 4d78c35ec2 yarn lock 2022-07-01 13:40:43 +02:00
Ken 343fd910a8 Merge branch 'master' into big-one-oh 2022-07-01 13:40:19 +02:00
Ken 86c3545fb7 codemod readme 2022-07-01 13:39:29 +02:00
Ken f1341c6666 la til readmes 2022-07-01 13:13:47 +02:00
Ken 0949ba0b56 publishaccess 2022-07-01 12:41:12 +02:00
Ken 2ae9f382fb Lerna versionbump [ci skip] 2022-07-01 12:34:07 +02:00
Ken 95476ff04e codemod-versjon 2022-07-01 12:28:55 +02:00
Ken 12be3f9ba6 yarn lock 2022-07-01 12:26:54 +02:00
Ken 9d00cecc92 Merge branch 'master' into big-one-oh 2022-07-01 12:25:58 +02:00
Ken 755fd0cf3c Helptext figma-sync (#1586) 2022-06-30 16:22:11 +02:00
Ken 9295bda19d fjernet console.logs 2022-06-30 13:14:11 +02:00
Ken 2688b488e5 fikset bruk av mergeRefs i ds 2022-06-30 13:11:57 +02:00
Ken 6aacf70c3d fikset tooltip-infinite render bug 2022-06-30 13:09:27 +02:00
Ken d211a06f5f fikset checkbox tester 2022-06-30 09:52:29 +02:00
Ken e8ea9a8e34 Oppdatert small alert, banner -> fullWidth prop (#1584) 2022-06-30 09:36:03 +02:00
Ken 7fef4d5ef8 Merge branch 'master' into big-one-oh 2022-06-29 14:23:15 +02:00
Ken a7f04b4902 Erstattet "classnames" med "clsx" (#1577) 2022-06-29 10:31:40 +02:00
Ken e0fa04930d synced yarn lock 2022-06-24 09:17:47 +02:00
Ken 57cea8cb6d Merge branch 'master' into big-one-oh 2022-06-24 09:17:27 +02:00
Ken 1884c6345b Migrert popover og tooltip til floating-ui (#1571)
* oppdatert tooltip

* oppdatert popover

* fikset helptext popover

* fjernet popperjs

* yarn lock

* fikset ssr popover

* fjernet react-dom versjon for floating-ui

* fjernet bruk av placement type

* tooltip-tester

* tooltip-tester

* fikset popover outside-click

* render popover/tooltip with styles

* fjernet gamle tester

* focus-loss test for tooltip

* migration

* forsøk på react types fix

* ryddet opp i storybook

* tester å fjerne react-collapse typer

* type-install

* react-dom versjon

* gjorde types-react optional som peer

* yarn lock
2022-06-24 09:16:53 +02:00
Ken cb962e0332 Update Migrering-v1.md 2022-06-22 11:35:51 +02:00
Ken b246578fe9 yarn lock 2022-06-21 19:38:27 +02:00
Ken 1d42e573bf Merge branch 'master' into big-one-oh 2022-06-21 19:38:16 +02:00
Ken 1eea43c36f Merge branch 'master' into big-one-oh 2022-06-20 13:07:35 +02:00
Ken 6fe7227345 Merge branch 'master' into big-one-oh 2022-06-17 10:55:20 +02:00
Ken 362c8991c9 migration-guide 2022-06-17 10:54:32 +02:00
Ken 204bc1e010 [FIX] Alert synket med Figma (#1570)
* alert fullWidth -> banner

* fikset styling spacing
2022-06-17 10:49:51 +02:00
Kenandgithub-actions[bot] 7ac379364e Oppdatert useId og TextareaAutoSize (#1568)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-06-16 21:08:16 +02:00
Ken cff48a3c47 Merge branch 'master' into big-one-oh 2022-06-16 12:22:07 +02:00
Ken a8c4aa785f Merge branch 'master' into big-one-oh 2022-06-16 11:32:14 +02:00
Ken aebbaef65e textarea example 2022-06-15 23:34:08 +02:00
Ken 5009beddb0 textareaautosize 2022-06-15 23:28:52 +02:00
Ken 7247c19b15 textareaautosize 2022-06-15 22:36:19 +02:00
Ken 8e8d8a093f Merge branch 'master' into big-one-oh 2022-06-15 21:56:24 +02:00
Kenandgithub-actions[bot] 08bd97cfa1 Dependency updates for react-18 (#1567)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-06-15 21:55:31 +02:00
Ken cd80f303c8 Merge branch 'master' into big-one-oh 2022-06-15 15:38:44 +02:00
Ken 23a32607e7 grid stories 2022-06-14 20:10:16 +02:00
Ken 15a7ae44d4 Merge branch 'master' into big-one-oh 2022-06-14 19:54:14 +02:00
Ken 6e6d052283 header stories 2022-06-14 19:23:25 +02:00
Ken 0d8a35350b dropdown story 2022-06-14 18:57:12 +02:00
Ken 9bc50d4775 copytoclipboard stories 2022-06-14 18:51:39 +02:00
Ken 4bac85e5e2 Merge branch 'master' into big-one-oh 2022-06-14 13:22:48 +02:00
Ken 9868c49c37 Merge branch 'master' into big-one-oh 2022-06-14 10:13:19 +02:00
Ken 077454002c Merge branch 'master' into big-one-oh 2022-06-14 09:46:15 +02:00
Ken bc423af462 table-stories 2022-06-13 16:00:32 +02:00
Ken a009536b79 linkpanel stories 2022-06-13 15:52:55 +02:00
Ken c7735d179d guidepanel stoies 2022-06-13 15:48:17 +02:00
Ken 390e8ffd33 lint-fix 2022-06-13 15:40:54 +02:00
Ken 422d4548c5 fjernet shadow-card token 2022-06-13 15:40:29 +02:00
Ken f74b35a69a Fjernet StepindIcator fra kodebase (erstattes av Stepper) (#1559) 2022-06-13 15:37:12 +02:00
Ken 69497cad51 Fjernet navno pakker (#1557) 2022-06-13 15:33:45 +02:00
Ken 0e02a74089 migreringsguide 2022-06-13 15:33:23 +02:00
Ken 852d859f93 Fjernet Menu (#1556) 2022-06-13 15:29:43 +02:00
Ken 99fed38942 Merge branch 'master' into big-one-oh 2022-06-13 15:09:38 +02:00
Ken 1fbe799a56 Merge branch 'master' into big-one-oh 2022-06-13 12:07:27 +02:00
Ken 2b5527cbb3 yarn lock 2022-06-13 12:06:33 +02:00
Ken 88e951fa8c Merge branch 'master' into big-one-oh 2022-06-13 12:06:20 +02:00
Ken cd22e3e682 migreringsguide 2022-06-13 08:45:51 +02:00
Ken 4d28da3aa4 Oppdatert SpeechBubble API og styling (#1549) 2022-06-13 08:38:48 +02:00
Ken 51ed62741c yarn lock 2022-06-10 20:14:14 +02:00
Ken 560a1dc96d Merge branch 'master' into big-one-oh 2022-06-10 20:13:49 +02:00
KenandAndreas Nordahl 0fc11d8e88 Pagination (#1459)
* la til forwardref

* gjør forrige/neste usynlig

* large versjon

* sync pagination

* render pagination item as link

* types n stuff

* bump border radius on medium items

* update yarn.lock

* update yarn.lock

* oppdatert stories

* optional onpagechange

Co-authored-by: Andreas Nordahl <andnorda@gmail.com>
2022-06-10 15:25:09 +02:00
Ken 4b0505164f git merge master 2022-06-09 16:48:20 +02:00
Ken 02d7b89d2b Samversjonering (#1543) 2022-06-08 12:27:05 +02:00
Ken e38b4f87ed Merge branch 'master' into big-one-oh 2022-06-08 11:50:41 +02:00
Andreas Nordahl 7bf8900e0f oopsie 2022-06-07 11:11:13 +02:00
Andreas Nordahl 5337f2f716 add chromatic pr for big-one-oh (#1537) 2022-06-07 11:09:17 +02:00
Ken d4eae9ce0b [BREAKING] Oppdatert Tabs (#1536) 2022-06-07 11:05:19 +02:00
Ken e12f49660f Merge branch 'master' into big-one-oh 2022-06-07 10:42:32 +02:00
Andreas Nordahl 6e4716ef3e make divider internal to dropdown (#1534) 2022-06-03 14:42:19 +02:00
202 changed files with 4905 additions and 5666 deletions

No files matched your search

+5 -2
View File
@@ -2,9 +2,12 @@ name: Chromatic
on:
push:
branches: [master]
branches:
- master
pull_request:
branches: [master]
branches:
- master
- big-one-oh
jobs:
chromatic-pr:
-12
View File
@@ -1,12 +0,0 @@
import { Meta, Canvas } from "@storybook/addon-docs";
<Meta title="ds-react(deprecated)/intro" />
# Utdaterte pakker
På sikt vil komponentene under bli flyttet ut av ds-react eller erstattes av andre komponenter
- PageHeader -> @navikt/ds-react-navno
- MicroCard -> @navikt/ds-react-navno
- StepIndicator -> Horizontal `<Stepper />`
+1 -1
View File
@@ -7,7 +7,7 @@ export const parameters = {
options: {
storySort: {
method: "",
order: ["Intro", "ds-icons", "ds-react", ["Default"]],
order: ["Intro", "ds-icons", "ds-react", ["form"], ["Default"]],
locales: "",
},
},
+106
View File
@@ -0,0 +1,106 @@
# NAV designsystem Codemods
Collection of Codemods for easier migration between breaking changes.
Highly inspired by both MUI and NEXT
- [NEXT](https://nextjs.org/docs/advanced-features/codemods)
- [MUI](https://github.com/mui/material-ui/tree/master/packages/mui-codemod)
## Usage
Codemod transformations runs code-transformations programmatically in your project. This helps when migrating lots of breaking changes without spending hours doing it manually.
NOTE: This codemod only supports fairly "default" usage of components. Components used with dynamic imports, styled-components, non-default imports (example `import * as DS from "@navikt/ds-react"` or `from "@navikt/ds-react/cjs"`) will not work as expected.
```javascript
npx @navikt/ds-codemod <transform> <path>
```
transform - name of transform, see available transforms below.
path - files or directory to transform
--dry Do a dry-run, no code will be edited
--print Prints the changed output for comparison
## Beta (0.19.x) -> v1.0.0
`npx @navikt/ds-codemod v1.0.0/preset src`
### preset
Combines all avaliable codemods for migrating from beta -> v1.0.0. This transform should only be ran once.
Includes these transforms
- v1.0.0/tabs
- v1.0.0/chat
- v1.0.0/pagination
### tabs
`npx @navikt/ds-codemod v1.0.0/tabs src`
```diff
<Tabs
defaultValue="logg"
onChange={(x) => console.log(x)}
- loop
+ iconPosition="left"
>
<Tabs.List
- loop
>
<Tabs.Tab
value="logg"
label="logg"
- iconPosition="left"
/>
</Tabs.List>
<Tabs.Panel value="logg">TabPanel for Logg-tab</Tabs.Panel>
</Tabs>
```
### chat
`npx @navikt/ds-codemodmod v1.0.0/chat src`
```diff
-<SpeechBubble
+<Chat
- illustration={<Illustration />}
- topText="Ola Normann 01.01.21 14:00"
- illustrationBgColor="blue"
+ avatar={<Illustration />}
+ name="Ola Normann 01.01.21 14:00"
+ avatarBgColor="blue"
backgroundColor="red"
>
- <SpeechBubble.Bubble>
+ <Chat.Bubble>
Aute minim nisi sunt mollit duis sunt nulla minim non proident.
- </SpeechBubble.Bubble>
+ </Chat.Bubble>
-</SpeechBubble>
+</Chat>
```
### pagination
`npx @navikt/ds-codemod v1.0.0/pagination src`
This codemod should only be ran once, since the size-scale will keep decreasing for each subsequent iteration.
```diff
-<Pagiation />
+<Pagiation size="small"/>
-<Pagiation size="medium"/>
+<Pagiation size="small"/>
-<Pagiation size="small"/>
+<Pagiation size="xsmall"/>
```
## License
[MIT](https://github.com/navikt/Designsystemet/blob/master/LICENCE)
+12
View File
@@ -94,6 +94,18 @@ export function runTransform({ files, flags, transformer }) {
}
const TRANSFORMER_INQUIRER_CHOICES = [
{
name: "v1.0.0/preset: Runs all codemods for beta to v1 migration",
value: "v1.0.0/preset",
},
{
name: "v1.0.0/pagination: Fixes breaking API-changes from <Pagination /> component",
value: "v1.0.0/pagination",
},
{
name: "v1.0.0/tabs: Fixes breaking API-changes from <Tabs /> component",
value: "v1.0.0/tabs",
},
{
name: "v1.0.0/chat: Fixes breaking API-changes from <SpeechBubble /> (now <Chat/>) component",
value: "v1.0.0/chat",
+4 -2
View File
@@ -1,7 +1,6 @@
{
"name": "@navikt/ds-codemod",
"version": "1.0.2",
"private": true,
"version": "1.0.0-rc.4",
"description": "NAV designsystem codemods",
"author": "NAV Designsystem team",
"license": "MIT",
@@ -49,5 +48,8 @@
"sideEffects": false,
"engines": {
"node": ">=12.0.0"
},
"publishConfig": {
"access": "public"
}
}
@@ -6,6 +6,8 @@ export const Demo = () => {
<Pagination size="small" onPageChange={setPage} data-version="v1" />
<Pagination size="small" onPageChange={setPage} data-version="v1" />
<Pagination size="xsmall" onPageChange={setPage} data-version="v1" />
<Pagination onPageChange={setPage} />
<Pagination size="small" onPageChange={setPage} />
</div>
);
};
@@ -6,6 +6,8 @@ export const Demo = () => {
<Pagination size="small" onPageChange={setPage} data-version="v1" />
<Pagination size="small" onPageChange={setPage} data-version="v1" />
<Pagination size="xsmall" onPageChange={setPage} data-version="v1" />
<Pagination size="small" onPageChange={setPage} data-version="v1" />
<Pagination size="xsmall" onPageChange={setPage} data-version="v1" />
</div>
);
};
@@ -3,9 +3,9 @@ import { Pagination as DsPagination, Button } from "@navikt/ds-react";
export const Demo = () => {
return (
<div>
<DsPagination size="small" onPageChange={setPage} />
<DsPagination size="small" onPageChange={setPage} />
<DsPagination size="xsmall" onPageChange={setPage} />
<DsPagination size="small" onPageChange={setPage} data-version="v1" />
<DsPagination size="small" onPageChange={setPage} data-version="v1" />
<DsPagination size="xsmall" onPageChange={setPage} data-version="v1" />
</div>
);
};
@@ -3,9 +3,9 @@ import { Pagination, Button } from "@navikt/ds-react";
export const Demo = () => {
return (
<div>
<Pagination size="small" onPageChange={setPage} />
<Pagination size="small" onPageChange={setPage} />
<Pagination size="xsmall" onPageChange={setPage} />
<Pagination size="small" onPageChange={setPage} data-version="v1" />
<Pagination size="small" onPageChange={setPage} data-version="v1" />
<Pagination size="xsmall" onPageChange={setPage} data-version="v1" />
</div>
);
};
@@ -8,6 +8,22 @@ export default function transformer(file, api, options) {
const root = j(file.source);
function addMigrationTag(node) {
const attributes = node.openingElement.attributes;
const isMigrated = attributes.find(
(node) =>
node.type === "JSXAttribute" &&
node.name.name === "data-version" &&
node.value.value === "v1"
);
if (!isMigrated) {
attributes.push(
j.jsxAttribute(j.jsxIdentifier("data-version"), j.literal("v1"))
);
}
}
/* https://github.com/mui/material-ui/blob/master/packages/mui-codemod/src/v5.0.0/variant-prop.js */
function addExplicitStandardProp(node) {
const attributes = node.openingElement.attributes;
@@ -19,6 +35,7 @@ export default function transformer(file, api, options) {
attributes.unshift(
j.jsxAttribute(j.jsxIdentifier("size"), j.literal("small"))
);
addMigrationTag(node);
}
}
@@ -42,14 +59,20 @@ export default function transformer(file, api, options) {
const skip = !!parent.value.openingElement?.attributes.find(
(x) => x.name.name === "data-version" && x.value.value === "v1"
);
parent.value.openingElement?.attributes.forEach((x, index) => {
let didUpdate = false;
if (x.name?.name === "size" && x.type === "JSXAttribute" && !skip) {
/* addExplicitStandardProp */
if (x.value.value === "medium") {
x.value = j.literal("small");
didUpdate = true;
} else if (x.value.value === "small") {
x.value = j.literal("xsmall");
didUpdate = true;
}
didUpdate && addMigrationTag(parent.value);
}
});
addExplicitStandardProp(parent.value);
@@ -0,0 +1,15 @@
import transformTabs from "./tabs";
import transformChat from "./chat";
import transformPagination from "./pagination";
/**
* @param {import('jscodeshift').FileInfo} file
* @param {import('jscodeshift').API} api
*/
export default function transformer(file, api, options) {
file.source = transformTabs(file, api, options);
file.source = transformChat(file, api, options);
file.source = transformPagination(file, api, options);
return file.source;
}
+43
View File
@@ -0,0 +1,43 @@
# NAV designsystem styling
CSS-package containing design for @navikt/ds-react and more.
- All our tokens (Colors, border, shadows etc)
- Component-styling for `@navikt/ds-react` packages
- Normalize.css v8
- Fonts
## Installation
Install `@navikt/ds-css` with yarn
```bash
yarn add @navikt/ds-css
```
Install `@navikt/ds-css` with npm
```bash
npm install @navikt/ds-css
```
## Usage
Import styling for make it accessible. Only need to do this one place.
```javascript
import "@navikt/ds-css";
function App() {
return <Component />;
}
```
## Learn more
- [Designsystem documentation](https://aksel.nav.no/designsystem)
- [Storybook](https://master--5f801fb2aea7820022de2936.chromatic.com/)
## License
[MIT](https://github.com/navikt/Designsystemet/blob/master/LICENCE)
-4
View File
@@ -11,10 +11,6 @@
);
}
.navds-accordion .ReactCollapse--collapse {
transition: height 250ms cubic-bezier(0.4, 0, 0.2, 1);
}
.navds-accordion__item:focus-within {
position: relative;
}
-6
View File
@@ -34,18 +34,12 @@
.navds-alert--small {
padding: var(--navds-spacing-2) var(--navds-spacing-4);
gap: var(--navds-spacing-3);
}
.navds-alert--full-width {
border-radius: 0;
}
.navds-alert--full-width.navds-alert--small {
padding-right: var(--navds-spacing-4);
padding-left: var(--navds-spacing-4);
}
.navds-alert > .navds-alert__icon {
flex-shrink: 0;
font-size: 1.5rem;
+43 -17
View File
@@ -116,24 +116,35 @@
display: inline-flex;
cursor: pointer;
margin: 0;
text-align: center;
text-decoration: none;
border: none;
background: none;
border-radius: var(--navds-border-radius-small);
min-width: 48px;
padding: var(--navds-spacing-3);
padding: var(--navds-spacing-3) var(--navds-spacing-5);
align-items: center;
justify-content: center;
gap: var(--navds-spacing-2);
}
.navds-button--small {
padding-top: 0.375rem;
padding-bottom: 0.375rem;
min-width: 32px;
padding: 0.375rem var(--navds-spacing-3);
}
.navds-button--xsmall {
padding: 0.125rem 0.375rem;
min-width: 24px;
padding: 0.125rem var(--navds-spacing-2);
gap: var(--navds-spacing-1);
}
.navds-button--icon-only {
padding: var(--navds-spacing-3);
}
.navds-button--small.navds-button--icon-only {
padding: 0.375rem;
}
.navds-button--xsmall.navds-button--icon-only {
padding: var(--navds-spacing-1);
}
.navds-button:focus {
@@ -141,22 +152,37 @@
box-shadow: var(--navds-shadow-focus);
}
.navds-button__inner {
margin: auto;
display: flex;
align-items: center;
gap: var(--navds-spacing-2);
}
.navds-button__icon {
--navds-button-icon-adjustment: -4px;
.navds-button svg {
font-size: 1.5rem;
display: flex;
}
.navds-button--small svg,
.navds-button--xsmall svg {
.navds-button__icon:first-child {
margin-left: var(--navds-button-icon-adjustment);
}
.navds-button__icon:last-child {
margin-right: var(--navds-button-icon-adjustment);
}
.navds-button__icon:only-child {
margin: 0;
}
.navds-button--small .navds-button__icon {
--navds-button-icon-adjustment: -2px;
font-size: 1.25rem;
}
.navds-button--xsmall .navds-button__icon {
--navds-button-icon-adjustment: -2px;
font-size: 1rem;
}
/*************************
* .navds-button--primary *
*************************/
-55
View File
@@ -1,55 +0,0 @@
:root {
--navds-card-micro-color-text: var(--navds-semantic-color-text);
--navds-card-micro-color-background: var(--navds-global-color-orange-200);
--navds-card-micro-color-border: transparent;
--navds-card-micro-color-text-hover: var(--navds-semantic-color-link);
--navds-card-micro-color-background-hover: var(
--navds-semantic-color-component-background-light
);
--navds-card-micro-color-border-hover: var(
--navds-semantic-color-interaction-primary
);
--navds-card-micro-color-text-focus: var(--navds-semantic-color-link);
--navds-card-micro-color-background-focus: var(
--navds-semantic-color-component-background-light
);
--navds-card-micro-color-shadow-focus: var(--navds-semantic-color-focus);
--navds-card-micro-color-background-active: var(
--navds-semantic-color-interaction-primary
);
--navds-card-micro-color-text-active: var(
--navds-semantic-color-text-inverted
);
}
/*
MicroCard
*/
.navds-card__micro {
border-radius: var(--navds-border-radius-full);
color: var(--navds-card-micro-color-text);
display: inline-flex;
padding: var(--navds-spacing-1) var(--navds-spacing-2);
text-decoration: none;
background-color: var(--navds-card-micro-color-background);
border: 1px solid var(--navds-card-micro-color-border);
}
.navds-card__micro:hover {
background-color: var(--navds-card-micro-color-background-hover);
border-color: var(--navds-card-micro-color-border-hover);
color: var(--navds-card-micro-color-text-hover);
}
.navds-card__micro:focus {
background-color: var(--navds-card-micro-color-background-focus);
color: var(--navds-card-micro-color-text-focus);
outline: none;
box-shadow: 0 0 0 3px var(--navds-card-micro-color-shadow-focus);
}
.navds-card__micro:active {
background-color: var(--navds-card-micro-color-background-active);
color: var(--navds-card-micro-color-text-active);
}
+90
View File
@@ -0,0 +1,90 @@
:root {
--navds-chat-color-background: var(--navds-semantic-color-canvas-background);
--navds-chat-color-avatar: var(--navds-semantic-color-text);
--navds-chat-color-avatar-background: var(
--navds-semantic-color-canvas-background
);
}
.navds-chat {
display: flex;
align-items: flex-end;
gap: var(--navds-spacing-4);
padding-right: var(--navds-spacing-16);
}
.navds-chat--right {
flex-direction: row-reverse;
padding-right: 0;
padding-left: var(--navds-spacing-16);
}
.navds-chat__bubble-wrapper {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: var(--navds-spacing-3);
}
.navds-chat--right .navds-chat__bubble-wrapper {
align-items: flex-end;
}
.navds-chat__avatar {
align-items: center;
background: var(--navds-chat-color-avatar-background);
color: var(--navds-chat-color-avatar);
border-radius: var(--navds-border-radius-full);
display: flex;
flex-shrink: 0;
justify-content: center;
overflow: hidden;
height: 3rem;
width: 3rem;
}
.navds-chat__avatar svg {
align-self: center;
height: 100%;
width: 100%;
}
.navds-chat__bubble {
padding: 1rem;
box-shadow: var(--navds-shadow-small);
width: fit-content;
max-width: 37.5rem;
background-color: var(--navds-chat-color-background);
border-radius: var(--navds-border-radius-xlarge);
border-bottom-left-radius: 2px;
display: flex;
flex-direction: column;
gap: var(--navds-spacing-2);
}
.navds-chat__bubble:focus {
box-shadow: var(--navds-shadow-focus);
outline: none;
}
.navds-chat--right .navds-chat__bubble {
border-radius: var(--navds-border-radius-xlarge);
border-bottom-right-radius: 2px;
}
.navds-chat__top-text {
color: var(--navds-semantic-color-text-muted);
display: flex;
gap: var(--navds-spacing-2);
align-items: baseline;
}
.navds-chat--right .navds-chat__top-text {
align-self: flex-end;
}
.navds-chat__name {
font-weight: var(--navds-font-weight-bold);
}
-1
View File
@@ -37,7 +37,6 @@
resize: none;
width: 100%;
display: block;
min-height: 48px;
color: var(--navds-text-field-color-text);
}
+19 -11
View File
@@ -15,7 +15,6 @@
--navds-help-text-color-shadow-hover: var(
--navds-semantic-color-interaction-primary
);
--navds-help-text-color-shadow-focus: var(--navds-semantic-color-focus);
--navds-help-text-color-popover-background: var(
--navds-semantic-color-feedback-info-background
);
@@ -35,27 +34,36 @@
font-size: 1.5rem;
}
.navds-help-text__button:hover {
color: var(--navds-help-text-color-hover);
background: var(--navds-help-text-color-background-hover);
box-shadow: 0 0 0 2px var(--navds-help-text-color-shadow-hover);
}
.navds-help-text__button:focus {
outline: none;
color: var(--navds-help-text-color-focus);
background: var(--navds-help-text-color-background-focus);
box-shadow: 0 0 0 3px var(--navds-help-text-color-shadow-focus);
box-shadow: 0 0 0 1px var(--navds-global-color-white),
0 0 0 4px var(--navds-semantic-color-focus);
}
.navds-help-text__icon {
border-radius: var(--navds-border-radius-full);
}
.navds-help-text__popover > .navds-popover__arrow::before {
.navds-help-text__popover > .navds-popover__arrow {
background-color: var(--navds-help-text-color-popover-background);
}
.navds-help-text__popover.navds-popover {
background-color: var(--navds-help-text-color-popover-background);
--navds-popover-color-border: rgba(38 38 38 / 0.22);
}
.navds-help-text__icon--filled {
display: none;
}
.navds-help-text__button:where(:hover, :focus, [aria-expanded="true"])
> .navds-help-text__icon {
display: none;
}
.navds-help-text__button:where(:hover, :focus, [aria-expanded="true"])
> .navds-help-text__icon--filled {
display: inherit;
}
+1 -7
View File
@@ -7,12 +7,12 @@
@import "alert.css";
@import "button.css";
@import "content-container.css";
@import "chat.css";
@import "guide-panel.css";
@import "form/index.css";
@import "help-text.css";
@import "link.css";
@import "loader.css";
@import "menu.css";
@import "modal.css";
@import "pagination.css";
@import "popover.css";
@@ -22,12 +22,6 @@
@import "panel.css";
@import "link-panel.css";
@import "read-more.css";
@import "speech-bubble.css";
@import "step-indicator.css";
@import "stepper.css";
@import "table.css";
@import "tabs.css";
/* Navno spesific packages */
@import "page-header.css";
@import "card.css";
-102
View File
@@ -1,102 +0,0 @@
:root {
--navds-menu-color-text: var(--navds-semantic-color-link);
--navds-menu-color-text-hover: var(--navds-semantic-color-text);
--navds-menu-color-text-focus: var(--navds-semantic-color-text);
--navds-menu-color-background-hover: var(--navds-global-color-blue-50);
--navds-menu-color-text-active: var(--navds-semantic-color-text);
--navds-menu-outline-focus: var(--navds-semantic-color-focus);
}
.navds-menu__list {
list-style: none;
margin: 0;
padding: 0;
padding: 0 0.5rem;
}
.navds-menu__list--inner {
padding: 0;
}
.navds-menu-collapse__button {
cursor: pointer;
background-color: transparent;
border: none;
font: inherit;
text-align: inherit;
margin: 0;
width: 100%;
justify-content: space-between;
align-items: center;
font-weight: var(--navds-font-weight-bold);
color: var(--navds-menu-color-text);
}
.navds-menu-item,
.navds-menu-collapse__button {
font-weight: var(--navds-font-weight-bold);
display: flex;
padding: var(--navds-spacing-3) var(--navds-spacing-2);
text-decoration: none;
}
.navds-menu-item:focus,
.navds-menu-collapse__button:focus {
outline: 3px solid var(--navds-menu-outline-focus);
outline-offset: -3px;
color: var(--navds-menu-color-text-focus);
}
.navds-menu-collapse__button:focus > .navds-menu-collapse__expand-icon {
color: var(--navds-menu-color-focus);
}
.navds-menu-item:hover,
.navds-menu-collapse__button:hover {
background-color: var(--navds-menu-color-background-hover);
color: var(--navds-menu-color-text-hover);
}
.navds-menu-item--active {
box-shadow: -0.5rem 0 var(--navds-semantic-color-link);
color: var(--navds-menu-color-text-active);
text-decoration: none;
}
/* Collapse icon */
.navds-menu-collapse__expand-icon {
font-size: 1.5rem;
flex-shrink: 0;
margin-left: var(--navds-spacing-2);
}
.navds-menu-collapse__expand-icon--filled,
.navds-menu-collapse__button:hover > .navds-menu-collapse__expand-icon {
display: none;
}
.navds-menu-collapse__button:hover > .navds-menu-collapse__expand-icon--filled {
display: block;
}
.navds-menu-collapse--open
> .navds-menu-collapse__button
> .navds-menu-collapse__expand-icon {
transform: rotate(180deg);
}
/* Nesting levels */
.navds-menu__list[data-depth="1"] .navds-menu-collapse__button,
.navds-menu__list[data-depth="1"] .navds-menu-item {
padding-left: var(--navds-spacing-6);
}
.navds-menu__list[data-depth="2"] .navds-menu-collapse__button,
.navds-menu__list[data-depth="2"] .navds-menu-item {
padding-left: var(--navds-spacing-10);
}
.navds-menu__list[data-depth="3"] .navds-menu-collapse__button,
.navds-menu__list[data-depth="3"] .navds-menu-item {
padding-left: var(--navds-spacing-14);
}
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-css",
"version": "0.18.27",
"version": "1.0.0-rc.4",
"description": "Css for NAV Designsystem components",
"author": "NAV Designsystem team",
"keywords": [
@@ -20,7 +20,7 @@
"watch": "postcss --watch --use postcss-import -o dist/index.css index.css"
},
"devDependencies": {
"@navikt/ds-tokens": "^0.9.7",
"@navikt/ds-tokens": "^1.0.0-rc.4",
"normalize.css": "^8.0.1",
"postcss": "^8.3.6",
"postcss-cli": "^8.3.1",
-76
View File
@@ -1,76 +0,0 @@
:root {
--navds-page-header-color-background: var(
--navds-semantic-color-component-background-light
);
--navds-page-header-color-shadow-situation: var(
--navds-global-color-orange-400
);
--navds-page-header-color-shadow-product: var(--navds-global-color-green-400);
--navds-page-header-color-shadow-guide: var(
--navds-global-color-deepblue-400
);
}
.navds-page-header {
display: flex;
justify-content: center;
background-color: var(--navds-page-header-color-background);
padding: 1.5rem calc((100vw - 100%) / 2);
margin-left: calc((100vw - 100%) / -2);
margin-right: calc((100vw - 100%) / -2);
}
.navds-page-header__wrapper {
width: 100%;
max-width: 56.5rem;
text-align: left;
}
.navds-page-header__title {
display: flex;
margin: 0 auto;
width: 100%;
position: relative;
flex-direction: column;
}
.navds-page-header--left > .navds-page-header__wrapper {
text-align: left;
}
.navds-page-header--center > .navds-page-header__wrapper {
text-align: center;
}
.navds-page-header__illustration {
margin-right: 1.5rem;
pointer-events: none;
}
.navds-page-header__illustration > svg {
width: 5rem;
height: 5rem;
}
.navds-page-header--situation {
box-shadow: 0 -4px 0 var(--navds-page-header-color-shadow-situation) inset;
}
.navds-page-header--product {
box-shadow: 0 -4px 0 var(--navds-page-header-color-shadow-product) inset;
}
.navds-page-header--guide {
box-shadow: 0 -4px 0 var(--navds-page-header-color-shadow-guide) inset;
}
@media (max-width: 649px) {
.navds-page-header__illustration > svg {
width: 3rem;
height: 3rem;
}
.navds-page-header__title {
font-size: var(--navds-font-size-heading-xlarge);
}
}
+18 -72
View File
@@ -1,25 +1,12 @@
:root {
--navds-pagination-color-background-hover: var(
--navds-semantic-color-canvas-background
);
--navds-pagination-color-background-active: var(
--navds-semantic-color-interaction-primary-selected
);
--navds-pagination-color-text-active: var(
--navds-semantic-color-text-inverted
);
--navds-pagination-color-background-selected: var(
--navds-semantic-color-interaction-primary
--navds-semantic-color-interaction-primary-selected
);
--navds-pagination-color-text-selected: var(
--navds-semantic-color-text-inverted
);
}
.navds-pagination {
display: flex;
}
.navds-pagination__list {
margin: 0;
padding: 0;
@@ -32,89 +19,48 @@
display: flex;
align-items: center;
justify-content: center;
width: var(--navds-spacing-8);
width: var(--navds-spacing-12);
cursor: default;
}
.navds-pagination--small .navds-pagination__ellipsis {
width: var(--navds-spacing-8);
}
.navds-pagination--xsmall .navds-pagination__ellipsis {
width: var(--navds-spacing-6);
}
.navds-pagination__item {
display: flex;
cursor: pointer;
margin: 0;
text-decoration: none;
border: none;
background: none;
border-radius: var(--navds-border-radius-small);
padding: var(--navds-spacing-1) var(--navds-spacing-3);
color: var(--navds-semantic-color-text);
}
.navds-pagination--small .navds-pagination__item {
padding: 2px var(--navds-spacing-2);
}
.navds-pagination__item:hover {
background-color: var(--navds-pagination-color-background-hover);
}
.navds-pagination__item:active {
background-color: var(--navds-pagination-color-background-active);
color: var(--navds-pagination-color-text-active);
}
.navds-pagination__item:focus {
box-shadow: inset 0 0 0 2px var(--navds-semantic-color-focus),
inset 0 0 0 3px white;
outline: none;
.navds-pagination--medium .navds-pagination__item {
border-radius: var(--navds-border-radius-medium);
}
.navds-pagination__item[aria-current="true"] {
background-color: var(--navds-pagination-color-background-selected);
color: var(--navds-pagination-color-text-selected);
font-weight: var(--navds-font-weight-bold);
}
.navds-pagination__item[aria-current="true"]:focus {
box-shadow: inset 0 0 0 1px var(--navds-button-color-tertiary-border-active),
var(--navds-shadow-focus);
}
.navds-pagination__prev-next {
display: flex;
cursor: pointer;
margin: 0;
padding: 0;
border: none;
background: none;
text-decoration: underline;
color: var(--navds-semantic-color-link);
align-items: center;
gap: var(--navds-spacing-1);
border-radius: var(--navds-border-radius-small);
}
.navds-pagination__prev-next:focus {
outline: none;
box-shadow: inset 0 0 0 2px var(--navds-semantic-color-focus);
.navds-pagination--small .navds-pagination__prev-next {
padding: 0.375rem;
}
.navds-pagination__prev-next:disabled {
cursor: not-allowed;
opacity: 0.3;
}
.navds-pagination__prev-next-icon {
margin: 7px;
}
.navds-pagination--small .navds-pagination__prev-next-icon {
margin: var(--navds-spacing-1);
font-size: 1rem;
}
.navds-pagination__next-text {
padding-left: 0.75rem;
}
.navds-pagination__prev-text {
padding-right: 0.75rem;
.navds-pagination--xsmall .navds-pagination__prev-next {
padding: 0.125rem;
}
.navds-pagination--invisible {
+5 -27
View File
@@ -28,55 +28,33 @@
}
.navds-popover__arrow {
position: absolute;
z-index: -1;
}
.navds-popover__arrow::before {
display: block;
content: "";
transform: rotate(45deg);
background-color: var(--navds-popover-color-background);
border: 1px solid;
border-color: var(--navds-popover-color-border);
width: 1rem;
height: 1rem;
top: 0;
left: 0;
}
.navds-popover[data-popper-placement^="top"] > .navds-popover__arrow {
bottom: calc(1rem / -2);
}
.navds-popover[data-popper-placement^="top"] > .navds-popover__arrow::before {
.navds-popover[data-placement^="top"] > .navds-popover__arrow {
border-left-color: transparent;
border-top-color: transparent;
}
.navds-popover[data-popper-placement^="bottom"] > .navds-popover__arrow {
top: calc(1rem / -2);
}
/* prettier-ignore */
.navds-popover[data-popper-placement^="bottom"] > .navds-popover__arrow::before {
.navds-popover[data-placement^="bottom"] > .navds-popover__arrow {
border-bottom-color: transparent;
border-right-color: transparent;
}
.navds-popover[data-popper-placement^="left"] > .navds-popover__arrow {
right: calc(1rem / -2);
}
.navds-popover[data-popper-placement^="left"] > .navds-popover__arrow::before {
.navds-popover[data-placement^="left"] > .navds-popover__arrow {
border-left-color: transparent;
border-bottom-color: transparent;
}
.navds-popover[data-popper-placement^="right"] > .navds-popover__arrow {
left: calc(1rem / -2);
}
.navds-popover[data-popper-placement^="right"] > .navds-popover__arrow::before {
.navds-popover[data-placement^="right"] > .navds-popover__arrow {
border-right-color: transparent;
border-top-color: transparent;
}
+19 -20
View File
@@ -1,11 +1,11 @@
.navds-read-more {
.navds-read-more__button {
cursor: pointer;
margin: 0;
border: none;
background: none;
display: flex;
align-items: center;
gap: var(--navds-spacing-2);
align-items: flex-start;
gap: 0.125rem;
color: var(--navds-semantic-color-link);
border-radius: var(--navds-border-radius-small);
padding: var(--navds-spacing-1) var(--navds-spacing-1) var(--navds-spacing-1)
@@ -13,44 +13,43 @@
text-align: start;
}
.navds-read-more--small {
.navds-read-more--small .navds-read-more__button {
padding: 2px var(--navds-spacing-1) 2px 2px;
}
.navds-read-more:hover {
.navds-read-more__button:hover {
background-color: rgba(38 38 38 / 0.06);
}
.navds-read-more:active {
.navds-read-more__button:active {
background-color: rgba(38 38 38 / 0.1);
}
.navds-read-more:focus {
.navds-read-more__button:focus {
outline: none;
box-shadow: var(--navds-shadow-focus);
}
.navds-read-more + .ReactCollapse--collapse {
transition: all 250ms cubic-bezier(0.4, 0, 0.2, 1);
padding-top: var(--navds-spacing-1);
}
.navds-read-more:not(.navds-read-more--open) + .ReactCollapse--collapse {
padding: 0;
}
.navds-read-more__content {
margin-top: var(--navds-spacing-1);
border-left: 2px solid rgba(38 38 38 / 0.36);
margin-left: 11px;
padding-left: 15px;
padding-left: 11px;
}
.navds-read-more__expand-icon {
font-size: 1.25rem;
height: 1.5rem;
flex-shrink: 0;
}
.navds-read-more--open > .navds-read-more__expand-icon {
.navds-read-more--small .navds-read-more__expand-icon {
height: 1.25rem;
}
.navds-read-more--open
> .navds-read-more__button
> .navds-read-more__expand-icon {
transform: rotate(-180deg);
}
@@ -58,11 +57,11 @@
display: none;
}
.navds-read-more:hover
.navds-read-more__button:hover
> .navds-read-more__expand-icon.navds-read-more__expand-icon--filled {
display: inherit;
}
.navds-read-more:hover > .navds-read-more__expand-icon {
.navds-read-more__button:hover > .navds-read-more__expand-icon {
display: none;
}
-85
View File
@@ -1,85 +0,0 @@
:root {
--navds-speechbubble-color-background: var(
--navds-semantic-color-component-background-alternate
);
--navds-speechbubble-color-illustration: var(--navds-semantic-color-text);
--navds-speechbubble-color-illustration-background: var(
--navds-semantic-color-canvas-background
);
--navds-speechbubble-color-detail-text: var(
--navds-semantic-color-text-muted
);
}
.navds-speechbubble {
display: flex;
align-items: flex-end;
gap: var(--navds-spacing-4);
}
.navds-speechbubble--right {
flex-direction: row-reverse;
}
.navds-speechbubble__bubble-list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: var(--navds-spacing-3);
}
.navds-speechbubble--right .navds-speechbubble__bubble-list {
align-items: flex-end;
}
.navds-speechbubble__illustration {
align-items: center;
background: var(--navds-speechbubble-color-illustration-background);
color: var(--navds-speechbubble-color-illustration);
border-radius: var(--navds-border-radius-full);
display: flex;
flex-shrink: 0;
justify-content: center;
overflow: hidden;
height: 3rem;
width: 3rem;
}
.navds-speechbubble__illustration svg {
align-self: center;
height: 100%;
width: 100%;
}
.navds-speechbubble__bubble {
padding: 1rem;
box-shadow: var(--navds-shadow-small);
width: fit-content;
max-width: 37.5rem;
background-color: var(--navds-speechbubble-color-background);
border-radius: var(--navds-border-radius-xlarge);
border-bottom-left-radius: 2px;
display: flex;
flex-direction: column;
gap: var(--navds-spacing-2);
}
.navds-speechbubble__bubble:focus {
box-shadow: var(--navds-shadow-focus);
outline: none;
}
.navds-speechbubble--right .navds-speechbubble__bubble {
border-radius: var(--navds-border-radius-xlarge);
border-bottom-right-radius: 2px;
}
.navds-speechbubble__top-text {
color: var(--navds-speechbubble-color-detail-text);
}
.navds-speechbubble--right .navds-speechbubble__top-text {
align-self: flex-end;
}
-202
View File
@@ -1,202 +0,0 @@
:root {
--navds-step-indicator-color-step-line: var(--navds-semantic-color-divider);
--navds-step-indicator-color-step-text: var(--navds-semantic-color-text);
--navds-step-indicator-color-step-label: var(
--navds-semantic-color-interaction-primary
);
--navds-step-indicator-color-step-number-background: var(
--navds-semantic-color-canvas-background-light
);
--navds-step-indicator-color-step-number-background-finished: var(
--navds-semantic-color-canvas-background
);
--navds-step-indicator-color-step-number-shadow: var(
--navds-semantic-color-border
);
--navds-step-indicator-color-step-number-shadow-active: var(
--navds-semantic-color-interaction-primary-selected
);
--navds-step-indicator-color-step-number-shadow-hover: var(
--navds-semantic-color-interaction-primary
);
--navds-step-indicator-color-step-number-background-active: var(
--navds-semantic-color-interaction-primary-selected
);
--navds-step-indicator-color-step-number-text-active: var(
--navds-semantic-color-text-inverted
);
--navds-step-indicator-color-step-number-shadow-inset: var(
--navds-semantic-color-component-background-light
);
}
/* StepIndicator */
.navds-step-indicator {
display: flex;
align-items: flex-start;
padding: 0;
margin: 0;
}
/* Step */
.navds-step-indicator__step-wrapper {
padding: 0 var(--navds-spacing-2);
flex: 1;
position: relative;
list-style: none;
min-width: 10rem;
}
.navds-step-indicator__step-wrapper--hidelabel {
min-width: 5rem;
}
.navds-step-indicator__step {
display: flex;
align-items: center;
flex-direction: column;
padding: 0;
background: none;
border: none;
appearance: none;
width: 100%;
flex-shrink: 1;
color: var(--navds-step-indicator-color-step-text);
text-decoration: none;
cursor: pointer;
}
.navds-step-indicator__step-number {
flex-shrink: 0;
display: flex;
width: 2rem;
height: 2rem;
margin: 0.5rem;
border-radius: var(--navds-border-radius-full);
align-items: center;
justify-content: center;
box-shadow: 0 0 0 1px var(--navds-step-indicator-color-step-number-shadow);
background-color: var(--navds-step-indicator-color-step-number-background);
}
.navds-step-indicator__step-wrapper:first-child
> .navds-step-indicator__step
> .navds-step-indicator__step-number {
padding-right: 0;
}
.navds-step-indicator__step-wrapper:last-child
> .navds-step-indicator__step
> .navds-step-indicator__step-number {
padding-left: 0;
}
.navds-step-indicator__step-label {
width: 100%;
margin-top: var(--navds-spacing-4);
text-align: center;
color: var(--navds-step-indicator-color-step-label);
text-decoration: underline;
}
.navds-step-indicator__step-line {
flex: 1 1 100%;
position: absolute;
top: 1.5rem;
right: calc(50% + 2rem);
left: calc(-50% + 2rem);
display: block;
border-top: 2px solid var(--navds-step-indicator-color-step-line);
border-radius: var(--navds-border-radius-medium);
pointer-events: none;
}
.navds-step-indicator__step--active > .navds-step-indicator__step-label {
color: var(--navds-step-indicator-color-step-text);
font-weight: bold;
}
.navds-step-indicator__step--active > .navds-step-indicator__step-number {
background-color: var(
--navds-step-indicator-color-step-number-background-active
);
color: var(--navds-step-indicator-color-step-number-text-active);
box-shadow: 0 0 0 1px
var(--navds-step-indicator-color-step-number-shadow-active);
width: 2.5rem;
height: 2.5rem;
margin: 0.25rem;
}
.navds-step-indicator__step:focus {
outline: none;
}
.navds-step-indicator__step:hover > .navds-step-indicator__step-label {
text-decoration: none;
}
.navds-step-indicator__step.navds-step-indicator__step--disabled:hover
> .navds-step-indicator__step-label {
text-decoration: underline;
}
.navds-step-indicator__step--active > .navds-step-indicator__step-label,
.navds-step-indicator__step--active.navds-step-indicator__step--disabled:hover
> .navds-step-indicator__step-label {
text-decoration: none;
}
.navds-step-indicator__step:hover > .navds-step-indicator__step-number {
background: var(--navds-step-indicator-color-step-number-background);
box-shadow: 0 0 0 2px
var(--navds-step-indicator-color-step-number-shadow-hover);
}
.navds-step-indicator__step--active:hover > .navds-step-indicator__step-number {
background-color: var(
--navds-step-indicator-color-step-number-background-active
);
color: var(--navds-step-indicator-color-step-number-text-active);
box-shadow: 0 0 0 1px
var(--navds-step-indicator-color-step-number-shadow-active);
}
.navds-step-indicator__step:focus > .navds-step-indicator__step-number {
box-shadow: var(--navds-shadow-focus);
outline: none;
}
.navds-step-indicator__step--active:focus > .navds-step-indicator__step-number {
box-shadow: 0 0 0 1px inset
var(--navds-step-indicator-color-step-number-shadow-inset),
var(--navds-shadow-focus);
}
.navds-step-indicator__step--disabled:hover
> .navds-step-indicator__step-number {
box-shadow: 0 0 0 1px var(--navds-step-indicator-color-step-number-shadow);
}
.navds-step-indicator__step--disabled.navds-step-indicator__step--active:disabled
> .navds-step-indicator__step-number {
box-shadow: 0 0 0 1px
var(--navds-step-indicator-color-step-number-shadow-active);
}
/* Finished state */
.navds-step-indicator__step--finished > .navds-step-indicator__step-number,
.navds-step-indicator__step--finished.navds-step-indicator__step--disabled
> .navds-step-indicator__step-number {
background: var(--navds-step-indicator-color-step-number-background-finished);
}
/* Disabled */
.navds-step-indicator__step--disabled > .navds-step-indicator__step-number,
.navds-step-indicator__step--disabled > .navds-step-indicator__step-label {
opacity: 0.3;
}
.navds-step-indicator__step--disabled {
cursor: not-allowed;
}
+1 -2
View File
@@ -224,8 +224,7 @@
display: none;
}
.navds-table__expanded-row-collapse {
transition: height 250ms cubic-bezier(0.4, 0, 0.2, 1);
.navds-table__expanded-row-collapse:not([style*="height: 0px;"]) {
border-bottom: 1px solid var(--navds-table-cell-color-border);
}
+4
View File
@@ -74,6 +74,10 @@
gap: var(--navds-spacing-1);
}
.navds-tabs__tab-inner svg {
flex-shrink: 0;
}
.navds-tabs__tab-icon--top > .navds-tabs__tab-inner {
flex-direction: column;
gap: 0;
-3
View File
@@ -10,9 +10,6 @@
.navds-tooltip {
z-index: var(--navds-z-index-tooltip);
}
.navds-tooltip__inner {
background-color: var(--navds-semantic-color-component-background-inverted);
color: var(--navds-semantic-color-text-inverted);
border-radius: var(--navds-border-radius-small);
+32 -18
View File
@@ -1,28 +1,42 @@
# @navikt/ds-icons
# NAV icons
Leverer [NAVs ikoner](https://design.nav.no/resources/icons) i React og SVG.
All of NAVs own icons (400+ and counting)
## Installering
- As just SVG
- As React-components
```sh
// yarn
yarn add @navikt/ds-icons
## Installation
// npm
npm install @navikt/ds-icons
Install `@navikt/ds-icons` with yarn
```bash
yarn add @navikt/ds-icons
```
## Bruk
Install `@navikt/ds-icons` with npm
```jsx
/* ESM (anbefalt for tree-shaking)*/
import { Down } from "@navikt/ds-icons";
/* CJS */
import { Down } from "@navikt/cjs/ds-icons";
<Down aria-label="Åpne meny" />;
```bash
npm install @navikt/ds-icons
```
## Dokumentasjon
## Usage
- [Ikonsøk](https://design.nav.no/resources/icons)
Use as a regular React-component
```javascript
import { Star } from "@navikt/ds-icons";
function App() {
return <Star title="star" />;
}
```
## Learn more
- [Designsystem documentation](https://aksel.nav.no/designsystem)
- [Storybook](https://master--5f801fb2aea7820022de2936.chromatic.com/)
- [Icon-search](https://aksel.nav.no/designsystem/side/ikoner)
## License
[MIT](https://github.com/navikt/Designsystemet/blob/master/LICENCE)
+6 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-icons",
"version": "0.8.20",
"version": "1.0.0-rc.4",
"description": "NAVs egne ikoner i SVG og React format",
"repository": {
"type": "git",
@@ -31,19 +31,20 @@
"build": "yarn clean && copyfiles util/* src && yarn create-icons && concurrently \"tsc\" \"tsc -p tsconfig.esm.json\" && yarn create-package-json-pointers-to-esm",
"update": "ts-node figma/index.ts dotenv/config"
},
"dependencies": {
"uuid": "^8.3.2"
},
"peerDependencies": {
"@types/react": "^17.0.30 || ^18.0.0",
"react": "^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
},
"devDependencies": {
"@svgr/cli": "6.2.1",
"@types/lodash.startcase": "^4.4.6",
"@types/node": "^17.0.35",
"@types/rimraf": "3.0.2",
"@types/uuid": "^8.3.1",
"axios": "^0.21.3",
"concurrently": "7.2.1",
"copyfiles": "^2.4.1",
+37 -20
View File
@@ -1,22 +1,39 @@
import { useLayoutEffect, useState } from "react";
import { v4 } from "uuid";
//https://github.com/mui/material-ui/blob/master/packages/mui-utils/src/useId.ts
import React, { useEffect, useState } from "react";
const canUseDOM = (): boolean => {
return (
typeof window !== "undefined" &&
typeof window.document !== "undefined" &&
typeof window.document.createElement !== "undefined"
);
};
let globalId = 0;
function useGlobalId(idOverride?: string): string | undefined {
const [defaultId, setDefaultId] = useState(idOverride);
const id = idOverride || defaultId;
useEffect(() => {
if (defaultId == null) {
// Fallback to this default id when possible.
// Use the incrementing value for client-side rendering only.
// We can't use it server-side.
// If you want to use random values please consider the Birthday Problem: https://en.wikipedia.org/wiki/Birthday_problem
globalId += 1;
setDefaultId(`navds-id-${globalId}`);
}
}, [defaultId]);
return id;
}
export const useClientLayoutEffect = canUseDOM() ? useLayoutEffect : () => {};
export const useId: (id?: string) => string = (id) => {
const [newId, setNewId] = useState<string | undefined>(undefined);
useClientLayoutEffect(() => {
setNewId(v4());
}, []);
return id ?? newId ?? "";
};
// eslint-disable-next-line no-useless-concat -- Workaround for https://github.com/webpack/webpack/issues/14814
const maybeReactUseId: undefined | (() => string) = (React as any)[
// eslint-disable-next-line no-useless-concat
"useId" + ""
];
/**
*
* @example <div id={useId()} />
* @param idOverride
* @returns {string}
*/
export function useId(idOverride?: string): string | undefined {
if (maybeReactUseId !== undefined) {
const reactId = maybeReactUseId();
return idOverride ?? reactId;
}
// eslint-disable-next-line react-hooks/rules-of-hooks -- `useId` is invariant at runtime.
return useGlobalId(idOverride);
}
+43
View File
@@ -0,0 +1,43 @@
# NAV React-components
All of NAVs core React-components
- Uses styling from `@navikt/ds-css`
- All components implemented with React.forwardRef!
- Most components extend native html-elements.
## Installation
Install `@navikt/ds-react` with yarn
```bash
yarn add @navikt/ds-react
```
Install `@navikt/ds-react` with npm
```bash
npm install @navikt/ds-react
```
## Usage
Remember to also import @navikt/ds-css to apply styling!
```javascript
import { Button } from "@navikt/ds-react";
function App() {
return <Button variant="secondary">Click me!</Button>;
}
```
## Learn more
- [Designsystem documentation](https://aksel.nav.no/designsystem)
- [Component-docs](https://aksel.nav.no/designsystem/side/oversikt-komponenter)
- [Storybook](https://master--5f801fb2aea7820022de2936.chromatic.com/)
## License
[MIT](https://github.com/navikt/Designsystemet/blob/master/LICENCE)
+5
View File
@@ -1 +1,6 @@
import "@testing-library/jest-dom/extend-expect";
global.ResizeObserver = jest.fn().mockImplementation(() => ({
observe: jest.fn(),
unobserve: jest.fn(),
disconnect: jest.fn(),
}));
+12 -14
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-react",
"version": "0.19.25",
"version": "1.0.0-rc.4",
"description": "NAV designsystem react components",
"author": "NAV Designsystem team",
"license": "MIT",
@@ -35,28 +35,21 @@
"test": "jest"
},
"dependencies": {
"@floating-ui/react-dom": "0.6.0",
"@material-ui/core": "^4.12.3",
"@navikt/ds-icons": "^0.8.20",
"@popperjs/core": "^2.10.1",
"@floating-ui/react-dom-interactions": "0.6.6",
"@navikt/ds-icons": "^1.0.0-rc.4",
"@radix-ui/react-tabs": "0.1.5",
"@radix-ui/react-toggle-group": "0.1.5",
"classnames": "^2.2.6",
"react-collapse": "^5.1.0",
"react-merge-refs": "^1.1.0",
"react-modal": "3.15.1",
"react-popper": "^2.2.5",
"uuid": "^8.3.2"
"clsx": "^1.1.1",
"react-modal": "3.15.1"
},
"devDependencies": {
"@testing-library/dom": "8.13.0",
"@testing-library/jest-dom": "^5.16.0",
"@testing-library/react": "^13.0.0",
"@testing-library/user-event": "^14.0.0",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^14.2.0",
"@types/faker": "5.5.8",
"@types/jest": "^27.0.1",
"@types/node": "^17.0.35",
"@types/react-collapse": "^5.0.1",
"@types/react-modal": "^3.13.1",
"concurrently": "7.2.1",
"copyfiles": "^2.4.1",
@@ -75,5 +68,10 @@
"peerDependencies": {
"@types/react": "^17.0.30 || ^18.0.0",
"react": "^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
}
@@ -1,4 +1,4 @@
import cl from "classnames";
import cl from "clsx";
import React, { forwardRef } from "react";
import AccordionItem, { AccordionItemType } from "./AccordionItem";
import AccordionContent, { AccordionContentType } from "./AccordionContent";
@@ -1,6 +1,6 @@
import cl from "classnames";
import cl from "clsx";
import React, { forwardRef, useContext } from "react";
import { Collapse, UnmountClosed } from "react-collapse";
import AnimateHeight from "../util/AnimateHeight";
import { BodyLong } from "../typography";
import { AccordionItemContext } from "./AccordionItem";
@@ -8,8 +8,6 @@ export interface AccordionContentProps
extends React.HTMLAttributes<HTMLDivElement> {
/**
* Content inside Accordion.Content
* If renderContentWhenClosed is false in Accordion.Item,
* this will be removed from dom when Accordion is closed
*/
children: React.ReactNode;
}
@@ -19,7 +17,7 @@ export type AccordionContentType = React.ForwardRefExoticComponent<
>;
const AccordionContent: AccordionContentType = forwardRef(
({ children, className, id, ...rest }, ref) => {
({ children, className, ...rest }, ref) => {
const context = useContext(AccordionItemContext);
if (context === null) {
@@ -29,21 +27,17 @@ const AccordionContent: AccordionContentType = forwardRef(
return null;
}
const CollapseComponent = context.renderContentWhenClosed
? Collapse
: UnmountClosed;
return (
<div ref={ref} aria-labelledby={context.buttonId} {...rest}>
<CollapseComponent isOpened={context.open}>
<BodyLong
as="div"
className={cl("navds-accordion__content", className)}
>
{children}
</BodyLong>
</CollapseComponent>
</div>
<AnimateHeight height={context.open ? "auto" : 0} duration={250}>
<BodyLong
{...rest}
as="div"
ref={ref}
className={cl("navds-accordion__content", className)}
>
{children}
</BodyLong>
</AnimateHeight>
);
}
);
@@ -1,8 +1,8 @@
import { Expand, ExpandFilled } from "@navikt/ds-icons";
import cl from "classnames";
import cl from "clsx";
import React, { forwardRef, useContext } from "react";
import { Heading } from "..";
import { AccordionItemContext } from "./AccordionItem";
import { useClientLayoutEffect, useId } from "..";
export interface AccordionHeaderProps
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
@@ -17,15 +17,8 @@ export type AccordionHeaderType = React.ForwardRefExoticComponent<
>;
const AccordionHeader: AccordionHeaderType = forwardRef(
({ children, className, id, onClick, ...rest }, ref) => {
({ children, className, onClick, ...rest }, ref) => {
const context = useContext(AccordionItemContext);
const newId = useId(id);
const setButtonId = context && context.setButtonId;
useClientLayoutEffect(() => {
setButtonId && setButtonId(id ? newId : `accordionContent-${newId}`);
}, [setButtonId, newId]);
if (context === null) {
console.error(
@@ -45,18 +38,18 @@ const AccordionHeader: AccordionHeaderType = forwardRef(
<button
{...rest}
ref={ref}
id={context.buttonId}
className={cl(
"navds-accordion__header",
className,
"navds-heading",
"navds-heading--small"
)}
className={cl("navds-accordion__header", className)}
type="button"
onClick={handleClick}
aria-expanded={context.open}
>
<span className="navds-accordion__header-content">{children}</span>
<Heading
size="small"
as="span"
className="navds-accordion__header-content"
>
{children}
</Heading>
<Expand aria-hidden className="navds-accordion__expand-icon" />
<ExpandFilled
aria-hidden
@@ -1,4 +1,4 @@
import cl from "classnames";
import cl from "clsx";
import React, { createContext, forwardRef, useState } from "react";
export interface AccordionItemProps
@@ -18,11 +18,6 @@ export interface AccordionItemProps
* @default false
*/
defaultOpen?: boolean;
/**
* Removes content inside Accordion.Content if false from dom when closed
* @default false
*/
renderContentWhenClosed?: boolean;
}
export type AccordionItemType = React.ForwardRefExoticComponent<
@@ -32,9 +27,6 @@ export type AccordionItemType = React.ForwardRefExoticComponent<
export interface AccordionItemContextProps {
open: boolean;
toggleOpen: () => void;
setButtonId: (id: string) => void;
buttonId: string;
renderContentWhenClosed: boolean;
}
export const AccordionItemContext =
@@ -42,20 +34,10 @@ export const AccordionItemContext =
const AccordionItem: AccordionItemType = forwardRef(
(
{
children,
className,
open,
defaultOpen = false,
renderContentWhenClosed = false,
onClick,
id,
...rest
},
{ children, className, open, defaultOpen = false, onClick, id, ...rest },
ref
) => {
const [internalOpen, setInternalOpen] = useState<boolean>(defaultOpen);
const [buttonId, setButtonId] = useState("");
return (
<div
@@ -73,9 +55,6 @@ const AccordionItem: AccordionItemType = forwardRef(
setInternalOpen((iOpen) => !iOpen);
}
},
renderContentWhenClosed,
setButtonId,
buttonId,
}}
>
{children}
@@ -17,45 +17,45 @@ export default {
const Content = () => (
<Accordion.Content>
Magna aliquip aliquip fugiat nostrud nostrud velit pariatur veniam officia
laboris voluptate officia pariatur.Lorem est ex anim velit occaecat nisi qui
nostrud sit consectetur consectetur officia nostrud ullamco. Est ex duis
proident nostrud elit qui laborum anim minim eu eiusmod. Veniam in nostrud
sunt tempor velit incididunt sint ex dolor qui velit id eu. Deserunt magna
sunt velit in. Est exercitation id cillum qui do. Minim adipisicing nostrud
commodo proident occaecat aliquip nulla anim proident reprehenderit. Magna
ipsum officia veniam cupidatat duis veniam dolore reprehenderit mollit
velit.Ut consequat commodo minim occaecat id pariatur. Nisi enim tempor
laborum commodo. Tempor sit quis nostrud eu cupidatat sunt commodo
reprehenderit irure deserunt eiusmod ipsum. Exercitation quis commodo cillum
eiusmod eiusmod. Do laborum qui proident commodo adipisicing eiusmod id.
laboris voluptate officia pariatur. <a href="#Lorem">Lorem est</a> ex anim
velit occaecat nisi qui nostrud sit consectetur consectetur officia nostrud
ullamco. Est ex duis proident nostrud elit qui laborum anim minim eu
eiusmod. Veniam in nostrud sunt tempor velit incididunt sint ex dolor qui
velit id eu. Deserunt magna sunt velit in. Est exercitation id cillum qui
do. Minim adipisicing nostrud commodo proident occaecat aliquip nulla anim
proident reprehenderit. Magna ipsum officia veniam cupidatat duis veniam
dolore reprehenderit mollit velit. Ut consequat commodo minim occaecat id
pariatur. Nisi enim tempor laborum commodo. Tempor sit quis nostrud eu
cupidatat sunt commodo reprehenderit irure deserunt eiusmod ipsum.
Exercitation quis commodo cillum eiusmod eiusmod. Do laborum qui proident
commodo adipisicing eiusmod id.
</Accordion.Content>
);
export const Default = (props) => {
const Item = (props) => {
const [open, setOpen] = useState(false);
const Item = () =>
props.controlled ? (
<Accordion.Item
open={open}
renderContentWhenClosed={props.renderContentWhenClosed}
>
<Accordion.Header onClick={() => setOpen(!open)}>
Accordion header text
</Accordion.Header>
<Content />
</Accordion.Item>
) : (
<Accordion.Item renderContentWhenClosed={props.renderContentWhenClosed}>
<Accordion.Header>Accordion header text</Accordion.Header>
<Content />
</Accordion.Item>
);
return props.controlled ? (
<Accordion.Item open={open}>
<Accordion.Header onClick={() => setOpen(!open)}>
Accordion header text
</Accordion.Header>
<Content />
</Accordion.Item>
) : (
<Accordion.Item>
<Accordion.Header>Accordion header text</Accordion.Header>
<Content />
</Accordion.Item>
);
};
export const Default = (props) => {
return (
<div style={{ width: 500 }}>
<Accordion>
{[...Array(props.nItems ? props.nItems : 2)].map((_, y) => (
<Item key={y} />
<Item key={y} {...props} />
))}
</Accordion>
</div>
@@ -64,7 +64,6 @@ export const Default = (props) => {
Default.args = {
controlled: false,
renderContentWhenClosed: false,
nItems: 2,
};
+2 -2
View File
@@ -4,7 +4,7 @@ import {
SuccessColored,
WarningColored,
} from "@navikt/ds-icons";
import cl from "classnames";
import cl from "clsx";
import React, { forwardRef } from "react";
import { BodyLong } from "..";
@@ -23,7 +23,7 @@ export interface AlertProps extends React.HTMLAttributes<HTMLDivElement> {
*/
size?: "medium" | "small";
/**
* Toggles full-width Alert (removes border-radius)
* Removes border-radius
* @default false
*/
fullWidth?: boolean;
@@ -13,6 +13,12 @@ export default {
options: ["error", "warning", "info", "success"],
},
},
size: {
control: {
type: "radio",
options: ["medium", "small"],
},
},
},
};
@@ -36,6 +42,7 @@ export const Default = (props) => (
Default.args = {
children: "Id elit esse enim reprehenderit enim nisi veniam nostrud.",
fullWidth: false,
};
export const Small = () => {
+39 -14
View File
@@ -1,7 +1,6 @@
import React, { useRef, useState, forwardRef } from "react";
import mergeRefs from "react-merge-refs";
import cl from "classnames";
import { BodyShort, OverridableComponent, Loader } from "../";
import React, { useRef, useState, forwardRef, useMemo } from "react";
import cl from "clsx";
import { OverridableComponent, Loader, mergeRefs, Label } from "../";
import { useClientLayoutEffect } from "../util";
export interface ButtonProps
@@ -9,7 +8,7 @@ export interface ButtonProps
/**
* Button content
*/
children: React.ReactNode;
children?: React.ReactNode;
/**
* Changes design and interaction-visuals
* @default "primary"
@@ -30,6 +29,15 @@ export interface ButtonProps
* @default false
*/
loading?: boolean;
/**
* Button Icon
*/
icon?: React.ReactNode;
/**
* Icon position in Button
* @default "left"
*/
iconPosition?: "left" | "right";
}
export const Button: OverridableComponent<ButtonProps, HTMLButtonElement> =
@@ -44,14 +52,17 @@ export const Button: OverridableComponent<ButtonProps, HTMLButtonElement> =
loading = false,
disabled,
style,
icon,
iconPosition = "left",
...rest
},
ref
) => {
const buttonRef = useRef<HTMLButtonElement | null>(null);
const mergedRef = mergeRefs([buttonRef, ref]);
const [widthOverride, setWidthOverride] = useState<number>();
const mergedRef = useMemo(() => mergeRefs([buttonRef, ref]), [ref]);
useClientLayoutEffect(() => {
if (loading) {
const requestID = window.requestAnimationFrame(() => {
@@ -77,6 +88,7 @@ export const Button: OverridableComponent<ButtonProps, HTMLButtonElement> =
`navds-button--${size}`,
{
"navds-button--loading": widthOverride,
"navds-button--icon-only": !!icon && !children,
}
)}
style={{
@@ -85,14 +97,27 @@ export const Button: OverridableComponent<ButtonProps, HTMLButtonElement> =
}}
disabled={disabled ?? widthOverride ? true : undefined}
>
<BodyShort
as="span"
className="navds-button__inner"
size={size === "medium" ? "medium" : "small"}
aria-live="polite"
>
{widthOverride ? <Loader size={size} /> : children}
</BodyShort>
{widthOverride ? (
<Loader size={size} />
) : (
<>
{icon && iconPosition === "left" && (
<span className="navds-button__icon">{icon}</span>
)}
{children && (
<Label
as="span"
size={size === "medium" ? "medium" : "small"}
aria-live="polite"
>
{children}
</Label>
)}
{icon && iconPosition === "right" && (
<span className="navds-button__icon">{icon}</span>
)}
</>
)}
</Component>
);
}
@@ -18,7 +18,13 @@ export default {
size: {
control: {
type: "radio",
options: ["medium", "small"],
options: ["medium", "small", "xsmall"],
},
},
iconPosition: {
control: {
type: "radio",
options: ["left", "right"],
},
},
},
@@ -40,10 +46,14 @@ const varSwitch = {
export const Default = (props) => {
return (
<Button variant={props.variant} size={props.size} loading={props.loading}>
{props.icon ? <Star /> : null}
<Button
variant={props.variant}
size={props.size}
loading={props.loading}
icon={props.icon ? <Star /> : undefined}
iconPosition={props.iconPosition}
>
{props.children}
{props.icon ? <Star /> : null}
</Button>
);
};
@@ -51,6 +61,7 @@ export const Default = (props) => {
Default.args = {
icon: false,
loading: false,
iconPosition: "left",
children: "Knapp",
};
@@ -114,26 +125,31 @@ export const Icon = () => (
<div className="colgap">
<div className="rowgap">
{variants.map((variant) => (
<Button key={variant} variant={variant}>
<Star aria-hidden />
<span className="navds-sr-only">Stjerne</span>
</Button>
<Button
key={variant}
variant={variant}
icon={<Star title="Stjerne" />}
/>
))}
</div>
<div className="rowgap">
{variants.map((variant) => (
<Button key={variant} variant={variant} size="small">
<Star aria-hidden />
<span className="navds-sr-only">Stjerne</span>
</Button>
<Button
key={variant}
variant={variant}
size="small"
icon={<Star title="Stjerne" />}
/>
))}
</div>
<div className="rowgap">
{variants.map((variant) => (
<Button key={variant} variant={variant} size="xsmall">
<Star aria-hidden />
<span className="navds-sr-only">Stjerne</span>
</Button>
<Button
key={variant}
variant={variant}
size="xsmall"
icon={<Star title="Stjerne" />}
/>
))}
</div>
</div>
@@ -142,29 +158,40 @@ export const Icon = () => (
export const IconWText = () => (
<div className="colgap">
<div className="rowgap">
{variants.map((variant) => (
<Button key={variant} variant={variant}>
<Star aria-hidden />
{variants.map((variant, i) => (
<Button
key={variant}
variant={variant}
icon={<Star title="Stjerne" />}
iconPosition={i % 2 ? "left" : "right"}
>
{varSwitch[variant]}
<Star aria-hidden />
</Button>
))}
</div>
<div className="rowgap">
{variants.map((variant) => (
<Button key={variant} variant={variant} size="small">
<Star aria-hidden />
{variants.map((variant, i) => (
<Button
key={variant}
variant={variant}
size="small"
icon={<Star title="Stjerne" />}
iconPosition={i % 2 ? "left" : "right"}
>
{varSwitch[variant]}
<Star aria-hidden />
</Button>
))}
</div>
<div className="rowgap">
{variants.map((variant) => (
<Button key={variant} variant={variant} size="xsmall">
<Star aria-hidden />
{variants.map((variant, i) => (
<Button
key={variant}
variant={variant}
size="xsmall"
icon={<Star title="Stjerne" />}
iconPosition={i % 2 ? "left" : "right"}
>
{varSwitch[variant]}
<Star aria-hidden />
</Button>
))}
</div>
-32
View File
@@ -1,32 +0,0 @@
import React, { forwardRef } from "react";
import cl from "classnames";
import { OverridableComponent } from "..";
export interface MicroCardProps
extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
/**
* Link text
*/
children: React.ReactNode;
}
export const MicroCard: OverridableComponent<
MicroCardProps,
HTMLAnchorElement
> = forwardRef(({ className, as: Component = "a", children, ...rest }, ref) => (
<Component
ref={ref}
className={cl(
"navds-card__micro",
"navds-detail",
"navds-detail--small",
className
)}
title={children}
{...rest}
>
{children}
</Component>
));
export default MicroCard;
-2
View File
@@ -1,2 +0,0 @@
export { default as MicroCard } from "./MicroCard";
export { MicroCardProps } from "./MicroCard";
@@ -1,26 +0,0 @@
import { Meta, Canvas } from "@storybook/addon-docs";
import { MicroCard } from "../index.ts";
<Meta title="ds-react(deprecated)/card/intro" />
# Hvordan ta i bruk card
## MicroCard
Kan brukes som en vanlig lenke direkte:
```
<MicroCard href="/lenke/til/side">Lenketekst</MicroCard>
```
<Canvas>
<MicroCard href="/lenke/til/side">Lenketekst</MicroCard>
</Canvas>
Hvis man ønsker å ta i bruk nextjs sin `Link`-komponent:
```jsx
<Link href="/lenke/til/side" passHref>
<MicroCard>Lenketekst</MicroCard>
</Link>
```
@@ -1,16 +0,0 @@
import React from "react";
import { MicroCard } from "../index";
import { Meta } from "@storybook/react/types-6-0";
export default {
title: "ds-react(deprecated)/card",
component: MicroCard,
} as Meta;
export const All = () => {
return (
<div>
<h2>MicroCard</h2>
<MicroCard href="#">Sit laborum aliqua.</MicroCard>
</div>
);
};
+52
View File
@@ -0,0 +1,52 @@
import React, { forwardRef, HTMLAttributes } from "react";
import cl from "clsx";
import { Detail } from "../typography";
export interface BubbleProps extends HTMLAttributes<HTMLDivElement> {
/**
* Bubble text
*/
children: React.ReactNode;
/**
* name/sender on bubble
*/
name?: string;
/**
* Timestamp for sent message
*/
timestamp?: string;
/**
* Background color on bubble
*/
backgroundColor?: string;
}
export type BubbleType = React.ForwardRefExoticComponent<
BubbleProps & React.RefAttributes<HTMLDivElement>
>;
const Bubble: BubbleType = forwardRef(
({ children, className, name, timestamp, backgroundColor, ...rest }, ref) => {
return (
<div
ref={ref}
className={cl("navds-chat__bubble", className)}
style={{ backgroundColor: backgroundColor }}
tabIndex={0}
{...rest}
>
{(timestamp || name) && (
<div className="navds-chat__top-text">
{name && <Detail className="navds-chat__name">{name}</Detail>}
{timestamp && (
<Detail className="navds-chat__timestamp">{timestamp}</Detail>
)}
</div>
)}
{children}
</div>
);
}
);
export default Bubble;
+96
View File
@@ -0,0 +1,96 @@
import React, { forwardRef, HTMLAttributes } from "react";
import cl from "clsx";
import Bubble, { BubbleType } from "./Bubble";
import { BodyLong, BodyShort } from "..";
export interface ChatProps extends HTMLAttributes<HTMLDivElement> {
/**
* Children of type <Chat.Bubble />
*/
children: React.ReactNode;
/**
* Chat-message name
*/
name: string;
/**
* Timestamp for sent message
*/
timestamp?: string;
/**
* Avatar for messenger. Regular text for initials works to
*/
avatar: React.ReactNode;
/**
* Background color on bubbles
*/
backgroundColor?: string;
/**
* Background color for avatar
*/
avatarBgColor?: string;
/**
* Positions avatar and Bubbles
* @default "left"
*/
position?: "left" | "right";
}
interface ChatComponent
extends React.ForwardRefExoticComponent<
ChatProps & React.RefAttributes<HTMLDivElement>
> {
Bubble: BubbleType;
}
export const Chat = forwardRef<HTMLDivElement, ChatProps>(
(
{
children,
className,
name,
timestamp,
avatar,
position = "left",
avatarBgColor,
backgroundColor,
...rest
},
ref
) => {
return (
<div
ref={ref}
className={cl("navds-chat", className, `navds-chat--${position}`)}
{...rest}
>
<BodyShort
as="div"
className="navds-chat__avatar"
style={{ backgroundColor: avatarBgColor }}
>
{avatar}
</BodyShort>
<ol className="navds-chat__bubble-wrapper">
{React.Children.map(children, (child, i) => {
if (React.isValidElement(child)) {
return (
<BodyLong as="li">
{React.cloneElement(child, {
name: name && i === 0 ? name : undefined,
timestamp: timestamp && i === 0 ? timestamp : undefined,
backgroundColor,
...child.props,
})}
</BodyLong>
);
}
})}
</ol>
</div>
);
}
) as ChatComponent;
Chat.Bubble = Bubble;
export default Chat;
@@ -0,0 +1,202 @@
import React from "react";
import { Chat } from "../index";
import { Meta } from "@storybook/react/types-6-0";
export default {
title: "ds-react/Chat",
component: Chat,
argTypes: {
backgroundColor: {
control: {
type: "text",
},
},
avatarBgColor: {
control: {
type: "text",
},
},
},
} as Meta;
export const Default = (props) => {
return (
<Chat
avatar={props?.avatar ?? "ON"}
name={props?.name ?? "Ola Normann"}
timestamp={props?.timestamp ?? "01.01.21 14:00"}
avatarBgColor={props?.avatarBgColor}
backgroundColor={props?.backgroundColor}
>
<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>
);
};
Default.args = {
name: "Ola Normann",
timestamp: "01.01.21 14:00",
avatar: "ON",
};
export const Farger = () => {
return (
<Chat
avatar={"ON"}
name={"Ola Normann"}
timestamp={"01.01.21 14:00"}
avatarBgColor={"var(--navds-global-color-lightblue-200)"}
backgroundColor={"var(--navds-global-color-lightblue-100)"}
>
<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 Position = () => {
return (
<div className="colgap">
<Chat
avatar={"ON"}
name={"Ola Normann"}
timestamp={"01.01.21 14:00"}
backgroundColor="rgba(255, 249, 240, 1)"
avatarBgColor="rgba(255, 236, 204, 1)"
>
<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"
backgroundColor="rgba(230, 240, 255, 1)"
avatarBgColor="rgba(204, 225, 255, 1)"
>
<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"}
backgroundColor="rgba(255, 249, 240, 1)"
avatarBgColor="rgba(255, 236, 204, 1)"
>
<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>
);
};
export const Avatar = () => {
return (
<Chat
avatar={<Illustration />}
name={"Ola Normann"}
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>
);
+1
View File
@@ -0,0 +1 @@
export { default as Chat, ChatProps } from "./Chat";
@@ -1,5 +1,5 @@
import cl from "classnames";
import React, { forwardRef } from "react";
import cl from "clsx";
import { BodyLong, Checkbox, CheckboxProps, ErrorMessage } from "..";
import { useFormField } from "./useFormField";
@@ -27,7 +27,7 @@ export interface ConfirmationPanelProps
}
export const ConfirmationPanel = forwardRef<
HTMLDivElement,
HTMLInputElement,
ConfirmationPanelProps
>(({ className, children, label, ...props }, ref) => {
const { errorId, showErrorMsg, hasError, size, inputProps } = useFormField(
@@ -37,7 +37,6 @@ export const ConfirmationPanel = forwardRef<
return (
<div
ref={ref}
className={cl("navds-confirmation-panel", "navds-form-field", className, {
"navds-confirmation-panel--small": size === "small",
"navds-confirmation-panel--error": hasError,
@@ -53,7 +52,13 @@ export const ConfirmationPanel = forwardRef<
{children}
</BodyLong>
)}
<Checkbox {...props} {...inputProps} error={hasError} size={size}>
<Checkbox
ref={ref}
{...props}
{...inputProps}
error={hasError}
size={size}
>
{label}
</Checkbox>
</div>
@@ -1,4 +1,4 @@
import cl from "classnames";
import cl from "clsx";
import React, { FieldsetHTMLAttributes, forwardRef, useContext } from "react";
import { BodyShort, Detail, Label, ErrorMessage, omit } from "../..";
import { FormFieldProps } from "../useFormField";
+1 -1
View File
@@ -1,5 +1,5 @@
import React, { forwardRef, SelectHTMLAttributes } from "react";
import cl from "classnames";
import cl from "clsx";
import { Expand } from "@navikt/ds-icons";
import { BodyShort, Label, ErrorMessage, omit, Detail } from "..";
import { FormFieldProps, useFormField } from "./useFormField";
+1 -1
View File
@@ -1,4 +1,4 @@
import cl from "classnames";
import cl from "clsx";
import React, {
forwardRef,
InputHTMLAttributes,
+1 -1
View File
@@ -1,5 +1,5 @@
import React, { forwardRef, InputHTMLAttributes } from "react";
import cl from "classnames";
import cl from "clsx";
import { BodyShort, Detail, Label, ErrorMessage, omit } from "..";
import { FormFieldProps, useFormField } from "./useFormField";
+6 -6
View File
@@ -1,9 +1,9 @@
import React, { forwardRef, useState } from "react";
import cl from "classnames";
import TextareaAutosize from "@material-ui/core/TextareaAutosize";
import cl from "clsx";
import { BodyShort, Label, ErrorMessage, omit, Detail } from "..";
import { FormFieldProps, useFormField } from "./useFormField";
import { useId } from "..";
import TextareaAutosize from "../util/TextareaAutoSize";
/**
* TODO: Mulighet for lokalisering av sr-only/counter text
@@ -68,7 +68,7 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
...rest
} = props;
const maxLengthId = `TextareaMaxLength-${useId()}`;
const maxLengthId = useId();
const hasMaxLength = maxLength !== undefined && maxLength > 0;
const [controlledValue, setControlledValue] = useState<string>(
@@ -76,9 +76,9 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
);
const getMinRows = () => {
let rows = rest?.minRows && rest?.minRows >= 3 ? rest?.minRows : 3;
let rows = rest?.minRows ? rest?.minRows : 3;
if (size === "small") {
rows = rest?.minRows && rest?.minRows >= 2 ? rest?.minRows : 2;
rows = rest?.minRows ? rest?.minRows : 2;
}
return rows;
};
@@ -153,7 +153,7 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
}
)}
aria-describedby={cl(inputProps["aria-describedby"], {
[maxLengthId]: hasMaxLength,
[maxLengthId ?? ""]: hasMaxLength,
})}
/>
{hasMaxLength && (
@@ -1,6 +1,5 @@
import React from "react";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { act, fireEvent, render, screen } from "@testing-library/react";
import faker from "faker";
import { Checkbox, CheckboxGroup } from ".";
@@ -15,9 +14,8 @@ test("checkbox group chains onChange calls", async () => {
const onChange = jest.fn();
const value = faker.datatype.string();
const label = faker.datatype.string();
const user = userEvent.setup();
render(
const { getByLabelText } = render(
<CheckboxGroup legend="legend" onChange={onGroupChange}>
<Checkbox onChange={onChange} value={value}>
{label}
@@ -25,7 +23,9 @@ test("checkbox group chains onChange calls", async () => {
</CheckboxGroup>
);
await user.click(screen.getByLabelText(label));
await act(async () => {
fireEvent.click(getByLabelText(label));
});
expect(onGroupChange).toBeCalledTimes(1);
expect(onGroupChange).toBeCalledWith([value]);
@@ -42,10 +42,14 @@ describe("Checkbox handles controlled-state correctly", () => {
);
test("Checkbox is still checked after click when controlled", async () => {
const user = userEvent.setup();
render(<CheckboxComponent value={["value1", "value2"]} />);
await user.click(screen.getByLabelText("label1"));
await user.click(screen.getByLabelText("label2"));
const { getByLabelText } = render(
<CheckboxComponent value={["value1", "value2"]} />
);
await act(async () => {
fireEvent.click(getByLabelText("label1"));
fireEvent.click(getByLabelText("label2"));
});
expect((screen.getByLabelText("label1") as HTMLInputElement).checked).toBe(
true
@@ -58,22 +62,21 @@ describe("Checkbox handles controlled-state correctly", () => {
test("onChange called with expected values", async () => {
const onGroupChange = jest.fn();
const user = userEvent.setup();
render(
const { getByLabelText } = render(
<CheckboxComponent
onChange={onGroupChange}
value={["value1", "value2"]}
/>
);
await user.click(screen.getByLabelText("label1"));
await act(async () => {
fireEvent.click(getByLabelText("label1"));
expect(onGroupChange).lastCalledWith(["value2"]);
expect(onGroupChange).lastCalledWith(["value2"]);
await user.click(screen.getByLabelText("label2"));
expect(onGroupChange).lastCalledWith(["value1"]);
fireEvent.click(getByLabelText("label2"));
expect(onGroupChange).lastCalledWith(["value1"]);
});
});
test("Checkboxes updates after value-prop change", () => {
@@ -1,5 +1,5 @@
import React, { forwardRef, InputHTMLAttributes } from "react";
import cl from "classnames";
import cl from "clsx";
import useCheckbox from "./useCheckbox";
import { FormFieldProps } from "../useFormField";
import { BodyShort, Detail, omit } from "../..";
@@ -1,5 +1,5 @@
import React, { createContext, forwardRef, useContext, useState } from "react";
import cl from "classnames";
import cl from "clsx";
import { Fieldset, FieldsetProps, FieldsetContext } from "..";
export interface CheckboxGroupState {
@@ -1,5 +1,5 @@
import React, { forwardRef, HTMLAttributes } from "react";
import cl from "classnames";
import cl from "clsx";
import { Heading, BodyShort } from "../..";
import ErrorSummaryItem, { ErrorSummaryItemType } from "./ErrorSummaryItem";
import { useId } from "../../util";
@@ -58,13 +58,13 @@ export const ErrorSummary = forwardRef<HTMLDivElement, ErrorSummaryProps>(
tabIndex={-1}
aria-live="polite"
aria-relevant="all"
aria-labelledby={`error-summary-${headingId}`}
aria-labelledby={headingId}
>
<Heading
className="navds-error-summary__heading"
as={headingTag}
size="small"
id={`error-summary-${headingId}`}
id={headingId}
>
{heading}
</Heading>
@@ -1,5 +1,5 @@
import React, { forwardRef } from "react";
import cl from "classnames";
import cl from "clsx";
import { OverridableComponent } from "../..";
export interface ErrorSummaryItemProps
+1 -1
View File
@@ -1,5 +1,5 @@
import React, { forwardRef, InputHTMLAttributes } from "react";
import cl from "classnames";
import cl from "clsx";
import { BodyShort, Detail, omit } from "../..";
import { FormFieldProps } from "../useFormField";
import { useRadio } from "./useRadio";
@@ -1,5 +1,5 @@
import React, { forwardRef, useContext } from "react";
import cl from "classnames";
import cl from "clsx";
import { Fieldset, FieldsetContext, FieldsetProps } from "..";
import { useId } from "../..";
+11 -4
View File
@@ -1,14 +1,21 @@
import { Close, Search as SearchIcon } from "@navikt/ds-icons";
import cl from "classnames";
import cl from "clsx";
import React, {
forwardRef,
InputHTMLAttributes,
useCallback,
useMemo,
useRef,
useState,
} from "react";
import mergeRefs from "react-merge-refs";
import { BodyShort, ErrorMessage, Label, omit, useEventListener } from "../..";
import {
BodyShort,
ErrorMessage,
Label,
mergeRefs,
omit,
useEventListener,
} from "../..";
import { FormFieldProps, useFormField } from "../useFormField";
import SearchButton, { SearchButtonType } from "./SearchButton";
@@ -103,7 +110,7 @@ export const Search = forwardRef<HTMLInputElement, SearchProps>(
} = props;
const searchRef = useRef<HTMLInputElement | null>(null);
const mergedRef = mergeRefs([searchRef, ref]);
const mergedRef = useMemo(() => mergeRefs([searchRef, ref]), [ref]);
const [wrapperRef, setWrapperRef] = useState<HTMLDivElement | null>(null);
const [internalValue, setInternalValue] = useState(defaultValue ?? "");
@@ -1,5 +1,5 @@
import { Search } from "@navikt/ds-icons";
import cl from "classnames";
import cl from "clsx";
import React, { forwardRef, useContext } from "react";
import { Button, ButtonProps } from "../..";
import { SearchContext } from "./Search";
@@ -7,7 +7,7 @@ import { SearchContext } from "./Search";
export interface SearchButtonProps
extends Omit<ButtonProps, "size" | "children" | "variant"> {
/**
* Text set before <Search/> icon
* Text set after <Search/> icon
*/
children?: React.ReactNode;
}
@@ -36,9 +36,13 @@ const SearchButton: SearchButtonType = forwardRef(
variant={variant === "secondary" ? "secondary" : "primary"}
className={cl("navds-search__button-search", className)}
disabled={context?.disabled ?? disabled}
icon={
<Search
{...(children ? { "aria-hidden": true } : { title: "Søk" })}
/>
}
>
<Search aria-hidden />
{children ? children : <span className="navds-sr-only">Søk</span>}
{children}
</Button>
);
}
+1 -1
View File
@@ -1,5 +1,5 @@
import { useContext } from "react";
import cl from "classnames";
import cl from "clsx";
import { FieldsetContext } from "./index";
import { useId } from "../index";
+1 -1
View File
@@ -1,5 +1,5 @@
import React, { forwardRef, HTMLAttributes } from "react";
import cl from "classnames";
import cl from "clsx";
type Column = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
export interface CellProps extends HTMLAttributes<HTMLDivElement> {
@@ -1,5 +1,5 @@
import React, { forwardRef, HTMLAttributes } from "react";
import cl from "classnames";
import cl from "clsx";
export interface ContentContainerProps extends HTMLAttributes<HTMLDivElement> {
/**
+1 -1
View File
@@ -1,5 +1,5 @@
import React, { forwardRef, HTMLAttributes } from "react";
import cl from "classnames";
import cl from "clsx";
export interface GridProps extends HTMLAttributes<HTMLDivElement> {
/**
@@ -0,0 +1,68 @@
import * as React from "react";
import { BodyLong } from "../..";
import { Grid, Cell, ContentContainer } from "../index";
export default {
title: "ds-react/Grid",
component: { Grid, Cell },
parameters: {
layout: "fullscreen",
},
};
export const Default = () => {
return (
<>
<ContentContainer>
<span>
Grid har ikke blitt oppdatert siden 2020 og vil på sikt få større
endringer eller deprecates. Vi anbefaler derfor å ikke ta vår
grid-løsning i bruk for nå.
</span>
<Grid>
<Cell className="cell" xs={12} sm={6} lg={4}>
Kolonne
</Cell>
<Cell className="cell" xs={12} sm={6} lg={4}>
Kolonne
</Cell>
<Cell className="cell" xs={12} sm={12} lg={4}>
Kolonne
</Cell>
</Grid>
<style>{`.cell {padding: 1rem; background: repeating-linear-gradient(
45deg,
#d6d6d6,
#d6d6d6 10px,
transparent 10px,
transparent 20px
);}`}</style>
</ContentContainer>
</>
);
};
export const Contentcontainer = () => {
return (
<>
<ContentContainer className="container">
<BodyLong size="medium">-- Innhold --</BodyLong>
</ContentContainer>
<style>{`.container {
display: flex;
border-radius: var(--navds-border-radius-medium);
justify-content: center;
align-items: center;
margin-bottom: 1.5rem;
min-height: 10rem;
background: repeating-linear-gradient(
45deg,
#d6d6d6,
#d6d6d6 10px,
transparent 10px,
transparent 20px
);
}`}</style>
</>
);
};
@@ -1,79 +0,0 @@
import { Meta, Canvas } from "@storybook/addon-docs";
import { Grid, Cell } from "../../index";
<Meta title="ds-react/grid/intro" />
# Hvordan ta i bruk Grid
```jsx
<ContentContainer>
<Grid>
<Cell xs={12} sm={6} lg={4}>
Kolonne
</Cell>
<Cell xs={12} sm={6} lg={4}>
Kolonne
</Cell>
<Cell xs={12} sm={12} lg={4}>
Kolonne
</Cell>
</Grid>
</ContentContainer>
```
### ContentContainer
Denne fungerer som en wrapper som sentrer innholdet og passer på at anbefalt maksbredde ikke blir overskredet.
Stylingen som blir satt av den:
```css
.navds-content-container {
margin-left: auto;
margin-right: auto;
max-width: 79.5rem; # (1272px)
padding: var(--navds-spacing-4); # 1rem
}
@media (min-width: 448px) {
.navds-content-container {
padding: var(--navds-spacing-6); # 1.5rem
}
}
```
## Bredder
Bredden til hver `Cell` bestemmes av propsene `lg`, `md`, `sm`og `xs`
som respektivt styrer disse breakpointene
```jsx
type Column = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
/**
* Cell columns on width < 448px
*/
xs: Column;
/**
* Cell columns on min-width: 448
*/
sm?: Column;
/**
* Cell columns on min-width: 648
*/
md?: Column;
/**
* Cell columns on min-width: 960px
*/
lg?: Column;
```
Eks `xs={12} lg={4}` vil da si at `Cell` tar opp
4/12 av griddet når `width > 960px` og 12/12 av griddet
når skjermen er `width < 448px`
Griddet er dynamiskt, noe som vil si at griddet altids består av 12 columns
selv om skjermen er 1920px eller 400px. Innholdes "presses" altså sammen.
@@ -1,51 +0,0 @@
import * as React from "react";
import { BodyLong } from "../..";
import { Grid, Cell, ContentContainer } from "../index";
import "./styles.css";
export default {
title: "ds-react/grid",
component: { Grid, Cell },
parameters: {
layout: "fullscreen",
backgrounds: {
default: "NAV gray",
values: [
{
name: "white",
value: "#ffffff",
},
{
name: "NAV gray",
value: "#f1f1f1",
},
],
},
},
};
export const All = () => {
return (
<ContentContainer>
<Grid>
<Cell className={"navds-story-cell"} xs={12} sm={6} lg={4}>
Kolonne
</Cell>
<Cell className={"navds-story-cell"} xs={12} sm={6} lg={4}>
Kolonne
</Cell>
<Cell className={"navds-story-cell"} xs={12} sm={12} lg={4}>
Kolonne
</Cell>
</Grid>
</ContentContainer>
);
};
export const Contentcontainer = () => {
return (
<ContentContainer className={"navds-story-content-container"}>
<BodyLong size="medium">-- Innhold --</BodyLong>
</ContentContainer>
);
};
@@ -1,21 +0,0 @@
.navds-story-cell {
border-radius: var(--navds-border-radius-medium);
background: white;
padding: 1rem;
}
.navds-story-content-container {
display: flex;
border-radius: var(--navds-border-radius-medium);
justify-content: center;
align-items: center;
margin-bottom: 1.5rem;
min-height: 10rem;
background: repeating-linear-gradient(
45deg,
#d6d6d6,
#d6d6d6 10px,
transparent 10px,
transparent 20px
);
}
+1 -1
View File
@@ -1,5 +1,5 @@
import React, { forwardRef, HTMLAttributes } from "react";
import cl from "classnames";
import cl from "clsx";
import { DefaultIllustration } from "./Illustration";
export interface GuideProps
extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
@@ -1,6 +1,6 @@
import React, { forwardRef, HTMLAttributes } from "react";
import Guide from "./Guide";
import cl from "classnames";
import cl from "clsx";
export interface GuidePanelProps extends HTMLAttributes<HTMLDivElement> {
/**
+22 -8
View File
@@ -1,9 +1,7 @@
import { Helptext as HelpTextIcon } from "@navikt/ds-icons";
import { Placement } from "@popperjs/core";
import cl from "classnames";
import React, { forwardRef, useRef, useState } from "react";
import mergeRefs from "react-merge-refs";
import { Popover, PopoverProps } from "..";
import { Helptext as HelpTextIcon, HelptextFilled } from "@navikt/ds-icons";
import cl from "clsx";
import React, { forwardRef, useMemo, useRef, useState } from "react";
import { Popover, PopoverProps, mergeRefs } from "..";
export interface HelpTextProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
@@ -21,7 +19,19 @@ export interface HelpTextProps
* Default dialog-placement on open
* @default "top"
*/
placement?: Placement;
placement?:
| "top"
| "bottom"
| "right"
| "left"
| "top-start"
| "top-end"
| "bottom-start"
| "bottom-end"
| "right-start"
| "right-end"
| "left-start"
| "left-end";
}
export const HelpText = forwardRef<HTMLButtonElement, HelpTextProps>(
@@ -38,7 +48,7 @@ export const HelpText = forwardRef<HTMLButtonElement, HelpTextProps>(
ref
) => {
const buttonRef = useRef<HTMLButtonElement | null>(null);
const mergedRef = mergeRefs([buttonRef, ref]);
const mergedRef = useMemo(() => mergeRefs([buttonRef, ref]), [ref]);
const [open, setOpen] = useState(false);
return (
@@ -55,6 +65,10 @@ export const HelpText = forwardRef<HTMLButtonElement, HelpTextProps>(
aria-expanded={open}
>
<HelpTextIcon className="navds-help-text__icon" title={title} />
<HelptextFilled
className="navds-help-text__icon navds-help-text__icon--filled"
title={title}
/>
</button>
<Popover
onClose={() => setOpen(false)}
@@ -1,5 +1,5 @@
import React from "react";
import { TextField, HelpText } from "..";
import React, { useEffect, useRef } from "react";
import { HelpText } from "..";
export default {
title: "ds-react/HelpText",
@@ -9,6 +9,7 @@ export default {
control: {
type: "radio",
options: [
"top",
"bottom",
"right",
"left",
@@ -20,9 +21,6 @@ export default {
"right-end",
"left-start",
"left-end",
"auto",
"auto-start",
"auto-end",
],
},
},
@@ -47,17 +45,15 @@ Default.args = {
title: "show tooltip",
};
export const Inline = () => {
export const Open = () => {
const ref = useRef<HTMLButtonElement | null>(null);
useEffect(() => {
ref.current && ref.current.click();
}, []);
return (
<TextField
label={
<div style={{ display: "flex", gap: 8 }}>
Text field label
<HelpText title="show tooltip">
Id ullamco excepteur elit fugiat labore.
</HelpText>
</div>
}
/>
<HelpText ref={ref} title="show tooltip" strategy="fixed">
Id ullamco excepteur elit fugiat labore.
</HelpText>
);
};
+1 -7
View File
@@ -8,14 +8,12 @@ export * from "./guide-panel";
export * from "./link";
export * from "./link-panel";
export * from "./loader";
export * from "./menu";
export * from "./modal";
export * from "./pagination";
export * from "./panel";
export * from "./popover";
export * from "./read-more";
export * from "./speech-bubble";
export * from "./step-indicator";
export * from "./chat";
export * from "./stepper";
export * from "./tag";
export * from "./toggle-group";
@@ -24,7 +22,3 @@ export * from "./tabs";
export * from "./tooltip";
export * from "./typography";
export * from "./util";
/* Navno spesific packages */
export * from "./card";
export * from "./page-header";
@@ -1,7 +1,7 @@
import React, { forwardRef } from "react";
import { Panel, OverridableComponent } from "..";
import { Next } from "@navikt/ds-icons";
import cl from "classnames";
import cl from "clsx";
import { LinkPanelTitle, LinkPanelTitleType } from "./LinkPanelTitle";
import {
LinkPanelDescription,
@@ -1,5 +1,5 @@
import React, { forwardRef } from "react";
import cl from "classnames";
import cl from "clsx";
import { BodyLong } from "..";
interface LinkPanelDescriptionProps
@@ -1,5 +1,5 @@
import React, { forwardRef } from "react";
import cl from "classnames";
import cl from "clsx";
import { OverridableComponent } from "..";
interface LinkPanelTitleProps extends React.HTMLAttributes<HTMLDivElement> {
+1 -1
View File
@@ -1,5 +1,5 @@
import React, { forwardRef } from "react";
import cl from "classnames";
import cl from "clsx";
import { OverridableComponent } from "..";
export interface LinkProps
+1 -1
View File
@@ -1,5 +1,5 @@
import React, { forwardRef, SVGProps } from "react";
import cl from "classnames";
import cl from "clsx";
import { useId } from "..";
export interface LoaderProps extends SVGProps<SVGSVGElement> {
-36
View File
@@ -1,36 +0,0 @@
import React, { forwardRef } from "react";
import cl from "classnames";
import MenuItems from "./MenuItems";
import Item, { MenuItemType } from "./MenuItem";
import Collapse, { MenuCollapseType } from "./MenuCollapse";
export interface MenuProps extends React.HTMLAttributes<HTMLElement> {
children: React.ReactNode;
}
interface MenuComponent
extends React.ForwardRefExoticComponent<
MenuProps & React.RefAttributes<HTMLElement>
> {
Collapse: MenuCollapseType;
Item: MenuItemType;
}
export const Menu = forwardRef<HTMLElement, MenuProps>(
({ children, className, ...rest }, ref) => (
<nav
{...rest}
role="navigation"
ref={ref}
className={cl("navds-menu", className)}
>
<MenuItems>{children}</MenuItems>
</nav>
)
) as MenuComponent;
Menu.Collapse = Collapse;
Menu.Item = Item;
export default Menu;
@@ -1,80 +0,0 @@
import React, {
createContext,
forwardRef,
HTMLAttributes,
useContext,
useState,
} from "react";
import cl from "classnames";
import { Expand, ExpandFilled } from "@navikt/ds-icons";
import MenuItems from "./MenuItems";
export const NestingContext = createContext<{ depth: number }>({ depth: 1 });
const NestingProvider = ({ children }) => {
const context = useContext(NestingContext);
return (
<NestingContext.Provider
value={{
depth: context.depth + 1,
}}
>
{children}
</NestingContext.Provider>
);
};
export interface MenuCollapseProps extends HTMLAttributes<HTMLDivElement> {
title: string;
defaultOpen?: boolean;
children: React.ReactNode;
}
export type MenuCollapseType = React.ForwardRefExoticComponent<
MenuCollapseProps & React.RefAttributes<HTMLDivElement>
>;
export const Collapse: MenuCollapseType = forwardRef(
({ children, defaultOpen = false, title, className, ...rest }, ref) => {
const [isOpen, setIsOpen] = useState(defaultOpen);
const context = useContext(NestingContext);
return (
<div
{...rest}
ref={ref}
className={cl("navds-menu-collapse", className, {
"navds-menu-collapse--open": isOpen,
})}
>
<button
onClick={() => setIsOpen(!isOpen)}
className="navds-menu-collapse__button"
>
{title}
<Expand
title={isOpen ? "lukk navigasjons-skuff" : "åpne navigason-skuff"}
className="navds-menu-collapse__expand-icon"
/>
<ExpandFilled
title={isOpen ? "lukk navigasjons-skuff" : "åpne navigason-skuff"}
className="navds-menu-collapse__expand-icon navds-menu-collapse__expand-icon--filled"
/>
</button>
<NestingProvider>
{isOpen && (
<MenuItems
data-depth={context.depth}
className="navds-menu__list--inner"
>
{children}
</MenuItems>
)}
</NestingProvider>
</div>
);
}
);
export default Collapse;
-39
View File
@@ -1,39 +0,0 @@
import React, { forwardRef } from "react";
import { OverridableComponent } from "..";
import cl from "classnames";
export interface MenuItemProps
extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
children: React.ReactNode;
/**
* Sets active styling if true
* @default false
*/
active?: boolean;
}
export type MenuItemType = OverridableComponent<
MenuItemProps,
HTMLAnchorElement
>;
export const Item: MenuItemType = forwardRef(
(
{ children, as: Component = "a", active = false, className, ...rest },
ref
) => {
return (
<Component
ref={ref}
className={cl("navds-menu-item", className, {
"navds-menu-item--active": active,
})}
{...rest}
>
{children}
</Component>
);
}
);
export default Item;
-21
View File
@@ -1,21 +0,0 @@
import cl from "classnames";
import React from "react";
const MenuItems = ({
children,
className,
...rest
}: {
children: React.ReactNode;
className?: string;
}) => (
<ul {...rest} className={cl("navds-menu__list", className)}>
{React.Children.toArray(children).map((child, i) => (
<li key={i} className="navds-menu__list-item">
{child}
</li>
))}
</ul>
);
export default MenuItems;
-3
View File
@@ -1,3 +0,0 @@
export { default as Menu, MenuProps } from "./Menu";
export { MenuCollapseProps } from "./MenuCollapse";
export { MenuItemProps } from "./MenuItem";
@@ -1,93 +0,0 @@
import { Meta, Canvas } from "@storybook/addon-docs";
import { Menu } from "../../index";
<Meta title="ds-react/menu/intro" />
# Hvordan ta i bruk Menu
```jsx
<Menu>
<Menu.Item href="#leo">Leo</Menu.Item>
<Menu.Collapse title="Proin">
<Menu.Item href="#nulla" active>
Nulla
</Menu.Item>
<Menu.Item href="#luctus">Luctus</Menu.Item>
</Menu.Collapse>
<Menu.Collapse title="Accumsan">
<Menu.Item href="#justo" aria-current="page">
Justo
</Menu.Item>
<Menu.Collapse title="Proin">
<Menu.Item href="#nulla">Nulla</Menu.Item>
<Menu.Item href="#luctus">Luctus</Menu.Item>
</Menu.Collapse>
</Menu.Collapse>
</Menu>
```
<Canvas>
<Menu>
<Menu.Item href="#leo">Leo</Menu.Item>
<Menu.Collapse title="Proin">
<Menu.Item href="#nulla" active>
Nulla
</Menu.Item>
<Menu.Item href="#luctus">Luctus</Menu.Item>
</Menu.Collapse>
<Menu.Collapse title="Accumsan">
<Menu.Item href="#justo">Justo</Menu.Item>
<Menu.Collapse title="Proin">
<Menu.Item href="#nulla">Nulla</Menu.Item>
<Menu.Item href="#luctus">Luctus</Menu.Item>
</Menu.Collapse>
</Menu.Collapse>
</Menu>
</Canvas>
## Elementer i menyen
Menyen har to typer elementer man kan bruke: `Collapse` for nesting og `Item` for navigasjonslenker på siden.
<Canvas>
<div>
<h2>Item</h2>
<Menu>
<Menu.Item href="#leo">Lenke</Menu.Item>
<Menu.Item href="#leo">Lenke</Menu.Item>
<Menu.Item href="#leo">Lenke</Menu.Item>
<Menu.Item href="#leo">Lenke</Menu.Item>
<Menu.Item href="#leo">Lenke</Menu.Item>
</Menu>
<h2>Collapses + Item</h2>
<Menu>
<Menu.Collapse title="Proin">
<Menu.Item href="#nulla" active>
Nulla
</Menu.Item>
<Menu.Item href="#luctus">Luctus</Menu.Item>
</Menu.Collapse>
<Menu.Collapse title="Accumsan">
<Menu.Item href="#justo">Justo</Menu.Item>
<Menu.Collapse title="Proin">
<Menu.Item href="#nulla">Nulla</Menu.Item>
<Menu.Item href="#luctus">Luctus</Menu.Item>
</Menu.Collapse>
</Menu.Collapse>
<Menu.Item href="#leo">Lenke</Menu.Item>
<Menu.Item href="#leo">Lenke</Menu.Item>
</Menu>
</div>
</Canvas>
`Menu.Item` er implementert med `OverridableComponent`, noe som
gjør at man kan ta i bruk eks react-router slik:
```jsx
<Menu.Item as={NavLink} activeClassName="navds-menu-item--active" to="/1">
Lenketekst
</Menu.Item>
```
Her er `NavLink` fra `react-router-dom` brukt, og man får da
samtidig bruke alle propsene til denne komponenten som da er `activeClassName` her.
@@ -1,139 +0,0 @@
import * as React from "react";
import cl from "classnames";
import { Menu } from "../index";
import { NavLink, HashRouter as Router } from "react-router-dom";
import { MenuItemProps } from "../MenuItem";
export default {
title: "ds-react/menu",
component: { Menu },
};
export const All = () => (
<div
style={{
background: "white",
maxWidth: 288,
}}
>
<h2>Only Menu.Items</h2>
<Menu>
<Menu.Item href="#leo">Leo</Menu.Item>
<Menu.Item href="#justo">Justo</Menu.Item>
<Menu.Item href="#pariatur" active aria-current="page">
Pariatur
</Menu.Item>
<Menu.Item href="#nulla">Nulla</Menu.Item>
<Menu.Item href="#luctus">Luctus</Menu.Item>
<Menu.Item href="#justo">Justo</Menu.Item>
<Menu.Item href="#pariatur">Pariatur</Menu.Item>
</Menu>
<h2>With Collapse</h2>
<Menu>
<Menu.Item href="#leo">Leo</Menu.Item>
<Menu.Collapse title="Proin">
<Menu.Item href="#nulla" active>
Nulla
</Menu.Item>
<Menu.Item href="#luctus">Luctus</Menu.Item>
</Menu.Collapse>
<Menu.Collapse title="Accumsan">
<Menu.Item href="#justo" aria-current="page">
Justo
</Menu.Item>
<Menu.Item href="#pariatur" active aria-current="page">
Pariatur
</Menu.Item>
<Menu.Collapse title="Proin">
<Menu.Item href="#nulla" active>
Nulla
</Menu.Item>
<Menu.Collapse title="Proin">
<Menu.Item href="#nulla" active>
Nulla
</Menu.Item>
<Menu.Item href="#luctus">Luctus</Menu.Item>
</Menu.Collapse>
<Menu.Item href="#luctus">Luctus</Menu.Item>
</Menu.Collapse>
</Menu.Collapse>
<Menu.Item href="#justo" active>
Justo
</Menu.Item>
<Menu.Item href="#pariatur">Pariatur</Menu.Item>
</Menu>
</div>
);
export const ReactRouter = () => {
const MenuItemLink = (props: MenuItemProps & { to: string }) => {
const { to } = props;
const CustomLink = React.useMemo(
() => (props: MenuItemProps) => (
<NavLink
{...props}
to={to}
className={({ isActive }) =>
cl(props.className, {
"navds-menu-item--active": isActive,
})
}
/>
),
[to]
);
return (
<Menu.Item {...props} as={CustomLink}>
Nivå 2 innrykk 2 rems
</Menu.Item>
);
};
return (
<Menu>
<Menu.Collapse title="Nivå 1 - 3 rems høy">
<MenuItemLink to="/1">Nivå 2 innrykk 2 rems</MenuItemLink>
<MenuItemLink to="/2">Subtitle 3</MenuItemLink>
</Menu.Collapse>
<Menu.Collapse title="Skjema og søknad">
<Menu.Collapse title="Satser">
<MenuItemLink to="/3">
Nivå 3 - 3 rems innrykk Har du rett til dagpenger når du mottar
annen økonomisk støtte fra NAV?
</MenuItemLink>
</Menu.Collapse>
<MenuItemLink to="/4">Subtitle 2</MenuItemLink>
<MenuItemLink to="/5">Subtitle 3</MenuItemLink>
</Menu.Collapse>
<Menu.Collapse title="Sakbehandlingstider">
<Menu.Collapse title="Subtitle 4 Lang tittel på andre nivå lorem ipsum">
<MenuItemLink to="/6">Subtitle 5</MenuItemLink>
</Menu.Collapse>
</Menu.Collapse>
<MenuItemLink to="/7">Internasjonalt</MenuItemLink>
<Menu.Collapse title="Meld fra om endringer lang tittel på første nivå">
<MenuItemLink to="/8">Subtitle 6</MenuItemLink>
</Menu.Collapse>
<MenuItemLink to="/9">Nivå 1</MenuItemLink>
</Menu>
);
};
ReactRouter.decorators = [
(Story) => (
<Router>
<div
style={{
background: "white",
maxWidth: 288,
}}
>
<Story />
</div>
</Router>
),
];
+6 -8
View File
@@ -1,9 +1,8 @@
import React, { forwardRef, useRef } from "react";
import cl from "classnames";
import React, { forwardRef, useMemo, useRef } from "react";
import cl from "clsx";
import ReactModal from "react-modal";
import mergeRefs from "react-merge-refs";
import { Close } from "@navikt/ds-icons";
import { Button } from "..";
import { Button, mergeRefs } from "..";
import ModalContent, { ModalContentType } from "./ModalContent";
export interface ModalProps {
@@ -77,7 +76,7 @@ export const Modal = forwardRef<ReactModal, ModalProps>(
ref
) => {
const modalRef = useRef<ReactModal | null>(null);
const mergedRef = mergeRefs([modalRef, ref]);
const mergedRef = useMemo(() => mergeRefs([modalRef, ref]), [ref]);
const buttonRef = useRef<HTMLButtonElement>(null);
const onModalCloseRequest = (e) => {
@@ -114,9 +113,8 @@ export const Modal = forwardRef<ReactModal, ModalProps>(
variant="tertiary"
ref={buttonRef}
onClick={onClose}
>
<Close title="Lukk modalvindu" />
</Button>
icon={<Close title="Lukk modalvindu" />}
/>
)}
</ReactModal>
);
@@ -1,5 +1,5 @@
import React, { forwardRef } from "react";
import cl from "classnames";
import cl from "clsx";
export interface ModalContentProps
extends React.HTMLAttributes<HTMLDivElement> {
@@ -1,72 +0,0 @@
import React, { forwardRef, HTMLAttributes } from "react";
import cl from "classnames";
import { BodyShort, Heading } from "..";
export interface PageHeaderProps extends HTMLAttributes<HTMLDivElement> {
/**
* PageHeader title
*/
children: string;
/**
* Pictogram placed in PageHeader
*/
illustration?: React.ReactNode;
/**
* Short text placed under title
*/
description?: string;
/**
* Predefined variants for PageHeader
* @default "guide"
*/
variant?: "situation" | "product" | "guide";
/**
* Decides how to align content
* @default "left"
*/
align?: "left" | "center";
}
const PageHeader = forwardRef<HTMLDivElement, PageHeaderProps>(
(
{
children,
className,
illustration,
description,
variant = "guide",
align = "left",
...rest
},
ref
) => {
return (
<div
ref={ref}
className={cl(
"navds-page-header",
className,
`navds-page-header--${variant}`,
`navds-page-header--${align}`
)}
{...rest}
>
{illustration && (
<div className="navds-page-header__illustration">{illustration}</div>
)}
<div className="navds-page-header__wrapper">
<Heading className="navds-page-header__title" size="xlarge" level="1">
{children}
</Heading>
{description && (
<BodyShort className="navds-page-header__description">
{description}
</BodyShort>
)}
</div>
</div>
);
}
);
export default PageHeader;
@@ -1,2 +0,0 @@
export { default as PageHeader } from "./PageHeader";
export { PageHeaderProps } from "./PageHeader";
@@ -1,81 +0,0 @@
import { Meta, Canvas } from "@storybook/addon-docs";
import { PageHeader } from "../index";
import { illustrationPictogram } from "./pictogram";
<Meta title="ds-react(deprecated)/page-header/intro" />
# Hvordan ta i bruk PageHeader
Denne PageHeader-komponenten er utviklet i sammenheng med nye produktsider på NAV og
vil sannsynligvis forgå en del endringer før de er ferdige.
```jsx
<PageHeader description="LABORIS AUTE DESERUNT ID AUTE OFFICIA SINT SUNT FUGIAT EX ET CUPIDATAT CONSEQUAT DOLORE.">
AUTE OFFICIA SINT SUNT FUGIAT
</PageHeader>
```
<Canvas>
<PageHeader description="LABORIS AUTE DESERUNT ID AUTE OFFICIA SINT SUNT FUGIAT EX ET CUPIDATAT CONSEQUAT DOLORE.">
AUTE OFFICIA SINT SUNT FUGIAT
</PageHeader>
</Canvas>
## Med illustrasjon
Illustrasjonene brukt i PageHeader er "Pictogram" som er designet for den sepsifikke siden og
man skal da ikke bare velge et fra figma vilkårlig.
<Canvas>
<PageHeader
illustration={illustrationPictogram}
description="LABORIS AUTE DESERUNT ID AUTE OFFICIA SINT SUNT FUGIAT EX ET CUPIDATAT CONSEQUAT DOLORE."
>
AUTE OFFICIA SINT SUNT FUGIAT
</PageHeader>
</Canvas>
## Temaer
Headeren kommer i tre tema: `guide`, `product` og `situation`
<Canvas>
<PageHeader
description="LABORIS AUTE DESERUNT ID AUTE OFFICIA SINT SUNT FUGIAT EX ET CUPIDATAT CONSEQUAT DOLORE."
variant="guide"
>
AUTE OFFICIA SINT SUNT FUGIAT
</PageHeader>
<PageHeader
description="LABORIS AUTE DESERUNT ID AUTE OFFICIA SINT SUNT FUGIAT EX ET CUPIDATAT CONSEQUAT DOLORE."
variant="product"
>
AUTE OFFICIA SINT SUNT FUGIAT
</PageHeader>
<PageHeader
description="LABORIS AUTE DESERUNT ID AUTE OFFICIA SINT SUNT FUGIAT EX ET CUPIDATAT CONSEQUAT DOLORE."
variant="situation"
>
AUTE OFFICIA SINT SUNT FUGIAT
</PageHeader>
</Canvas>
## Sentrert
Innhold kan sentreres med `align="center"`-prop
<Canvas>
<PageHeader
description="LABORIS AUTE DESERUNT ID AUTE OFFICIA SINT SUNT FUGIAT EX ET CUPIDATAT CONSEQUAT DOLORE."
align="center"
>
AUTE OFFICIA SINT SUNT FUGIAT
</PageHeader>
<PageHeader
illustration={illustrationPictogram}
description="LABORIS AUTE DESERUNT ID AUTE OFFICIA SINT SUNT FUGIAT EX ET CUPIDATAT CONSEQUAT DOLORE."
align="center"
>
AUTE OFFICIA SINT SUNT FUGIAT
</PageHeader>
</Canvas>
Loaded 100 of 202 files, more files were not shown because too many files have changed in this diff. Show more