diff --git a/package.json b/package.json
index 612806f8..f4db1f3f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "react-timelines",
- "version": "2.4.0",
+ "version": "2.5.0",
"description": "React Timelines",
"main": "lib/index.js",
"scripts": {
@@ -42,7 +42,7 @@
"babel-preset-react": "^6.23.0",
"babel-preset-stage-2": "^6.22.0",
"enzyme": "^3.3.0",
- "enzyme-adapter-react-16": "^1.1.1",
+ "enzyme-adapter-react-16": "npm:enzyme-react-adapter-future",
"eslint": "^4.19.1",
"eslint-config-airbnb": "^16.1.0",
"eslint-plugin-import": "^2.12.0",
diff --git a/src/components/Contexts/Viewport.js b/src/components/Contexts/Viewport.js
new file mode 100644
index 00000000..84086f52
--- /dev/null
+++ b/src/components/Contexts/Viewport.js
@@ -0,0 +1,6 @@
+import React from 'react'
+
+export default React.createContext({
+ left: 0,
+ right: 0
+})
diff --git a/src/components/Elements/Basic.jsx b/src/components/Elements/Basic.jsx
index d11acca6..300dc5dc 100644
--- a/src/components/Elements/Basic.jsx
+++ b/src/components/Elements/Basic.jsx
@@ -1,7 +1,9 @@
import React from 'react'
import PropTypes from 'prop-types'
-import { getDayMonth } from '../../utils/formatDate'
+
import createClasses from '../../utils/classes'
+import Tooltip from './Tooltip'
+import Viewport from '../Contexts/Viewport'
const buildDataAttributes = (attributes = {}) => {
const value = {}
@@ -22,20 +24,19 @@ const Basic = ({
+ {
+ tooltip
+ // eslint-disable-next-line react/no-danger
+ ?
') }} />
+ : (
+
+
{title}
+
Start {getDayMonth(start)}
+
End {getDayMonth(end)}
+
+ )
+ }
+
+ )
+ }
+}
+
+Tooltip.propTypes = {
+ title: PropTypes.string.isRequired,
+ start: PropTypes.instanceOf(Date).isRequired,
+ end: PropTypes.instanceOf(Date).isRequired,
+ tooltip: PropTypes.string,
+ viewport: PropTypes.shape({
+ left: PropTypes.number
+ })
+}
+
+Tooltip.defaultProps = {
+ viewport: {
+ left: 0
+ }
+}
+
+export default Tooltip
diff --git a/src/components/Elements/__tests__/Basic.jsx b/src/components/Elements/__tests__/Basic.jsx
index 84cc0eef..6c015802 100644
--- a/src/components/Elements/__tests__/Basic.jsx
+++ b/src/components/Elements/__tests__/Basic.jsx
@@ -1,5 +1,5 @@
import React from 'react'
-import { shallow } from 'enzyme'
+import { mount, shallow } from 'enzyme'
import Basic from '../Basic'
@@ -19,14 +19,14 @@ describe('
', () => {
it('renders the tooltip value if it exists', () => {
const tooltip = 'Test tooltip'
const props = { ...defaultProps, tooltip }
- const wrapper = shallow(
)
+ const wrapper = mount(
)
expect(getTooltip(wrapper).html()).toMatch('Test tooltip')
})
it('handles multiline tooltips', () => {
const tooltip = 'Test\ntooltip'
const props = { ...defaultProps, tooltip }
- const wrapper = shallow(
)
+ const wrapper = mount(
)
expect(getTooltip(wrapper).html()).toMatch('Test
tooltip')
})
@@ -38,7 +38,7 @@ describe('
', () => {
const props = {
...defaultProps, tooltip, title, start, end
}
- const wrapper = shallow(
)
+ const wrapper = mount(
)
expect(getTooltip(wrapper).text()).toMatch('TEST')
expect(getTooltip(wrapper).text()).toMatch('Start 20 Mar')
expect(getTooltip(wrapper).text()).toMatch('End 15 Apr')
@@ -46,7 +46,7 @@ describe('
', () => {
it('can take an optional list of classnames to add to the parent', () => {
const props = { ...defaultProps, classes: ['foo', 'bar'] }
- const wrapper = shallow(
)
+ const wrapper = mount(
)
expect(wrapper.find('.rt-element').hasClass('foo')).toBe(true)
expect(wrapper.find('.rt-element').hasClass('bar')).toBe(true)
})
diff --git a/src/components/Layout/index.jsx b/src/components/Layout/index.jsx
index 9fccd79e..2d25844c 100644
--- a/src/components/Layout/index.jsx
+++ b/src/components/Layout/index.jsx
@@ -1,6 +1,7 @@
-import React, { PureComponent } from 'react'
+import React, { Component } from 'react'
import PropTypes from 'prop-types'
+import ViewportContext from '../Contexts/Viewport'
import Sidebar from '../Sidebar'
import Timeline from '../Timeline'
import { addListener, removeListener } from '../../utils/events'
@@ -9,7 +10,7 @@ import getNumericPropertyValue from '../../utils/getNumericPropertyValue'
const noop = () => {}
-class Layout extends PureComponent {
+class Layout extends Component {
constructor(props) {
super(props)
@@ -20,7 +21,8 @@ class Layout extends PureComponent {
this.state = {
isSticky: false,
headerHeight: 0,
- scrollLeft: 0
+ scrollLeft: 0,
+ viewport: {}
}
}
@@ -36,14 +38,13 @@ class Layout extends PureComponent {
}
componentDidUpdate(prevProps, prevState) {
- if (this.props.enableSticky && this.state.isSticky) {
- if (!prevState.isSticky) {
- this.updateTimelineHeaderScroll()
- }
+ if (this.props.enableSticky && this.state.isSticky && !prevState.isSticky) {
+ this.updateTimelineHeaderScroll()
+ }
- if (this.state.scrollLeft !== prevState.scrollLeft) {
- this.updateTimelineBodyScroll()
- }
+ if (this.state.scrollLeft !== prevState.scrollLeft) {
+ this.updateTimelineBodyScroll()
+ this.updateTimelineViewport()
}
if (this.props.isOpen !== prevProps.isOpen) {
@@ -64,9 +65,12 @@ class Layout extends PureComponent {
scrollToNow = () => {
const { time, scrollToNow, now } = this.props
+
if (scrollToNow) {
this.timeline.current.scrollLeft = time.toX(now) - (0.5 * this.props.timelineViewportWidth)
}
+
+ this.updateTimelineHeaderScroll()
}
updateTimelineBodyScroll = () => {
@@ -75,7 +79,17 @@ class Layout extends PureComponent {
updateTimelineHeaderScroll = () => {
const { scrollLeft } = this.timeline.current
- this.setState({ scrollLeft })
+ this.setState({ scrollLeft }, () => this.updateTimelineViewport())
+ }
+
+ updateTimelineViewport = () => {
+ const { left, right } = this.timeline.current.getBoundingClientRect()
+ this.setState({
+ viewport: {
+ left: left + this.state.scrollLeft,
+ right: right + this.state.scrollLeft
+ }
+ })
}
handleHeaderScrollY = (scrollLeft) => {
@@ -136,8 +150,10 @@ class Layout extends PureComponent {
const {
isSticky,
headerHeight,
- scrollLeft
+ scrollLeft,
+ viewport
} = this.state
+
return (
-
+
+
+
diff --git a/src/scss/components/_element.scss b/src/scss/components/_element.scss
index dd20b926..8dd1450c 100644
--- a/src/scss/components/_element.scss
+++ b/src/scss/components/_element.scss
@@ -17,6 +17,8 @@
text-overflow: ellipsis;
}
+$tooltip-size: 6px;
+
.rt-element__tooltip {
position: absolute;
bottom: 100%;
@@ -28,25 +30,35 @@
text-align: left;
background: $react-timelines-text-color;
color: white;
- transform: translateX(-50%) scale(0);
+ transform: translateX(-50%);
+ opacity: 0;
pointer-events: none;
&::before {
- $size: 6px;
+ $tooltip-size: 6px;
position: absolute;
top: 100%;
left: 50%;
- border-top: $size solid $react-timelines-text-color;
- border-right: $size solid transparent;
- border-left: $size solid transparent;
+ border-top: $tooltip-size solid $react-timelines-text-color;
+ border-right: $tooltip-size solid transparent;
+ border-left: $tooltip-size solid transparent;
transform: translateX(-50%);
content: ' ';
}
}
+.rt-element__tooltip--left::before {
+ left: $tooltip-size;
+}
+
+.rt-element__tooltip--right::before {
+ left: 100%;
+ margin-left: -$tooltip-size;
+}
+
.rt-element:hover > .rt-element__tooltip,
.rt-element:focus > .rt-element__tooltip {
$delay: 0.3s;
- transform: translateX(-50%) scale(1);
- transition: transform 0s $delay;
+ opacity: 1;
+ transition: opacity 0s $delay;
}
diff --git a/yarn.lock b/yarn.lock
index 2e439a26..9425b781 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1753,13 +1753,13 @@ entities@^1.1.1, entities@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"
-enzyme-adapter-react-16@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.1.1.tgz#a8f4278b47e082fbca14f5bfb1ee50ee650717b4"
+"enzyme-adapter-react-16@npm:enzyme-react-adapter-future":
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/enzyme-react-adapter-future/-/enzyme-react-adapter-future-1.1.3.tgz#f0c102f098086a0ad0270bbdaf9da5113297dc05"
dependencies:
enzyme-adapter-utils "^1.3.0"
lodash "^4.17.4"
- object.assign "^4.0.4"
+ object.assign "^4.1.0"
object.values "^1.0.4"
prop-types "^15.6.0"
react-reconciler "^0.7.0"