UNPKG

@furystack/shades-common-components

Version:

Common UI components for FuryStack Shades

153 lines 6.14 kB
import { Shade, createComponent } from '@furystack/shades'; import { buildTransition, cssVariableTheme } from '../../services/css-variable-theme.js'; import { ThemeProviderService } from '../../services/theme-provider-service.js'; import { FormContextToken } from '../form.js'; export const Switch = Shade({ customElementName: 'shade-switch', css: { display: 'inline-flex', fontFamily: cssVariableTheme.typography.fontFamily, alignItems: 'center', '& label': { display: 'inline-flex', alignItems: 'center', gap: cssVariableTheme.spacing.sm, cursor: 'pointer', fontSize: cssVariableTheme.typography.fontSize.sm, color: cssVariableTheme.text.primary, userSelect: 'none', webkitUserSelect: 'none', }, '& .switch-control': { position: 'relative', display: 'inline-flex', alignItems: 'center', flexShrink: '0', }, // Medium size (default) '& .switch-track': { width: '40px', height: '22px', borderRadius: '11px', backgroundColor: cssVariableTheme.text.secondary, transition: buildTransition([ 'background-color', cssVariableTheme.transitions.duration.fast, cssVariableTheme.transitions.easing.default, ]), position: 'relative', opacity: '0.5', }, '& .switch-thumb': { position: 'absolute', top: '2px', left: '2px', width: '18px', height: '18px', borderRadius: '50%', background: cssVariableTheme.background.paper, transition: buildTransition(['transform', cssVariableTheme.transitions.duration.fast, cssVariableTheme.transitions.easing.default], ['box-shadow', cssVariableTheme.transitions.duration.fast, cssVariableTheme.transitions.easing.default]), boxShadow: cssVariableTheme.shadows.sm, pointerEvents: 'none', }, // Small size '&[data-size="small"] .switch-track': { width: '32px', height: '18px', borderRadius: '9px', }, '&[data-size="small"] .switch-thumb': { width: '14px', height: '14px', }, // Large size '&[data-size="large"] .switch-track': { width: '48px', height: '26px', borderRadius: '13px', }, '&[data-size="large"] .switch-thumb': { width: '22px', height: '22px', }, // Hidden input '& input[type="checkbox"]': { position: 'absolute', width: '1px', height: '1px', margin: '-1px', padding: '0', overflow: 'hidden', clip: 'rect(0, 0, 0, 0)', whiteSpace: 'nowrap', border: '0', }, // Checked state '& input[type="checkbox"]:checked + .switch-track': { backgroundColor: 'var(--switch-color)', opacity: '1', }, '& input[type="checkbox"]:checked + .switch-track .switch-thumb': { transform: 'translateX(18px)', }, '&[data-size="small"] input[type="checkbox"]:checked + .switch-track .switch-thumb': { transform: 'translateX(14px)', }, '&[data-size="large"] input[type="checkbox"]:checked + .switch-track .switch-thumb': { transform: 'translateX(22px)', }, // Hover state '& .switch-control:hover .switch-track': { opacity: '0.7', }, '& .switch-control:hover input[type="checkbox"]:checked + .switch-track': { opacity: '0.85', }, // Focus state '& input[type="checkbox"]:focus-visible + .switch-track': { outline: 'none', boxShadow: cssVariableTheme.action.focusRing, }, // Disabled state '&[data-disabled] label': { color: cssVariableTheme.text.disabled, cursor: 'not-allowed', }, '&[data-disabled] .switch-control': { opacity: cssVariableTheme.action.disabledOpacity, pointerEvents: 'none', }, }, render: ({ props, injector, useDisposable, useHostProps, useRef }) => { const inputRef = useRef('formInput'); useDisposable('form-registration', () => { const formService = injector.get(FormContextToken); if (formService) { queueMicrotask(() => { if (inputRef.current) formService.inputs.add(inputRef.current); }); } return { [Symbol.dispose]: () => { if (inputRef.current && formService) formService.inputs.delete(inputRef.current); }, }; }); const themeProvider = injector.get(ThemeProviderService); const color = themeProvider.theme.palette[props.color || 'primary'].main; useHostProps({ 'data-disabled': props.disabled ? '' : undefined, 'data-size': props.size && props.size !== 'medium' ? props.size : undefined, style: { '--switch-color': color }, }); return (createComponent("label", { ...props.labelProps }, createComponent("span", { className: "switch-control" }, createComponent("input", { ref: inputRef, type: "checkbox", role: "switch", checked: props.checked, disabled: props.disabled, name: props.name, required: props.required, ...(props.value !== undefined ? { value: props.value } : {}) }), createComponent("span", { className: "switch-track" }, createComponent("span", { className: "switch-thumb" }))), props.labelTitle ? createComponent("span", { className: "switch-label" }, props.labelTitle) : null)); }, }); //# sourceMappingURL=switch.js.map