- Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet animi
- commodi cumque dicta ducimus eum iure, maiores mollitia, odit porro
- quas quod rerum soluta sunt tempora unde, vel voluptas voluptates.
-
-
- Lorem ipsum dolor sit amet, consectetur adipisicing elit. Amet animi
- commodi cumque dicta ducimus eum iure, maiores mollitia, odit porro
- quas quod rerum soluta sunt tempora unde, vel voluptas voluptates.
-
- );
-};
diff --git a/tools/ui-components/src/alert/index.ts b/tools/ui-components/src/alert/index.ts
deleted file mode 100644
index 2d2c5e525fe..00000000000
--- a/tools/ui-components/src/alert/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export { Alert } from './alert';
-export type { AlertProps } from './alert';
diff --git a/tools/ui-components/src/assets/code-brackets.svg b/tools/ui-components/src/assets/code-brackets.svg
deleted file mode 100644
index 73de9477600..00000000000
--- a/tools/ui-components/src/assets/code-brackets.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/tools/ui-components/src/assets/colors.svg b/tools/ui-components/src/assets/colors.svg
deleted file mode 100644
index 17d58d516e1..00000000000
--- a/tools/ui-components/src/assets/colors.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/tools/ui-components/src/assets/comments.svg b/tools/ui-components/src/assets/comments.svg
deleted file mode 100644
index 6493a139f52..00000000000
--- a/tools/ui-components/src/assets/comments.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/tools/ui-components/src/assets/direction.svg b/tools/ui-components/src/assets/direction.svg
deleted file mode 100644
index 65676ac2722..00000000000
--- a/tools/ui-components/src/assets/direction.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/tools/ui-components/src/assets/flow.svg b/tools/ui-components/src/assets/flow.svg
deleted file mode 100644
index 8ac27db403c..00000000000
--- a/tools/ui-components/src/assets/flow.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/tools/ui-components/src/assets/plugin.svg b/tools/ui-components/src/assets/plugin.svg
deleted file mode 100644
index 29e5c690c0a..00000000000
--- a/tools/ui-components/src/assets/plugin.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/tools/ui-components/src/assets/repo.svg b/tools/ui-components/src/assets/repo.svg
deleted file mode 100644
index f386ee902c1..00000000000
--- a/tools/ui-components/src/assets/repo.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/tools/ui-components/src/assets/stackalt.svg b/tools/ui-components/src/assets/stackalt.svg
deleted file mode 100644
index 9b7ad274350..00000000000
--- a/tools/ui-components/src/assets/stackalt.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/tools/ui-components/src/base.css b/tools/ui-components/src/base.css
deleted file mode 100644
index 91c8fa1c00c..00000000000
--- a/tools/ui-components/src/base.css
+++ /dev/null
@@ -1,19 +0,0 @@
-@import './colors.css';
-
-@tailwind base;
-
-@layer base {
- /* Override Tailwind's default `text-decoration` rule. */
- /* https://github.com/tailwindlabs/tailwindcss/blob/master/src/css/preflight.css#L85 */
- a {
- @apply underline;
- }
- /* Override Tailwind's default `-webkit-tap-highlight-color` rule. */
- /* https://github.com/tailwindlabs/tailwindcss/discussions/2984 */
- button {
- -webkit-tap-highlight-color: transparent;
- }
-}
-
-@tailwind components;
-@tailwind utilities;
diff --git a/tools/ui-components/src/button/button.stories.tsx b/tools/ui-components/src/button/button.stories.tsx
deleted file mode 100644
index 143bc26b0fa..00000000000
--- a/tools/ui-components/src/button/button.stories.tsx
+++ /dev/null
@@ -1,118 +0,0 @@
-import { Meta, StoryObj } from '@storybook/react';
-
-import { Button } from '.';
-
-const story = {
- title: 'Example/Button',
- component: Button,
- parameters: {
- controls: {
- include: [
- 'children',
- 'variant',
- 'size',
- 'disabled',
- 'block',
- 'href',
- 'download',
- 'target',
- 'onClick'
- ]
- }
- },
- argTypes: {
- variant: {
- options: ['primary', 'danger', 'info']
- },
- size: {
- options: ['small', 'medium', 'large']
- },
- disabled: {
- options: [true, false],
- control: { type: 'radio' }
- },
- block: {
- options: [true, false],
- control: { type: 'radio' }
- },
- target: {
- options: ['_self', '_blank', '_parent', '_top']
- },
- onClick: {
- action: 'clicked'
- },
- href: {
- control: { type: 'text' }
- },
- download: {
- control: { type: 'text' }
- }
- }
-} satisfies Meta;
-
-type Story = StoryObj;
-
-export const Default: Story = {
- args: {
- children: 'Button'
- }
-};
-
-export const Danger: Story = {
- args: {
- variant: 'danger',
- children: 'Button'
- }
-};
-
-export const Info: Story = {
- args: {
- variant: 'info',
- children: 'Button'
- }
-};
-
-export const Large: Story = {
- args: {
- size: 'large',
- children: 'Button'
- }
-};
-
-export const Small: Story = {
- args: {
- size: 'small',
- children: 'Button'
- }
-};
-
-export const Disabled: Story = {
- args: {
- children: 'Button',
- disabled: true
- }
-};
-
-export const FullWidth: Story = {
- args: {
- children: 'Button',
- block: true
- }
-};
-
-export const AsALink: Story = {
- args: {
- children: "I'm a link that looks like a button",
- href: 'https://www.freecodecamp.org'
- }
-};
-
-export const AsADownloadLink: Story = {
- args: {
- children: "I'm a download link",
- href: 'https://www.freecodecamp.org',
- download: 'my_file.txt'
- }
-};
-
-export default story;
diff --git a/tools/ui-components/src/button/button.test.tsx b/tools/ui-components/src/button/button.test.tsx
deleted file mode 100644
index 06eb32cde7e..00000000000
--- a/tools/ui-components/src/button/button.test.tsx
+++ /dev/null
@@ -1,117 +0,0 @@
-// Silence the `jest-dom/prefer-enabled-disabled` rule as the rule looks for the `disabled` attribute
-// while the Button component doesn't use it.
-/* eslint-disable jest-dom/prefer-enabled-disabled */
-
-import { render, screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import React from 'react';
-
-import { Button } from './button';
-
-describe('', () => {
- it("should have the role 'button' and render the correct text", () => {
- render();
-
- expect(
- screen.getByRole('button', { name: /hello world/i })
- ).toBeInTheDocument();
- });
-
- it("should have the type 'button' by default", () => {
- render();
-
- expect(
- screen.getByRole('button', { name: /hello world/i })
- ).toHaveAttribute('type', 'button');
- });
-
- it("should have the type 'submit' if it is specified", () => {
- render();
-
- expect(
- screen.getByRole('button', { name: /hello world/i })
- ).toHaveAttribute('type', 'submit');
- });
-
- it('should trigger the onClick prop on click if the component is a button element', async () => {
- const onClick = jest.fn();
-
- render();
-
- const button = screen.getByRole('button', { name: /hello world/i });
-
- await userEvent.click(button);
-
- expect(onClick).toHaveBeenCalledTimes(1);
- });
-
- it('should reflect the disabled state using the aria-disabled attribute', () => {
- render();
-
- const button = screen.getByRole('button', { name: /hello world/i });
-
- expect(button).toHaveAttribute('aria-disabled', 'true');
-
- // Ensure that the `disabled` attribute is not used.
- expect(button).not.toHaveAttribute('disabled', 'true');
- });
-
- it('should not trigger the onClick prop if the button is disabled', async () => {
- const onClick = jest.fn();
-
- render(
-
- );
-
- const button = screen.getByRole('button', { name: /hello world/i });
- await userEvent.click(button);
-
- expect(onClick).not.toHaveBeenCalled();
- });
-
- it('should render an anchor element if the `href` prop is defined', () => {
- render();
-
- const link = screen.getByRole('link', { name: /freeCodeCamp/i });
- const button = screen.queryByRole('button', { name: /freeCodeCamp/i });
-
- expect(link).toBeInTheDocument();
- expect(link).toHaveAttribute('href', 'https://www.freecodecamp.org');
- // Ensure that a button element is not rendered
- expect(button).not.toBeInTheDocument();
- });
-
- it('should render a button element if the `href` and `disabled` props are both defined', () => {
- render(
-
- );
-
- const button = screen.getByRole('button', { name: /freeCodeCamp/i });
- const link = screen.queryByRole('link', { name: /freeCodeCamp/i });
-
- expect(button).toBeInTheDocument();
- expect(button).toHaveAttribute('aria-disabled', 'true');
- // Ensure that a link element is not rendered
- expect(link).not.toBeInTheDocument();
- });
-
- it('should trigger the onClick prop on click if the component is an anchor element', async () => {
- const onClick = jest.fn();
-
- render(
-
- );
-
- const link = screen.getByRole('link', { name: /freeCodeCamp/i });
-
- await userEvent.click(link);
-
- expect(onClick).toHaveBeenCalledTimes(1);
- });
-});
diff --git a/tools/ui-components/src/button/button.tsx b/tools/ui-components/src/button/button.tsx
deleted file mode 100644
index 76b47cfaf8b..00000000000
--- a/tools/ui-components/src/button/button.tsx
+++ /dev/null
@@ -1,250 +0,0 @@
-import React, { useMemo } from 'react';
-import { ButtonProps, ButtonSize, ButtonVariant } from './types';
-
-const defaultClassNames = [
- // Positioning
- 'relative',
- 'inline-block',
- 'mt-[0.5px]',
- // Border
- 'border-solid',
- 'border-3',
- // Active state
- 'active:before:w-full',
- 'active:before:h-full',
- 'active:before:absolute',
- 'active:before:inset-0',
- 'active:before:border-3',
- 'active:before:border-transparent',
- 'active:before:bg-gray-900',
- 'active:before:opacity-20',
- // Disabled state
- 'aria-disabled:cursor-not-allowed',
- 'aria-disabled:opacity-50',
- // Focus state
- 'focus:outline-none', // Hide the default browser outline
- 'focus-visible:ring',
- 'focus-visible:ring-focus-outline-color',
- // Misc
- 'text-center',
- 'cursor-pointer',
- 'no-underline' // For link
-];
-
-const computeClassNames = ({
- size,
- variant,
- disabled,
- block
-}: {
- size?: ButtonSize;
- variant?: ButtonVariant;
- disabled?: boolean;
- block?: boolean;
-}) => {
- const classNames = [...defaultClassNames];
-
- if (block) {
- classNames.push('block', 'w-full');
- }
-
- switch (variant) {
- case 'danger':
- classNames.push(
- 'border-foreground-danger',
- 'bg-background-danger',
- 'text-foreground-danger',
- ...(disabled
- ? ['active:before:hidden']
- : [
- 'hover:bg-foreground-danger',
- 'hover:text-background-danger',
- // This hover rule is redundant for the component library,
- // but is needed to override the border color set in client's `global.css`.
- // We can remove it once we have completely removed the CSS overrides in client.
- 'hover:border-foreground-danger',
- 'dark:hover:bg-background-danger',
- 'dark:hover:text-foreground-danger'
- ])
- );
- break;
- case 'info':
- classNames.push(
- 'border-foreground-info',
- 'bg-background-info',
- 'text-foreground-info',
- ...(disabled
- ? ['active:before:hidden']
- : [
- 'hover:bg-foreground-info',
- 'hover:text-background-info',
- // This hover rule is redundant for the component library,
- // but is needed to override the border color set in client's `global.css`.
- // We can remove it once we have completely removed the CSS overrides in client.
- 'hover:border-foreground-info',
- 'dark:hover:bg-background-info',
- 'dark:hover:text-foreground-info'
- ])
- );
- break;
- // default variant is 'primary'
- default:
- classNames.push(
- 'border-foreground-secondary',
- 'bg-background-quaternary',
- 'text-foreground-secondary',
- ...(disabled
- ? ['active:before:hidden']
- : [
- 'hover:bg-foreground-primary',
- 'hover:text-background-primary',
- // This hover rule is redundant for the component library,
- // but is needed to override the border color set in client's `global.css`.
- // We can remove it once we have completely removed the CSS overrides in client.
- 'hover:border-foreground-secondary',
- 'dark:hover:bg-background-primary',
- 'dark:hover:text-foreground-primary'
- ])
- );
- }
-
- switch (size) {
- case 'large':
- classNames.push('px-4 py-2.5 text-lg');
- break;
- case 'small':
- classNames.push('px-2.5 py-1 text-sm');
- break;
- // default size is 'medium'
- default:
- classNames.push('px-3 py-1.5 text-md');
- }
-
- return classNames.join(' ');
-};
-
-const StylessButton = React.forwardRef, ButtonProps>(
- (
- { className, onClick, disabled, children, type = 'button', ...rest },
- ref
- ) => {
- // Manually prevent the click event if the button is disabled
- // as `aria-disabled` marks the element disabled but still registers the click event.
- // Ref: https://css-tricks.com/making-disabled-buttons-more-inclusive/#aa-the-difference-between-disabled-and-aria-disabled
- const handleClick = (event: React.MouseEvent) => {
- if (disabled) {
- return;
- }
-
- if (onClick) {
- onClick(event);
- }
- };
-
- return (
-
- );
- }
-);
-
-const Link = React.forwardRef, ButtonProps>(
- ({ className, href, download, target, children, ...rest }, ref) => {
- return (
-
- {children}
-
- );
- }
-);
-
-export const HeadlessButton = React.forwardRef<
- React.ElementRef<'button' | 'a'>,
- ButtonProps
->(
- (
- { onClick, className, children, disabled, href, download, target, ...rest },
- ref
- ) => {
- if (href && !disabled) {
- return (
- }
- onClick={onClick}
- {...rest}
- >
- {children}
-
- );
- } else {
- return (
- }
- {...rest}
- >
- {children}
-
- );
- }
- }
-);
-
-export const Button = React.forwardRef<
- React.ElementRef<'button' | 'a'>,
- ButtonProps
->(
- (
- {
- className,
- size = 'medium',
- disabled,
- variant = 'primary',
- block,
- ...rest
- },
- ref
- ) => {
- const classes = useMemo(
- () => computeClassNames({ size, variant, disabled, block }),
- [size, variant, disabled, block]
- );
-
- const buttonStyle = [className, classes].join(' ');
-
- return (
-
- );
- }
-);
-
-Button.displayName = 'Button';
-HeadlessButton.displayName = 'HeadlessButton';
-StylessButton.displayName = 'StylessButton';
-Link.displayName = 'Link';
diff --git a/tools/ui-components/src/button/index.ts b/tools/ui-components/src/button/index.ts
deleted file mode 100644
index 51e1cd5239a..00000000000
--- a/tools/ui-components/src/button/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-export { Button, HeadlessButton } from './button';
-export type { ButtonProps } from './types';
diff --git a/tools/ui-components/src/button/types.ts b/tools/ui-components/src/button/types.ts
deleted file mode 100644
index 8fac12b6f79..00000000000
--- a/tools/ui-components/src/button/types.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { MouseEventHandler } from 'react';
-
-export type ButtonVariant = 'primary' | 'danger' | 'info';
-
-export type ButtonSize = 'small' | 'medium' | 'large';
-
-export interface ButtonProps
- extends React.ButtonHTMLAttributes {
- children: React.ReactNode;
- variant?: ButtonVariant;
- size?: ButtonSize;
- onClick?: MouseEventHandler;
- type?: 'submit' | 'button';
- disabled?: boolean;
- block?: boolean;
- href?: string;
- download?: string;
- target?: React.HTMLAttributeAnchorTarget;
-}
diff --git a/tools/ui-components/src/close-button/close-button.stories.tsx b/tools/ui-components/src/close-button/close-button.stories.tsx
deleted file mode 100644
index 47d41ae5d6a..00000000000
--- a/tools/ui-components/src/close-button/close-button.stories.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Meta, StoryObj } from '@storybook/react';
-import { CloseButton } from './close-button';
-
-const story = {
- title: 'Example/CloseButton',
- component: CloseButton
-} satisfies Meta;
-
-type Story = StoryObj;
-
-export const Basic: Story = {
- args: {}
-};
-
-export default story;
diff --git a/tools/ui-components/src/close-button/close-button.test.tsx b/tools/ui-components/src/close-button/close-button.test.tsx
deleted file mode 100644
index 87e3536a4b0..00000000000
--- a/tools/ui-components/src/close-button/close-button.test.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import { render, screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import React from 'react';
-import { CloseButton } from './close-button';
-
-describe('', () => {
- it('should render', () => {
- render();
-
- expect(screen.getByRole('button')).toBeInTheDocument();
- });
-
- it('should have "Close" as the default label', () => {
- render();
-
- expect(screen.getByRole('button', { name: 'Close' })).toBeInTheDocument();
- });
-
- it('should set "aria-label" to "label" prop', () => {
- const expectedLabel = 'Close me please';
- render();
-
- expect(
- screen.getByRole('button', { name: expectedLabel })
- ).toBeInTheDocument();
- });
-
- it('should call "onClick" handler on button click', async () => {
- const onClick = jest.fn();
- render();
-
- await userEvent.click(screen.getByRole('button'));
-
- expect(onClick).toHaveBeenCalledTimes(1);
- });
-});
diff --git a/tools/ui-components/src/close-button/close-button.tsx b/tools/ui-components/src/close-button/close-button.tsx
deleted file mode 100644
index 8e845a5754f..00000000000
--- a/tools/ui-components/src/close-button/close-button.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import React from 'react';
-
-export interface CloseButtonProps {
- className?: string;
- label?: string;
- onClick: () => void;
-}
-
-/**
- * Basic UI component for closing modals, alerts, etc.
- */
-export function CloseButton({
- className,
- label,
- onClick
-}: CloseButtonProps): JSX.Element {
- const classes = [
- // Remove browser's default styles
- 'bg-transparent',
- 'border-none',
- // Text styles
- 'text-lg',
- 'font-bold',
- 'text-foreground-primary',
- // Focus state
- 'focus:opacity-100',
- 'focus:text-opacity-100',
- 'focus:outline-none', // Hide the default browser outline
- 'focus-visible:ring',
- 'focus-visible:ring-focus-outline-color',
- // Hover state
- 'hover:opacity-100',
- 'hover:text-opacity-100',
- // Content positioning
- 'flex',
- 'justify-center',
- 'items-center',
- // Others
- 'w-[24px]',
- 'h-[24px]',
- 'opacity-50',
- className
- ].join(' ');
-
- return (
-
- );
-}
diff --git a/tools/ui-components/src/close-button/index.tsx b/tools/ui-components/src/close-button/index.tsx
deleted file mode 100644
index eb88b41f0a0..00000000000
--- a/tools/ui-components/src/close-button/index.tsx
+++ /dev/null
@@ -1,2 +0,0 @@
-export { CloseButton } from './close-button';
-export type { CloseButtonProps } from './close-button';
diff --git a/tools/ui-components/src/col/col.stories.tsx b/tools/ui-components/src/col/col.stories.tsx
deleted file mode 100644
index 98975686f8c..00000000000
--- a/tools/ui-components/src/col/col.stories.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import React from 'react';
-import { Meta, StoryFn, StoryObj } from '@storybook/react';
-import { Col } from '.';
-
-const story = {
- title: 'Example/Col',
- component: Col,
- argTypes: {
- className: { control: { type: 'text' } },
- xs: { options: [8, 12, undefined] },
- sm: { options: [2, 4, 6, 8, 10, 12, undefined] },
- md: { options: [4, 6, 8, 10, undefined] },
- lg: { options: [6, 8, 10, undefined] },
- xsOffset: { options: [2, 3, undefined] },
- smOffset: { options: [1, 2, 3, 4, undefined] },
- mdOffset: { options: [1, 2, 3, 4, undefined] },
- lgOffset: { options: [0, 1, 2, undefined] },
- smPush: { options: [1, undefined] }
- }
-} satisfies Meta;
-
-const Template: StoryFn = args => {
- return (
-
-
Random text to test the element width
-
- );
-};
-
-export const Default: StoryObj = {
- render: Template,
-
- args: {
- // default props go here
- }
-};
-
-export default story;
diff --git a/tools/ui-components/src/col/col.test.tsx b/tools/ui-components/src/col/col.test.tsx
deleted file mode 100644
index 526da0387f7..00000000000
--- a/tools/ui-components/src/col/col.test.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import React from 'react';
-import { render, screen } from '@testing-library/react';
-
-import { Col } from '.';
-
-describe('
', () => {
- it('should change className when props are passed', () => {
- render(
-
- Learn to code for free.
-
- );
- expect(screen.getByText('Learn to code for free.')).toHaveClass(
- 'min-h-[1px] px-[15px] w-full md:w-5/6 min-[1200px]:w-2/3 md:ml-[8.3%] min-[1200px]:ml-[16.6%]'
- );
- });
- it('should have lgOffSet 0 when it is passed to the component', () => {
- render(
Learn to code for free.);
- expect(screen.getByText('Learn to code for free.')).toHaveClass(
- 'min-h-[1px] px-[15px] min-[1200px]:ml-0'
- );
- });
- it('should add className to it', () => {
- render(
-
- Laboriosam autem non et nisi. Ut voluptatem sit beatae assumenda
- amet aliquam corporis.
-
-
- Dolores voluptas omnis et cupiditate ducimus delectus vel. Voluptas
- atque cumque incidunt quia. A praesentium neque quis odit totam
- praesentium illum est. Ut doloribus quisquam ut. Incidunt vel
- suscipit accusamus consequuntur repellendus dolor sunt. Vel
- accusamus nesciunt perspiciatis sunt est.
-
-
- Tempore quis voluptas aut voluptatem praesentium nisi. Qui et quo ut
- et vel dolores facilis dignissimos. Omnis facere quisquam recusandae
- accusantium. Sit ut consectetur non id velit est odio. Laboriosam
- soluta tenetur asperiores. Excepturi reprehenderit rerum sint
- tempore molestiae vitae aliquid. Ea est sunt at atque ducimus
- doloribus quas sit.
-
- Laboriosam autem non et nisi. Ut voluptatem sit beatae assumenda
- amet aliquam corporis.
-
-
- Dolores voluptas omnis et cupiditate ducimus delectus vel. Voluptas
- atque cumque incidunt quia. A praesentium neque quis odit totam
- praesentium illum est. Ut doloribus quisquam ut. Incidunt vel
- suscipit accusamus consequuntur repellendus dolor sunt. Vel
- accusamus nesciunt perspiciatis sunt est.
-
-
- Tempore quis voluptas aut voluptatem praesentium nisi. Qui et quo ut
- et vel dolores facilis dignissimos. Omnis facere quisquam recusandae
- accusantium. Sit ut consectetur non id velit est odio. Laboriosam
- soluta tenetur asperiores. Excepturi reprehenderit rerum sint
- tempore molestiae vitae aliquid. Ea est sunt at atque ducimus
- doloribus quas sit.
-
-
-
-
-
-
-
-
-
- );
-};
-
-export const Default: Story = {
- render: DefaultTemplate
-};
-
-export const Large: Story = {
- render: DefaultTemplate,
- args: {
- size: 'large'
- }
-};
-
-export const ExtraLarge: Story = {
- render: DefaultTemplate,
- args: {
- size: 'xLarge'
- }
-};
-
-export const Danger: Story = {
- render: DangerTemplate,
- args: {
- variant: 'danger'
- }
-};
-
-export const WithoutCloseButton: Story = {
- render: DefaultTemplate,
- args: {
- showCloseButton: false
- }
-};
-
-export const LeftAlignedBody: Story = {
- render: DefaultTemplate,
- args: {
- alignment: 'left'
- }
-};
-
-export const StartAlignedBody: Story = {
- render: DefaultTemplate,
- args: {
- alignment: 'start'
- }
-};
-
-export default story;
diff --git a/tools/ui-components/src/modal/modal.test.tsx b/tools/ui-components/src/modal/modal.test.tsx
deleted file mode 100644
index d74f40cb373..00000000000
--- a/tools/ui-components/src/modal/modal.test.tsx
+++ /dev/null
@@ -1,162 +0,0 @@
-import React from 'react';
-import { render, screen, within } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-
-import { Button } from '../button';
-import { Modal } from './modal';
-import { type ModalProps, type HeaderProps } from './types';
-
-const originalWindow = window;
-
-describe('', () => {
- beforeAll(() => {
- // The Modal component uses `ResizeObserver` under the hood.
- // However, this property is not available in JSDOM, so we need to manually add it to the window object.
- // Ref: https://github.com/jsdom/jsdom/issues/3368
- Object.defineProperty(window, 'ResizeObserver', {
- writable: true,
- value: jest.fn(() => ({
- observe: jest.fn(),
- unobserve: jest.fn(),
- disconnect: jest.fn()
- }))
- });
- });
-
- afterEach(() => {
- jest.clearAllMocks();
- });
-
- afterAll(() => {
- Object.defineProperty(globalThis, 'window', {
- value: originalWindow
- });
- });
-
- const setup = ({
- showCloseButton,
- open = false,
- onClose = () => {},
- ...modalProps
- }: Partial) => {
- render(
-
-
- Lorem ipsum
-
-
-
Laboriosam autem non et nisi.
-
-
-
-
-
-
- );
- };
-
- it('should not appear if `open` is `false`', () => {
- setup({ open: false });
-
- expect(
- screen.queryByRole('dialog', { name: 'Lorem ipsum' })
- ).not.toBeInTheDocument();
- });
-
- it('should appear and render the content properly if `open` is `true`', async () => {
- setup({ open: true });
-
- const dialog = await screen.findByRole('dialog', { name: 'Lorem ipsum' });
- expect(dialog).toBeInTheDocument();
-
- expect(
- within(dialog).getByRole('heading', { level: 2 })
- ).toBeInTheDocument();
- expect(
- within(dialog).getByRole('button', { name: 'Close' })
- ).toBeInTheDocument();
- expect(
- within(dialog).getByText('Laboriosam autem non et nisi.')
- ).toBeInTheDocument();
- expect(
- within(dialog).getByRole('button', { name: 'Submit' })
- ).toBeInTheDocument();
- expect(
- within(dialog).getByRole('button', { name: 'Cancel' })
- ).toBeInTheDocument();
- });
-
- it('should hide the close button if `showCloseButton` is `false`', async () => {
- setup({ open: true, showCloseButton: false });
-
- const dialog = await screen.findByRole('dialog', { name: 'Lorem ipsum' });
- expect(dialog).toBeInTheDocument();
-
- expect(
- within(dialog).getByRole('heading', { level: 2 })
- ).toBeInTheDocument();
- expect(
- within(dialog).queryByRole('button', { name: 'Close' })
- ).not.toBeInTheDocument();
- expect(
- within(dialog).getByText('Laboriosam autem non et nisi.')
- ).toBeInTheDocument();
- expect(
- within(dialog).getByRole('button', { name: 'Submit' })
- ).toBeInTheDocument();
- expect(
- within(dialog).getByRole('button', { name: 'Cancel' })
- ).toBeInTheDocument();
- });
-
- it('should automatically focus on the close button when open', async () => {
- setup({ open: true });
-
- const dialog = await screen.findByRole('dialog', { name: 'Lorem ipsum' });
- expect(dialog).toBeInTheDocument();
-
- const closeButton = within(dialog).getByRole('button', { name: 'Close' });
- expect(closeButton).toHaveFocus();
- });
-
- it('should automatically focus on the first focusable element if `showCloseButton` is `false`', async () => {
- setup({ open: true, showCloseButton: false });
-
- const dialog = await screen.findByRole('dialog', { name: 'Lorem ipsum' });
- expect(dialog).toBeInTheDocument();
-
- const submitButton = within(dialog).getByRole('button', { name: 'Submit' });
- expect(submitButton).toHaveFocus();
- });
-
- it('should trigger the `onClose` prop on close button click', async () => {
- const onClose = jest.fn();
-
- setup({ open: true, onClose });
-
- const dialog = await screen.findByRole('dialog', { name: 'Lorem ipsum' });
- expect(dialog).toBeInTheDocument();
-
- const closeButton = within(dialog).getByRole('button', { name: 'Close' });
- await userEvent.click(closeButton);
-
- expect(onClose).toHaveBeenCalledTimes(1);
- });
-
- it('should trigger the `onClose` prop on Escape key press', async () => {
- const onClose = jest.fn();
-
- setup({ open: true, onClose });
-
- const dialog = await screen.findByRole('dialog', { name: 'Lorem ipsum' });
- expect(dialog).toBeInTheDocument();
-
- await userEvent.keyboard('{Escape}');
-
- expect(onClose).toHaveBeenCalledTimes(1);
- });
-});
diff --git a/tools/ui-components/src/modal/modal.tsx b/tools/ui-components/src/modal/modal.tsx
deleted file mode 100644
index 6dad3b5dc1b..00000000000
--- a/tools/ui-components/src/modal/modal.tsx
+++ /dev/null
@@ -1,156 +0,0 @@
-import React, { createContext, useContext, Fragment } from 'react';
-import { Dialog, Transition } from '@headlessui/react';
-
-import { CloseButton } from '../close-button';
-import type { ModalProps, HeaderProps, BodyProps, FooterProps } from './types';
-
-// There is a close button on the right side of the modal title.
-// Some extra padding needs to be added to the left of the title text
-// so that the title is properly centered.
-// The value of the left padding is the width of the close button.
-const TITLE_LEFT_PADDING = 24;
-
-const PANEL_DEFAULT_CLASSES =
- 'flex flex-col border-solid border-1 border-foreground-secondary bg-background-secondary';
-
-const HEADER_DEFAULT_CLASSES = 'p-[15px]';
-
-const ModalContext = createContext>({
- onClose: () => {},
- variant: 'default'
-});
-
-const Header = ({
- children,
- showCloseButton = true,
- closeButtonClassNames,
- borderless
-}: HeaderProps) => {
- const { onClose, variant } = useContext(ModalContext);
-
- let classes = HEADER_DEFAULT_CLASSES;
-
- if (variant === 'danger') {
- classes = classes.concat(' ', 'bg-foreground-danger');
- }
-
- if (!borderless) {
- classes = classes.concat(
- ' ',
- 'border-b-1 border-solid border-foreground-secondary'
- );
- }
-
- if (showCloseButton) {
- classes = classes.concat(' ', 'flex items-center justify-between');
-
- return (
-