Skip to content

Commit

Permalink
Merge pull request #95 from MetroStar/comet-ui-toggle-comp
Browse files Browse the repository at this point in the history
comet-ui-toggle-comp # added toggle component to comet
  • Loading branch information
kildre authored Jan 31, 2024
2 parents 5f1746c + c853375 commit 7670591
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/comet-extras/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { default as DataTable } from './data-table';
export { default as Spinner } from './spinner';
export { default as Tabs, TabPanel } from './tabs';
export { default as Toggle } from './toggle';
1 change: 1 addition & 0 deletions packages/comet-extras/src/components/toggle/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './toggle';
35 changes: 35 additions & 0 deletions packages/comet-extras/src/components/toggle/toggle.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import { Meta, StoryFn } from '@storybook/react';
import Toggle, { ToggleProps } from './toggle';

export default {
title: 'Extras/Toggle',
component: Toggle,
argTypes: {
id: { control: 'text' },
name: { control: 'text' },
checked: { control: 'boolean' },
label: { control: 'text' },
ariaLabel: { control: 'text' },
onChange: { action: 'changed' },
},
} as Meta<ToggleProps>;

const Template: StoryFn<ToggleProps> = (args) => <Toggle {...args} />;

export const Default = Template.bind({});
Default.args = {
id: 'toggle',
name: 'toggle',
checked: false,
label: 'Toggle',
ariaLabel: 'Toggle button',
};

export const Checked = Template.bind({});
Checked.args = {
...Default.args,
checked: true,
label: 'Checked Toggle',
ariaLabel: 'Checked toggle button',
};
59 changes: 59 additions & 0 deletions packages/comet-extras/src/components/toggle/toggle.style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/* Path: packages/comet-extras/src/components/toggle/toggle.tsx */
.toggle {
align-items: center;
display: flex;
}

.toggle-body {
background-color: #e6e6e6;
border-radius: 9999px;
box-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 0.05);
height: 1.5rem;
width: 3rem;
}

.toggle-body.toggle-body-on {
background-color: #005ea2;
}
.toggle .pos-rel {
position: relative;
}
.toggle-dot {
background-color: #ffffff;
border: 1px solid #e6e6e6;
border-radius: 9999px;
box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
position: absolute;
height: 1.5rem;
left: 0;
top: 0;
width: 1.5rem;

&.ml-6 {
margin-left: 1.5rem;
}
&.ml-0 {
margin-left: 0;
}
}

.toggle-label {
align-items: center;
cursor: pointer;
display: flex;
&.ml-3 {
margin-left: 0.75rem;
}
}

.toggle-sr-only {
border-width: 0;
clip: rect(0, 0, 0, 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
white-space: nowrap;
width: 1px;
}
37 changes: 37 additions & 0 deletions packages/comet-extras/src/components/toggle/toggle.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';
import { render, fireEvent, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
import { axe } from 'jest-axe';
import { Toggle } from './toggle'; // Assuming the Toggle component is in the same directory

describe('Toggle Component Tests', () => {
test('should render with no accessibility violations', async () => {
const { container } = render(
<Toggle id="test-toggle" label="Test toggle" onChange={jest.fn()} />,
);
expect(await axe(container)).toHaveNoViolations();
});
// Test to check if the Toggle renders correctly
test('renders the Toggle component', () => {
render(<Toggle id="test-toggle" />);

expect(screen.getByRole('checkbox')).toBeInTheDocument();
});

// Test to check if onChange is called and state changes on click
test('calls onChange and changes state when clicked', () => {
const handleChange = jest.fn();
render(<Toggle id="test-toggle" onChange={handleChange} />);
const toggle = screen.getByRole('checkbox');
fireEvent.click(toggle);
expect(handleChange).toHaveBeenCalledTimes(1);
expect(toggle).toBeChecked();
});

// Test to check if optional props like label are rendered correctly
test('renders label correctly when provided', () => {
const testLabel = 'Test Label';
render(<Toggle id="test-toggle" label={testLabel} />);
expect(screen.getByText(testLabel)).toBeInTheDocument();
});
});
71 changes: 71 additions & 0 deletions packages/comet-extras/src/components/toggle/toggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import './toggle.style.css';
import React, { ChangeEvent, ChangeEventHandler, useEffect, useState } from 'react';

export interface ToggleProps {
/**
* The unique identifier for this component
*/
id: string;
/**
* The name of the text input
*/
name?: string;
/**
* Whether the toggle is checked or not
*/
checked?: boolean;
/**
* A label to display with the toggle
*/
label?: string;
/**
* An accessible label for the toggle
*/
ariaLabel?: string;
/**
* Custom callback for when input is changed
*/
onChange?: ChangeEventHandler<HTMLInputElement>;
}

export const Toggle = ({
id,
name,
checked = false,
label,
ariaLabel,
onChange,
}: ToggleProps): React.ReactElement => {
const [isChecked, setIsChecked] = useState(false);
const toggleHandler = (event: ChangeEvent<HTMLInputElement>): void => {
setIsChecked(!isChecked);
onChange?.(event);
};

useEffect(() => {
setIsChecked(checked);
}, [checked]);

return (
<div className="toggle">
<label htmlFor={id} className="toggle-label" tabIndex={0} aria-label={ariaLabel}>
<div className="pos-rel">
<input
type="checkbox"
id={id}
name={name}
className="toggle-sr-only"
checked={isChecked}
onChange={toggleHandler}
tabIndex={-1}
/>
<div className={`toggle-body ${isChecked ? 'toggle-body-on' : ''}`}></div>
<div className={`toggle-dot ${isChecked ? 'ml-6' : 'ml-0'}`}></div>
</div>
{label && <span className="toggle-label ml-3">{label}</span>}
</label>
</div>
);
};

export default Toggle;

0 comments on commit 7670591

Please sign in to comment.