UNPKG

@sap-ux/ui-components

Version:
275 lines 11.3 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.UIToggle = exports.UIToggleSize = void 0; const react_1 = __importDefault(require("react")); const react_dom_1 = __importDefault(require("react-dom")); const react_2 = require("@fluentui/react"); const ValidationMessage_1 = require("../../helper/ValidationMessage"); const UIIcon_1 = require("../UIIcon"); const Icons_1 = require("../Icons"); var UIToggleSize; (function (UIToggleSize) { UIToggleSize["Standard"] = "Standard"; UIToggleSize["Small"] = "Small"; })(UIToggleSize || (exports.UIToggleSize = UIToggleSize = {})); const TOGGLE_SIZE = { width: 30, height: 18, padding: '0 1px', margin: '0', label: { fontSize: 13, padding: '0px 0px 1px 0px' }, circle: { width: 14, height: 14, borderWidth: 1 } }; const ICON_STYLE = new Map([ [ true, { position: 'relative', top: -9, left: 0 } ], [ false, { position: 'relative', top: -11, left: 0 } ] ]); const DISABLED_OPACITY = 0.4; const COLORS = { pill: { unchecked: { background: 'var(--vscode-editorWidget-background)', borderColor: 'var(--vscode-editorWidget-border)', hover: { background: 'var(--vscode-editorWidget-background)', borderColor: 'var(--vscode-editorWidget-border)' } }, checked: { background: 'var(--vscode-editorWidget-background)', borderColor: 'var(--vscode-contrastActiveBorder, var(--vscode-editorWidget-border))', hover: { background: 'var(--vscode-editorWidget-background)', borderColor: 'var(--vscode-contrastActiveBorder, var(--vscode-editorWidget-border))' } }, focus: { outline: '1px solid var(--vscode-focusBorder) !important' } }, thumb: { unchecked: { background: 'var(--vscode-button-secondaryBackground)', borderColor: 'var(--vscode-button-border, transparent)', hover: { borderColor: 'var(--vscode-button-border, transparent)', background: 'var(--vscode-contrastBorder, var(--vscode-button-secondaryHoverBackground))' } }, checked: { background: 'var(--vscode-button-background)', borderColor: 'var(--vscode-contrastActiveBorder, var(--vscode-button-border, transparent))', hover: { borderColor: 'var(--vscode-contrastActiveBorder, var(--vscode-button-border, transparent))', background: 'var(--vscode-contrastActiveBorder, var(--vscode-button-hoverBackground))' } } } }; /** * UIToggle component. * based on https://developer.microsoft.com/en-us/fluentui#/controls/web/toggle * * @exports * @class UIToggle * @extends {React.Component<IToggleProps, {}>} */ class UIToggle extends react_1.default.Component { /** * Initializes component properties. * * @param {UIToggleProps} props */ constructor(props) { super(props); this.toggleRootRef = react_1.default.createRef(); this.handleChange = this.handleChange.bind(this); this.replaceThumbWithIcon = this.replaceThumbWithIcon.bind(this); } /** * Lifecycle method called immediately after a component is mounted. * Executes initialization logic such as DOM manipulations or fetching data. * * @returns {void} This method does not return a value. */ componentDidMount() { this.replaceThumbWithIcon(this.props.checked ?? this.props.defaultChecked); } /** * Determines whether the component should update when the new props are received. * This method is typically used for performance optimization. * * @param {UIToggleProps} nextProps - The next props to be received by the component. * @returns {boolean} A boolean value indicating whether the component should update. */ shouldComponentUpdate(nextProps) { if (nextProps.checked !== this.props.checked) { this.replaceThumbWithIcon(nextProps.checked); } return true; } /** * Handles the change event triggered by the user interaction. * * @param {React.MouseEvent<HTMLElement>} event - The mouse event object associated with the interaction. * @param {boolean} [checked] - An optional parameter indicating the current state of the interaction. * @returns {void} This method does not return a value. */ handleChange(event, checked) { this.replaceThumbWithIcon(checked); this.props.onChange?.(event, checked); } /** * Replaces the thumb element of a toggle switch with an icon based on the toggle's state. * * @param {boolean} [checked] Optional. Represents the state of the toggle switch. If not provided, it checks `defaultChecked` prop or defaults to `false`. * @returns {void} Does not return a value. */ replaceThumbWithIcon(checked = false) { if (this.toggleRootRef.current) { const thumbElement = this.toggleRootRef.current?.querySelector('.ms-Toggle-thumb'); if (thumbElement) { const style = ICON_STYLE.get(checked); react_dom_1.default.render(react_1.default.createElement(UIIcon_1.UIIcon, { iconName: checked ? Icons_1.UiIcons.SwitchOn : Icons_1.UiIcons.SwitchOff, style: style }), thumbElement); } } } /** * Method returns size of margin bottom for root container depending on current props state. * * @param {string} [message] Validation message. * @returns {number | undefined} Value for margin bottom. */ getMarginBottom(message) { const { inlineLabel } = this.props; if (message) { return inlineLabel ? 0 : 4; } return undefined; } /** * @returns {JSX.Element} */ render() { const { inlineLabelLeft, labelFlexGrow, inlineLabel } = this.props; const sizeInfo = TOGGLE_SIZE; const messageInfo = (0, ValidationMessage_1.getMessageInfo)(this.props); const styles = (styleProps) => { return { root: { ...(labelFlexGrow && { flexGrow: 1, justifyContent: 'space-between' }), margin: sizeInfo?.margin, marginBottom: this.getMarginBottom(messageInfo.message) }, label: { color: 'var(--vscode-foreground)', fontWeight: 'normal', fontSize: sizeInfo?.label.fontSize, padding: sizeInfo?.label.padding, ...(inlineLabel && { marginLeft: 10 }), ...(inlineLabelLeft && { order: 0, marginLeft: 0, marginRight: 10 }), opacity: this.props.disabled ? DISABLED_OPACITY : 'inherit' }, pill: { height: sizeInfo?.height, width: sizeInfo?.width, padding: sizeInfo?.padding, background: COLORS.pill.checked.background, borderColor: COLORS.pill.checked.borderColor, borderStyle: 'solid', ':hover .ms-Toggle-thumb': { background: COLORS.thumb.checked.hover.background, borderColor: COLORS.thumb.checked.hover.borderColor }, ':hover': { background: COLORS.pill.checked.hover.background, borderColor: COLORS.pill.checked.hover.borderColor }, ':disabled': { background: COLORS.pill.checked.background, borderColor: COLORS.pill.checked.borderColor, opacity: DISABLED_OPACITY }, ...(!styleProps.checked && { background: COLORS.pill.unchecked.background, borderColor: COLORS.pill.unchecked.borderColor, borderStyle: 'solid', // This is a bug: the best implementation approach is to set hover styles in the "thumb" section. // However, the hover styles for the unchecked thumb don't work properly ':hover .ms-Toggle-thumb': { background: COLORS.thumb.unchecked.hover.background, borderColor: COLORS.thumb.unchecked.hover.borderColor }, ':hover': { background: COLORS.pill.unchecked.hover.background, borderColor: COLORS.pill.unchecked.hover.borderColor }, ':disabled': { background: COLORS.pill.unchecked.background, borderColor: COLORS.pill.unchecked.borderColor, opacity: DISABLED_OPACITY } }), selectors: { ':focus::after': { // Overwrite flunt ui focus borders border: 'none !important', outline: COLORS.pill.focus.outline } } }, thumb: { height: sizeInfo?.circle.height, width: sizeInfo?.circle.width, borderWidth: sizeInfo?.circle.borderWidth, backgroundPosition: 'center', borderColor: COLORS.thumb.checked.borderColor, backgroundColor: COLORS.thumb.checked.background, ':hover': { background: COLORS.thumb.checked.hover.background, borderColor: COLORS.thumb.checked.hover.borderColor }, ...(!styleProps.checked && { borderColor: COLORS.thumb.unchecked.borderColor, backgroundColor: COLORS.thumb.unchecked.background }) } }; }; const toggleComponent = (react_1.default.createElement(react_2.Toggle, { ...this.props, styles: styles, ref: this.toggleRootRef, onChange: this.handleChange })); return messageInfo.message ? (react_1.default.createElement(ValidationMessage_1.MessageWrapper, { message: messageInfo }, toggleComponent)) : (toggleComponent); } } exports.UIToggle = UIToggle; //# sourceMappingURL=UIToggle.js.map