UNPKG

@furystack/shades-common-components

Version:

Common UI components for FuryStack Shades

176 lines 6.97 kB
import { Shade, createComponent } from '@furystack/shades'; import { cssVariableTheme } from '../../services/css-variable-theme.js'; import { ThemeProviderService } from '../../services/theme-provider-service.js'; import { FormContextToken } from '../form.js'; export const Checkbox = Shade({ customElementName: 'shade-checkbox', 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', }, '& .checkbox-control': { position: 'relative', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: '20px', height: '20px', flexShrink: '0', }, '& input[type="checkbox"]': { appearance: 'none', webkitAppearance: 'none', width: '20px', height: '20px', margin: '0', border: `2px solid ${cssVariableTheme.text.secondary}`, borderRadius: cssVariableTheme.shape.borderRadius.xs, backgroundColor: 'transparent', cursor: 'pointer', transition: `all ${cssVariableTheme.transitions.duration.fast} ${cssVariableTheme.transitions.easing.default}`, outline: 'none', }, '& input[type="checkbox"]:hover:not(:disabled)': { borderColor: 'var(--checkbox-color)', }, '& input[type="checkbox"]:focus-visible': { outline: 'none', boxShadow: cssVariableTheme.action.focusRing, }, '& input[type="checkbox"]:checked': { backgroundColor: 'var(--checkbox-color)', borderColor: 'var(--checkbox-color)', }, '& input[type="checkbox"]:checked::after': { content: '""', position: 'absolute', left: '6px', top: '2px', width: '5px', height: '10px', border: `solid ${cssVariableTheme.background.paper}`, borderWidth: '0 2px 2px 0', transform: 'rotate(45deg)', pointerEvents: 'none', }, '&[data-indeterminate] input[type="checkbox"]': { backgroundColor: 'var(--checkbox-color)', borderColor: 'var(--checkbox-color)', }, '&[data-indeterminate] input[type="checkbox"]::after': { content: '""', position: 'absolute', left: '4px', top: '8px', width: '10px', height: '2px', background: cssVariableTheme.background.paper, border: 'none', transform: 'none', pointerEvents: 'none', }, '&[data-disabled] label': { color: cssVariableTheme.text.disabled, cursor: 'not-allowed', }, '&[data-disabled] input[type="checkbox"]': { opacity: cssVariableTheme.action.disabledOpacity, cursor: 'not-allowed', }, // Size: small '&[data-size="small"] label': { fontSize: cssVariableTheme.typography.fontSize.xs, }, '&[data-size="small"] .checkbox-control': { width: '16px', height: '16px', }, '&[data-size="small"] input[type="checkbox"]': { width: '16px', height: '16px', }, '&[data-size="small"] input[type="checkbox"]:checked::after': { left: '4px', top: '1px', width: '4px', height: '8px', }, '&[data-size="small"][data-indeterminate] input[type="checkbox"]::after': { left: '3px', top: '6px', width: '8px', }, // Size: large '&[data-size="large"] label': { fontSize: cssVariableTheme.typography.fontSize.md, }, '&[data-size="large"] .checkbox-control': { width: '24px', height: '24px', }, '&[data-size="large"] input[type="checkbox"]': { width: '24px', height: '24px', }, '&[data-size="large"] input[type="checkbox"]:checked::after': { left: '8px', top: '3px', width: '6px', height: '12px', }, '&[data-size="large"][data-indeterminate] input[type="checkbox"]::after': { left: '5px', top: '10px', width: '12px', }, }, 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-size': props.size && props.size !== 'medium' ? props.size : undefined, 'data-disabled': props.disabled ? '' : undefined, 'data-indeterminate': props.indeterminate ? '' : undefined, style: { '--checkbox-color': color }, }); // The host element already receives `props.onchange` via Shade's attachProps; // a bubbled change from the inner input triggers it once. This handler exists // only to keep the input in its `indeterminate` visual state across toggles. const handleChange = () => { if (props.indeterminate && inputRef.current) { inputRef.current.indeterminate = true; } }; return (createComponent("label", { ...props.labelProps }, createComponent("span", { className: "checkbox-control" }, createComponent("input", { ref: inputRef, type: "checkbox", checked: props.checked, disabled: props.disabled, name: props.name, required: props.required, onchange: handleChange, ...(props.value !== undefined ? { value: props.value } : {}) })), props.labelTitle ? createComponent("span", { className: "checkbox-label" }, props.labelTitle) : null)); }, }); //# sourceMappingURL=checkbox.js.map