Skip to content

Commit

Permalink
React components/button (#304)
Browse files Browse the repository at this point in the history
# Contents

<!-- Description of what this PR contains. New components/features,
bugfixes, etc. -->

## Checklist

<!-- Surround an item with double tildes `~~` to indicate that it does
not apply to this PR -->

- [x] New features/components and bugfixes are covered by tests
- [x] Changesets are created
- [x] Definition of Done is checked

---------

Co-authored-by: Jaap-Hein Wester <j.h.wester@setonix.nl>
  • Loading branch information
MMeijerink and Jaap-Hein Wester authored Oct 23, 2024
1 parent 60ac1d8 commit e7a4ac7
Show file tree
Hide file tree
Showing 15 changed files with 543 additions and 2,022 deletions.
2 changes: 1 addition & 1 deletion .changeset/fair-tigers-eat.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
"@lux-design-system/components-react": minor
"@lux-design-system/components-react": major
---

In deze commit:
Expand Down
7 changes: 7 additions & 0 deletions .changeset/tiny-hairs-enjoy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@lux-design-system/components-react": major
---

In deze commit:

- Nieuw component: LuxButton
14 changes: 3 additions & 11 deletions packages/components-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
],
"dependencies": {
"@utrecht/component-library-css": "6.0.0",
"@utrecht/component-library-react": "7.0.0",
"@utrecht/component-library-react": "7.1.0",
"clsx": "2.1.1",
"date-fns": "3.6.0",
"lodash.chunk": "4.2.0"
Expand All @@ -55,9 +55,6 @@
"@babel/runtime": "7.25.0",
"@jest/globals": "29.7.0",
"@lux-design-system/components-css": "workspace:*",
"@rollup/plugin-babel": "6.0.4",
"@rollup/plugin-commonjs": "26.0.1",
"@rollup/plugin-node-resolve": "15.2.3",
"@testing-library/dom": "10.4.0",
"@testing-library/jest-dom": "6.5.0",
"@testing-library/react": "16.0.0",
Expand All @@ -76,18 +73,13 @@
"react-dom": "18.3.1",
"rimraf": "6.0.1",
"rollup": "4.20.0",
"rollup-plugin-filesize": "10.0.0",
"rollup-plugin-node-externals": "7.1.2",
"rollup-plugin-node-polyfills": "0.2.1",
"rollup-plugin-peer-deps-external": "2.2.4",
"rollup-plugin-postcss": "4.0.2",
"rollup-plugin-typescript2": "0.36.0",
"sass": "1.77.8",
"tslib": "2.6.3",
"typescript": "5.5.4",
"vite": "5.3.5",
"vite-plugin-dts": "4.2.3",
"vite-plugin-runtime-config": "1.0.2"
"vite-plugin-runtime-config": "1.0.2",
"vite-plugin-css-injected-by-js": "3.5.2"
},
"peerDependencies": {
"react": "18",
Expand Down
66 changes: 0 additions & 66 deletions packages/components-react/rollup.config.mjs

This file was deleted.

18 changes: 18 additions & 0 deletions packages/components-react/src/button/Button.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.lux-button {
display: inline-flex;
}

.lux-button--small {
padding-block-start: var(--lux-button-small-padding-block-start);
padding-block-end: var(--lux-button-small-padding-block-end);
min-inline-size: var(--lux-button-small-min-inline-size);
min-block-size: var(--lux-button-small-min-block-size);
}

.lux-button-icon--start {
order: 0;
}

.lux-button-icon--end {
order: 1;
}
45 changes: 45 additions & 0 deletions packages/components-react/src/button/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {
Button as UtrechtButton,
type ButtonProps as UtrechtButtonProps,
} from '@utrecht/component-library-react/dist/css-module';
import './Button.css';
import React, { ReactElement } from 'react';

type IconPosition = 'start' | 'end';
type Size = 'small';

export type LuxButtonProps = UtrechtButtonProps & {
size?: Size;
iconPosition?: IconPosition;
};

const SIZE_CLASSNAME: { [key: string]: string } = {
small: 'lux-button--small',
};

const ICON_POSITIONS: { [key: string]: string } = {
start: 'lux-button-icon--start',
end: 'lux-button-icon--end',
};

export const LuxButton = (props: LuxButtonProps) => {
const { size, icon: iconNode, iconPosition, ...otherProps } = props;

const className = `lux-button ${size !== undefined ? SIZE_CLASSNAME[size] : ''}`;

const positionedIcon = React.Children.map(iconNode, (iconElement) => {
if (!iconElement) {
return null;
}

if (!React.isValidElement<HTMLElement>(iconElement)) {
return iconElement;
}

return React.cloneElement(iconElement as ReactElement, {
className: `${iconElement?.props?.className || ''}${iconPosition !== undefined ? ICON_POSITIONS[iconPosition] : ''}`,
});
});

return <UtrechtButton {...otherProps} className={className} {...(positionedIcon ? { icon: positionedIcon } : {})} />;
};
51 changes: 51 additions & 0 deletions packages/components-react/src/button/test/Button.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { describe, expect, it } from '@jest/globals';
import { render, screen } from '@testing-library/react';
import { LuxButton } from '../Button';

//TODO replace icon in #308
const ExampleIcon = (
<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg">
<circle r="6" cx="7" cy="7" fill="white" stroke="green" />
</svg>
);

describe('Button', () => {
it('renders a button', () => {
render(<LuxButton label="LUX Button" />);

const button = screen.getByRole('button', {
name: 'LUX Button',
});
expect(button).toBeInTheDocument();
});

it('renders a small button', () => {
render(<LuxButton label="LUX Button" size="small" />);

const button = screen.getByRole('button', {
name: 'LUX Button',
});

expect(button).toHaveClass('lux-button--small');
});

it('renders a button with a start icon', () => {
render(<LuxButton label="LUX Button" icon={ExampleIcon} iconPosition="start" />);

const button = screen.getByRole('button', {
name: 'LUX Button',
});

expect(button.children[0].getAttribute('class')).toEqual('lux-button-icon--start');
});

it('renders a button with an end icon', () => {
render(<LuxButton label="LUX Button" icon={ExampleIcon} iconPosition="end" />);

const button = screen.getByRole('button', {
name: 'LUX Button',
});

expect(button.children[0].getAttribute('class')).toEqual('lux-button-icon--end');
});
});
2 changes: 1 addition & 1 deletion packages/components-react/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import '@utrecht/component-library-css/dist/index.css';
export { LuxButton, type LuxButtonProps } from './button/Button';
export { LuxDocument, type LuxDocumentProps } from './document/Document';
export {
LuxHeading,
Expand Down
4 changes: 3 additions & 1 deletion packages/components-react/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import react from '@vitejs/plugin-react';
import { resolve } from 'path';
import { defineConfig } from 'vite';
import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js';
import dts from 'vite-plugin-dts';

export default defineConfig({
Expand All @@ -23,9 +24,10 @@ export default defineConfig({
globals: {
react: 'React',
},
manualChunks: undefined,
},
},
minify: false,
},
plugins: [dts(), react()],
plugins: [dts(), react(), cssInjectedByJsPlugin({ topExecutionPriority: false })],
});
1 change: 1 addition & 0 deletions packages/storybook/config/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const config: StorybookConfig = {
'@storybook/addon-actions',
'@storybook/addon-interactions',
'@storybook/addon-links',
'storybook-addon-pseudo-states',
],
framework: {
name: '@storybook/react-vite',
Expand Down
1 change: 1 addition & 0 deletions packages/storybook/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"rimraf": "6.0.1",
"shadow-dom-testing-library": "1.11.2",
"storybook": "8.2.7",
"storybook-addon-pseudo-states": "4.0.2",
"typescript": "5.5.4",
"vite": "5.3.5"
},
Expand Down
49 changes: 49 additions & 0 deletions packages/storybook/src/react-components/button/button.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Canvas, Controls, Markdown, Meta } from "@storybook/blocks";
import markdown from "@utrecht/button-css/README.md?raw";
import * as ButtonStories from "./button.stories.tsx";
import { CitationDocumentation } from "../../utils/CitationDocumentation.tsx";

