UNPKG

@patreon/studio

Version:

Patreon Studio Design System

123 lines (112 loc) 3.47 kB
'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