Skip to content

Commit

Permalink
Basic styling and multilevel poc for discussion
Browse files Browse the repository at this point in the history
  • Loading branch information
dlnr committed May 24, 2024
1 parent 7b98773 commit 1ad758c
Show file tree
Hide file tree
Showing 12 changed files with 299 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/css/src/components/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

/* Append here */
@import "./table-of-contents/table-of-contents";
@import "./field/field";
@import "./select/select";
@import "./time-input/time-input";
Expand Down
3 changes: 3 additions & 0 deletions packages/css/src/components/table-of-contents/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<!-- @license CC0-1.0 -->

# Table of Contents
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
* @license EUPL-1.2+
* Copyright Gemeente Amsterdam
*/

@import "../../common/text-rendering";

@mixin reset {
box-sizing: border-box;
margin-block: 0;
padding-inline: 0;
}

.ams-table-of-contents {
display: flex;
flex-direction: column;
font-family: var(--ams-table-of-contents-font-family, inherit);
font-size: var(--ams-table-of-contents-font-size);
font-weight: var(--ams-table-of-contents-font-weight);
gap: var(--ams-table-of-contents-gap);
line-height: var(--ams-table-of-contents-line-height);
}

.ams-table-of-contents__list {
display: flex;
flex-direction: column;
gap: var(--ams-table-of-contents-list-gap);
list-style: none;

.ams-table-of-contents__list {
display: none;
padding-block-start: var(--ams-table-of-contents-list-gap);
padding-inline-start: var(--ams-table-of-contents-list-list-padding-inline-start);
}

@include text-rendering;
@include reset;
}

.ams-table-of-contents__title {
font-size: var(--ams-table-of-contents-title-font-size);
font-weight: var(--ams-table-of-contents-title-font-weight);
line-height: var(--ams-table-of-contents-title-line-height);
}

.ams-table-of-contents__item:has(.ams-table-of-contents) {
background-image: var(--ams-table-of-contents-list-item-background-image);
background-position-x: right;
background-position-y: 0.3em;
background-repeat: no-repeat;
background-size: var(--ams-table-of-contents-font-size);

&:has(.ams-table-of-contents__link--active),
.ams-table-of-contents__item:has(.ams-table-of-contents) {
background-image: var(--ams-table-of-contents-list-item-active-background-image);

.ams-table-of-contents__list {
display: flex;
}
}
}

.ams-table-of-contents__link {
color: var(--ams-table-of-contents-link-color);
outline-offset: var(--ams-table-of-contents-link-outline-offset);
text-decoration-line: var(--ams-table-of-contents-link-text-decoration-line);
text-decoration-thickness: var(--ams-table-of-contents-link-text-decoration-thickness);
text-underline-offset: var(--ams-table-of-contents-link-text-underline-offset);

&--active {
font-weight: 700;
}

&:hover {
color: var(--ams-table-of-contents-link-hover-color);
text-decoration-line: var(--ams-table-of-contents-link-hover-text-decoration-line);
}
}
5 changes: 5 additions & 0 deletions packages/react/src/TableOfContents/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<!-- @license CC0-1.0 -->

# React Table of Contents component

[Table of Contents documentation](../../../css/src/components/table-of-contents/README.md)
37 changes: 37 additions & 0 deletions packages/react/src/TableOfContents/TableOfContents.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { render } from '@testing-library/react'
import { createRef } from 'react'
import { TableOfContents } from './TableOfContents'
import '@testing-library/jest-dom'

describe('Table of contents', () => {
it('renders', () => {
const { container } = render(<TableOfContents />)
const component = container.querySelector(':only-child')

expect(component).toBeInTheDocument()
expect(component).toBeVisible()
})

it('renders a design system BEM class name', () => {
const { container } = render(<TableOfContents />)
const component = container.querySelector(':only-child')

expect(component).toHaveClass('ams-table-of-contents')
})

it('renders an additional class name', () => {
const { container } = render(<TableOfContents className="extra" />)
const component = container.querySelector(':only-child')

expect(component).toHaveClass('ams-table-of-contents extra')
})

it('supports ForwardRef in React', () => {
const ref = createRef<HTMLDivElement>()

const { container } = render(<TableOfContents ref={ref} />)
const component = container.querySelector(':only-child')

expect(ref.current).toBe(component)
})
})
26 changes: 26 additions & 0 deletions packages/react/src/TableOfContents/TableOfContents.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* @license EUPL-1.2+
* Copyright Gemeente Amsterdam
*/

import clsx from 'clsx'
import { forwardRef } from 'react'
import type { ForwardedRef, HTMLAttributes, PropsWithChildren } from 'react'
import { TableOfContentsLink } from './TableOfContentsLink'

export type TableOfContentsProps = {
title?: string
} & PropsWithChildren<HTMLAttributes<HTMLDivElement>>

const TableOfContentsRoot = forwardRef(
({ children, className, title, ...restProps }: TableOfContentsProps, ref: ForwardedRef<HTMLDivElement>) => (
<nav {...restProps} ref={ref} className={clsx('ams-table-of-contents', className)}>
{title && <div className="ams-table-of-contents__title">{title}</div>}
<ol className="ams-table-of-contents__list">{children}</ol>
</nav>
),
)

TableOfContentsRoot.displayName = 'TableOfContents'

export const TableOfContents = Object.assign(TableOfContentsRoot, { Link: TableOfContentsLink })
33 changes: 33 additions & 0 deletions packages/react/src/TableOfContents/TableOfContentsLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* @license EUPL-1.2+
* Copyright Gemeente Amsterdam
*/

