Skip to content

Commit

Permalink
feat: table of contents component
Browse files Browse the repository at this point in the history
  • Loading branch information
Robbert authored and Yolijn committed Oct 1, 2024
1 parent 7b8ebea commit 1227678
Show file tree
Hide file tree
Showing 17 changed files with 447 additions and 1 deletion.
9 changes: 9 additions & 0 deletions .changeset/empty-icons-deliver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@utrecht/component-library-react": minor
"@utrecht/component-library-pdf": minor
"@utrecht/table-of-contents-css": minor
"@utrecht/components": minor
"@utrecht/component-library-css": minor
---

Add Table of Contents component for the PDF component library.
1 change: 1 addition & 0 deletions components/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
@import "./spotlight-section/src/index";
@import "./surface/src/index";
@import "./table/src/index";
@import "./table-of-contents/src/index";
@import "./textarea/src/index";
@import "./textbox/src/index";
@import "./toptask-link/src/index";
Expand Down
5 changes: 5 additions & 0 deletions components/table-of-contents/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<!-- @license CC0-1.0 -->

# Table of Contents

Lijst met de koppenstructuur van een document.
31 changes: 31 additions & 0 deletions components/table-of-contents/docs/technology-pdf.nl.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!-- @license CC0-1.0 -->

# PDF

Table of Contents moet opgebouwd worden met de volgende tags:

- `<TOC>` voor de lijst met Table of Contents.
- `<TOCI>` voor de items in de lijst met Table of Contents.
- `<Reference>` als wrapper om de link.
- `<Link>` voor de link.
- `<Lbl>` voor het hoofdstuknummer.
- `<Span>` voor koptekst.

Als de Table of Contents een heading of extra content heeft, dan moet die buiten de `<TOC>` tag staan. Je kunt de hele table of contents in een `<Sect>` tag plaatsen.

```text
<TOC> {
<TOCI> {
<Reference> {
<Link> {
<Lbl> {
"1.0.0"
}
<Span> {
"The quick brown fox jumps over the lazy dog"
}
}
}
}
}
```
32 changes: 32 additions & 0 deletions components/table-of-contents/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"version": "0.0.0",
"author": "Community for NL Design System",
"description": "Table of Contents component for the Municipality of Utrecht based on the NL Design System architecture",
"license": "EUPL-1.2",
"name": "@utrecht/table-of-contents-css",
"files": [
"dist/",
"docs/",
"src/",
"*.md"
],
"main": "dist/index.css",
"scripts": {
"build": "rollup -c ../rollup.config.mjs",
"clean": "rimraf dist"
},
"devDependencies": {
"rollup": "4.18.0"
},
"keywords": [
"nl-design-system"
],
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git+ssh",
"url": "git@github.com:nl-design-system/utrecht.git",
"directory": "components/table-of-contents"
}
}
57 changes: 57 additions & 0 deletions components/table-of-contents/src/_mixin.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* @license EUPL-1.2
* Copyright (c) 2021 Robbert Broersma
*/

$utrecht-support-prince-xml: false !default;

/* stylelint-disable order/properties-alphabetical-order */
@mixin utrecht-table-of-contents {
page-break-inside: avoid;
}

@mixin utrecht-table-of-contents__list {
list-style-type: none;
padding-inline-start: 0;
page-break-inside: avoid;

@if $utrecht-support-prince-xml {
-prince-pdf-tag-type: TOC;

/* reset Prince XML default styling of <ul> */
/* stylelint-disable-next-line property-disallowed-list */
margin-left: 0;
/* stylelint-disable-next-line property-disallowed-list */
margin-top: 0;
/* stylelint-disable-next-line property-disallowed-list */
margin-right: 0;
}
}

@mixin utrecht-table-of-contents__list-item {
margin-block-end: var(--utrecht-unordered-list-item-margin-block-end);
margin-block-start: var(--utrecht-unordered-list-item-margin-block-start);

@if $utrecht-support-prince-xml {
-prince-pdf-tag-type: TOCI;
}
}

@mixin utrecht-table-of-contents__list-item-body {
@if $utrecht-support-prince-xml {
-prince-pdf-tag-type: P;
}
}

@mixin utrecht-table-of-contents__list-item-label {
font-variant-numeric: lining-nums tabular-nums;
@if $utrecht-support-prince-xml {
-prince-pdf-tag-type: Lbl;
}
}

