diff --git a/src/pages/ComponentsPage/components/BadgeComponents.tsx b/src/pages/ComponentsPage/components/BadgeComponents.tsx
new file mode 100644
index 0000000..4511b02
--- /dev/null
+++ b/src/pages/ComponentsPage/components/BadgeComponents.tsx
@@ -0,0 +1,102 @@
+import { PropsWithClassName, PropsWithTestId } from '@leanstacks/react-common';
+import { createColumnHelper } from '@tanstack/react-table';
+
+import { ComponentProperty } from '../model/components';
+import Text from 'components/Text/Text';
+import Table from 'components/Table/Table';
+import CodeSnippet from 'components/Text/CodeSnippet';
+import Badge from 'components/Badge/Badge';
+
+/**
+ * Properties for the `BadgeComponents` React component.
+ * @see {@link PropsWithClassName}
+ * @see {@link PropsWithTestId}
+ */
+interface BadgeComponentsProps extends PropsWithClassName, PropsWithTestId {}
+
+/**
+ * The `BadgeComponents` React component renders a set of examples illustrating
+ * the use of the `Badge` component.
+ * @param {BadgeComponentsProps} props - Component properties.
+ * @returns {JSX.Element} JSX
+ */
+const BadgeComponents = ({
+ className,
+ testId = 'components-badge',
+}: BadgeComponentsProps): JSX.Element => {
+ const data: ComponentProperty[] = [
+ {
+ name: 'children',
+ description: 'The content to be displayed.',
+ },
+ {
+ name: 'className',
+ description: 'Optional. Additional CSS class names.',
+ },
+ {
+ name: 'testId',
+ description: 'Optional. Identifier for testing.',
+ },
+ ];
+ const columnHelper = createColumnHelper
();
+ const columns = [
+ columnHelper.accessor('name', {
+ cell: (info) => {info.getValue()} ,
+ header: () => 'Name',
+ }),
+ columnHelper.accessor('description', {
+ cell: (info) => info.renderValue(),
+ header: () => 'Description',
+ }),
+ ];
+
+ return (
+
+
+ Badge Component
+
+
+
+ The Badge component displays a stylized
+ counter. Useful for displaying the number of items of a specific type, for example, the
+ number of notifications.
+
+
+
+
+ Properties
+
+
data={data} columns={columns} />
+
+
+ Examples
+
+
+
+
+
+
+
+ 19
+
+
+
19`}
+ />
+
+
+ );
+};
+
+export default BadgeComponents;
diff --git a/src/pages/ComponentsPage/components/ButtonComponents.tsx b/src/pages/ComponentsPage/components/ButtonComponents.tsx
index 039c5cf..63cdee6 100644
--- a/src/pages/ComponentsPage/components/ButtonComponents.tsx
+++ b/src/pages/ComponentsPage/components/ButtonComponents.tsx
@@ -3,6 +3,9 @@ import { ButtonVariant, PropsWithClassName, PropsWithTestId } from '@leanstacks/
import Button from 'components/Button/Button';
import CodeSnippet from 'components/Text/CodeSnippet';
import Text from 'components/Text/Text';
+import { ComponentProperty } from '../model/components';
+import { createColumnHelper } from '@tanstack/react-table';
+import Table from 'components/Table/Table';
/**
* Properties for the `ButtonComponents` React component.
@@ -21,19 +24,70 @@ const ButtonComponents = ({
className,
testId = 'components-button',
}: ButtonComponentsProps): JSX.Element => {
+ const data: ComponentProperty[] = [
+ {
+ name: 'children',
+ description: 'The content to be displayed.',
+ },
+ {
+ name: 'className',
+ description: 'Optional. Additional CSS class names.',
+ },
+ {
+ name: 'onClick',
+ description: 'Optional. Click event handler function.',
+ },
+ {
+ name: 'testId',
+ description: 'Optional. Identifier for testing.',
+ },
+ {
+ name: 'variant',
+ description: 'Optional. Applies default styling. Default: solid',
+ },
+ ];
+ const columnHelper = createColumnHelper();
+ const columns = [
+ columnHelper.accessor('name', {
+ cell: (info) => {info.getValue()} ,
+ header: () => 'Name',
+ }),
+ columnHelper.accessor('description', {
+ cell: (info) => info.renderValue(),
+ header: () => 'Description',
+ }),
+ ];
+
return (
- Button Components
+ Button Component
- Default button
+ The Button component displays a clickable
+ button which is styled in a standardized way.
+
+
+
+
+ Properties
+
+
data={data} columns={columns} />
+
+
+ Examples
+
+
+ Default button
+
Default button`} />
-
Outline button
+
+ Outline button
+
Outline button`}
@@ -41,7 +95,9 @@ const ButtonComponents = ({
-
Solid button
+
+ Solid button
+
Solid button`}
@@ -49,12 +105,38 @@ const ButtonComponents = ({
-
Text button
+
+ Text button
+
Text button`}
/>
+
+
+
+ alert('Hey! You clicked me!')}
+ testId="click-me-button"
+ >
+ Click me
+
+
+
alert('Hey! You clicked me!')}
+ testId="click-me-button"
+>
+ Click me
+`}
+ />
+
);
};
diff --git a/src/pages/ComponentsPage/components/CardComponents.tsx b/src/pages/ComponentsPage/components/CardComponents.tsx
new file mode 100644
index 0000000..dc74ad5
--- /dev/null
+++ b/src/pages/ComponentsPage/components/CardComponents.tsx
@@ -0,0 +1,186 @@
+import { PropsWithClassName, PropsWithTestId } from '@leanstacks/react-common';
+import { createColumnHelper } from '@tanstack/react-table';
+
+import { ComponentProperty } from '../model/components';
+import Text from 'components/Text/Text';
+import Table from 'components/Table/Table';
+import CodeSnippet from 'components/Text/CodeSnippet';
+import Card from 'components/Card/Card';
+import MessageCard from 'components/Card/MessageCard';
+
+/**
+ * Properties for the `CardComponents` React component.
+ * @see {@link PropsWithClassName}
+ * @see {@link PropsWithTestId}
+ */
+interface CardComponentsProps extends PropsWithClassName, PropsWithTestId {}
+
+/**
+ * The `CardComponents` React component renders a set of examples illustrating
+ * the use of the `Card` family of components.
+ * @param {CardComponentsProps} props - Component properties.
+ * @returns {JSX.Element} JSX
+ */
+const CardComponents = ({
+ className,
+ testId = 'components-card',
+}: CardComponentsProps): JSX.Element => {
+ const columnHelper = createColumnHelper();
+ const cardData: ComponentProperty[] = [
+ {
+ name: 'children',
+ description: 'The content to be displayed.',
+ },
+ {
+ name: 'className',
+ description: 'Optional. Additional CSS class names.',
+ },
+ {
+ name: 'testId',
+ description: 'Optional. Identifier for testing.',
+ },
+ ];
+ const messageCardData: ComponentProperty[] = [
+ {
+ name: 'className',
+ description: 'Optional. Additional CSS class names.',
+ },
+ {
+ name: 'iconProps',
+ description: 'Optional. Icon properties object.',
+ },
+ {
+ name: 'message',
+ description: 'Messasge text.',
+ },
+ {
+ name: 'testId',
+ description: 'Optional. Identifier for testing.',
+ },
+ {
+ name: 'title',
+ description: 'Optional. Title text.',
+ },
+ ];
+ const columns = [
+ columnHelper.accessor('name', {
+ cell: (info) => {info.getValue()} ,
+ header: () => 'Name',
+ }),
+ columnHelper.accessor('description', {
+ cell: (info) => info.renderValue(),
+ header: () => 'Description',
+ }),
+ ];
+
+ return (
+
+
+
+ Card Component
+
+
+
+ The Card component displays block container
+ for a group of related content.
+
+
+
+
+ Properties
+
+
data={cardData} columns={columns} />
+
+
+ Examples
+
+
+ I am the card content.
+
+
I am the card content.`} />
+
+
+
+
+
+ I am the card content.
+
+
+
+ I am the card content.
+`}
+ />
+
+
+
+
+
+ MessageCard Component
+
+
+
+ The MessageCard component displays block
+ container for displaying messages. The card consists of a message with optional title and
+ icon.
+
+
+
+
+ Properties
+
+
data={messageCardData} columns={columns} />
+
+
+ Examples
+
+
+
+
+
+
+
+ );
+};
+
+export default CardComponents;
diff --git a/src/pages/ComponentsPage/components/TextComponents.tsx b/src/pages/ComponentsPage/components/TextComponents.tsx
index 07d4741..0302cff 100644
--- a/src/pages/ComponentsPage/components/TextComponents.tsx
+++ b/src/pages/ComponentsPage/components/TextComponents.tsx
@@ -1,7 +1,10 @@
import { PropsWithClassName, PropsWithTestId } from '@leanstacks/react-common';
+import { createColumnHelper } from '@tanstack/react-table';
import CodeSnippet from 'components/Text/CodeSnippet';
import Text from 'components/Text/Text';
+import { ComponentProperty } from '../model/components';
+import Table from 'components/Table/Table';
/**
* Properties for the `TextComponents` React component.
@@ -20,43 +23,93 @@ const TextComponents = ({
className,
testId = 'components-text',
}: TextComponentsProps): JSX.Element => {
+ const data: ComponentProperty[] = [
+ {
+ name: 'children',
+ description: 'The content to be displayed.',
+ },
+ {
+ name: 'className',
+ description: 'Optional. Additional CSS class names.',
+ },
+ {
+ name: 'testId',
+ description: 'Optional. Identifier for testing.',
+ },
+ {
+ name: 'variant',
+ description: 'Optional. Applies default styling. Default: body copy',
+ },
+ ];
+ const columnHelper = createColumnHelper();
+ const columns = [
+ columnHelper.accessor('name', {
+ cell: (info) => {info.getValue()} ,
+ header: () => 'Name',
+ }),
+ columnHelper.accessor('description', {
+ cell: (info) => info.renderValue(),
+ header: () => 'Description',
+ }),
+ ];
+
return (
- Text Components
+ Text Component
- Heading 1
+ The Text component displays blocks of text
+ which is styled in a standardized way.
+
+
+
+
+ Properties
+
+
data={data} columns={columns} />
+
+
+ Examples
+
+
+ Heading 1
+
Heading 1`} />
-
Heading 2
+
+ Heading 2
+
Heading 2`} />
-
Heading 3
+
+ Heading 3
+
Heading 3`} />
-
Body Copy
-
- This is the standard body copy text. It may be styled in various ways such as{' '}
-
bold or
italic , as{' '}
-
underlined or{' '}
-
strikethrough .
+
+
+ This is standard body copy text. It may be styled in various ways such as{' '}
+ bold or italic , as{' '}
+ underlined or{' '}
+ strikethrough .
+
+ code={`
This is the standard body copy text. It may be styled in various ways such as{' '}
bold or italic , as{' '}
underlined or{' '}
strikethrough .
- `}
+`}
/>
diff --git a/src/pages/ComponentsPage/components/__tests__/BadgeComponents.test.tsx b/src/pages/ComponentsPage/components/__tests__/BadgeComponents.test.tsx
new file mode 100644
index 0000000..b146672
--- /dev/null
+++ b/src/pages/ComponentsPage/components/__tests__/BadgeComponents.test.tsx
@@ -0,0 +1,31 @@
+import { render, screen } from 'test/test-utils';
+import BadgeComponents from '../BadgeComponents';
+
+describe('BadgeComponents', () => {
+ it('should render successfully', async () => {
+ // ARRANGE
+ render( );
+ await screen.findByTestId('components-badge');
+
+ // ASSERT
+ expect(screen.getByTestId('components-badge')).toBeDefined();
+ });
+
+ it('should use custom testId', async () => {
+ // ARRANGE
+ render( );
+ await screen.findByTestId('custom-testId');
+
+ // ASSERT
+ expect(screen.getByTestId('custom-testId')).toBeDefined();
+ });
+
+ it('should use custom className', async () => {
+ // ARRANGE
+ render( );
+ await screen.findByTestId('components-badge');
+
+ // ASSERT
+ expect(screen.getByTestId('components-badge').classList).toContain('custom-className');
+ });
+});
diff --git a/src/pages/ComponentsPage/components/__tests__/ButtonComponents.test.tsx b/src/pages/ComponentsPage/components/__tests__/ButtonComponents.test.tsx
index 6272f2b..8f6a27c 100644
--- a/src/pages/ComponentsPage/components/__tests__/ButtonComponents.test.tsx
+++ b/src/pages/ComponentsPage/components/__tests__/ButtonComponents.test.tsx
@@ -1,5 +1,6 @@
import { render, screen } from 'test/test-utils';
import ButtonComponents from '../ButtonComponents';
+import userEvent from '@testing-library/user-event';
describe('ButtonComponents', () => {
it('should render successfully', async () => {
@@ -28,4 +29,17 @@ describe('ButtonComponents', () => {
// ASSERT
expect(screen.getByTestId('components-button').classList).toContain('custom-className');
});
+
+ it('should display alert', async () => {
+ // ARRANGE
+ const alertSpy = jest.spyOn(window, 'alert').mockImplementation(() => {});
+ render( );
+ await screen.findByTestId('components-button');
+
+ // ACT
+ await userEvent.click(screen.getByTestId('click-me-button'));
+
+ // ASSERT
+ expect(alertSpy).toHaveBeenCalled();
+ });
});
diff --git a/src/pages/ComponentsPage/components/__tests__/CardComponents.test.tsx b/src/pages/ComponentsPage/components/__tests__/CardComponents.test.tsx
new file mode 100644
index 0000000..2c8e115
--- /dev/null
+++ b/src/pages/ComponentsPage/components/__tests__/CardComponents.test.tsx
@@ -0,0 +1,31 @@
+import { render, screen } from 'test/test-utils';
+import CardComponents from '../CardComponents';
+
+describe('CardComponents', () => {
+ it('should render successfully', async () => {
+ // ARRANGE
+ render( );
+ await screen.findByTestId('components-card');
+
+ // ASSERT
+ expect(screen.getByTestId('components-card')).toBeDefined();
+ });
+
+ it('should use custom testId', async () => {
+ // ARRANGE
+ render( );
+ await screen.findByTestId('custom-testId');
+
+ // ASSERT
+ expect(screen.getByTestId('custom-testId')).toBeDefined();
+ });
+
+ it('should use custom className', async () => {
+ // ARRANGE
+ render( );
+ await screen.findByTestId('components-card');
+
+ // ASSERT
+ expect(screen.getByTestId('components-card').classList).toContain('custom-className');
+ });
+});
diff --git a/src/pages/ComponentsPage/model/components.ts b/src/pages/ComponentsPage/model/components.ts
new file mode 100644
index 0000000..0ce95f7
--- /dev/null
+++ b/src/pages/ComponentsPage/model/components.ts
@@ -0,0 +1,10 @@
+/**
+ * A `ComponentProperty` object contains metadata describing a single attribute
+ * in a React component's properties object.
+ * @param {string} name - The property, i.e. attribute, name.
+ * @param {string} description - A short description of the property.
+ */
+export type ComponentProperty = {
+ name: string;
+ description: string;
+}
\ No newline at end of file