@sap-ux/ui-components
Version:
SAP UI Components Library
452 lines • 19 kB
JavaScript
import React from 'react';
import { DefaultButton } from '@fluentui/react';
import { UIContextualMenu } from '../UIContextualMenu/index.js';
import { COMMON_INPUT_STYLES } from '../UIInput/index.js';
import { UiIcons } from '../Icons.js';
const VSCODE_BORDER_COLOR = 'var(--vscode-button-border, transparent)';
const VSCODE_SECONDARY_BORDER_COLOR = `var(--vscode-button-secondaryBorder, ${VSCODE_BORDER_COLOR})`;
export const BASE_STYLES = {
color: 'var(--vscode-button-foreground)',
checkedBorderColor: 'var(--vscode-contrastActiveBorder, var(--vscode-button-border, transparent))',
primary: {
backgroundColor: 'var(--vscode-button-background)',
disabledBorderColor: VSCODE_BORDER_COLOR,
borderColor: VSCODE_BORDER_COLOR,
hoverBackgroundColor: 'var(--vscode-button-hoverBackground)',
hoverBorderColor: VSCODE_BORDER_COLOR
},
secondary: {
backgroundColor: 'var(--vscode-button-secondaryBackground)',
disabledBorderColor: VSCODE_SECONDARY_BORDER_COLOR,
borderColor: VSCODE_SECONDARY_BORDER_COLOR,
hoverBackgroundColor: 'var(--vscode-button-secondaryHoverBackground)',
hoverBorderColor: VSCODE_SECONDARY_BORDER_COLOR,
color: 'var(--vscode-button-secondaryForeground)'
},
alert: {
backgroundColor: 'var(--vscode-errorForeground)',
disabledBorderColor: VSCODE_BORDER_COLOR,
borderColor: VSCODE_BORDER_COLOR,
hoverBackgroundColor: 'var(--vscode-editorError-foreground)',
hoverBorderColor: VSCODE_BORDER_COLOR
},
transparent: {
backgroundColor: 'transparent',
disabledBorderColor: 'transparent',
borderColor: 'transparent',
hoverBackgroundColor: 'var(--vscode-toolbar-hoverBackground, var(--vscode-menubar-selectionBackground))',
hoverBorderColor: 'var(--vscode-contrastActiveBorder, transparent)',
hoverBorderStyle: 'dashed',
color: 'var(--vscode-foreground)',
checkedBackgroundColor: 'var(--vscode-button-background)',
checkedColor: 'var(--vscode-button-foreground)',
checkedBorderStyle: 'solid'
},
height: 26
};
const ICON_SELECTOR = 'svg > path, svg > rect';
/**
* UIDefaultButton component
* based on https://developer.microsoft.com/en-us/fluentui#/controls/web/button
*
* @exports
* @class UIDefaultButton
* @extends {React.Component<UIDefaultButtonProps, {}>}
*/
export class UIDefaultButton extends React.Component {
/**
* Initializes component properties.
*
* @param {UIDefaultButtonProps} props
*/
constructor(props) {
super(props);
/**
* Method returns styles of root button element.
*
* @param props Button props.
* @returns Styles of root button element.
*/
this.setStyle = (props) => {
const { primary, alert, transparent } = props;
const dividerStyle = {
position: 'absolute',
width: 1,
right: BASE_STYLES.height - 1,
top: 0,
bottom: 0,
backgroundColor: 'var(--vscode-editor-background)'
};
const interactionStyles = {
root: this.getInteractionStyle(false, primary, alert, transparent),
checked: this.getInteractionStyle(true, primary, alert, transparent)
};
return {
root: {
minWidth: 'initial',
minHeight: BASE_STYLES.height,
height: BASE_STYLES.height,
fontSize: '13px',
fontWeight: 400,
borderRadius: COMMON_INPUT_STYLES.borderRadius,
paddingLeft: 13,
paddingRight: 13,
// Add to use hard coded value here as Theia doesn't support these values correctly
// as on Theia
// `--vscode-button-secondaryBackground` does not exist and is replaced by:
// `--vscode-secondaryButton-background` = #ffffff
// `--vscode-secondaryButton-foreground` does not exist
// And on VSCode `--vscode-button-secondaryForeground` exist and is equal to `#ffffff`
// So if we use the declare Theia variable `--vscode-secondaryButton-background` it will be white on white!!!
// And to finish these stuff of course Theia mess with the highContrast theme as it does not have any of them.
// Theia colors are a mess!!!!
backgroundColor: BASE_STYLES.secondary.backgroundColor,
borderColor: BASE_STYLES.secondary.borderColor,
color: BASE_STYLES.secondary.color,
...(primary && {
backgroundColor: BASE_STYLES.primary.backgroundColor,
borderColor: BASE_STYLES.primary.borderColor,
color: BASE_STYLES.color
}),
// alert button
...(alert && {
backgroundColor: BASE_STYLES.alert.backgroundColor,
borderColor: BASE_STYLES.alert.borderColor,
color: BASE_STYLES.color
}),
// Transparent button
...(transparent && {
backgroundColor: BASE_STYLES.transparent.backgroundColor,
borderColor: BASE_STYLES.transparent.borderColor,
color: BASE_STYLES.transparent.color
}),
selectors: {
'.ms-Fabric--isFocusVisible &:focus:after': {
outlineColor: 'var(--vscode-focusBorder)',
inset: -3
}
}
},
flexContainer: {
height: 18
},
label: {
marginLeft: 0,
marginRight: 0,
fontWeight: 400,
lineHeight: 20,
whiteSpace: 'nowrap'
},
rootDisabled: this.getRootDisabledStyles(primary, alert, transparent),
rootPressed: interactionStyles.root,
rootHovered: interactionStyles.root,
icon: this.getIconStyleOverrides(primary, alert, transparent),
menuIcon: this.getMenuIconStyleOverrides(primary, alert),
rootChecked: {
backgroundColor: BASE_STYLES.secondary.backgroundColor,
color: BASE_STYLES.secondary.color,
borderColor: BASE_STYLES.checkedBorderColor,
...(primary && {
backgroundColor: BASE_STYLES.primary.backgroundColor,
color: BASE_STYLES.color
}),
...(alert && {
backgroundColor: BASE_STYLES.alert.backgroundColor,
color: BASE_STYLES.color
}),
...(transparent && {
backgroundColor: BASE_STYLES.transparent.checkedBackgroundColor,
color: BASE_STYLES.transparent.checkedColor,
borderStyle: BASE_STYLES.transparent.checkedBorderStyle
})
},
rootCheckedHovered: interactionStyles.checked,
rootCheckedPressed: interactionStyles.checked,
splitButtonMenuButton: {
padding: 6,
minHeight: BASE_STYLES.height,
height: BASE_STYLES.height,
boxSizing: 'border-box',
borderRadius: `0 ${COMMON_INPUT_STYLES.borderRadius} ${COMMON_INPUT_STYLES.borderRadius} 0 !important`,
borderLeft: 'none',
outline: 'transparent',
userSelect: 'none',
display: 'inline-block',
textDecoration: 'none',
textAlign: 'center',
cursor: 'pointer',
verticalAlign: 'top',
// Split button should be square — width matches height
width: BASE_STYLES.height,
marginLeft: -1,
marginTop: 0,
marginRight: 0,
marginBottom: 0,
backgroundColor: BASE_STYLES.primary.backgroundColor,
borderColor: BASE_STYLES.primary.borderColor,
color: BASE_STYLES.color,
selectors: {
'&:hover': {
color: BASE_STYLES.color,
backgroundColor: 'var(--vscode-button-hoverBackground)',
borderColor: 'var(--vscode-contrastActiveBorder, var(--vscode-button-hoverBackground))',
selectors: {
[ICON_SELECTOR]: {
fill: BASE_STYLES.color
}
}
}
}
},
splitButtonMenuButtonDisabled: {
opacity: '0.5 !important',
// Add to use hard coded value here as Theia doesn't support these values correctly
backgroundColor: 'var(--vscode-button-secondaryBackground,#5f6a79)',
borderColor: BASE_STYLES.secondary.backgroundColor,
color: BASE_STYLES.secondary.color,
...(primary && {
color: BASE_STYLES.color,
backgroundColor: BASE_STYLES.primary.backgroundColor,
borderColor: 'var(--vscode-button-background)'
}),
...(alert && {
color: BASE_STYLES.color,
backgroundColor: BASE_STYLES.alert.backgroundColor,
borderColor: 'var(--vscode-button-background)'
})
},
splitButtonMenuFocused: {
selectors: {
'&:focus': {
color: 'red'
}
}
},
splitButtonMenuButtonExpanded: {
color: BASE_STYLES.color,
backgroundColor: 'var(--vscode-button-hoverBackground)',
borderColor: 'var(--vscode-contrastActiveBorder, var(--vscode-button-hoverBackground))',
selectors: {
[ICON_SELECTOR]: {
fill: BASE_STYLES.color
},
'&:hover': {
color: BASE_STYLES.color,
backgroundColor: 'var(--vscode-button-hoverBackground)',
borderColor: 'var(--vscode-contrastActiveBorder, var(--vscode-button-hoverBackground))',
selectors: {
[ICON_SELECTOR]: {
fill: BASE_STYLES.color
}
}
}
}
},
splitButtonDivider: dividerStyle,
splitButtonDividerDisabled: dividerStyle,
splitButtonContainerFocused: {
'.ms-Fabric--isFocusVisible &:focus:after': {
border: 'none',
outlineColor: 'var(--vscode-focusBorder)',
inset: -2
}
}
};
};
}
/**
* Method returns styles for hover and press States of root button element.
*
* @param checked Is styles for checked state.
* @param primary Is button primary.
* @param alert Is button alert.
* @param transparent Is button transparent.
* @returns Styles for hover and press States of root button element.
*/
getInteractionStyle(checked, primary, alert, transparent) {
let styles = {
color: BASE_STYLES.secondary.color,
backgroundColor: BASE_STYLES.secondary.hoverBackgroundColor,
borderColor: BASE_STYLES.secondary.hoverBorderColor,
selectors: {
[ICON_SELECTOR]: {
fill: BASE_STYLES.secondary.color
}
},
...(primary && {
color: BASE_STYLES.color,
backgroundColor: BASE_STYLES.primary.hoverBackgroundColor,
borderColor: BASE_STYLES.primary.hoverBorderColor,
selectors: {
[ICON_SELECTOR]: {
fill: BASE_STYLES.color
}
}
}),
...(alert && {
color: BASE_STYLES.color,
backgroundColor: BASE_STYLES.alert.hoverBackgroundColor,
borderColor: BASE_STYLES.alert.hoverBorderColor,
selectors: {
[ICON_SELECTOR]: {
fill: BASE_STYLES.color
}
}
}),
...(checked && {
borderColor: BASE_STYLES.checkedBorderColor
})
};
if (transparent) {
if (checked) {
styles = {
...styles,
color: BASE_STYLES.color,
backgroundColor: BASE_STYLES.primary.backgroundColor,
borderColor: BASE_STYLES.primary.borderColor,
selectors: {
[ICON_SELECTOR]: {
fill: BASE_STYLES.color
}
}
};
}
else {
styles = {
...styles,
color: BASE_STYLES.transparent.color,
backgroundColor: BASE_STYLES.transparent.hoverBackgroundColor,
borderColor: BASE_STYLES.transparent.hoverBorderColor,
borderStyle: BASE_STYLES.transparent.hoverBorderStyle,
selectors: {
[ICON_SELECTOR]: {
fill: BASE_STYLES.transparent.color
}
}
};
}
}
if (checked) {
styles = { ...styles, borderColor: BASE_STYLES.checkedBorderColor };
}
return styles;
}
/**
* Returns rootDisabled style overrides based on button variant.
*
* @param primary - primary button variant
* @param alert - alert button variant
* @param transparent - transparent button variant
* @returns IStyle
*/
getRootDisabledStyles(primary, alert, transparent) {
return {
opacity: '0.5 !important',
// Add to use hard coded value here as Theia doesn't support these values correctly
backgroundColor: BASE_STYLES.secondary.backgroundColor,
borderColor: BASE_STYLES.secondary.disabledBorderColor,
color: BASE_STYLES.secondary.color,
...(primary && {
opacity: '0.5 !important',
color: BASE_STYLES.color,
backgroundColor: BASE_STYLES.primary.backgroundColor,
borderColor: BASE_STYLES.primary.disabledBorderColor
}),
...(alert && {
opacity: '0.5 !important',
color: BASE_STYLES.color,
backgroundColor: BASE_STYLES.alert.backgroundColor,
borderColor: BASE_STYLES.alert.disabledBorderColor
}),
...(transparent && {
color: BASE_STYLES.transparent.color,
backgroundColor: BASE_STYLES.transparent.backgroundColor,
borderColor: BASE_STYLES.transparent.disabledBorderColor
})
};
}
/**
* Returns icon style overrides based on button variant.
*
* @param primary - primary button variant
* @param alert - alert button variant
* @param transparent - transparent button variant
* @returns IStyle
*/
getIconStyleOverrides(primary, alert, transparent) {
return {
height: 16,
lineHeight: 16,
marginLeft: -3,
color: BASE_STYLES.secondary.color,
selectors: {
[ICON_SELECTOR]: {
fill: BASE_STYLES.secondary.color
}
},
...(primary && {
color: BASE_STYLES.color,
selectors: {
[ICON_SELECTOR]: {
fill: BASE_STYLES.color
}
}
}),
...(alert && {
color: BASE_STYLES.color,
selectors: {
[ICON_SELECTOR]: {
fill: BASE_STYLES.color
}
}
}),
...(transparent && {
color: BASE_STYLES.transparent.color,
selectors: {
[ICON_SELECTOR]: {
fill: BASE_STYLES.transparent.color
}
}
})
};
}
/**
* Returns menuIcon style overrides based on button variant.
*
* @param primary - primary button variant
* @param alert - alert button variant
* @returns IStyle
*/
getMenuIconStyleOverrides(primary, alert) {
return {
selectors: {
'svg > path': {
fill: BASE_STYLES.secondary.color
},
...(primary && {
'svg > path': {
fill: BASE_STYLES.color
}
}),
...(alert && {
'svg > path': {
fill: BASE_STYLES.color
}
})
}
};
}
/**
* @returns {JSX.Element}
*/
render() {
const defaultMenuIconProps = this.props.menuProps?.items
? {
// Overwrite build-in fluentui icon
iconName: UiIcons.ArrowDown
}
: undefined;
return (React.createElement(DefaultButton, { menuIconProps: defaultMenuIconProps, ...this.props, styles: this.setStyle(this.props), menuAs: UIContextualMenu }));
}
}
//# sourceMappingURL=UIDefaultButton.js.map