@mixin utrecht-table-of-contents__list-item-title {
@if $utrecht-support-prince-xml {
-prince-pdf-tag-type: Span;
}
}
34 changes: 34 additions & 0 deletions components/table-of-contents/src/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* @license EUPL-1.2
* Copyright (c) 2021 Robbert Broersma
*/

@import "./mixin";

.utrecht-table-of-contents {
@include utrecht-table-of-contents;
}

.utrecht-table-of-contents__list {
@include utrecht-table-of-contents__list;
}

.utrecht-table-of-contents__list-item {
@include utrecht-table-of-contents__list-item;
}

.utrecht-table-of-contents__list-item::before {
content: "";
}

.utrecht-table-of-contents__list-item-body {
@include utrecht-table-of-contents__list-item-body;
}

.utrecht-table-of-contents__list-item-label {
@include utrecht-table-of-contents__list-item-label;
}

.utrecht-table-of-contents__list-item-title {
@include utrecht-table-of-contents__list-item-title;
}
5 changes: 5 additions & 0 deletions components/table-of-contents/src/tokens.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"utrecht": {
"table-of-contents": {}
}
}
65 changes: 65 additions & 0 deletions packages/component-library-pdf/src/TableOfContents.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/* eslint-env jest */

import { beforeAll, describe, expect, it } from '@jest/globals';
import {
Heading1,
Heading2,
TableOfContents,
TableOfContentsLink,
TableOfContentsList,
TableOfContentsListItem,
} from '@utrecht/component-library-react/src/index';
import React from 'react';
import { renderPdf } from './lib';

describe('Table of Contents', () => {
let sha256: string;

beforeAll(async () => {
({ sha256 } = await renderPdf({
id: 'pdf-table-of-contents',
render: () => (
<>
<Heading1>Document Title</Heading1>
<TableOfContents>
<Heading2>Table of Contents</Heading2>
<TableOfContentsList>
<TableOfContentsListItem>
<TableOfContentsLink href="#chapter-1" label="1. ">
The quick brown fox jumps over the lazy dog
</TableOfContentsLink>
</TableOfContentsListItem>
</TableOfContentsList>
</TableOfContents>
<Heading2 id="chapter-1">The quick brown fox jumps over the lazy dog</Heading2>
</>
),
}));
});

it('renders a <TOC> tag', async () => {
expect(sha256).toBe('bd73ea7ffb47470d26b64dae2336118acc8b7448190b63c399de448bb09a14c2');
});

describe('list item', () => {
it('renders a <TOCI> tag', async () => {
expect(sha256).toBe('bd73ea7ffb47470d26b64dae2336118acc8b7448190b63c399de448bb09a14c2');
});

it('renders a <Reference> tag', async () => {
expect(sha256).toBe('bd73ea7ffb47470d26b64dae2336118acc8b7448190b63c399de448bb09a14c2');
});

it('renders a <Link> tag', async () => {
expect(sha256).toBe('bd73ea7ffb47470d26b64dae2336118acc8b7448190b63c399de448bb09a14c2');
});

it('renders a <Lbl> tag with chapter number', async () => {
expect(sha256).toBe('bd73ea7ffb47470d26b64dae2336118acc8b7448190b63c399de448bb09a14c2');
});

it('renders a <Span> tag with the text content', async () => {
expect(sha256).toBe('bd73ea7ffb47470d26b64dae2336118acc8b7448190b63c399de448bb09a14c2');
});
});
});
1 change: 1 addition & 0 deletions packages/component-library-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@
"@utrecht/superscript-css": "workspace:*",
"@utrecht/surface-css": "workspace:*",
"@utrecht/table-css": "workspace:*",
"@utrecht/table-of-contents-css": "workspace:*",
"@utrecht/textarea-css": "workspace:*",
"@utrecht/textbox-css": "workspace:*",
"@utrecht/top-task-link-css": "workspace:*",
Expand Down
57 changes: 57 additions & 0 deletions packages/component-library-react/src/TableOfContents.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* @license EUPL-1.2
* Copyright (c) 2022 Robbert Broersma
*/

import { clsx } from 'clsx';
import { HTMLAttributes, LiHTMLAttributes, type PropsWithChildren } from 'react';
import { Link, LinkProps } from './Link';

export type TableOfContentsProps = HTMLAttributes<HTMLElement>;

export const TableOfContents = ({ children, className, ...restProps }: PropsWithChildren<TableOfContentsProps>) => (
<section className={clsx('utrecht-table-of-contents', className)} {...restProps}>
{children}
</section>
);

export type TableOfContentsListProps = HTMLAttributes<HTMLElement>;

