@r365/react-calendar-timeline
Advanced tools
Comparing version 0.25.0-drag.3 to 0.26.0-alpha.0
@@ -10,2 +10,57 @@ # Change Log | ||
## 0.23.0 | ||
- improve unit tests coverage #426 - @ilaiwi | ||
- stack items by group #384 - @acemac | ||
- fix bug where `canMove` prop gets ignored #484 - @acemac + @ilaiwi | ||
- fix sidebar re-render when groupHeights do not change #478 - @SDupZ | ||
### Stack per group | ||
now you can stack choose to stack items in individual groups by providing the property `stackItems` in group object. The property in group overrides the timeline prop `stackItems`. | ||
``` | ||
const groups = [{ id: 1, title: 'group 1', stackItems: false }, { id: 2, title: 'group 2', stackItems: true }] | ||
const items = [ | ||
{ | ||
id: 1, | ||
group: 1, | ||
title: 'item 1', | ||
start_time: moment(), | ||
end_time: moment().add(1, 'hour') | ||
}, | ||
{ | ||
id: 2, | ||
group: 2, | ||
title: 'item 2', | ||
start_time: moment().add(-0.5, 'hour'), | ||
end_time: moment().add(0.5, 'hour') | ||
}, | ||
{ | ||
id: 3, | ||
group: 1, | ||
title: 'item 3', | ||
start_time: moment().add(2, 'hour'), | ||
end_time: moment().add(3, 'hour') | ||
} | ||
] | ||
ReactDOM.render( | ||
<div> | ||
Rendered by react! | ||
<Timeline | ||
groups={groups} | ||
items={items} | ||
defaultTimeStart={moment().add(-12, 'hour')} | ||
defaultTimeEnd={moment().add(12, 'hour')} | ||
/> | ||
</div>, | ||
document.getElementById('root') | ||
) | ||
``` | ||
## 0.22.0 | ||
### Fixed | ||
@@ -12,0 +67,0 @@ |
@@ -98,2 +98,14 @@ 'use strict'; | ||
var _calendar = require('./lib/utility/calendar'); | ||
Object.keys(_calendar).forEach(function (key) { | ||
if (key === "default" || key === "__esModule") return; | ||
Object.defineProperty(exports, key, { | ||
enumerable: true, | ||
get: function get() { | ||
return _calendar[key]; | ||
} | ||
}); | ||
}); | ||
var _Timeline = require('./lib/Timeline'); | ||
@@ -100,0 +112,0 @@ |
@@ -7,2 +7,4 @@ 'use strict'; | ||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | ||
@@ -20,4 +22,8 @@ | ||
var _TimelineStateContext = require('../timeline/TimelineStateContext'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
@@ -29,2 +35,13 @@ | ||
var passThroughPropTypes = { | ||
canvasTimeStart: _propTypes2.default.number.isRequired, | ||
canvasTimeEnd: _propTypes2.default.number.isRequired, | ||
canvasWidth: _propTypes2.default.number.isRequired, | ||
lineCount: _propTypes2.default.number.isRequired, | ||
minUnit: _propTypes2.default.string.isRequired, | ||
timeSteps: _propTypes2.default.object.isRequired, | ||
height: _propTypes2.default.number.isRequired, | ||
verticalLineClassNamesForTime: _propTypes2.default.func | ||
}; | ||
var Columns = function (_Component) { | ||
@@ -54,3 +71,4 @@ _inherits(Columns, _Component); | ||
height = _props.height, | ||
verticalLineClassNamesForTime = _props.verticalLineClassNamesForTime; | ||
verticalLineClassNamesForTime = _props.verticalLineClassNamesForTime, | ||
getLeftOffsetFromDate = _props.getLeftOffsetFromDate; | ||
@@ -62,8 +80,4 @@ var ratio = canvasWidth / (canvasTimeEnd - canvasTimeStart); | ||
(0, _calendar.iterateTimes)(canvasTimeStart, canvasTimeEnd, minUnit, timeSteps, function (time, nextTime) { | ||
var left = Math.round((time.valueOf() - canvasTimeStart) * ratio, -2); | ||
var minUnitValue = time.get(minUnit === 'day' ? 'date' : minUnit); | ||
var firstOfType = minUnitValue === (minUnit === 'day' ? 1 : 0); | ||
var lineWidth = firstOfType ? 2 : 1; | ||
var labelWidth = Math.ceil((nextTime.valueOf() - time.valueOf()) * ratio) - lineWidth; | ||
var leftPush = firstOfType ? -1 : 0; | ||
@@ -79,2 +93,4 @@ var classNamesForTime = []; | ||
var left = getLeftOffsetFromDate(time.valueOf()); | ||
var right = getLeftOffsetFromDate(nextTime.valueOf()); | ||
lines.push(_react2.default.createElement('div', { | ||
@@ -86,4 +102,4 @@ key: 'line-' + time.valueOf(), | ||
top: '0px', | ||
left: left + leftPush + 'px', | ||
width: labelWidth + 'px', | ||
left: left + 'px', | ||
width: right - left + 'px', | ||
height: height + 'px' | ||
@@ -105,12 +121,22 @@ } | ||
Columns.propTypes = { | ||
canvasTimeStart: _propTypes2.default.number.isRequired, | ||
canvasTimeEnd: _propTypes2.default.number.isRequired, | ||
canvasWidth: _propTypes2.default.number.isRequired, | ||
lineCount: _propTypes2.default.number.isRequired, | ||
minUnit: _propTypes2.default.string.isRequired, | ||
timeSteps: _propTypes2.default.object.isRequired, | ||
height: _propTypes2.default.number.isRequired, | ||
verticalLineClassNamesForTime: _propTypes2.default.func | ||
Columns.propTypes = _extends({}, passThroughPropTypes, { | ||
getLeftOffsetFromDate: _propTypes2.default.func.isRequired | ||
}); | ||
var ColumnsWrapper = function ColumnsWrapper(_ref) { | ||
var props = _objectWithoutProperties(_ref, []); | ||
return _react2.default.createElement( | ||
_TimelineStateContext.TimelineStateConsumer, | ||
null, | ||
function (_ref2) { | ||
var getLeftOffsetFromDate = _ref2.getLeftOffsetFromDate; | ||
return _react2.default.createElement(Columns, _extends({ getLeftOffsetFromDate: getLeftOffsetFromDate }, props)); | ||
} | ||
); | ||
}; | ||
exports.default = Columns; | ||
ColumnsWrapper.defaultProps = _extends({}, passThroughPropTypes); | ||
exports.default = ColumnsWrapper; |
@@ -49,5 +49,6 @@ 'use strict'; | ||
timeSteps = props.timeSteps, | ||
showPeriod = props.showPeriod; | ||
showPeriod = props.showPeriod, | ||
getLeftOffsetFromDate = props.getLeftOffsetFromDate; | ||
var ratio = _this.calculateRatio(canvasWidth, canvasTimeEnd, canvasTimeStart); | ||
var intervals = _this.getHeaderIntervals({ | ||
@@ -60,8 +61,7 @@ canvasTimeStart: canvasTimeStart, | ||
showPeriod: showPeriod, | ||
ratio: ratio | ||
getLeftOffsetFromDate: getLeftOffsetFromDate | ||
}); | ||
_this.state = { | ||
intervals: intervals, | ||
ratio: ratio | ||
intervals: intervals | ||
}; | ||
@@ -74,3 +74,3 @@ return _this; | ||
value: function shouldComponentUpdate(nextProps) { | ||
if (nextProps.canvasTimeStart !== this.props.canvasTimeStart || nextProps.canvasTimeEnd !== this.props.canvasTimeEnd || nextProps.canvasWidth !== this.props.canvasWidth || nextProps.unit !== this.props.unit || nextProps.timeSteps !== this.props.timeSteps || nextProps.showPeriod !== this.props.showPeriod || nextProps.children !== this.props.children) { | ||
if (nextProps.canvasTimeStart !== this.props.canvasTimeStart || nextProps.canvasTimeEnd !== this.props.canvasTimeEnd || nextProps.canvasWidth !== this.props.canvasWidth || nextProps.unit !== this.props.unit || nextProps.timeSteps !== this.props.timeSteps || nextProps.showPeriod !== this.props.showPeriod || nextProps.children !== this.props.children || nextProps.headerData !== this.props.headerData) { | ||
return true; | ||
@@ -89,5 +89,6 @@ } | ||
timeSteps = nextProps.timeSteps, | ||
showPeriod = nextProps.showPeriod; | ||
showPeriod = nextProps.showPeriod, | ||
getLeftOffsetFromDate = nextProps.getLeftOffsetFromDate; | ||
var ratio = this.calculateRatio(canvasWidth, canvasTimeEnd, canvasTimeStart); | ||
var intervals = this.getHeaderIntervals({ | ||
@@ -100,18 +101,14 @@ canvasTimeStart: canvasTimeStart, | ||
showPeriod: showPeriod, | ||
ratio: ratio | ||
getLeftOffsetFromDate: getLeftOffsetFromDate | ||
}); | ||
this.setState({ intervals: intervals, ratio: ratio }); | ||
this.setState({ intervals: intervals }); | ||
} | ||
} | ||
}, { | ||
key: 'calculateRatio', | ||
value: function calculateRatio(canvasWidth, canvasTimeEnd, canvasTimeStart) { | ||
return canvasWidth / (canvasTimeEnd - canvasTimeStart); | ||
} | ||
}, { | ||
key: 'render', | ||
value: function render() { | ||
var props = this.getStateAndHelpers(); | ||
return this.props.children(props, this.props.props); | ||
var Renderer = this.props.children; | ||
return _react2.default.createElement(Renderer, props); | ||
} | ||
@@ -127,4 +124,4 @@ }]); | ||
unit: _propTypes2.default.string.isRequired, | ||
//Timeline context | ||
timeSteps: _propTypes2.default.object.isRequired, | ||
//Timeline context | ||
visibleTimeStart: _propTypes2.default.number.isRequired, | ||
@@ -136,3 +133,5 @@ visibleTimeEnd: _propTypes2.default.number.isRequired, | ||
showPeriod: _propTypes2.default.func.isRequired, | ||
props: _propTypes2.default.object | ||
headerData: _propTypes2.default.object, | ||
getLeftOffsetFromDate: _propTypes2.default.func.isRequired, | ||
height: _propTypes2.default.number.isRequired | ||
}; | ||
@@ -148,11 +147,14 @@ | ||
timeSteps = _ref4.timeSteps, | ||
ratio = _ref4.ratio; | ||
getLeftOffsetFromDate = _ref4.getLeftOffsetFromDate; | ||
var intervals = []; | ||
(0, _calendar.iterateTimes)(canvasTimeStart, canvasTimeEnd, unit, timeSteps, function (startTime, endTime) { | ||
var labelWidth = Math.ceil((endTime.valueOf() - startTime.valueOf()) * ratio); | ||
var left = getLeftOffsetFromDate(startTime.valueOf()); | ||
var right = getLeftOffsetFromDate(endTime.valueOf()); | ||
var width = right - left; | ||
intervals.push({ | ||
startTime: startTime, | ||
endTime: endTime, | ||
labelWidth: labelWidth | ||
labelWidth: width, | ||
left: left | ||
}); | ||
@@ -163,8 +165,2 @@ }); | ||
this.rootProps = { | ||
style: { | ||
position: 'relative' | ||
} | ||
}; | ||
this.getRootProps = function () { | ||
@@ -175,3 +171,7 @@ var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
return { | ||
style: Object.assign({}, style ? style : {}, _this2.rootProps.style) | ||
style: Object.assign({}, style ? style : {}, { | ||
position: 'relative', | ||
width: _this2.props.canvasWidth, | ||
height: _this2.props.height | ||
}) | ||
}; | ||
@@ -185,5 +185,6 @@ }; | ||
if (!interval) throw new Error("you should provide interval to the prop getter"); | ||
if (!interval) throw new Error('you should provide interval to the prop getter'); | ||
var startTime = interval.startTime, | ||
labelWidth = interval.labelWidth; | ||
labelWidth = interval.labelWidth, | ||
left = interval.left; | ||
@@ -197,3 +198,3 @@ return { | ||
unit: _this2.props.unit, | ||
ratio: _this2.state.ratio | ||
left: left | ||
}), | ||
@@ -205,15 +206,8 @@ key: 'label-' + startTime.valueOf() | ||
this.getIntervalStyle = function (_ref5) { | ||
var startTime = _ref5.startTime, | ||
canvasTimeStart = _ref5.canvasTimeStart, | ||
ratio = _ref5.ratio, | ||
unit = _ref5.unit, | ||
var left = _ref5.left, | ||
labelWidth = _ref5.labelWidth, | ||
style = _ref5.style; | ||
var left = Math.round((startTime.valueOf() - canvasTimeStart) * ratio); | ||
var unitValue = startTime.get(unit === 'day' ? 'date' : unit); | ||
var firstOfType = unitValue === (unit === 'day' ? 1 : 0); | ||
var leftCorrect = firstOfType ? 1 : 0; | ||
return _extends({}, style, { | ||
left: left - leftCorrect, | ||
left: left, | ||
width: labelWidth, | ||
@@ -232,3 +226,4 @@ position: 'absolute' | ||
visibleTimeStart = _props.visibleTimeStart, | ||
visibleTimeEnd = _props.visibleTimeEnd; | ||
visibleTimeEnd = _props.visibleTimeEnd, | ||
headerData = _props.headerData; | ||
//TODO: only evaluate on changing params | ||
@@ -250,3 +245,4 @@ | ||
getIntervalProps: _this2.getIntervalProps, | ||
showPeriod: showPeriod | ||
showPeriod: showPeriod, | ||
data: headerData | ||
}; | ||
@@ -259,3 +255,4 @@ }; | ||
unit = _ref.unit, | ||
props = _ref.props; | ||
headerData = _ref.headerData, | ||
height = _ref.height; | ||
return _react2.default.createElement( | ||
@@ -266,3 +263,4 @@ _TimelineStateContext.TimelineStateConsumer, | ||
var getTimelineState = _ref2.getTimelineState, | ||
showPeriod = _ref2.showPeriod; | ||
showPeriod = _ref2.showPeriod, | ||
getLeftOffsetFromDate = _ref2.getLeftOffsetFromDate; | ||
@@ -281,3 +279,5 @@ var timelineState = getTimelineState(); | ||
}, timelineState, { | ||
props: props | ||
headerData: headerData, | ||
getLeftOffsetFromDate: getLeftOffsetFromDate, | ||
height: height | ||
})); | ||
@@ -293,5 +293,10 @@ } | ||
unit: _propTypes2.default.string, | ||
props: _propTypes2.default.object | ||
headerData: _propTypes2.default.object, | ||
height: _propTypes2.default.number | ||
}; | ||
CustomHeaderWrapper.defaultProps = { | ||
height: 30 | ||
}; | ||
exports.default = CustomHeaderWrapper; |
@@ -9,4 +9,2 @@ 'use strict'; | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | ||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
@@ -61,9 +59,8 @@ | ||
return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = DateHeader.__proto__ || Object.getPrototypeOf(DateHeader)).call.apply(_ref, [this].concat(args))), _this), _this.getHeaderUnit = function () { | ||
if (_this.props.unit) { | ||
if (_this.props.unit === 'primaryHeader') { | ||
return (0, _calendar.getNextUnit)(_this.props.timelineUnit); | ||
} else if (_this.props.unit) { | ||
return _this.props.unit; | ||
} else if (_this.props.primaryHeader) { | ||
return (0, _calendar.getNextUnit)(_this.props.timelineUnit); | ||
} else { | ||
return _this.props.timelineUnit; | ||
} | ||
return _this.props.timelineUnit; | ||
}, _this.getRootStyle = function () { | ||
@@ -77,2 +74,16 @@ return _extends({ | ||
_createClass(DateHeader, [{ | ||
key: 'getLabelFormat', | ||
value: function getLabelFormat(interval, unit, labelWidth) { | ||
var labelFormat = this.props.labelFormat; | ||
if (typeof labelFormat === 'string') { | ||
var startTime = interval[0]; | ||
return startTime.format(labelFormat); | ||
} else if (typeof labelFormat === 'function') { | ||
return labelFormat(interval, unit, labelWidth); | ||
} else { | ||
throw new Error('labelFormat should be function or string'); | ||
} | ||
} | ||
}, { | ||
key: 'render', | ||
@@ -83,12 +94,15 @@ value: function render() { | ||
var unit = this.getHeaderUnit(); | ||
var props = this.props.props; | ||
var _props = this.props, | ||
headerData = _props.headerData, | ||
height = _props.height; | ||
return _react2.default.createElement( | ||
_CustomHeader2.default, | ||
{ unit: unit, props: props }, | ||
function (_ref2, props) { | ||
{ unit: unit, height: height, headerData: headerData }, | ||
function (_ref2) { | ||
var intervals = _ref2.headerContext.intervals, | ||
getRootProps = _ref2.getRootProps, | ||
getIntervalProps = _ref2.getIntervalProps, | ||
showPeriod = _ref2.showPeriod; | ||
showPeriod = _ref2.showPeriod, | ||
data = _ref2.data; | ||
@@ -110,7 +124,6 @@ var unit = _this2.getHeaderUnit(); | ||
intervalText: intervalText, | ||
primaryHeader: !!_this2.props.primaryHeader, | ||
secondaryHeader: !!_this2.props.secondaryHeader, | ||
primaryHeader: _this2.props.unit === 'primaryHeader', | ||
getIntervalProps: getIntervalProps, | ||
intervalRenderer: _this2.props.intervalRenderer, | ||
props: props | ||
headerData: data | ||
}); | ||
@@ -122,18 +135,2 @@ }) | ||
} | ||
}, { | ||
key: 'getLabelFormat', | ||
value: function getLabelFormat(interval, unit, labelWidth) { | ||
var labelFormat = this.props.labelFormat; | ||
if (typeof labelFormat === 'string') { | ||
var startTime = interval[0]; | ||
return startTime.format(labelFormat); | ||
} else if ((typeof labelFormat === 'undefined' ? 'undefined' : _typeof(labelFormat)) === 'object') { | ||
return formatLabel(interval, unit, labelWidth, labelFormat); | ||
} else if (typeof labelFormat === 'function') { | ||
return labelFormat(interval, unit, labelWidth); | ||
} else { | ||
throw new Error('labelFormat should be function, object or string'); | ||
} | ||
} | ||
}]); | ||
@@ -145,4 +142,2 @@ | ||
DateHeader.propTypes = { | ||
primaryHeader: _propTypes2.default.bool, | ||
secondaryHeader: _propTypes2.default.bool, | ||
unit: _propTypes2.default.string, | ||
@@ -154,3 +149,4 @@ style: _propTypes2.default.object, | ||
intervalRenderer: _propTypes2.default.func, | ||
props: _propTypes2.default.object | ||
headerData: _propTypes2.default.object, | ||
height: _propTypes2.default.number | ||
}; | ||
@@ -160,5 +156,3 @@ | ||
var DateHeaderWrapper = function DateHeaderWrapper(_ref3) { | ||
var primaryHeader = _ref3.primaryHeader, | ||
secondaryHeader = _ref3.secondaryHeader, | ||
unit = _ref3.unit, | ||
var unit = _ref3.unit, | ||
labelFormat = _ref3.labelFormat, | ||
@@ -168,3 +162,4 @@ style = _ref3.style, | ||
intervalRenderer = _ref3.intervalRenderer, | ||
props = _ref3.props; | ||
headerData = _ref3.headerData, | ||
height = _ref3.height; | ||
return _react2.default.createElement( | ||
@@ -179,4 +174,2 @@ _TimelineStateContext.TimelineStateConsumer, | ||
timelineUnit: timelineState.timelineUnit, | ||
primaryHeader: primaryHeader, | ||
secondaryHeader: secondaryHeader, | ||
unit: unit, | ||
@@ -187,3 +180,4 @@ labelFormat: labelFormat, | ||
intervalRenderer: intervalRenderer, | ||
props: props | ||
headerData: headerData, | ||
height: height | ||
}); | ||
@@ -197,12 +191,10 @@ } | ||
className: _propTypes2.default.string, | ||
primaryHeader: _propTypes2.default.bool, | ||
secondaryHeader: _propTypes2.default.bool, | ||
unit: _propTypes2.default.string, | ||
labelFormat: _propTypes2.default.oneOfType([_propTypes2.default.func, _propTypes2.default.objectOf(_propTypes2.default.objectOf(_propTypes2.default.string)), _propTypes2.default.string]), | ||
intervalRenderer: _propTypes2.default.func, | ||
props: _propTypes2.default.object | ||
headerData: _propTypes2.default.object, | ||
height: _propTypes2.default.number | ||
}; | ||
DateHeaderWrapper.defaultProps = { | ||
secondaryHeader: true, | ||
labelFormat: formatLabel | ||
@@ -209,0 +201,0 @@ }; |
@@ -24,6 +24,2 @@ 'use strict'; | ||
var _constants = require('./constants'); | ||
var _calendar = require('../utility/calendar'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -30,0 +26,0 @@ |
@@ -45,17 +45,3 @@ 'use strict'; | ||
return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Interval.__proto__ || Object.getPrototypeOf(Interval)).call.apply(_ref, [this].concat(args))), _this), _this.getIntervalStyle = function () { | ||
return { | ||
display: 'flex', | ||
alignItems: 'center', | ||
justifyContent: 'center', | ||
backgroundColor: _this.props.secondaryHeader && !_this.props.primaryHeader ? 'rgb(240, 240, 240)' : 'initial', | ||
height: '100%', | ||
borderLeft: _this.props.primaryHeader ? '1px solid #bbb' : '2px solid #bbb', | ||
borderRight: _this.props.primaryHeader ? '1px solid #bbb' : 'none', | ||
borderBottom: '1px solid #bbb', | ||
color: _this.props.primaryHeader ? '#fff' : 'initial', | ||
cursor: 'pointer', | ||
fontSize: '14px' | ||
}; | ||
}, _this.onIntervalClick = function () { | ||
return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Interval.__proto__ || Object.getPrototypeOf(Interval)).call.apply(_ref, [this].concat(args))), _this), _this.onIntervalClick = function () { | ||
var _this$props = _this.props, | ||
@@ -93,15 +79,20 @@ primaryHeader = _this$props.primaryHeader, | ||
intervalRenderer = _props.intervalRenderer, | ||
props = _props.props; | ||
headerData = _props.headerData; | ||
if (intervalRenderer) return intervalRenderer({ | ||
getIntervalProps: this.getIntervalProps, | ||
intervalContext: { | ||
interval: interval, | ||
intervalText: intervalText | ||
} | ||
}, props); | ||
var Renderer = intervalRenderer; | ||
if (Renderer) { | ||
return _react2.default.createElement(Renderer, { | ||
getIntervalProps: this.getIntervalProps, | ||
intervalContext: { | ||
interval: interval, | ||
intervalText: intervalText | ||
}, | ||
data: headerData | ||
}); | ||
} | ||
return _react2.default.createElement( | ||
'div', | ||
this.getIntervalProps({ | ||
style: this.getIntervalStyle() | ||
_extends({}, this.getIntervalProps({}), { | ||
className: 'rct-dateHeader ' + (this.props.primaryHeader ? 'rct-dateHeader-primary' : '') | ||
}), | ||
@@ -127,6 +118,5 @@ _react2.default.createElement( | ||
primaryHeader: _propTypes2.default.bool.isRequired, | ||
secondaryHeader: _propTypes2.default.bool.isRequired, | ||
getIntervalProps: _propTypes2.default.func.isRequired, | ||
props: _propTypes2.default.object | ||
headerData: _propTypes2.default.object | ||
}; | ||
exports.default = Interval; |
@@ -51,9 +51,10 @@ 'use strict'; | ||
return { | ||
style: _extends({ | ||
style: _extends({}, style, { | ||
width: width | ||
}, style) | ||
}) | ||
}; | ||
}, _this.getStateAndHelpers = function () { | ||
return { | ||
getRootProps: _this.getRootProps | ||
getRootProps: _this.getRootProps, | ||
data: _this.props.headerData | ||
}; | ||
@@ -67,3 +68,4 @@ }, _temp), _possibleConstructorReturn(_this, _ret); | ||
var props = this.getStateAndHelpers(); | ||
return this.props.children(props, this.props.props); | ||
var Renderer = this.props.children; | ||
return _react2.default.createElement(Renderer, props); | ||
} | ||
@@ -80,3 +82,3 @@ }]); | ||
variant: _propTypes2.default.string, | ||
props: _propTypes2.default.object | ||
headerData: _propTypes2.default.object | ||
}; | ||
@@ -88,3 +90,3 @@ | ||
variant = _ref2.variant, | ||
props = _ref2.props; | ||
headerData = _ref2.headerData; | ||
return _react2.default.createElement( | ||
@@ -102,3 +104,3 @@ _HeadersContext.TimelineHeadersConsumer, | ||
variant: variant, | ||
props: props | ||
headerData: headerData | ||
}); | ||
@@ -112,3 +114,3 @@ } | ||
variant: _propTypes2.default.string, | ||
props: _propTypes2.default.object | ||
headerData: _propTypes2.default.object | ||
}; | ||
@@ -115,0 +117,0 @@ |
@@ -46,8 +46,5 @@ 'use strict'; | ||
_this.getRootStyle = function () { | ||
return _extends({ | ||
background: '#c52020', | ||
borderBottom: '1px solid #bbb' | ||
}, _this.props.style, { | ||
display: 'flex', | ||
width: 'max-content' | ||
return _extends({}, _this.props.style, { | ||
display: 'flex' | ||
// width: 'max-content' | ||
}); | ||
@@ -62,5 +59,3 @@ }; | ||
return _extends({ | ||
border: '1px solid #bbb' | ||
}, calendarHeaderStyle, { | ||
return _extends({}, calendarHeaderStyle, { | ||
overflow: 'hidden', | ||
@@ -71,2 +66,8 @@ width: _this.props.width | ||
_this.handleRootRef = function (element) { | ||
if (_this.props.headerRef) { | ||
_this.props.headerRef(element); | ||
} | ||
}; | ||
return _this; | ||
@@ -85,6 +86,8 @@ } | ||
_react2.default.Children.map(children, function (child) { | ||
if (child.type === _SidebarHeader2.default && child.props.variant === _constants.RIGHT_VARIANT) { | ||
rightSidebarHeader = child; | ||
} else if (child.type === _SidebarHeader2.default && child.props.variant === _constants.LEFT_VARIANT) { | ||
leftSidebarHeader = child; | ||
if (child.type === _SidebarHeader2.default) { | ||
if (child.props.variant === _constants.RIGHT_VARIANT) { | ||
rightSidebarHeader = child; | ||
} else { | ||
leftSidebarHeader = child; | ||
} | ||
} else { | ||
@@ -96,3 +99,8 @@ calendarHeaders.push(child); | ||
'div', | ||
{ style: this.getRootStyle(), className: this.props.className }, | ||
{ | ||
ref: this.handleRootRef, | ||
style: this.getRootStyle(), | ||
className: 'rct-header-root ' + this.props.className | ||
}, | ||
leftSidebarHeader, | ||
@@ -104,3 +112,3 @@ _react2.default.createElement( | ||
style: this.getCalendarHeaderStyle(), | ||
className: this.props.calendarHeaderClassName | ||
className: 'rct-calendar-header ' + this.props.calendarHeaderClassName | ||
}, | ||
@@ -125,3 +133,4 @@ calendarHeaders | ||
calendarHeaderClassName: _propTypes2.default.string, | ||
width: _propTypes2.default.number.isRequired | ||
width: _propTypes2.default.number.isRequired, | ||
headerRef: _propTypes2.default.func | ||
}; | ||
@@ -173,5 +182,6 @@ | ||
calendarHeaderStyle: _propTypes2.default.object, | ||
calendarHeaderClassName: _propTypes2.default.string | ||
calendarHeaderClassName: _propTypes2.default.string, | ||
headerRef: _propTypes2.default.func | ||
}; | ||
exports.default = TimelineHeadersWrapper; |
@@ -234,3 +234,3 @@ 'use strict'; | ||
}).draggable({ | ||
enabled: this.props.selected | ||
enabled: this.props.selected && this.canMove() | ||
}).styleCursor(false).on('dragstart', function (e) { | ||
@@ -257,3 +257,3 @@ if (_this2.props.selected) { | ||
if (_this2.props.moveResizeValidator) { | ||
dragTime = _this2.props.moveResizeValidator('move', _this2.props.item, dragTime, undefined, (0, _generic._get)(_this2.props.dimensions.order.group, _this2.props.keys.groupIdKey)); | ||
dragTime = _this2.props.moveResizeValidator('move', _this2.props.item, dragTime); | ||
} | ||
@@ -276,3 +276,3 @@ | ||
if (_this2.props.moveResizeValidator) { | ||
dragTime = _this2.props.moveResizeValidator('move', _this2.props.item, dragTime, undefined, (0, _generic._get)(_this2.props.dimensions.order.group, _this2.props.keys.groupIdKey)); | ||
dragTime = _this2.props.moveResizeValidator('move', _this2.props.item, dragTime); | ||
} | ||
@@ -313,4 +313,3 @@ | ||
if (_this2.props.moveResizeValidator) { | ||
console.log(_this2.props.dimensions); | ||
resizeTime = _this2.props.moveResizeValidator('resize', _this2.props.item, resizeTime, resizeEdge, (0, _generic._get)(_this2.props.dimensions.order.group, _this2.props.keys.groupIdKey)); | ||
resizeTime = _this2.props.moveResizeValidator('resize', _this2.props.item, resizeTime, resizeEdge); | ||
} | ||
@@ -333,3 +332,3 @@ | ||
if (_this2.props.moveResizeValidator) { | ||
resizeTime = _this2.props.moveResizeValidator('resize', _this2.props.item, resizeTime, resizeEdge, (0, _generic._get)(_this2.props.dimensions.order.group, _this2.props.keys.groupIdKey)); | ||
resizeTime = _this2.props.moveResizeValidator('resize', _this2.props.item, resizeTime, resizeEdge); | ||
} | ||
@@ -348,3 +347,5 @@ | ||
}).on('tap', function (e) { | ||
_this2.actualClick(e, e.pointerType === 'mouse' ? 'click' : 'touch'); | ||
if (e.pointerType !== 'mouse') { | ||
_this2.actualClick(e, 'touch'); | ||
} | ||
}); | ||
@@ -389,8 +390,7 @@ | ||
this.cacheDataFromProps(this.props); | ||
var interactMounted = this.state.interactMounted; | ||
var couldDrag = this.props.selected && this.canMove(this.props); | ||
var couldResizeLeft = this.props.selected && this.canResizeLeft(this.props); | ||
var couldResizeRight = this.props.selected && this.canResizeRight(this.props); | ||
var couldDrag = prevProps.selected && this.canMove(prevProps); | ||
var couldResizeLeft = prevProps.selected && this.canResizeLeft(prevProps); | ||
var couldResizeRight = prevProps.selected && this.canResizeRight(prevProps); | ||
var willBeAbleToDrag = this.props.selected && this.canMove(this.props); | ||
@@ -400,24 +400,30 @@ var willBeAbleToResizeLeft = this.props.selected && this.canResizeLeft(this.props); | ||
if (this.props.selected && !interactMounted) { | ||
this.mountInteract(); | ||
interactMounted = true; | ||
} | ||
if (!!this.item) { | ||
if (this.props.selected && !interactMounted) { | ||
this.mountInteract(); | ||
interactMounted = true; | ||
} | ||
if (interactMounted && (couldResizeLeft !== willBeAbleToResizeLeft || couldResizeRight !== willBeAbleToResizeRight)) { | ||
var leftResize = this.props.useResizeHandle ? this.dragLeft : true; | ||
var rightResize = this.props.useResizeHandle ? this.dragRight : true; | ||
if (interactMounted && (couldResizeLeft !== willBeAbleToResizeLeft || couldResizeRight !== willBeAbleToResizeRight)) { | ||
var leftResize = this.props.useResizeHandle ? this.dragLeft : true; | ||
var rightResize = this.props.useResizeHandle ? this.dragRight : true; | ||
(0, _interactjs2.default)(this.item).resizable({ | ||
enabled: willBeAbleToResizeLeft || willBeAbleToResizeRight, | ||
edges: { | ||
top: false, | ||
bottom: false, | ||
left: willBeAbleToResizeLeft && leftResize, | ||
right: willBeAbleToResizeRight && rightResize | ||
} | ||
}); | ||
(0, _interactjs2.default)(this.item).resizable({ | ||
enabled: willBeAbleToResizeLeft || willBeAbleToResizeRight, | ||
edges: { | ||
top: false, | ||
bottom: false, | ||
left: willBeAbleToResizeLeft && leftResize, | ||
right: willBeAbleToResizeRight && rightResize | ||
} | ||
}); | ||
} | ||
if (interactMounted && couldDrag !== willBeAbleToDrag) { | ||
(0, _interactjs2.default)(this.item).draggable({ enabled: willBeAbleToDrag }); | ||
} | ||
} else { | ||
interactMounted = false; | ||
} | ||
if (interactMounted && couldDrag !== willBeAbleToDrag) { | ||
(0, _interactjs2.default)(this.item).draggable({ enabled: willBeAbleToDrag }); | ||
} | ||
this.setState({ | ||
interactMounted: interactMounted | ||
}); | ||
} | ||
@@ -536,16 +542,2 @@ }, { | ||
this.onMouseDown = function (e) { | ||
if (!_this3.state.interactMounted) { | ||
e.preventDefault(); | ||
_this3.startedClicking = true; | ||
} | ||
}; | ||
this.onMouseUp = function (e) { | ||
if (!_this3.state.interactMounted && _this3.startedClicking) { | ||
_this3.startedClicking = false; | ||
_this3.actualClick(e, 'click'); | ||
} | ||
}; | ||
this.onTouchStart = function (e) { | ||
@@ -603,4 +595,2 @@ if (!_this3.state.interactMounted) { | ||
className: classNames + (' ' + (props.className ? props.className : '')), | ||
onMouseDown: (0, _events.composeEvents)(_this3.onMouseDown, props.onMouseDown), | ||
onMouseUp: (0, _events.composeEvents)(_this3.onMouseUp, props.onMouseUp), | ||
onTouchStart: (0, _events.composeEvents)(_this3.onTouchStart, props.onTouchStart), | ||
@@ -610,3 +600,6 @@ onTouchEnd: (0, _events.composeEvents)(_this3.onTouchEnd, props.onTouchEnd), | ||
onContextMenu: (0, _events.composeEvents)(_this3.handleContextMenu, props.onContextMenu), | ||
style: Object.assign({}, _this3.getItemStyle(props)) | ||
style: Object.assign({}, _this3.getItemStyle(props)), | ||
onClick: function onClick(e) { | ||
_this3.actualClick(e, 'click'); | ||
} | ||
}; | ||
@@ -613,0 +606,0 @@ }; |
@@ -39,3 +39,3 @@ 'use strict'; | ||
value: function shouldComponentUpdate(nextProps) { | ||
return !((0, _generic.arraysEqual)(nextProps.groups, this.props.groups) && nextProps.keys === this.props.keys && nextProps.width === this.props.width && (0, _generic.arraysEqual)(nextProps.groupHeights, this.props.groupHeights) && nextProps.height === this.props.height); | ||
return !(nextProps.keys === this.props.keys && nextProps.width === this.props.width && nextProps.height === this.props.height && (0, _generic.arraysEqual)(nextProps.groups, this.props.groups) && (0, _generic.arraysEqual)(nextProps.groupHeights, this.props.groupHeights)); | ||
} | ||
@@ -42,0 +42,0 @@ }, { |
@@ -0,0 +0,0 @@ 'use strict'; |
@@ -0,0 +0,0 @@ 'use strict'; |
@@ -0,0 +0,0 @@ 'use strict'; |
@@ -88,3 +88,3 @@ 'use strict'; | ||
markers: state.markers.filter(function (marker) { | ||
return marker !== newMarker; | ||
return marker.id !== newMarker.id; | ||
}) | ||
@@ -91,0 +91,0 @@ }; |
@@ -110,2 +110,6 @@ 'use strict'; | ||
_this.getSelected = _this.getSelected.bind(_this); | ||
_this.hasSelectedItem = _this.hasSelectedItem.bind(_this); | ||
_this.isItemSelected = _this.isItemSelected.bind(_this); | ||
var visibleTimeStart = null; | ||
@@ -333,3 +337,3 @@ var visibleTimeEnd = null; | ||
key: 'childrenWithProps', | ||
value: function childrenWithProps(canvasTimeStart, canvasTimeEnd, canvasWidth, dimensionItems, groupHeights, groupTops, height, headerHeight, visibleTimeStart, visibleTimeEnd, minUnit, timeSteps) { | ||
value: function childrenWithProps(canvasTimeStart, canvasTimeEnd, canvasWidth, dimensionItems, groupHeights, groupTops, height, visibleTimeStart, visibleTimeEnd, minUnit, timeSteps) { | ||
if (!this.props.children) { | ||
@@ -356,5 +360,4 @@ return null; | ||
groupTops: groupTops, | ||
selected: this.state.selectedItem && !this.props.selected ? [this.state.selectedItem] : this.props.selected || [], | ||
selected: this.getSelected(), | ||
height: height, | ||
headerHeight: headerHeight, | ||
minUnit: minUnit, | ||
@@ -373,2 +376,21 @@ timeSteps: timeSteps | ||
}, { | ||
key: 'getSelected', | ||
value: function getSelected() { | ||
return this.state.selectedItem && !this.props.selected ? [this.state.selectedItem] : this.props.selected || []; | ||
} | ||
}, { | ||
key: 'hasSelectedItem', | ||
value: function hasSelectedItem() { | ||
if (!Array.isArray(this.props.selected)) return !!this.state.selectedItem; | ||
return this.props.selected.length > 0; | ||
} | ||
}, { | ||
key: 'isItemSelected', | ||
value: function isItemSelected(itemId) { | ||
var selectedItems = this.getSelected(); | ||
return selectedItems.some(function (i) { | ||
return i === itemId; | ||
}); | ||
} | ||
}, { | ||
key: 'render', | ||
@@ -381,4 +403,2 @@ value: function render() { | ||
groups = _props.groups, | ||
headerLabelGroupHeight = _props.headerLabelGroupHeight, | ||
headerLabelHeight = _props.headerLabelHeight, | ||
sidebarWidth = _props.sidebarWidth, | ||
@@ -406,3 +426,2 @@ rightSidebarWidth = _props.rightSidebarWidth, | ||
var minUnit = (0, _calendar.getMinUnit)(zoom, width, timeSteps); | ||
var headerHeight = headerLabelGroupHeight + headerLabelHeight; | ||
@@ -478,6 +497,6 @@ var isInteractingWithItem = !!draggingItem || !!resizingItem; | ||
this.items(canvasTimeStart, zoom, canvasTimeEnd, canvasWidth, minUnit, dimensionItems, groupHeights, groupTops), | ||
this.columns(canvasTimeStart, canvasTimeEnd, canvasWidth, minUnit, timeSteps, height, headerHeight), | ||
this.columns(canvasTimeStart, canvasTimeEnd, canvasWidth, minUnit, timeSteps, height), | ||
this.rows(canvasWidth, groupHeights, groups), | ||
this.infoLabel(), | ||
this.childrenWithProps(canvasTimeStart, canvasTimeEnd, canvasWidth, dimensionItems, groupHeights, groupTops, height, headerHeight, visibleTimeStart, visibleTimeEnd, minUnit, timeSteps) | ||
this.childrenWithProps(canvasTimeStart, canvasTimeEnd, canvasWidth, dimensionItems, groupHeights, groupTops, height, visibleTimeStart, visibleTimeEnd, minUnit, timeSteps) | ||
) | ||
@@ -535,7 +554,4 @@ ), | ||
minResizeWidth: _propTypes2.default.number, | ||
stickyOffset: _propTypes2.default.number, | ||
stickyHeader: _propTypes2.default.bool, | ||
lineHeight: _propTypes2.default.number, | ||
headerLabelGroupHeight: _propTypes2.default.number, | ||
headerLabelHeight: _propTypes2.default.number, | ||
itemHeightRatio: _propTypes2.default.number, | ||
@@ -554,3 +570,3 @@ | ||
stackItems: _propTypes2.default.bool, | ||
stackItems: _propTypes2.default.oneOf([false, 'space', 'lines']), | ||
@@ -655,3 +671,4 @@ traditionalZoom: _propTypes2.default.bool, | ||
children: _propTypes2.default.node, | ||
width: _propTypes2.default.number | ||
width: _propTypes2.default.number, | ||
onUpdateMove: _propTypes2.default.func | ||
}; | ||
@@ -663,7 +680,4 @@ ReactCalendarTimeline.defaultProps = { | ||
minResizeWidth: 20, | ||
stickyOffset: 0, | ||
stickyHeader: true, | ||
lineHeight: 30, | ||
headerLabelGroupHeight: 30, | ||
headerLabelHeight: 30, | ||
itemHeightRatio: 0.65, | ||
@@ -729,3 +743,4 @@ | ||
selected: null | ||
selected: null, | ||
onUpdateMove: null | ||
}; | ||
@@ -851,3 +866,3 @@ ReactCalendarTimeline.childContextTypes = { | ||
this.selectItem = function (item, clickType, e) { | ||
if (_this4.state.selectedItem === item || _this4.props.itemTouchSendsClick && clickType === 'touch') { | ||
if (_this4.isItemSelected(item) || _this4.props.itemTouchSendsClick && clickType === 'touch') { | ||
if (item && _this4.props.onItemClick) { | ||
@@ -928,3 +943,5 @@ var time = _this4.timeFromItemEvent(e); | ||
var keys = _this4.props.keys; | ||
if (_this4.props.onUpdateMove) { | ||
_this4.props.onUpdateMove(item, dragTime, newGroupOrder, 'move'); | ||
} | ||
_this4.setState({ | ||
@@ -946,2 +963,5 @@ draggingItem: item, | ||
this.resizingItem = function (item, resizeTime, edge) { | ||
if (_this4.props.onUpdateMove) { | ||
_this4.props.onUpdateMove(item, resizeTime, undefined, 'resize', edge); | ||
} | ||
_this4.setState({ | ||
@@ -963,3 +983,3 @@ resizingItem: item, | ||
// shouldnt this be handled by the user, as far as when to deselect an item? | ||
if (_this4.state.selectedItem) { | ||
if (_this4.hasSelectedItem()) { | ||
_this4.selectItem(null); | ||
@@ -1017,3 +1037,3 @@ } | ||
_react2.default.createElement(_SidebarHeader2.default, null), | ||
_react2.default.createElement(_DateHeader2.default, { primaryHeader: true }), | ||
_react2.default.createElement(_DateHeader2.default, { unit: 'primaryHeader' }), | ||
_react2.default.createElement(_DateHeader2.default, null), | ||
@@ -1030,2 +1050,2 @@ _this4.props.rightSidebarWidth ? _react2.default.createElement(_SidebarHeader2.default, { variant: 'right' }) : null | ||
exports.default = ReactCalendarTimeline; | ||
exports.default = ReactCalendarTimeline; |
@@ -0,0 +0,0 @@ 'use strict'; |
@@ -24,2 +24,3 @@ 'use strict'; | ||
exports.collision = collision; | ||
exports.groupStackInLines = groupStackInLines; | ||
exports.groupStack = groupStack; | ||
@@ -100,3 +101,4 @@ exports.groupNoStack = groupNoStack; | ||
var nextTime = (0, _moment2.default)(time).add(timeSteps[unit] || 1, unit + 's'); | ||
callback(time, nextTime); | ||
var endTime = (0, _moment2.default)(time).endOf(unit + 's'); | ||
callback(time, endTime); | ||
time = nextTime; | ||
@@ -178,6 +180,9 @@ } | ||
day: 'month', | ||
month: 'year' | ||
month: 'year', | ||
year: 'year' | ||
}; | ||
return nextUnits[unit] || ''; | ||
if (!nextUnits[unit]) { | ||
throw new Error('unit ' + unit + ' in not acceptable'); | ||
} | ||
return nextUnits[unit]; | ||
} | ||
@@ -310,2 +315,19 @@ | ||
/** | ||
* Calculate the position of a given item for a group that each in a line | ||
* is being stacked | ||
*/ | ||
function groupStackInLines(lineHeight, item, items, groupHeight, groupTop, itemIndex) { | ||
// calculate non-overlapping positions | ||
var verticalMargin = lineHeight - item.dimensions.height; | ||
if (item.dimensions.stack && item.dimensions.top === null) { | ||
item.dimensions.top = groupTop + verticalMargin + itemIndex * lineHeight; | ||
} | ||
return { | ||
groupHeight: lineHeight * items.length, | ||
verticalMargin: verticalMargin, | ||
itemTop: item.dimensions.top | ||
}; | ||
} | ||
/** | ||
* Calculate the position of a given item for a group that | ||
@@ -317,3 +339,3 @@ * is being stacked | ||
var curHeight = groupHeight; | ||
var verticalMargin = lineHeight - item.dimensions.height; | ||
var verticalMargin = (lineHeight - item.dimensions.height) / 2; | ||
if (item.dimensions.stack && item.dimensions.top === null) { | ||
@@ -338,3 +360,3 @@ item.dimensions.top = groupTop + verticalMargin; | ||
item.dimensions.top = collidingItem.dimensions.top + lineHeight; | ||
curHeight = Math.max(curHeight, item.dimensions.top + item.dimensions.height - groupTop); | ||
curHeight = Math.max(curHeight, item.dimensions.top + item.dimensions.height + verticalMargin - groupTop); | ||
} | ||
@@ -402,3 +424,3 @@ } while (collidingItem); | ||
} else { | ||
groupHeights.push(Math.max(groupHeight + verticalMargin, lineHeight)); | ||
groupHeights.push(Math.max(groupHeight, lineHeight)); | ||
} | ||
@@ -414,7 +436,7 @@ } | ||
/** | ||
* | ||
* @param {*} itemsDimensions | ||
* @param {*} isGroupStacked | ||
* @param {*} lineHeight | ||
* @param {*} groupTop | ||
* | ||
* @param {*} itemsDimensions | ||
* @param {*} isGroupStacked | ||
* @param {*} lineHeight | ||
* @param {*} groupTop | ||
*/ | ||
@@ -427,4 +449,6 @@ function stackGroup(itemsDimensions, isGroupStacked, lineHeight, groupTop) { | ||
var r = {}; | ||
if (isGroupStacked) { | ||
if (isGroupStacked === 'space') { | ||
r = groupStack(lineHeight, itemsDimensions[itemIndex], itemsDimensions, groupHeight, groupTop, itemIndex); | ||
} else if (isGroupStacked === 'lines') { | ||
r = groupStackInLines(lineHeight, itemsDimensions[itemIndex], itemsDimensions, groupHeight, groupTop, itemIndex); | ||
} else { | ||
@@ -431,0 +455,0 @@ r = groupNoStack(lineHeight, itemsDimensions[itemIndex], groupHeight, groupTop); |
{ | ||
"name": "@r365/react-calendar-timeline", | ||
"version": "0.25.0-drag.3", | ||
"version": "0.26.0-alpha.0", | ||
"description": "react calendar timeline", | ||
@@ -130,3 +130,3 @@ "main": "lib/index.js", | ||
"interactjs": "^1.3.4", | ||
"jest": "^23.1.0", | ||
"jest": "^23.6.0", | ||
"jest-dom": "^1.12.1", | ||
@@ -144,3 +144,3 @@ "jest-watch-typeahead": "^0.1.0", | ||
"react-router-dom": "^4.1.1", | ||
"react-testing-library": "^5.1.0", | ||
"react-testing-library": "^6.0.3", | ||
"rimraf": "^2.6.2", | ||
@@ -147,0 +147,0 @@ "sass-loader": "^7.0.3", |
301
README.md
# React Calendar Timeline | ||
A modern and responsive react timeline component. | ||
A modern and responsive React timeline component. | ||
@@ -19,3 +19,3 @@ ![calendar demo](https://raw.githubusercontent.com/namespace-ee/react-calendar-timeline/master/demo.gif) | ||
`react-calendar-timeline` has `react`, `react-dom`, [`moment`](http://momentjs.com/) and [`interactjs`](http://interactjs.io/docs/) as peer dependencies. | ||
`react-calendar-timeline` has [react](https://reactjs.org/), [react-dom](https://reactjs.org/docs/react-dom.html), [`moment`](http://momentjs.com/) and [`interactjs`](http://interactjs.io/docs/) as peer dependencies. | ||
@@ -87,3 +87,3 @@ # Usage | ||
rightTitle: 'title in the right sidebar', | ||
stackItems?: true, | ||
stackItems?: false or 'space' or 'line', | ||
height?: 30 | ||
@@ -93,3 +93,3 @@ } | ||
If you use right sidebar, you can pass optional `rightTitle` property here. | ||
If you use the right sidebar, you can pass optional `rightTitle` property here. | ||
If you want to overwrite the calculated height with a custom height, you can pass a `height` property as an int in pixels here. This can be very useful for categorized groups. | ||
@@ -124,3 +124,3 @@ | ||
The preferred (fastest) option is to give unix timestamps in milliseconds for `start_time` and `end_time`. Objects that convert to them (JavaScript Date or moment()) will also work, but will be a lot slower. | ||
The preferred (fastest) option is to give Unix timestamps in milliseconds for `start_time` and `end_time`. Objects that convert to them (JavaScript `Date` or `moment()`) will also work, but will be a lot slower. | ||
@@ -133,3 +133,3 @@ ## defaultTimeStart and defaultTimeEnd | ||
The exact viewport of the calendar. When these are specified, scrolling in the calendar must be orchestrated by the `onTimeChange` function. This parameter expects a unix timestamp in milliseconds. | ||
The exact viewport of the calendar. When these are specified, scrolling in the calendar must be orchestrated by the `onTimeChange` function. This parameter expects a Unix timestamp in milliseconds. | ||
@@ -185,15 +185,2 @@ **Note that you need to provide either `defaultTimeStart/End` or `visibleTimeStart/End` for the timeline to function** | ||
## stickyOffset | ||
At what height from the top of the screen should we start "sticking" the header (i.e. position: sticky)? This is useful if for example you already have | ||
a sticky navbar and want to push the timeline header down further. Defaults `0`. | ||
## stickyHeader | ||
Specify whether you want the timeline header to be "sticky". Pass `false` if you want the header to fix at top of element and not fix when you scroll down the page. Defaults to `true` | ||
## headerRef | ||
Ref callback that gets a DOM reference to the header element. See [FAQ below](#the-timeline-header-doesnt-fix-to-the-top-of-the-container-when-i-scroll-down). | ||
## lineHeight | ||
@@ -203,10 +190,2 @@ | ||
## headerLabelGroupHeight | ||
Height of the top header line. Default `30` | ||
## headerLabelHeight | ||
Height of the bottom header line. Default `30` | ||
## itemHeightRatio | ||
@@ -226,3 +205,3 @@ | ||
How many pixels we can drag the background for it to be counted as a click on the background. Defualt: `3` | ||
How many pixels we can drag the background for it to be counted as a click on the background. Default `3` | ||
@@ -249,2 +228,7 @@ ## canMove | ||
can be assigned to | ||
- false | ||
- space (saves space in stacking) | ||
- line (stack each item in a line) | ||
## traditionalZoom | ||
@@ -319,3 +303,3 @@ | ||
## moveResizeValidator(action, itemId, time, resizeEdge, groupId) | ||
## moveResizeValidator(action, itemId, time, resizeEdge) | ||
@@ -330,4 +314,2 @@ This function is called when an item is being moved or resized. It's up to this function to return a new version of `change`, when the proposed move would violate business logic. | ||
The argument `groupId` is the new group id to be moved to. | ||
The function must return a new unix timestamp in milliseconds... or just `time` if the proposed new time doesn't interfere with business logic. | ||
@@ -347,76 +329,7 @@ | ||
``` | ||
## onUpdateMove(itemId, time, newGroup, action,resizeEdge) | ||
## headerLabelFormats and subHeaderLabelFormats | ||
this function is called after moveResizeValidator on every drag update | ||
The formats passed to moment to render times in the header and subheader. Defaults to these: | ||
```js | ||
import { | ||
defaultHeaderLabelFormats, | ||
defaultSubHeaderLabelFormats | ||
} from 'react-calendar-timeline' | ||
defaultHeaderLabelFormats == | ||
{ | ||
yearShort: 'YY', | ||
yearLong: 'YYYY', | ||
monthShort: 'MM/YY', | ||
monthMedium: 'MM/YYYY', | ||
monthMediumLong: 'MMM YYYY', | ||
monthLong: 'MMMM YYYY', | ||
dayShort: 'L', | ||
dayLong: 'dddd, LL', | ||
hourShort: 'HH', | ||
hourMedium: 'HH:00', | ||
hourMediumLong: 'L, HH:00', | ||
hourLong: 'dddd, LL, HH:00', | ||
time: 'LLL' | ||
} | ||
defaultSubHeaderLabelFormats == | ||
{ | ||
yearShort: 'YY', | ||
yearLong: 'YYYY', | ||
monthShort: 'MM', | ||
monthMedium: 'MMM', | ||
monthLong: 'MMMM', | ||
dayShort: 'D', | ||
dayMedium: 'dd D', | ||
dayMediumLong: 'ddd, Do', | ||
dayLong: 'dddd, Do', | ||
hourShort: 'HH', | ||
hourLong: 'HH:00', | ||
minuteShort: 'mm', | ||
minuteLong: 'HH:mm' | ||
} | ||
``` | ||
For US time formats (AM/PM), use these: | ||
```js | ||
import { | ||
defaultHeaderLabelFormats, | ||
defaultSubHeaderLabelFormats | ||
} from 'react-calendar-timeline' | ||
const usHeaderLabelFormats = Object.assign({}, defaultSubHeaderLabelFormats, { | ||
hourShort: 'h A', | ||
hourMedium: 'h A', | ||
hourMediumLong: 'L, h A', | ||
hourLong: 'dddd, LL, h A' | ||
}) | ||
const usSubHeaderLabelFormats = Object.assign( | ||
{}, | ||
defaultSubHeaderLabelFormats, | ||
{ | ||
hourShort: 'h A', | ||
hourLong: 'h A', | ||
minuteLong: 'h:mm A' | ||
} | ||
) | ||
``` | ||
... and then pass these as `headerLabelFormats` and `subHeaderLabelFormats` | ||
## onTimeChange(visibleTimeStart, visibleTimeEnd, updateScrollCanvas) | ||
@@ -452,5 +365,5 @@ | ||
Render prop function used to render a customized item. The function provides multiple paramerters that can be used to render each item. | ||
Render prop function used to render a customized item. The function provides multiple parameters that can be used to render each item. | ||
Paramters provided to the function has two types: context params which have the state of the item and timeline, and prop getters functions | ||
Parameters provided to the function has two types: context params which have the state of the item and timeline, and prop getters functions | ||
@@ -486,2 +399,3 @@ #### Render props params | ||
| `dragStart` | `object` | returns `x` and `y` of the start dragging point of the item. | | ||
| `dragTime` | `number` | current drag time. | | ||
| `dragGroupDelta` | `number` | returns number of groups the item moved. if negative, moving was to top. If positive, moving was to down | | ||
@@ -491,2 +405,3 @@ | `resizing` | `boolean` | returns if the item is being resized. | | ||
| `resizeStart` | `number` | returns the x value from where the component start moving | | ||
| `resizeTime` | `number` | current resize time | | ||
| `width` | `boolean` | returns the width of the item (same as in dimensions) | | ||
@@ -508,3 +423,3 @@ | ||
* key: item id | ||
* ref: function to get item referance | ||
* ref: function to get item reference | ||
* className: classnames to be applied to the item | ||
@@ -519,5 +434,5 @@ * onMouseDown: event handler | ||
\*\* _the given styles will only override the styles that are not a requirement for postioning the item. Other styles like `color`, `radius` and others_ | ||
\*\* _the given styles will only override the styles that are not a requirement for positioning the item. Other styles like `color`, `radius` and others_ | ||
These properties can be override using the prop argument with proprties: | ||
These properties can be override using the prop argument with properties: | ||
@@ -731,6 +646,6 @@ * className: class names to be added | ||
{({ styles, date }) => | ||
// date is value of current date. Use this to render special styles for the marker | ||
// or any other custom logic based on date: | ||
// e.g. styles = {...styles, backgroundColor: isDateInAfternoon(date) ? 'red' : 'limegreen'} | ||
return <div style={styles} /> | ||
// date is value of current date. Use this to render special styles for the marker | ||
// or any other custom logic based on date: | ||
// e.g. styles = {...styles, backgroundColor: isDateInAfternoon(date) ? 'red' : 'limegreen'} | ||
<div style={styles} /> | ||
} | ||
@@ -758,5 +673,3 @@ </TodayMarker> | ||
<CustomMarker date={today}> | ||
{({ styles, date }) => | ||
return <div style={styles} /> | ||
} | ||
{({ styles, date }) => <div style={styles} />} | ||
</CustomMarker> | ||
@@ -791,6 +704,6 @@ | ||
{({ styles, date }) => | ||
// date is value of current date. Use this to render special styles for the marker | ||
// or any other custom logic based on date: | ||
// e.g. styles = {...styles, backgroundColor: isDateInAfternoon(date) ? 'red' : 'limegreen'} | ||
return <div style={styles} /> | ||
// date is value of current date. Use this to render special styles for the marker | ||
// or any other custom logic based on date: | ||
// e.g. styles = {...styles, backgroundColor: isDateInAfternoon(date) ? 'red' : 'limegreen'} | ||
<div style={styles} /> | ||
} | ||
@@ -828,3 +741,3 @@ </CursorMarker> | ||
</SidebarHeader> | ||
<DateHeader primaryHeader /> | ||
<DateHeader unit="primaryHeader" /> | ||
<DateHeader /> | ||
@@ -850,4 +763,4 @@ </TimelineHeaders> | ||
| `calendarHeaderClassName`| `string`| applied to the root component of the calendar headers -scrolable div- `DateHeader` and `CustomHeader`)| | ||
| `headerRef` | `function` | used to get the ref of the header element | ||
### `SidebarHeader` | ||
@@ -863,2 +776,3 @@ | ||
| `children` | `Function`| function as a child component to render the header| | ||
| `headerData` | `any`| Contextual data to be passed to the item renderer as a data prop | | ||
@@ -876,2 +790,3 @@ #### Child function renderer | ||
| `getRootProps` | `function(props={})` | returns the props you should apply to the root div element.| | ||
| `data` | `any` | Contextual data passed by `headerData` prop| | ||
@@ -902,8 +817,8 @@ * `getRootProps` The returned props are: | ||
</SidebarHeader> | ||
<SidebarHeader variant="right"> | ||
{({ getRootProps }) => { | ||
return <div {...getRootProps()}>Right</div> | ||
<SidebarHeader variant="right" headerData={{someData: 'extra'}}> | ||
{({ getRootProps, data }) => { | ||
return <div {...getRootProps()}>Right {data.someData}</div> | ||
}} | ||
</SidebarHeader> | ||
<DateHeader primaryHeader /> | ||
<DateHeader unit="primaryHeader" /> | ||
<DateHeader /> | ||
@@ -914,2 +829,4 @@ </TimelineHeaders> | ||
_Note_ : the Child function renderer can be a component or a function for convenience | ||
### `DateHeader` | ||
@@ -926,35 +843,43 @@ | ||
| `className` | `string`| applied to the root of the header| | ||
| `unit`| `second`, `minute`, `hour`, `day`, `week`, `month`, `year` | intervals between columns | | ||
| `primaryHeader`| `boolean` | main header with interval unit larger than timeline unit by 1 | | ||
| `secondaryHeader` | `boolean` (`true` by default) | sub header with interval equal to timeline unit | | ||
| `labelFormat` | `Function` or `object` or `string`| controls the how to format the interval label | | ||
| `intervalRenderer`| `Function`| render prop to render each interval in the header | | ||
| `unit`| `second`, `minute`, `hour`, `day`, `week`, `month`, `year` or `primaryHeader` | intervals between columns | | ||
| `labelFormat` | `Function` or `string`| controls the how to format the interval label | | ||
| `intervalRenderer`| `Function`| render prop to render each interval in the header | ||
| `headerData` | `any`| Contextual data to be passed to the item renderer as a data prop | | ||
| `height` | `number` default (30)| height of the header in pixels | | ||
_Note_: passing `primaryHeader` to unit the header will act as the main header with interval unit larger than timeline unit by 1 | ||
#### Interval unit | ||
intervals are decided through three props: `unit`, `primaryHeader` and `secondaryHeader` (default true). `secondaryHeader` is the default if no prop are set. The unit of the intervals will be the same the timeline and a special style is matches the default style of the secondary header from when no custom headers are applied. | ||
intervals are decided through the prop: `unit`. By default, the unit of the intervals will be the same the timeline. | ||
If `primaryHeader` is set to true, it will override `secondaryHeader` and the unit if the timeline will be larger by 1 of the timeline unit. The default style will match the primary header from when no custom headers are applied. | ||
If `primaryHeader` is passed to unit, it will override the unit with a unit a unit larger by 1 of the timeline unit. | ||
If `unit` is set, it will override both `primaryHeader` and `secondaryHeader`. The unit of the header will be the unit passed though the prop and can be any `unit of time` from `momentjs`. The default style will match the primary header from when no custom headers are applied. | ||
If `unit` is set, the unit of the header will be the unit passed though the prop and can be any `unit of time` from `momentjs`. | ||
#### Label format | ||
To format each interval label you can use 3 types of props to format which are: | ||
To format each interval label you can use 2 types of props to format which are: | ||
- `string`: if a string was passed it will be passed to `startTime` method `format` which is a `momentjs` object . | ||
- `object`: this will give you more flexibility to format the label with respect to `labelWidth`. Internally the `startTime` will be formated with the string corresponding to `formatObject[unit][range]` | ||
The object will be in the following type: | ||
- `Function`: This is the more powerful method and offers the most control over what is rendered. The returned `string` will be rendered inside the interval | ||
```typescript | ||
type unit = `second` | `minute` | `hour` | `day` | `week` | `month` | `year` | ||
interface LabelFormat { | ||
[unit]: { | ||
long: string, | ||
mediumLong: string, | ||
medium: string, | ||
short: string | ||
} | ||
} | ||
type Unit = `second` | `minute` | `hour` | `day` | `month` | `year` | ||
([startTime, endTime] : [Moment, Moment], unit: Unit, labelWidth: number, formatOptions: LabelFormat = defaultFormat ) => string | ||
``` | ||
##### Default format | ||
by default we provide a responsive format for the dates based on the label width. it follows the following rules: | ||
The `long`, `mediumLong`, `medium` and `short` will be be decided through the `labelWidth` value according to where it lays upon the following scale: | ||
``` | ||
|-----`short`-----50px-----`medium`-----100px-----`mediumLong`-----150px--------`long`----- | ||
``` | ||
```typescript | ||
// default format object | ||
@@ -995,15 +920,5 @@ const format : LabelFormat = { | ||
The `long`, `mediumLong`, `medium` and `short` will be be decided through the `labelWidth` value according to where it lays upon the following scale: | ||
_Note_: this is only an implementation of the function param. You can do this on your own easily | ||
``` | ||
|-----`short`-----50px-----`medium`-----100px-----`mediumLong`-----150px--------`long`----- | ||
``` | ||
- `Function`: This is the more powerful method and offers the most control over what is rendered. The returned `string` will be rendered inside the interval | ||
```typescript | ||
type Unit = `second` | `minute` | `hour` | `day` | `month` | `year` | ||
([startTime, endTime] : [Moment, Moment], unit: Unit, labelWidth: number, formatOptions: LabelFormat = defaultFormat ) => string | ||
``` | ||
#### intervalRenderer | ||
@@ -1015,2 +930,4 @@ | ||
_Note_ : the renderProp can be a component or a function for convenience | ||
##### interval context | ||
@@ -1022,3 +939,3 @@ | ||
| ------------------ | -------- | ---------------------------------------------------- | | ||
| `interval` | `array : [Moment, Moment]` | an tuple array conating two moment object the first `startTime` and the second `endTime`| | ||
| `interval` | `object : {startTime, endTime, labelWidth, left}` | an object containing data related to the interval| | ||
| `intervalText` | `string` | the string returned from `labelFormat` prop | | ||
@@ -1046,2 +963,6 @@ | ||
##### data | ||
data passed through headerData | ||
#### example | ||
@@ -1063,3 +984,3 @@ | ||
</SidebarHeader> | ||
<DateHeader primaryHeader /> | ||
<DateHeader unit="primaryHeader" /> | ||
<DateHeader /> | ||
@@ -1070,5 +991,7 @@ <DateHeader | ||
style={{ height: 50 }} | ||
intervalRenderer={({ getIntervalProps, intervalContext }) => { | ||
data={{someData: 'example'}} | ||
intervalRenderer={({ getIntervalProps, intervalContext, data }) => { | ||
return <div {...getIntervalProps()}> | ||
{intervalContext.intervalText} | ||
{data.example} | ||
</div> | ||
@@ -1205,2 +1128,4 @@ }} | ||
| `children` | `Function`| function as a child component to render the header| | ||
| `headerData` | `any`| Contextual data to be passed to the item renderer as a data prop | | ||
| `height` | `number` default (30)| height of the header in pixels | | ||
@@ -1217,2 +1142,4 @@ #### unit | ||
_Note_ : the Child function renderer can be a component or a function for convenience | ||
``` | ||
@@ -1233,3 +1160,5 @@ ({ | ||
getIntervalProps: this.getIntervalProps, | ||
showPeriod | ||
showPeriod, | ||
//contextual data passed through headerData | ||
data, | ||
})=> React.Node | ||
@@ -1247,7 +1176,7 @@ ``` | ||
| ------------------ | -------- | ---------------------------------------------------- | | ||
| `timelineWidth` | `array : [Moment, Moment]` | an tuple array conating two moment object the first `startTime` and the second `endTime`| | ||
| `visibleTimeStart` | `string` | the string returned from `labelFormat` prop | | ||
| `visibleTimeEnd` | `array : [Moment, Moment]` | an tuple array conating two moment object the first `startTime` and the second `endTime`| | ||
| `canvasTimeStart` | `string` | the string returned from `labelFormat` prop | | ||
| `canvasTimeEnd` | `array : [Moment, Moment]` | an tuple array conating two moment object the first `startTime` and the second `endTime`| | ||
| `timelineWidth` | `number` | width of timeline| | ||
| `visibleTimeStart` | `number` | unix milliseconds of start visible time | | ||
| `visibleTimeEnd` | `number` | unix milliseconds of end visible time| | ||
| `canvasTimeStart` | `number` | unix milliseconds of start buffer time | | ||
| `canvasTimeEnd` | `number` |unix milliseconds of end buffer time| | ||
@@ -1289,3 +1218,5 @@ ###### Header context | ||
##### data: | ||
pass through the `headerData` prop content | ||
@@ -1308,5 +1239,5 @@ #### example | ||
</SidebarHeader> | ||
<DateHeader primaryHeader /> | ||
<DateHeader unit="primaryHeader" /> | ||
<DateHeader /> | ||
<CustomHeader unit="year"> | ||
<CustomHeader headerData={{someData: 'data'}} unit="year"> | ||
{({ | ||
@@ -1316,3 +1247,4 @@ headerContext: { intervals }, | ||
getIntervalProps, | ||
showPeriod | ||
showPeriod, | ||
data, | ||
}) => { | ||
@@ -1363,3 +1295,3 @@ return ( | ||
Now you can use item renderer for rendering items with different colors [itemRenderer](https://github.com/namespace-ee/react-calendar-timeline#itemrenderer). | ||
Now you can use item renderer for rendering items with different colors [itemRenderer](https://github.com/namespace-ee/react-calendar-timeline#itemrenderer). | ||
Please refer to [examples](https://github.com/namespace-ee/react-calendar-timeline/tree/master/examples#custom-item-rendering) for a sandbox example | ||
@@ -1372,7 +1304,6 @@ | ||
To use it, you need to add two props to the `<Timeline />` component: | ||
To use it, you need to add a props to the `<Timeline />` component: | ||
```jsx | ||
rightSidebarWidth={150} | ||
rightSidebarContent={<p>Second filter</p>} | ||
``` | ||
@@ -1390,29 +1321,8 @@ | ||
If you are using Custom Headers then you need to add `SidebarHeader` component under `TimelineHeader` with variant `right` | ||
## The timeline header doesn't fix to the top of the container when I scroll down. | ||
There are two causes of this: | ||
you need to add sticky to the header like [this example](https://github.com/FoothillSolutions/react-calendar-timeline/tree/dest-build/examples#sticky-header). | ||
* you are passing `stickyHeader={false}` to the timeline component. The header by default has sticky behavior unless you tell it not to using this prop. | ||
* the browser you are viewing the timeline in doesn't support `position: sticky`. In this scenario, you will need to polyfill this behavior using the `headerRef`. | ||
In this example, we use [stickyfill](https://github.com/wilddeer/stickyfill) as our sticky polyfill | ||
```jsx | ||
// add a handler in your parent component that accepts a DOM element | ||
// with this element, pass the element into a polyfill library | ||
handleHeaderRef = (el) => { | ||
// polyfill dom element with stickyfill | ||
Stickyfill.addOne(el) | ||
} | ||
// in render, pass this handler to the `headerRef` prop: | ||
render() { | ||
<Timeline | ||
//other props | ||
headerRef={this.handleHeaderRef} | ||
/> | ||
} | ||
``` | ||
@@ -1498,1 +1408,4 @@ | ||
--> | ||
## License | ||
[MIT licensed](/LICENSE.md). |
@@ -15,2 +15,3 @@ import Timeline from './lib/Timeline' | ||
export {default as ItemHeader} from './lib/headers/ItemHeader' | ||
export * from './lib/utility/calendar' | ||
export default Timeline |
@@ -5,13 +5,19 @@ import PropTypes from 'prop-types' | ||
import { iterateTimes } from '../utility/calendar' | ||
import { TimelineStateConsumer } from '../timeline/TimelineStateContext' | ||
export default class Columns extends Component { | ||
const passThroughPropTypes = { | ||
canvasTimeStart: PropTypes.number.isRequired, | ||
canvasTimeEnd: PropTypes.number.isRequired, | ||
canvasWidth: PropTypes.number.isRequired, | ||
lineCount: PropTypes.number.isRequired, | ||
minUnit: PropTypes.string.isRequired, | ||
timeSteps: PropTypes.object.isRequired, | ||
height: PropTypes.number.isRequired, | ||
verticalLineClassNamesForTime: PropTypes.func | ||
} | ||
class Columns extends Component { | ||
static propTypes = { | ||
canvasTimeStart: PropTypes.number.isRequired, | ||
canvasTimeEnd: PropTypes.number.isRequired, | ||
canvasWidth: PropTypes.number.isRequired, | ||
lineCount: PropTypes.number.isRequired, | ||
minUnit: PropTypes.string.isRequired, | ||
timeSteps: PropTypes.object.isRequired, | ||
height: PropTypes.number.isRequired, | ||
verticalLineClassNamesForTime: PropTypes.func | ||
...passThroughPropTypes, | ||
getLeftOffsetFromDate: PropTypes.func.isRequired | ||
} | ||
@@ -41,3 +47,4 @@ | ||
height, | ||
verticalLineClassNamesForTime | ||
verticalLineClassNamesForTime, | ||
getLeftOffsetFromDate | ||
} = this.props | ||
@@ -54,9 +61,4 @@ const ratio = canvasWidth / (canvasTimeEnd - canvasTimeStart) | ||
(time, nextTime) => { | ||
const left = Math.round((time.valueOf() - canvasTimeStart) * ratio, -2) | ||
const minUnitValue = time.get(minUnit === 'day' ? 'date' : minUnit) | ||
const firstOfType = minUnitValue === (minUnit === 'day' ? 1 : 0) | ||
const lineWidth = firstOfType ? 2 : 1 | ||
const labelWidth = | ||
Math.ceil((nextTime.valueOf() - time.valueOf()) * ratio) - lineWidth | ||
const leftPush = firstOfType ? -1 : 0 | ||
@@ -80,2 +82,4 @@ let classNamesForTime = [] | ||
const left = getLeftOffsetFromDate(time.valueOf()) | ||
const right = getLeftOffsetFromDate(nextTime.valueOf()) | ||
lines.push( | ||
@@ -88,4 +92,4 @@ <div | ||
top: '0px', | ||
left: `${left + leftPush}px`, | ||
width: `${labelWidth}px`, | ||
left: `${left}px`, | ||
width: `${right - left}px`, | ||
height: `${height}px` | ||
@@ -100,2 +104,18 @@ }} | ||
} | ||
} | ||
} | ||
const ColumnsWrapper = ({ ...props }) => { | ||
return ( | ||
<TimelineStateConsumer> | ||
{({ getLeftOffsetFromDate }) => ( | ||
<Columns getLeftOffsetFromDate={getLeftOffsetFromDate} {...props} /> | ||
)} | ||
</TimelineStateConsumer> | ||
) | ||
} | ||
ColumnsWrapper.defaultProps = { | ||
...passThroughPropTypes | ||
} | ||
export default ColumnsWrapper |
@@ -0,0 +0,0 @@ export const defaultKeys = { |
export const LEFT_VARIANT= 'left' | ||
export const RIGHT_VARIANT= 'right' | ||
@@ -5,3 +5,3 @@ import React from 'react' | ||
import { TimelineStateConsumer } from '../timeline/TimelineStateContext' | ||
import { iterateTimes } from '../utility/calendar' | ||
import { iterateTimes, calculateXPositionForTime } from '../utility/calendar' | ||
@@ -13,4 +13,4 @@ export class CustomHeader extends React.Component { | ||
unit: PropTypes.string.isRequired, | ||
//Timeline context | ||
timeSteps: PropTypes.object.isRequired, | ||
//Timeline context | ||
visibleTimeStart: PropTypes.number.isRequired, | ||
@@ -22,3 +22,5 @@ visibleTimeEnd: PropTypes.number.isRequired, | ||
showPeriod: PropTypes.func.isRequired, | ||
props: PropTypes.object | ||
headerData: PropTypes.object, | ||
getLeftOffsetFromDate: PropTypes.func.isRequired, | ||
height: PropTypes.number.isRequired, | ||
} | ||
@@ -33,9 +35,6 @@ constructor(props) { | ||
timeSteps, | ||
showPeriod | ||
showPeriod, | ||
getLeftOffsetFromDate | ||
} = props | ||
const ratio = this.calculateRatio( | ||
canvasWidth, | ||
canvasTimeEnd, | ||
canvasTimeStart | ||
) | ||
const intervals = this.getHeaderIntervals({ | ||
@@ -48,8 +47,7 @@ canvasTimeStart, | ||
showPeriod, | ||
ratio, | ||
getLeftOffsetFromDate | ||
}) | ||
this.state = { | ||
intervals, | ||
ratio | ||
intervals | ||
} | ||
@@ -66,3 +64,4 @@ } | ||
nextProps.showPeriod !== this.props.showPeriod || | ||
nextProps.children !== this.props.children | ||
nextProps.children !== this.props.children || | ||
nextProps.headerData !== this.props.headerData | ||
) { | ||
@@ -89,9 +88,6 @@ return true | ||
timeSteps, | ||
showPeriod | ||
showPeriod, | ||
getLeftOffsetFromDate | ||
} = nextProps | ||
const ratio = this.calculateRatio( | ||
canvasWidth, | ||
canvasTimeEnd, | ||
canvasTimeStart | ||
) | ||
const intervals = this.getHeaderIntervals({ | ||
@@ -104,6 +100,6 @@ canvasTimeStart, | ||
showPeriod, | ||
ratio, | ||
getLeftOffsetFromDate | ||
}) | ||
this.setState({ intervals, ratio }) | ||
this.setState({ intervals }) | ||
} | ||
@@ -117,3 +113,3 @@ } | ||
timeSteps, | ||
ratio, | ||
getLeftOffsetFromDate | ||
}) => { | ||
@@ -127,9 +123,10 @@ const intervals = [] | ||
(startTime, endTime) => { | ||
const labelWidth = Math.ceil( | ||
(endTime.valueOf() - startTime.valueOf()) * ratio | ||
) | ||
const left = getLeftOffsetFromDate(startTime.valueOf()) | ||
const right = getLeftOffsetFromDate(endTime.valueOf()) | ||
const width = right - left | ||
intervals.push({ | ||
startTime, | ||
endTime, | ||
labelWidth | ||
labelWidth: width, | ||
left | ||
}) | ||
@@ -141,12 +138,10 @@ } | ||
rootProps = { | ||
style: { | ||
position: 'relative' | ||
} | ||
} | ||
getRootProps = (props = {}) => { | ||
const { style } = props | ||
return { | ||
style: Object.assign({}, style ? style : {}, this.rootProps.style) | ||
style: Object.assign({}, style ? style : {}, { | ||
position: 'relative', | ||
width: this.props.canvasWidth, | ||
height: this.props.height, | ||
}) | ||
} | ||
@@ -157,4 +152,5 @@ } | ||
const { interval, style } = props | ||
if (!interval) throw new Error("you should provide interval to the prop getter") | ||
const { startTime, labelWidth } = interval | ||
if (!interval) | ||
throw new Error('you should provide interval to the prop getter') | ||
const { startTime, labelWidth, left } = interval | ||
return { | ||
@@ -167,3 +163,3 @@ style: this.getIntervalStyle({ | ||
unit: this.props.unit, | ||
ratio: this.state.ratio | ||
left | ||
}), | ||
@@ -174,14 +170,6 @@ key: `label-${startTime.valueOf()}` | ||
calculateRatio(canvasWidth, canvasTimeEnd, canvasTimeStart) { | ||
return canvasWidth / (canvasTimeEnd - canvasTimeStart) | ||
} | ||
getIntervalStyle = ({ startTime, canvasTimeStart, ratio, unit, labelWidth, style, }) => { | ||
const left = Math.round((startTime.valueOf() - canvasTimeStart) * ratio) | ||
const unitValue = startTime.get(unit === 'day' ? 'date' : unit) | ||
const firstOfType = unitValue === (unit === 'day' ? 1 : 0) | ||
const leftCorrect = firstOfType ? 1 : 0 | ||
getIntervalStyle = ({ left, labelWidth, style }) => { | ||
return { | ||
...style, | ||
left: left - leftCorrect, | ||
left, | ||
width: labelWidth, | ||
@@ -200,3 +188,4 @@ position: 'absolute' | ||
visibleTimeStart, | ||
visibleTimeEnd | ||
visibleTimeEnd, | ||
headerData, | ||
} = this.props | ||
@@ -218,3 +207,4 @@ //TODO: only evaluate on changing params | ||
getIntervalProps: this.getIntervalProps, | ||
showPeriod | ||
showPeriod, | ||
data: headerData, | ||
} | ||
@@ -225,9 +215,10 @@ } | ||
const props = this.getStateAndHelpers() | ||
return this.props.children(props, this.props.props) | ||
const Renderer = this.props.children | ||
return <Renderer {...props}/> | ||
} | ||
} | ||
const CustomHeaderWrapper = ({ children, unit, props }) => ( | ||
const CustomHeaderWrapper = ({ children, unit, headerData, height }) => ( | ||
<TimelineStateConsumer> | ||
{({ getTimelineState, showPeriod }) => { | ||
{({ getTimelineState, showPeriod, getLeftOffsetFromDate }) => { | ||
const timelineState = getTimelineState() | ||
@@ -243,3 +234,5 @@ return ( | ||
{...timelineState} | ||
props={props} | ||
headerData={headerData} | ||
getLeftOffsetFromDate={getLeftOffsetFromDate} | ||
height={height} | ||
/> | ||
@@ -256,5 +249,10 @@ )} | ||
unit: PropTypes.string, | ||
props: PropTypes.object, | ||
headerData: PropTypes.object, | ||
height: PropTypes.number, | ||
} | ||
CustomHeaderWrapper.defaultProps = { | ||
height: 30, | ||
} | ||
export default CustomHeaderWrapper |
@@ -11,4 +11,2 @@ import React from 'react' | ||
static propTypes = { | ||
primaryHeader: PropTypes.bool, | ||
secondaryHeader: PropTypes.bool, | ||
unit: PropTypes.string, | ||
@@ -24,12 +22,31 @@ style: PropTypes.object, | ||
intervalRenderer: PropTypes.func, | ||
props: PropTypes.object, | ||
headerData: PropTypes.object, | ||
height: PropTypes.number, | ||
} | ||
getHeaderUnit = () => { | ||
if (this.props.unit) { | ||
if (this.props.unit === 'primaryHeader') { | ||
return getNextUnit(this.props.timelineUnit) | ||
} else if (this.props.unit) { | ||
return this.props.unit | ||
} else if (this.props.primaryHeader) { | ||
return getNextUnit(this.props.timelineUnit) | ||
} | ||
return this.props.timelineUnit | ||
} | ||
getRootStyle = () => { | ||
return { | ||
height: 30, | ||
...this.props.style | ||
} | ||
} | ||
getLabelFormat(interval, unit, labelWidth) { | ||
const { labelFormat } = this.props | ||
if (typeof labelFormat === 'string') { | ||
const startTime = interval[0] | ||
return startTime.format(labelFormat) | ||
} else if (typeof labelFormat === 'function') { | ||
return labelFormat(interval, unit, labelWidth) | ||
} else { | ||
return this.props.timelineUnit | ||
throw new Error('labelFormat should be function or string') | ||
} | ||
@@ -40,5 +57,5 @@ } | ||
const unit = this.getHeaderUnit() | ||
const {props} = this.props; | ||
const { headerData, height } = this.props | ||
return ( | ||
<CustomHeader unit={unit} props={props}> | ||
<CustomHeader unit={unit} height={height} headerData={headerData}> | ||
{({ | ||
@@ -48,4 +65,5 @@ headerContext: { intervals }, | ||
getIntervalProps, | ||
showPeriod | ||
}, props) => { | ||
showPeriod, | ||
data | ||
}) => { | ||
const unit = this.getHeaderUnit() | ||
@@ -55,2 +73,3 @@ | ||
<div | ||
data-testid={`dateHeader`} | ||
className={this.props.className} | ||
@@ -72,7 +91,6 @@ {...getRootProps({ style: this.getRootStyle() })} | ||
intervalText={intervalText} | ||
primaryHeader={!!this.props.primaryHeader} | ||
secondaryHeader={!!this.props.secondaryHeader} | ||
primaryHeader={this.props.unit === 'primaryHeader'} | ||
getIntervalProps={getIntervalProps} | ||
intervalRenderer={this.props.intervalRenderer} | ||
props={props} | ||
headerData={data} | ||
/> | ||
@@ -87,28 +105,5 @@ ) | ||
} | ||
getRootStyle = () => { | ||
return { | ||
height: 30, | ||
...this.props.style | ||
} | ||
} | ||
getLabelFormat(interval, unit, labelWidth) { | ||
const { labelFormat } = this.props | ||
if (typeof labelFormat === 'string') { | ||
const startTime = interval[0] | ||
return startTime.format(labelFormat) | ||
} else if (typeof labelFormat === 'object') { | ||
return formatLabel(interval, unit, labelWidth, labelFormat) | ||
} else if (typeof labelFormat === 'function') { | ||
return labelFormat(interval, unit, labelWidth) | ||
} else { | ||
throw new Error('labelFormat should be function, object or string') | ||
} | ||
} | ||
} | ||
const DateHeaderWrapper = ({ | ||
primaryHeader, | ||
secondaryHeader, | ||
unit, | ||
@@ -119,3 +114,4 @@ labelFormat, | ||
intervalRenderer, | ||
props, | ||
headerData, | ||
height, | ||
}) => ( | ||
@@ -128,4 +124,2 @@ <TimelineStateConsumer> | ||
timelineUnit={timelineState.timelineUnit} | ||
primaryHeader={primaryHeader} | ||
secondaryHeader={secondaryHeader} | ||
unit={unit} | ||
@@ -136,3 +130,4 @@ labelFormat={labelFormat} | ||
intervalRenderer={intervalRenderer} | ||
props={props} | ||
headerData={headerData} | ||
height={height} | ||
/> | ||
@@ -147,4 +142,2 @@ ) | ||
className: PropTypes.string, | ||
primaryHeader: PropTypes.bool, | ||
secondaryHeader: PropTypes.bool, | ||
unit: PropTypes.string, | ||
@@ -157,7 +150,7 @@ labelFormat: PropTypes.oneOfType([ | ||
intervalRenderer: PropTypes.func, | ||
props: PropTypes.object, | ||
headerData: PropTypes.object, | ||
height: PropTypes.number, | ||
} | ||
DateHeaderWrapper.defaultProps = { | ||
secondaryHeader: true, | ||
labelFormat: formatLabel | ||
@@ -164,0 +157,0 @@ } |
@@ -5,4 +5,2 @@ import React from 'react' | ||
import { noop } from '../utility/generic' | ||
import { LEFT_SIDEBAR_ID, RIGHT_SIDEBAR_ID } from './constants' | ||
import { getNextUnit } from '../utility/calendar' | ||
@@ -9,0 +7,0 @@ const defaultContextState = { |
@@ -14,28 +14,6 @@ import React from 'react' | ||
primaryHeader: PropTypes.bool.isRequired, | ||
secondaryHeader: PropTypes.bool.isRequired, | ||
getIntervalProps: PropTypes.func.isRequired, | ||
props: PropTypes.object | ||
headerData: PropTypes.object | ||
} | ||
getIntervalStyle = () => { | ||
return { | ||
display: 'flex', | ||
alignItems: 'center', | ||
justifyContent: 'center', | ||
backgroundColor: | ||
this.props.secondaryHeader && !this.props.primaryHeader | ||
? 'rgb(240, 240, 240)' | ||
: 'initial', | ||
height: '100%', | ||
borderLeft: this.props.primaryHeader | ||
? '1px solid #bbb' | ||
: '2px solid #bbb', | ||
borderRight: this.props.primaryHeader ? '1px solid #bbb' : 'none', | ||
borderBottom: '1px solid #bbb', | ||
color: this.props.primaryHeader ? '#fff' : 'initial', | ||
cursor: 'pointer', | ||
fontSize: '14px' | ||
} | ||
} | ||
onIntervalClick = () => { | ||
@@ -53,3 +31,3 @@ const { primaryHeader, interval, unit, showPeriod } = this.props | ||
getIntervalProps = (props={}) => { | ||
getIntervalProps = (props = {}) => { | ||
return { | ||
@@ -65,16 +43,23 @@ ...this.props.getIntervalProps({ | ||
render() { | ||
const { intervalText, interval, intervalRenderer, props } = this.props | ||
if (intervalRenderer) | ||
return intervalRenderer({ | ||
getIntervalProps: this.getIntervalProps, | ||
intervalContext: { | ||
interval, | ||
intervalText | ||
} | ||
}, props) | ||
const { intervalText, interval, intervalRenderer, headerData } = this.props | ||
const Renderer = intervalRenderer | ||
if (Renderer) { | ||
return ( | ||
<Renderer | ||
getIntervalProps={this.getIntervalProps} | ||
intervalContext={{ | ||
interval, | ||
intervalText | ||
}} | ||
data={headerData} | ||
/> | ||
) | ||
} | ||
return ( | ||
<div | ||
data-testid="dateHeaderInterval" | ||
{...this.getIntervalProps({ | ||
style: this.getIntervalStyle() | ||
})} | ||
className={`rct-dateHeader ${this.props.primaryHeader? 'rct-dateHeader-primary' : ''}`} | ||
> | ||
@@ -81,0 +66,0 @@ <span>{intervalText}</span> |
@@ -0,0 +0,0 @@ import React from 'react' |
@@ -12,3 +12,3 @@ import React from 'react' | ||
variant: PropTypes.string, | ||
props: PropTypes.object | ||
headerData: PropTypes.object | ||
} | ||
@@ -24,4 +24,4 @@ | ||
style: { | ||
...style, | ||
width, | ||
...style | ||
} | ||
@@ -33,3 +33,4 @@ } | ||
return { | ||
getRootProps: this.getRootProps | ||
getRootProps: this.getRootProps, | ||
data: this.props.headerData, | ||
} | ||
@@ -40,7 +41,8 @@ } | ||
const props = this.getStateAndHelpers() | ||
return this.props.children(props, this.props.props) | ||
const Renderer = this.props.children | ||
return <Renderer {...props}/> | ||
} | ||
} | ||
const SidebarWrapper = ({ children, variant, props }) => ( | ||
const SidebarWrapper = ({ children, variant, headerData }) => ( | ||
<TimelineHeadersConsumer> | ||
@@ -54,3 +56,3 @@ {({ leftSidebarWidth, rightSidebarWidth }) => { | ||
variant={variant} | ||
props={props} | ||
headerData={headerData} | ||
/> | ||
@@ -65,3 +67,3 @@ ) | ||
variant: PropTypes.string, | ||
props: PropTypes.object | ||
headerData: PropTypes.object | ||
} | ||
@@ -71,5 +73,5 @@ | ||
variant: LEFT_VARIANT, | ||
children: ({ getRootProps }) => <div {...getRootProps()} /> | ||
children: ({ getRootProps }) => <div data-testid="sidebarHeader" {...getRootProps()} /> | ||
} | ||
export default SidebarWrapper |
@@ -16,3 +16,4 @@ import React from 'react' | ||
calendarHeaderClassName: PropTypes.string, | ||
width: PropTypes.number.isRequired | ||
width: PropTypes.number.isRequired, | ||
headerRef: PropTypes.func, | ||
} | ||
@@ -26,7 +27,5 @@ | ||
return { | ||
background: '#c52020', | ||
borderBottom: '1px solid #bbb', | ||
...this.props.style, | ||
display: 'flex', | ||
width: 'max-content' | ||
// width: 'max-content' | ||
} | ||
@@ -42,3 +41,2 @@ } | ||
return { | ||
border: '1px solid #bbb', | ||
...calendarHeaderStyle, | ||
@@ -50,2 +48,8 @@ overflow: 'hidden', | ||
handleRootRef = (element) => { | ||
if(this.props.headerRef){ | ||
this.props.headerRef(element) | ||
} | ||
} | ||
render() { | ||
@@ -59,12 +63,8 @@ let rightSidebarHeader | ||
React.Children.map(children, child => { | ||
if ( | ||
child.type === SidebarHeader && | ||
child.props.variant === RIGHT_VARIANT | ||
) { | ||
rightSidebarHeader = child | ||
} else if ( | ||
child.type === SidebarHeader && | ||
child.props.variant === LEFT_VARIANT | ||
) { | ||
leftSidebarHeader = child | ||
if (child.type === SidebarHeader) { | ||
if (child.props.variant === RIGHT_VARIANT) { | ||
rightSidebarHeader = child | ||
} else { | ||
leftSidebarHeader = child | ||
} | ||
} else { | ||
@@ -75,3 +75,8 @@ calendarHeaders.push(child) | ||
return ( | ||
<div style={this.getRootStyle()} className={this.props.className}> | ||
<div | ||
ref={this.handleRootRef} | ||
data-testid="headerRootDiv" | ||
style={this.getRootStyle()} | ||
className={`rct-header-root ${this.props.className}`} | ||
> | ||
{leftSidebarHeader} | ||
@@ -81,3 +86,4 @@ <div | ||
style={this.getCalendarHeaderStyle()} | ||
className={this.props.calendarHeaderClassName} | ||
className={`rct-calendar-header ${this.props.calendarHeaderClassName}`} | ||
data-testid="headerContainer" | ||
> | ||
@@ -129,5 +135,6 @@ {calendarHeaders} | ||
calendarHeaderStyle: PropTypes.object, | ||
calendarHeaderClassName: PropTypes.string | ||
calendarHeaderClassName: PropTypes.string, | ||
headerRef: PropTypes.func, | ||
} | ||
export default TimelineHeadersWrapper |
@@ -0,0 +0,0 @@ import React from 'react' |
@@ -240,3 +240,3 @@ import { Component } from 'react' | ||
.draggable({ | ||
enabled: this.props.selected | ||
enabled: this.props.selected && this.canMove() | ||
}) | ||
@@ -269,5 +269,3 @@ .styleCursor(false) | ||
this.props.item, | ||
dragTime, | ||
undefined, | ||
_get(this.props.dimensions.order.group, this.props.keys.groupIdKey) | ||
dragTime | ||
) | ||
@@ -299,5 +297,3 @@ } | ||
this.props.item, | ||
dragTime, | ||
undefined, | ||
_get(this.props.dimensions.order.group, this.props.keys.groupIdKey) | ||
dragTime | ||
) | ||
@@ -345,3 +341,2 @@ } | ||
if (this.props.moveResizeValidator) { | ||
console.log(this.props.dimensions) | ||
resizeTime = this.props.moveResizeValidator( | ||
@@ -351,4 +346,3 @@ 'resize', | ||
resizeTime, | ||
resizeEdge, | ||
_get(this.props.dimensions.order.group, this.props.keys.groupIdKey) | ||
resizeEdge | ||
) | ||
@@ -376,4 +370,3 @@ } | ||
resizeTime, | ||
resizeEdge, | ||
_get(this.props.dimensions.order.group, this.props.keys.groupIdKey) | ||
resizeEdge | ||
) | ||
@@ -399,3 +392,5 @@ } | ||
.on('tap', e => { | ||
this.actualClick(e, e.pointerType === 'mouse' ? 'click' : 'touch') | ||
if(e.pointerType !== 'mouse'){ | ||
this.actualClick(e, 'touch') | ||
} | ||
}) | ||
@@ -430,9 +425,8 @@ | ||
this.cacheDataFromProps(this.props) | ||
let { interactMounted } = this.state | ||
const couldDrag = this.props.selected && this.canMove(this.props) | ||
const couldDrag = prevProps.selected && this.canMove(prevProps) | ||
const couldResizeLeft = | ||
this.props.selected && this.canResizeLeft(this.props) | ||
prevProps.selected && this.canResizeLeft(prevProps) | ||
const couldResizeRight = | ||
this.props.selected && this.canResizeRight(this.props) | ||
prevProps.selected && this.canResizeRight(prevProps) | ||
const willBeAbleToDrag = this.props.selected && this.canMove(this.props) | ||
@@ -444,44 +438,38 @@ const willBeAbleToResizeLeft = | ||
if (this.props.selected && !interactMounted) { | ||
this.mountInteract() | ||
interactMounted = true | ||
if(!!this.item){ | ||
if (this.props.selected && !interactMounted) { | ||
this.mountInteract() | ||
interactMounted = true | ||
} | ||
if ( | ||
interactMounted && | ||
(couldResizeLeft !== willBeAbleToResizeLeft || | ||
couldResizeRight !== willBeAbleToResizeRight) | ||
) { | ||
const leftResize = this.props.useResizeHandle ? this.dragLeft : true | ||
const rightResize = this.props.useResizeHandle ? this.dragRight : true | ||
interact(this.item).resizable({ | ||
enabled: willBeAbleToResizeLeft || willBeAbleToResizeRight, | ||
edges: { | ||
top: false, | ||
bottom: false, | ||
left: willBeAbleToResizeLeft && leftResize, | ||
right: willBeAbleToResizeRight && rightResize | ||
} | ||
}) | ||
} | ||
if (interactMounted && couldDrag !== willBeAbleToDrag) { | ||
interact(this.item).draggable({ enabled: willBeAbleToDrag }) | ||
} | ||
} | ||
if ( | ||
interactMounted && | ||
(couldResizeLeft !== willBeAbleToResizeLeft || | ||
couldResizeRight !== willBeAbleToResizeRight) | ||
) { | ||
const leftResize = this.props.useResizeHandle ? this.dragLeft : true | ||
const rightResize = this.props.useResizeHandle ? this.dragRight : true | ||
interact(this.item).resizable({ | ||
enabled: willBeAbleToResizeLeft || willBeAbleToResizeRight, | ||
edges: { | ||
top: false, | ||
bottom: false, | ||
left: willBeAbleToResizeLeft && leftResize, | ||
right: willBeAbleToResizeRight && rightResize | ||
} | ||
}) | ||
else{ | ||
interactMounted= false; | ||
} | ||
if (interactMounted && couldDrag !== willBeAbleToDrag) { | ||
interact(this.item).draggable({ enabled: willBeAbleToDrag }) | ||
} | ||
} | ||
this.setState({ | ||
interactMounted, | ||
}) | ||
onMouseDown = e => { | ||
if (!this.state.interactMounted) { | ||
e.preventDefault() | ||
this.startedClicking = true | ||
} | ||
} | ||
onMouseUp = e => { | ||
if (!this.state.interactMounted && this.startedClicking) { | ||
this.startedClicking = false | ||
this.actualClick(e, 'click') | ||
} | ||
} | ||
onTouchStart = e => { | ||
@@ -537,4 +525,2 @@ if (!this.state.interactMounted) { | ||
className: classNames + ` ${props.className ? props.className : ''}`, | ||
onMouseDown: composeEvents(this.onMouseDown, props.onMouseDown), | ||
onMouseUp: composeEvents(this.onMouseUp, props.onMouseUp), | ||
onTouchStart: composeEvents(this.onTouchStart, props.onTouchStart), | ||
@@ -544,3 +530,4 @@ onTouchEnd: composeEvents(this.onTouchEnd, props.onTouchEnd), | ||
onContextMenu: composeEvents(this.handleContextMenu, props.onContextMenu), | ||
style: Object.assign({}, this.getItemStyle(props)) | ||
style: Object.assign({}, this.getItemStyle(props)), | ||
onClick : (e) => {this.actualClick(e, 'click')} | ||
} | ||
@@ -547,0 +534,0 @@ } |
@@ -0,0 +0,0 @@ import PropTypes from 'prop-types' |
@@ -0,0 +0,0 @@ export const overridableStyles = { |
@@ -19,7 +19,7 @@ import PropTypes from 'prop-types' | ||
return !( | ||
arraysEqual(nextProps.groups, this.props.groups) && | ||
nextProps.keys === this.props.keys && | ||
nextProps.width === this.props.width && | ||
arraysEqual(nextProps.groupHeights, this.props.groupHeights) && | ||
nextProps.height === this.props.height | ||
nextProps.height === this.props.height && | ||
arraysEqual(nextProps.groups, this.props.groups) && | ||
arraysEqual(nextProps.groupHeights, this.props.groupHeights) | ||
) | ||
@@ -26,0 +26,0 @@ } |
@@ -0,0 +0,0 @@ import React from 'react' |
@@ -0,0 +0,0 @@ import React from 'react' |
@@ -0,0 +0,0 @@ import React from 'react' |
@@ -0,0 +0,0 @@ import React from 'react' |
@@ -0,0 +0,0 @@ import React from 'react' |
@@ -0,0 +0,0 @@ import React from 'react' |
@@ -45,3 +45,3 @@ import React from 'react' | ||
return { | ||
markers: state.markers.filter(marker => marker !== newMarker) | ||
markers: state.markers.filter(marker => marker.id !== newMarker.id) | ||
} | ||
@@ -48,0 +48,0 @@ }) |
@@ -0,0 +0,0 @@ import React, { PureComponent } from 'react' |
@@ -0,0 +0,0 @@ import PropTypes from 'prop-types' |
@@ -0,0 +0,0 @@ import React, { PureComponent } from 'react' |
@@ -46,7 +46,4 @@ import PropTypes from 'prop-types' | ||
minResizeWidth: PropTypes.number, | ||
stickyOffset: PropTypes.number, | ||
stickyHeader: PropTypes.bool, | ||
lineHeight: PropTypes.number, | ||
headerLabelGroupHeight: PropTypes.number, | ||
headerLabelHeight: PropTypes.number, | ||
itemHeightRatio: PropTypes.number, | ||
@@ -65,3 +62,3 @@ | ||
stackItems: PropTypes.bool, | ||
stackItems: PropTypes.oneOf([false,'space', 'lines']), | ||
@@ -167,2 +164,3 @@ traditionalZoom: PropTypes.bool, | ||
width: PropTypes.number, | ||
onUpdateMove: PropTypes.func, | ||
} | ||
@@ -175,7 +173,4 @@ | ||
minResizeWidth: 20, | ||
stickyOffset: 0, | ||
stickyHeader: true, | ||
lineHeight: 30, | ||
headerLabelGroupHeight: 30, | ||
headerLabelHeight: 30, | ||
itemHeightRatio: 0.65, | ||
@@ -245,3 +240,4 @@ | ||
selected: null | ||
selected: null, | ||
onUpdateMove: null, | ||
} | ||
@@ -282,2 +278,6 @@ | ||
this.getSelected = this.getSelected.bind(this) | ||
this.hasSelectedItem = this.hasSelectedItem.bind(this) | ||
this.isItemSelected= this.isItemSelected.bind(this) | ||
let visibleTimeStart = null | ||
@@ -599,3 +599,3 @@ let visibleTimeEnd = null | ||
if ( | ||
this.state.selectedItem === item || | ||
this.isItemSelected(item) || | ||
(this.props.itemTouchSendsClick && clickType === 'touch') | ||
@@ -648,2 +648,3 @@ ) { | ||
canvasTimeStart, | ||
canvasTimeEnd, | ||
@@ -680,3 +681,5 @@ getCanvasWidth(width), | ||
const keys = this.props.keys | ||
if(this.props.onUpdateMove){ | ||
this.props.onUpdateMove(item, dragTime, newGroupOrder, 'move') | ||
} | ||
this.setState({ | ||
@@ -698,2 +701,5 @@ draggingItem: item, | ||
resizingItem = (item, resizeTime, edge) => { | ||
if(this.props.onUpdateMove){ | ||
this.props.onUpdateMove(item, resizeTime, undefined, 'resize', edge) | ||
} | ||
this.setState({ | ||
@@ -737,3 +743,3 @@ resizingItem: item, | ||
// shouldnt this be handled by the user, as far as when to deselect an item? | ||
if (this.state.selectedItem) { | ||
if (this.hasSelectedItem()) { | ||
this.selectItem(null) | ||
@@ -900,3 +906,2 @@ } | ||
height, | ||
headerHeight, | ||
visibleTimeStart, | ||
@@ -928,8 +933,4 @@ visibleTimeEnd, | ||
groupTops: groupTops, | ||
selected: | ||
this.state.selectedItem && !this.props.selected | ||
? [this.state.selectedItem] | ||
: this.props.selected || [], | ||
selected: this.getSelected(), | ||
height: height, | ||
headerHeight: headerHeight, | ||
minUnit: minUnit, | ||
@@ -963,3 +964,3 @@ timeSteps: timeSteps | ||
<SidebarHeader /> | ||
<DateHeader primaryHeader /> | ||
<DateHeader unit="primaryHeader" /> | ||
<DateHeader /> | ||
@@ -975,3 +976,18 @@ {this.props.rightSidebarWidth ? <SidebarHeader variant="right"/> : null} | ||
} | ||
getSelected() { | ||
return this.state.selectedItem && !this.props.selected | ||
? [this.state.selectedItem] | ||
: this.props.selected || []; | ||
} | ||
hasSelectedItem(){ | ||
if(!Array.isArray(this.props.selected)) return !!this.state.selectedItem | ||
return this.props.selected.length > 0 | ||
} | ||
isItemSelected(itemId){ | ||
const selectedItems = this.getSelected() | ||
return selectedItems.some(i => i === itemId) | ||
} | ||
render() { | ||
@@ -981,4 +997,2 @@ const { | ||
groups, | ||
headerLabelGroupHeight, | ||
headerLabelHeight, | ||
sidebarWidth, | ||
@@ -1003,3 +1017,2 @@ rightSidebarWidth, | ||
const minUnit = getMinUnit(zoom, width, timeSteps) | ||
const headerHeight = headerLabelGroupHeight + headerLabelHeight | ||
@@ -1092,3 +1105,2 @@ const isInteractingWithItem = !!draggingItem || !!resizingItem | ||
height, | ||
headerHeight | ||
)} | ||
@@ -1105,3 +1117,2 @@ {this.rows(canvasWidth, groupHeights, groups)} | ||
height, | ||
headerHeight, | ||
visibleTimeStart, | ||
@@ -1108,0 +1119,0 @@ visibleTimeEnd, |
@@ -0,0 +0,0 @@ import React from 'react' |
@@ -72,3 +72,4 @@ import moment from 'moment' | ||
let nextTime = moment(time).add(timeSteps[unit] || 1, `${unit}s`) | ||
callback(time, nextTime) | ||
let endTime = moment(time).endOf(`${unit}s`) | ||
callback(time, endTime) | ||
time = nextTime | ||
@@ -152,6 +153,9 @@ } | ||
day: 'month', | ||
month: 'year' | ||
month: 'year', | ||
year: 'year' | ||
} | ||
return nextUnits[unit] || '' | ||
if (!nextUnits[unit]) { | ||
throw new Error(`unit ${unit} in not acceptable`) | ||
} | ||
return nextUnits[unit] | ||
} | ||
@@ -302,2 +306,26 @@ | ||
/** | ||
* Calculate the position of a given item for a group that each in a line | ||
* is being stacked | ||
*/ | ||
export function groupStackInLines( | ||
lineHeight, | ||
item, | ||
items, | ||
groupHeight, | ||
groupTop, | ||
itemIndex | ||
) { | ||
// calculate non-overlapping positions | ||
let verticalMargin = lineHeight - item.dimensions.height | ||
if (item.dimensions.stack && item.dimensions.top === null) { | ||
item.dimensions.top = groupTop + verticalMargin + itemIndex * lineHeight | ||
} | ||
return { | ||
groupHeight: lineHeight * items.length, | ||
verticalMargin, | ||
itemTop: item.dimensions.top | ||
} | ||
} | ||
/** | ||
* Calculate the position of a given item for a group that | ||
@@ -316,3 +344,3 @@ * is being stacked | ||
let curHeight = groupHeight | ||
let verticalMargin = lineHeight - item.dimensions.height | ||
let verticalMargin = (lineHeight - item.dimensions.height) / 2 | ||
if (item.dimensions.stack && item.dimensions.top === null) { | ||
@@ -343,3 +371,3 @@ item.dimensions.top = groupTop + verticalMargin | ||
curHeight, | ||
item.dimensions.top + item.dimensions.height - groupTop | ||
item.dimensions.top + item.dimensions.height + verticalMargin - groupTop | ||
) | ||
@@ -354,3 +382,2 @@ } | ||
} | ||
} | ||
@@ -405,3 +432,3 @@ | ||
} else { | ||
groupHeights.push(Math.max(groupHeight + verticalMargin, lineHeight)) | ||
groupHeights.push(Math.max(groupHeight, lineHeight)) | ||
} | ||
@@ -417,9 +444,14 @@ } | ||
/** | ||
* | ||
* @param {*} itemsDimensions | ||
* @param {*} isGroupStacked | ||
* @param {*} lineHeight | ||
* @param {*} groupTop | ||
* | ||
* @param {*} itemsDimensions | ||
* @param {*} isGroupStacked | ||
* @param {*} lineHeight | ||
* @param {*} groupTop | ||
*/ | ||
export function stackGroup(itemsDimensions, isGroupStacked, lineHeight, groupTop) { | ||
export function stackGroup( | ||
itemsDimensions, | ||
isGroupStacked, | ||
lineHeight, | ||
groupTop | ||
) { | ||
var groupHeight = 0 | ||
@@ -430,3 +462,3 @@ var verticalMargin = 0 | ||
let r = {} | ||
if (isGroupStacked) { | ||
if (isGroupStacked === 'space') { | ||
r = groupStack( | ||
@@ -440,4 +472,18 @@ lineHeight, | ||
) | ||
} else if (isGroupStacked === 'lines') { | ||
r = groupStackInLines( | ||
lineHeight, | ||
itemsDimensions[itemIndex], | ||
itemsDimensions, | ||
groupHeight, | ||
groupTop, | ||
itemIndex | ||
) | ||
} else { | ||
r = groupNoStack(lineHeight, itemsDimensions[itemIndex], groupHeight, groupTop) | ||
r = groupNoStack( | ||
lineHeight, | ||
itemsDimensions[itemIndex], | ||
groupHeight, | ||
groupTop | ||
) | ||
} | ||
@@ -444,0 +490,0 @@ groupHeight = r.groupHeight |
@@ -0,0 +0,0 @@ // TODO: can we use getBoundingClientRect instead?? |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
9997
467150
1368