diff --git a/packages/xod-client/src/core/styles/components/Sidebar.scss b/packages/xod-client/src/core/styles/components/Sidebar.scss
index 90e0c8bd3..9ce55ccff 100644
--- a/packages/xod-client/src/core/styles/components/Sidebar.scss
+++ b/packages/xod-client/src/core/styles/components/Sidebar.scss
@@ -27,7 +27,7 @@
}
.Sidebar-title {
- display: block;
+ display: flex;
height: 28px;
margin: 0;
background: $sidebar-color-bg;
@@ -43,11 +43,9 @@
height: 28px;
&.Sidebar-title--left {
- float: left;
border-right: 2px solid $chrome-outlines;
}
&.Sidebar-title--right {
- float: right;
border-left: 2px solid $chrome-outlines;
}
}
diff --git a/packages/xod-client/src/core/styles/components/Tabs.scss b/packages/xod-client/src/core/styles/components/Tabs.scss
index d5f213cc8..44da9d1fa 100644
--- a/packages/xod-client/src/core/styles/components/Tabs.scss
+++ b/packages/xod-client/src/core/styles/components/Tabs.scss
@@ -1,6 +1,8 @@
.Tabs {
background: $chrome-outlines;
- flex-direction: column;
+ display: flex;
+ flex-direction: row;
+ height: 30px;
.Sidebar-title {
display: flex;
@@ -11,4 +13,17 @@
display: flex;
flex-grow: 1;
}
+
+ .ScrollTabs {
+ padding: 4px 8px 0 8px;
+ border: none;
+ background: $chrome-outlines;
+ color: $color-tabs-unactive-text;
+ font-weight: bold;
+
+ &:hover {
+ color: $color-tabs-active-text;
+ cursor: pointer;
+ }
+ }
}
diff --git a/packages/xod-client/src/core/styles/components/TabsContainer.scss b/packages/xod-client/src/core/styles/components/TabsContainer.scss
index 15d3229ba..7823d1d55 100644
--- a/packages/xod-client/src/core/styles/components/TabsContainer.scss
+++ b/packages/xod-client/src/core/styles/components/TabsContainer.scss
@@ -5,8 +5,31 @@
position: relative;
height: 30px;
-
list-style: none;
margin: 0;
- padding: 0 4px;
+
+ // bottom padding to push horizontal scrollbar away
+ padding: 0 4px 30px 4px;
+ overflow-x: scroll;
+ overflow-y: hidden;
+ scroll-behavior: smooth;
+ // to prevent flashes of scrollbar in firefox when adding tabs
+ scrollbar-width: none;
+
+ &.isOverflowed {
+ padding: 0 20px;
+
+ .tabsScrollLeft {
+ position: absolute;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ }
+ .tabsScrollRight {
+ position: absolute;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ }
+ }
}
diff --git a/packages/xod-client/src/core/styles/components/Workarea.scss b/packages/xod-client/src/core/styles/components/Workarea.scss
index 8d442ad5a..aa38ad310 100644
--- a/packages/xod-client/src/core/styles/components/Workarea.scss
+++ b/packages/xod-client/src/core/styles/components/Workarea.scss
@@ -3,6 +3,7 @@
display: flex;
flex-direction: column;
flex-grow: 1;
+ max-width: 100%;
}
.Workarea-inner {
diff --git a/packages/xod-client/src/editor/components/TabsContainer.jsx b/packages/xod-client/src/editor/components/TabsContainer.jsx
index 04939b9e8..3231fbc34 100644
--- a/packages/xod-client/src/editor/components/TabsContainer.jsx
+++ b/packages/xod-client/src/editor/components/TabsContainer.jsx
@@ -1,11 +1,75 @@
import React from 'react';
+import normalizeWheel from 'normalize-wheel';
import PropTypes from 'prop-types';
-const TabsContainer = ({ children }) => (
-
-);
+import ReactResizeDetector from 'react-resize-detector';
+
+class TabsContainer extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.isOverflowed = false;
+ this.domElement = null;
+
+ this.setRef = this.setRef.bind(this);
+ this.checkOverflow = this.checkOverflow.bind(this);
+ this.handleScroll = this.handleScroll.bind(this);
+ }
+
+ componentDidMount() {
+ this.checkOverflow();
+ }
+
+ componentDidUpdate() {
+ this.checkOverflow();
+ }
+
+ setRef(domElement) {
+ this.domElement = domElement;
+ this.props.forwardedRef(domElement);
+ }
+
+ checkOverflow() {
+ if (!this.domElement) return;
+
+ const isOverflowed =
+ this.domElement.scrollWidth > this.domElement.clientWidth;
+
+ if (isOverflowed !== this.isOverflowed) {
+ this.isOverflowed = isOverflowed;
+ this.props.onOverflowChange(isOverflowed);
+ }
+ }
+
+ handleScroll(event) {
+ const normalizedWheel = normalizeWheel(event);
+
+ if (normalizedWheel.pixelX === 0) {
+ this.domElement.scrollLeft += normalizedWheel.pixelY;
+ }
+ }
+
+ render() {
+ return (
+
+ {this.props.children}
+
+
+ );
+ }
+}
TabsContainer.propTypes = {
+ forwardedRef: PropTypes.func.isRequired,
+ onOverflowChange: PropTypes.func.isRequired,
children: PropTypes.oneOfType([
PropTypes.element,
PropTypes.arrayOf(PropTypes.element),
diff --git a/packages/xod-client/src/editor/containers/Tabs.jsx b/packages/xod-client/src/editor/containers/Tabs.jsx
index 83fb5471d..48682a2a5 100644
--- a/packages/xod-client/src/editor/containers/Tabs.jsx
+++ b/packages/xod-client/src/editor/containers/Tabs.jsx
@@ -1,6 +1,7 @@
import * as R from 'ramda';
import React from 'react';
import PropTypes from 'prop-types';
+import { Icon } from 'react-fa';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { sortableContainer, sortableElement } from 'react-sortable-hoc';
@@ -25,26 +26,31 @@ const SortableItem = sortableElement(({ value }) => (
/>
));
-const SortableList = sortableContainer(({ items, onClick, onClose }) => (
-
- {items.map((value, index) => {
- const item = R.merge(value, {
- onClick,
- onClose,
- });
-
- return (
-
- );
- })}
-
-));
+const SortableList = sortableContainer(
+ ({ items, onClick, onClose, forwardedRef, onOverflowChange }) => (
+
+ {items.map((value, index) => {
+ const item = R.merge(value, {
+ onClick,
+ onClose,
+ });
+
+ return (
+
+ );
+ })}
+
+ )
+);
class Tabs extends React.Component {
constructor(props) {
@@ -54,6 +60,13 @@ class Tabs extends React.Component {
this.onCloseTab = this.onCloseTab.bind(this);
this.onSortEnd = this.onSortEnd.bind(this);
+ this.tabsListRef = null;
+ this.state = { isTabsListOverflown: false };
+ this.setTabsRef = this.setTabsRef.bind(this);
+ this.onTabsListOverflowChange = this.onTabsListOverflowChange.bind(this);
+ this.scrollTabsLeft = this.scrollTabsLeft.bind(this);
+ this.scrollTabsRight = this.scrollTabsRight.bind(this);
+
this.shouldComponentUpdate = deepSCU.bind(this);
}
@@ -82,11 +95,28 @@ class Tabs extends React.Component {
)(tabs);
}
+ onTabsListOverflowChange(isTabsListOverflown) {
+ this.setState({ isTabsListOverflown });
+ }
+
+ setTabsRef(ref) {
+ this.tabsListRef = ref;
+ }
+
getTabs() {
return R.sortBy(R.prop('index'))(R.values(this.props.tabs));
}
+ scrollTabsLeft() {
+ this.tabsListRef.scrollLeft -= 100;
+ }
+
+ scrollTabsRight() {
+ this.tabsListRef.scrollLeft += 100;
+ }
+
render() {
+ const { isTabsListOverflown } = this.state;
const tabs = this.getTabs();
return (
@@ -97,13 +127,14 @@ class Tabs extends React.Component {
onTogglePanel={this.props.actions.togglePanel}
isLoggedIn={this.props.userAuthorised}
/>
-
+ {isTabsListOverflown ? (
+
+ ) : null}
+ {isTabsListOverflown ? (
+
+ ) : null}
+
);