export const TableOfContentsList = ({
children,
className,
...restProps
}: PropsWithChildren<TableOfContentsListProps>) => (
<ul className={clsx('utrecht-table-of-contents__list', className)} {...restProps}>
{children}
</ul>
);

export type TableOfContentsListItemProps = LiHTMLAttributes<HTMLLIElement>;

export const TableOfContentsListItem = ({
children,
className,
...restProps
}: PropsWithChildren<TableOfContentsListItemProps>) => (
<li className={clsx('utrecht-table-of-contents__list-item', className)} {...restProps}>
<span className="utrecht-table-of-contents__list-item-body">{children}</span>
</li>
);

export interface TableOfContentsLinkProps extends LinkProps {
href: string;
label?: string;
}

export const TableOfContentsLink = ({
children,
className,
label,
...restProps
}: PropsWithChildren<TableOfContentsLinkProps>) => (
<Link className={clsx('utrecht-table-of-contents__link', className)} {...restProps}>
{label && <span className="utrecht-table-of-contents__list-item-label">{label}</span>}
<span className="utrecht-table-of-contents__list-item-title">{children}</span>
</Link>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* @license EUPL-1.2
* Copyright (c) 2021 Robbert Broersma
*/

import '@utrecht/table-of-contents-css/src/index.scss';

export * from '../TableOfContents';
7 changes: 7 additions & 0 deletions packages/component-library-react/src/css-module/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,13 @@ export { TableFooter } from './TableFooter';
export type { TableHeaderProps } from '../TableHeader';
export { TableHeader } from './TableHeader';
export type { TableHeaderCellProps } from '../TableHeaderCell';
export type {
TableOfContentsProps,
TableOfContentsListProps,
TableOfContentsListItemProps,
TableOfContentsLinkProps,
} from '../TableOfContents';
export { TableOfContents, TableOfContentsList, TableOfContentsListItem, TableOfContentsLink } from './TableOfContents';
export { TableHeaderCell } from './TableHeaderCell';
export type { TableRowProps } from '../TableRow';
export { TableRow } from './TableRow';
Expand Down
7 changes: 7 additions & 0 deletions packages/component-library-react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,13 @@ export type { TableHeaderProps } from './TableHeader';
export { TableHeader } from './TableHeader';
export type { TableHeaderCellProps } from './TableHeaderCell';
export { TableHeaderCell } from './TableHeaderCell';
export type {
TableOfContentsProps,
TableOfContentsListProps,
TableOfContentsListItemProps,
TableOfContentsLinkProps,
} from './TableOfContents';
export { TableOfContents, TableOfContentsList, TableOfContentsListItem, TableOfContentsLink } from './TableOfContents';
export type { TableRowProps } from './TableRow';
export { TableRow } from './TableRow';
export type { TextareaProps } from './Textarea';
Expand Down
22 changes: 21 additions & 1 deletion packages/storybook-pdf/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,29 @@
"@storybook/types": "7.6.4",
"@tabler/icons-react": "2.44.0",
"@types/prettier": "2.7.3",
"@types/react": "18.3.3",
"@types/react-dom": "18.3.0",
"@types/react": "18.3.3",
"@utrecht/article-css": "workspace:*",
"@utrecht/checkbox-css": "workspace:*",
"@utrecht/code-block-css": "workspace:*",
"@utrecht/code-css": "workspace:*",
"@utrecht/component-library-pdf": "workspace:*",
"@utrecht/data-list-css": "workspace:*",
"@utrecht/heading-1-css": "workspace:*",
"@utrecht/heading-2-css": "workspace:*",
"@utrecht/heading-3-css": "workspace:*",
"@utrecht/heading-4-css": "workspace:*",
"@utrecht/heading-5-css": "workspace:*",
"@utrecht/heading-6-css": "workspace:*",
"@utrecht/link-css": "workspace:*",
"@utrecht/ordered-list-css": "workspace:*",
"@utrecht/page-css": "workspace:*",
"@utrecht/radio-button-css": "workspace:*",
"@utrecht/table-css": "workspace:*",
"@utrecht/table-of-contents-css": "workspace:*",
"@utrecht/textarea-css": "workspace:*",
"@utrecht/textbox-css": "workspace:*",
"@utrecht/unordered-list-css": "workspace:*",
"@utrecht/storybook-helpers": "workspace:*",
"babel-loader": "9.1.3",
"clsx": "2.1.1",
Expand Down
Loading

0 comments on commit 1227678

Please sign in to comment.