UNPKG

@octopusdeploy/design-system-components

Version:
108 lines (107 loc) 5.63 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Switch = Switch; const jsx_runtime_1 = require("react/jsx-runtime"); const css_1 = require("@emotion/css"); const design_system_icons_1 = require("@octopusdeploy/design-system-icons"); const design_system_tokens_1 = require("@octopusdeploy/design-system-tokens"); const react_1 = require("react"); const InputLabel_1 = __importDefault(require("../Form/Primitives/InputLabel")); function Switch({ value, autoFocus, disabled, onChange, accessibleName, ...otherProps }) { const switchId = useInputId("switch-"); const { label, popover } = "label" in otherProps ? otherProps : { label: undefined, popover: undefined }; return ((0, jsx_runtime_1.jsxs)("div", { className: switchStyles.root, children: [(0, jsx_runtime_1.jsxs)("button", { autoFocus: autoFocus, className: switchStyles.button, type: "button", role: "switch", id: switchId, "aria-checked": value, "aria-label": accessibleName, disabled: disabled, onClick: () => onChange(!value), children: [(0, jsx_runtime_1.jsx)("span", { className: (0, css_1.cx)(switchStyles.thumb, value && switchStyles.thumbOn) }), (0, jsx_runtime_1.jsx)("span", { className: value ? switchStyles.iconOn : switchStyles.iconOff, children: value ? (0, jsx_runtime_1.jsx)(design_system_icons_1.CheckIcon, { size: 16, color: "currentColor" }) : (0, jsx_runtime_1.jsx)(design_system_icons_1.XmarkIcon, { size: 16, color: "currentColor" }) })] }), label && (0, jsx_runtime_1.jsx)(InputLabel_1.default, { isRadioOrCheckbox: false, label: label, htmlFor: switchId, popover: popover, isDisabled: disabled })] })); } const switchWidth = "2.5rem"; const switchHeight = "1.25rem"; const thumbSize = "1rem"; const thumbSlideDistance = `calc(${switchWidth} - ${thumbSize} - ${design_system_tokens_1.space[4]})`; const switchStyles = { root: (0, css_1.css)({ display: "flex", gap: design_system_tokens_1.space[8], alignItems: "center", margin: 0, }), button: (0, css_1.css)({ display: "flex", alignItems: "center", position: "relative", padding: `${design_system_tokens_1.space[2]} ${design_system_tokens_1.space[4]} ${design_system_tokens_1.space[2]} ${design_system_tokens_1.space[2]}`, width: switchWidth, height: switchHeight, borderRadius: design_system_tokens_1.borderRadius.extraLarge, border: "none", cursor: "pointer", //We set the status icon color via currentColor, so we need to set //the color here for the icon. color: design_system_tokens_1.themeTokens.color.icon.inverse.primary, backgroundColor: design_system_tokens_1.themeTokens.color.background.inverse.neutral, outline: "none", transition: "background-color 150ms ease", "&:hover:not(:disabled)": { backgroundColor: design_system_tokens_1.themeTokens.color.background.inverse.secondary, }, "&:focus-visible": { backgroundColor: design_system_tokens_1.themeTokens.color.background.inverse.secondary, outline: `2px solid ${design_system_tokens_1.themeTokens.color.border.selected}`, outlineOffset: "2px", }, "&:disabled": { cursor: "not-allowed", color: design_system_tokens_1.themeTokens.color.icon.secondary, backgroundColor: design_system_tokens_1.themeTokens.color.background.disabled, }, '&[aria-checked="true"]': { backgroundColor: design_system_tokens_1.themeTokens.color.background.inverse.success, "&:hover:not(:disabled)": { color: design_system_tokens_1.themeTokens.color.button.icon.primary, backgroundColor: design_system_tokens_1.themeTokens.color.button.background.primary.hover, }, "&:focus-visible": { color: design_system_tokens_1.themeTokens.color.button.icon.primary, backgroundColor: design_system_tokens_1.themeTokens.color.button.background.primary.hover, outline: `2px solid ${design_system_tokens_1.themeTokens.color.border.selected}`, outlineOffset: "2px", }, "&:disabled": { color: design_system_tokens_1.themeTokens.color.icon.secondary, backgroundColor: design_system_tokens_1.themeTokens.color.background.disabled, }, }, }), thumb: (0, css_1.css)({ flexShrink: 0, width: thumbSize, height: thumbSize, borderRadius: "50%", backgroundColor: design_system_tokens_1.themeTokens.color.background.primary.default, transition: "transform 150ms ease", }), thumbOn: (0, css_1.css)({ transform: `translateX(${thumbSlideDistance})`, }), // Icon is absolutely positioned so it doesn't participate in flex layout — // only the thumb does, keeping the Figma spacing correct. iconOff: (0, css_1.css)({ position: "absolute", top: "50%", right: design_system_tokens_1.space[4], transform: "translateY(-50%)", display: "flex", }), iconOn: (0, css_1.css)({ position: "absolute", top: "50%", left: design_system_tokens_1.space[4], transform: "translateY(-50%)", display: "flex", }), }; function useInputId(prefix) { const baseId = (0, react_1.useId)(); return `${prefix}${baseId}`; }