Skip to content

Commit

Permalink
Feature/button (#481)
Browse files Browse the repository at this point in the history
closes #455
closes #470

---------

Co-authored-by: Ruben Smit <[email protected]>
Co-authored-by: Mees <[email protected]>
  • Loading branch information
3 people authored and Mees Work committed Aug 22, 2024
1 parent b8a775d commit d847792
Show file tree
Hide file tree
Showing 17 changed files with 249 additions and 149 deletions.
43 changes: 16 additions & 27 deletions apps/rhc-templates/src/app/collage/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

import {
AccordionProvider,
Blockquote,
BreadcrumbNav,
BreadcrumbNavLink,
Blockquote,
Button,
Heading,
IconButton,
Link,
Paragraph,
} from '@rijkshuisstijl-community/components-react';
Expand All @@ -21,7 +23,6 @@ import {
import {
Alert,
BadgeCounter,
Button,
Checkbox,
DataList,
DataListActions,
Expand Down Expand Up @@ -67,14 +68,12 @@ export default function Collage() {
<Avatar label="BK"></Avatar>
</div>
<Heading level={1}>Componenten collage NL Design System</Heading>
<div className="unstarted">
<Image
alt="Multicolored tulip field"
width="640"
height="763"
src="https://raw.githubusercontent.com/nl-design-system/rijkshuisstijl-community/0bfd32af3f34ff7ce62f4769fbec8895720dde75/proprietary/assets/src/placeholder.jpg"
></Image>
</div>
<Image
alt="Multicolored tulip field"
width="640"
height="763"
src="https://raw.githubusercontent.com/nl-design-system/rijkshuisstijl-community/0bfd32af3f34ff7ce62f4769fbec8895720dde75/proprietary/assets/src/placeholder.jpg"
></Image>
<Paragraph lead>
In het NL Design System verzamelen we principes, handvatten, elementen, patronen en richtlijnen.
</Paragraph>
Expand Down Expand Up @@ -122,23 +121,13 @@ export default function Collage() {
{`Hello, I'm a link `}
<IconArrowRight />
</Link>
<div className="unstarted">
<Button appearance="primary-action-button">Primary button</Button>
</div>
<div className="unstarted">
<Button appearance="secondary-action-button">Secondary button</Button>
</div>
<div className="unstarted">
<Button>Default button</Button>
</div>
<div className="unstarted">
<Button appearance="subtle-button">Subtle button</Button>
</div>
<div className="unstarted">
<Button appearance="subtle-button">
<IconCalendarEvent />
</Button>
</div>
<Button appearance="primary-action-button">Primary button</Button>
<Button appearance="secondary-action-button">Secondary button</Button>
<Button>Default button</Button>
<Button appearance="subtle-button">Subtle button</Button>
<IconButton label="calendar">
<IconCalendarEvent />
</IconButton>
<div className="unstarted">
<FormField label="Name" description="Description">
<Textbox></Textbox>
Expand Down
11 changes: 4 additions & 7 deletions apps/rhc-templates/src/app/form/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
'use client';

import { AccordionProvider, Heading, Link, Logo, Paragraph } from '@rijkshuisstijl-community/components-react';
import { AccordionProvider, Button, Heading, Link, Logo, Paragraph } from '@rijkshuisstijl-community/components-react';
import { FormLabel } from '@utrecht/component-library-react';
import {
BreadcrumbNav,
BreadcrumbNavLink,
Button,
Checkbox,
Fieldset,
FieldsetLegend,
Expand Down Expand Up @@ -169,11 +168,9 @@ export default function Form() {
</FormField>
</Fieldset>
</div>
<div className="unstarted">
<Button type="submit" appearance="primary-action-button">
Ga verder
</Button>
</div>
<Button type="submit" appearance="primary-action-button">
Ga verder
</Button>
</form>
</PageContent>
<div className="unstarted">
Expand Down
21 changes: 13 additions & 8 deletions apps/rhc-templates/src/app/page/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use client';

import {
Button,
ButtonLink,
Icon,
LinkList,
Expand All @@ -28,7 +27,15 @@ import {
Figure,
FigureCaption,
} from '@utrecht/component-library-react/dist/css-module';
import { ActionGroup, Blockquote, Heading, Link, Logo, Paragraph } from '@rijkshuisstijl-community/components-react';
import {
ActionGroup,
Blockquote,
Button,
Heading,
Link,
Logo,
Paragraph,
} from '@rijkshuisstijl-community/components-react';
import { HeadingGroup } from '@utrecht/component-library-react';

export default function Page() {
Expand Down Expand Up @@ -71,11 +78,9 @@ export default function Page() {
></Image>
<FigureCaption>Bijschrift (figcaption) van een afbeelding)</FigureCaption>
</Figure>
<div className="unstarted">
<Button type="submit" appearance="primary-action-button">
Primary action button
</Button>
</div>
<Button type="submit" appearance="primary-action-button">
Primary action button
</Button>
<Heading level={2}>Dit is een H2</Heading>
<Paragraph>Dit is een paragraaf.</Paragraph>
<Paragraph>Opsomming ordered list</Paragraph>
Expand Down Expand Up @@ -115,7 +120,7 @@ export default function Page() {
</div>
<Heading level={3}>Dit is een H3</Heading>
<Paragraph>Dit is een paragraaf.</Paragraph>
<Link external={true} href="example.com">
<Link external={true} externalLabel="example external label" href="example.com">
Dit is een externe link
</Link>
<div className="unstarted">
Expand Down
23 changes: 23 additions & 0 deletions packages/components-css/button/_mixin.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* @license EUPL-1.2
* Copyright (c) 2020-2022 Gemeente Utrecht
* Copyright (c) 2020-2022 Frameless B.V.
*/

@mixin invisible-but-accessible {
block-size: 1px !important;

/* Source: https://kittygiraudel.com/snippets/sr-only-class/ */
border: 0 !important;
clip: rect(1px, 1px, 1px, 1px) !important;
-webkit-clip-path: inset(50%) !important;
clip-path: inset(50%) !important;
inline-size: 1px !important;
/* stylelint-disable-next-line property-disallowed-list */
margin: -1px !important;
overflow: hidden !important;
/* stylelint-disable-next-line property-disallowed-list */
padding: 0 !important;
position: absolute !important;
white-space: nowrap !important;
}
16 changes: 16 additions & 0 deletions packages/components-css/button/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* @license EUPL-1.2
* Copyright (c) 2021 Community for NL Design System
*/
@import "./mixin";

.rhc-button--icon-only {
padding-block-end: var(--rhc-icon-only-button-padding-block-end);
padding-block-start: var(--rhc-icon-only-button-padding-block-start);
padding-inline-end: var(--rhc-icon-only-button-padding-inline-end);
padding-inline-start: var(--rhc-icon-only-button-padding-inline-start);
}

.rhc-button--icon-only .rhc-button__sr-only {
@include invisible-but-accessible;
}
1 change: 1 addition & 0 deletions packages/components-css/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

@import "accordion/index";
@import "button/index";
@import "blockquote/index";
@import "alert/index";
@import "link/index";
Expand Down
7 changes: 6 additions & 1 deletion packages/components-css/link/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@
* @license EUPL-1.2
* Copyright (c) 2021 Community for NL Design System
*/
@import "../button/mixin";

.utrecht-link:any-link {
.rhc-link:any-link {
align-items: center;
column-gap: var(--utrecht-link-column-gap, inherit);
display: inline-flex;
}

.rhc-link .rhc-link__sr-only {
@include invisible-but-accessible;
}
81 changes: 81 additions & 0 deletions packages/components-react/src/Button.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { render, screen } from '@testing-library/react';
import { IconButton } from './Button';
import '@testing-library/jest-dom';

describe('IconButton', () => {
it('renders an HTML button element', () => {
const { container } = render(<IconButton label="example-icon-label" />);

const button = container.querySelector('button');

expect(button).toBeInTheDocument();
});

it('renders an sr-only label for accessibility', () => {
render(<IconButton label="example-icon-label" />);

const span = screen.getByText('example-icon-label');

expect(span).toHaveClass('rhc-button__sr-only');
});

it('renders a design system BEM class name', () => {
const { container } = render(<IconButton label="example-icon-label" />);

const button = container.querySelector('button');

expect(button).toHaveClass('rhc-button');

expect(button).toHaveClass('rhc-button--icon-only');
});

it('is not disabled by default', () => {
const { container } = render(<IconButton label="example-icon-label" />);

const button = container.querySelector('button');

expect(button).not.toBeDisabled();

expect(button).not.toHaveAttribute('aria-disabled');

expect(button).not.toHaveAttribute('disabled');
});

it('can have a disabled state', () => {
const { container } = render(<IconButton label="example-icon-label" disabled={true} />);

const button = container.querySelector('button');

expect(button).toBeDisabled();
});

it('can be hidden', () => {
const { container } = render(<IconButton label="example-icon-label" hidden />);

const button = container.querySelector('button');

expect(button).not.toBeVisible();
});

it('can have a additional class name', () => {
const { container } = render(<IconButton label="example-icon-label" className="large" />);

const button = container.querySelector('button');

expect(button).toHaveClass('large');

expect(button).toHaveClass('utrecht-button');
});

it('can trigger a click event', () => {
const handleClick = jest.fn();

const { container } = render(<IconButton label="example-icon-label" onClick={handleClick} />);

const button = container.querySelector<HTMLElement>('button');

button?.click();

expect(handleClick).toHaveBeenCalled();
});
});
31 changes: 31 additions & 0 deletions packages/components-react/src/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import '@rijkshuisstijl-community/components-css/index.scss';
import {
Button,
type ButtonProps,
Icon,
PrimaryActionButton,
SecondaryActionButton,
SubtleButton,
} from '@utrecht/component-library-react/dist/css-module';
import clsx from 'clsx';
import { ForwardedRef, forwardRef, PropsWithChildren } from 'react';

export { type ButtonProps, Button, PrimaryActionButton, SecondaryActionButton, SubtleButton };

export interface IconButtonProps extends ButtonProps {
label: string;
}

export const IconButton = forwardRef(
(
{ children, className, label, ...restProps }: PropsWithChildren<IconButtonProps>,
ref: ForwardedRef<HTMLButtonElement>,
) => (
<SubtleButton ref={ref} className={clsx('rhc-button', 'rhc-button--icon-only', className)} {...restProps}>
<span className="rhc-button__sr-only">{label}</span>
<Icon>{children}</Icon>
</SubtleButton>
),
);

IconButton.displayName = 'IconButton';
14 changes: 4 additions & 10 deletions packages/components-react/src/Link.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,18 +127,12 @@ describe('Link', () => {
expect(icon).toBeInTheDocument();
});

it('contains a visual icon that has an aria-label that comes from a property', () => {
const { container } = render(<Link external externalLabel="some-external-label" />);
it('contains a visual icon that has an sr-only label that comes from a property', () => {
render(<Link external externalLabel="some-external-label" />);

const link = container.querySelector(':only-child');

const icon = link?.querySelector('.utrecht-icon');

expect(icon).toBeInTheDocument();

expect(icon).toHaveAttribute('aria-label');
const label = screen.getByText('some-external-label');

expect(icon?.getAttribute('aria-label')).toContain('some-external-label');
expect(label).toHaveClass('rhc-link__sr-only');
});
});
});
Expand Down
20 changes: 14 additions & 6 deletions packages/components-react/src/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
Link as UtrechtLink,
type LinkProps as UtrechtLinkProps,
} from '@utrecht/component-library-react/dist/css-module';
import clsx from 'clsx';
import { ForwardedRef, forwardRef } from 'react';
import '@rijkshuisstijl-community/components-css/index.scss';

Expand All @@ -18,17 +19,24 @@ const IconExternalLink = () => (
);

interface RhcLinkProps extends UtrechtLinkProps {
external?: boolean;
externalLabel?: string;
}

export const Link = forwardRef(
({ children, externalLabel, ...restProps }: RhcLinkProps, ref: ForwardedRef<HTMLAnchorElement>) => (
<UtrechtLink {...restProps} ref={ref}>
(
{ children, className, external, externalLabel, ...restProps }: RhcLinkProps,
ref: ForwardedRef<HTMLAnchorElement>,
) => (
<UtrechtLink {...restProps} external={external} className={clsx('rhc-link', className)} ref={ref}>
{children}
{restProps.external && (
<Icon role="img" aria-label={externalLabel}>
<IconExternalLink />
</Icon>
{external && (
<>
<span className="rhc-link__sr-only">{externalLabel}</span>
<Icon role="img">
<IconExternalLink />
</Icon>
</>
)}
</UtrechtLink>
),
Expand Down
Loading

0 comments on commit d847792

Please sign in to comment.