Compare commits

..
Author SHA1 Message Date
github-actions[bot] 064bf66c0f Lerna versionbump [ci skip]
- @navikt/ds-css@0.15.7
2022-02-22 14:00:59 +00:00
Ken a8b66dfec9 [FIX] charset utf-8 i css (#1433) 2022-02-22 14:53:27 +01:00
github-actions[bot] 8f99813590 Lerna versionbump [ci skip]
- @navikt/ds-react@0.16.12
 - @navikt/ds-react-internal@0.11.12
2022-02-22 11:47:39 +00:00
Ken 21b078a9a4 [FIX] hotfix modal-props 2022-02-22 12:39:41 +01:00
github-actions[bot] e89d3b27b2 Lerna versionbump [ci skip]
- @navikt/ds-css@0.15.6
 - @navikt/ds-react@0.16.11
 - @navikt/ds-react-internal@0.11.11
2022-02-22 11:20:41 +00:00
Andreas NordahlandKen ddd2fd2e08 [fix] Pagination component (#1420)
* add pagination component and styles

* pagination css custom props

* 1px #fff linje mellom bg og shadow

* fix focus bug

* fix tilbake title bug

* endret på stories

* errors on invalid pagination arguments

* prev & next -> prev-next

* fix next-prev button focus padding

Co-authored-by: Ken <ken.aleksander@gmail.com>
2022-02-22 12:13:39 +01:00
github-actions[bot] a7c326aa43 Lerna versionbump [ci skip]
- @navikt/ds-react@0.16.10
 - @navikt/ds-react-internal@0.11.10
2022-02-22 10:09:25 +00:00
Ken 0b89387bae [FIX] ToggleGroup role=toolbar for NVDA-støtte (#1431) 2022-02-22 11:01:44 +01:00
github-actions[bot] 8a58d75efb Lerna versionbump [ci skip]
- @navikt/ds-css@0.15.5
 - @navikt/ds-react@0.16.9
 - @navikt/ds-react-internal@0.11.9
2022-02-21 09:35:40 +00:00
Ken bf18ffcb0c [FIX] ToggleGroup css-patch (#1430) 2022-02-21 10:28:43 +01:00
Ken ad3c88d542 [ci skip] revert siste endring 2022-02-18 16:01:41 +01:00
Ken eb90447bb7 [FIX] Forced CJS-versjon av ToggleGroup 2022-02-18 14:23:42 +01:00
16 changed files with 525 additions and 14 deletions

No files matched your search

+2
View File
@@ -1,3 +1,4 @@
@charset "UTF-8";
@import "baseline/baseline.css";
@import "typography.css";
@import "grid.css";
@@ -13,6 +14,7 @@
@import "loader.css";
@import "menu.css";
@import "modal.css";
@import "pagination.css";
@import "popover.css";
@import "tag.css";
@import "toggle-group.css";
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-css",
"version": "0.15.4",
"version": "0.15.7",
"private": false,
"description": "Css for NAV Designsystem components",
"author": "NAV Designsystem team",
+118
View File
@@ -0,0 +1,118 @@
: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-pagination-color-text-selected: var(
--navds-semantic-color-text-inverted
);
}
.navds-pagination {
display: flex;
}
.navds-pagination__list {
margin: 0;
padding: 0;
list-style: none;
display: flex;
gap: var(--navds-spacing-3);
}
.navds-pagination__ellipsis {
display: flex;
align-items: center;
justify-content: center;
width: var(--navds-spacing-8);
cursor: default;
}
.navds-pagination--small .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: 2px;
padding: var(--navds-spacing-1) var(--navds-spacing-3);
}
.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__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__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: 2px;
}
.navds-pagination__prev-next:focus {
outline: none;
box-shadow: inset 0 0 0 2px var(--navds-semantic-color-focus);
}
.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;
}
+6 -2
View File
@@ -34,13 +34,13 @@
align-items: center;
justify-content: center;
padding: var(--navds-spacing-3);
min-width: 48px;
min-height: 48px;
border: none;
cursor: pointer;
background-color: var(--navds-toggle-group-color-background);
color: var(--navds-toggle-group-color-text);
border-radius: 2px;
min-width: fit-content;
}
.navds-toggle-group__button:hover {
@@ -65,6 +65,10 @@
gap: var(--navds-spacing-2);
}
.navds-toggle-group__button-inner > * {
flex-shrink: 0;
}
.navds-toggle-group__button[aria-pressed="true"] {
background-color: var(--navds-toggle-group-color-background-pressed);
color: var(--navds-toggle-group-color-text-pressed);
@@ -72,8 +76,8 @@
.navds-toggle-group--small > .navds-toggle-group__button {
padding: 0.375rem;
min-width: 32px;
min-height: 32px;
min-width: fit-content;
}
.navds-toggle-group__button > .navds-toggle-group__button-inner > svg {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-react",
"version": "0.16.8",
"version": "0.16.12",
"private": false,
"description": "NAV designsystem react components",
"author": "NAV Designsystem team",
+1
View File
@@ -10,6 +10,7 @@ export * from "./link-panel";
export * from "./loader";
export * from "./menu";
export * from "./modal";
export * from "./pagination";
export * from "./panel";
export * from "./popover";
export * from "./speech-bubble";
+1 -1
View File
@@ -6,7 +6,7 @@ import { Close } from "@navikt/ds-icons";
import { Button } from "..";
import ModalContent, { ModalContentType } from "./ModalContent";
export interface ModalProps extends ReactModal {
export interface ModalProps {
/**
* Modal content
*/
@@ -0,0 +1,191 @@
import React from "react";
import cl from "classnames";
import { Back, Next } from "@navikt/ds-icons";
import { BodyShort } from "..";
interface PaginationProps extends React.HTMLAttributes<HTMLElement> {
/**
* Current page
*/
page: number;
/**
* Number of always visible pages before and after the current page.
* @default 1
*/
siblingCount?: number;
/**
* Number of always visible pages at the beginning and end.
* @default 1
*/
boundaryCount?: number;
/**
* Callback when current page changes
*/
onPageChange: (page: number) => void;
/**
* Total number of pages
*/
count: number;
/**
* Changes padding, height and font-size
* @default "medium"
*/
size?: "medium" | "small";
/**
* Display text alongside "previous" and "next" icons
* @default false
*/
prevNextTexts?: boolean;
}
export const getSteps = ({
page,
count,
boundaryCount = 1,
siblingCount = 1,
}) => {
const range = (start: number, end: number) =>
Array.from({ length: end - start + 1 }, (_, i) => start + i);
if (count <= (boundaryCount + siblingCount) * 2 + 3) return range(1, count);
const startPages = range(1, boundaryCount);
const endPages = range(count - boundaryCount + 1, count);
const siblingsStart = Math.max(
Math.min(page - siblingCount, count - boundaryCount - siblingCount * 2 - 1),
boundaryCount + 2
);
const siblingsEnd = siblingsStart + siblingCount * 2;
return [
...startPages,
siblingsStart - (startPages[startPages.length - 1] ?? 0) === 2
? siblingsStart - 1
: "ellipsis",
...range(siblingsStart, siblingsEnd),
(endPages[0] ?? count + 1) - siblingsEnd === 2
? siblingsEnd + 1
: "ellipsis",
...endPages,
];
};
const Pagination = ({
page,
onPageChange,
count,
boundaryCount = 1,
siblingCount = 1,
className,
size = "medium",
prevNextTexts = false,
}: PaginationProps) => {
if (page < 1) {
console.error("page cannot be less than 1");
return null;
}
if (count < 1) {
console.error("count cannot be less than 1");
return null;
}
if (boundaryCount < 0) {
console.error("boundaryCount cannot be less than 0");
return null;
}
if (siblingCount < 0) {
console.error("siblingCount cannot be less than 0");
return null;
}
return (
<nav
className={cl("navds-pagination", `navds-pagination--${size}`, className)}
>
{prevNextTexts && (
<button
className="navds-pagination__prev-next"
disabled={page === 1}
onClick={() => onPageChange(page - 1)}
>
<Back
className="navds-pagination__prev-next-icon"
role="presentation"
/>
<BodyShort size={size} className="navds-pagination__prev-text">
Tilbake
</BodyShort>
</button>
)}
<ul className="navds-pagination__list">
{!prevNextTexts && (
<li>
<button
className="navds-pagination__prev-next"
disabled={page === 1}
onClick={() => onPageChange(page - 1)}
>
<Back
className="navds-pagination__prev-next-icon"
title="Tilbake"
/>
</button>
</li>
)}
{getSteps({ page, count, siblingCount, boundaryCount }).map(
(step, i) => {
const n = Number(step);
return isNaN(n) ? (
<li className="navds-pagination__ellipsis" key={`${step}${i}`}>
<BodyShort size={size}>...</BodyShort>
</li>
) : (
<li key={step}>
<BodyShort
size={size}
as="button"
className="navds-pagination__item"
onClick={() => onPageChange(n)}
aria-current={page === n ? true : undefined}
>
{n}
</BodyShort>
</li>
);
}
)}
{!prevNextTexts && (
<li>
<button
className="navds-pagination__prev-next"
disabled={page === count}
onClick={() => onPageChange(page + 1)}
>
<Next
className="navds-pagination__prev-next-icon"
title="Neste"
/>
</button>
</li>
)}
</ul>
{prevNextTexts && (
<button
className="navds-pagination__prev-next"
disabled={page === count}
onClick={() => onPageChange(page + 1)}
>
<BodyShort size={size} className="navds-pagination__next-text">
Neste
</BodyShort>
<Next
className="navds-pagination__prev-next-icon"
role="presentation"
/>
</button>
)}
</nav>
);
};
export default Pagination;
@@ -0,0 +1,2 @@
export { default as Pagination } from "./Pagination";
export * from "./Pagination";
@@ -0,0 +1,37 @@
import React, { useState } from "react";
import Pagination from "./Pagination";
export default {
title: "ds-react/pagination",
component: Pagination,
};
export const All = (props) => {
const [page, setPage] = useState(props.page);
return (
<div>
<h2>Pagination</h2>
<Pagination {...props} page={page} onPageChange={setPage} />
<h2>Small</h2>
<Pagination size="small" {...props} page={page} onPageChange={setPage} />
<h2>prevNextTexts</h2>
<Pagination prevNextTexts {...props} page={page} onPageChange={setPage} />
<h3>prevNextTexts small</h3>
<Pagination
prevNextTexts
size="small"
{...props}
page={page}
onPageChange={setPage}
/>
</div>
);
};
All.args = {
page: 1,
count: 8,
siblingCount: 1,
boundaryCount: 1,
};
@@ -0,0 +1,120 @@
import faker from "faker";
import { getSteps } from "./Pagination";
describe("getSteps", () => {
it("lists all pages when count is <= 7", () => {
const count = faker.datatype.number({ min: 1, max: 7 });
expect(getSteps({ page: 1, count })).toEqual(
Array.from({ length: count }, (_, i) => i + 1)
);
});
it("has an end ellipsis when count >= 8", () => {
const count = faker.datatype.number({ min: 8 });
const page = faker.datatype.number({ min: 1, max: 4 });
expect(
getSteps({
page,
count,
})
).toEqual([1, 2, 3, 4, 5, "ellipsis", count]);
});
it("has a start ellipsis when count - page >= 3", () => {
const count = faker.datatype.number({ min: 8 });
const page = faker.datatype.number({ min: count - 3, max: count });
expect(
getSteps({
page,
count,
})
).toEqual([
1,
"ellipsis",
count - 4,
count - 3,
count - 2,
count - 1,
count,
]);
});
it("has start & end ellipsis when count is high", () => {
const count = faker.datatype.number({ min: 9 });
const page = faker.datatype.number({ min: 5, max: count - 4 });
expect(
getSteps({
page,
count,
})
).toEqual([1, "ellipsis", page - 1, page, page + 1, "ellipsis", count]);
});
it("can have a reduced siblingCount", () => {
const count = faker.datatype.number({ min: 7 });
const page = faker.datatype.number({ min: 4, max: count - 3 });
expect(
getSteps({
page,
count,
siblingCount: 0,
})
).toEqual([1, "ellipsis", page, "ellipsis", count]);
});
it("can have an increased siblingCount", () => {
const count = faker.datatype.number({ min: 11 });
const page = faker.datatype.number({ min: 6, max: count - 5 });
expect(
getSteps({
page,
count,
siblingCount: 2,
})
).toEqual([
1,
"ellipsis",
page - 2,
page - 1,
page,
page + 1,
page + 2,
"ellipsis",
count,
]);
});
it("can have an reduced boundaryCount", () => {
const count = faker.datatype.number({ min: 7 });
const page = faker.datatype.number({ min: 4, max: count - 3 });
expect(
getSteps({
page,
count,
boundaryCount: 0,
})
).toEqual(["ellipsis", page - 1, page, page + 1, "ellipsis"]);
});
it("can have an increased boundaryCount", () => {
const count = faker.datatype.number({ min: 11 });
const page = faker.datatype.number({ min: 6, max: count - 5 });
expect(
getSteps({
page,
count,
boundaryCount: 2,
})
).toEqual([
1,
2,
"ellipsis",
page - 1,
page,
page + 1,
"ellipsis",
count - 1,
count,
]);
});
});
@@ -10,19 +10,43 @@ export default {
},
} as Meta;
const Items = (icon?: boolean) => (
const Items = (icon?: boolean, both?: boolean) => (
<>
<ToggleGroup.Item value="first">
{icon ? <Hamburger /> : "First"}
{both ? (
<>
<Hamburger /> First
</>
) : (
<>{icon ? <Hamburger /> : "First"}</>
)}
</ToggleGroup.Item>
<ToggleGroup.Item value="second">
{icon ? <Star /> : "Second more txt"}
{both ? (
<>
<Star /> Second more txt
</>
) : (
<>{icon ? <Star /> : "Second more txt"}</>
)}
</ToggleGroup.Item>
<ToggleGroup.Item value="third">
{icon ? <Attachment /> : "Third"}
{both ? (
<>
<Attachment /> Thrid
</>
) : (
<>{icon ? <Attachment /> : "Third"}</>
)}
</ToggleGroup.Item>
<ToggleGroup.Item value="fourth">
{icon ? <System /> : "Fourth"}
{both ? (
<>
<System /> Fourth
</>
) : (
<>{icon ? <System /> : "Fourth"}</>
)}
</ToggleGroup.Item>
</>
);
@@ -41,6 +65,9 @@ export const All = () => {
<ToggleGroup value={activeValue} onChange={setActiveValue}>
{Items(true)}
</ToggleGroup>
<ToggleGroup value={activeValue} onChange={setActiveValue}>
{Items(true, true)}
</ToggleGroup>
</div>
<h2>ToggleGroup Small</h2>
<h3>{activeValue}</h3>
@@ -51,6 +78,9 @@ export const All = () => {
<ToggleGroup size="small" value={activeValue} onChange={setActiveValue}>
{Items(true)}
</ToggleGroup>
<ToggleGroup size="small" value={activeValue} onChange={setActiveValue}>
{Items(true, true)}
</ToggleGroup>
</div>
<h2>ToggleGroup label</h2>
<div style={{ display: "flex", flexDirection: "column", gap: "0.5rem" }}>
@@ -88,6 +88,10 @@ const ToggleGroup = forwardRef<HTMLDivElement, ToggleGroupProps>(
[labelId]: !!label,
});
if (!value && !defaultValue) {
console.error("ToggleGroup needs either a value or defaultValue");
}
return (
<ToggleGroupContext.Provider
value={{
@@ -116,6 +120,7 @@ const ToggleGroup = forwardRef<HTMLDivElement, ToggleGroupProps>(
`navds-toggle-group--${size}`
)}
{...(describeBy && { "aria-describedby": describeBy })}
role="toolbar"
type="single"
>
{children}
@@ -1,7 +1,8 @@
import React, { forwardRef, useContext } from "react";
import cl from "classnames";
import { Label, ToggleGroupContext } from "..";
import { Label } from "..";
import * as RadixToggleGroup from "@radix-ui/react-toggle-group";
import { ToggleGroupContext } from "./ToggleGroup";
export interface ToggleItemProps
extends React.HTMLAttributes<HTMLButtonElement> {
+1 -1
View File
@@ -1,2 +1,2 @@
export { default as ToggleGroup } from "./ToggleGroup";
export * from "./ToggleGroup";
export { ToggleGroupProps } from "./ToggleGroup";
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-react-internal",
"version": "0.11.8",
"version": "0.11.12",
"private": false,
"description": "NAV internal designsystem react components",
"author": "NAV Designsystem team",
@@ -34,7 +34,7 @@
},
"dependencies": {
"@navikt/ds-icons": "^0.8.4",
"@navikt/ds-react": "^0.16.8",
"@navikt/ds-react": "^0.16.12",
"@popperjs/core": "^2.10.1",
"classnames": "^2.3.1",
"copy-to-clipboard": "^3.3.1",