Merge branch 'release' of https://github.com/appsmithorg/appsmith into release
This commit is contained in:
commit
b8d1d56310
|
|
@ -1,108 +1,3 @@
|
||||||
import React from "react";
|
import { CommonComponentProps } from "./common";
|
||||||
import { Tab, Tabs, TabList, TabPanel } from "react-tabs";
|
|
||||||
import "react-tabs/style/react-tabs.css";
|
|
||||||
import styled from "styled-components";
|
|
||||||
import { Icon, IconName } from "./Icon";
|
|
||||||
import { Size } from "./Button";
|
|
||||||
|
|
||||||
const TabsWrapper = styled.div<{ shouldOverflow?: boolean }>`
|
// Create a wrapper around react-tabs
|
||||||
font-family: ${props => props.theme.fonts.main};
|
|
||||||
user-select: none;
|
|
||||||
border-radius: 0px;
|
|
||||||
height: 100%;
|
|
||||||
span {
|
|
||||||
margin-right: ${props => props.theme.spaces[2] - 1}px;
|
|
||||||
}
|
|
||||||
.react-tabs {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
.react-tabs__tab-panel {
|
|
||||||
height: calc(100% - 32px);
|
|
||||||
overflow: scroll;
|
|
||||||
}
|
|
||||||
.react-tabs__tab-list {
|
|
||||||
border-bottom: 2px solid ${props => props.theme.colors.blackShades[3]};
|
|
||||||
color: ${props => props.theme.colors.blackShades[6]};
|
|
||||||
${props =>
|
|
||||||
props.shouldOverflow &&
|
|
||||||
`
|
|
||||||
overflow-y: hidden;
|
|
||||||
overflow-x: auto;
|
|
||||||
white-space: nowrap;
|
|
||||||
`}
|
|
||||||
}
|
|
||||||
.react-tabs__tab {
|
|
||||||
padding: ${props => props.theme.space[7]}px 0;
|
|
||||||
margin-right: ${props => props.theme.space[15]}px;
|
|
||||||
text-align: center;
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
.react-tabs__tab:hover {
|
|
||||||
color: ${props => props.theme.colors.blackShades[9]};
|
|
||||||
path {
|
|
||||||
fill: ${props => props.theme.colors.blackShades[9]};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.react-tabs__tab:focus {
|
|
||||||
box-shadow: none;
|
|
||||||
border-bottom: ${props => props.theme.colors.info.main}
|
|
||||||
${props => props.theme.space[16]}px solid;
|
|
||||||
path {
|
|
||||||
fill: ${props => props.theme.colors.blackShades[9]};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.react-tabs__tab--selected {
|
|
||||||
color: ${props => props.theme.colors.blackShades[9]};
|
|
||||||
border: 0px solid;
|
|
||||||
border-bottom: ${props => props.theme.colors.info.main}
|
|
||||||
${props => props.theme.space[16]}px solid;
|
|
||||||
background-color: transparent;
|
|
||||||
path {
|
|
||||||
fill: ${props => props.theme.colors.blackShades[9]};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.react-tabs__tab:focus:after {
|
|
||||||
content: none;
|
|
||||||
height: ${props => props.theme.space[16]}px;
|
|
||||||
background: ${props => props.theme.colors.info.main};
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
type TabbedViewComponentType = {
|
|
||||||
tabs: Array<{
|
|
||||||
key: string;
|
|
||||||
title: string;
|
|
||||||
panelComponent: JSX.Element;
|
|
||||||
icon?: IconName;
|
|
||||||
}>;
|
|
||||||
selectedIndex?: number;
|
|
||||||
setSelectedIndex?: Function;
|
|
||||||
overflow?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const AdsTabComponent = (props: TabbedViewComponentType) => {
|
|
||||||
return (
|
|
||||||
<TabsWrapper shouldOverflow={props.overflow}>
|
|
||||||
<Tabs
|
|
||||||
selectedIndex={props.selectedIndex}
|
|
||||||
onSelect={(index: number) => {
|
|
||||||
props.setSelectedIndex && props.setSelectedIndex(index);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<TabList>
|
|
||||||
{props.tabs.map(tab => (
|
|
||||||
<Tab key={tab.key}>
|
|
||||||
{tab.icon ? <Icon name={tab.icon} size={Size.large} /> : null}
|
|
||||||
{tab.title}
|
|
||||||
</Tab>
|
|
||||||
))}
|
|
||||||
</TabList>
|
|
||||||
{props.tabs.map(tab => (
|
|
||||||
<TabPanel key={tab.key}>{tab.panelComponent}</TabPanel>
|
|
||||||
))}
|
|
||||||
</Tabs>
|
|
||||||
</TabsWrapper>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,7 @@ const StyledText = styled.div<TabProps>`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const TabsComponent = (props: TabsComponentProps) => {
|
const TabsComponent = (props: TabsComponentProps) => {
|
||||||
|
const { onTabChange, ...remainingProps } = props;
|
||||||
const tabContainerRef: RefObject<HTMLDivElement> = useRef<HTMLDivElement>(
|
const tabContainerRef: RefObject<HTMLDivElement> = useRef<HTMLDivElement>(
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
|
|
@ -135,7 +136,7 @@ const TabsComponent = (props: TabsComponentProps) => {
|
||||||
)}
|
)}
|
||||||
<ChildrenWrapper>
|
<ChildrenWrapper>
|
||||||
<ScrollableCanvasWrapper
|
<ScrollableCanvasWrapper
|
||||||
{...props}
|
{...remainingProps}
|
||||||
className={`${
|
className={`${
|
||||||
props.shouldScrollContents ? getCanvasClassName() : ""
|
props.shouldScrollContents ? getCanvasClassName() : ""
|
||||||
} ${generateClassName(props.widgetId)}`}
|
} ${generateClassName(props.widgetId)}`}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import { ControlIcons } from "icons/ControlIcons";
|
||||||
import { AnyStyledComponent } from "styled-components";
|
import { AnyStyledComponent } from "styled-components";
|
||||||
import { generateReactKey } from "utils/generators";
|
import { generateReactKey } from "utils/generators";
|
||||||
import { DroppableComponent } from "../designSystems/appsmith/DraggableListComponent";
|
import { DroppableComponent } from "../designSystems/appsmith/DraggableListComponent";
|
||||||
|
import { getNextEntityName } from "utils/AppsmithUtils";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
|
|
||||||
const StyledDeleteIcon = styled(FormIcons.DELETE_ICON as AnyStyledComponent)`
|
const StyledDeleteIcon = styled(FormIcons.DELETE_ICON as AnyStyledComponent)`
|
||||||
|
|
@ -161,7 +162,11 @@ class TabControl extends BaseControl<ControlProps> {
|
||||||
? JSON.parse(this.props.propertyValue)
|
? JSON.parse(this.props.propertyValue)
|
||||||
: this.props.propertyValue;
|
: this.props.propertyValue;
|
||||||
const newTabId = generateReactKey({ prefix: "tab" });
|
const newTabId = generateReactKey({ prefix: "tab" });
|
||||||
tabs.push({ id: newTabId, label: `Tab ${tabs.length + 1}` });
|
const newTabLabel = getNextEntityName(
|
||||||
|
"Tab ",
|
||||||
|
tabs.map(tab => tab.label),
|
||||||
|
);
|
||||||
|
tabs.push({ id: newTabId, label: newTabLabel });
|
||||||
this.updateProperty(this.props.propertyName, JSON.stringify(tabs));
|
this.updateProperty(this.props.propertyName, JSON.stringify(tabs));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
import { AdsTabComponent } from "components/ads/Tabs";
|
|
||||||
import { withKnobs } from "@storybook/addon-knobs";
|
|
||||||
import { withDesign } from "storybook-addon-designs";
|
|
||||||
import { ThemeProvider } from "styled-components";
|
|
||||||
import { adsTheme } from "../ads/baseTheme";
|
|
||||||
import { IconName } from "../ads/Icon";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
title: "tabs",
|
|
||||||
component: AdsTabComponent,
|
|
||||||
decorators: [withKnobs, withDesign],
|
|
||||||
};
|
|
||||||
|
|
||||||
type tabSingle = {
|
|
||||||
key: string;
|
|
||||||
title: string;
|
|
||||||
panelComponent: JSX.Element;
|
|
||||||
icon: IconName;
|
|
||||||
};
|
|
||||||
|
|
||||||
const tabArr: tabSingle[] = [
|
|
||||||
{
|
|
||||||
key: "r",
|
|
||||||
title: "Tab one",
|
|
||||||
panelComponent: (
|
|
||||||
<div
|
|
||||||
style={{ backgroundColor: "#CB4810", width: "100%", height: "100%" }}
|
|
||||||
></div>
|
|
||||||
),
|
|
||||||
icon: "delete",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "r",
|
|
||||||
title: "Tab two",
|
|
||||||
panelComponent: (
|
|
||||||
<div
|
|
||||||
style={{ backgroundColor: "#218358", width: "100%", height: "100%" }}
|
|
||||||
></div>
|
|
||||||
),
|
|
||||||
icon: "delete",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "r",
|
|
||||||
title: "Tab three",
|
|
||||||
panelComponent: (
|
|
||||||
<div
|
|
||||||
style={{ backgroundColor: "#457AE6", width: "100%", height: "100%" }}
|
|
||||||
></div>
|
|
||||||
),
|
|
||||||
icon: "delete",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export const withDynamicProps = () => (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
width: "100%",
|
|
||||||
height: "600px",
|
|
||||||
backgroundColor: "#1A191C",
|
|
||||||
padding: "100px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ThemeProvider theme={adsTheme}>
|
|
||||||
<AdsTabComponent tabs={tabArr}></AdsTabComponent>
|
|
||||||
</ThemeProvider>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
@ -8,6 +8,7 @@ import { WidgetPropertyValidationType } from "utils/ValidationFactory";
|
||||||
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { EventType } from "constants/ActionConstants";
|
import { EventType } from "constants/ActionConstants";
|
||||||
|
import { WidgetOperations } from "widgets/BaseWidget";
|
||||||
|
|
||||||
class TabsWidget extends BaseWidget<
|
class TabsWidget extends BaseWidget<
|
||||||
TabsWidgetProps<TabContainerWidgetProps>,
|
TabsWidgetProps<TabContainerWidgetProps>,
|
||||||
|
|
@ -60,21 +61,26 @@ class TabsWidget extends BaseWidget<
|
||||||
|
|
||||||
renderComponent = () => {
|
renderComponent = () => {
|
||||||
const selectedTabId = this.props.selectedTabId;
|
const selectedTabId = this.props.selectedTabId;
|
||||||
const children = this.props.children.filter(item => {
|
const childWidgetData: TabContainerWidgetProps = this.props.children.filter(
|
||||||
|
item => {
|
||||||
return selectedTabId === item.tabId;
|
return selectedTabId === item.tabId;
|
||||||
})[0];
|
},
|
||||||
const childWidgetData: TabContainerWidgetProps = children;
|
)[0];
|
||||||
|
|
||||||
if (!childWidgetData) {
|
if (!childWidgetData) {
|
||||||
return <div></div>;
|
return null;
|
||||||
}
|
}
|
||||||
childWidgetData.shouldScrollContents = false;
|
childWidgetData.shouldScrollContents = false;
|
||||||
childWidgetData.canExtend = this.props.shouldScrollContents;
|
childWidgetData.canExtend = this.props.shouldScrollContents;
|
||||||
const { componentWidth, componentHeight } = this.getComponentDimensions();
|
const { componentWidth, componentHeight } = this.getComponentDimensions();
|
||||||
childWidgetData.rightColumn = componentWidth;
|
childWidgetData.rightColumn = componentWidth;
|
||||||
|
childWidgetData.isVisible = this.props.isVisible;
|
||||||
childWidgetData.bottomRow = this.props.shouldScrollContents
|
childWidgetData.bottomRow = this.props.shouldScrollContents
|
||||||
? (this.props.bottomRow - this.props.topRow - 1) *
|
? childWidgetData.bottomRow
|
||||||
this.props.parentRowSpace
|
: componentHeight - 1;
|
||||||
: componentHeight;
|
childWidgetData.parentId = this.props.widgetId;
|
||||||
|
childWidgetData.minHeight = componentHeight;
|
||||||
|
|
||||||
return WidgetFactory.createWidget(childWidgetData, this.props.renderMode);
|
return WidgetFactory.createWidget(childWidgetData, this.props.renderMode);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -117,11 +123,12 @@ class TabsWidget extends BaseWidget<
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
this.updateWidget("ADD_CHILD", this.props.widgetId, config);
|
this.updateWidget(WidgetOperations.ADD_CHILD, this.props.widgetId, config);
|
||||||
};
|
};
|
||||||
|
|
||||||
removeTabContainer = () => {
|
removeTabContainer = () => {
|
||||||
let removedContainerWidgetId = "";
|
let removedContainerWidgetId = "";
|
||||||
|
let removedTabId = "";
|
||||||
const tabIds: string[] = this.props.tabs.map(tab => {
|
const tabIds: string[] = this.props.tabs.map(tab => {
|
||||||
return tab.id;
|
return tab.id;
|
||||||
});
|
});
|
||||||
|
|
@ -129,9 +136,22 @@ class TabsWidget extends BaseWidget<
|
||||||
const children = this.props.children[index];
|
const children = this.props.children[index];
|
||||||
if (!tabIds.includes(children.tabId)) {
|
if (!tabIds.includes(children.tabId)) {
|
||||||
removedContainerWidgetId = children.widgetId;
|
removedContainerWidgetId = children.widgetId;
|
||||||
|
removedTabId = children.tabId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.updateWidget("REMOVE_CHILD", removedContainerWidgetId, {
|
/* Selecting first tab as default tab when no tab is selected */
|
||||||
|
if (
|
||||||
|
this.props.tabs.length > 1 &&
|
||||||
|
removedTabId === this.props.selectedTabId
|
||||||
|
) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.updateWidgetProperty(
|
||||||
|
"defaultTab",
|
||||||
|
this.props.tabs.filter(tab => tab.id !== removedTabId)[0].label,
|
||||||
|
);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
this.updateWidget(WidgetOperations.DELETE, removedContainerWidgetId, {
|
||||||
parentId: this.props.widgetId,
|
parentId: this.props.widgetId,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user