blob: 291b16efea14d7a27ec978c0077a481aa686b2a5 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { css, styled, useTheme } from '@apache-superset/core/ui';
// eslint-disable-next-line no-restricted-imports
import { Tabs as AntdTabs, TabsProps as AntdTabsProps } from 'antd';
import { Icons } from '@superset-ui/core/components/Icons';
import type { SerializedStyles } from '@emotion/react';
export interface TabsProps extends AntdTabsProps {
allowOverflow?: boolean;
fullHeight?: boolean;
contentStyle?: SerializedStyles;
}
const StyledTabs = ({
animated = false,
allowOverflow = true,
fullHeight = false,
tabBarStyle,
contentStyle,
...props
}: TabsProps) => {
const theme = useTheme();
const defaultTabBarStyle = { paddingLeft: theme.sizeUnit * 4 };
const mergedStyle = { ...defaultTabBarStyle, ...tabBarStyle };
return (
<AntdTabs
animated={animated}
{...props}
tabBarStyle={mergedStyle}
css={theme => css`
overflow: ${allowOverflow ? 'visible' : 'hidden'};
${fullHeight && 'height: 100%;'}
.ant-tabs-content-holder {
overflow: ${allowOverflow ? 'visible' : 'auto'};
${fullHeight && 'height: 100%;'}
}
.ant-tabs-content {
${fullHeight && 'height: 100%;'}
}
.ant-tabs-tabpane {
${fullHeight && 'height: 100%;'}
${contentStyle}
}
.ant-tabs-tab {
flex: 1 1 auto;
.short-link-trigger.btn {
padding: 0 ${theme.sizeUnit}px;
& > .fa.fa-link {
top: 0;
}
}
}
.ant-tabs-tab-btn {
display: flex;
flex: 1 1 auto;
align-items: center;
justify-content: center;
font-size: ${theme.fontSizeSM}px;
text-align: center;
user-select: none;
.required {
margin-left: ${theme.sizeUnit / 2}px;
color: ${theme.colorError};
}
&:focus-visible {
box-shadow: none;
}
}
`}
/>
);
};
const StyledTabPane = styled(AntdTabs.TabPane)``;
const Tabs = Object.assign(StyledTabs, {
TabPane: StyledTabPane,
});
const StyledEditableTabs = styled(StyledTabs)`
${({ theme, contentStyle }) => `
.ant-tabs-content-holder {
background: ${theme.colorBgContainer};
${contentStyle}
}
& > .ant-tabs-nav {
margin-bottom: 0;
}
.ant-tabs-tab-remove {
padding-top: 0;
padding-bottom: 0;
height: ${theme.sizeUnit * 6}px;
}
`}
`;
const StyledCloseOutlined = styled(Icons.CloseOutlined)`
color: ${({ theme }) => theme.colorIcon};
`;
export const EditableTabs = Object.assign(StyledEditableTabs, {
TabPane: StyledTabPane,
});
EditableTabs.defaultProps = {
type: 'editable-card',
animated: { inkBar: true, tabPane: false },
};
EditableTabs.TabPane.defaultProps = {
closeIcon: <StyledCloseOutlined iconSize="s" role="button" tabIndex={0} />,
};
export const StyledLineEditableTabs = styled(EditableTabs)`
&.ant-tabs-card > .ant-tabs-nav .ant-tabs-tab {
margin: 0 ${({ theme }) => theme.sizeUnit * 4}px;
padding: ${({ theme }) => `${theme.sizeUnit * 3}px ${theme.sizeUnit}px`};
background: transparent;
border: none;
}
&.ant-tabs-card > .ant-tabs-nav .ant-tabs-ink-bar {
visibility: visible;
}
.ant-tabs-tab-btn {
font-size: ${({ theme }) => theme.fontSize}px;
}
.ant-tabs-tab-remove {
margin-left: 0;
padding-right: 0;
}
.ant-tabs-nav-add {
min-width: unset !important;
background: transparent !important;
border: none !important;
}
`;
export const LineEditableTabs = Object.assign(StyledLineEditableTabs, {
TabPane: StyledTabPane,
});
export default Tabs;