<Meta of={ButtonStories} />

# Button

<CitationDocumentation
component="Utrecht Button"
url="https://nl-design-system.github.io/utrecht/storybook-css/index.html?path=/docs/css-heading--docs"
/>

<Markdown>{markdown}</Markdown>

## Opmerkingen

- De `iconPosition` property is toegevoegd om het icoon te positioneren binnen de button.
- Met de `size` property kan de grootte van de button ingesteld worden.

## Playground

<Canvas of={ButtonStories.Playground} />
<Controls of={ButtonStories.Playground} />

## Small Button

<Canvas of={ButtonStories.SmallButton} />

## Variants

<Canvas of={ButtonStories.Primary} />
<Canvas of={ButtonStories.Secondary} />
<Canvas of={ButtonStories.Tertiary} />

## Button states

<Canvas of={ButtonStories.Active} />
<Canvas of={ButtonStories.Focus} />
<Canvas of={ButtonStories.Hover} />
<Canvas of={ButtonStories.Disabled} />
<Canvas of={ButtonStories.Busy} />
<Canvas of={ButtonStories.Toggle} />

## Button With Icon

<Canvas of={ButtonStories.ButtonWithIconAtPositionStart} />
<Canvas of={ButtonStories.ButtonWithIconAtPositionEnd} />
Loading

0 comments on commit e7a4ac7

Please sign in to comment.