refactor(Button): Upgrade Button component to Antd5 (#31623)
This commit is contained in:
parent
840a920aba
commit
9cd3a8d5b0
|
|
@ -106,7 +106,7 @@ export const databasesPage = {
|
|||
alertMessage: '.antd5-alert-message',
|
||||
errorField: '[role="alert"]',
|
||||
uploadJson: '[title="Upload JSON file"]',
|
||||
chooseFile: '[class="ant-btn input-upload-btn"]',
|
||||
chooseFile: '[class="antd5-btn input-upload-btn"]',
|
||||
additionalParameters: '[name="query_input"]',
|
||||
sqlAlchemyUriInput: dataTestLocator('sqlalchemy-uri-input'),
|
||||
advancedTab: '#rc-tabs-0-tab-2',
|
||||
|
|
@ -148,7 +148,7 @@ export const sqlLabView = {
|
|||
examplesMenuItem: '[title="examples"]',
|
||||
tableInput: ':nth-child(4) > .select > :nth-child(1)',
|
||||
sqlEditor: '#brace-editor textarea',
|
||||
saveAsButton: '.SaveQuery > .ant-btn',
|
||||
saveAsButton: '.SaveQuery > .antd5-btn',
|
||||
saveAsModal: {
|
||||
footer: '.antd5-modal-footer',
|
||||
queryNameInput: 'input[class^="ant-input"]',
|
||||
|
|
@ -195,7 +195,7 @@ export const savedQuery = {
|
|||
export const annotationLayersView = {
|
||||
emptyDescription: {
|
||||
description: '.ant-empty-description',
|
||||
addAnnotationLayerButton: '.ant-empty-footer > .ant-btn',
|
||||
addAnnotationLayerButton: '.ant-empty-footer > .antd5-btn',
|
||||
},
|
||||
modal: {
|
||||
content: {
|
||||
|
|
@ -434,7 +434,7 @@ export const dashboardListView = {
|
|||
newDashboardButton: '.css-yff34v',
|
||||
},
|
||||
importModal: {
|
||||
selectFileButton: '.ant-upload > .ant-btn > span',
|
||||
selectFileButton: '.ant-upload > .antd5-btn > span',
|
||||
importButton: dataTestLocator('modal-confirm-button'),
|
||||
},
|
||||
header: {
|
||||
|
|
@ -588,7 +588,7 @@ export const exploreView = {
|
|||
rowsContainer: dataTestLocator('table-content-rows'),
|
||||
},
|
||||
confirmModal: {
|
||||
okButton: '.antd5-modal-confirm-btns .ant-btn-primary',
|
||||
okButton: '.antd5-modal-confirm-btns .antd5-btn-primary',
|
||||
},
|
||||
},
|
||||
visualizationTypeModal: {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ const SaveDatasetActionButton = ({
|
|||
const StyledDropdownButton = styled(
|
||||
DropdownButton as FC<DropdownButtonProps>,
|
||||
)`
|
||||
&.ant-dropdown-button button.ant-btn.ant-btn-default {
|
||||
&.ant-dropdown-button button.antd5-btn.antd5-btn-default {
|
||||
font-weight: ${theme.gridUnit * 150};
|
||||
background-color: ${theme.colors.primary.light4};
|
||||
color: ${theme.colors.primary.dark1};
|
||||
|
|
|
|||
|
|
@ -26,10 +26,10 @@ import {
|
|||
|
||||
import { mix } from 'polished';
|
||||
import cx from 'classnames';
|
||||
import { Button as AntdButton } from 'antd';
|
||||
import { Button as AntdButton } from 'antd-v5';
|
||||
import { useTheme } from '@superset-ui/core';
|
||||
import { Tooltip, TooltipProps } from 'src/components/Tooltip';
|
||||
import { ButtonProps as AntdButtonProps } from 'antd/lib/button';
|
||||
import { ButtonProps as AntdButtonProps } from 'antd-v5/lib/button';
|
||||
|
||||
export type OnClickHandler = MouseEventHandler<HTMLElement>;
|
||||
|
||||
|
|
@ -56,6 +56,25 @@ export type ButtonProps = Omit<AntdButtonProps, 'css'> &
|
|||
showMarginRight?: boolean;
|
||||
};
|
||||
|
||||
const decideType = (buttonStyle: ButtonStyle) => {
|
||||
const typeMap: Record<
|
||||
ButtonStyle,
|
||||
'primary' | 'default' | 'dashed' | 'link'
|
||||
> = {
|
||||
primary: 'primary',
|
||||
danger: 'primary',
|
||||
warning: 'primary',
|
||||
success: 'primary',
|
||||
secondary: 'default',
|
||||
default: 'default',
|
||||
tertiary: 'dashed',
|
||||
dashed: 'dashed',
|
||||
link: 'link',
|
||||
};
|
||||
|
||||
return typeMap[buttonStyle];
|
||||
};
|
||||
|
||||
export default function Button(props: ButtonProps) {
|
||||
const {
|
||||
tooltip,
|
||||
|
|
@ -73,7 +92,7 @@ export default function Button(props: ButtonProps) {
|
|||
|
||||
const theme = useTheme();
|
||||
const { colors, transitionTiming, borderRadius, typography } = theme;
|
||||
const { primary, grayscale, success, warning, error } = colors;
|
||||
const { primary, grayscale, success, warning } = colors;
|
||||
|
||||
let height = 32;
|
||||
let padding = 18;
|
||||
|
|
@ -85,25 +104,19 @@ export default function Button(props: ButtonProps) {
|
|||
padding = 10;
|
||||
}
|
||||
|
||||
let backgroundColor = primary.light4;
|
||||
let backgroundColorHover = mix(0.1, primary.base, primary.light4);
|
||||
let backgroundColorActive = mix(0.25, primary.base, primary.light4);
|
||||
let backgroundColor;
|
||||
let backgroundColorHover;
|
||||
let backgroundColorActive;
|
||||
let backgroundColorDisabled = grayscale.light2;
|
||||
let color = primary.dark1;
|
||||
let colorHover = color;
|
||||
let color;
|
||||
let colorHover;
|
||||
let borderWidth = 0;
|
||||
let borderStyle = 'none';
|
||||
let borderColor = 'transparent';
|
||||
let borderColorHover = 'transparent';
|
||||
let borderColor;
|
||||
let borderColorHover;
|
||||
let borderColorDisabled = 'transparent';
|
||||
|
||||
if (buttonStyle === 'primary') {
|
||||
backgroundColor = primary.base;
|
||||
backgroundColorHover = primary.dark1;
|
||||
backgroundColorActive = mix(0.2, grayscale.dark2, primary.dark1);
|
||||
color = grayscale.light5;
|
||||
colorHover = color;
|
||||
} else if (buttonStyle === 'tertiary' || buttonStyle === 'dashed') {
|
||||
if (buttonStyle === 'tertiary' || buttonStyle === 'dashed') {
|
||||
backgroundColor = grayscale.light5;
|
||||
backgroundColorHover = grayscale.light5;
|
||||
backgroundColorActive = grayscale.light5;
|
||||
|
|
@ -114,10 +127,6 @@ export default function Button(props: ButtonProps) {
|
|||
borderColorHover = primary.light1;
|
||||
borderColorDisabled = grayscale.light2;
|
||||
} else if (buttonStyle === 'danger') {
|
||||
backgroundColor = error.base;
|
||||
backgroundColorHover = mix(0.1, grayscale.light5, error.base);
|
||||
backgroundColorActive = mix(0.2, grayscale.dark2, error.base);
|
||||
color = grayscale.light5;
|
||||
colorHover = color;
|
||||
} else if (buttonStyle === 'warning') {
|
||||
backgroundColor = warning.base;
|
||||
|
|
@ -135,7 +144,7 @@ export default function Button(props: ButtonProps) {
|
|||
backgroundColor = 'transparent';
|
||||
backgroundColorHover = 'transparent';
|
||||
backgroundColorActive = 'transparent';
|
||||
colorHover = primary.base;
|
||||
color = primary.dark1;
|
||||
}
|
||||
|
||||
const element = children as ReactElement;
|
||||
|
|
@ -149,10 +158,14 @@ export default function Button(props: ButtonProps) {
|
|||
const firstChildMargin =
|
||||
showMarginRight && renderedChildren.length > 1 ? theme.gridUnit * 2 : 0;
|
||||
|
||||
const effectiveButtonStyle: ButtonStyle = buttonStyle ?? 'default';
|
||||
|
||||
const button = (
|
||||
<AntdButton
|
||||
href={disabled ? undefined : href}
|
||||
disabled={disabled}
|
||||
type={decideType(effectiveButtonStyle)}
|
||||
danger={effectiveButtonStyle === 'danger'}
|
||||
className={cx(
|
||||
className,
|
||||
'superset-button',
|
||||
|
|
@ -179,12 +192,18 @@ export default function Button(props: ButtonProps) {
|
|||
borderColor,
|
||||
borderRadius,
|
||||
color,
|
||||
backgroundColor,
|
||||
'&:hover': {
|
||||
color: colorHover,
|
||||
backgroundColor: backgroundColorHover,
|
||||
borderColor: borderColorHover,
|
||||
background: backgroundColor,
|
||||
...(colorHover || backgroundColorHover || borderColorHover
|
||||
? {
|
||||
[`&.superset-button.superset-button-${buttonStyle}:hover`]: {
|
||||
...(colorHover && { color: colorHover }),
|
||||
...(backgroundColorHover && {
|
||||
background: backgroundColorHover,
|
||||
}),
|
||||
...(borderColorHover && { borderColor: borderColorHover }),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
'&:active': {
|
||||
color,
|
||||
backgroundColor: backgroundColorActive,
|
||||
|
|
@ -206,7 +225,7 @@ export default function Button(props: ButtonProps) {
|
|||
'& + .superset-button': {
|
||||
marginLeft: theme.gridUnit * 2,
|
||||
},
|
||||
'& > :first-of-type': {
|
||||
'& > span > :first-of-type': {
|
||||
marginRight: firstChildMargin,
|
||||
},
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ import { styled } from '@superset-ui/core';
|
|||
import { kebabCase } from 'lodash';
|
||||
|
||||
const StyledDropdownButton = styled.div`
|
||||
.ant-btn-group {
|
||||
button.ant-btn {
|
||||
.antd5-btn-group {
|
||||
button.antd5-btn {
|
||||
background-color: ${({ theme }) => theme.colors.primary.dark1};
|
||||
border-color: transparent;
|
||||
color: ${({ theme }) => theme.colors.grayscale.light5};
|
||||
|
|
|
|||
|
|
@ -41,10 +41,10 @@ export interface DropDownSelectableProps extends Pick<MenuProps, 'onSelect'> {
|
|||
}
|
||||
|
||||
const StyledDropdownButton = styled(DropdownButton as FC<DropdownButtonProps>)`
|
||||
button.ant-btn:first-of-type {
|
||||
button.antd5-btn:first-of-type {
|
||||
display: none;
|
||||
}
|
||||
> button.ant-btn:nth-of-type(2) {
|
||||
> button.antd5-btn:nth-of-type(2) {
|
||||
display: inline-flex;
|
||||
background-color: transparent !important;
|
||||
height: unset;
|
||||
|
|
|
|||
|
|
@ -17,8 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
import { styled } from '@superset-ui/core';
|
||||
import Button from 'src/components/Button';
|
||||
import { ButtonProps as AntdButtonProps } from 'antd/lib/button';
|
||||
import Button, { ButtonProps as AntdButtonProps } from 'src/components/Button';
|
||||
import Icons from 'src/components/Icons';
|
||||
import LinesEllipsis from 'react-lines-ellipsis';
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ export const menuTriggerStyles = (theme: SupersetTheme) => css`
|
|||
padding: 0;
|
||||
border: 1px solid ${theme.colors.primary.dark2};
|
||||
|
||||
&.ant-btn > span.anticon {
|
||||
&.antd5-btn > span.anticon {
|
||||
line-height: 0;
|
||||
transition: inherit;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ const AddButtonContainer = styled.div`
|
|||
padding-bottom: 1px;
|
||||
}
|
||||
|
||||
.ant-btn > .anticon + span {
|
||||
.antd5-btn > .anticon + span {
|
||||
margin-left: 0;
|
||||
}
|
||||
`}
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ export const MenuTrigger = styled(Button)`
|
|||
padding: 0;
|
||||
border: 1px solid ${theme.colors.primary.dark2};
|
||||
|
||||
&.ant-btn > span.anticon {
|
||||
&.antd5-btn > span.anticon {
|
||||
line-height: 0;
|
||||
transition: inherit;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -624,7 +624,7 @@ describe('DatabaseModal', () => {
|
|||
];
|
||||
|
||||
visibleComponents.forEach(component => {
|
||||
expect(component).toBeVisible();
|
||||
expect(component).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -781,7 +781,7 @@ describe('DatabaseModal', () => {
|
|||
enableRowExpansionCheckbox,
|
||||
];
|
||||
visibleComponents.forEach(component => {
|
||||
expect(component).toBeVisible();
|
||||
expect(component).toBeInTheDocument();
|
||||
});
|
||||
invisibleComponents.forEach(component => {
|
||||
expect(component).not.toBeVisible();
|
||||
|
|
@ -849,7 +849,7 @@ describe('DatabaseModal', () => {
|
|||
];
|
||||
|
||||
visibleComponents.forEach(component => {
|
||||
expect(component).toBeVisible();
|
||||
expect(component).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -929,7 +929,7 @@ describe('DatabaseModal', () => {
|
|||
|
||||
// ---------- Assertions ----------
|
||||
visibleComponents.forEach(component => {
|
||||
expect(component).toBeVisible();
|
||||
expect(component).toBeInTheDocument();
|
||||
});
|
||||
invisibleComponents.forEach(component => {
|
||||
expect(component).not.toBeVisible();
|
||||
|
|
@ -1137,7 +1137,7 @@ describe('DatabaseModal', () => {
|
|||
expect(await screen.findByText(/step 2 of 2/i)).toBeInTheDocument();
|
||||
const sqlAlchemyFormStepText = screen.getByText(/step 2 of 2/i);
|
||||
|
||||
expect(sqlAlchemyFormStepText).toBeVisible();
|
||||
expect(sqlAlchemyFormStepText).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe('SQL Alchemy form flow', () => {
|
||||
|
|
@ -1293,7 +1293,7 @@ describe('DatabaseModal', () => {
|
|||
|
||||
expect(await screen.findByText(/step 2 of 2/i)).toBeInTheDocument();
|
||||
const SSHTunnelingToggle = screen.getByTestId('ssh-tunnel-switch');
|
||||
expect(SSHTunnelingToggle).toBeVisible();
|
||||
expect(SSHTunnelingToggle).toBeInTheDocument();
|
||||
const SSHTunnelServerAddressInput = screen.queryByTestId(
|
||||
'ssh-tunnel-server_address-input',
|
||||
);
|
||||
|
|
@ -1325,26 +1325,26 @@ describe('DatabaseModal', () => {
|
|||
const SSHTunnelUsePasswordInput = screen.getByTestId(
|
||||
'ssh-tunnel-use_password-radio',
|
||||
);
|
||||
expect(SSHTunnelUsePasswordInput).toBeVisible();
|
||||
expect(SSHTunnelUsePasswordInput).toBeInTheDocument();
|
||||
const SSHTunnelUsePrivateKeyInput = screen.getByTestId(
|
||||
'ssh-tunnel-use_private_key-radio',
|
||||
);
|
||||
expect(SSHTunnelUsePrivateKeyInput).toBeVisible();
|
||||
expect(SSHTunnelUsePrivateKeyInput).toBeInTheDocument();
|
||||
const SSHTunnelPasswordInput = screen.getByTestId(
|
||||
'ssh-tunnel-password-input',
|
||||
);
|
||||
// By default, we use Password as login method
|
||||
expect(SSHTunnelPasswordInput).toBeVisible();
|
||||
expect(SSHTunnelPasswordInput).toBeInTheDocument();
|
||||
// Change the login method to use private key
|
||||
userEvent.click(SSHTunnelUsePrivateKeyInput);
|
||||
const SSHTunnelPrivateKeyInput = screen.getByTestId(
|
||||
'ssh-tunnel-private_key-input',
|
||||
);
|
||||
expect(SSHTunnelPrivateKeyInput).toBeVisible();
|
||||
expect(SSHTunnelPrivateKeyInput).toBeInTheDocument();
|
||||
const SSHTunnelPrivateKeyPasswordInput = screen.getByTestId(
|
||||
'ssh-tunnel-private_key_password-input',
|
||||
);
|
||||
expect(SSHTunnelPrivateKeyPasswordInput).toBeVisible();
|
||||
expect(SSHTunnelPrivateKeyPasswordInput).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ export const StyledLayoutFooter = styled.div`
|
|||
`;
|
||||
|
||||
export const HeaderComponentStyles = styled.div`
|
||||
.ant-btn {
|
||||
.antd5-btn {
|
||||
span {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
import { type ThemeConfig } from 'antd-v5';
|
||||
import { theme as supersetTheme } from 'src/preamble';
|
||||
import { mix } from 'polished';
|
||||
import { lightAlgorithm } from './light';
|
||||
|
||||
export enum ThemeType {
|
||||
|
|
@ -72,6 +73,45 @@ const baseConfig: ThemeConfig = {
|
|||
Badge: {
|
||||
paddingXS: supersetTheme.gridUnit * 2,
|
||||
},
|
||||
Button: {
|
||||
defaultBg: supersetTheme.colors.primary.light4,
|
||||
defaultHoverBg: mix(
|
||||
0.1,
|
||||
supersetTheme.colors.primary.base,
|
||||
supersetTheme.colors.primary.light4,
|
||||
),
|
||||
defaultActiveBg: mix(
|
||||
0.25,
|
||||
supersetTheme.colors.primary.base,
|
||||
supersetTheme.colors.primary.light4,
|
||||
),
|
||||
defaultColor: supersetTheme.colors.primary.dark1,
|
||||
defaultHoverColor: supersetTheme.colors.primary.dark1,
|
||||
defaultBorderColor: 'transparent',
|
||||
defaultHoverBorderColor: 'transparent',
|
||||
colorPrimaryHover: supersetTheme.colors.primary.dark1,
|
||||
colorPrimaryActive: mix(
|
||||
0.2,
|
||||
supersetTheme.colors.grayscale.dark2,
|
||||
supersetTheme.colors.primary.dark1,
|
||||
),
|
||||
primaryColor: supersetTheme.colors.grayscale.light5,
|
||||
colorPrimaryTextHover: supersetTheme.colors.grayscale.light5,
|
||||
colorError: supersetTheme.colors.error.base,
|
||||
colorErrorHover: mix(
|
||||
0.1,
|
||||
supersetTheme.colors.grayscale.light5,
|
||||
supersetTheme.colors.error.base,
|
||||
),
|
||||
colorErrorBg: mix(
|
||||
0.2,
|
||||
supersetTheme.colors.grayscale.dark2,
|
||||
supersetTheme.colors.error.base,
|
||||
),
|
||||
dangerColor: supersetTheme.colors.grayscale.light5,
|
||||
colorLinkHover: supersetTheme.colors.primary.base,
|
||||
linkHoverBg: 'transparent',
|
||||
},
|
||||
Card: {
|
||||
paddingLG: supersetTheme.gridUnit * 6,
|
||||
fontWeightStrong: supersetTheme.typography.weights.medium,
|
||||
|
|
|
|||
Loading…
Reference in New Issue