mirror of
https://github.com/navikt/aksel.git
synced 2026-10-13 01:02:02 +00:00
Compare commits
119
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36a5ed09af | ||
|
|
6f3091d0e8 | ||
|
|
79e4ab9499 | ||
|
|
e2e7961302 | ||
|
|
722bbcc3cb | ||
|
|
687e9822d5 | ||
|
|
a1454ed86f | ||
|
|
5f71be7678 | ||
|
|
b5d7e49d74 | ||
|
|
e52394ac6b | ||
|
|
189ee1454e | ||
|
|
f21595afa2 | ||
|
|
fe24ced90d | ||
|
|
1a88d50809 | ||
|
|
f9f6a1db44 | ||
|
|
ec88b293c9 | ||
|
|
27456b0187 | ||
|
|
5a207c222e | ||
|
|
513a1c5a1c | ||
|
|
cd2b2fece2 | ||
|
|
2b33e30e54 | ||
|
|
56d8c26a53 | ||
|
|
4801a8491a | ||
|
|
e943e71637 | ||
|
|
41106f6dd3 | ||
|
|
40837111c0 | ||
|
|
999cc95310 | ||
|
|
93d59968f2 | ||
|
|
70b6beed75 | ||
|
|
9102781d5c | ||
|
|
4405c89d5f | ||
|
|
309cd0fba3 | ||
|
|
5f1ca61501 | ||
|
|
a75622752e | ||
|
|
62a00f745c | ||
|
|
7b946d76ac | ||
|
|
0e42521c90 | ||
|
|
95e5891b27 | ||
|
|
9230adaa89 | ||
|
|
1885f0e935 | ||
|
|
c718348749 | ||
|
|
2166a7933f | ||
|
|
70ba56e218 | ||
|
|
69a21190b0 | ||
|
|
72c52f6cda | ||
|
|
ae297ee3fd | ||
|
|
e3ce3d0a28 | ||
|
|
d4cf0d2b1e | ||
|
|
60f1397043 | ||
|
|
4d78c35ec2 | ||
|
|
343fd910a8 | ||
|
|
86c3545fb7 | ||
|
|
f1341c6666 | ||
|
|
0949ba0b56 | ||
|
|
2ae9f382fb | ||
|
|
95476ff04e | ||
|
|
12be3f9ba6 | ||
|
|
9d00cecc92 | ||
|
|
755fd0cf3c | ||
|
|
9295bda19d | ||
|
|
2688b488e5 | ||
|
|
6aacf70c3d | ||
|
|
d211a06f5f | ||
|
|
e8ea9a8e34 | ||
|
|
7fef4d5ef8 | ||
|
|
a7f04b4902 | ||
|
|
e0fa04930d | ||
|
|
57cea8cb6d | ||
|
|
1884c6345b | ||
|
|
cb962e0332 | ||
|
|
b246578fe9 | ||
|
|
1d42e573bf | ||
|
|
1eea43c36f | ||
|
|
6fe7227345 | ||
|
|
362c8991c9 | ||
|
|
204bc1e010 | ||
|
|
7ac379364e | ||
|
|
cff48a3c47 | ||
|
|
a8c4aa785f | ||
|
|
aebbaef65e | ||
|
|
5009beddb0 | ||
|
|
7247c19b15 | ||
|
|
8e8d8a093f | ||
|
|
08bd97cfa1 | ||
|
|
cd80f303c8 | ||
|
|
23a32607e7 | ||
|
|
15a7ae44d4 | ||
|
|
6e6d052283 | ||
|
|
0d8a35350b | ||
|
|
9bc50d4775 | ||
|
|
4bac85e5e2 | ||
|
|
9868c49c37 | ||
|
|
077454002c | ||
|
|
bc423af462 | ||
|
|
a009536b79 | ||
|
|
c7735d179d | ||
|
|
390e8ffd33 | ||
|
|
422d4548c5 | ||
|
|
f74b35a69a | ||
|
|
69497cad51 | ||
|
|
0e02a74089 | ||
|
|
852d859f93 | ||
|
|
99fed38942 | ||
|
|
1fbe799a56 | ||
|
|
2b5527cbb3 | ||
|
|
88e951fa8c | ||
|
|
cd22e3e682 | ||
|
|
4d28da3aa4 | ||
|
|
51ed62741c | ||
|
|
560a1dc96d | ||
|
|
0fc11d8e88 | ||
|
|
4b0505164f | ||
|
|
02d7b89d2b | ||
|
|
e38b4f87ed | ||
|
|
7bf8900e0f | ||
|
|
5337f2f716 | ||
|
|
d4eae9ce0b | ||
|
|
e12f49660f | ||
|
|
6e4716ef3e |
No files matched your search
@@ -2,9 +2,12 @@ name: Chromatic
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches: [master]
|
||||
branches:
|
||||
- master
|
||||
- big-one-oh
|
||||
|
||||
jobs:
|
||||
chromatic-pr:
|
||||
|
||||
@@ -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 />`
|
||||
@@ -20,7 +20,6 @@ module.exports = {
|
||||
"@storybook/addon-docs",
|
||||
"@storybook/addon-a11y",
|
||||
"@whitespace/storybook-addon-html",
|
||||
"storybook-addon-css-user-preferences",
|
||||
{
|
||||
name: "@storybook/addon-storysource",
|
||||
options: {
|
||||
|
||||
@@ -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: "",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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)
|
||||
@@ -35,7 +35,7 @@ export function checkGitStatus(force) {
|
||||
if (force) {
|
||||
console.log(`WARNING: ${errorMessage}. Forcibly continuing.`);
|
||||
} else {
|
||||
console.log("Thank you for using @@navikt/ds-codemod");
|
||||
console.log("Thank you for using @navikt/ds-codemod");
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
"\nBut before we continue, please stash or commit your git changes."
|
||||
@@ -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",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-codemod",
|
||||
"version": "1.0.2",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"description": "NAV designsystem codemods",
|
||||
"author": "NAV Designsystem team",
|
||||
"license": "MIT",
|
||||
@@ -11,7 +10,7 @@
|
||||
"jscodeshift"
|
||||
],
|
||||
"files": [
|
||||
"transforms/*.js",
|
||||
"transforms/**/*.js",
|
||||
"bin/*.js",
|
||||
"lib/**/*.js",
|
||||
"lib/cra-to-next/gitignore"
|
||||
@@ -49,5 +48,8 @@
|
||||
"sideEffects": false,
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,9 @@ export const Page = () => {
|
||||
topText="Ola Normann 01.01.21 14:00"
|
||||
backgroundColor="red"
|
||||
illustrationBgColor="blue"
|
||||
{...testProps}
|
||||
>
|
||||
<SpeechBubble.Bubble>
|
||||
<SpeechBubble.Bubble {...testProps}>
|
||||
Aute minim nisi sunt mollit duis sunt nulla minim non proident.
|
||||
</SpeechBubble.Bubble>
|
||||
<SpeechBubble.Bubble>
|
||||
|
||||
@@ -8,8 +8,9 @@ export const Page = () => {
|
||||
name="Ola Normann 01.01.21 14:00"
|
||||
backgroundColor="red"
|
||||
avatarBgColor="blue"
|
||||
{...testProps}
|
||||
>
|
||||
<Chat.Bubble>
|
||||
<Chat.Bubble {...testProps}>
|
||||
Aute minim nisi sunt mollit duis sunt nulla minim non proident.
|
||||
</Chat.Bubble>
|
||||
<Chat.Bubble>
|
||||
|
||||
@@ -3,9 +3,16 @@ import { Pagination, Button } from "@navikt/ds-react";
|
||||
export const Demo = () => {
|
||||
return (
|
||||
<div>
|
||||
<Pagination size="small" onPageChange={setPage} data-version="v1" />
|
||||
<Pagination
|
||||
size="small"
|
||||
onPageChange={setPage}
|
||||
data-version="v1"
|
||||
{...testProps}
|
||||
/>
|
||||
<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>
|
||||
);
|
||||
};
|
||||
@@ -3,7 +3,14 @@ import { Pagination, Button } from "@navikt/ds-react";
|
||||
export const Demo = () => {
|
||||
return (
|
||||
<div>
|
||||
<Pagination
|
||||
size="small"
|
||||
onPageChange={setPage}
|
||||
data-version="v1"
|
||||
{...testProps}
|
||||
/>
|
||||
<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>
|
||||
);
|
||||
};
|
||||
@@ -4,9 +4,9 @@ const TabComp = () => {
|
||||
return (
|
||||
/* prettier-ignore */
|
||||
<div>
|
||||
<Tabs defaultValue="logg" onChange={(x) => console.log(x)}>
|
||||
<Tabs.List loop={false}>
|
||||
<Tabs.Tab value="logg" iconPosition={props.left} label="logg" />
|
||||
<Tabs defaultValue="logg" onChange={(x) => console.log(x)} {...testProps}>
|
||||
<Tabs.List loop={false} {...testProps}>
|
||||
<Tabs.Tab value="logg" iconPosition={props.left} label="logg" {...testProps}/>
|
||||
<Tabs.Tab value="logg2" iconPosition="top" label="logg2medlangtekst" />
|
||||
</Tabs.List>
|
||||
<Tabs.Panel value="logg">TabPanel for Logg-tab</Tabs.Panel>
|
||||
|
||||
@@ -7,10 +7,11 @@ const TabComp = () => {
|
||||
<Tabs
|
||||
defaultValue="logg"
|
||||
onChange={(x) => console.log(x)}
|
||||
{...testProps}
|
||||
loop={false}
|
||||
iconPosition={props.left}>
|
||||
<Tabs.List>
|
||||
<Tabs.Tab value="logg" label="logg" />
|
||||
<Tabs.List {...testProps}>
|
||||
<Tabs.Tab value="logg" label="logg" {...testProps} />
|
||||
<Tabs.Tab value="logg2" label="logg2medlangtekst" />
|
||||
</Tabs.List>
|
||||
<Tabs.Panel value="logg">TabPanel for Logg-tab</Tabs.Panel>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
# 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
|
||||
|
||||
You can import these styles once to make it accessible in your entire project. Typically you will add the following line to your root .js or .ts files.
|
||||
|
||||
```javascript
|
||||
import "@navikt/ds-css";
|
||||
|
||||
function App() {
|
||||
return <Component />;
|
||||
}
|
||||
```
|
||||
|
||||
But you can also import it in a .css-file like this
|
||||
|
||||
```css
|
||||
@import "@navikt/ds-css";
|
||||
```
|
||||
|
||||
## Learn more
|
||||
|
||||
- [Designsystem documentation](https://aksel.nav.no/designsystem)
|
||||
- [Storybook](https://master--5f801fb2aea7820022de2936.chromatic.com/)
|
||||
- [ds-react README](https://github.com/navikt/Designsystemet/blob/master/%40navikt/core/react/README.md)
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://github.com/navikt/Designsystemet/blob/master/LICENCE)
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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 *
|
||||
*************************/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -3,9 +3,6 @@
|
||||
--navds-semantic-color-component-background-light
|
||||
);
|
||||
--navds-radio-checkbox-color-text: var(--navds-semantic-color-text);
|
||||
--navds-radio-checkbox-color-description: var(
|
||||
--navds-semantic-color-text-muted
|
||||
);
|
||||
--navds-radio-checkbox-color-background-hover: var(
|
||||
--navds-semantic-color-interaction-primary-hover-subtle
|
||||
);
|
||||
@@ -75,11 +72,6 @@
|
||||
gap: var(--navds-spacing-1);
|
||||
}
|
||||
|
||||
.navds-checkbox__description,
|
||||
.navds-radio__description {
|
||||
color: var(--navds-radio-checkbox-color-description);
|
||||
}
|
||||
|
||||
.navds-checkbox--small > .navds-checkbox__input,
|
||||
.navds-radio--small > .navds-radio__input {
|
||||
width: 32px;
|
||||
|
||||
@@ -72,10 +72,6 @@
|
||||
padding: 0.75rem 0 0.75rem 3.25rem;
|
||||
}
|
||||
|
||||
.navds-switch__description {
|
||||
color: var(--navds-semantic-color-text-muted);
|
||||
}
|
||||
|
||||
.navds-switch--right > .navds-switch__label-wrapper > .navds-switch__content {
|
||||
padding: 0.75rem 3.25rem 0.75rem 0;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
resize: none;
|
||||
width: 100%;
|
||||
display: block;
|
||||
min-height: 48px;
|
||||
color: var(--navds-text-field-color-text);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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";
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-css",
|
||||
"version": "0.18.29",
|
||||
"version": "1.0.0",
|
||||
"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.8",
|
||||
"@navikt/ds-tokens": "^1.0.0",
|
||||
"normalize.css": "^8.0.1",
|
||||
"postcss": "^8.3.6",
|
||||
"postcss-cli": "^8.3.1",
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
@@ -1955,6 +1955,30 @@
|
||||
"created_at": "2021-01-11T13:37:55.658Z",
|
||||
"pageName": "Arrow"
|
||||
},
|
||||
{
|
||||
"name": "RotateLeft",
|
||||
"description": "",
|
||||
"created_at": "2022-08-03T12:27:13.304Z",
|
||||
"pageName": "Interface"
|
||||
},
|
||||
{
|
||||
"name": "RotateLeftFilled",
|
||||
"description": "",
|
||||
"created_at": "2022-08-03T12:27:13.309Z",
|
||||
"pageName": "Interface"
|
||||
},
|
||||
{
|
||||
"name": "RotateRight",
|
||||
"description": "",
|
||||
"created_at": "2022-08-03T12:27:13.299Z",
|
||||
"pageName": "Interface"
|
||||
},
|
||||
{
|
||||
"name": "RotateRightFilled",
|
||||
"description": "",
|
||||
"created_at": "2022-08-03T12:27:13.294Z",
|
||||
"pageName": "Interface"
|
||||
},
|
||||
{
|
||||
"name": "Ruler",
|
||||
"description": "",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-icons",
|
||||
"version": "0.8.20",
|
||||
"version": "1.0.0",
|
||||
"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",
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.2931 5.29289L13.7931 1.79289L15.2074 3.20711L13.4145 5H16C19.3137 5 22 7.68629 22 11V15H20V11C20 8.79086 18.2091 7 16 7H13.4145L15.2074 8.79289L13.7931 10.2071L10.2931 6.70711L9.58603 6L10.2931 5.29289ZM4 11C2.89543 11 2 11.8954 2 13V20C2 21.1046 2.89543 22 4 22H11C12.1046 22 13 21.1046 13 20V13C13 11.8954 12.1046 11 11 11H4ZM4 13H11V20H4V13Z" fill="#262626"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 519 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 0C0.447715 0 0 0.447716 0 1V23C0 23.5523 0.447716 24 1 24H23C23.5523 24 24 23.5523 24 23V1C24 0.447715 23.5523 0 23 0H1ZM12.7931 1.79289L9.29314 5.29289L8.58603 6L9.29314 6.70711L12.7931 10.2071L14.2074 8.79289L12.4145 7H15C17.2091 7 19 8.79086 19 11V15H21V11C21 7.68629 18.3137 5 15 5H12.4145L14.2074 3.20711L12.7931 1.79289ZM3 13.5C3 12.6716 3.67157 12 4.5 12H10.5C11.3284 12 12 12.6716 12 13.5V19.5C12 20.3284 11.3284 21 10.5 21H4.5C3.67157 21 3 20.3284 3 19.5V13.5Z" fill="#262626"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 643 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 7H10.5859L8.79299 8.79289L10.2072 10.2071L13.7072 6.7071L14.4143 6.00002L13.7072 5.29292L10.2072 1.79267L8.79297 3.20684L10.586 5H8C4.68629 5 2 7.68629 2 11V15H4V11C4 8.79086 5.79086 7 8 7ZM13 11C11.8954 11 11 11.8954 11 13V20C11 21.1046 11.8954 22 13 22H20C21.1046 22 22 21.1046 22 20V13C22 11.8954 21.1046 11 20 11H13ZM13 13H20V20H13V13Z" fill="#262626"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 513 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 0C0.447715 0 0 0.447716 0 1V23C0 23.5523 0.447716 24 1 24H23C23.5523 24 24 23.5523 24 23V1C24 0.447715 23.5523 0 23 0H1ZM11.5858 7H9C6.79086 7 5 8.79086 5 11V15H3V11C3 7.68629 5.68629 5 9 5H11.5859L9.79287 3.20682L11.2071 1.79266L14.7071 5.2929L15.4142 6.00001L14.7071 6.70709L11.2071 10.2071L9.79289 8.79288L11.5858 7ZM12 13.5C12 12.6716 12.6716 12 13.5 12H19.5C20.3284 12 21 12.6716 21 13.5V19.5C21 20.3284 20.3284 21 19.5 21H13.5C12.6716 21 12 20.3284 12 19.5V13.5Z" fill="#262626"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 642 B |
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
# 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! See README-link under "learn more"-section below.
|
||||
|
||||
```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/)
|
||||
- [ds-css README](https://github.com/navikt/Designsystemet/blob/master/%40navikt/core/css/README.md)
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://github.com/navikt/Designsystemet/blob/master/LICENCE)
|
||||
@@ -1 +1,6 @@
|
||||
import "@testing-library/jest-dom/extend-expect";
|
||||
global.ResizeObserver = jest.fn().mockImplementation(() => ({
|
||||
observe: jest.fn(),
|
||||
unobserve: jest.fn(),
|
||||
disconnect: jest.fn(),
|
||||
}));
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-react",
|
||||
"version": "0.19.27",
|
||||
"version": "1.0.0",
|
||||
"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",
|
||||
"@radix-ui/react-tabs": "^1.0.0",
|
||||
"@radix-ui/react-toggle-group": "^1.0.0",
|
||||
"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"
|
||||
"@floating-ui/react-dom-interactions": "0.9.2",
|
||||
"@navikt/ds-icons": "^1.0.0",
|
||||
"@radix-ui/react-tabs": "1.0.0",
|
||||
"@radix-ui/react-toggle-group": "1.0.0",
|
||||
"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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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 = () => {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
@@ -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;
|
||||
@@ -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>
|
||||
);
|
||||
@@ -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,6 +1,6 @@
|
||||
import cl from "classnames";
|
||||
import cl from "clsx";
|
||||
import React, { FieldsetHTMLAttributes, forwardRef, useContext } from "react";
|
||||
import { BodyShort, Detail, Label, ErrorMessage, omit } from "../..";
|
||||
import { BodyLong, Detail, Label, ErrorMessage, omit } from "../..";
|
||||
import { FormFieldProps } from "../useFormField";
|
||||
import { useFieldset } from "./useFieldset";
|
||||
|
||||
@@ -106,7 +106,7 @@ export const Fieldset = forwardRef<HTMLFieldSetElement, FieldsetProps>(
|
||||
</Label>
|
||||
{!!description &&
|
||||
(size === "medium" ? (
|
||||
<BodyShort
|
||||
<BodyLong
|
||||
className={cl("navds-fieldset__description", {
|
||||
"navds-sr-only": !!hideLegend,
|
||||
})}
|
||||
@@ -115,7 +115,7 @@ export const Fieldset = forwardRef<HTMLFieldSetElement, FieldsetProps>(
|
||||
as="div"
|
||||
>
|
||||
{props.description}
|
||||
</BodyShort>
|
||||
</BodyLong>
|
||||
) : (
|
||||
<Detail
|
||||
className={cl("navds-fieldset__description", {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
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 { BodyLong, Label, ErrorMessage, omit, Detail } from "..";
|
||||
import { FormFieldProps, useFormField } from "./useFormField";
|
||||
|
||||
export interface SelectProps
|
||||
@@ -66,7 +66,6 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>(
|
||||
<Label
|
||||
htmlFor={inputProps.id}
|
||||
size={size}
|
||||
as="label"
|
||||
className={cl("navds-form-field__label", {
|
||||
"navds-sr-only": hideLabel,
|
||||
})}
|
||||
@@ -76,7 +75,7 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>(
|
||||
{!!description && (
|
||||
<>
|
||||
{size === "medium" ? (
|
||||
<BodyShort
|
||||
<BodyLong
|
||||
className={cl("navds-form-field__description", {
|
||||
"navds-sr-only": hideLabel,
|
||||
})}
|
||||
@@ -85,7 +84,7 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>(
|
||||
as="div"
|
||||
>
|
||||
{description}
|
||||
</BodyShort>
|
||||
</BodyLong>
|
||||
) : (
|
||||
<Detail
|
||||
className={cl("navds-form-field__description", {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import cl from "classnames";
|
||||
import cl from "clsx";
|
||||
import React, {
|
||||
forwardRef,
|
||||
InputHTMLAttributes,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { forwardRef, InputHTMLAttributes } from "react";
|
||||
import cl from "classnames";
|
||||
import { BodyShort, Detail, Label, ErrorMessage, omit } from "..";
|
||||
import cl from "clsx";
|
||||
import { BodyLong, Detail, Label, ErrorMessage, omit } from "..";
|
||||
import { FormFieldProps, useFormField } from "./useFormField";
|
||||
|
||||
export interface TextFieldProps
|
||||
@@ -70,7 +70,6 @@ export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
|
||||
<Label
|
||||
htmlFor={inputProps.id}
|
||||
size={size}
|
||||
as="label"
|
||||
className={cl("navds-form-field__label", {
|
||||
"navds-sr-only": hideLabel,
|
||||
})}
|
||||
@@ -81,7 +80,7 @@ export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
|
||||
{!!description && (
|
||||
<>
|
||||
{size === "medium" ? (
|
||||
<BodyShort
|
||||
<BodyLong
|
||||
className={cl("navds-form-field__description", {
|
||||
"navds-sr-only": hideLabel,
|
||||
})}
|
||||
@@ -90,7 +89,7 @@ export const TextField = forwardRef<HTMLInputElement, TextFieldProps>(
|
||||
as="div"
|
||||
>
|
||||
{description}
|
||||
</BodyShort>
|
||||
</BodyLong>
|
||||
) : (
|
||||
<Detail
|
||||
className={cl("navds-form-field__description", {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React, { forwardRef, useState } from "react";
|
||||
import cl from "classnames";
|
||||
import TextareaAutosize from "@material-ui/core/TextareaAutosize";
|
||||
import { BodyShort, Label, ErrorMessage, omit, Detail } from "..";
|
||||
import cl from "clsx";
|
||||
import { BodyShort, BodyLong, 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,13 +76,17 @@ 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;
|
||||
};
|
||||
|
||||
const describedBy = cl(inputProps["aria-describedby"], {
|
||||
[maxLengthId ?? ""]: hasMaxLength,
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cl(
|
||||
@@ -99,7 +103,6 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
<Label
|
||||
htmlFor={inputProps.id}
|
||||
size={size}
|
||||
as="label"
|
||||
className={cl("navds-form-field__label", {
|
||||
"navds-sr-only": hideLabel,
|
||||
})}
|
||||
@@ -109,7 +112,7 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
{!!description && (
|
||||
<>
|
||||
{size === "medium" ? (
|
||||
<BodyShort
|
||||
<BodyLong
|
||||
className={cl("navds-form-field__description", {
|
||||
"navds-sr-only": hideLabel,
|
||||
})}
|
||||
@@ -118,7 +121,7 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
as="div"
|
||||
>
|
||||
{description}
|
||||
</BodyShort>
|
||||
</BodyLong>
|
||||
) : (
|
||||
<Detail
|
||||
className={cl("navds-form-field__description", {
|
||||
@@ -152,9 +155,7 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
"navds-textarea--counter": hasMaxLength,
|
||||
}
|
||||
)}
|
||||
aria-describedby={cl(inputProps["aria-describedby"], {
|
||||
[maxLengthId]: hasMaxLength,
|
||||
})}
|
||||
{...(describedBy ? { "aria-describedby": describedBy } : {})}
|
||||
/>
|
||||
{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 "../..";
|
||||
@@ -84,24 +84,24 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
|
||||
}}
|
||||
/>
|
||||
<label htmlFor={inputProps.id} className="navds-checkbox__label">
|
||||
<div
|
||||
<span
|
||||
className={cl("navds-checkbox__content", {
|
||||
"navds-sr-only": props.hideLabel,
|
||||
})}
|
||||
>
|
||||
<BodyShort as="div" size={size}>
|
||||
<BodyShort as="span" size={size}>
|
||||
{props.children}
|
||||
</BodyShort>
|
||||
{props.description && (
|
||||
<Description
|
||||
as="div"
|
||||
as="span"
|
||||
size="small"
|
||||
className="navds-checkbox__description"
|
||||
>
|
||||
{props.description}
|
||||
</Description>
|
||||
)}
|
||||
</div>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -8,6 +8,9 @@ export default {
|
||||
subcomponents: {
|
||||
CheckboxGroup,
|
||||
},
|
||||
argTypes: {
|
||||
size: { control: { type: "select", options: ["medium", "small"] } },
|
||||
},
|
||||
} as Meta;
|
||||
|
||||
export const Default = (props) => {
|
||||
@@ -22,7 +25,7 @@ export const Default = (props) => {
|
||||
onChange={props.controlled ? setState : undefined}
|
||||
hideLegend={props.hideLegend}
|
||||
error={props.errorGroup ? "Errormelding for checkboxgruppe" : undefined}
|
||||
{...props}
|
||||
size={props?.size}
|
||||
>
|
||||
<Checkbox
|
||||
value="checkbox1"
|
||||
|
||||
@@ -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,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";
|
||||
@@ -40,20 +40,20 @@ export const Radio = forwardRef<HTMLInputElement, RadioProps>((props, ref) => {
|
||||
ref={ref}
|
||||
/>
|
||||
<label htmlFor={inputProps.id} className="navds-radio__label">
|
||||
<div className="navds-radio__content">
|
||||
<BodyShort as="div" size={size}>
|
||||
<span className="navds-radio__content">
|
||||
<BodyShort as="span" size={size}>
|
||||
{props.children}
|
||||
</BodyShort>
|
||||
{props.description && (
|
||||
<Description
|
||||
as="div"
|
||||
as="span"
|
||||
size="small"
|
||||
className="navds-radio__description"
|
||||
>
|
||||
{props.description}
|
||||
</Description>
|
||||
)}
|
||||
</div>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -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 "../..";
|
||||
|
||||
|
||||
@@ -8,6 +8,9 @@ export default {
|
||||
subcomponents: {
|
||||
RadioGroup,
|
||||
},
|
||||
argTypes: {
|
||||
size: { control: { type: "select", options: ["medium", "small"] } },
|
||||
},
|
||||
} as Meta;
|
||||
|
||||
export const Default = (props) => {
|
||||
@@ -21,7 +24,7 @@ export const Default = (props) => {
|
||||
onChange={props.controlled ? setState : undefined}
|
||||
hideLegend={props.hideLegend}
|
||||
error={props.errorGroup ? "Errormelding" : undefined}
|
||||
{...props}
|
||||
size={props?.size}
|
||||
>
|
||||
<Radio value="radio1">{props.children || "Apple"}</Radio>
|
||||
<Radio
|
||||
@@ -38,6 +41,7 @@ export const Default = (props) => {
|
||||
|
||||
Default.args = {
|
||||
controlled: false,
|
||||
size: "medium",
|
||||
legend: "Legend-tekst",
|
||||
radioDescription: false,
|
||||
hideLegend: false,
|
||||
|
||||
@@ -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 ?? "");
|
||||
@@ -156,7 +163,6 @@ export const Search = forwardRef<HTMLInputElement, SearchProps>(
|
||||
<Label
|
||||
htmlFor={inputProps.id}
|
||||
size={size}
|
||||
as="label"
|
||||
className={cl("navds-form-field__label", {
|
||||
"navds-sr-only": hideLabel,
|
||||
})}
|
||||
|
||||
@@ -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,5 +1,5 @@
|
||||
import { useContext } from "react";
|
||||
import cl from "classnames";
|
||||
import cl from "clsx";
|
||||
import { FieldsetContext } from "./index";
|
||||
import { useId } from "../index";
|
||||
|
||||
|
||||
@@ -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,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,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> {
|
||||
/**
|
||||
|
||||
@@ -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>,
|
||||
@@ -11,7 +9,7 @@ export interface HelpTextProps
|
||||
/**
|
||||
* Helptext-dialog content
|
||||
*/
|
||||
children: React.ReactNode;
|
||||
children: string;
|
||||
/**
|
||||
* Adds a title-tooltip with the given text
|
||||
* @default "hjelp"
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
@@ -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> {
|
||||
|
||||
Loaded 100 of 218 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user