@sap-ux/ui-components
Version:
SAP UI Components Library
275 lines • 11.3 kB
JavaScript
"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