diff --git a/app/client/src/assets/icons/control/drag.svg b/app/client/src/assets/icons/control/drag.svg
new file mode 100644
index 0000000000..a432baa4a2
--- /dev/null
+++ b/app/client/src/assets/icons/control/drag.svg
@@ -0,0 +1,3 @@
+
diff --git a/app/client/src/components/designSystems/appsmith/Table.tsx b/app/client/src/components/designSystems/appsmith/Table.tsx
index 68da25e7e4..95dcef8f5c 100644
--- a/app/client/src/components/designSystems/appsmith/Table.tsx
+++ b/app/client/src/components/designSystems/appsmith/Table.tsx
@@ -69,7 +69,7 @@ export const Table = (props: TableProps) => {
const data = React.useMemo(() => props.data, [JSON.stringify(props.data)]);
const columns = React.useMemo(() => props.columns, [
JSON.stringify(props.columns),
- props.columnActions,
+ JSON.stringify(props.columnActions),
]);
const {
getTableProps,
diff --git a/app/client/src/components/designSystems/appsmith/TabsComponent.tsx b/app/client/src/components/designSystems/appsmith/TabsComponent.tsx
index 069febc174..5ba211dec0 100644
--- a/app/client/src/components/designSystems/appsmith/TabsComponent.tsx
+++ b/app/client/src/components/designSystems/appsmith/TabsComponent.tsx
@@ -3,6 +3,7 @@ import styled, { css } from "styled-components";
import { ComponentProps } from "./BaseComponent";
import { TabsWidgetProps, TabContainerWidgetProps } from "widgets/TabsWidget";
import { generateClassName, getCanvasClassName } from "utils/generators";
+import { scrollbarLight } from "constants/DefaultTheme";
interface TabsComponentProps extends ComponentProps {
children?: ReactNode;
@@ -53,8 +54,13 @@ const ScrollableCanvasWrapper = styled.div<
`;
const TabsContainer = styled.div`
+ width: 100%;
+ overflow-x: auto;
+ overflow-y: hidden;
+ ${scrollbarLight};
+ background: ${props => props.theme.colors.builderBodyBG};
&& {
- height: 32px;
+ height: 38px;
width: 100%;
display: flex;
justify-content: flex-start;
diff --git a/app/client/src/components/propertyControls/TabControl.tsx b/app/client/src/components/propertyControls/TabControl.tsx
index 97197ef6ff..1b180b8fdd 100644
--- a/app/client/src/components/propertyControls/TabControl.tsx
+++ b/app/client/src/components/propertyControls/TabControl.tsx
@@ -16,12 +16,10 @@ const StyledDeleteIcon = styled(FormIcons.DELETE_ICON as AnyStyledComponent)`
cursor: pointer;
`;
-const StyledDragIcon = styled(
- ControlIcons.DRAGGABLE_CONTROL as AnyStyledComponent,
-)`
+const StyledDragIcon = styled(ControlIcons.DRAG_CONTROL as AnyStyledComponent)`
padding: 0;
position: relative;
- margin-left: 15px;
+ margin-right: 15px;
cursor: move;
svg {
path {
@@ -40,6 +38,7 @@ const StyledPropertyPaneButtonWrapper = styled.div`
const ItemWrapper = styled.div`
display: flex;
justify-content: flex-start;
+ align-items: center;
`;
const TabsWrapper = styled.div`
@@ -77,6 +76,7 @@ function TabControlComponent(props: RenderComponentProps) {
const { deleteOption, updateOption, item, index } = props;
return (
+
-
);
}
diff --git a/app/client/src/constants/DefaultTheme.tsx b/app/client/src/constants/DefaultTheme.tsx
index 8805865b53..a3c316b48b 100644
--- a/app/client/src/constants/DefaultTheme.tsx
+++ b/app/client/src/constants/DefaultTheme.tsx
@@ -564,5 +564,23 @@ export const theme: Theme = {
},
};
+export const scrollbarLight = css`
+ scrollbar-color: ${props => props.theme.colors.paneText}
+
+ scrollbar-width: thin;
+ &::-webkit-scrollbar {
+ width: 6px;
+ height: 6px;
+ }
+ &::-webkit-scrollbar-track {
+ box-shadow: inset 0 0 6px
+ ${props => getColorWithOpacity(props.theme.colors.paneText, 0.3)};
+ }
+ &::-webkit-scrollbar-thumb {
+ background-color: ${props => props.theme.colors.paneText};
+ border-radius: ${props => props.theme.radii[1]}px;
+ }
+`;
+
export { css, createGlobalStyle, keyframes, ThemeProvider };
export default styled;
diff --git a/app/client/src/constants/WidgetValidation.ts b/app/client/src/constants/WidgetValidation.ts
index 8dbc8b9ef0..9741656714 100644
--- a/app/client/src/constants/WidgetValidation.ts
+++ b/app/client/src/constants/WidgetValidation.ts
@@ -17,6 +17,7 @@ export const VALIDATION_TYPES = {
MARKERS: "MARKERS",
ACTION_SELECTOR: "ACTION_SELECTOR",
ARRAY_ACTION_SELECTOR: "ARRAY_ACTION_SELECTOR",
+ SELECTED_TAB: "SELECTED_TAB",
};
export type ValidationResponse = {
diff --git a/app/client/src/icons/ControlIcons.tsx b/app/client/src/icons/ControlIcons.tsx
index ddcd8199eb..455025cb07 100644
--- a/app/client/src/icons/ControlIcons.tsx
+++ b/app/client/src/icons/ControlIcons.tsx
@@ -15,6 +15,7 @@ import { ReactComponent as HelpIcon } from "assets/icons/control/help.svg";
import { ReactComponent as PickMyLocationSelectedIcon } from "assets/icons/control/pick-location-selected.svg";
import { ReactComponent as SettingsIcon } from "assets/icons/control/settings.svg";
+import { ReactComponent as DragIcon } from "assets/icons/control/drag.svg";
import PlayIcon from "assets/icons/control/play-icon.png";
/* eslint-disable react/display-name */
@@ -101,6 +102,11 @@ export const ControlIcons: {
/>
),
+ DRAG_CONTROL: (props: IconProps) => (
+
+
+
+ ),
};
export type ControlIconName = keyof typeof ControlIcons;
diff --git a/app/client/src/utils/Validators.ts b/app/client/src/utils/Validators.ts
index 3a1568c709..6bfbc6d4d3 100644
--- a/app/client/src/utils/Validators.ts
+++ b/app/client/src/utils/Validators.ts
@@ -499,4 +499,25 @@ export const VALIDATORS: Record = {
message: message,
};
},
+ [VALIDATION_TYPES.SELECTED_TAB]: (
+ value: any,
+ props: WidgetProps,
+ dataTree?: DataTree,
+ ): ValidationResponse => {
+ const tabs =
+ props.tabs && _.isString(props.tabs)
+ ? JSON.parse(props.tabs)
+ : props.tabs && Array.isArray(props.tabs)
+ ? props.tabs
+ : [];
+ const tabNames = tabs.map((i: { label: string; id: string }) => i.label);
+ const isValidTabName = tabNames.includes(value);
+ return {
+ isValid: isValidTabName,
+ parsed: value,
+ message: isValidTabName
+ ? ""
+ : `${WIDGET_TYPE_VALIDATION_ERROR}: Invalid tab name.`,
+ };
+ },
};
diff --git a/app/client/src/widgets/TabsWidget.tsx b/app/client/src/widgets/TabsWidget.tsx
index f52729f49e..1f10f6587a 100644
--- a/app/client/src/widgets/TabsWidget.tsx
+++ b/app/client/src/widgets/TabsWidget.tsx
@@ -14,6 +14,7 @@ class TabsWidget extends BaseWidget<
static getPropertyValidationMap(): WidgetPropertyValidationType {
return {
tabs: VALIDATION_TYPES.TABS_DATA,
+ selectedTab: VALIDATION_TYPES.SELECTED_TAB,
};
}