@patreon/studio
Version:
Patreon Studio Design System
123 lines (112 loc) • 3.47 kB
JSX
'use client';
import React, { useCallback } from 'react';
import styled, { css } from 'styled-components';
import { tokens } from '../../tokens';
import { filterForAriaProps } from '../../utilities/accessibility';
import { LoadingSpinner } from '../LoadingSpinner';
export function Toggle({ disabled, id, onClick, isLoading, isOn, ...props }) {
const handleClick = useCallback((e) => {
if (!disabled) {
onClick?.(e);
}
}, [disabled, onClick]);
const handleKeyPress = useCallback((e) => {
if (['Space', 'Enter'].includes(e.key)) {
handleClick(e);
}
}, [handleClick]);
return (<ToggleContainer aria-checked={isOn} aria-live="polite" aria-readonly={disabled} disabled={disabled} id={id} isOn={isOn} onClick={handleClick} onKeyPress={handleKeyPress} role="switch" type="button" {...filterForAriaProps(props)}>
<ToggleHandle isOn={isOn} disabled={disabled}/>
<LoadingSpinnerWrapper isOn={isOn} isLoading={isLoading}>
<LoadingSpinner color="actionBase" size="xs"/>
</LoadingSpinnerWrapper>
</ToggleContainer>);
}
const ToggleContainer = styled.button `
align-items: center;
appearance: none;
background: none;
border: 0;
box-sizing: border-box;
display: flex;
overflow: hidden;
position: relative;
height: 24px;
width: 48px;
padding: 0 6px;
border-radius: ${tokens.global.radius.circle};
background-color: ${tokens.global.primary.muted.default};
${({ isOn, disabled }) => css `
${isOn &&
css `
background-color: ${tokens.global.primary.actionBase.default};
`}
${disabled &&
css `
cursor: not-allowed;
opacity: ${tokens.global.opacity.disabled};
`}
${!disabled &&
css `
cursor: pointer;
&:hover {
background-color: ${tokens.global.primary.muted.hover};
}
&:active {
background-color: ${tokens.global.primary.muted.pressed};
}
${isOn &&
css `
&:hover {
background-color: ${tokens.global.primary.actionBase.hover};
}
&:active {
background-color: ${tokens.global.primary.actionBase.pressed};
}
`}
`}
`}
${({ disabled }) => disabled &&
css `
cursor: not-allowed;
opacity: ${tokens.global.opacity.disabled};
`}
`;
const ToggleHandle = styled.div `
position: absolute;
height: 20px;
width: 20px;
background-color: ${tokens.global.primary.onActionBase.default};
border-radius: ${tokens.global.radius.circle};
box-shadow: ${({ disabled }) => !disabled && tokens.global.boxShadow.low};
left: 0;
top: 0;
margin: 2px;
z-index: 2;
transition: transform ${tokens.global.transition.fast.duration} ${tokens.global.transition.fast.easing};
${({ isOn }) => isOn &&
css `
transform: translateX(calc(100% + 4px));
`}
`;
const LoadingSpinnerWrapper = styled.div `
position: relative;
z-index: 1;
margin: 2px;
transition: opacity ${tokens.global.transition.fast.duration} ${tokens.global.transition.fast.easing};
opacity: 0;
transform: scale(0.7);
transform-origin: center;
${({ isLoading }) => isLoading &&
css `
opacity: ${tokens.global.opacity.disabled};
`}
${({ isOn }) => isOn
? css `
margin-left: -2px;
`
: css `
margin-left: calc(50% + 2px);
`};
`;
//# sourceMappingURL=index.jsx.map