import { clsx } from 'clsx'
import { forwardRef } from 'react'
import type { AnchorHTMLAttributes, ForwardedRef } from 'react'

export type TableOfContentsLinkProps = {
label: string
active?: boolean
} & AnchorHTMLAttributes<HTMLAnchorElement>

export const TableOfContentsLink = forwardRef(
(
{ children, className, label, active, ...restProps }: TableOfContentsLinkProps,
ref: ForwardedRef<HTMLAnchorElement>,
) => (
<li className="ams-table-of-contents__item">
<a
{...restProps}
className={clsx('ams-table-of-contents__link', active && 'ams-table-of-contents__link--active', className)}
ref={ref}
>
{label}
</a>
{children}
</li>
),
)

TableOfContentsLink.displayName = 'TableOfContents.Link'
2 changes: 2 additions & 0 deletions packages/react/src/TableOfContents/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { TableOfContents } from './TableOfContents'
export type { TableOfContentsProps } from './TableOfContents'
1 change: 1 addition & 0 deletions packages/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

/* Append here */
export * from './TableOfContents'
export * from './Field'
export * from './Select'
export * from './TimeInput'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"ams": {
"table-of-contents": {
"color": { "value": "{ams.color.primary-black}" },
"font-family": { "value": "{ams.text.font-family}" },
"font-size": { "value": "{ams.text.level.5.font-size}" },
"font-weight": { "value": "{ams.text.font-weight.normal}" },
"gap": { "value": "{ams.space.inside.lg}" },
"line-height": { "value": "{ams.text.level.5.line-height}" },
"link": {
"color": { "value": "{ams.color.primary-blue}" },
"inverse-color": { "value": "{ams.color.primary-white}" },
"hover": {
"color": { "value": "{ams.color.dark-blue}" }
}
},
"list": {
"gap": { "value": "{ams.space.inside.lg}" },
"item": {
"background-image": {
"value": "url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><path fill-rule='evenodd' d='m16 25.757-16-16 2.91-2.9L16 19.937l13.09-13.08 2.91 2.9z'/></svg>\")"
},
"active": {
"background-image": {
"value": "url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><path fill-rule='evenodd' d='M29.09 25.757 16 12.677 2.91 25.757 0 22.857l16-16 16 16z'/></svg>\")"
}
}
},
"list": {
"padding-inline-start": { "value": "{ams.space.inside.lg}" }
}
},
"title": {
"font-weight": { "value": "{ams.text.font-weight.bold}" },
"font-size": { "value": "{ams.text.level.4.font-size}" },
"line-height": { "value": "{ams.text.level.4.line-height}" }
}
}
}
}
11 changes: 11 additions & 0 deletions storybook/src/components/TableOfContents/TableOfContents.docs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Controls, Markdown, Meta, Primary } from "@storybook/blocks";
import * as TableOfContentsStories from "./TableOfContents.stories.tsx";
import README from "../../../../packages/css/src/components/table-of-contents/README.md?raw";

<Meta of={TableOfContentsStories} />

<Markdown>{README}</Markdown>

<Primary />

<Controls />
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* @license EUPL-1.2+
* Copyright Gemeente Amsterdam
*/

import { TableOfContents } from '@amsterdam/design-system-react/src'
import { Meta, StoryObj } from '@storybook/react'

const meta = {
title: 'Components/Navigation/Table of Contents',
component: TableOfContents,
args: {
title: 'Op deze pagina',
children: [
<>
<TableOfContents.Link href="#section-1" label="Zo werkt het" />
<TableOfContents.Link href="#section-2" label="Voorwaarden" />
<TableOfContents.Link href="#section-4" label="Aanvragen" />
<TableOfContents.Link href="#section-4" label="Zie ook" />
</>,
],
},
} satisfies Meta<typeof TableOfContents>

export default meta

type Story = StoryObj<typeof meta>

export const Default: Story = {}

export const MultiLevel: Story = {
args: {
title: 'Inhoudsopgave',
children: [
<>
<TableOfContents.Link href="#section-1" label="Waarom is het belangrijk om helder te schrijven?" />
<TableOfContents.Link href="#section-2" label="Schrijf in stappen">
<TableOfContents>
<TableOfContents.Link href="#section-4.1" label="Stap 2" />
<TableOfContents.Link href="#section-4.2" label="Stap 3" />
<TableOfContents.Link href="#section-4.3" label="Stap 4" />
</TableOfContents>
</TableOfContents.Link>
<TableOfContents.Link href="#section-3" label="Structuur van een heldere tekst" active>
<TableOfContents>
<TableOfContents.Link href="#section-3.1" label="Opmaakeisen" />
<TableOfContents.Link href="#section-3.2" label="Tekstlengte">
<TableOfContents>
<TableOfContents.Link href="#section-3.2.1" label="Boodschap en achtergronden" />
</TableOfContents>
</TableOfContents.Link>
<TableOfContents.Link href="#section-3.2" label="Alinea's en tussenkopjes" />
<TableOfContents.Link href="#section-3.2" label="Opsommingen" />
</TableOfContents>
</TableOfContents.Link>
<TableOfContents.Link href="#section-4" label="Taalgebruik in heldere taal" />
<TableOfContents.Link href="#section-5" label="Tekstonderdelen in heldere taal" />
<TableOfContents.Link href="#section-6" label="Moeilijke woordenboek (inclusief niet te gebruiken)" />
</>,
],
},
}

0 comments on commit 1ad758c

Please sign in to comment.