@octopusdeploy/design-system-components
Version:
The design systems component library.
108 lines (107 loc) • 5.63 kB
JavaScript
;
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}`;
}