fix(dashboard-v2): migrate Switch to styled-components
This commit is contained in:
parent
a00d4f8db9
commit
cb5a162fe4
|
@ -1,40 +0,0 @@
|
||||||
.react-switch-checkbox {
|
|
||||||
height: 0;
|
|
||||||
width: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-switch-label {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
cursor: pointer;
|
|
||||||
width: 44px;
|
|
||||||
height: 22px;
|
|
||||||
background: white;
|
|
||||||
border-radius: 11px;
|
|
||||||
@apply border-palette-200;
|
|
||||||
border-width: 1px;
|
|
||||||
position: relative;
|
|
||||||
transition: background-color 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-switch-label .react-switch-button {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
top: 2px;
|
|
||||||
left: 2px;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
border-radius: 8px;
|
|
||||||
transition: 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-switch-checkbox:checked + .react-switch-label .react-switch-button {
|
|
||||||
left: calc(100% - 2px);
|
|
||||||
transform: translateX(-100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.react-switch-label:active .react-switch-button {
|
|
||||||
width: 20px;
|
|
||||||
}
|
|
|
@ -1,37 +1,86 @@
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import "./Switch.css";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { nanoid } from "nanoid";
|
||||||
|
|
||||||
|
const Container = styled.div.attrs({
|
||||||
|
className: "inline-flex items-center gap-1 cursor-pointer select-none",
|
||||||
|
})``;
|
||||||
|
|
||||||
|
const Checkbox = styled.input.attrs({
|
||||||
|
type: "checkbox",
|
||||||
|
className: `h-0 w-0 hidden`,
|
||||||
|
})``;
|
||||||
|
|
||||||
|
const Label = styled.label.attrs({
|
||||||
|
className: "cursor-pointer inline-flex items-center gap-2",
|
||||||
|
})`
|
||||||
|
&:active .toggle-pin {
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Toggle = styled.span.attrs({
|
||||||
|
className: `flex flex-row items-center justify-between
|
||||||
|
w-[44px] h-[22px] bg-white rounded-full
|
||||||
|
border border-palette-200 relative cursor-pointer`,
|
||||||
|
})`
|
||||||
|
&:active .toggle-pin {
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const TogglePin = styled.span.attrs(({ $checked }) => ({
|
||||||
|
className: `toggle-pin
|
||||||
|
absolute top-[2px] w-4 h-4 rounded-full
|
||||||
|
transition-[width_left] active:w-5
|
||||||
|
|
||||||
|
${$checked ? "checked bg-primary" : "bg-palette-200"}`,
|
||||||
|
}))`
|
||||||
|
left: 2px;
|
||||||
|
|
||||||
|
&.checked {
|
||||||
|
left: calc(100% - 2px);
|
||||||
|
transform: translateX(-100%);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const Switch = ({ children, defaultChecked, onChange, ...props }) => {
|
||||||
|
const id = useMemo(nanoid, [onChange]);
|
||||||
|
const [checked, setChecked] = useState(defaultChecked);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
onChange(checked);
|
||||||
|
}, [checked, onChange]);
|
||||||
|
|
||||||
/**
|
|
||||||
* Primary UI component for user interaction
|
|
||||||
*/
|
|
||||||
export const Switch = ({ isOn, handleToggle }) => {
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Container {...props}>
|
||||||
<input
|
<Checkbox checked={checked} onChange={(ev) => setChecked(ev.target.checked)} id={id} />
|
||||||
checked={isOn}
|
<Label htmlFor={id}>
|
||||||
onChange={handleToggle}
|
<Toggle>
|
||||||
className="react-switch-checkbox"
|
<TogglePin $checked={checked} />
|
||||||
id={`react-switch-new`}
|
</Toggle>
|
||||||
type="checkbox"
|
{children}
|
||||||
/>
|
</Label>
|
||||||
<label className={"react-switch-label"} htmlFor={`react-switch-new`}>
|
</Container>
|
||||||
<span className={`react-switch-button ${isOn ? "bg-primary" : "bg-palette-200"}`} />
|
|
||||||
</label>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
Switch.propTypes = {
|
Switch.propTypes = {
|
||||||
/**
|
/**
|
||||||
* Switch's current value
|
* Should the checkbox be checked by default?
|
||||||
*/
|
*/
|
||||||
isOn: PropTypes.bool,
|
defaultChecked: PropTypes.bool,
|
||||||
|
/**
|
||||||
|
* Element to be rendered as the switch label
|
||||||
|
*/
|
||||||
|
children: PropTypes.element,
|
||||||
/**
|
/**
|
||||||
* Function to execute on change
|
* Function to execute on change
|
||||||
*/
|
*/
|
||||||
handleToggle: PropTypes.func,
|
onChange: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
Switch.defaultProps = {
|
Switch.defaultProps = {
|
||||||
isOn: false,
|
defaultChecked: false,
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,10 +13,10 @@ const Template = (args) => <Switch {...args} />;
|
||||||
export const SwitchTrue = Template.bind({});
|
export const SwitchTrue = Template.bind({});
|
||||||
// More on args: https://storybook.js.org/docs/react/writing-stories/args
|
// More on args: https://storybook.js.org/docs/react/writing-stories/args
|
||||||
SwitchTrue.args = {
|
SwitchTrue.args = {
|
||||||
isOn: true,
|
defaultChecked: true,
|
||||||
};
|
};
|
||||||
export const SwitchFalse = Template.bind({});
|
export const SwitchFalse = Template.bind({});
|
||||||
// More on args: https://storybook.js.org/docs/react/writing-stories/args
|
// More on args: https://storybook.js.org/docs/react/writing-stories/args
|
||||||
SwitchFalse.args = {
|
SwitchFalse.args = {
|
||||||
isOn: false,
|
defaultChecked: false,
|
||||||
};
|
};
|
||||||
|
|
Reference in New Issue