Compare commits

...
Author SHA1 Message Date
github-actions[bot] 2723363fa0 Lerna versionbump [ci skip]
- @navikt/ds-css@0.2.2
 - @navikt/ds-react@0.2.4
 - @navikt/ds-tokens@0.1.1
2021-03-22 13:22:25 +00:00
d56bc72977 Rename Layout til ProductPageLayout, legg til tittel og container (#1022)
* Rename Layout til ProductPageLayout, legg til tittel og container

* Juster padding på header

* Korriger mobil-visning

* Korriger brekkpunkt

* Del opp css

* Fjern ubrukt import

* Korriger klassenavn

* Legg på --decorator-sticky-offset på sticky-menyer

* Legg modul under riktig mappe

* Merge

* Oppdater ds-icons

* Fjern react-dom

* Revert package.json endringer

* Fiks typo i package.json

* Legg inn avhengighet til @navikt/nav-dekoratoren-moduler

* Oppdater versjon av @navikt/nav-dekoratoren-moduler

* Refaktorer css

* Fiks identering

* Rename decorator function name

* Prettify

* Fiks react-import

* Flytt på import

* Fjern avhengigheten til nav-dekoratoren-moduler

* Sett bakgrunnsfarge på body

* Fjern nav-dekoratoren-moduler fra yarn lock

* Layout with panels (#1023)

* Legg til panel i layouts

* Oppdaters responsive regler

* Fiks posisjonen på ikonet

* Responsive tweak

* Rename klasser

* Legg til funksjonalitet for kopiering

* Endre til et mer logisk funksjonsnavn

* Engelsk klassenavn

* Legg til highlight param

* Oppdater eksempel

* Fiks linting

* Fjern ubrukte imports

* Fiks styling

* Oppdater anker

* Flytt id

* Fjern trailing slash

* Endre bakgrunn på body

* Bugfiks for copyToClipboard

* Flytt window.location inn i onClick

* Rename variabeler

* Fiks gutters

* Bugfixes

* Bugfixes

* Accordion menu (#1019)

* Legg til dekoratøren på content-container og layout i storybook

* Fjern duplikat bakgrunn

* Dytt footer til bunnen av siden

* Flytt styling til preview-head.html

* Legg til prettier ignore på en stygg linje

* Flytt env til toppen av fil

* Flytt docs-root

* Legg til accordion-menu

* Oppdater eksempeldata, dropdown -> collapsable

* V2

* Oppdater dummy-data

* Fiks linting

* Fiks imports

* Oppdater size

* Fiks feil på layout

* Korriger størrelser på teksten

* Merge

* Fiks logikk for aktivt element i sidemeny

* Legg komponent under riktig kategori

* fjernet bruken av nav-frontend- pakker

* endringer for venstre-notch active link

* width px -> rem for notch

* Accordion menu med Overridablecomponent (#1034)

* oppdatert til link

* now with overridable component

* ignore stories in eslint

* riktig styling

* imports opprydding

* fjernet console log

* Fiks skrivefeil i variabelnavn

* Kun rendre tittel dersom den er definert

* fikset active styling

* Legg padding på lenkene

* Refaktor styles

* Flytt tilbake styling

* Fjern ubrukt import

* Flytt komponenter opp en mappe

* Refaktor context

* Legg til hooks dependencies

* Flytt smoothScrollBehavior

* Fjern ubrukt import

* Refaktor register og unregister anchor

* Benytt useCallback for å forhindre infinite loop

* Rename store

* Forhindre duplikat variabeldefinisjon

* Endre default aria-label på nav

* Set url hash

* Revert store-endringer

* Oppdater beta-versjon

* Oppdater versjonsnr

* Endre overskrift

* Versjon 0.2.1-beta.1

* Rename variabler

* v0.2.1-beta.1

* Sjekk om brukeren har scrollet til bunnen av siden

* 0.2.1-beta.3

* IE11 support

* v0.2.1-beta.4

* Margin only if not last child

* v0.2.1-beta.5

* Rename css

* 0.2.1-beta.6

* Legg til overridable component

* Fjern prop

* v0.2.1-beta.7

* Fiks body-padding

* v0.2.1-beta.8

* v0.2.1-beta.8

* Fiks eslint-problemer

* Fjern ubrukt import

* Fiks signatur på funskjon

* Fjern anchor-interface

Co-authored-by: Ken <ken.aleksander@gmail.com>
Co-authored-by: Ken <26967723+KenAJoh@users.noreply.github.com>

Co-authored-by: Ken <ken.aleksander@gmail.com>
Co-authored-by: Ken <26967723+KenAJoh@users.noreply.github.com>

* use popover for copied-text

* oppdatert versjoner

Co-authored-by: Ken <ken.aleksander@gmail.com>
Co-authored-by: Ken <26967723+KenAJoh@users.noreply.github.com>
Co-authored-by: Andreas Nordahl <andnorda@gmail.com>
2021-03-22 14:07:34 +01:00
Andreas NordahlandKen e203d669e1 Refactor docs mdx handling (#1050)
* remove unused plugins and mdxproviders

* toc in getStaticProps

* unused imports

* strange next link behaviour

* moved mdxcomponents

* slugger slugging slugs

* fjernet ubrukte npm-pakker

Co-authored-by: Ken <ken.aleksander@gmail.com>
2021-03-22 10:04:07 +01:00
Andreas NordahlandKen 90c06964a3 dynamic docs menu PoC (#1047)
* dynamic docs menu PoC

* working menu

* render mdx

* remove stray parens

* null check

* npm works :)

* fix index page and toc

* fikset id for heading

Co-authored-by: Ken <ken.aleksander@gmail.com>
2021-03-19 12:01:44 +01:00
Ken c35850a5e5 Nextjs TableOfContents (#1048)
* oppdatert toc

* oppdatert toc

* pr fix

* css update
2021-03-19 11:31:58 +01:00
Henning Håkonsen fd2ebe2629 Update README.md (#1046) 2021-03-18 09:50:50 +01:00
Ken 206cdaa2ce Forsøk på manuell sidestruktur (#1045)
* demo sidebar

* flyttet menu

* fjernet route

* fikset imports

* refactored meny

* fikset key
2021-03-17 13:44:52 +01:00
github-actions[bot] 42bc4288f5 Lerna versionbump [ci skip]
- @navikt/ds-react@0.2.3
2021-03-17 10:37:50 +00:00
Ken 3d7cc1112c Oppdatert kommentarer for komponenter (#1043)
* accordion comments + props

* alert comments + props

* button comments + props

* contentcontainer comments + props

* grid comments + props

* grid + internal-header

* oppdatert alle componenter

* fjernet unødvendig endring i pr modal

* fikset popover

* fjernet prop-types fra komponenter
2021-03-17 11:26:13 +01:00
github-actions[bot] 00fec86f80 Lerna versionbump [ci skip]
- @navikt/ds-react@0.2.2
2021-03-16 13:23:29 +00:00
Ken d631e4b611 setappelement extender nå Modal komponent (#1044)
* setappelement implementert

* fjernet comments
2021-03-16 14:10:48 +01:00
Ken 3097afe082 Nextjs base-struktur med mdx v0.1 (#1040)
* nav-logo white

* base-struktur layout

* fjernet docs-old

* fjernet docs-old

* Code-preview, bash og npm  (#1041)

* laget code-preview

* fikset styling

* npm komponent
2021-03-16 11:08:14 +01:00
92 changed files with 4301 additions and 814 deletions

No files matched your search

+113
View File
@@ -0,0 +1,113 @@
/*******************
* .accordion-menu *
*******************/
.navds-accordion-menu__html {
scroll-behavior: smooth;
}
.navds-accordion-menu__nav {
padding: var(--navds-layout-padding-small) 0;
overflow: hidden;
}
.navds-accordion-menu__container {
padding: 0;
margin: 0;
list-style: none;
}
.navds-accordion-menu__title {
margin: var(--navds-layout-padding-small) 0;
padding: 0 var(--navds-layout-padding-small);
}
.navds-accordion-menu__item {
position: relative;
margin: 0;
}
.navds-accordion-menu__item--active::after {
content: "";
position: absolute;
top: 0;
width: 0.5rem;
height: 100%;
background-color: var(--navds-color-blue-50);
}
.navds-link.navds-accordion-menu__link,
.navds-link.navds-accordion-menu__button {
min-height: 3rem;
display: flex;
align-items: center;
padding: 0 var(--navds-layout-padding-small);
background: none;
cursor: pointer;
}
.navds-link.navds-accordion-menu__link--active:not(:active):not(:focus) {
font-size: 1.125rem;
font-weight: 600;
color: var(--navds-color-text-primary);
text-decoration: none;
}
.navds-accordion-menu__chevron {
margin-right: 0.25rem;
font-size: 1rem;
}
.navds-accordion-menu__button {
display: flex;
clear: both;
align-items: center;
justify-content: space-between;
border: 0;
width: 100%;
}
.navds-accordion-menu__dropdown--content .navds-accordion-menu__link,
.navds-accordion-menu__dropdown--content .navds-accordion-menu__button {
padding-left: calc(var(--navds-layout-padding-small) + 2rem);
}
@media (min-width: 448px) {
.navds-accordion-menu__nav {
padding: var(--navds-layout-padding-medium-and-larger) 0;
}
.navds-accordion-menu__title {
padding: 0 var(--navds-layout-padding-medium-and-larger);
}
.navds-link.navds-accordion-menu__link,
.navds-link.navds-accordion-menu__button {
padding: 0 var(--navds-layout-padding-medium-and-larger);
}
.navds-accordion-menu__dropdown--content .navds-accordion-menu__link,
.navds-accordion-menu__dropdown--content .navds-accordion-menu__button {
padding: 0 calc(var(--navds-layout-padding-medium-and-larger) + 2rem);
}
}
@media (min-width: 960px) {
.navds-accordion-menu__nav {
padding: var(--navds-layout-padding-small) 0;
}
.navds-accordion-menu__title {
padding: 0 var(--navds-layout-padding-small);
}
.navds-link.navds-accordion-menu__link,
.navds-link.navds-accordion-menu__button {
padding: 0 calc(var(--navds-layout-padding-small));
}
.navds-accordion-menu__dropdown--content .navds-accordion-menu__link,
.navds-accordion-menu__dropdown--content .navds-accordion-menu__button {
padding: 0 calc(var(--navds-layout-padding-small) + 1rem);
}
}
-1
View File
@@ -24,7 +24,6 @@
.navds-accordion__chevron {
width: 1.25em;
height: 1.25em;
transition: 300ms transform;
transform: rotateZ(0deg);
flex-shrink: 0;
margin-left: 1rem;
+2 -1
View File
@@ -1,11 +1,12 @@
@import "baseline/baseline.css";
@import "accordion.css";
@import "accordion-menu.css";
@import "alert.css";
@import "button.css";
@import "content-container.css";
@import "grid.css";
@import "internal-header.css";
@import "layout.css";
@import "layouts.css";
@import "link.css";
@import "modal.css";
@import "popover.css";
-117
View File
@@ -1,117 +0,0 @@
.navds-layout__container {
display: grid;
grid-gap: var(--navds-grid-gutter-small);
grid-template-columns: repeat(12, minmax(0, 1fr));
margin-right: auto;
margin-left: auto;
}
.navds-layout__container--1-columns,
.navds-layout__container--2-columns {
max-width: 60rem;
}
.navds-layout__container--3-columns {
max-width: 79.5rem;
}
.navds-layout__section--white > * {
background: white;
}
.navds-layout__section--padding > * {
padding: var(--navds-layout-padding-small);
}
.navds-layout__section--sticky > * {
top: var(--navds-grid-gutter-small);
position: sticky;
}
.navds-layout__section--left,
.navds-layout__section--main,
.navds-layout__section--right {
grid-column: span 12;
}
@media (min-width: 448px) {
.navds-layout__container {
grid-gap: var(--navds-grid-gutter-medium-and-larger);
}
.navds-layout__section--padding.navds-layout__section--left > *,
.navds-layout__section--padding.navds-layout__section--main > *,
.navds-layout__section--padding.navds-layout__section--right > * {
padding: var(--navds-layout-padding-medium-and-larger);
}
}
@media (min-width: 648px) {
.navds-layout__container {
grid-gap: var(--navds-grid-gutter-medium-and-larger);
}
.navds-layout__section--padding.navds-layout__section--right > * {
padding: var(--navds-layout-padding-small);
}
/* prettier-ignore */
.navds-layout__container--2-columns > .navds-layout__section--padding.navds-layout__section--left > * {
padding: var(--navds-layout-padding-small);
}
.navds-layout__container--1-columns > .navds-layout__section--main {
grid-column: span 10;
}
.navds-layout__container--2-columns > .navds-layout__section--left,
.navds-layout__container--2-columns > .navds-layout__section--right {
grid-row: 1;
grid-column: span 4;
}
.navds-layout__container--2-columns > .navds-layout__section--main {
grid-row: 1;
grid-column: span 8;
}
.navds-layout__container--3-columns > .navds-layout__section--left {
grid-row: 1;
grid-column: span 8;
}
.navds-layout__container--3-columns > .navds-layout__section--main {
grid-row: 2;
grid-column: span 8;
}
.navds-layout__container--3-columns > .navds-layout__section--right {
grid-column: span 4;
grid-row: 1 / span 2;
}
}
@media (min-width: 960px) {
.navds-layout__section--padding.navds-layout__section--left > * {
padding: var(--navds-layout-padding-small);
}
.navds-layout__container--1-columns > .navds-layout__section--main {
grid-column: span 8;
}
.navds-layout__container--3-columns > .navds-layout__section--left {
grid-row: 1;
grid-column: span 3;
}
.navds-layout__container--3-columns > .navds-layout__section--main {
grid-row: 1;
grid-column: span 6;
}
.navds-layout__container--3-columns > .navds-layout__section--right {
grid-row: 1;
grid-column: span 3;
}
}
+284
View File
@@ -0,0 +1,284 @@
/*****************
* .navds-layout *
*****************/
.navds-layout__container {
display: grid;
grid-gap: var(--navds-grid-gutter-small);
grid-template-columns: repeat(12, minmax(0, 1fr));
margin-right: auto;
margin-left: auto;
}
.navds-layout__container--1-columns,
.navds-layout__container--2-columns {
max-width: 60rem;
}
.navds-layout__container--3-columns {
max-width: 79.5rem;
}
.navds-layout__section--white > * {
background: white;
}
.navds-layout__section--padding > * {
padding: var(--navds-layout-padding-small);
}
.navds-layout__section--sticky > * {
top: calc(var(--navds-grid-gutter-small) + var(--decorator-sticky-offset));
position: sticky;
}
.navds-layout__section > *:not(:last-child) {
margin-bottom: var(--navds-layout-padding-small);
}
.navds-layout__section--left,
.navds-layout__section--main,
.navds-layout__section--right {
grid-column: span 12;
}
@media (min-width: 448px) {
.navds-layout__container {
grid-gap: var(--navds-grid-gutter-medium-and-larger);
}
.navds-layout__section > *:not(:last-child) {
margin-bottom: var(--navds-grid-gutter-medium-and-larger);
}
.navds-layout__section--padding.navds-layout__section--left > *,
.navds-layout__section--padding.navds-layout__section--main > *,
.navds-layout__section--padding.navds-layout__section--right > * {
padding: var(--navds-layout-padding-medium-and-larger);
}
}
@media (min-width: 648px) {
.navds-layout__container {
grid-gap: var(--navds-grid-gutter-medium-and-larger);
}
.navds-layout__section--padding.navds-layout__section--right > * {
padding: var(--navds-layout-padding-small);
}
/* prettier-ignore */
.navds-layout__container--2-columns > .navds-layout__section--padding.navds-layout__section--left > * {
padding: var(--navds-layout-padding-small);
}
.navds-layout__container--1-columns > .navds-layout__section--main {
grid-column: span 10;
}
.navds-layout__container--2-columns > .navds-layout__section--left,
.navds-layout__container--2-columns > .navds-layout__section--right {
grid-row: 1;
grid-column: span 4;
}
.navds-layout__container--2-columns > .navds-layout__section--main {
grid-row: 1;
grid-column: span 8;
}
.navds-layout__container--3-columns > .navds-layout__section--left {
grid-row: 1;
grid-column: span 8;
}
.navds-layout__container--3-columns > .navds-layout__section--main {
grid-row: 2;
grid-column: span 8;
}
.navds-layout__container--3-columns > .navds-layout__section--right {
grid-column: span 4;
grid-row: 1 / span 2;
}
}
@media (min-width: 960px) {
.navds-layout__section--padding.navds-layout__section--left > * {
padding: var(--navds-layout-padding-small);
}
.navds-layout__container--1-columns > .navds-layout__section--main {
grid-column: span 8;
}
.navds-layout__container--3-columns > .navds-layout__section--left {
grid-row: 1;
grid-column: span 3;
}
.navds-layout__container--3-columns > .navds-layout__section--main {
grid-row: 1;
grid-column: span 6;
}
.navds-layout__container--3-columns > .navds-layout__section--right {
grid-row: 1;
grid-column: span 3;
}
}
/*************************
* .navds-layout__header *
************************/
.navds-layout__header {
background: var(--navds-layout-background-white);
}
.navds-layout__header-content {
grid-column: span 12;
}
.navds-layout__header-title {
margin: 0.25rem 0.85rem;
}
@media (min-width: 448px) {
.navds-layout__header-title {
margin: 0.25rem 0;
}
}
/*************************
* .navds-layout__body *
************************/
.navds-layout__body {
background: var(--navds-layout-background-gray);
}
.navds-layout__body--white {
background: var(--navds-layout-background-white);
}
@media (min-width: 648px) {
.navds-layout__body--2-columns.navds-layout__body--padding {
padding-top: 3rem;
}
}
@media (min-width: 960px) {
.navds-layout__body--3-columns.navds-layout__body--padding {
padding-top: 3rem;
}
}
/*************************
* .navds-layout__panel *
************************/
.navds-layout__panel {
width: 100%;
max-width: 100%;
position: relative;
display: inline-block;
padding: var(--navds-layout-padding-small);
background: white;
padding-top: 2.5rem;
}
.navds-layout__panel--icon-margin {
margin-top: 2rem;
}
.navds-layout__panel:not(:last-child) {
margin-bottom: var(--navds-grid-gutter-small);
}
.navds-layout__panel--highlight {
box-shadow: rgb(102, 164, 220) 0 0 0 0.15rem;
}
.navds-layout__panel-content {
margin-top: 1.25rem;
}
.navds-layout__panel-icon {
position: absolute;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
top: -2rem;
left: 0;
}
.navds-layout__panel-icon svg,
.navds-layout__panel-icon img {
background: #c7dbed;
border-radius: 2rem;
padding: 1rem;
height: 4rem;
width: 4rem;
}
.navds-layout__panel-title {
margin: 0.5rem 0;
}
.navds-layout__panel-copy {
display: flex;
align-items: center;
font-weight: 600;
}
.navds-layout__panel-copy-icon {
color: var(--navds-color-text-link);
margin-right: 0.5rem;
height: 1.5rem;
width: 1.5rem;
}
.navds-layout__panel-popover-content {
margin: 0.5rem;
}
.navds-layout__panel-copy-button {
display: flex;
align-items: center;
cursor: pointer;
background: transparent;
margin: 0 1rem 0 0;
padding-left: 0;
padding-right: 0;
border: 0;
}
@media (min-width: 448px) {
.navds-layout__panel {
padding: var(--navds-layout-padding-medium-and-larger);
}
.navds-layout__panel:not(:last-child) {
margin-bottom: var(--navds-grid-gutter-medium-and-larger);
}
}
@media (min-width: 648px) {
/* prettier-ignore */
.navds-layout__container--2-columns .navds-layout__panel--icon-margin:first-child {
margin-top: 0;
}
}
@media (min-width: 960px) {
/* prettier-ignore */
.navds-layout__container--3-columns .navds-layout__panel--icon-margin:first-child {
margin-top: 0;
}
.navds-layout__panel--icon-margin:not(:first-child) {
margin-top: 2rem;
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-css",
"version": "0.2.1",
"version": "0.2.2",
"private": false,
"description": "Css for NAV Designsystem components",
"author": "NAV Designsystem team",
@@ -21,7 +21,7 @@
"watch-css": "postcss -w --use postcss-import -o dist/index.css index.css"
},
"devDependencies": {
"@navikt/ds-tokens": "^0.1.0",
"@navikt/ds-tokens": "^0.1.1",
"normalize.css": "^8.0.1",
"postcss": "^8.2.7",
"postcss-cli": "^8.3.1",
-5
View File
@@ -4,11 +4,6 @@
box-shadow: 0 0.05rem 0.25rem 0.125rem rgba(0, 0, 0, 0.08);
border: var(--navds-border-default);
border-radius: 2px;
padding: 1rem;
}
.navds-popover--small {
padding: 0.5rem;
}
.navds-popover--hidden {
@@ -0,0 +1,40 @@
import React, { createContext, useCallback, useContext, useState } from "react";
interface Props {
children: JSX.Element | JSX.Element[];
}
export interface ActiveAnchorStore {
anchors: string[];
activeAnchor?: string;
registerAnchor: (anchor: string) => void;
unregisterAnchor: (anchor: string) => void;
setActiveAnchor: (anchor: string) => void;
}
export const ActiveAnchorContext = createContext({} as ActiveAnchorStore);
export const ActiveAnchorProvider = (props: Props) => {
const { children } = props;
const [anchors, setAnchors] = useState<string[]>([]);
const [activeAnchor, setActiveAnchor] = useState<string>();
return (
<ActiveAnchorContext.Provider
value={{
anchors,
activeAnchor,
registerAnchor: useCallback((anchor) => {
setAnchors((anchors) => [...anchors, anchor]);
}, []),
unregisterAnchor: useCallback((anchor) => {
setAnchors((anchors) => anchors.filter((a) => a !== anchor));
}, []),
setActiveAnchor: useCallback((anchor) => {
setActiveAnchor(anchor);
}, []),
}}
>
{children}
</ActiveAnchorContext.Provider>
);
};
export const useStore = () => useContext(ActiveAnchorContext);
@@ -0,0 +1,52 @@
import React, { forwardRef, HTMLAttributes, useState } from "react";
import cl from "classnames";
import { Expand } from "@navikt/ds-icons";
export interface AccordionMenuCollapsableProps
extends HTMLAttributes<HTMLButtonElement> {
title: string;
active?: boolean;
}
const Collapsable = forwardRef<
HTMLButtonElement,
AccordionMenuCollapsableProps
>(({ children, active, title, className, ...rest }, ref) => {
const [open, setOpen] = useState(active || false);
return (
<li
className={cl(
"navds-accordion-menu__item",
"navds-accordion-menu__dropdown"
)}
>
<button
ref={ref}
onClick={() => setOpen(!open)}
className={cl("navds-link", "navds-accordion-menu__button", className)}
{...rest}
>
{title}
<Expand
className={cl(
"navds-accordion__chevron",
`navds-accordion__chevron--${open ? "up" : "down"}`,
`navds-accordion-menu__chevron`
)}
/>
</button>
{open && (
<ul
className={cl(
"navds-accordion-menu__container",
"navds-accordion-menu__dropdown--content"
)}
>
{children}
</ul>
)}
</li>
);
});
export default Collapsable;
+62
View File
@@ -0,0 +1,62 @@
import React, { forwardRef, useEffect } from "react";
import { useStore } from "./ActiveAnchorStore";
import { OverridableComponent } from "../util";
import cl from "classnames";
export interface AccordionMenuItemProps {
props: {
children: React.ReactNode;
active?: boolean;
} & React.HTMLAttributes<HTMLLIElement>;
defaultComponent: "a";
}
const Item: OverridableComponent<AccordionMenuItemProps> = forwardRef(
(
{
children,
component: Component = "a",
active = false,
className,
...rest
},
ref
) => {
const anchor = rest.href && rest.href.split("#")[1];
const { activeAnchor, registerAnchor, unregisterAnchor } = useStore();
const isActive = active || (anchor && activeAnchor === anchor) || false;
useEffect(() => {
if (anchor) {
const target = document.getElementById(anchor);
if (target) {
registerAnchor(anchor);
return () => {
unregisterAnchor(anchor);
};
}
}
}, [anchor, registerAnchor, unregisterAnchor]);
return (
<li
className={cl(
"navds-accordion-menu__item",
isActive && "navds-accordion-menu__item--active"
)}
>
<Component
ref={ref}
className={cl("navds-link", "navds-accordion-menu__link", className, {
"navds-accordion-menu__link--active": isActive,
})}
{...rest}
>
{children}
</Component>
</li>
);
}
);
export default Item;
+68
View File
@@ -0,0 +1,68 @@
import React, {
forwardRef,
ForwardRefExoticComponent,
HTMLAttributes,
useEffect,
} from "react";
import { default as Item, AccordionMenuItemProps } from "./Item";
import { default as Collapsable } from "./Collapsable";
import { AccordionMenuCollapsableProps } from "./Collapsable";
import { Heading, OverridableComponent } from "../index";
import { ActiveAnchorProvider } from "./ActiveAnchorStore";
import Nav from "./Nav";
import cl from "classnames";
export interface LayoutWithSubComponents
extends ForwardRefExoticComponent<AccordionMenuProps> {
Collapsable: ForwardRefExoticComponent<AccordionMenuCollapsableProps>;
Item: OverridableComponent<AccordionMenuItemProps>;
}
export interface AccordionMenuProps extends HTMLAttributes<HTMLUListElement> {
title?: string;
smoothScrollBehavior?: boolean;
}
const AccordionMenu = forwardRef<HTMLUListElement, AccordionMenuProps>(
(
{ children, title, smoothScrollBehavior = true, className, ...rest },
ref
) => {
useEffect(() => {
if (smoothScrollBehavior) {
const htmlElement = document.documentElement;
htmlElement.classList.add("navds-accordion-menu__html");
return () => {
htmlElement.classList.remove("navds-accordion-menu__html");
};
}
}, [smoothScrollBehavior]);
return (
<ActiveAnchorProvider>
<Nav title={title}>
{title && (
<Heading
level={2}
size="medium"
className={cl("navds-accordion-menu__title", className)}
>
{title}
</Heading>
)}
<ul
ref={ref}
className={cl("navds-accordion-menu__container", className)}
{...rest}
>
{children}
</ul>
</Nav>
</ActiveAnchorProvider>
);
}
) as LayoutWithSubComponents;
AccordionMenu.Item = Item;
AccordionMenu.Collapsable = Collapsable;
export default AccordionMenu;
+54
View File
@@ -0,0 +1,54 @@
import React, { forwardRef, HTMLAttributes, useEffect } from "react";
import { useStore } from "./ActiveAnchorStore";
export interface AccordionMenuItemProps
extends HTMLAttributes<HTMLAnchorElement> {
title?: string;
}
const Nav = forwardRef<HTMLAnchorElement, AccordionMenuItemProps>(
({ children, title, className, ...rest }, ref) => {
const { anchors, activeAnchor, setActiveAnchor } = useStore();
useEffect(() => {
const scrollListener = () => {
const offset = 100;
const lastPassedAnchor = anchors
.map((anchor) => document.getElementById(anchor))
.map((element: HTMLElement) => ({
id: element.id,
top: element.getBoundingClientRect().top - offset,
scrolledToBottom:
window.innerHeight + window.pageYOffset >=
document.body.offsetHeight,
}))
.filter((element) => element.scrolledToBottom || element.top <= 0)
.sort((a, b) => (a.top < b.top ? -1 : 1))
.map((anchor) => anchor.id)
.pop();
// Set active anchor and related url hash
if (lastPassedAnchor && activeAnchor !== lastPassedAnchor) {
const { href, hash } = window.location;
const urlWithoutHash = href.replace(hash, "");
const urlWithAnchor = `${urlWithoutHash}#${lastPassedAnchor}`;
const title = document.title;
window.history.pushState(lastPassedAnchor, title, urlWithAnchor);
setActiveAnchor(lastPassedAnchor);
}
};
window.addEventListener("scroll", scrollListener);
return () => {
window.removeEventListener("scroll", scrollListener);
};
}, [anchors, activeAnchor, setActiveAnchor]);
return (
<nav className={"navds-accordion-menu__nav"} aria-label={title || "Meny"}>
{children}
</nav>
);
}
);
export default Nav;
+5
View File
@@ -0,0 +1,5 @@
import { default as AccordionMenu, AccordionMenuProps } from "./Menu";
import { AccordionMenuItemProps } from "./Item";
export { AccordionMenu, AccordionMenuProps, AccordionMenuItemProps };
export default AccordionMenu;
@@ -0,0 +1,12 @@
.navds-story-menu {
margin-top: 0;
list-style-type: none;
}
.navds-story-menu li:not(:last-child) {
margin-bottom: 1rem;
}
.navds-story-section {
margin-bottom: 1rem;
}
@@ -0,0 +1,139 @@
import * as React from "react";
import Menu from "../index";
import { useEffect } from "react";
import { ProductPageLayout } from "../../index";
import { Right } from "../../layouts/stories/components/sections/Right";
import { LightBulb, Telephone } from "@navikt/ds-icons";
import { MainOne } from "../../layouts/stories/components/sections/Main";
import { MainTwo } from "../../layouts/stories/components/sections/Main";
import { MainThree } from "../../layouts/stories/components/sections/Main";
import { Link, HashRouter as Router } from "react-router-dom";
import "./components/styles.css";
export default {
title: "ds-react/accordion-menu",
component: { Menu },
decorators: [
(Story) => {
useEffect(() => {
document.getElementById("decorator-header").style.display = "block";
document.getElementById("decorator-footer").style.display = "block";
return () => {
document.getElementById("decorator-header").style.display = "none";
document.getElementById("decorator-footer").style.display = "none";
};
}, []);
return <Story />;
},
],
parameters: {
layout: "fullscreen",
},
};
export const All = () => (
<ProductPageLayout title={"Nunc et lorem"}>
<ProductPageLayout.Section left sticky withPadding={false}>
<Menu title={"Minima"}>
<Menu.Item href={"#leo-quis"}>Leo quis</Menu.Item>
<Menu.Collapsable title={"Proin accumsan"}>
<Menu.Item href={"#nulla-pariatur"}>Nulla pariatur</Menu.Item>
<Menu.Item href={"#luctus-justo"}>Luctus justo</Menu.Item>
</Menu.Collapsable>
<Menu.Item href={"#maecenas-in-pretium"}>Maecenas in pretium</Menu.Item>
</Menu>
</ProductPageLayout.Section>
<ProductPageLayout.Section whiteBackground={false} withPadding={false}>
<ProductPageLayout.Panel
title={"Leo quis"}
anchor={"leo-quis"}
highlight={true}
icon={<LightBulb />}
>
<MainOne title={false} />
</ProductPageLayout.Panel>
<ProductPageLayout.Panel
title={"Proin accumsan"}
anchor={"proin-accumsan"}
>
<MainTwo title={false} />
</ProductPageLayout.Panel>
<ProductPageLayout.Panel
title={"Maecenas in pretium"}
anchor={"maecenas-in-pretium"}
icon={<Telephone />}
>
<MainThree title={false} />
</ProductPageLayout.Panel>
</ProductPageLayout.Section>
<ProductPageLayout.Section right sticky>
<Right />
</ProductPageLayout.Section>
</ProductPageLayout>
);
export const ReactRouter = () => (
<ProductPageLayout title={"Nunc et lorem"}>
<ProductPageLayout.Section left sticky withPadding={false}>
<Menu>
<Menu.Item component={Link} to="/link1">
Leo quis
</Menu.Item>
<Menu.Collapsable title={"Proin accumsan"}>
<Menu.Item component={Link} to="/link2">
Nulla pariatur
</Menu.Item>
<Menu.Item component={Link} to="/link3">
Luctus justo
</Menu.Item>
</Menu.Collapsable>
<Menu.Collapsable title={"Sint cupidatat"}>
<Menu.Item component={Link} to="/link4">
Nulla pariatur
</Menu.Item>
<Menu.Item component={Link} to="/link5">
Luctus justo
</Menu.Item>
</Menu.Collapsable>
<Menu.Item component={Link} to="/link6">
Maecenas in pretium
</Menu.Item>
</Menu>
</ProductPageLayout.Section>
<ProductPageLayout.Section whiteBackground={false} withPadding={false}>
<ProductPageLayout.Panel
title={"Leo quis"}
anchor={"leo-quis"}
highlight={true}
icon={<LightBulb />}
>
<MainOne title={false} />
</ProductPageLayout.Panel>
<ProductPageLayout.Panel
title={"Proin accumsan"}
anchor={"proin-accumsan"}
>
<MainTwo title={false} />
</ProductPageLayout.Panel>
<ProductPageLayout.Panel
title={"Maecenas in pretium"}
anchor={"maecenas-in-pretium"}
icon={<Telephone />}
>
<MainThree title={false} />
</ProductPageLayout.Panel>
</ProductPageLayout.Section>
<ProductPageLayout.Section right sticky>
<Right />
</ProductPageLayout.Section>
</ProductPageLayout>
);
ReactRouter.decorators = [
(Story) => (
<Router>
<Story />
</Router>
),
];
+24 -1
View File
@@ -1,16 +1,39 @@
import React, { forwardRef, useEffect, useRef, useState } from "react";
import cl from "classnames";
import { UnmountClosed, Collapse } from "react-collapse";
import { Expand } from "@navikt/ds-icons";
import { v4 as uuidv4 } from "uuid";
export interface AccordionProps
extends React.HTMLAttributes<HTMLButtonElement> {
/**
* Component content
*/
children: React.ReactNode;
/**
* @ignore
*/
className?: string;
/**
* Content on interactive surface of component
*/
heading: React.ReactNode;
/**
* Opens component if 'true', closes if 'false'
* Using this props removes automatic control of open-state
* @default false
*/
open?: boolean;
/**
* Callback for when user interacts with component
*
* @param {object} event
*/
onClick?: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
/**
* Removes content-element from dom when closed
* @default false
*/
renderContentWhenClosed?: boolean;
}
+14
View File
@@ -8,8 +8,22 @@ import {
} from "@navikt/ds-icons";
export interface AlertProps extends React.HTMLAttributes<HTMLDivElement> {
/**
* Decides what design the alert will have
*/
variant: "error" | "warning" | "info" | "success";
/**
* Component content
*/
children: React.ReactNode;
/**
* @ignore
*/
className?: string;
/**
* Reduces padding on component
* @default "medium"
*/
size?: "medium" | "small";
}
+16
View File
@@ -2,7 +2,23 @@ import React, { forwardRef } from "react";
import cl from "classnames";
export interface ButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
/**
* Component content
*/
children: React.ReactNode;
/**
* @ignore
*/
className?: string;
/**
* Decides component design and interactions
* @default "primary"
*/
variant?: "primary" | "secondary" | "action" | "danger";
/**
* Reduces internal padding for component
* @default "medium"
*/
size?: "medium" | "small";
}
@@ -1,7 +1,17 @@
import React, { forwardRef, HTMLAttributes } from "react";
import cl from "classnames";
export type ContentContainerProps = HTMLAttributes<HTMLDivElement>;
export interface ContentContainerProps extends HTMLAttributes<HTMLDivElement> {
/**
* @ignore
*/
classNames?: string;
/**
* Component content
*/
children: React.ReactNode;
}
const ContentContainer = forwardRef<HTMLDivElement, ContentContainerProps>(
({ children, className, ...rest }, ref) => (
<div
+20
View File
@@ -3,9 +3,29 @@ import cl from "classnames";
type Column = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
export interface CellProps extends HTMLAttributes<HTMLDivElement> {
/**
* @ignore
*/
className?: string;
/**
* Component content
*/
children?: React.ReactNode;
/**
* 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;
}
+10 -1
View File
@@ -1,7 +1,16 @@
import React, { forwardRef, HTMLAttributes } from "react";
import cl from "classnames";
export type GridProps = HTMLAttributes<HTMLDivElement>;
export interface GridProps extends HTMLAttributes<HTMLDivElement> {
/**
* Component content
*/
children: React.ReactNode;
/**
* @ignore
*/
className?: string;
}
const Grid = forwardRef<HTMLDivElement, GridProps>(
({ children, className, ...rest }, ref) => (
<div ref={ref} className={cl("navds-grid", className)} {...rest}>
+10 -1
View File
@@ -14,7 +14,16 @@ export {
InternalHeaderUser,
InternalHeaderUserProps,
} from "./internal-header/index";
export { Layout, LayoutProps, SectionProps } from "./layout/index";
export {
ProductPageLayout,
ProductPageLayoutProps,
ProductPageLayoutSectionProps,
} from "./layouts/index";
export {
AccordionMenu,
AccordionMenuProps,
AccordionMenuItemProps,
} from "./accordion-menu";
export { Link, LinkProps } from "./link/index";
export { Modal, ModalProps } from "./modal/index";
export { Popover, PopoverProps } from "./popover/index";
@@ -2,7 +2,14 @@ import React, { forwardRef, HTMLAttributes } from "react";
import cl from "classnames";
export interface InternalHeaderProps extends HTMLAttributes<HTMLElement> {
/**
* Component content
*/
children?: React.ReactNode;
/**
* @ignore
*/
className?: string;
}
const InternalHeader = forwardRef<HTMLElement, InternalHeaderProps>(
@@ -2,7 +2,18 @@ import React, { forwardRef, HTMLAttributes, createElement } from "react";
import cl from "classnames";
export interface InternalHeaderTitleProps extends HTMLAttributes<HTMLElement> {
/**
* Component content
*/
children?: React.ReactNode;
/**
* @ignore
*/
className?: string;
/**
* Tag this component will use. Usefull for defining a button/link
* @default "h1"
*/
element?: keyof React.ReactHTML;
}
@@ -3,7 +3,17 @@ import cl from "classnames";
export interface InternalHeaderUserProps
extends HTMLAttributes<HTMLDivElement> {
/**
* @ignore
*/
className?: string;
/**
* user name
*/
name: string;
/**
* user ident
*/
ident: string;
}
-40
View File
@@ -1,40 +0,0 @@
import cl from "classnames";
import React, {
Children,
forwardRef,
ForwardRefExoticComponent,
HTMLAttributes,
} from "react";
import { default as Section, SectionProps } from "./Section";
export interface LayoutWithSubComponents
extends ForwardRefExoticComponent<LayoutProps> {
Section: ForwardRefExoticComponent<SectionProps>;
}
export interface LayoutProps extends HTMLAttributes<HTMLElement> {
children?: React.ReactNode;
className?: string;
}
const Layout = forwardRef<HTMLDivElement, LayoutProps>(
({ children, className, ...rest }, ref) => {
const columns = Children.count(children);
return (
<div
ref={ref}
className={cl(
"navds-layout__container",
`navds-layout__container--${columns}-columns`,
className
)}
{...rest}
>
{children}
</div>
);
}
) as LayoutWithSubComponents;
Layout.Section = Section;
export default Layout;
-3
View File
@@ -1,3 +0,0 @@
export { default as Layout } from "./Layout";
export * from "./Layout";
export * from "./Section";
@@ -1,94 +0,0 @@
import * as React from "react";
import { useEffect } from "react";
import { ContentContainer } from "../../index";
import { Layout } from "../index";
import { Left } from "./components/sections/Left";
import { Main } from "./components/sections/Main";
import { Right } from "./components/sections/Right";
import "./components/styles.css";
export default {
title: "ds-react/layout/Article",
component: { Layout },
decorators: [
(Story) => {
useEffect(() => {
document.getElementById("decorator-header").style.display = "block";
document.getElementById("decorator-footer").style.display = "block";
return () => {
document.getElementById("decorator-header").style.display = "none";
document.getElementById("decorator-footer").style.display = "none";
};
}, []);
return <Story />;
},
],
parameters: {
layout: "fullscreen",
backgrounds: {
default: "NAV gray",
values: [
{
name: "NAV gray",
value: "#f1f1f1",
},
{
name: "white",
value: "#ffffff",
},
],
},
},
};
export const ThreeColumns = () => (
<ContentContainer>
<Layout>
<Layout.Section left sticky>
<Left />
</Layout.Section>
<Layout.Section>
<Main />
</Layout.Section>
<Layout.Section right sticky>
<Right />
</Layout.Section>
</Layout>
</ContentContainer>
);
export const TwoColumnsLeft = () => (
<ContentContainer>
<Layout>
<Layout.Section left sticky>
<Left />
</Layout.Section>
<Layout.Section>
<Main />
</Layout.Section>
</Layout>
</ContentContainer>
);
export const TwoColumnsRight = () => (
<ContentContainer>
<Layout>
<Layout.Section>
<Main />
</Layout.Section>
<Layout.Section right sticky>
<Right />
</Layout.Section>
</Layout>
</ContentContainer>
);
export const OneColumn = () => (
<ContentContainer>
<Layout>
<Layout.Section>
<Main />
</Layout.Section>
</Layout>
</ContentContainer>
);
@@ -1,108 +0,0 @@
import * as React from "react";
import {
Button,
Cell,
Grid,
Heading,
Link,
Paragraph,
Alert,
} from "../../../../index";
export const Main = () => (
<div>
<Heading className={"navds-story-section"} level={1} size={"xl"}>
Quis autem
</Heading>
<Paragraph className={"section"}>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium
doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo
inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut
fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem
sequi nesciunt.
</Paragraph>
<Grid className={"section"}>
<Cell xs={6}>
<Link href={"#"}>Ea voluptate</Link>
</Cell>
<Cell xs={6}>
<Link href={"#"}>Quis autem</Link>
</Cell>
</Grid>
<Paragraph className={"section"}>
Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet,
consectetur, adipisci velit, sed quia non numquam eius modi tempora
incidunt ut labore et dolore magnam aliquam quaerat voluptatem.{" "}
</Paragraph>
<Alert variant="info" className={"section"}>
Suspendisse potenti. Interdum et malesuada fames ac ante ipsum primis in
faucibus.
</Alert>
<Paragraph className={"section"}>
Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis
suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem
vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil
molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla
pariatur?
</Paragraph>
<Heading className={"section"} level={2} size={"xl"}>
Nulla pariatur?
</Heading>
<Paragraph className={"section"}>
Etiam viverra neque sit amet libero dapibus tincidunt. Pellentesque quis
imperdiet erat. Morbi sodales bibendum volutpat. Sed malesuada risus
lorem, in elementum purus commodo eget. Mauris maximus congue efficitur.
Cras vestibulum id metus sed pellentesque.
</Paragraph>
<table className={"section tabell tabell--stripet"}>
<thead>
<tr>
<th>ID</th>
<th>Fornavn</th>
<th>Etternavn</th>
<th>Rolle</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Jean-Luc</td>
<td>Picard</td>
<td>Kaptein</td>
</tr>
<tr>
<td>2</td>
<td>William</td>
<td>Riker</td>
<td>Kommandør</td>
</tr>
<tr>
<td>3</td>
<td>Geordi</td>
<td>La Forge</td>
<td>Sjefsingeniør</td>
</tr>
</tbody>
</table>
<Paragraph className={"section"}>
Curabitur a purus pretium, condimentum magna ac, pellentesque diam. Nulla
facilisi. Nullam consequat, dui sed bibendum faucibus, metus mauris
commodo tortor, eget mollis nunc augue eu elit. Ut nec fringilla odio, eu
scelerisque tellus.
</Paragraph>
<Paragraph className={"section"}>
Proin nec luctus justo. Pellentesque et dapibus libero. Phasellus non elit
eget justo mattis venenatis. In hac habitasse platea dictumst. Proin nunc
ipsum, ornare eu pretium in, aliquet non velit. Nullam efficitur tincidunt
leo, vel tempus nibh consectetur sed. Etiam porttitor finibus erat varius
rhoncus. Sed ac augue imperdiet, porta tellus vitae, aliquam est.
</Paragraph>
<Paragraph className={"section"}>
Nunc eget consectetur felis, id scelerisque sapien. Ut id feugiat nulla,
ut cursus sem. In viverra felis vitae aliquet finibus.
</Paragraph>
<Button>Søk ...</Button>
</div>
);
+3
View File
@@ -0,0 +1,3 @@
export { default as ProductPageLayout } from "./product-page/Layout";
export { LayoutProps as ProductPageLayoutProps } from "./product-page/Layout";
export { SectionProps as ProductPageLayoutSectionProps } from "./product-page/Section";
@@ -0,0 +1,69 @@
import React, { useEffect, Children, forwardRef } from "react";
import { ForwardRefExoticComponent, HTMLAttributes } from "react";
import { default as Section, SectionProps } from "./Section";
import { default as Panel, PanelProps } from "./Panel";
import { ContentContainer, Heading, OverridableComponent } from "../../";
import cl from "classnames";
export interface LayoutWithSubComponents
extends ForwardRefExoticComponent<LayoutProps> {
Section: ForwardRefExoticComponent<SectionProps>;
Panel: OverridableComponent<PanelProps>;
}
export interface LayoutProps extends HTMLAttributes<HTMLElement> {
title: string;
children?: React.ReactNode;
}
const Layout = forwardRef<HTMLDivElement, LayoutProps>(
({ children, title, className, ...rest }, ref) => {
const columns = Children.toArray(children).length;
const classNames = cl(
"navds-layout__container",
`navds-layout__container--${columns}-columns`,
className
);
useEffect(() => {
const layoutBody = document.getElementById("navds-layout-body");
layoutBody?.classList.add(`navds-layout__body--${columns}-columns`);
document.body.classList.add("navds-layout__body--white");
return () => {
layoutBody?.classList.remove(`navds-layout__body--${columns}-columns`);
document.body.classList.remove("navds-layout__body--white");
};
}, [columns]);
return (
<div ref={ref}>
<div id={"navds-layout-header"} className={"navds-layout__header"}>
<ContentContainer>
<div className={classNames} {...rest}>
<div className={cl("navds-layout__header-content")}>
<Heading
size={"xxl"}
className={cl("navds-layout__header-title")}
level={1}
>
{title}
</Heading>
</div>
</div>
</ContentContainer>
</div>
<div id={"navds-layout-body"} className={"navds-layout__body"}>
<ContentContainer>
<div className={classNames} {...rest}>
{children}
</div>
</ContentContainer>
</div>
</div>
);
}
) as LayoutWithSubComponents;
Layout.Section = Section;
Layout.Panel = Panel;
export default Layout;
@@ -0,0 +1,101 @@
import React, { useEffect, useState } from "react";
import { forwardRef, ReactNode } from "react";
import cl from "classnames";
import { Button, Heading, Popover } from "../../";
import { Attachment } from "@navikt/ds-icons";
import { OverridableComponent } from "../../util";
export interface PanelProps {
props: {
title: string;
icon?: ReactNode;
highlight?: boolean;
anchor?: string;
whiteBackground?: boolean;
withPadding?: boolean;
} & React.HTMLAttributes<HTMLDivElement>;
defaultComponent: "div";
}
const Panel: OverridableComponent<PanelProps> = forwardRef(
(
{
title,
highlight,
icon,
anchor,
component: Component = "div",
className,
children,
...rest
},
ref
) => {
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
const [copied, setIsCopied] = useState<boolean>(false);
useEffect(() => {
const header = document.getElementById("navds-layout-body");
header?.classList.add("navds-layout__body--padding");
}, []);
return (
<Component
ref={ref}
id={anchor}
className={cl(
"navds-layout__panel",
icon && "navds-layout__panel--icon-margin",
highlight && "navds-layout__panel--highlight",
className
)}
{...rest}
>
{icon && <div className={"navds-layout__panel-icon"}>{icon}</div>}
<Heading size={"xl"} className={"navds-layout__panel-title"} level={2}>
{title}
</Heading>
{anchor && (
<div className={"navds-layout__panel-copy"}>
<Button
ref={(el) => setAnchorEl(el)}
variant={"secondary"}
className={"navds-layout__panel-copy-button"}
onClick={() => {
setIsCopied(true);
const { href, hash } = window.location;
const urlWithoutHash = href.replace(hash, "");
copyToClipboard(`${urlWithoutHash}#${anchor}`);
setTimeout(() => {
setIsCopied(false);
}, 1000);
}}
>
<Attachment className={"navds-layout__panel-copy-icon"} />
<span>Kopier lenke</span>
</Button>
<Popover anchorEl={anchorEl} open={copied} onClose={() => {}}>
<div className="navds-layout__panel-popover-content">Kopiert</div>
</Popover>
</div>
)}
<div className={"navds-layout__panel-content"}>{children}</div>
</Component>
);
}
);
const copyToClipboard = (text: string) => {
const textArea = document.createElement("textarea");
textArea.value = text;
textArea.style.top = "0";
textArea.style.left = "0";
textArea.style.position = "fixed";
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
document.execCommand("copy");
document.body.removeChild(textArea);
};
export default Panel;
@@ -4,16 +4,16 @@ import { Button, Link } from "../../../../index";
export const Left = () => (
<ul className={"navds-story-menu"}>
<li>
<Link href={"#"}>Iusto odio dignissimos</Link>
<Link href={"#leo-quis"}>Leo quis</Link>
</li>
<li>
<Link href={"#"}>Nam libero tempore</Link>
<Link href={"#proin-accumsan"}>Proin accumsan</Link>
</li>
<li>
<Link href={"#"}>Reiciendis voluptatibus</Link>
<Link href={"#nulla-pariatur"}>Nulla pariatur?</Link>
</li>
<li>
<Link href={"#"}>Earum rerum</Link>
<Link href={"#maecenas-in-pretium"}>Maecenas in pretium</Link>
</li>
<li>
<Button>Søk ...</Button>
@@ -0,0 +1,145 @@
import * as React from "react";
import {
Button,
Cell,
Grid,
Heading,
Link,
Paragraph,
} from "../../../../index";
import Snakkeboble from "nav-frontend-snakkeboble";
export const Main = ({ title = true }) => (
<>
<MainOne title={title} />
<MainTwo title={title} />
<MainThree title={title} />
</>
);
export const MainOne = ({ title = true }) => (
<div>
{title && (
<Heading level={1} size={"xl"} id={"leo-quis"}>
Leo quis
</Heading>
)}
<Paragraph>
Sed ullamcorper quam eget lorem volutpat, quis cursus risus fermentum.
Quisque varius ornare nulla, ut condimentum sapien dapibus non. Nullam
eget interdum nibh
</Paragraph>
</div>
);
export const MainTwo = ({ title = true }) => (
<div>
{title && (
<Heading level={1} size={"xl"} id={"proin-accumsan"}>
Proin accumsan
</Heading>
)}
<Paragraph className={"section"}>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium
doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo
inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
</Paragraph>
<Grid className={"section"}>
<Cell xs={6}>
<Link href={"#"}>Ea voluptate</Link>
</Cell>
<Cell xs={6}>
<Link href={"#"}>Quis autem</Link>
</Cell>
</Grid>
<Paragraph className={"section"}>
Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet,
consectetur, adipisci velit, sed quia non numquam eius modi tempora.
</Paragraph>
<Heading level={2} size={"large"} id={"nulla-pariatur"}>
Nulla pariatur?
</Heading>
<Paragraph className={"section"}>
Etiam viverra neque sit amet libero dapibus tincidunt. Pellentesque quis
imperdiet erat. Morbi sodales bibendum volutpat.
</Paragraph>
<table className={"section tabell tabell--stripet"}>
<thead>
<tr>
<th>ID</th>
<th>Fornavn</th>
<th>Etternavn</th>
<th>Rolle</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Jean-Luc</td>
<td>Picard</td>
<td>Kaptein</td>
</tr>
<tr>
<td>2</td>
<td>William</td>
<td>Riker</td>
<td>Kommandør</td>
</tr>
<tr>
<td>3</td>
<td>Geordi</td>
<td>La Forge</td>
<td>Sjefsingeniør</td>
</tr>
</tbody>
</table>
<Paragraph className={"section"}>
Curabitur a purus pretium, condimentum magna ac, pellentesque diam. Nulla
facilisi. Nullam consequat, dui sed bibendum faucibus, metus mauris
commodo tortor.
</Paragraph>
<Heading level={2} size={"large"} id={"luctus-justo"}>
Luctus justo
</Heading>
<Paragraph className={"section"}>
Nunc eget consectetur felis, id scelerisque sapien. Ut id feugiat nulla,
ut cursus sem. In viverra felis vitae aliquet finibus.
</Paragraph>
<Button>Søk ...</Button>
</div>
);
export const MainThree = ({ title = true }) => (
<div>
{title && (
<Heading level={1} size={"xl"} id={"maecenas-in-pretium"}>
Maecenas in pretium
</Heading>
)}
<Paragraph>
Sed ullamcorper quam eget lorem volutpat, quis cursus risus fermentum.
Quisque varius ornare nulla, ut condimentum sapien dapibus non. Nullam
eget interdum nibh
</Paragraph>
<Snakkeboble>Integer aliquam feugiat purus et imperdie</Snakkeboble>
<Paragraph>
Cras tempor eros sed dapibus egestas. Curabitur bibendum quam quis lectus
pretium lacinia. Nunc consequat ac augue quis laoreet. Donec porta, erat
vitae blandit egestas, arcu metus pharetra nulla, et laoreet risus purus
convallis turpis.
</Paragraph>
<Snakkeboble pilHoyre={true}>
Integer aliquam feugiat purus et imperdie
</Snakkeboble>
<Paragraph>
Suspendisse potenti. Praesent at elit interdum, porttitor sem eget,
blandit dolor. Nunc eget consectetur felis, id scelerisque sapien. Ut id
feugiat nulla, ut cursus sem. In viverra felis vitae aliquet finibus.
</Paragraph>
<Paragraph>
Vivamus id mi lectus. Duis ac augue magna. Aliquam ut euismod dui. Duis
consectetur, magna a malesuada tempus, elit urna fermentum arcu, at
porttitor magna sapien id enim.
</Paragraph>
</div>
);
@@ -0,0 +1,102 @@
import * as React from "react";
import { useEffect } from "react";
import { ProductPageLayout } from "../../index";
import { Left } from "./components/sections/Left";
import { Main, MainOne, MainTwo, MainThree } from "./components/sections/Main";
import { Right } from "./components/sections/Right";
import { LightBulb, Telephone } from "@navikt/ds-icons";
import "./components/styles.css";
export default {
title: "ds-react/layouts/ProductPage",
component: ProductPageLayout,
decorators: [
(Story) => {
useEffect(() => {
document.getElementById("decorator-header").style.display = "block";
document.getElementById("decorator-footer").style.display = "block";
return () => {
document.getElementById("decorator-header").style.display = "none";
document.getElementById("decorator-footer").style.display = "none";
};
}, []);
return <Story />;
},
],
parameters: {
layout: "fullscreen",
},
};
const title = "Nunc et lorem";
export const ThreeColumns = () => (
<ProductPageLayout title={title}>
<ProductPageLayout.Section left sticky>
<Left />
</ProductPageLayout.Section>
<ProductPageLayout.Section whiteBackground={false} withPadding={false}>
<ProductPageLayout.Panel
title={"Leo quis"}
anchor={"leo-quis"}
highlight={true}
icon={<LightBulb />}
>
<MainOne title={false} />
</ProductPageLayout.Panel>
<ProductPageLayout.Panel
title={"Proin accumsan"}
anchor={"proin-accumsan"}
>
<MainTwo title={false} />
</ProductPageLayout.Panel>
<ProductPageLayout.Panel
title={"Maecenas in pretium"}
anchor={"maecenas-in-pretium"}
icon={<Telephone />}
>
<MainThree title={false} />
</ProductPageLayout.Panel>
</ProductPageLayout.Section>
<ProductPageLayout.Section right sticky>
<Right />
</ProductPageLayout.Section>
</ProductPageLayout>
);
export const TwoColumnsLeft = () => (
<ProductPageLayout title={title}>
<ProductPageLayout.Section left sticky>
<Left />
</ProductPageLayout.Section>
<ProductPageLayout.Section>
<ProductPageLayout.Panel
title={"Leo quis"}
anchor={"leo-quis"}
highlight={true}
icon={<LightBulb />}
>
<MainOne title={false} />
</ProductPageLayout.Panel>
<Main />
</ProductPageLayout.Section>
</ProductPageLayout>
);
export const TwoColumnsRight = () => (
<ProductPageLayout title={title}>
<ProductPageLayout.Section>
<Main />
</ProductPageLayout.Section>
<ProductPageLayout.Section right sticky>
<Right />
</ProductPageLayout.Section>
</ProductPageLayout>
);
export const OneColumn = () => (
<ProductPageLayout title={title}>
<ProductPageLayout.Section>
<Main />
</ProductPageLayout.Section>
</ProductPageLayout>
);
+8
View File
@@ -3,6 +3,14 @@ import cl from "classnames";
export interface LinkProps
extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
/**
* Component content
*/
children: React.ReactNode;
/**
* @ignore
*/
className?: string;
/**
* Link anchor should direct to
*/
+10 -8
View File
@@ -5,9 +5,6 @@ import mergeRefs from "react-merge-refs";
import { Close } from "@navikt/ds-icons";
import { Button } from "../index";
// TODO: Has to be documented well that the user has to import react-modal and call
// ReactModal.setAppElement("#root")
export interface ModalProps {
/**
* Content of modal
@@ -27,7 +24,7 @@ export interface ModalProps {
*/
shouldCloseOnOverlayClick?: boolean;
/**
* User defined classname for wrapper element
* @ignore
*/
className?: string;
/**
@@ -36,7 +33,14 @@ export interface ModalProps {
contentClassName?: string;
}
const Modal = forwardRef<ReactModal, ModalProps>(
type ModalLifecycle = {
setAppElement?: (element: any) => void;
};
const Modal: ModalLifecycle &
React.ForwardRefExoticComponent<
ModalProps & React.RefAttributes<ReactModal>
> = forwardRef<ReactModal, ModalProps>(
(
{
children,
@@ -89,8 +93,6 @@ const Modal = forwardRef<ReactModal, ModalProps>(
}
);
export const setAppElement = (element) => {
ReactModal.setAppElement(element);
};
Modal.setAppElement = (element) => ReactModal.setAppElement(element);
export default Modal;
@@ -1,13 +1,12 @@
import React, { useState } from "react";
import { Modal } from "../index";
import ReactModal from "react-modal";
export default {
title: "ds-react/modal",
component: Modal,
};
ReactModal.setAppElement("#root");
Modal.setAppElement("#root");
export const All = () => {
const [open, setOpen] = useState(true);
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-react",
"version": "0.2.1",
"version": "0.2.4",
"private": false,
"description": "NAV designsystem react components",
"author": "NAV Designsystem team",
+6 -4
View File
@@ -27,12 +27,15 @@ export interface PopoverProps extends HTMLAttributes<HTMLDivElement> {
* Content rendered inside popover
*/
children: React.ReactNode;
/**
* @ignore
*/
className?: string;
/**
* Orientation for popover
* @default 'auto'
* @default "right"
*/
placement?: Placement;
size?: "medium" | "small";
}
const useEventLister = (event: string, callback) =>
@@ -52,7 +55,6 @@ const Popover = forwardRef<HTMLDivElement, PopoverProps>(
children,
placement = "right",
className,
size = "medium",
...rest
},
ref
@@ -130,7 +132,7 @@ const Popover = forwardRef<HTMLDivElement, PopoverProps>(
return (
<div
ref={mergedRef}
className={cl("navds-popover", `navds-popover--${size}`, className, {
className={cl("navds-popover", className, {
"navds-popover--hidden": !open || !anchorEl,
})}
aria-live="polite"
@@ -27,7 +27,7 @@ const Template = (props) => {
{props.placement}
</div>
<Popover {...props} anchorEl={anchorEl} onClose={() => {}} open>
Contents
<div style={{ margin: "1rem" }}>Contents</div>
</Popover>
</>
);
@@ -56,27 +56,3 @@ export const All = () => {
</div>
);
};
export const Small = () => {
return (
<div
style={{
display: "flex",
flexWrap: "wrap",
margin: "4rem 8rem 4rem 8rem",
}}
>
{placements.map((placement) => (
<div
style={{
width: "20%",
height: "100px",
margin: "4rem",
}}
>
<Template placement={placement} size="small" />
</div>
))}
</div>
);
};
+9 -1
View File
@@ -2,7 +2,14 @@ import React, { forwardRef, HTMLAttributes } from "react";
import cl from "classnames";
export interface TagProps extends HTMLAttributes<HTMLSpanElement> {
/**
* Component content
*/
children: React.ReactNode;
/**
* @ignore
*/
className?: string;
/**
* Changes background-color and border-color
*/
@@ -10,11 +17,12 @@ export interface TagProps extends HTMLAttributes<HTMLSpanElement> {
}
const Tag = forwardRef<HTMLSpanElement, TagProps>(
({ children, className, variant }, ref) => {
({ children, className, variant, ...rest }, ref) => {
return (
<span
ref={ref}
className={cl("navds-tag", className, `navds-tag--${variant}`)}
{...rest}
>
{children}
</span>
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-tokens",
"version": "0.1.0",
"version": "0.1.1",
"private": false,
"description": "Auto-generated design-tokens for NAV design-systems framework",
"author": "NAV Designsystem team",
+4
View File
@@ -170,6 +170,10 @@ module.exports = {
},
},
layout: {
background: {
white: { value: "#FFFFFF" },
gray: { value: "#F1F1F1" },
},
padding: {
small: { value: "1rem" },
mediumAndLarger: { value: "2.5rem" },
+18
View File
@@ -0,0 +1,18 @@
import { Heading, Paragraph } from "@navikt/ds-react";
import Bash from "./code/Bash";
import Import from "./code/Import";
import Preview from "./code-preview/Preview";
import Npm from "./npm/Npm";
import TableOfContents from "./table-of-contents/TableOfContents";
export default {
h1: (props) => <Heading size="xxl" level={1} {...props} />,
h2: (props) => <Heading size="large" level={2} {...props} />,
h3: (props) => <Heading size="small" level={3} {...props} />,
p: (props) => <Paragraph size="medium" {...props} />,
Bash,
Preview,
Import,
Npm,
TableOfContents,
};
+6
View File
@@ -0,0 +1,6 @@
<svg width="77" height="48" viewBox="0 0 77 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 34.4688L4.90367 22.3328H9.61534L4.71792 34.4688H0Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M60.5095 34.4688L65.3504 22.3328H67.9191L63.0785 34.4688H60.5095Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M70.0298 34.4688L74.8699 22.3328H76.2341L71.3934 34.4688H70.0298Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M56.055 22.3327H51.7901C51.7901 22.3327 51.4962 22.3327 51.3922 22.5923L49.032 29.8176L46.6737 22.5923C46.5698 22.3327 46.2741 22.3327 46.2741 22.3327H38.0738C37.8963 22.3327 37.7474 22.481 37.7474 22.6574V25.1111C37.7474 23.1647 35.6763 22.3327 34.4635 22.3327C31.7477 22.3327 29.9297 24.1215 29.3636 26.8411C29.3329 25.0369 29.183 24.3905 28.697 23.7284C28.4738 23.4041 28.1511 23.1314 27.7998 22.9059C27.0764 22.4821 26.4268 22.3327 25.0308 22.3327H23.3917C23.3917 22.3327 23.0955 22.3327 22.991 22.5923L21.4996 26.2883V22.6574C21.4996 22.481 21.3519 22.3327 21.1747 22.3327H17.3818C17.3818 22.3327 17.089 22.3327 16.9825 22.5923L15.432 26.4355C15.432 26.4355 15.2772 26.8198 15.6311 26.8198H17.089V34.143C17.089 34.3248 17.2321 34.4688 17.4147 34.4688H21.1747C21.3519 34.4688 21.4996 34.3248 21.4996 34.143V26.8198H22.9651C23.8061 26.8198 23.9842 26.8428 24.3114 26.9953C24.5085 27.0697 24.686 27.2202 24.7829 27.3938C24.9811 27.767 25.0308 28.2152 25.0308 29.5367V34.143C25.0308 34.3248 25.1768 34.4688 25.3572 34.4688H28.9609C28.9609 34.4688 29.3682 34.4688 29.5292 34.0666L30.3279 32.0927C31.3898 33.5801 33.1377 34.4688 35.3099 34.4688H35.7845C35.7845 34.4688 36.1944 34.4688 36.3566 34.0666L37.7474 30.622V34.143C37.7474 34.3248 37.8963 34.4688 38.0738 34.4688H41.7524C41.7524 34.4688 42.1583 34.4688 42.3213 34.0666C42.3213 34.0666 43.7926 30.4138 43.7983 30.3862H43.8005C43.8571 30.0823 43.4731 30.0823 43.4731 30.0823H42.16V23.8145L46.2911 34.0666C46.4525 34.4688 46.8592 34.4688 46.8592 34.4688H51.205C51.205 34.4688 51.614 34.4688 51.7754 34.0666L56.3552 22.7258C56.5137 22.3327 56.055 22.3327 56.055 22.3327V22.3327ZM37.7474 30.0823H35.2764C34.2928 30.0823 33.4927 29.2859 33.4927 28.3012C33.4927 27.3182 34.2928 26.5167 35.2764 26.5167H35.9674C36.9485 26.5167 37.7474 27.3182 37.7474 28.3012V30.0823ZM35.5908 47.9835C22.3436 47.9835 11.6021 37.2426 11.6021 23.9935C11.6021 10.7429 22.3436 0 35.5908 0C48.8427 0 59.5854 10.7429 59.5854 23.9935C59.5854 37.2426 48.8427 47.9835 35.5908 47.9835Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+61
View File
@@ -0,0 +1,61 @@
import React, { useState } from "react";
import Tabs from "../tabs/Tabs";
import style from "./preview.module.css";
import { renderToString } from "react-dom/server";
import Bash from "../code/Bash";
import Prettier from "prettier/standalone";
import ParserBabel from "prettier/parser-babel";
const prettierOptions = {
semi: true,
parser: "babel",
plugins: [ParserBabel],
jsxBracketSameLine: false,
printWidth: 30,
};
interface PreviewProps {
react: string;
children?: React.ReactElement;
hideHtml?: boolean;
}
const Preview = ({
children,
react,
hideHtml = false,
...props
}: PreviewProps) => {
const [tab, setTab] = useState(0);
const handleChange = (x: number) => {
setTab(x);
};
const reactFormat = Prettier.format(react, prettierOptions).slice(0, -2);
const htmlFormat =
!!children &&
Prettier.format(
renderToString(
React.Children.count(children) > 1 ? <div>{children}</div> : children
),
prettierOptions
)
.slice(0, -2)
.replace(` data-reactroot=""`, "");
const tabs = !hideHtml || !!children ? ["REACT", "HTML/CSS"] : ["REACT"];
return (
<div className={style.wrapper}>
{!!children && <div className={style.preview}>{children}</div>}
<Tabs tabs={tabs} onChange={(x) => handleChange(x)} />
{tab === 0 && <Bash code={reactFormat} language="jsx" copy />}
{(!hideHtml || !!children) && tab === 1 && (
<Bash code={htmlFormat} language="jsx" copy />
)}
</div>
);
};
export default Preview;
@@ -0,0 +1,13 @@
.wrapper {
padding: 1rem;
margin: 1rem 0;
background-color: var(--bg-secondary);
margin-bottom: 3rem;
outline: var(--outline);
}
.preview {
border-bottom: 2px solid var(--code-divider);
padding-bottom: 3rem;
margin-bottom: 1rem;
}
+108
View File
@@ -0,0 +1,108 @@
import copy from "copy-to-clipboard";
import Prism from "prismjs";
import style from "./bash.module.css";
import cl from "classnames";
import { Files } from "@navikt/ds-icons";
import { Popover } from "@navikt/ds-react";
import { useEffect, useRef, useState } from "react";
import "prismjs/components/prism-jsx.min";
type PrismLanguages =
| "extend"
| "insertBefore"
| "DFS"
| "markup"
| "html"
| "mathml"
| "svg"
| "xml"
| "ssml"
| "atom"
| "rss"
| "css"
| "clike"
| "javascript"
| "js"
| "jsx";
export const copyCode = (content) => {
if (typeof content === "string") {
copy(content, {
format: "text/plain",
});
}
};
const Bash = ({
code,
terminal = false,
copy = false,
language = "html",
...props
}: {
code: string;
terminal?: boolean;
copy?: boolean;
language?: PrismLanguages;
}) => {
const highlighted = terminal
? code
: Prism.highlight(code, Prism.languages[language], language);
const buttonRef = useRef<HTMLButtonElement>(null);
const timeoutRef = useRef<NodeJS.Timeout>();
const [openPopover, setOpenPopover] = useState<boolean>(false);
useEffect(() => {
if (openPopover) {
timeoutRef.current = setTimeout(() => setOpenPopover(false), 1500);
return () => timeoutRef.current && clearTimeout(timeoutRef.current);
}
}, [openPopover]);
const handleCopy = () => {
copyCode(code);
setOpenPopover(true);
};
return (
<div className={style.preWrapper}>
<pre className={style.pre}>
<code
className={cl(style.code, {
[style.codeCopy]: copy,
[style.terminal]: terminal,
})}
{...props}
dangerouslySetInnerHTML={{ __html: highlighted }}
/>
{copy && (
<>
<div className={style.buttonBackground}>
<button
ref={buttonRef}
className={style.copyButton}
onClick={() => handleCopy()}
>
<Files />
</button>
<Popover
role="alert"
anchorEl={buttonRef.current}
open={openPopover}
onClose={() => setOpenPopover(false)}
size="small"
placement="auto-start"
/* arrow={false} */
>
Kode er kopiert
</Popover>
</div>
</>
)}
</pre>
</div>
);
};
export default Bash;
+22
View File
@@ -0,0 +1,22 @@
import Bash from "./Bash";
interface ImportProps {
from: string;
imports: string | string[];
namedExport?: boolean;
}
const Import = ({ namedExport = true, from, imports }: ImportProps) => {
const genCode = () => {
if (Array.isArray(imports)) {
return `import { ${imports.join(", ")} } from "${from}";`;
} else if (!namedExport) {
return `import ${imports} from "${from}";`;
} else {
return `import { ${imports} } from "${from}";`;
}
};
return <Bash code={genCode()} copy language="jsx"></Bash>;
};
export default Import;
+64
View File
@@ -0,0 +1,64 @@
.pre {
padding: 1rem;
margin: 1rem 0 0 0;
overflow: auto;
width: calc(100vw - 2rem);
background-color: var(--bg-code);
align-items: center;
display: flex;
/* Fixer pixelbug på høyre side av bash-panel */
box-shadow: inset -4px 0 0 var(--bg-code);
}
.preWrapper {
position: relative;
align-items: center;
display: flex;
}
.terminal {
color: var(--color-code);
}
.code {
padding-right: 4rem;
color: var(--color-code);
}
.terminal::before {
content: "$ ";
}
.buttonBackground {
width: 3rem;
background-color: var(--bg-code);
position: absolute;
right: 0;
margin: 1rem 0;
display: flex;
justify-content: center;
height: calc(100% - 3rem - 0.5rem);
align-items: center;
}
.copyButton {
background-color: var(--bg-code);
color: white;
font-size: 1.5rem;
padding: 0.5rem;
border: none;
align-items: center;
display: inline-flex;
height: 2.5rem;
width: 2.5rem;
}
.copyButton:hover {
background-color: rgba(255, 255, 255, 0.2);
}
.copyButton:focus {
outline: var(--outline-code);
outline-offset: var(--outline-offset);
}
+52
View File
@@ -0,0 +1,52 @@
import Header from "./header/Header";
import Sidebar from "./sidebar/Sidebar";
import { Grid, Cell, ContentContainer } from "@navikt/ds-react";
import { useMediaQuery } from "react-responsive";
import useKeypress from "react-use-keypress";
import { useEffect, useState } from "react";
import style from "./layout.module.css";
interface LayoutProps {
children?: React.ReactNode;
menu: any[];
}
const Layout = ({ children, menu }: LayoutProps) => {
const [sidebar, setSidebar] = useState(false);
const small = useMediaQuery({
query: "(max-width: 959px)",
});
useKeypress("Escape", () => {
setSidebar(false);
});
useEffect(() => {
setSidebar(!small);
}, [small]);
return (
<div className={style.pageWrapper + " lightTheme"}>
<Header sidebar={sidebar} onSidebarChange={(x) => setSidebar(x)} />
<Sidebar
menu={menu}
sidebar={sidebar}
small={small}
onSidebarChange={(x) => setSidebar(x)}
/>
{/* TEMP UNTIL LAYOUT UPDATE */}
<main className={style.contentWrapper}>
<ContentContainer>
<Grid>
<Cell className={style.content} xs={12} sm={12} md={12} lg={12}>
{children}
</Cell>
</Grid>
</ContentContainer>
</main>
</div>
);
};
export default Layout;
+40
View File
@@ -0,0 +1,40 @@
import Link from "next/link";
import NavLogo from "../../assets/navLogo.svg";
import { HamburgerFilled } from "@navikt/ds-icons";
import cl from "classnames";
import style from "../layout.module.css";
interface HeaderProps {
className?: string;
sidebar: boolean;
onSidebarChange: (x: boolean) => void;
}
const Header = ({
className,
sidebar,
onSidebarChange,
...props
}: HeaderProps) => {
return (
<header className={style.header}>
<button
onClick={() => onSidebarChange(!sidebar)}
className={cl(style.header__link, style.header__icon, {
[style["header__icon--hidden"]]: sidebar,
})}
tabIndex={!sidebar ? 0 : -1}
>
<HamburgerFilled />
</button>
<Link href="/">
<button className={style.header__link}>
<NavLogo />
<span className={style["header__link-title"]}>NAV Designsystem</span>
</button>
</Link>
</header>
);
};
export default Header;
+147
View File
@@ -0,0 +1,147 @@
.pageWrapper {
display: grid;
grid-template-columns: auto 1fr;
grid-template-rows: auto 1fr;
grid-template-areas:
"header header"
"sidebar content";
height: 100vh;
background-color: var(--bg-primary);
}
.header {
grid-area: header;
width: 100vw;
display: flex;
z-index: 99;
color: #fff;
height: 5rem;
background-color: #c30000;
}
.header__link {
background: none;
border: none;
display: flex;
align-items: center;
column-gap: 3rem;
height: 100%;
flex-shrink: 0;
}
.header__icon {
color: #fff;
font-size: 1.5rem;
height: 5rem;
width: 5rem;
display: flex;
justify-content: center;
flex-shrink: 0;
}
.sidebar__icon {
color: var(--navds-color-blue-50);
height: 5rem;
width: 5rem;
font-size: 1.5rem;
display: flex;
justify-content: center;
flex-shrink: 0;
background: none;
border: none;
align-items: center;
}
.sidebar__icon:focus {
outline: 2px solid var(--navds-color-blue-50);
outline-offset: -2px;
}
.header__icon--hidden {
visibility: hidden;
}
.header__link:focus {
outline: 2px solid white;
outline-offset: -2px;
}
.header__link-title {
color: white;
font-size: var(--navds-font-size-heading-large);
font-weight: var(--navds-font-weight-bold);
line-height: var(--navds-font-line-height-large);
}
.sidebar {
display: flex;
grid-area: sidebar;
flex-direction: column;
width: 300px;
flex-grow: 1;
flex-shrink: 1;
background-color: var(--bg-secondary);
box-shadow: inset -2px 0px 0px var(--sidebar-shadow);
flex-grow: 1;
}
.contentWrapper {
grid-area: content;
overflow-y: auto;
overflow: visible;
margin: 0 auto 0 0;
width: 100%;
/* TMP UNTIL LAYOUT UPDATE */
max-width: 520px;
}
.content {
width: 100%;
}
@media (max-width: 959px) {
.sidebar {
display: none;
}
}
@media (max-width: 447px) {
.header__link {
column-gap: 1rem;
}
}
.sidebar__mobile {
z-index: 999;
display: flex;
background-color: var(--bg-secondary);
flex-direction: column;
color: var(--text-color);
overflow-y: auto;
position: fixed;
left: -300px;
min-height: 100vh;
border-right: var(--sidebar-divider);
}
.sidebar__mobile--open {
transition: transform 250ms cubic-bezier(0.6, 0.05, 0.28, 0.91);
transform: translateX(100%);
}
.sidebar--overlay {
display: block;
z-index: 200;
background: rgba(0, 0, 0, 0);
position: fixed;
left: 0;
right: 0;
bottom: 0;
top: 0;
transition: background 0.15s linear;
}
.sidebar--overlay--fade {
background: rgba(0, 0, 0, 0.5);
}
+47
View File
@@ -0,0 +1,47 @@
import { NavdsPage } from "../../../src/pages";
import Link from "next/link";
/* TODO: Replace with accordion-menu when ready */
const subLinks = (page: NavdsPage) => {
return (
<div key={page.title}>
<span>{page.title}</span>
<ul id={"collapse " + page.title}>{parsePages(page.children)}</ul>
</div>
);
};
const parsePages = (pages) => {
return pages?.map((page) => {
if (page.pathName) {
return (
<li key={page.pathName}>
<Link href={page.pathName}>
{page.title ? page.title : parseTitle(page.pathName)}
</Link>
</li>
);
} else if (page.title && page.children) {
return subLinks(page);
} else {
return null;
}
});
};
const parseTitle = (path: string) =>
path
.split("/")
.pop()
.replace(/^\w/, (c) => c.toUpperCase())
.replace("-", " ") || "ERR: Default Title";
const Menu = ({ menu }) => {
return (
<nav>
<ul>{parsePages(menu)}</ul>
</nav>
);
};
export default Menu;
@@ -0,0 +1,45 @@
import cl from "classnames";
import { Close } from "@navikt/ds-icons";
import style from "../layout.module.css";
import Menu from "./Menu";
interface SidebarProps {
classname?: string;
sidebar: boolean;
small: boolean;
onSidebarChange: (x: boolean) => void;
menu: any[];
}
const Sidebar = ({ sidebar, small, onSidebarChange, menu }: SidebarProps) => {
return (
<>
{sidebar && small && (
<div
onClick={() => onSidebarChange(false)}
className={cl(style["sidebar--overlay"], {
[style["sidebar--overlay--fade"]]: sidebar,
})}
/>
)}
<div
className={cl(style.sidebar, {
[style.sidebar__mobile]: small,
[style["sidebar__mobile--open"]]: small && sidebar,
})}
>
{small && sidebar && (
<button
onClick={() => onSidebarChange(!sidebar)}
className={style.sidebar__icon}
>
<Close />
</button>
)}
<Menu menu={menu} />
</div>
</>
);
};
export default Sidebar;
+61
View File
@@ -0,0 +1,61 @@
import getConfig from "next/config";
import Import from "../code/Import";
import style from "./npm.module.css";
const Npm = ({
packName,
imports,
namedExport,
}: {
packName: string;
imports: string | string[];
namedExport?: boolean;
}) => {
const { publicRuntimeConfig } = getConfig();
const packs = publicRuntimeConfig.packages.filter(
(pack) => pack.name === packName
);
return (
<div>
{packs.map(({ name, data }) => (
<div key={name}>
<span className={style.badges}>
<a
target="_blank"
rel="noreferrer"
href={`https://www.npmjs.com/package/${name}`}
>
<img src={`https://badgen.net/npm/v/${name}`} alt="123" />
</a>
<a
target="_blank"
rel="noreferrer"
href={`https://bundlephobia.com/result?p=${name}`}
>
<img
src={`https://badgen.net/bundlephobia/tree-shaking/${name}`}
alt="123"
/>
</a>
<a
target="_blank"
rel="noreferrer"
href={`https://bundlephobia.com/result?p=${name}`}
>
<img
src={`https://badgen.net/bundlephobia/min/${name}`}
alt="123"
/>
</a>
</span>
<Import from={name} imports={imports} namedExport={namedExport} />
</div>
))}
</div>
);
};
export default Npm;
+5
View File
@@ -0,0 +1,5 @@
.badges {
display: flex;
column-gap: 0.5rem;
flex-wrap: wrap;
}
-11
View File
@@ -1,11 +0,0 @@
interface SidebarProps {}
const Sidebar = ({ ...props }: SidebarProps) => {
return (
<>
<div>Current path</div>
</>
);
};
export default Sidebar;
@@ -0,0 +1,32 @@
import { useContext } from "react";
import { Next } from "@navikt/ds-icons";
import { Heading } from "@navikt/ds-react";
import style from "./tableOfContents.module.css";
import { PagePropsContext } from "../../pages/_app";
const TableOfContents = () => {
const { tableOfContents } = useContext<any>(PagePropsContext);
return (
<>
<Heading size="large" level={2}>
Innhold
</Heading>
<ul className={style.ul}>
{tableOfContents?.map(({ heading, slug }) => (
<li key={slug} className={style.li}>
<Next
aria-label="Pil peker på lenke"
focusable="false"
role="img"
aria-hidden
/>
<a href={`#${slug}`}>{heading}</a>
</li>
))}
</ul>
</>
);
};
export default TableOfContents;
@@ -0,0 +1,45 @@
.ul {
margin: 0;
padding: 0;
list-style: none;
}
.li {
list-style: none;
margin: 0;
font-size: var(--navds-font-size-medium);
line-height: var(--navds-font-line-height-medium);
color: var(--navds-color-blue-50);
display: flex;
align-items: center;
transition: margin 100ms linear;
column-gap: 0.25rem;
padding: 0.25rem 0;
width: fit-content;
}
.li > svg {
flex-shrink: 0;
}
.li:hover {
margin-left: 0.25rem;
}
.li > a {
padding: 0.25rem 0;
}
.li:hover > a,
.li:hover > svg {
color: var(--navds-color-darkgray);
transition: color 150ms linear;
text-decoration: underline;
}
.li > svg + a:focus {
color: white;
transition: color 0ms linear;
background-color: var(--navds-color-blue-80);
outline: none;
}
+34
View File
@@ -0,0 +1,34 @@
import { useState } from "react";
import style from "./tabs.module.css";
import cl from "classnames";
interface TabsProps {
onChange: (tab: number) => void;
tabs: string[];
}
const Tabs = ({ onChange, tabs, ...props }: TabsProps) => {
const [tab, setTab] = useState(0);
const handleClick = (x: number) => {
onChange(x);
setTab(x);
};
return (
<ul className={style.ul}>
{tabs.map((t, x) => (
<li key={t + x} className={style.li}>
<button
className={cl(style.button, { [style.buttonActive]: x === tab })}
onClick={() => handleClick(x)}
>
{t}
</button>
</li>
))}
</ul>
);
};
export default Tabs;
+32
View File
@@ -0,0 +1,32 @@
.ul {
padding: 0;
margin: 0;
display: flex;
}
.li {
list-style: none;
}
.button {
color: var(--tab-color);
border: none;
background: none;
padding: 0.5rem 1.5rem;
font-weight: var(--navds-font-weight-bold);
}
.button:hover {
border-bottom: 4px solid var(--navds-color-darkgray);
color: var(--navds-color-darkgray);
}
.button:focus {
outline: var(--outline-focus);
outline-offset: var(--outline-offset);
}
.buttonActive {
border-bottom: var(--tab-border);
color: var(--tab-color-active);
}
+7
View File
@@ -0,0 +1,7 @@
---
title: Button
---
# Button content
<Npm packName="@navikt/ds-react" imports="Button" />
+4
View File
@@ -0,0 +1,4 @@
---
title: Komponenter
rank: 3
---
+5
View File
@@ -0,0 +1,5 @@
---
title: Header
---
# interne flater header
+3
View File
@@ -0,0 +1,3 @@
---
title: Interne flater
---
+32
View File
@@ -0,0 +1,32 @@
---
title: Kom i gang
rank: 1
---
# Kom i gang content
<TableOfContents />
## Varianter
## Varianter
Deserunt nostrud anim nisi reprehenderit cillum commodo. Ullamco excepteur sit aute commodo duis. Elit magna laboris amet occaecat velit proident dolore nostrud. Qui ullamco tempor ex sunt veniam cillum et anim. Deserunt dolore voluptate dolor nulla commodo laboris ad. Sint excepteur eu velit consectetur nostrud non irure excepteur adipisicing.
## Størrelser
Non fugiat irure excepteur adipisicing nulla enim nisi. Ut dolore ullamco est commodo consectetur nisi pariatur labore incididunt. Aute ipsum magna nulla sunt labore do nulla laboris anim proident Lorem deserunt aute ea. Anim ea aute qui ullamco. Proident nostrud sunt sit minim excepteur esse. Lorem laboris ad dolore qui pariatur laborum sunt dolore laboris voluptate incididunt. Quis amet aliqua eu minim laboris id occaecat.
## Interne-flater
adad
## Tilgjengelighet
adasd
## Eksempler for bruk
Non fugiat irure excepteur adipisicing nulla enim nisi. Ut dolore ullamco est commodo consectetur nisi pariatur labore incididunt. Aute ipsum magna nulla sunt labore do nulla laboris anim proident Lorem deserunt aute ea. Anim ea aute qui ullamco. Proident nostrud sunt sit minim excepteur esse. Lorem laboris ad dolore qui pariatur laborum sunt dolore laboris voluptate incididunt. Quis amet aliqua eu minim laboris id occaecat.
## Prop-table
+4
View File
@@ -0,0 +1,4 @@
---
title: Retningslinjer
rank: 2
---
+5
View File
@@ -0,0 +1,5 @@
---
title: Typografi
---
# Typografi content
+1
View File
@@ -0,0 +1 @@
# Hello, world
+4
View File
@@ -0,0 +1,4 @@
module.exports = {
preset: "ts-jest",
testEnvironment: "node",
};
+21 -1
View File
@@ -1,5 +1,25 @@
const glob = require("glob");
const loadPackage = () => {
const navFrontend = glob.sync("../packages/**/package.json");
const vnext = glob.sync("../@navikt/*/package.json");
return [...navFrontend, ...vnext]
.filter((file) => !file.includes("node_modules"))
.map((file) => {
const pack = require(file);
return { name: pack.name, data: pack };
});
};
module.exports = {
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
webpack: (config) => {
config.module.rules.push({
test: /\.svg$/,
use: ["@svgr/webpack"],
});
return config;
},
publicRuntimeConfig: {
packages: loadPackage(),
},
};
+26 -3
View File
@@ -5,7 +5,8 @@
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
"start": "next start",
"test": "jest"
},
"dependencies": {
"@types/react": "^17.0.2",
@@ -13,8 +14,30 @@
"react": "17.0.1",
"react-dom": "17.0.1",
"typescript": "^4.2.3",
"@navikt/ds-css": "^0.2.0",
"@navikt/ds-react": "^0.2.0"
"react-responsive": "^8.2.0",
"react-use-keypress": "^1.2.0",
"classnames": "^2.2.6",
"glob": "^7.1.6",
"copy-to-clipboard": "^3.3.1",
"remark-parse": "^9.0.0",
"unified": "^9.2.1",
"prismjs": "^1.23.0",
"@svgr/webpack": "^5.5.0",
"@navikt/ds-css": "*",
"@navikt/ds-react": "*",
"next-mdx-remote": "^2.1.3",
"github-slugger": "1.3.0",
"remark-slug": "6.0.0"
},
"devDependencies": {
"@next/bundle-analyzer": "^10.0.8",
"@types/prettier": "^2.2.2",
"@types/react-dom": "^17.0.2",
"prettier": "2.2.1",
"gray-matter": "^4.0.2",
"jest": "^26.6.3",
"ts-jest": "^26.5.4",
"@types/jest": "^22.2.3"
},
"eslintConfig": {
"rules": {
+45
View File
@@ -0,0 +1,45 @@
import fs from "fs";
import glob from "glob";
import matter from "gray-matter";
import hydrate from "next-mdx-remote/hydrate";
import renderToString from "next-mdx-remote/render-to-string";
import components from "../components/MDXComponents";
import tableOfContents from "../src/table-of-contents";
import mainMenu from "../src/main-menu";
const Page = ({ mdxSource }) => hydrate(mdxSource, { components });
export default Page;
export async function getStaticProps({ params: { path } }) {
const { content } = matter(
fs.readFileSync(`data/${path?.join("/") || "index"}.mdx`, "utf8")
);
return {
props: {
mdxSource: await renderToString(content, {
components,
mdxOptions: {
remarkPlugins: [require("remark-slug")],
},
}),
menu: mainMenu(),
tableOfContents: tableOfContents(content),
},
};
}
export async function getStaticPaths() {
return {
paths: [
{ params: { path: [] } },
...glob
.sync("data/**/*.mdx")
.filter((path) => !path.endsWith("index.mdx"))
.map((path) => path.slice(5, -4).split("/"))
.map((path) => ({ params: { path } })),
],
fallback: false,
};
}
+13 -8
View File
@@ -1,19 +1,24 @@
import { createContext } from "react";
import Head from "next/head";
import { useRouter } from "next/router";
import Sidebar from "../components/sidebar/Sidebar";
/* import "@navikt/ds-css/baseline/index.css"; */
import Layout from "../components/layout/Layout";
import "../styles/theme.css";
import "../styles/globals.css";
import "../styles/prismjs.css";
import "@navikt/ds-css";
export const PagePropsContext = createContext({});
const Website = ({ Component, pageProps }) => {
const route = useRouter();
return (
<>
<PagePropsContext.Provider value={pageProps}>
<Head>
<title>NAV Designsystem</title>
<link rel="icon" href="/favicon-32x32.png" />
</Head>
<Sidebar route={route} />
<Component {...pageProps} />
</>
<Layout menu={pageProps.menu}>
<Component {...pageProps} />
</Layout>
</PagePropsContext.Provider>
);
};
-7
View File
@@ -1,7 +0,0 @@
export default function Home() {
return (
<div>
<main>Website</main>
</div>
);
}
-11
View File
@@ -1,11 +0,0 @@
interface Props {}
const KomIGang = ({ ...props }: Props) => {
return (
<>
<div>Kom-i-gang</div>
</>
);
};
export default KomIGang;
+45
View File
@@ -0,0 +1,45 @@
import fs from "fs";
import glob from "glob";
import matter from "gray-matter";
import pathsToTree from "../src/paths-to-tree";
export default () => {
let tree = pathsToTree(
glob.sync("data/**/*.mdx").filter((path) => !path.endsWith("index.mdx"))
);
const populateNode = (node, parentPath) => {
let metadata;
if (node.name.endsWith(".mdx")) {
metadata = matter(fs.readFileSync(`${parentPath}${node.name}`, "utf8"))
.data;
} else {
const indexPath = `${parentPath}${node.name}/index.mdx`;
if (fs.existsSync(indexPath)) {
metadata = matter(fs.readFileSync(indexPath, "utf8")).data;
}
}
if (metadata) {
if (metadata.title) {
node.title = metadata.title;
}
if (metadata.rank) {
node.rank = metadata.rank;
}
}
if (node.children) {
node.children.forEach((child) =>
populateNode(child, `${parentPath}${node.name}/`)
);
node.children.sort((a, b) => a.rank - b.rank);
} else {
node.pathName = `/${parentPath}${node.name}`.slice(5, -4);
}
};
tree.forEach((node) => populateNode(node, ""));
return tree[0].children;
};
+48
View File
@@ -0,0 +1,48 @@
export interface NavdsPage {
pathName?: string;
children?: NavdsPage[];
title?: string;
}
const pages: NavdsPage[] = [
{
pathName: "/kom-i-gang",
},
{
title: "Komponenter",
children: [
{ pathName: "/komponenter", title: "Kom i gang" },
{ pathName: "/komponenter/alert" },
{ pathName: "/komponenter/accordion" },
{ pathName: "/komponenter/button" },
{
title: "Interne flater",
children: [
{ pathName: "/komponenter/interne-flater/header" },
{ pathName: "/komponenter/interne-flater/copy-knapp" },
],
},
],
},
{
title: "Ikonpakke",
children: [
{ pathName: "/ikonpakke", title: "Ikonsøk" },
{ pathName: "/ikonpakke/installering" },
],
},
{
title: "Retningslinjer",
children: [
{ pathName: "/retningslinjer/farger" },
{ pathName: "/retningslinjer/typografi" },
{ pathName: "/retningslinjer/språk" },
],
},
{
pathName: "/kontakt",
title: "Kontakt oss",
},
];
export default pages;
+41
View File
@@ -0,0 +1,41 @@
import pathsToTree from "./paths-to-tree";
test("empty list", () => {
expect(pathsToTree([])).toEqual([]);
});
test("single simple string", () => {
expect(pathsToTree(["foo"])).toEqual([{ name: "foo" }]);
});
test("two levels", () => {
expect(pathsToTree(["foo/bar"])).toEqual([
{
name: "foo",
children: [{ name: "bar" }],
},
]);
});
test("two levels, two strings", () => {
expect(pathsToTree(["foo", "foo/bar"])).toEqual([
{
name: "foo",
children: [{ name: "bar" }],
},
]);
});
test("three levels, three strings", () => {
expect(pathsToTree(["foo", "foo/bar/baz", "foo/bar"])).toEqual([
{
name: "foo",
children: [
{
name: "bar",
children: [{ name: "baz" }],
},
],
},
]);
});
+22
View File
@@ -0,0 +1,22 @@
type Node = {
name: string;
children?: Node[];
};
const pathsToTree: (paths: string[]) => Node[] = (paths: string[]) =>
paths.reduce((list, path) => {
path.split("/").reduce((list, name, i, a) => {
let node = list.find((item) => item.name === name);
if (!node) {
node = { name };
list.push(node);
}
if (!node.children && i !== a.length - 1) {
node.children = [];
}
return node.children;
}, list);
return list;
}, []);
export default pathsToTree;
+18
View File
@@ -0,0 +1,18 @@
import GithubSlugger from "github-slugger";
import markdown from "remark-parse";
import unified from "unified";
export default (content) => {
const slugger = new GithubSlugger();
return unified()
.use(markdown)
.parse(content)
.children.filter((node) => node.type === "heading")
.filter((node) => node.depth === 2)
.map((node) => node.children[0].value)
.map((heading) => ({
heading,
slug: slugger.slug(heading),
}));
};
+2
View File
@@ -2,6 +2,8 @@ html,
body {
padding: 0;
margin: 0;
background-color: var(--bg-primary);
scroll-behavior: smooth;
}
a {
+122
View File
@@ -0,0 +1,122 @@
/**
* Dracula Theme originally by Zeno Rocha [@zenorocha]
* https://draculatheme.com/
*
* Ported for PrismJS by Albert Vallverdu [@byverdu]
*/
code[class*="language-"],
pre[class*="language-"] {
color: #f8f8f2;
background: none;
text-shadow: 0 1px rgba(0, 0, 0, 0.3);
font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: 0.5em 0;
overflow: auto;
border-radius: 0.3em;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #282a36;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: 0.1em;
border-radius: 0.3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #6272a4;
}
.token.punctuation {
color: #f8f8f2;
}
.namespace {
opacity: 0.7;
}
.token.property,
.token.tag,
.token.constant,
.token.symbol,
.token.deleted {
color: #ff79c6;
}
.token.boolean,
.token.number {
color: #bd93f9;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #50fa7b;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string,
.token.variable {
color: #f8f8f2;
}
.token.atrule,
.token.attr-value,
.token.function,
.token.class-name {
color: #f1fa8c;
}
.token.keyword {
color: #8be9fd;
}
.token.regex,
.token.important {
color: #ffb86c;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
+24
View File
@@ -0,0 +1,24 @@
:root {
--bg-primary: #faf9f9;
}
.darkTheme {
--theme: "dark";
}
.lightTheme {
--theme: "light";
--bg-primary: #faf9f9;
--bg-secondary: #fff;
--sidebar-shadow: #e7e9e9;
--outline: 1px solid var(--navds-color-gray-40);
--tab-color: var(--navds-color-blue-50);
--tab-color-active: var(--navds-color-darkgray);
--tab-border: 4px solid var(--navds-color-blue-50);
--outline-focus: 2px solid var(--navds-color-blue-80);
--outline-offset: -2px;
--bg-code: var(--navds-color-darkgray);
--color-code: #fff;
--code-divider: var(--sidebar-shadow);
--outline-code: 2px solid var(--color-code);
}
+2 -2
View File
@@ -137,13 +137,13 @@
"prettier": "2.2.1",
"prop-types": "^15.5.10",
"react": "^16.8.0 || ^17.0.0",
"react-docgen-typescript": "^1.21.0",
"react-is": "^16.13.1",
"stylelint": "^13.7.2",
"stylelint-config-standard": "^20.0.0",
"svg-url-loader": "^7.1.1",
"typescript": "^3.7.3",
"webpack": "^5.4.0",
"webpack-cli": "^4.2.0",
"react-docgen-typescript": "^1.21.0"
"webpack-cli": "^4.2.0"
}
}
@@ -27,7 +27,7 @@ Legg til `import EkspanderbartPanel from 'nav-frontend-ekspanderbartpanel'`
Bruker man `redux` har man mulighet til å lagre staten der, og kan (om man vil) bruke en `pure` versjon av panelet.
Da må man selv alltid sende inn `apen`-propen.
Legg til `import { EkspanderbartpanelPure } from 'nav-frontend-ekspanderbartpanel'`
Legg til `import { EkspanderbartpanelBase } from 'nav-frontend-ekspanderbartpanel'`
<!-- AUTO-GENERATED-CONTENT:START (DISCLAIMER) -->
+1543 -349
View File
File diff suppressed because it is too large. Load diff