diff --git a/CHANGELOG.md b/CHANGELOG.md
index 61deacbfc..eb95dc440 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,44 @@ and this project adheres (more or less) to [Semantic Versioning](http://semver.o
## Unreleased
+### Fixes and Improvements
+
+- create local stack context for z-index @ilaiwi
+- huge performance improvements @ilaiwi
+- [new examples](https://github.com/namespace-ee/react-calendar-timeline/tree/rowRenderer/examples)
+- `z-index`: removed for vertical lines, cursor line, horizontal lines
+
+### New features
+
+#### [rowRenderer](https://github.com/namespace-ee/react-calendar-timeline/tree/rowRenderer#row-renderer)
+
+This API would give you control to add custom UI on calendar rows using a render prop. You can control what is rendered by default with the library like Items and Vertical/Horizontal lines, and the renderer will provide you the ability to render custom backgrounds and droppable layers for custom dnd.
+
+#### [`hideHorizontalLines` prop](https://github.com/namespace-ee/react-calendar-timeline/tree/rowRenderer#hidehorizontallines)
+
+Boolean to hide or show HorizontalLines. `true` by default. Hiding the horizontalLines will have a good impact on performance.
+
+#### [helpers](https://github.com/namespace-ee/react-calendar-timeline/tree/rowRenderer#helpers)
+
+Helpers are methods provided by `HelperContext`. These helpers power most of the rendered UI in the timeline like: Headers, Markers, Items and row renderers.
+
+### breaking changes
+
+- `onItemMove`
+
+changed from `onItemMove(itemId, dragTime, newGroupOrder)` to `onItemMove(itemId, dragTime, newGroupId)`. Now you will be provided with a new group id instead of new group order
+
+- `onItemDrag`
+
+changed from providing `newGroupOrder` to `newGroupId`. Now you will be provided with a new group id instead of new group order
+
+- saving state in `Item` using `itemRenderer`
+
+if you render a stateful component via `itemRenderer` then the state will be lost because item will unmount in some cases
+
+- You need to do `e.stopPropagation()` for all callbacks passed to `itemRenderer`
+
+
## 0.26.6
* fix `visibleTimeStart`, `visibleTimeEnd` and `onTimeChange` not working as expected in controlled mode @ilaiwi
diff --git a/README.md b/README.md
index 614c0d2d8..d565fbc7f 100644
--- a/README.md
+++ b/README.md
@@ -166,17 +166,10 @@ An array specifying keys in the `items` and `groups` objects. Defaults to
Width of the sidebar in pixels. If set to `0`, the sidebar is not rendered. Defaults to `150`.
-## sidebarContent
-
-Everything passed here will be displayed above the left sidebar. Use this to display small filters or so. Defaults to `null`.
-
## rightSidebarWidth
Width of the right sidebar in pixels. If set to `0`, the right sidebar is not rendered. Defaults to `0`.
-## rightSidebarContent
-
-Everything passed here will be displayed above the right sidebar. Use this to display small filters or so. Defaults to `null`.
## dragSnap
@@ -265,12 +258,12 @@ Called when an item is moving or resizing. Returns an object with the following
| `itemId` | `number` | ID of the item being moved or resized |
| `time` | `number` | UNIX timestamp in milliseconds |
| `edge` | `string` | on `resize`, returns a value of either `left` or `right` |
-| `newGroupOrder` | `number` | on `move`, index position of the new group that the item is moving to |
+| `newGroupId` | `number` | on `move`, new group id of the new group that the item is moving to |
-## onItemMove(itemId, dragTime, newGroupOrder)
+## onItemMove(itemId, dragTime, newGroupId)
-Callback when an item is moved. Returns 1) the item's ID, 2) the new start time and 3) the index of the new group in the `groups` array.
+Callback when an item is moved. Returns 1) the item's ID, 2) the new start time and 3) group id of the new group.
## onItemResize(itemId, time, edge)
@@ -366,6 +359,10 @@ function (visibleTimeStart, visibleTimeEnd, updateScrollCanvas) {
Called when the bounds in the calendar's canvas change. Use it for example to load new data to display. (see "Behind the scenes" below). `canvasTimeStart` and `canvasTimeEnd` are unix timestamps in milliseconds.
+## hideHorizontalLines
+
+Boolean to hide or show HorizontalLines. `true` by default. Hiding the horizontalLines will have a good impact on performance.
+
## itemRenderer
Render prop function used to render a customized item. The function provides multiple parameters that can be used to render each item.
@@ -505,6 +502,11 @@ itemRenderer: ({
}
```
+#### Limitations
+
+- You can't save state inside the item because when changing groups the item will be remounted losing all existing state.
+- You need to do `e.stopPropagation()` for all callbacks passed to `itemRenderer`
+
## groupRenderer
React component that will be used to render the content of groups in the
@@ -572,6 +574,153 @@ An example could look like:
horizontalLineClassNamesForGroup={(group) => group.root ? ["row-root"] : []}
```
+## `rowData`
+
+Data to be passed to `rowRenderer`'s `rowData` param. Changing this prop will cause rerender of the `rowRenderer`
+
+# Helpers
+
+Helpers are methods provided by `HelperContext`. These helpers power most of the rendered UI in the timeline like: Headers, Markers, Items and row renderers.
+
+## Methods
+
+### `getLeftOffsetFromDate(x: number): number`
+
+Given time in milliseconds. The method will return the corresponding `left` position in `px`
+
+### `getDateFromLeftOffsetPosition(left: number): number`
+
+Given `left` position in `px`, the method will return the corresponding date in milliseconds.
+
+**inverse of `getLeftOffsetFromDate`**
+
+### `getItemDimensions(itemId: string|number): dimensions`
+
+Given a item id, It will return back the left and top of the item relative to row it is in. This is useful to know the where an item is relative to other items in the same row.
+
+### `getItemAbsoluteDimensions(itemId: string|number): dimensions`.
+
+Given a item id, It will return back the left and top of the item relative to the calendar container. This is useful to know the position of items in different rows relative to each other.
+
+
+### `getGroupDimensions(groupId: string | number): groupDimensions`
+
+Given groupId. The method will return `height` of the group row and `top` of the group row relative to the calendar.
+
+## Example
+
+[CodeSandbox Example](https://codesandbox.io/s/timeline-demo-helpers-doc-example-o24h6)
+
+
+```jsx
+import React, { Component } from "react";
+import moment from "moment";
+
+import Timeline, {
+ HelpersContext,
+ TimelineHeaders,
+ DateHeader,
+ CustomHeader
+} from "react-calendar-timeline";
+import generateFakeData from "./generate-fake-data";
+
+export default class App extends Component {
+ constructor(props) {
+ super(props);
+
+ const { groups, items } = generateFakeData();
+ const defaultTimeStart = moment()
+ .startOf("week")
+ .toDate();
+ const defaultTimeEnd = moment()
+ .startOf("week")
+ .add(1, "week")
+ .toDate();
+
+ this.state = {
+ groups,
+ items,
+ defaultTimeStart,
+ defaultTimeEnd,
+ customEvents: [
+ {
+ start: moment()
+ .startOf("week")
+ .add(12, "h"),
+ end: moment()
+ .startOf("week")
+ .endOf("day"),
+ title: "Lakers game"
+ },
+ {
+ start: moment()
+ .startOf("week")
+ .add(3, 'd'),
+ end: moment()
+ .startOf("week")
+ .add(5, "d"),
+ title: "Christmas"
+ }
+ ]
+ };
+ }
+
+ render() {
+ const { groups, items, defaultTimeStart, defaultTimeEnd } = this.state;
+
+ return (
+
+
+
+
+ {({
+ getRootProps,
+ data: { customEvents }
+ }) => {
+ const { getLeftOffsetFromDate } = React.useContext(
+ HelpersContext
+ );
+ return (
+
+ {customEvents.map(event => {
+ const left = getLeftOffsetFromDate(event.start.valueOf());
+ const right = getLeftOffsetFromDate(event.end.valueOf());
+ const width = right - left;
+ return (
+
+ {event.title}
+
+ );
+ })}
+
+ );
+ }}
+
+
+
+ );
+ }
+}
+
+```
+
+
# Timeline Markers
Timeline markers are markers that are overlayed on the canvas at specific datepoints.
@@ -708,6 +857,9 @@ Custom renderer for this marker. Ensure that you always pass `styles` to the roo
```
+
+Helpers are a group of
+
# Timeline Headers
Timeline headers are the section above the timeline which consist of two main parts: First, the calender header which is a scrolable div containing the dates of the calendar called `DateHeader`. Second, is the headers for the sidebars, called `SidebarHeader`, the left one and optionally the right one.
@@ -1153,6 +1305,239 @@ import Timeline, {
```
+# Row renderer
+
+This API would give you control to add custom UI on calendar rows using a render prop. You can control what is rendered by default with the library like Items and Vertical/Horizontal lines, and the renderer will provide you the ability to render custom backgrounds and droppable layers for custom dnd.
+
+## example
+
+[CodeSandbox](https://codesandbox.io/s/timeline-demo-rowrenderer-doc-example-66pvw)
+
+```jsx
+import Timeline, {
+ RowItems,
+ GroupRow,
+ HelpersContext
+} from "react-calendar-timeline";
+
+import moment from 'moment'
+
+const groups = [{ id: 1, title: 'group 1' }, { id: 2, title: 'group 2' }]
+
+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(
+ {
+ const { getLeftOffsetFromDate } = React.useContext(HelpersContext)
+ const { unavailableSlots } = rowData;
+ const groupUnavailableSlots = unavailableSlots[group.id]
+ ? unavailableSlots[group.id]
+ : [];
+ return (
+
+
+
+
+ );
+ }}
+ rowData={{
+ //keys here are groupIds
+ unavailableSlots: {
+ "1": [
+ {
+ id: "0",
+ groupId: "0",
+ startTime: moment()
+ .startOf("day")
+ .add(16, "h"),
+ endTime: moment()
+ .startOf("day")
+ .add(20, "h")
+ }
+ ]
+ }
+ }}
+ />
+)
+
+function UnavailableLayer({
+ getLayerRootProps,
+ groupUnavailableSlots,
+ getLeftOffsetFromDate
+}) {
+ return (
+
+ {groupUnavailableSlots.map(slot => {
+ const left = getLeftOffsetFromDate(slot.startTime.valueOf());
+ const right = getLeftOffsetFromDate(slot.endTime.valueOf());
+ return (
+
+ unavailable
+
+ );
+ })}
+
+ );
+}
+```
+
+## API
+
+`rowRenderer` follow the render prop pattern with some prebuilt components to display the rows, items and columns.
+
+_Note_ : the renderProp can be a component or a function for convenience
+
+## `rowRenderer` prop
+
+```typescript
+interface Params {
+ getLayerRootProps: (props: React.HTMLProps) => React.HTMLProps;
+ rowData : any;
+ group: Group;
+ itemsWithInteractions: Items[];
+}
+type rowRenderer = (args: Params) => React.Node
+```
+
+### getLayerRootProps
+
+These functions are used to apply props to the layer that you want to render. This gives you maximum flexibility to render what, when, and wherever you like.
+
+### rowData
+
+object passed by the `rowData` prop.
+
+### group
+
+current group being rendered in the row.
+
+### itemsWithInteractions
+
+items to be rendered in the row. These items respect visibility and interaction. This means that the items you will get back are only the items in the visible + buffer zone and if dragging/resizing is happening you will get the items the start/end time with the interaction.
+
+## Components
+
+Row renderer comes with some components needed to render the rows and the default layers (columns and rows). The default value for the row renderer is:
+
+```typescript
+import React from 'react';
+import {GroupRow, RowItems} from '../../index'
+
+const DefaultRowRenderer = () => {
+ return
+
+
+}
+```
+
+### GroupRow
+
+renders the row's root div.
+
+### ItemsRow
+
+renders the row's items
+
+### Custom Layers
+
+To render custom layers you need to implement the row renderer with the necessary layers
+
+```jsx
+import React from 'react';
+import {GroupRow, RowColumns, RowItems, HelpersContext} from 'react-calendar-timeline';
+
+const rowRenderer = ({
+ getLayerRootProps,
+ group,
+ itemsWithInteractions
+}) => {
+ const { getLeftOffsetFromDate } = React.useContext({ HelpersContext })
+ return (
+
+
+
+
+
+ {`group id: ${group.id} renders ${itemsWithInteractions.length} items`}
+
+
+
+
+ );
+}
+```
+
+## order
+
+You can switch the order between `RowColumns`, `RowItems` and custom layers. This will change what renders above what. So if you had `RowItems` in the bottom all the other layer will render in top of it
+
# FAQ
## My timeline is unstyled
@@ -1216,10 +1601,7 @@ It's the same issue as above. See [issue 134](https://github.com/namespace-ee/re
This is useful when using the plugins (that you pass as children to the component). Override the CSS to change:
-* Horizontal Lines: 30
-* Vertical Lines: 40
* Items: 80-88 (depending on selection, dragging, etc)
-* Header: 90
## Behind the scenes
diff --git a/__fixtures__/groupOrderAndItemDimentions.js b/__fixtures__/groupOrderAndItemDimentions.js
index 4637688eb..3f9b7392e 100644
--- a/__fixtures__/groupOrderAndItemDimentions.js
+++ b/__fixtures__/groupOrderAndItemDimentions.js
@@ -26,12 +26,6 @@ export const dimensionItems = [
collisionWidth: 6803877,
height: 22.5,
left: 907.4074074074074,
- order: {
- group: {
- id: '1'
- },
- index: 0
- },
stack: true,
top: 7.5,
width: 78.74857638888886
@@ -44,12 +38,6 @@ export const dimensionItems = [
collisionWidth: 21203877,
height: 22.5,
left: 824.074074074074,
- order: {
- group: {
- id: '1'
- },
- index: 0
- },
stack: true,
top: 37.5,
width: 245.4152430555556
@@ -62,12 +50,6 @@ export const dimensionItems = [
collisionWidth: 24803877,
height: 22.5,
left: 1032.4074074074074,
- order: {
- group: {
- id: '1'
- },
- index: 0
- },
stack: true,
top: 7.5,
width: 287.08190972222224
@@ -80,12 +62,6 @@ export const dimensionItems = [
collisionWidth: 14875919,
height: 22.5,
left: 1254.6296296296296,
- order: {
- group: {
- id: '1'
- },
- index: 0
- },
stack: true,
top: 37.5,
width: 172.1749884259259
@@ -98,12 +74,6 @@ export const dimensionItems = [
collisionWidth: 20397548,
height: 22.5,
left: 1833.3333333333333,
- order: {
- group: {
- id: '1'
- },
- index: 0
- },
stack: true,
top: 7.5,
width: 236.08273148148123
@@ -116,12 +86,6 @@ export const dimensionItems = [
collisionWidth: 20397548,
height: 22.5,
left: 2250,
- order: {
- group: {
- id: '3'
- },
- index: 2
- },
stack: true,
top: 105,
width: 236.08273148148146
diff --git a/__fixtures__/itemsAndGroups.js b/__fixtures__/itemsAndGroups.js
index f98b3810b..806a873e2 100644
--- a/__fixtures__/itemsAndGroups.js
+++ b/__fixtures__/itemsAndGroups.js
@@ -6,7 +6,8 @@ export const items = [
start_time: 1540540000000,
end_time: 1540546803877,
canMove: false,
- canResize: false
+ canResize: false,
+ title: 'title 0',
},
{
id: '5',
@@ -15,7 +16,8 @@ export const items = [
end_time: 1540554003877,
canMove: false,
canResize: false,
- className: ''
+ className: '',
+ title: 'title 5',
},
{
id: '6',
@@ -24,7 +26,8 @@ export const items = [
end_time: 1540575603877,
canMove: false,
canResize: false,
- className: ''
+ className: '',
+ title: 'title 6',
},
{
id: '1',
@@ -32,7 +35,8 @@ export const items = [
start_time: 1540570000000,
end_time: 1540584875919,
canMove: true,
- canResize: 'both'
+ canResize: 'both',
+ title: 'title 1',
},
{
id: '2',
@@ -41,7 +45,8 @@ export const items = [
end_time: 1540640397548,
canMove: false,
canResize: false,
- className: ''
+ className: '',
+ title: 'title 2',
},
{
id: '3',
@@ -50,7 +55,8 @@ export const items = [
end_time: 1540676397548,
canMove: false,
canResize: false,
- className: ''
+ className: '',
+ title: 'title 3',
}
]
diff --git a/__fixtures__/stateAndProps.js b/__fixtures__/stateAndProps.js
index 6cc7746fa..fd3d9489d 100644
--- a/__fixtures__/stateAndProps.js
+++ b/__fixtures__/stateAndProps.js
@@ -1,10 +1,12 @@
import { defaultKeys } from 'lib/default-config'
import {items} from './itemsAndGroups'
+import Timeline from 'lib/Timeline'
export const visibleTimeStart = 1540501200000
export const visibleTimeEnd = 1540587600000
export const props = {
+ ...Timeline.defaultProps,
keys: defaultKeys,
lineHeight: 30,
stackItems: true,
@@ -25,7 +27,8 @@ export const state = {
resizingItem: null,
resizingEdge: null,
resizeTime: null,
- newGroupOrder: null,
+ newGroupId: null,
+ selectedItem: null,
canvasTimeStart: 1540414800000,
visibleTimeEnd: visibleTimeEnd,
visibleTimeStart: visibleTimeStart,
@@ -40,14 +43,14 @@ export const stateMoveItem = {
...state,
draggingItem: items[0].id,
dragTime: items[0].start_time+timeOffset,
- newGroupOrder: 0,
+ newGroupId: items[0].group,
}
export const stateResizeItemLeft = {
...state,
resizingItem: items[0].id,
resizingEdge: 'left',
resizeTime: items[0].start_time+timeOffset,
- newGroupOrder: 0,
+ newGroupId: items[0].group,
}
export const stateResizeItemRight = {
@@ -55,5 +58,5 @@ export const stateResizeItemRight = {
resizingItem: items[0].id,
resizingEdge: 'right',
resizeTime: items[0].end_time+timeOffset,
- newGroupOrder: 0,
+ newGroupId: items[0].group,
}
\ No newline at end of file
diff --git a/__tests__/components/GroupRow/GroupRow.test.js b/__tests__/components/GroupRow/GroupRow.test.js
deleted file mode 100644
index 4b5f3fdd3..000000000
--- a/__tests__/components/GroupRow/GroupRow.test.js
+++ /dev/null
@@ -1,90 +0,0 @@
-import React from 'react'
-import { mount, render } from 'enzyme'
-import { noop } from 'test-utility'
-import GroupRow from 'lib/row/GroupRow'
-
-const defaultProps = {
- onClick: noop,
- onDoubleClick: noop,
- onContextMenu: noop,
- isEvenRow: false,
- clickTolerance: 10,
- style: {},
- group: {}
-}
-
-// using mount to be able to interact with element, render
-// to assert dom level props (styles, className)
-describe('GroupRow', () => {
- it('calls passed in onDoubleClick', () => {
- const onDoubleClickMock = jest.fn()
- const props = {
- ...defaultProps,
- onDoubleClick: onDoubleClickMock
- }
-
- const wrapper = mount( )
-
- wrapper.simulate('doubleclick')
-
- expect(onDoubleClickMock).toHaveBeenCalledTimes(1)
- })
-
- it('calls passed in onClick', () => {
- const onClickMock = jest.fn()
- const props = {
- ...defaultProps,
- onClick: onClickMock
- }
-
- const wrapper = mount( )
-
- wrapper.simulate('click')
-
- expect(onClickMock).toHaveBeenCalledTimes(1)
- })
-
- it('calls passed in onContextMenu', () => {
- const onContextMenuMock = jest.fn()
- const props = {
- ...defaultProps,
- onContextMenu: onContextMenuMock
- }
-
- const wrapper = mount( )
-
- wrapper.simulate('contextmenu')
-
- expect(onContextMenuMock).toHaveBeenCalledTimes(1)
- })
- it('assigns "rct-hl-even" class if isEvenRow is true', () => {
- const props = {
- ...defaultProps,
- isEvenRow: true
- }
-
- const wrapper = render( )
-
- expect(wrapper.prop('class').trim()).toBe('rct-hl-even')
- })
- it('assigns "rct-hl-odd" if isEvenRow is false', () => {
- const props = {
- ...defaultProps,
- isEvenRow: false
- }
-
- const wrapper = render( )
-
- expect(wrapper.prop('class').trim()).toBe('rct-hl-odd')
- })
- it('passes style prop to style', () => {
- const props = {
- ...defaultProps,
- style: { border: '1px solid black' }
- }
-
- const wrapper = render( )
-
- expect(wrapper.prop('style').border).toBe(props.style.border)
- })
-})
diff --git a/__tests__/components/GroupRow/GroupRows.test.js b/__tests__/components/GroupRow/GroupRows.test.js
deleted file mode 100644
index 263e37ff3..000000000
--- a/__tests__/components/GroupRow/GroupRows.test.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import React from 'react'
-import { mount } from 'enzyme'
-import { noop } from 'test-utility'
-import GroupRows from 'lib/row/GroupRows'
-
-const defaultProps = {
- groups: [
- {
- bgColor: '#e8ccff',
- id: '2998',
- label: 'Label Dustin"',
- rightTitle: 'Wolff',
- title: 'Carlotta',
- },
- {
- bgColor: '#e8ccff',
- id: '2999',
- label: 'Label Myrtle"',
- rightTitle: '"Sauer"',
- title: 'Elmer',
- }
- ],
- canvasWidth: 10,
- lineCount: 2,
- groupHeights: [30, 27],
- onRowClick: noop,
- onRowDoubleClick: noop,
- clickTolerance: 0,
- onRowContextClick: noop,
-}
-
-describe('GroupRows', () => {
- it('passes props and get right height for first group', () => {
- const wrapper = mount( );
-
- const component = wrapper.find('GroupRow').first();
- expect(component.prop('style').height).toBe('30px');
- })
-})
diff --git a/__tests__/components/Headers/CustomHeader.test.js b/__tests__/components/Headers/CustomHeader.test.js
index 34779bb93..85ec0e193 100644
--- a/__tests__/components/Headers/CustomHeader.test.js
+++ b/__tests__/components/Headers/CustomHeader.test.js
@@ -1,6 +1,5 @@
import React from 'react'
-import { render, cleanup, prettyDOM } from 'react-testing-library'
-import Timeline from 'lib/Timeline'
+import { render, cleanup } from 'react-testing-library'
import DateHeader from 'lib/headers/DateHeader'
import SidebarHeader from 'lib/headers/SidebarHeader'
import TimelineHeaders from 'lib/headers/TimelineHeaders'
@@ -9,7 +8,7 @@ import { RenderHeadersWrapper } from '../../test-utility/header-renderer'
import { getCustomHeadersInTimeline } from '../../test-utility/headerRenderers'
import { parsePxToNumbers } from '../../test-utility/index'
-import 'jest-dom/extend-expect'
+import '@testing-library/jest-dom/extend-expect'
import moment from 'moment'
describe('CustomHeader Component Test', () => {
diff --git a/__tests__/components/Headers/DateHeader.test.js b/__tests__/components/Headers/DateHeader.test.js
index 5d6ecf6f7..5b188dd41 100644
--- a/__tests__/components/Headers/DateHeader.test.js
+++ b/__tests__/components/Headers/DateHeader.test.js
@@ -4,7 +4,7 @@ import Timeline from 'lib/Timeline'
import DateHeader from 'lib/headers/DateHeader'
import SidebarHeader from 'lib/headers/SidebarHeader'
import TimelineHeaders from 'lib/headers/TimelineHeaders'
-import 'jest-dom/extend-expect'
+import '@testing-library/jest-dom/extend-expect'
import { RenderHeadersWrapper } from '../../test-utility/header-renderer'
import moment from 'moment'
diff --git a/__tests__/components/Headers/SideBarHeader.test.js b/__tests__/components/Headers/SideBarHeader.test.js
index 6775547c4..90544fb25 100644
--- a/__tests__/components/Headers/SideBarHeader.test.js
+++ b/__tests__/components/Headers/SideBarHeader.test.js
@@ -3,7 +3,7 @@ import { render, cleanup } from 'react-testing-library'
import DateHeader from 'lib/headers/DateHeader'
import SidebarHeader from 'lib/headers/SidebarHeader'
import TimelineHeaders from 'lib/headers/TimelineHeaders'
-import 'jest-dom/extend-expect'
+import '@testing-library/jest-dom/extend-expect'
import { RenderHeadersWrapper } from '../../test-utility/header-renderer'
import {
renderSidebarHeaderWithCustomValues,
diff --git a/__tests__/components/Headers/TimelineHeader.test.js b/__tests__/components/Headers/TimelineHeader.test.js
index ae9cd0867..53e05995a 100644
--- a/__tests__/components/Headers/TimelineHeader.test.js
+++ b/__tests__/components/Headers/TimelineHeader.test.js
@@ -2,7 +2,7 @@ import { render } from 'react-testing-library'
import SidebarHeader from 'lib/headers/SidebarHeader'
import DateHeader from 'lib/headers/DateHeader'
import TimelineHeaders from 'lib/headers/TimelineHeaders'
-import 'jest-dom/extend-expect'
+import '@testing-library/jest-dom/extend-expect'
import 'react-testing-library/cleanup-after-each'
import React from 'react'
diff --git a/__tests__/components/Headers/defaultHeaders.js b/__tests__/components/Headers/defaultHeaders.js
index dbd7722fe..9971f6edf 100644
--- a/__tests__/components/Headers/defaultHeaders.js
+++ b/__tests__/components/Headers/defaultHeaders.js
@@ -6,7 +6,7 @@ import {
} from '../../../__fixtures__/stateAndProps'
import 'react-testing-library/cleanup-after-each'
import Timeline from 'lib/Timeline'
-import 'jest-dom/extend-expect'
+import '@testing-library/jest-dom/extend-expect'
/**
* Testing The Default Functionality
diff --git a/__tests__/components/HelpersContext/HelperContextProvider.test.js b/__tests__/components/HelpersContext/HelperContextProvider.test.js
new file mode 100644
index 000000000..2e1f5a478
--- /dev/null
+++ b/__tests__/components/HelpersContext/HelperContextProvider.test.js
@@ -0,0 +1,71 @@
+import React from 'react'
+import { render } from 'react-testing-library'
+import renderWithTimelineStateAndHelpers from '../../test-utility/renderWithTimelineStateAndHelpers'
+import 'react-testing-library/cleanup-after-each'
+import { stackTimelineItems } from 'lib/utility/calendar'
+import {
+ HelpersContextProvider,
+ HelpersConsumer
+} from '../../../src/lib/timeline/HelpersContext'
+import {
+ TimelineStateProvider,
+ TimelineStateConsumer
+} from '../../../src/lib/timeline/TimelineStateContext'
+import { items, groups } from '../../../__fixtures__/itemsAndGroups'
+import { props, state } from '../../../__fixtures__/stateAndProps'
+import { defaultKeys } from '../../../src/lib/default-config'
+
+describe('HelperContext', () => {
+ it('should work correctly', () => {
+ const canvasWidth = state.width * 3
+ const {
+ groupsWithItemsDimensions,
+ groupHeights,
+ groupTops,
+ itemsWithInteractions
+ } = stackTimelineItems(
+ items,
+ groups,
+ canvasWidth,
+ state.canvasTimeStart,
+ state.canvasTimeEnd,
+ props.keys,
+ props.lineHeight,
+ props.itemHeightRatio,
+ props.stackItems,
+ state.draggingItem,
+ state.resizingItem,
+ state.dragTime,
+ state.resizingEdge,
+ state.resizeTime,
+ state.newGroupId
+ )
+ const defaultTimelineState = {
+ visibleTimeStart: state.visibleTimeStart,
+ visibleTimeEnd: state.visibleTimeEnd,
+ canvasTimeStart: state.canvasTimeStart,
+ canvasTimeEnd: state.canvasTimeEnd,
+ canvasWidth: canvasWidth,
+ showPeriod: jest.fn(),
+ timelineUnit: 'day',
+ timelineWidth: state.width,
+ keys: defaultKeys
+ }
+ renderWithTimelineStateAndHelpers(
+
+ {props => {
+ expect(props).toEqual(
+ expect.objectContaining({
+ getDateFromLeftOffsetPosition: expect.any(Function),
+ getLeftOffsetFromDate: expect.any(Function),
+ getItemDimensions: expect.any(Function),
+ getItemAbsoluteDimensions: expect.any(Function),
+ getGroupDimensions: expect.any(Function)
+ })
+ )
+ return
+ }}
+
+ )
+ })
+})
diff --git a/__tests__/components/Items/Item.test.js b/__tests__/components/Items/Item.test.js
new file mode 100644
index 000000000..0ab8a9b01
--- /dev/null
+++ b/__tests__/components/Items/Item.test.js
@@ -0,0 +1,66 @@
+import React from 'react'
+import 'react-testing-library/cleanup-after-each'
+import render from '../../test-utility/renderWithTimelineStateAndHelpers'
+import Item from 'lib/items/Item'
+import { items } from '../../../__fixtures__/itemsAndGroups'
+import { props, state } from '../../../__fixtures__/stateAndProps'
+import { orderedGroups } from '../../../__fixtures__/groupOrderAndItemDimentions'
+import { noop } from 'test-utility/index'
+import { defaultItemRenderer } from 'lib/items/defaultItemRenderer'
+
+describe('Item', () => {
+ it('should render', () => {
+ const container = document.createElement('div')
+ const { } = render(
+ ,
+ {
+ container: document.body.appendChild(container)
+ }
+ )
+ })
+})
diff --git a/__tests__/components/Items/Items.test.js b/__tests__/components/Items/Items.test.js
new file mode 100644
index 000000000..3239acf59
--- /dev/null
+++ b/__tests__/components/Items/Items.test.js
@@ -0,0 +1,58 @@
+import React from 'react'
+import 'react-testing-library/cleanup-after-each'
+import render from '../../test-utility/renderWithTimelineStateAndHelpers'
+import Items from 'lib/items/Items'
+import { ItemsContextProvider } from 'lib/items/ItemsContext'
+import { items } from '../../../__fixtures__/itemsAndGroups'
+import { props, state } from '../../../__fixtures__/stateAndProps'
+import {
+ orderedGroups,
+ dimensionItems
+} from '../../../__fixtures__/groupOrderAndItemDimentions'
+import { noop } from 'test-utility/index'
+import { defaultItemRenderer } from 'lib/items/defaultItemRenderer'
+
+describe('Items', () => {
+ it('should render', () => {
+ const container = document.createElement('div')
+ const {} = render(
+
+
+ ,
+ {
+ container: document.body.appendChild(container)
+ }
+ )
+ })
+})
diff --git a/__tests__/components/Markers/CursorMarker.test.js b/__tests__/components/Markers/CursorMarker.test.js
index c3fbfb226..519074d66 100644
--- a/__tests__/components/Markers/CursorMarker.test.js
+++ b/__tests__/components/Markers/CursorMarker.test.js
@@ -1,6 +1,6 @@
import React from 'react'
import { render, fireEvent, cleanup } from 'react-testing-library'
-import 'jest-dom/extend-expect'
+import '@testing-library/jest-dom/extend-expect'
import TimelineMarkers from 'lib/markers/public/TimelineMarkers'
import CursorMarker from 'lib/markers/public/CursorMarker'
import { RenderWrapper } from 'test-utility/marker-renderer'
diff --git a/__tests__/components/Markers/CustomMarker.test.js b/__tests__/components/Markers/CustomMarker.test.js
index 32929c2de..d3e0fb722 100644
--- a/__tests__/components/Markers/CustomMarker.test.js
+++ b/__tests__/components/Markers/CustomMarker.test.js
@@ -1,9 +1,10 @@
import React from 'react'
import { render, fireEvent, cleanup } from 'react-testing-library'
-import 'jest-dom/extend-expect'
+import '@testing-library/jest-dom/extend-expect'
import TimelineMarkers from 'lib/markers/public/TimelineMarkers'
import CustomMarker from 'lib/markers/public/CustomMarker'
import { RenderWrapper } from 'test-utility/marker-renderer'
+import { defaultKeys } from '../../../src/lib/default-config'
describe('CustomMarker', () => {
afterEach(cleanup)
@@ -70,7 +71,8 @@ describe('CustomMarker', () => {
canvasWidth,
showPeriod: () => {},
timelineWidth: 1000,
- timelineUnit: 'day'
+ timelineUnit: 'day',
+ keys: defaultKeys
}
const markerDate = now + oneDay / 2
diff --git a/__tests__/components/Markers/TimelineMarkers.test.js b/__tests__/components/Markers/TimelineMarkers.test.js
index 8d03a5361..40ecad5d7 100644
--- a/__tests__/components/Markers/TimelineMarkers.test.js
+++ b/__tests__/components/Markers/TimelineMarkers.test.js
@@ -1,6 +1,6 @@
import React from 'react'
import { render } from 'react-testing-library'
-import 'jest-dom/extend-expect'
+import '@testing-library/jest-dom/extend-expect'
import TimelineMarkers from 'lib/markers/public/TimelineMarkers'
import TodayMarker from 'lib/markers/public/TodayMarker'
import CustomMarker from 'lib/markers/public/CustomMarker'
diff --git a/__tests__/components/Markers/TodayMarker.test.js b/__tests__/components/Markers/TodayMarker.test.js
index 22d62a084..98a83942b 100644
--- a/__tests__/components/Markers/TodayMarker.test.js
+++ b/__tests__/components/Markers/TodayMarker.test.js
@@ -1,6 +1,6 @@
import React from 'react'
import { render, fireEvent, cleanup } from 'react-testing-library'
-import 'jest-dom/extend-expect'
+import '@testing-library/jest-dom/extend-expect'
import { RenderWrapper } from 'test-utility/marker-renderer'
import TimelineMarkers from 'lib/markers/public/TimelineMarkers'
import TodayMarker from 'lib/markers/public/TodayMarker'
diff --git a/__tests__/components/Rows/GroupRow.test.js b/__tests__/components/Rows/GroupRow.test.js
new file mode 100644
index 000000000..cf415977e
--- /dev/null
+++ b/__tests__/components/Rows/GroupRow.test.js
@@ -0,0 +1,115 @@
+import React from 'react'
+import { fireEvent} from 'react-testing-library';
+import render from '../../test-utility/renderWithTimelineStateAndHelpers'
+import { noop } from 'test-utility'
+import GroupRow from 'lib/rows/GroupRow'
+import {RenderGroupRowWrapper} from '../../test-utility/groupRow-renderer'
+import 'react-testing-library/cleanup-after-each'
+import '@testing-library/jest-dom/extend-expect'
+
+const defaultProps = {
+ onClick: noop,
+ onDoubleClick: noop,
+ onContextMenu: noop,
+ isEvenRow: false,
+ clickTolerance: 10,
+ style: {},
+ group: {}
+}
+
+// using mount to be able to interact with element, render
+// to assert dom level props (styles, className)
+describe('GroupRow', () => {
+ it('calls passed in onDoubleClick with correct group index', () => {
+ const onDoubleClickMock = jest.fn()
+ const text = "some text"
+ const {getByText} = render(
+
+
+
+ {text}
+
+
+
+ )
+ fireEvent.doubleClick(getByText(text))
+ expect(onDoubleClickMock).toHaveBeenCalledTimes(1)
+ expect(onDoubleClickMock).toHaveBeenCalledWith(expect.anything(), 4)
+ })
+
+ it('calls passed in onClick with correct group index', () => {
+ const onClickMock = jest.fn()
+ const text = "some text"
+ const {getByText} = render(
+
+
+
+ {text}
+
+
+
+ )
+ fireEvent.click(getByText(text))
+ expect(onClickMock).toHaveBeenCalledTimes(1)
+ expect(onClickMock).toHaveBeenCalledWith(expect.anything(), 4)
+ })
+
+ it('calls passed in onContextMenu with correct group index', () => {
+ const onContextMenuMock = jest.fn()
+ const text = "some text"
+ const {getByText} = render(
+
+
+
+ {text}
+
+
+
+ )
+ fireEvent.contextMenu(getByText(text))
+ expect(onContextMenuMock).toHaveBeenCalledTimes(1)
+ expect(onContextMenuMock).toHaveBeenCalledWith(expect.anything(), 4)
+ })
+ it('assigns "rct-hl-even" class if isEvenRow is true', () => {
+ const text = "some text"
+ const {getByTestId} = render(
+
+
+
+ {text}
+
+
+
+ )
+ const wrapper = getByTestId("groupRow")
+ expect(wrapper).toHaveClass("rct-hl-even")
+ })
+ it('assigns "rct-hl-odd" if isEvenRow is false', () => {
+ const text = "some text"
+ const {getByTestId} = render(
+
+
+
+ {text}
+
+
+
+ )
+ const wrapper = getByTestId("groupRow")
+ expect(wrapper).toHaveClass("rct-hl-odd")
+ })
+ it('passes style prop to style', () => {
+ const text = "some text"
+ const {getByTestId} = render(
+
+
+
+ {text}
+
+
+
+ )
+ const wrapper = getByTestId("groupRow")
+ expect(wrapper).toHaveStyle(`width: 3000px; height: 30px;`)
+ })
+})
diff --git a/__tests__/components/Rows/Rows.test.js b/__tests__/components/Rows/Rows.test.js
new file mode 100644
index 000000000..b082b0513
--- /dev/null
+++ b/__tests__/components/Rows/Rows.test.js
@@ -0,0 +1,63 @@
+import React from 'react'
+import 'react-testing-library/cleanup-after-each'
+import render from 'test-utility/renderWithTimelineStateAndHelpers'
+import Rows from 'lib/rows/Rows'
+import { props, state } from '../../../__fixtures__/stateAndProps'
+import { items, groups } from '../../../__fixtures__/itemsAndGroups'
+import { defaultItemRenderer } from 'lib/items/defaultItemRenderer'
+import { noop } from 'test-utility/index'
+import { stackTimelineItems } from 'lib/utility/calendar'
+
+describe('Rows', () => {
+ it('should render', () => {
+ const container = document.createElement('div')
+ const canvasWidth = state.width * 3
+ const {
+ groupsWithItemsDimensions,
+ groupHeights,
+ groupTops,
+ itemsWithInteractions
+ } = stackTimelineItems(
+ items,
+ groups,
+ canvasWidth,
+ state.canvasTimeStart,
+ state.canvasTimeEnd,
+ props.keys,
+ props.lineHeight,
+ props.itemHeightRatio,
+ props.stackItems,
+ state.draggingItem,
+ state.resizingItem,
+ state.dragTime,
+ state.resizingEdge,
+ state.resizeTime,
+ state.newGroupId
+ )
+ const {} = render(
+ ,
+ {
+ container: document.body.appendChild(container)
+ }
+ )
+ })
+})
diff --git a/__tests__/test-utility/groupRow-renderer.js b/__tests__/test-utility/groupRow-renderer.js
new file mode 100644
index 000000000..464606744
--- /dev/null
+++ b/__tests__/test-utility/groupRow-renderer.js
@@ -0,0 +1,28 @@
+import React from 'react'
+import { TimelineStateProvider } from 'lib/timeline/TimelineStateContext'
+import { state } from '../../__fixtures__/stateAndProps'
+import { groups } from '../../__fixtures__/itemsAndGroups'
+import { defaultTimeSteps, defaultKeys } from '../../src/lib/default-config'
+import { GroupRowContextProvider } from '../../src/lib/rows/GroupRowContext'
+
+// eslint-disable-next-line
+export const RenderGroupRowWrapper = ({ children, groupRowState = {} }) => {
+ const groupRowStateProps = {
+ clickTolerance: 20,
+ onContextMenu: () => {},
+ onClick: () => {},
+ onDoubleClick: () => {},
+ isEvenRow: true,
+ group: groups[1],
+ horizontalLineClassNamesForGroup: undefined,
+ groupHeight: 60,
+ groupIndex: 3,
+ ...groupRowState
+ }
+
+ return (
+
+ {children}
+
+ )
+}
diff --git a/__tests__/test-utility/header-renderer.js b/__tests__/test-utility/header-renderer.js
index 645fb8ee0..b61959c87 100644
--- a/__tests__/test-utility/header-renderer.js
+++ b/__tests__/test-utility/header-renderer.js
@@ -4,7 +4,7 @@ import { TimelineMarkersProvider } from 'lib/markers/TimelineMarkersContext'
import { TimelineStateProvider } from 'lib/timeline/TimelineStateContext'
import { state } from '../../__fixtures__/stateAndProps'
import jest from 'jest'
-import { defaultTimeSteps } from '../../src/lib/default-config'
+import { defaultTimeSteps, defaultKeys } from '../../src/lib/default-config'
import { TimelineHeadersProvider } from '../../src/lib/headers/HeadersContext'
// eslint-disable-next-line
@@ -23,7 +23,8 @@ export const RenderHeadersWrapper = ({
canvasWidth: 2000,
showPeriod: showPeriod,
timelineUnit: 'day',
- timelineWidth: 1000
+ timelineWidth: 1000,
+ keys: defaultKeys
}
const timelineStateProps = {
diff --git a/__tests__/test-utility/marker-renderer.js b/__tests__/test-utility/marker-renderer.js
index 566792c6b..33fc6904b 100644
--- a/__tests__/test-utility/marker-renderer.js
+++ b/__tests__/test-utility/marker-renderer.js
@@ -2,6 +2,7 @@ import React from 'react'
import TimelineMarkersRenderer from 'lib/markers/TimelineMarkersRenderer'
import { TimelineMarkersProvider } from 'lib/markers/TimelineMarkersContext'
import { TimelineStateProvider } from 'lib/timeline/TimelineStateContext'
+import { defaultKeys } from '../../src/lib/default-config'
const oneDay = 1000 * 60 * 60 * 24
// eslint-disable-next-line
@@ -18,7 +19,8 @@ export const RenderWrapper = ({ children, timelineState }) => {
visibleWidth: 1000,
showPeriod:()=>{},
timelineWidth:1000,
- timelineUnit:'day'
+ timelineUnit:'day',
+ keys: defaultKeys,
}
timelineState = timelineState != null ? timelineState : defaultTimelineState
diff --git a/__tests__/test-utility/renderWithTimelineStateAndHelpers.js b/__tests__/test-utility/renderWithTimelineStateAndHelpers.js
new file mode 100644
index 000000000..102e242a9
--- /dev/null
+++ b/__tests__/test-utility/renderWithTimelineStateAndHelpers.js
@@ -0,0 +1,91 @@
+import React from 'react';
+import { render } from 'react-testing-library'
+import { items, groups } from '../../__fixtures__/itemsAndGroups'
+import { props, state } from '../../__fixtures__/stateAndProps'
+import { HelpersContextProvider } from '../../src/lib/timeline/HelpersContext'
+import {
+ TimelineStateProvider,
+ TimelineStateConsumer
+} from '../../src/lib/timeline/TimelineStateContext'
+import { stackTimelineItems } from 'lib/utility/calendar'
+
+function renderWithTimelineStateAndHelpers(
+ ui,
+ { providersPropsOverride, ...options } = { providersPropsOverride: {} }
+) {
+ const canvasWidth = state.width * 3
+ const {
+ groupsWithItemsDimensions,
+ groupHeights,
+ groupTops,
+ itemsWithInteractions
+ } = stackTimelineItems(
+ items,
+ groups,
+ canvasWidth,
+ state.canvasTimeStart,
+ state.canvasTimeEnd,
+ props.keys,
+ props.lineHeight,
+ props.itemHeightRatio,
+ props.stackItems,
+ state.draggingItem,
+ state.resizingItem,
+ state.dragTime,
+ state.resizingEdge,
+ state.resizeTime,
+ state.newGroupId
+ )
+ const providersProps = {
+ visibleTimeStart: state.visibleTimeStart,
+ visibleTimeEnd: state.visibleTimeEnd,
+ canvasTimeStart: state.canvasTimeStart,
+ canvasTimeEnd: state.canvasTimeEnd,
+ canvasWidth: canvasWidth,
+ showPeriod: ()=>{},
+ timelineUnit: 'day',
+ timelineWidth: state.width,
+ keys: props.keys,
+ groupsWithItemsDimensions,
+ groupHeights,
+ groupTops,
+ itemsWithInteractions,
+ ...providersPropsOverride
+ }
+ function Wrapper(props) {
+ return (
+
+
+ {({ getLeftOffsetFromDate, getDateFromLeftOffsetPosition }) => (
+
+ {props.children}
+
+ )}
+
+
+ )
+ }
+ return render(ui, { wrapper: Wrapper, ...options })
+}
+
+export default renderWithTimelineStateAndHelpers
diff --git a/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap b/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap
index 757fcc868..43f499607 100644
--- a/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap
+++ b/__tests__/utils/calendar/__snapshots__/calculate-scroll-canvas.js.snap
@@ -4,116 +4,249 @@ exports[`calculateScrollCanvas should calculate new scroll state correctly 1`] =
Object {
"canvasTimeEnd": 1540720800000,
"canvasTimeStart": 1540461600000,
- "dimensionItems": Array [
- Object {
- "dimensions": Object {
- "collisionLeft": 1540540000000,
- "collisionWidth": 6803877,
- "height": 22.5,
- "left": 907.4074074074074,
- "order": Object {
- "group": Object {
- "id": "1",
+ "groupHeights": Array [
+ 60,
+ 30,
+ 30,
+ ],
+ "groupTops": Array [
+ 0,
+ 60,
+ 90,
+ ],
+ "groupsWithItemsDimensions": Object {
+ "1": Object {
+ "group": Object {
+ "id": "1",
+ },
+ "height": 60,
+ "index": 0,
+ "itemDimensions": Array [
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540540000000,
+ "collisionWidth": 6803877,
+ "height": 22.5,
+ "left": 907.4074074074074,
+ "stack": true,
+ "top": 3.75,
+ "width": 78.74857638888886,
+ },
+ "id": "0",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540532800000,
+ "collisionWidth": 21203877,
+ "height": 22.5,
+ "left": 824.074074074074,
+ "stack": true,
+ "top": 33.75,
+ "width": 245.4152430555556,
+ },
+ "id": "5",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540550800000,
+ "collisionWidth": 24803877,
+ "height": 22.5,
+ "left": 1032.4074074074074,
+ "stack": true,
+ "top": 3.75,
+ "width": 287.08190972222224,
+ },
+ "id": "6",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540570000000,
+ "collisionWidth": 14875919,
+ "height": 22.5,
+ "left": 1254.6296296296296,
+ "stack": true,
+ "top": 33.75,
+ "width": 172.1749884259259,
+ },
+ "id": "1",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540620000000,
+ "collisionWidth": 20397548,
+ "height": 22.5,
+ "left": 1833.3333333333333,
+ "stack": true,
+ "top": 3.75,
+ "width": 236.08273148148123,
},
- "index": 0,
+ "id": "2",
+ },
+ ],
+ "items": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "end_time": 1540546803877,
+ "group": "1",
+ "id": "0",
+ "start_time": 1540540000000,
+ "title": "title 0",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540554003877,
+ "group": "1",
+ "id": "5",
+ "start_time": 1540532800000,
+ "title": "title 5",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540575603877,
+ "group": "1",
+ "id": "6",
+ "start_time": 1540550800000,
+ "title": "title 6",
},
- "stack": true,
- "top": 3.75,
- "width": 78.74857638888886,
+ Object {
+ "canMove": true,
+ "canResize": "both",
+ "end_time": 1540584875919,
+ "group": "1",
+ "id": "1",
+ "start_time": 1540570000000,
+ "title": "title 1",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540640397548,
+ "group": "1",
+ "id": "2",
+ "start_time": 1540620000000,
+ "title": "title 2",
+ },
+ ],
+ },
+ "2": Object {
+ "group": Object {
+ "id": "2",
},
- "id": "0",
+ "height": 30,
+ "index": 1,
+ "itemDimensions": Array [],
+ "items": Array [],
},
- Object {
- "dimensions": Object {
- "collisionLeft": 1540532800000,
- "collisionWidth": 21203877,
- "height": 22.5,
- "left": 824.074074074074,
- "order": Object {
- "group": Object {
- "id": "1",
+ "3": Object {
+ "group": Object {
+ "id": "3",
+ },
+ "height": 30,
+ "index": 2,
+ "itemDimensions": Array [
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540656000000,
+ "collisionWidth": 20397548,
+ "height": 22.5,
+ "left": 2250,
+ "stack": true,
+ "top": 3.75,
+ "width": 236.08273148148146,
},
- "index": 0,
+ "id": "3",
},
- "stack": true,
- "top": 33.75,
- "width": 245.4152430555556,
- },
+ ],
+ "items": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540676397548,
+ "group": "3",
+ "id": "3",
+ "start_time": 1540656000000,
+ "title": "title 3",
+ },
+ ],
+ },
+ },
+ "height": 120,
+ "itemsWithInteractions": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "end_time": 1540546803877,
+ "group": "1",
+ "id": "0",
+ "start_time": 1540540000000,
+ "title": "title 0",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540554003877,
+ "group": "1",
"id": "5",
+ "start_time": 1540532800000,
+ "title": "title 5",
},
Object {
- "dimensions": Object {
- "collisionLeft": 1540550800000,
- "collisionWidth": 24803877,
- "height": 22.5,
- "left": 1032.4074074074074,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 3.75,
- "width": 287.08190972222224,
- },
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540575603877,
+ "group": "1",
"id": "6",
+ "start_time": 1540550800000,
+ "title": "title 6",
},
Object {
- "dimensions": Object {
- "collisionLeft": 1540570000000,
- "collisionWidth": 14875919,
- "height": 22.5,
- "left": 1254.6296296296296,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 33.75,
- "width": 172.1749884259259,
- },
+ "canMove": true,
+ "canResize": "both",
+ "end_time": 1540584875919,
+ "group": "1",
"id": "1",
+ "start_time": 1540570000000,
+ "title": "title 1",
},
Object {
- "dimensions": Object {
- "collisionLeft": 1540620000000,
- "collisionWidth": 20397548,
- "height": 22.5,
- "left": 1833.3333333333333,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 3.75,
- "width": 236.08273148148123,
- },
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540640397548,
+ "group": "1",
"id": "2",
+ "start_time": 1540620000000,
+ "title": "title 2",
},
Object {
- "dimensions": Object {
- "collisionLeft": 1540656000000,
- "collisionWidth": 20397548,
- "height": 22.5,
- "left": 2250,
- "order": Object {
- "group": Object {
- "id": "3",
- },
- "index": 2,
- },
- "stack": true,
- "top": 93.75,
- "width": 236.08273148148146,
- },
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540676397548,
+ "group": "3",
"id": "3",
+ "start_time": 1540656000000,
+ "title": "title 3",
},
],
+ "visibleTimeEnd": 1540634400000,
+ "visibleTimeStart": 1540548000000,
+}
+`;
+
+exports[`calculateScrollCanvas should calculate new state if zoom changed correctly 1`] = `
+Object {
+ "canvasTimeEnd": 1540681200000,
+ "canvasTimeStart": 1540411200000,
"groupHeights": Array [
60,
30,
@@ -124,137 +257,230 @@ Object {
60,
90,
],
- "height": 120,
- "visibleTimeEnd": 1540634400000,
- "visibleTimeStart": 1540548000000,
-}
-`;
-
-exports[`calculateScrollCanvas should calculate new state if zoom changed correctly 1`] = `
-Object {
- "canvasTimeEnd": 1540681200000,
- "canvasTimeStart": 1540411200000,
- "dimensionItems": Array [
- Object {
- "dimensions": Object {
- "collisionLeft": 1540540000000,
- "collisionWidth": 6803877,
- "height": 22.5,
- "left": 1431.111111111111,
- "order": Object {
- "group": Object {
- "id": "1",
+ "groupsWithItemsDimensions": Object {
+ "1": Object {
+ "group": Object {
+ "id": "1",
+ },
+ "height": 60,
+ "index": 0,
+ "itemDimensions": Array [
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540540000000,
+ "collisionWidth": 6803877,
+ "height": 22.5,
+ "left": 1431.111111111111,
+ "stack": true,
+ "top": 3.75,
+ "width": 75.59863333333351,
+ },
+ "id": "0",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540532800000,
+ "collisionWidth": 21203877,
+ "height": 22.5,
+ "left": 1351.111111111111,
+ "stack": true,
+ "top": 33.75,
+ "width": 235.5986333333335,
+ },
+ "id": "5",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540550800000,
+ "collisionWidth": 24803877,
+ "height": 22.5,
+ "left": 1551.111111111111,
+ "stack": true,
+ "top": 3.75,
+ "width": 275.5986333333335,
},
- "index": 0,
+ "id": "6",
},
- "stack": true,
- "top": 3.75,
- "width": 75.59863333333351,
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540570000000,
+ "collisionWidth": 14875919,
+ "height": 22.5,
+ "left": 1764.4444444444446,
+ "stack": true,
+ "top": 33.75,
+ "width": 165.28798888888878,
+ },
+ "id": "1",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540620000000,
+ "collisionWidth": 20397548,
+ "height": 22.5,
+ "left": 2320,
+ "stack": true,
+ "top": 3.75,
+ "width": 226.6394222222225,
+ },
+ "id": "2",
+ },
+ ],
+ "items": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "end_time": 1540546803877,
+ "group": "1",
+ "id": "0",
+ "start_time": 1540540000000,
+ "title": "title 0",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540554003877,
+ "group": "1",
+ "id": "5",
+ "start_time": 1540532800000,
+ "title": "title 5",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540575603877,
+ "group": "1",
+ "id": "6",
+ "start_time": 1540550800000,
+ "title": "title 6",
+ },
+ Object {
+ "canMove": true,
+ "canResize": "both",
+ "end_time": 1540584875919,
+ "group": "1",
+ "id": "1",
+ "start_time": 1540570000000,
+ "title": "title 1",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540640397548,
+ "group": "1",
+ "id": "2",
+ "start_time": 1540620000000,
+ "title": "title 2",
+ },
+ ],
+ },
+ "2": Object {
+ "group": Object {
+ "id": "2",
},
- "id": "0",
+ "height": 30,
+ "index": 1,
+ "itemDimensions": Array [],
+ "items": Array [],
},
- Object {
- "dimensions": Object {
- "collisionLeft": 1540532800000,
- "collisionWidth": 21203877,
- "height": 22.5,
- "left": 1351.111111111111,
- "order": Object {
- "group": Object {
- "id": "1",
+ "3": Object {
+ "group": Object {
+ "id": "3",
+ },
+ "height": 30,
+ "index": 2,
+ "itemDimensions": Array [
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540656000000,
+ "collisionWidth": 20397548,
+ "height": 22.5,
+ "left": 2720,
+ "stack": true,
+ "top": 3.75,
+ "width": 226.6394222222225,
},
- "index": 0,
+ "id": "3",
},
- "stack": true,
- "top": 33.75,
- "width": 235.5986333333335,
- },
+ ],
+ "items": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540676397548,
+ "group": "3",
+ "id": "3",
+ "start_time": 1540656000000,
+ "title": "title 3",
+ },
+ ],
+ },
+ },
+ "height": 120,
+ "itemsWithInteractions": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "end_time": 1540546803877,
+ "group": "1",
+ "id": "0",
+ "start_time": 1540540000000,
+ "title": "title 0",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540554003877,
+ "group": "1",
"id": "5",
+ "start_time": 1540532800000,
+ "title": "title 5",
},
Object {
- "dimensions": Object {
- "collisionLeft": 1540550800000,
- "collisionWidth": 24803877,
- "height": 22.5,
- "left": 1551.111111111111,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 3.75,
- "width": 275.5986333333335,
- },
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540575603877,
+ "group": "1",
"id": "6",
+ "start_time": 1540550800000,
+ "title": "title 6",
},
Object {
- "dimensions": Object {
- "collisionLeft": 1540570000000,
- "collisionWidth": 14875919,
- "height": 22.5,
- "left": 1764.4444444444446,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 33.75,
- "width": 165.28798888888878,
- },
+ "canMove": true,
+ "canResize": "both",
+ "end_time": 1540584875919,
+ "group": "1",
"id": "1",
+ "start_time": 1540570000000,
+ "title": "title 1",
},
Object {
- "dimensions": Object {
- "collisionLeft": 1540620000000,
- "collisionWidth": 20397548,
- "height": 22.5,
- "left": 2320,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 3.75,
- "width": 226.6394222222225,
- },
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540640397548,
+ "group": "1",
"id": "2",
+ "start_time": 1540620000000,
+ "title": "title 2",
},
Object {
- "dimensions": Object {
- "collisionLeft": 1540656000000,
- "collisionWidth": 20397548,
- "height": 22.5,
- "left": 2720,
- "order": Object {
- "group": Object {
- "id": "3",
- },
- "index": 2,
- },
- "stack": true,
- "top": 93.75,
- "width": 226.6394222222225,
- },
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540676397548,
+ "group": "3",
"id": "3",
+ "start_time": 1540656000000,
+ "title": "title 3",
},
],
- "groupHeights": Array [
- 60,
- 30,
- 30,
- ],
- "groupTops": Array [
- 0,
- 60,
- 90,
- ],
- "height": 120,
"visibleTimeEnd": 1540591200000,
"visibleTimeStart": 1540501200000,
}
diff --git a/__tests__/utils/calendar/__snapshots__/get-group-with-item-dimensions.js.snap b/__tests__/utils/calendar/__snapshots__/get-group-with-item-dimensions.js.snap
new file mode 100644
index 000000000..cbad82d16
--- /dev/null
+++ b/__tests__/utils/calendar/__snapshots__/get-group-with-item-dimensions.js.snap
@@ -0,0 +1,141 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`getGroupWithItemDimensions should work as expected 1`] = `
+Object {
+ "height": 60,
+ "itemDimensions": Array [
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540540000000,
+ "collisionWidth": 6803877,
+ "height": 22.5,
+ "left": 1449.074074074074,
+ "stack": true,
+ "top": 3.75,
+ "width": 78.74857638888898,
+ },
+ "id": "0",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540532800000,
+ "collisionWidth": 21203877,
+ "height": 22.5,
+ "left": 1365.7407407407406,
+ "stack": true,
+ "top": 33.75,
+ "width": 245.4152430555555,
+ },
+ "id": "5",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540550800000,
+ "collisionWidth": 24803877,
+ "height": 22.5,
+ "left": 1574.074074074074,
+ "stack": true,
+ "top": 3.75,
+ "width": 287.08190972222224,
+ },
+ "id": "6",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540570000000,
+ "collisionWidth": 14875919,
+ "height": 22.5,
+ "left": 1796.2962962962963,
+ "stack": true,
+ "top": 33.75,
+ "width": 172.1749884259259,
+ },
+ "id": "1",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540620000000,
+ "collisionWidth": 20397548,
+ "height": 22.5,
+ "left": 2375,
+ "stack": true,
+ "top": 3.75,
+ "width": 236.08273148148146,
+ },
+ "id": "2",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540656000000,
+ "collisionWidth": 20397548,
+ "height": 22.5,
+ "left": 2791.6666666666665,
+ "stack": true,
+ "top": 3.75,
+ "width": 208.33333333333348,
+ },
+ "id": "3",
+ },
+ ],
+ "items": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "end_time": 1540546803877,
+ "group": "1",
+ "id": "0",
+ "start_time": 1540540000000,
+ "title": "title 0",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540554003877,
+ "group": "1",
+ "id": "5",
+ "start_time": 1540532800000,
+ "title": "title 5",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540575603877,
+ "group": "1",
+ "id": "6",
+ "start_time": 1540550800000,
+ "title": "title 6",
+ },
+ Object {
+ "canMove": true,
+ "canResize": "both",
+ "end_time": 1540584875919,
+ "group": "1",
+ "id": "1",
+ "start_time": 1540570000000,
+ "title": "title 1",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540640397548,
+ "group": "1",
+ "id": "2",
+ "start_time": 1540620000000,
+ "title": "title 2",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540676397548,
+ "group": "3",
+ "id": "3",
+ "start_time": 1540656000000,
+ "title": "title 3",
+ },
+ ],
+}
+`;
diff --git a/__tests__/utils/calendar/__snapshots__/get-grouped-items.js.snap b/__tests__/utils/calendar/__snapshots__/get-grouped-items.js.snap
deleted file mode 100644
index b4a4b264b..000000000
--- a/__tests__/utils/calendar/__snapshots__/get-grouped-items.js.snap
+++ /dev/null
@@ -1,137 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`getGroupedItems works as expected 1`] = `
-Object {
- "0": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- "items": Array [
- Object {
- "dimensions": Object {
- "collisionLeft": 1540540000000,
- "collisionWidth": 6803877,
- "height": 22.5,
- "left": 907.4074074074074,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 7.5,
- "width": 78.74857638888886,
- },
- "id": "0",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540532800000,
- "collisionWidth": 21203877,
- "height": 22.5,
- "left": 824.074074074074,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 37.5,
- "width": 245.4152430555556,
- },
- "id": "5",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540550800000,
- "collisionWidth": 24803877,
- "height": 22.5,
- "left": 1032.4074074074074,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 7.5,
- "width": 287.08190972222224,
- },
- "id": "6",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540570000000,
- "collisionWidth": 14875919,
- "height": 22.5,
- "left": 1254.6296296296296,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 37.5,
- "width": 172.1749884259259,
- },
- "id": "1",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540620000000,
- "collisionWidth": 20397548,
- "height": 22.5,
- "left": 1833.3333333333333,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 7.5,
- "width": 236.08273148148123,
- },
- "id": "2",
- },
- ],
- },
- "1": Object {
- "group": Object {
- "id": "2",
- },
- "index": 1,
- "items": Array [],
- },
- "2": Object {
- "group": Object {
- "id": "3",
- },
- "index": 2,
- "items": Array [
- Object {
- "dimensions": Object {
- "collisionLeft": 1540656000000,
- "collisionWidth": 20397548,
- "height": 22.5,
- "left": 2250,
- "order": Object {
- "group": Object {
- "id": "3",
- },
- "index": 2,
- },
- "stack": true,
- "top": 105,
- "width": 236.08273148148146,
- },
- "id": "3",
- },
- ],
- },
-}
-`;
diff --git a/__tests__/utils/calendar/__snapshots__/get-groups-with-item-dimensions.js.snap b/__tests__/utils/calendar/__snapshots__/get-groups-with-item-dimensions.js.snap
new file mode 100644
index 000000000..3f04eb86a
--- /dev/null
+++ b/__tests__/utils/calendar/__snapshots__/get-groups-with-item-dimensions.js.snap
@@ -0,0 +1,167 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`getGroupsWithItemDimensions should work as expected 1`] = `
+Object {
+ "1": Object {
+ "group": Object {
+ "id": "1",
+ },
+ "height": 60,
+ "index": 0,
+ "itemDimensions": Array [
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540540000000,
+ "collisionWidth": 6803877,
+ "height": 22.5,
+ "left": 1449.074074074074,
+ "stack": true,
+ "top": 3.75,
+ "width": 78.74857638888898,
+ },
+ "id": "0",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540532800000,
+ "collisionWidth": 21203877,
+ "height": 22.5,
+ "left": 1365.7407407407406,
+ "stack": true,
+ "top": 33.75,
+ "width": 245.4152430555555,
+ },
+ "id": "5",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540550800000,
+ "collisionWidth": 24803877,
+ "height": 22.5,
+ "left": 1574.074074074074,
+ "stack": true,
+ "top": 3.75,
+ "width": 287.08190972222224,
+ },
+ "id": "6",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540570000000,
+ "collisionWidth": 14875919,
+ "height": 22.5,
+ "left": 1796.2962962962963,
+ "stack": true,
+ "top": 33.75,
+ "width": 172.1749884259259,
+ },
+ "id": "1",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540620000000,
+ "collisionWidth": 20397548,
+ "height": 22.5,
+ "left": 2375,
+ "stack": true,
+ "top": 3.75,
+ "width": 236.08273148148146,
+ },
+ "id": "2",
+ },
+ ],
+ "items": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "end_time": 1540546803877,
+ "group": "1",
+ "id": "0",
+ "start_time": 1540540000000,
+ "title": "title 0",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540554003877,
+ "group": "1",
+ "id": "5",
+ "start_time": 1540532800000,
+ "title": "title 5",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540575603877,
+ "group": "1",
+ "id": "6",
+ "start_time": 1540550800000,
+ "title": "title 6",
+ },
+ Object {
+ "canMove": true,
+ "canResize": "both",
+ "end_time": 1540584875919,
+ "group": "1",
+ "id": "1",
+ "start_time": 1540570000000,
+ "title": "title 1",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540640397548,
+ "group": "1",
+ "id": "2",
+ "start_time": 1540620000000,
+ "title": "title 2",
+ },
+ ],
+ },
+ "2": Object {
+ "group": Object {
+ "id": "2",
+ },
+ "height": 30,
+ "index": 1,
+ "itemDimensions": Array [],
+ "items": Array [],
+ },
+ "3": Object {
+ "group": Object {
+ "id": "3",
+ },
+ "height": 30,
+ "index": 2,
+ "itemDimensions": Array [
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540656000000,
+ "collisionWidth": 20397548,
+ "height": 22.5,
+ "left": 2791.6666666666665,
+ "stack": true,
+ "top": 3.75,
+ "width": 208.33333333333348,
+ },
+ "id": "3",
+ },
+ ],
+ "items": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540676397548,
+ "group": "3",
+ "id": "3",
+ "start_time": 1540656000000,
+ "title": "title 3",
+ },
+ ],
+ },
+}
+`;
diff --git a/__tests__/utils/calendar/__snapshots__/get-item-dimensions.js.snap b/__tests__/utils/calendar/__snapshots__/get-item-dimensions.js.snap
index 06f90cb2d..92d01306a 100644
--- a/__tests__/utils/calendar/__snapshots__/get-item-dimensions.js.snap
+++ b/__tests__/utils/calendar/__snapshots__/get-item-dimensions.js.snap
@@ -7,12 +7,6 @@ Object {
"collisionWidth": 6803877,
"height": 60,
"left": 1449.074074074074,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
"stack": true,
"top": null,
"width": 78.74857638888898,
diff --git a/__tests__/utils/calendar/__snapshots__/get-ordered-groups-with-items.js.snap b/__tests__/utils/calendar/__snapshots__/get-ordered-groups-with-items.js.snap
new file mode 100644
index 000000000..f8728a9c0
--- /dev/null
+++ b/__tests__/utils/calendar/__snapshots__/get-ordered-groups-with-items.js.snap
@@ -0,0 +1,87 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`getGroupWithItemDimensions should work as expected 1`] = `
+Object {
+ "1": Object {
+ "group": Object {
+ "id": "1",
+ },
+ "index": 0,
+ "items": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "end_time": 1540546803877,
+ "group": "1",
+ "id": "0",
+ "start_time": 1540540000000,
+ "title": "title 0",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540554003877,
+ "group": "1",
+ "id": "5",
+ "start_time": 1540532800000,
+ "title": "title 5",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540575603877,
+ "group": "1",
+ "id": "6",
+ "start_time": 1540550800000,
+ "title": "title 6",
+ },
+ Object {
+ "canMove": true,
+ "canResize": "both",
+ "end_time": 1540584875919,
+ "group": "1",
+ "id": "1",
+ "start_time": 1540570000000,
+ "title": "title 1",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540640397548,
+ "group": "1",
+ "id": "2",
+ "start_time": 1540620000000,
+ "title": "title 2",
+ },
+ ],
+ },
+ "2": Object {
+ "group": Object {
+ "id": "2",
+ },
+ "index": 1,
+ "items": Array [],
+ },
+ "3": Object {
+ "group": Object {
+ "id": "3",
+ },
+ "index": 2,
+ "items": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540676397548,
+ "group": "3",
+ "id": "3",
+ "start_time": 1540656000000,
+ "title": "title 3",
+ },
+ ],
+ },
+}
+`;
diff --git a/__tests__/utils/calendar/__snapshots__/stack-all.js.snap b/__tests__/utils/calendar/__snapshots__/stack-all.js.snap
deleted file mode 100644
index 7121386fb..000000000
--- a/__tests__/utils/calendar/__snapshots__/stack-all.js.snap
+++ /dev/null
@@ -1,33 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`stackAll works as expected not stacked 1`] = `
-Object {
- "groupHeights": Array [
- 60,
- 60,
- 60,
- ],
- "groupTops": Array [
- 0,
- 60,
- 120,
- ],
- "height": 180,
-}
-`;
-
-exports[`stackAll works as expected stacked 1`] = `
-Object {
- "groupHeights": Array [
- 60,
- 60,
- 60,
- ],
- "groupTops": Array [
- 0,
- 60,
- 120,
- ],
- "height": 180,
-}
-`;
diff --git a/__tests__/utils/calendar/__snapshots__/stack-group.js.snap b/__tests__/utils/calendar/__snapshots__/stack-group.js.snap
index 759f9e9f0..fae7aac14 100644
--- a/__tests__/utils/calendar/__snapshots__/stack-group.js.snap
+++ b/__tests__/utils/calendar/__snapshots__/stack-group.js.snap
@@ -2,14 +2,14 @@
exports[`stackGroup should not stack list of items 1`] = `
Object {
- "groupHeight": 0,
+ "groupHeight": 30,
"verticalMargin": 0,
}
`;
exports[`stackGroup should stack list of items 1`] = `
Object {
- "groupHeight": 0,
+ "groupHeight": 30,
"verticalMargin": 3.75,
}
`;
diff --git a/__tests__/utils/calendar/__snapshots__/stack-items.js.snap b/__tests__/utils/calendar/__snapshots__/stack-items.js.snap
deleted file mode 100644
index 9d0000a46..000000000
--- a/__tests__/utils/calendar/__snapshots__/stack-items.js.snap
+++ /dev/null
@@ -1,631 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`stackItems should stack items while moving an item 1`] = `
-Object {
- "dimensionItems": Array [
- Object {
- "dimensions": Object {
- "collisionLeft": 1540543600000,
- "collisionWidth": 6803877,
- "height": 22.5,
- "left": 4472.222222222223,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 3.75,
- "width": 236.24572916666602,
- },
- "id": "0",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540532800000,
- "collisionWidth": 21203877,
- "height": 22.5,
- "left": 4097.222222222223,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 33.75,
- "width": 736.245729166666,
- },
- "id": "5",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540550800000,
- "collisionWidth": 24803877,
- "height": 22.5,
- "left": 4722.222222222223,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 3.75,
- "width": 861.245729166666,
- },
- "id": "6",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540570000000,
- "collisionWidth": 14875919,
- "height": 22.5,
- "left": 5388.888888888889,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 33.75,
- "width": 516.5249652777784,
- },
- "id": "1",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540620000000,
- "collisionWidth": 20397548,
- "height": 22.5,
- "left": 7125,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 3.75,
- "width": 708.2481944444444,
- },
- "id": "2",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540656000000,
- "collisionWidth": 20397548,
- "height": 22.5,
- "left": 8375,
- "order": Object {
- "group": Object {
- "id": "3",
- },
- "index": 2,
- },
- "stack": true,
- "top": 93.75,
- "width": 625,
- },
- "id": "3",
- },
- ],
- "groupHeights": Array [
- 60,
- 30,
- 30,
- ],
- "groupTops": Array [
- 0,
- 60,
- 90,
- ],
- "height": 120,
-}
-`;
-
-exports[`stackItems should stack items while resize item left 1`] = `
-Object {
- "dimensionItems": Array [
- Object {
- "dimensions": Object {
- "collisionLeft": 1540543600000,
- "collisionWidth": 3203877,
- "height": 22.5,
- "left": 4472.222222222223,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 3.75,
- "width": 111.24572916666602,
- },
- "id": "0",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540532800000,
- "collisionWidth": 21203877,
- "height": 22.5,
- "left": 4097.222222222223,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 33.75,
- "width": 736.245729166666,
- },
- "id": "5",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540550800000,
- "collisionWidth": 24803877,
- "height": 22.5,
- "left": 4722.222222222223,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 3.75,
- "width": 861.245729166666,
- },
- "id": "6",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540570000000,
- "collisionWidth": 14875919,
- "height": 22.5,
- "left": 5388.888888888889,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 33.75,
- "width": 516.5249652777784,
- },
- "id": "1",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540620000000,
- "collisionWidth": 20397548,
- "height": 22.5,
- "left": 7125,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 3.75,
- "width": 708.2481944444444,
- },
- "id": "2",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540656000000,
- "collisionWidth": 20397548,
- "height": 22.5,
- "left": 8375,
- "order": Object {
- "group": Object {
- "id": "3",
- },
- "index": 2,
- },
- "stack": true,
- "top": 93.75,
- "width": 625,
- },
- "id": "3",
- },
- ],
- "groupHeights": Array [
- 60,
- 30,
- 30,
- ],
- "groupTops": Array [
- 0,
- 60,
- 90,
- ],
- "height": 120,
-}
-`;
-
-exports[`stackItems should stack items while resize item right 1`] = `
-Object {
- "dimensionItems": Array [
- Object {
- "dimensions": Object {
- "collisionLeft": 1540540000000,
- "collisionWidth": 10403877,
- "height": 22.5,
- "left": 4347.222222222223,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 3.75,
- "width": 361.245729166666,
- },
- "id": "0",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540532800000,
- "collisionWidth": 21203877,
- "height": 22.5,
- "left": 4097.222222222223,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 33.75,
- "width": 736.245729166666,
- },
- "id": "5",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540550800000,
- "collisionWidth": 24803877,
- "height": 22.5,
- "left": 4722.222222222223,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 3.75,
- "width": 861.245729166666,
- },
- "id": "6",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540570000000,
- "collisionWidth": 14875919,
- "height": 22.5,
- "left": 5388.888888888889,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 33.75,
- "width": 516.5249652777784,
- },
- "id": "1",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540620000000,
- "collisionWidth": 20397548,
- "height": 22.5,
- "left": 7125,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 3.75,
- "width": 708.2481944444444,
- },
- "id": "2",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540656000000,
- "collisionWidth": 20397548,
- "height": 22.5,
- "left": 8375,
- "order": Object {
- "group": Object {
- "id": "3",
- },
- "index": 2,
- },
- "stack": true,
- "top": 93.75,
- "width": 625,
- },
- "id": "3",
- },
- ],
- "groupHeights": Array [
- 60,
- 30,
- 30,
- ],
- "groupTops": Array [
- 0,
- 60,
- 90,
- ],
- "height": 120,
-}
-`;
-
-exports[`stackItems work as expected 1`] = `
-Object {
- "dimensionItems": Array [
- Object {
- "dimensions": Object {
- "collisionLeft": 1540540000000,
- "collisionWidth": 6803877,
- "height": 22.5,
- "left": 4347.222222222223,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 3.75,
- "width": 236.24572916666602,
- },
- "id": "0",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540532800000,
- "collisionWidth": 21203877,
- "height": 22.5,
- "left": 4097.222222222223,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 33.75,
- "width": 736.245729166666,
- },
- "id": "5",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540550800000,
- "collisionWidth": 24803877,
- "height": 22.5,
- "left": 4722.222222222223,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 3.75,
- "width": 861.245729166666,
- },
- "id": "6",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540570000000,
- "collisionWidth": 14875919,
- "height": 22.5,
- "left": 5388.888888888889,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 33.75,
- "width": 516.5249652777784,
- },
- "id": "1",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540620000000,
- "collisionWidth": 20397548,
- "height": 22.5,
- "left": 7125,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 3.75,
- "width": 708.2481944444444,
- },
- "id": "2",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540656000000,
- "collisionWidth": 20397548,
- "height": 22.5,
- "left": 8375,
- "order": Object {
- "group": Object {
- "id": "3",
- },
- "index": 2,
- },
- "stack": true,
- "top": 93.75,
- "width": 625,
- },
- "id": "3",
- },
- ],
- "groupHeights": Array [
- 60,
- 30,
- 30,
- ],
- "groupTops": Array [
- 0,
- 60,
- 90,
- ],
- "height": 120,
-}
-`;
-
-exports[`stackItems work as expected no stack 1`] = `
-Object {
- "dimensionItems": Array [
- Object {
- "dimensions": Object {
- "collisionLeft": 1540540000000,
- "collisionWidth": 6803877,
- "height": 22.5,
- "left": 4347.222222222223,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 3.75,
- "width": 236.24572916666602,
- },
- "id": "0",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540532800000,
- "collisionWidth": 21203877,
- "height": 22.5,
- "left": 4097.222222222223,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 3.75,
- "width": 736.245729166666,
- },
- "id": "5",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540550800000,
- "collisionWidth": 24803877,
- "height": 22.5,
- "left": 4722.222222222223,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 3.75,
- "width": 861.245729166666,
- },
- "id": "6",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540570000000,
- "collisionWidth": 14875919,
- "height": 22.5,
- "left": 5388.888888888889,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 3.75,
- "width": 516.5249652777784,
- },
- "id": "1",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540620000000,
- "collisionWidth": 20397548,
- "height": 22.5,
- "left": 7125,
- "order": Object {
- "group": Object {
- "id": "1",
- },
- "index": 0,
- },
- "stack": true,
- "top": 3.75,
- "width": 708.2481944444444,
- },
- "id": "2",
- },
- Object {
- "dimensions": Object {
- "collisionLeft": 1540656000000,
- "collisionWidth": 20397548,
- "height": 22.5,
- "left": 8375,
- "order": Object {
- "group": Object {
- "id": "3",
- },
- "index": 2,
- },
- "stack": true,
- "top": 63.75,
- "width": 625,
- },
- "id": "3",
- },
- ],
- "groupHeights": Array [
- 30,
- 30,
- 30,
- ],
- "groupTops": Array [
- 0,
- 30,
- 60,
- ],
- "height": 90,
-}
-`;
diff --git a/__tests__/utils/calendar/__snapshots__/stack-timeline-items.js.snap b/__tests__/utils/calendar/__snapshots__/stack-timeline-items.js.snap
new file mode 100644
index 000000000..7df40ae81
--- /dev/null
+++ b/__tests__/utils/calendar/__snapshots__/stack-timeline-items.js.snap
@@ -0,0 +1,1196 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`stackItems should stack items while moving an item 1`] = `
+Object {
+ "groupHeights": Array [
+ 60,
+ 30,
+ 30,
+ ],
+ "groupTops": Array [
+ 0,
+ 60,
+ 90,
+ ],
+ "groupsWithItemsDimensions": Object {
+ "1": Object {
+ "group": Object {
+ "id": "1",
+ },
+ "height": 60,
+ "index": 0,
+ "itemDimensions": Array [
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540543600000,
+ "collisionWidth": 6803877,
+ "height": 22.5,
+ "left": 4472.222222222223,
+ "stack": true,
+ "top": 3.75,
+ "width": 236.24572916666602,
+ },
+ "id": "0",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540532800000,
+ "collisionWidth": 21203877,
+ "height": 22.5,
+ "left": 4097.222222222223,
+ "stack": true,
+ "top": 33.75,
+ "width": 736.245729166666,
+ },
+ "id": "5",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540550800000,
+ "collisionWidth": 24803877,
+ "height": 22.5,
+ "left": 4722.222222222223,
+ "stack": true,
+ "top": 3.75,
+ "width": 861.245729166666,
+ },
+ "id": "6",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540570000000,
+ "collisionWidth": 14875919,
+ "height": 22.5,
+ "left": 5388.888888888889,
+ "stack": true,
+ "top": 33.75,
+ "width": 516.5249652777784,
+ },
+ "id": "1",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540620000000,
+ "collisionWidth": 20397548,
+ "height": 22.5,
+ "left": 7125,
+ "stack": true,
+ "top": 3.75,
+ "width": 708.2481944444444,
+ },
+ "id": "2",
+ },
+ ],
+ "items": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "end_time": 1540550403877,
+ "group": "1",
+ "id": "0",
+ "start_time": 1540543600000,
+ "title": "title 0",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540554003877,
+ "group": "1",
+ "id": "5",
+ "start_time": 1540532800000,
+ "title": "title 5",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540575603877,
+ "group": "1",
+ "id": "6",
+ "start_time": 1540550800000,
+ "title": "title 6",
+ },
+ Object {
+ "canMove": true,
+ "canResize": "both",
+ "end_time": 1540584875919,
+ "group": "1",
+ "id": "1",
+ "start_time": 1540570000000,
+ "title": "title 1",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540640397548,
+ "group": "1",
+ "id": "2",
+ "start_time": 1540620000000,
+ "title": "title 2",
+ },
+ ],
+ },
+ "2": Object {
+ "group": Object {
+ "id": "2",
+ },
+ "height": 30,
+ "index": 1,
+ "itemDimensions": Array [],
+ "items": Array [],
+ },
+ "3": Object {
+ "group": Object {
+ "id": "3",
+ },
+ "height": 30,
+ "index": 2,
+ "itemDimensions": Array [
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540656000000,
+ "collisionWidth": 20397548,
+ "height": 22.5,
+ "left": 8375,
+ "stack": true,
+ "top": 3.75,
+ "width": 625,
+ },
+ "id": "3",
+ },
+ ],
+ "items": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540676397548,
+ "group": "3",
+ "id": "3",
+ "start_time": 1540656000000,
+ "title": "title 3",
+ },
+ ],
+ },
+ },
+ "height": 120,
+ "itemsWithInteractions": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "end_time": 1540550403877,
+ "group": "1",
+ "id": "0",
+ "start_time": 1540543600000,
+ "title": "title 0",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540554003877,
+ "group": "1",
+ "id": "5",
+ "start_time": 1540532800000,
+ "title": "title 5",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540575603877,
+ "group": "1",
+ "id": "6",
+ "start_time": 1540550800000,
+ "title": "title 6",
+ },
+ Object {
+ "canMove": true,
+ "canResize": "both",
+ "end_time": 1540584875919,
+ "group": "1",
+ "id": "1",
+ "start_time": 1540570000000,
+ "title": "title 1",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540640397548,
+ "group": "1",
+ "id": "2",
+ "start_time": 1540620000000,
+ "title": "title 2",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540676397548,
+ "group": "3",
+ "id": "3",
+ "start_time": 1540656000000,
+ "title": "title 3",
+ },
+ ],
+}
+`;
+
+exports[`stackItems should stack items while resize item left 1`] = `
+Object {
+ "groupHeights": Array [
+ 60,
+ 30,
+ 30,
+ ],
+ "groupTops": Array [
+ 0,
+ 60,
+ 90,
+ ],
+ "groupsWithItemsDimensions": Object {
+ "1": Object {
+ "group": Object {
+ "id": "1",
+ },
+ "height": 60,
+ "index": 0,
+ "itemDimensions": Array [
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540543600000,
+ "collisionWidth": 3203877,
+ "height": 22.5,
+ "left": 4472.222222222223,
+ "stack": true,
+ "top": 3.75,
+ "width": 111.24572916666602,
+ },
+ "id": "0",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540532800000,
+ "collisionWidth": 21203877,
+ "height": 22.5,
+ "left": 4097.222222222223,
+ "stack": true,
+ "top": 33.75,
+ "width": 736.245729166666,
+ },
+ "id": "5",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540550800000,
+ "collisionWidth": 24803877,
+ "height": 22.5,
+ "left": 4722.222222222223,
+ "stack": true,
+ "top": 3.75,
+ "width": 861.245729166666,
+ },
+ "id": "6",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540570000000,
+ "collisionWidth": 14875919,
+ "height": 22.5,
+ "left": 5388.888888888889,
+ "stack": true,
+ "top": 33.75,
+ "width": 516.5249652777784,
+ },
+ "id": "1",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540620000000,
+ "collisionWidth": 20397548,
+ "height": 22.5,
+ "left": 7125,
+ "stack": true,
+ "top": 3.75,
+ "width": 708.2481944444444,
+ },
+ "id": "2",
+ },
+ ],
+ "items": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "end_time": 1540546803877,
+ "group": "1",
+ "id": "0",
+ "start_time": 1540543600000,
+ "title": "title 0",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540554003877,
+ "group": "1",
+ "id": "5",
+ "start_time": 1540532800000,
+ "title": "title 5",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540575603877,
+ "group": "1",
+ "id": "6",
+ "start_time": 1540550800000,
+ "title": "title 6",
+ },
+ Object {
+ "canMove": true,
+ "canResize": "both",
+ "end_time": 1540584875919,
+ "group": "1",
+ "id": "1",
+ "start_time": 1540570000000,
+ "title": "title 1",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540640397548,
+ "group": "1",
+ "id": "2",
+ "start_time": 1540620000000,
+ "title": "title 2",
+ },
+ ],
+ },
+ "2": Object {
+ "group": Object {
+ "id": "2",
+ },
+ "height": 30,
+ "index": 1,
+ "itemDimensions": Array [],
+ "items": Array [],
+ },
+ "3": Object {
+ "group": Object {
+ "id": "3",
+ },
+ "height": 30,
+ "index": 2,
+ "itemDimensions": Array [
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540656000000,
+ "collisionWidth": 20397548,
+ "height": 22.5,
+ "left": 8375,
+ "stack": true,
+ "top": 3.75,
+ "width": 625,
+ },
+ "id": "3",
+ },
+ ],
+ "items": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540676397548,
+ "group": "3",
+ "id": "3",
+ "start_time": 1540656000000,
+ "title": "title 3",
+ },
+ ],
+ },
+ },
+ "height": 120,
+ "itemsWithInteractions": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "end_time": 1540546803877,
+ "group": "1",
+ "id": "0",
+ "start_time": 1540543600000,
+ "title": "title 0",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540554003877,
+ "group": "1",
+ "id": "5",
+ "start_time": 1540532800000,
+ "title": "title 5",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540575603877,
+ "group": "1",
+ "id": "6",
+ "start_time": 1540550800000,
+ "title": "title 6",
+ },
+ Object {
+ "canMove": true,
+ "canResize": "both",
+ "end_time": 1540584875919,
+ "group": "1",
+ "id": "1",
+ "start_time": 1540570000000,
+ "title": "title 1",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540640397548,
+ "group": "1",
+ "id": "2",
+ "start_time": 1540620000000,
+ "title": "title 2",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540676397548,
+ "group": "3",
+ "id": "3",
+ "start_time": 1540656000000,
+ "title": "title 3",
+ },
+ ],
+}
+`;
+
+exports[`stackItems should stack items while resize item right 1`] = `
+Object {
+ "groupHeights": Array [
+ 60,
+ 30,
+ 30,
+ ],
+ "groupTops": Array [
+ 0,
+ 60,
+ 90,
+ ],
+ "groupsWithItemsDimensions": Object {
+ "1": Object {
+ "group": Object {
+ "id": "1",
+ },
+ "height": 60,
+ "index": 0,
+ "itemDimensions": Array [
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540540000000,
+ "collisionWidth": 10403877,
+ "height": 22.5,
+ "left": 4347.222222222223,
+ "stack": true,
+ "top": 3.75,
+ "width": 361.245729166666,
+ },
+ "id": "0",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540532800000,
+ "collisionWidth": 21203877,
+ "height": 22.5,
+ "left": 4097.222222222223,
+ "stack": true,
+ "top": 33.75,
+ "width": 736.245729166666,
+ },
+ "id": "5",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540550800000,
+ "collisionWidth": 24803877,
+ "height": 22.5,
+ "left": 4722.222222222223,
+ "stack": true,
+ "top": 3.75,
+ "width": 861.245729166666,
+ },
+ "id": "6",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540570000000,
+ "collisionWidth": 14875919,
+ "height": 22.5,
+ "left": 5388.888888888889,
+ "stack": true,
+ "top": 33.75,
+ "width": 516.5249652777784,
+ },
+ "id": "1",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540620000000,
+ "collisionWidth": 20397548,
+ "height": 22.5,
+ "left": 7125,
+ "stack": true,
+ "top": 3.75,
+ "width": 708.2481944444444,
+ },
+ "id": "2",
+ },
+ ],
+ "items": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "end_time": 1540550403877,
+ "group": "1",
+ "id": "0",
+ "start_time": 1540540000000,
+ "title": "title 0",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540554003877,
+ "group": "1",
+ "id": "5",
+ "start_time": 1540532800000,
+ "title": "title 5",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540575603877,
+ "group": "1",
+ "id": "6",
+ "start_time": 1540550800000,
+ "title": "title 6",
+ },
+ Object {
+ "canMove": true,
+ "canResize": "both",
+ "end_time": 1540584875919,
+ "group": "1",
+ "id": "1",
+ "start_time": 1540570000000,
+ "title": "title 1",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540640397548,
+ "group": "1",
+ "id": "2",
+ "start_time": 1540620000000,
+ "title": "title 2",
+ },
+ ],
+ },
+ "2": Object {
+ "group": Object {
+ "id": "2",
+ },
+ "height": 30,
+ "index": 1,
+ "itemDimensions": Array [],
+ "items": Array [],
+ },
+ "3": Object {
+ "group": Object {
+ "id": "3",
+ },
+ "height": 30,
+ "index": 2,
+ "itemDimensions": Array [
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540656000000,
+ "collisionWidth": 20397548,
+ "height": 22.5,
+ "left": 8375,
+ "stack": true,
+ "top": 3.75,
+ "width": 625,
+ },
+ "id": "3",
+ },
+ ],
+ "items": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540676397548,
+ "group": "3",
+ "id": "3",
+ "start_time": 1540656000000,
+ "title": "title 3",
+ },
+ ],
+ },
+ },
+ "height": 120,
+ "itemsWithInteractions": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "end_time": 1540550403877,
+ "group": "1",
+ "id": "0",
+ "start_time": 1540540000000,
+ "title": "title 0",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540554003877,
+ "group": "1",
+ "id": "5",
+ "start_time": 1540532800000,
+ "title": "title 5",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540575603877,
+ "group": "1",
+ "id": "6",
+ "start_time": 1540550800000,
+ "title": "title 6",
+ },
+ Object {
+ "canMove": true,
+ "canResize": "both",
+ "end_time": 1540584875919,
+ "group": "1",
+ "id": "1",
+ "start_time": 1540570000000,
+ "title": "title 1",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540640397548,
+ "group": "1",
+ "id": "2",
+ "start_time": 1540620000000,
+ "title": "title 2",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540676397548,
+ "group": "3",
+ "id": "3",
+ "start_time": 1540656000000,
+ "title": "title 3",
+ },
+ ],
+}
+`;
+
+exports[`stackItems work as expected 1`] = `
+Object {
+ "groupHeights": Array [
+ 60,
+ 30,
+ 30,
+ ],
+ "groupTops": Array [
+ 0,
+ 60,
+ 90,
+ ],
+ "groupsWithItemsDimensions": Object {
+ "1": Object {
+ "group": Object {
+ "id": "1",
+ },
+ "height": 60,
+ "index": 0,
+ "itemDimensions": Array [
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540540000000,
+ "collisionWidth": 6803877,
+ "height": 22.5,
+ "left": 4347.222222222223,
+ "stack": true,
+ "top": 3.75,
+ "width": 236.24572916666602,
+ },
+ "id": "0",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540532800000,
+ "collisionWidth": 21203877,
+ "height": 22.5,
+ "left": 4097.222222222223,
+ "stack": true,
+ "top": 33.75,
+ "width": 736.245729166666,
+ },
+ "id": "5",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540550800000,
+ "collisionWidth": 24803877,
+ "height": 22.5,
+ "left": 4722.222222222223,
+ "stack": true,
+ "top": 3.75,
+ "width": 861.245729166666,
+ },
+ "id": "6",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540570000000,
+ "collisionWidth": 14875919,
+ "height": 22.5,
+ "left": 5388.888888888889,
+ "stack": true,
+ "top": 33.75,
+ "width": 516.5249652777784,
+ },
+ "id": "1",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540620000000,
+ "collisionWidth": 20397548,
+ "height": 22.5,
+ "left": 7125,
+ "stack": true,
+ "top": 3.75,
+ "width": 708.2481944444444,
+ },
+ "id": "2",
+ },
+ ],
+ "items": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "end_time": 1540546803877,
+ "group": "1",
+ "id": "0",
+ "start_time": 1540540000000,
+ "title": "title 0",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540554003877,
+ "group": "1",
+ "id": "5",
+ "start_time": 1540532800000,
+ "title": "title 5",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540575603877,
+ "group": "1",
+ "id": "6",
+ "start_time": 1540550800000,
+ "title": "title 6",
+ },
+ Object {
+ "canMove": true,
+ "canResize": "both",
+ "end_time": 1540584875919,
+ "group": "1",
+ "id": "1",
+ "start_time": 1540570000000,
+ "title": "title 1",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540640397548,
+ "group": "1",
+ "id": "2",
+ "start_time": 1540620000000,
+ "title": "title 2",
+ },
+ ],
+ },
+ "2": Object {
+ "group": Object {
+ "id": "2",
+ },
+ "height": 30,
+ "index": 1,
+ "itemDimensions": Array [],
+ "items": Array [],
+ },
+ "3": Object {
+ "group": Object {
+ "id": "3",
+ },
+ "height": 30,
+ "index": 2,
+ "itemDimensions": Array [
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540656000000,
+ "collisionWidth": 20397548,
+ "height": 22.5,
+ "left": 8375,
+ "stack": true,
+ "top": 3.75,
+ "width": 625,
+ },
+ "id": "3",
+ },
+ ],
+ "items": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540676397548,
+ "group": "3",
+ "id": "3",
+ "start_time": 1540656000000,
+ "title": "title 3",
+ },
+ ],
+ },
+ },
+ "height": 120,
+ "itemsWithInteractions": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "end_time": 1540546803877,
+ "group": "1",
+ "id": "0",
+ "start_time": 1540540000000,
+ "title": "title 0",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540554003877,
+ "group": "1",
+ "id": "5",
+ "start_time": 1540532800000,
+ "title": "title 5",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540575603877,
+ "group": "1",
+ "id": "6",
+ "start_time": 1540550800000,
+ "title": "title 6",
+ },
+ Object {
+ "canMove": true,
+ "canResize": "both",
+ "end_time": 1540584875919,
+ "group": "1",
+ "id": "1",
+ "start_time": 1540570000000,
+ "title": "title 1",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540640397548,
+ "group": "1",
+ "id": "2",
+ "start_time": 1540620000000,
+ "title": "title 2",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540676397548,
+ "group": "3",
+ "id": "3",
+ "start_time": 1540656000000,
+ "title": "title 3",
+ },
+ ],
+}
+`;
+
+exports[`stackItems work as expected no stack 1`] = `
+Object {
+ "groupHeights": Array [
+ 30,
+ 30,
+ 30,
+ ],
+ "groupTops": Array [
+ 0,
+ 30,
+ 60,
+ ],
+ "groupsWithItemsDimensions": Object {
+ "1": Object {
+ "group": Object {
+ "id": "1",
+ },
+ "height": 30,
+ "index": 0,
+ "itemDimensions": Array [
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540540000000,
+ "collisionWidth": 6803877,
+ "height": 22.5,
+ "left": 4347.222222222223,
+ "stack": true,
+ "top": 3.75,
+ "width": 236.24572916666602,
+ },
+ "id": "0",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540532800000,
+ "collisionWidth": 21203877,
+ "height": 22.5,
+ "left": 4097.222222222223,
+ "stack": true,
+ "top": 3.75,
+ "width": 736.245729166666,
+ },
+ "id": "5",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540550800000,
+ "collisionWidth": 24803877,
+ "height": 22.5,
+ "left": 4722.222222222223,
+ "stack": true,
+ "top": 3.75,
+ "width": 861.245729166666,
+ },
+ "id": "6",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540570000000,
+ "collisionWidth": 14875919,
+ "height": 22.5,
+ "left": 5388.888888888889,
+ "stack": true,
+ "top": 3.75,
+ "width": 516.5249652777784,
+ },
+ "id": "1",
+ },
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540620000000,
+ "collisionWidth": 20397548,
+ "height": 22.5,
+ "left": 7125,
+ "stack": true,
+ "top": 3.75,
+ "width": 708.2481944444444,
+ },
+ "id": "2",
+ },
+ ],
+ "items": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "end_time": 1540546803877,
+ "group": "1",
+ "id": "0",
+ "start_time": 1540540000000,
+ "title": "title 0",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540554003877,
+ "group": "1",
+ "id": "5",
+ "start_time": 1540532800000,
+ "title": "title 5",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540575603877,
+ "group": "1",
+ "id": "6",
+ "start_time": 1540550800000,
+ "title": "title 6",
+ },
+ Object {
+ "canMove": true,
+ "canResize": "both",
+ "end_time": 1540584875919,
+ "group": "1",
+ "id": "1",
+ "start_time": 1540570000000,
+ "title": "title 1",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540640397548,
+ "group": "1",
+ "id": "2",
+ "start_time": 1540620000000,
+ "title": "title 2",
+ },
+ ],
+ },
+ "2": Object {
+ "group": Object {
+ "id": "2",
+ },
+ "height": 30,
+ "index": 1,
+ "itemDimensions": Array [],
+ "items": Array [],
+ },
+ "3": Object {
+ "group": Object {
+ "id": "3",
+ },
+ "height": 30,
+ "index": 2,
+ "itemDimensions": Array [
+ Object {
+ "dimensions": Object {
+ "collisionLeft": 1540656000000,
+ "collisionWidth": 20397548,
+ "height": 22.5,
+ "left": 8375,
+ "stack": true,
+ "top": 3.75,
+ "width": 625,
+ },
+ "id": "3",
+ },
+ ],
+ "items": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540676397548,
+ "group": "3",
+ "id": "3",
+ "start_time": 1540656000000,
+ "title": "title 3",
+ },
+ ],
+ },
+ },
+ "height": 90,
+ "itemsWithInteractions": Array [
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "end_time": 1540546803877,
+ "group": "1",
+ "id": "0",
+ "start_time": 1540540000000,
+ "title": "title 0",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540554003877,
+ "group": "1",
+ "id": "5",
+ "start_time": 1540532800000,
+ "title": "title 5",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540575603877,
+ "group": "1",
+ "id": "6",
+ "start_time": 1540550800000,
+ "title": "title 6",
+ },
+ Object {
+ "canMove": true,
+ "canResize": "both",
+ "end_time": 1540584875919,
+ "group": "1",
+ "id": "1",
+ "start_time": 1540570000000,
+ "title": "title 1",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540640397548,
+ "group": "1",
+ "id": "2",
+ "start_time": 1540620000000,
+ "title": "title 2",
+ },
+ Object {
+ "canMove": false,
+ "canResize": false,
+ "className": "",
+ "end_time": 1540676397548,
+ "group": "3",
+ "id": "3",
+ "start_time": 1540656000000,
+ "title": "title 3",
+ },
+ ],
+}
+`;
diff --git a/__tests__/utils/calendar/calculate-scroll-canvas.js b/__tests__/utils/calendar/calculate-scroll-canvas.js
index 71f37a27f..192089d2f 100644
--- a/__tests__/utils/calendar/calculate-scroll-canvas.js
+++ b/__tests__/utils/calendar/calculate-scroll-canvas.js
@@ -1,7 +1,11 @@
import { calculateScrollCanvas } from 'lib/utility/calendar'
-import {items, groups} from '../../../__fixtures__/itemsAndGroups'
-import {props, state, visibleTimeStart, visibleTimeEnd} from '../../../__fixtures__/stateAndProps'
-
+import { items, groups } from '../../../__fixtures__/itemsAndGroups'
+import {
+ props,
+ state,
+ visibleTimeStart,
+ visibleTimeEnd
+} from '../../../__fixtures__/stateAndProps'
describe('calculateScrollCanvas', () => {
it('should calculate new scroll state', () => {
@@ -18,7 +22,7 @@ describe('calculateScrollCanvas', () => {
)
expect(result).toHaveProperty('visibleTimeStart')
expect(result).toHaveProperty('visibleTimeEnd')
- expect(result).toHaveProperty('dimensionItems')
+ expect(result).toHaveProperty('groupsWithItemsDimensions')
})
it('should calculate new scroll state correctly', () => {
const newStartTime = visibleTimeStart + 13 * 60 * 60 * 1000
@@ -35,8 +39,8 @@ describe('calculateScrollCanvas', () => {
expect(result).toMatchSnapshot()
})
it('should skip new calculation if new visible start and visible end in canvas', () => {
- const newStartTime = visibleTimeStart + 1 * 60 * 60 * 1000
- const newEndTime = visibleTimeEnd + 1 * 60 * 60 * 1000
+ const newStartTime = visibleTimeStart + 1 * 60 * 60 * 1000
+ const newEndTime = visibleTimeEnd + 1 * 60 * 60 * 1000
const result = calculateScrollCanvas(
newStartTime,
newEndTime,
@@ -48,11 +52,11 @@ describe('calculateScrollCanvas', () => {
)
expect(result).toHaveProperty('visibleTimeStart')
expect(result).toHaveProperty('visibleTimeEnd')
- expect(result).not.toHaveProperty('dimensionItems')
+ expect(result).not.toHaveProperty('groupsWithItemsDimensions')
})
it('should force new calculation', () => {
- const newStartTime = visibleTimeStart + 1 * 60 * 60 * 1000
- const newEndTime = visibleTimeEnd + 1 * 60 * 60 * 1000
+ const newStartTime = visibleTimeStart + 1 * 60 * 60 * 1000
+ const newEndTime = visibleTimeEnd + 1 * 60 * 60 * 1000
const result = calculateScrollCanvas(
newStartTime.valueOf(),
newEndTime.valueOf(),
@@ -64,11 +68,11 @@ describe('calculateScrollCanvas', () => {
)
expect(result).toHaveProperty('visibleTimeStart')
expect(result).toHaveProperty('visibleTimeEnd')
- expect(result).toHaveProperty('dimensionItems')
+ expect(result).toHaveProperty('groupsWithItemsDimensions')
})
it('should calculate new state if zoom changed ', () => {
const newStartTime = visibleTimeStart
- const newEndTime = visibleTimeEnd + 1 * 60 * 60 * 1000
+ const newEndTime = visibleTimeEnd + 1 * 60 * 60 * 1000
const result = calculateScrollCanvas(
newStartTime,
newEndTime,
@@ -80,11 +84,11 @@ describe('calculateScrollCanvas', () => {
)
expect(result).toHaveProperty('visibleTimeStart')
expect(result).toHaveProperty('visibleTimeEnd')
- expect(result).toHaveProperty('dimensionItems')
+ expect(result).toHaveProperty('groupsWithItemsDimensions')
})
it('should calculate new state if zoom changed correctly', () => {
const newStartTime = visibleTimeStart
- const newEndTime = visibleTimeEnd + 1 * 60 * 60 * 1000
+ const newEndTime = visibleTimeEnd + 1 * 60 * 60 * 1000
const result = calculateScrollCanvas(
newStartTime,
newEndTime,
diff --git a/__tests__/utils/calendar/get-group-with-item-dimensions.js b/__tests__/utils/calendar/get-group-with-item-dimensions.js
new file mode 100644
index 000000000..de699197b
--- /dev/null
+++ b/__tests__/utils/calendar/get-group-with-item-dimensions.js
@@ -0,0 +1,56 @@
+import {getGroupWithItemDimensions} from 'lib/utility/calendar'
+import {items} from '../../../__fixtures__/itemsAndGroups'
+import {props, state} from '../../../__fixtures__/stateAndProps'
+
+
+describe('getGroupWithItemDimensions', ()=>{
+ it('should work as expected', ()=>{
+ const groupWithItems = {
+ items,
+ }
+ expect(getGroupWithItemDimensions(
+ groupWithItems,
+ props.keys,
+ state.canvasTimeStart,
+ state.canvasTimeEnd,
+ state.width*3,
+ props.lineHeight,
+ props.itemHeightRatio,
+ props.stackItems
+ )).toMatchSnapshot()
+ })
+ it("should pass along group's data with item", ()=>{
+ const groupWithItems = {
+ items,
+ passThrough: '2323'
+ }
+ expect(getGroupWithItemDimensions(
+ groupWithItems,
+ props.keys,
+ state.canvasTimeStart,
+ state.canvasTimeEnd,
+ state.width*3,
+ props.lineHeight,
+ props.itemHeightRatio,
+ props.stackItems
+ )).toEqual(expect.objectContaining({
+ passThrough: expect.any(String)
+ }))
+ })
+ it('should pass new reference of groupWithItems', ()=>{
+ const groupWithItems = {
+ items,
+ }
+ expect(getGroupWithItemDimensions(
+ groupWithItems,
+ props.keys,
+ state.canvasTimeStart,
+ state.canvasTimeEnd,
+ state.width*3,
+ props.lineHeight,
+ props.itemHeightRatio,
+ props.stackItems
+ )).not.toBe(groupWithItems)
+ })
+})
+
diff --git a/__tests__/utils/calendar/get-grouped-items.js b/__tests__/utils/calendar/get-grouped-items.js
deleted file mode 100644
index e9bf0957f..000000000
--- a/__tests__/utils/calendar/get-grouped-items.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import { getGroupedItems } from 'lib/utility/calendar'
-import {orderedGroups, dimensionItems} from '../../../__fixtures__/groupOrderAndItemDimentions'
-
-describe('getGroupedItems', () => {
- it('works as expected', () => {
- expect(getGroupedItems(dimensionItems,orderedGroups)).toMatchSnapshot()
- })
-})
diff --git a/__tests__/utils/calendar/get-groups-cache.js b/__tests__/utils/calendar/get-groups-cache.js
new file mode 100644
index 000000000..3206fe057
--- /dev/null
+++ b/__tests__/utils/calendar/get-groups-cache.js
@@ -0,0 +1,89 @@
+import { getGroupsCache } from 'lib/utility/calendar'
+import { groups, items } from '../../../__fixtures__/itemsAndGroups'
+import { props, state } from '../../../__fixtures__/stateAndProps'
+
+describe('getGroupsCache', () => {
+ it('should map of groupId:function', () => {
+ const mockMethod = jest.fn()
+ const result = getGroupsCache(groups, props.keys, mockMethod)
+ const keys = Object.keys(result)
+ expect(keys).toHaveLength(groups.length)
+ keys.forEach(key => {
+ expect(result[key]).toBeInstanceOf(Function)
+ })
+ })
+ it('should cache result when passed same args', () => {
+ const mockMethod = jest.fn()
+ const oldResult = getGroupsCache(groups, props.keys, mockMethod)
+ const newResult = getGroupsCache(groups, props.keys, mockMethod)
+ const newKeys = Object.keys(newResult)
+ const oldKeys = Object.keys(oldResult)
+ expect(oldResult).toBe(newResult)
+ expect(oldKeys).toEqual(newKeys)
+ newKeys.forEach(key => {
+ expect(newResult[key]).toBe(oldResult[key])
+ })
+ })
+ it('should cache result of methods map', () => {
+ const mockMethod = jest.fn()
+ const groupWithItems = {
+ items
+ }
+ const args = [
+ groupWithItems,
+ props.keys,
+ state.canvasTimeStart,
+ state.canvasTimeEnd,
+ state.width * 3,
+ props.lineHeight,
+ props.itemHeightRatio,
+ props.stackItems
+ ]
+ const result = getGroupsCache(groups, props.keys, mockMethod)
+ const keys = Object.keys(result)
+ keys.forEach(key => {
+ const method = result[key]
+ method(...args)
+ method(...args)
+ expect(mockMethod).toHaveBeenCalledTimes(1)
+ //reset after checking each method before trying the next one in the groupid:method dictionary
+ mockMethod.mockClear();
+ })
+ })
+ it('should call method again if arg is different', () => {
+ const mockMethod = jest.fn()
+ const groupWithItems = {
+ items
+ }
+ const args = [
+ groupWithItems,
+ props.keys,
+ state.canvasTimeStart,
+ state.canvasTimeEnd,
+ state.width * 3,
+ props.lineHeight,
+ props.itemHeightRatio,
+ props.stackItems
+ ]
+ const newArgs = [
+ groupWithItems,
+ props.keys,
+ state.canvasTimeStart + 1,
+ state.canvasTimeEnd,
+ state.width * 3,
+ props.lineHeight,
+ props.itemHeightRatio,
+ props.stackItems
+ ]
+ const result = getGroupsCache(groups, props.keys, mockMethod)
+ const keys = Object.keys(result)
+ keys.forEach(key => {
+ const method = result[key]
+ method(...args)
+ method(...newArgs)
+ expect(mockMethod).toHaveBeenCalledTimes(2)
+ //reset after checking each method before trying the next one in the groupid:method dictionary
+ mockMethod.mockClear();
+ })
+ })
+})
diff --git a/__tests__/utils/calendar/get-groups-with-item-dimensions.js b/__tests__/utils/calendar/get-groups-with-item-dimensions.js
new file mode 100644
index 000000000..09aa0c7a1
--- /dev/null
+++ b/__tests__/utils/calendar/get-groups-with-item-dimensions.js
@@ -0,0 +1,45 @@
+import {
+ getGroupsWithItemDimensions,
+ getOrderedGroupsWithItems
+} from 'lib/utility/calendar'
+import { groups, items } from '../../../__fixtures__/itemsAndGroups'
+import { props, state } from '../../../__fixtures__/stateAndProps'
+
+describe('getGroupsWithItemDimensions', () => {
+ it('should work as expected', () => {
+ const groupsWithItems = getOrderedGroupsWithItems(groups, items, props.keys)
+ const result = getGroupsWithItemDimensions(
+ groupsWithItems,
+ props.keys,
+ props.lineHeight,
+ props.itemHeightRatio,
+ props.stackItems,
+ state.canvasTimeStart,
+ state.canvasTimeEnd,
+ state.width * 3,
+ groups
+ )
+ expect(Object.keys(result)).toHaveLength(groups.length)
+ expect(result).toMatchSnapshot()
+ })
+ it('should cache groups if no params changed', () => {
+ const groupsWithItems = getOrderedGroupsWithItems(groups, items, props.keys)
+ const args = [
+ groupsWithItems,
+ props.keys,
+ props.lineHeight,
+ props.itemHeightRatio,
+ props.stackItems,
+ state.canvasTimeStart,
+ state.canvasTimeEnd,
+ state.width * 3,
+ groups
+ ]
+ const oldResult = getGroupsWithItemDimensions(...args)
+ const newResult = getGroupsWithItemDimensions(...args)
+ const keys = Object.keys(oldResult)
+ keys.forEach(key => {
+ expect(oldResult[key]).toBe(newResult[key])
+ })
+ })
+})
diff --git a/__tests__/utils/calendar/get-item-with-interactions.js b/__tests__/utils/calendar/get-item-with-interactions.js
index f0c17067d..6747c82bd 100644
--- a/__tests__/utils/calendar/get-item-with-interactions.js
+++ b/__tests__/utils/calendar/get-item-with-interactions.js
@@ -14,8 +14,22 @@ describe('getItemWithInteractions', () => {
dragTime: false,
resizingEdge: false,
resizeTime: false,
- groups,
- newGroupOrder: 0
+ newGroupId: '1'
+ })
+ ).toBe(item)
+ })
+ it('should return the same item if draggingItem and resizingItem is not for the same item', () => {
+ const item = items[0]
+ expect(
+ getItemWithInteractions({
+ item,
+ keys: defaultKeys,
+ draggingItem: 'some id',
+ resizingItem: 'some id',
+ dragTime: false,
+ resizingEdge: false,
+ resizeTime: false,
+ newGroupId: '1'
})
).toBe(item)
})
@@ -32,8 +46,7 @@ describe('getItemWithInteractions', () => {
dragTime: item.start_time + dragOffset,
resizingEdge: false,
resizeTime: false,
- groups,
- newGroupOrder: 0
+ newGroupId: '1'
})
).toMatchObject({
...item,
@@ -55,8 +68,7 @@ describe('getItemWithInteractions', () => {
dragTime: item.start_time + dragOffset,
resizingEdge: false,
resizeTime: false,
- groups,
- newGroupOrder: 1
+ newGroupId: groups[1].id,
})
).toMatchObject({
...item,
@@ -78,8 +90,7 @@ describe('getItemWithInteractions', () => {
dragTime: undefined,
resizingEdge: 'left',
resizeTime: item.start_time + dragOffset,
- groups,
- newGroupOrder: 0
+ newGroupId: 0
})
).toMatchObject({
...item,
@@ -99,8 +110,7 @@ describe('getItemWithInteractions', () => {
dragTime: undefined,
resizingEdge: 'right',
resizeTime: item.end_time + dragOffset,
- groups,
- newGroupOrder: 0
+ newGroupId: 0
})
).toMatchObject({
...item,
diff --git a/__tests__/utils/calendar/get-ordered-groups-with-items.js b/__tests__/utils/calendar/get-ordered-groups-with-items.js
new file mode 100644
index 000000000..5e1d6afa5
--- /dev/null
+++ b/__tests__/utils/calendar/get-ordered-groups-with-items.js
@@ -0,0 +1,30 @@
+import {getOrderedGroupsWithItems} from 'lib/utility/calendar'
+import {items, groups} from '../../../__fixtures__/itemsAndGroups'
+import {props} from '../../../__fixtures__/stateAndProps'
+
+
+describe('getGroupWithItemDimensions', ()=>{
+ it('should work as expected', ()=>{
+ expect(getOrderedGroupsWithItems(groups, items, props.keys)).toMatchSnapshot()
+ })
+ it('should have all groups indexed', ()=>{
+ const result = getOrderedGroupsWithItems(groups, items, props.keys)
+ expect(Object.keys(result)).toHaveLength(groups.length)
+ })
+ it('should index all items into corresponding groups', ()=>{
+ const result = getOrderedGroupsWithItems(groups, items, props.keys)
+ let itemSum = 0;
+ Object.keys(result).forEach((id)=>{
+ itemSum += result[id].items.length
+ })
+ expect(itemSum).toBe(items.length)
+ })
+ it('should have an empty array of items if no items exist for group', ()=>{
+ const itemsWithNoGroupId2 = items.filter(item => {
+ return item.group !== '2'
+ })
+ const result = getOrderedGroupsWithItems(groups, itemsWithNoGroupId2, props.keys)
+ expect(Array.isArray(result['2'].items)).toBeTruthy();
+ expect(result['2'].items).toHaveLength(0);
+ })
+})
\ No newline at end of file
diff --git a/__tests__/utils/calendar/group-no-stack.js b/__tests__/utils/calendar/group-no-stack.js
index 758927266..63335fd09 100644
--- a/__tests__/utils/calendar/group-no-stack.js
+++ b/__tests__/utils/calendar/group-no-stack.js
@@ -4,8 +4,7 @@ import {orderedGroups, dimensionItems} from '../../../__fixtures__/groupOrderAnd
describe('groupNoStack', ()=>{
it('works as expected', ()=>{
const groupHeight = 0;
- const totalHeight = 0;
const index = 0;
- expect(groupNoStack(60, dimensionItems[index], groupHeight, totalHeight, index)).toMatchSnapshot()
+ expect(groupNoStack(60, dimensionItems[index], groupHeight)).toMatchSnapshot()
})
})
diff --git a/__tests__/utils/calendar/group-stack.js b/__tests__/utils/calendar/group-stack.js
index 2abd4eea6..82e543766 100644
--- a/__tests__/utils/calendar/group-stack.js
+++ b/__tests__/utils/calendar/group-stack.js
@@ -4,8 +4,7 @@ import {orderedGroups, dimensionItems} from '../../../__fixtures__/groupOrderAnd
describe('groupStack', ()=>{
it('works as expected', ()=>{
const groupHeight = 0;
- const totalHeight = 0;
const index = 0;
- expect(groupStack(60, dimensionItems[index], dimensionItems, groupHeight, totalHeight, index)).toMatchSnapshot()
+ expect(groupStack(60, dimensionItems[index], dimensionItems, groupHeight, index)).toMatchSnapshot()
})
})
diff --git a/__tests__/utils/calendar/is-equal-item-with-dimensions.js b/__tests__/utils/calendar/is-equal-item-with-dimensions.js
new file mode 100644
index 000000000..0c2b580f1
--- /dev/null
+++ b/__tests__/utils/calendar/is-equal-item-with-dimensions.js
@@ -0,0 +1,113 @@
+import { isEqualItemWithDimensions } from 'lib/utility/calendar'
+import { items } from '../../../__fixtures__/itemsAndGroups'
+import { props, state } from '../../../__fixtures__/stateAndProps'
+
+describe('isEqualItemWithDimensions', () => {
+ it('should return true when same old and new args', () => {
+ const groupWithItems = {
+ items
+ }
+ const newArgs = [
+ groupWithItems,
+ props.keys,
+ state.canvasTimeStart,
+ state.canvasTimeEnd,
+ state.width * 3,
+ props.lineHeight,
+ props.itemHeightRatio,
+ props.stackItems
+ ]
+ const oldArgs = [
+ groupWithItems,
+ props.keys,
+ state.canvasTimeStart,
+ state.canvasTimeEnd,
+ state.width * 3,
+ props.lineHeight,
+ props.itemHeightRatio,
+ props.stackItems
+ ]
+ expect(isEqualItemWithDimensions(newArgs, oldArgs)).toBeTruthy()
+ })
+ it('should return false when changing something other than groupWithItems', () => {
+ const groupWithItems = {
+ items
+ }
+ const newArgsChangeCanvasStart = [
+ groupWithItems,
+ props.keys,
+ state.canvasTimeStart + 1,
+ state.canvasTimeEnd,
+ state.width * 3,
+ props.lineHeight,
+ props.itemHeightRatio,
+ props.stackItems
+ ]
+ const newArgsChangeCanvasEnd = [
+ groupWithItems,
+ props.keys,
+ state.canvasTimeStart,
+ state.canvasTimeEnd + 1,
+ state.width * 3,
+ props.lineHeight,
+ props.itemHeightRatio,
+ props.stackItems
+ ]
+ const newArgsChangeStackItems = [
+ groupWithItems,
+ props.keys,
+ state.canvasTimeStart,
+ state.canvasTimeEnd + 1,
+ state.width * 3,
+ props.lineHeight,
+ props.itemHeightRatio,
+ !props.stackItems
+ ]
+ const oldArgs = [
+ groupWithItems,
+ props.keys,
+ state.canvasTimeStart,
+ state.canvasTimeEnd,
+ state.width * 3,
+ props.lineHeight,
+ props.itemHeightRatio,
+ props.stackItems
+ ]
+ expect(
+ isEqualItemWithDimensions(newArgsChangeCanvasStart, oldArgs)
+ ).toBeFalsy()
+ expect(
+ isEqualItemWithDimensions(newArgsChangeCanvasEnd, oldArgs)
+ ).toBeFalsy()
+ expect(
+ isEqualItemWithDimensions(newArgsChangeStackItems, oldArgs)
+ ).toBeFalsy()
+ })
+ it('should return false when groupWithItems is different', () => {
+ const groupWithItems = {
+ items
+ }
+ const otherGroupWithItems = { items: [items[1]] }
+ const newArgs = [
+ otherGroupWithItems,
+ props.keys,
+ state.canvasTimeStart,
+ state.canvasTimeEnd,
+ state.width * 3,
+ props.lineHeight,
+ props.itemHeightRatio,
+ props.stackItems
+ ]
+ const oldArgs = [
+ groupWithItems,
+ props.keys,
+ state.canvasTimeStart,
+ state.canvasTimeEnd,
+ state.width * 3,
+ props.lineHeight,
+ props.itemHeightRatio,
+ props.stackItems
+ ]
+ expect(isEqualItemWithDimensions(newArgs, oldArgs)).toBeFalsy()
+ })
+})
diff --git a/__tests__/utils/calendar/shallow-is-equal-ordered-group.js b/__tests__/utils/calendar/shallow-is-equal-ordered-group.js
new file mode 100644
index 000000000..c2f31ed3f
--- /dev/null
+++ b/__tests__/utils/calendar/shallow-is-equal-ordered-group.js
@@ -0,0 +1,57 @@
+import { shallowIsEqualOrderedGroup } from 'lib/utility/calendar'
+import { groups, items } from '../../../__fixtures__/itemsAndGroups'
+
+describe('shallowIsEqualOrderedGroup', () => {
+ it('should return true if passing same group', ()=>{
+ const newGroupOrder = {
+ group: groups[0],
+ index: 0,
+ items: [items[0], items[1], items[2]]
+ }
+ const oldGroupOrder = {
+ group: groups[0],
+ index: 0,
+ items: [items[0], items[1], items[2]]
+ }
+ expect(shallowIsEqualOrderedGroup(newGroupOrder, oldGroupOrder)).toBeTruthy()
+ })
+ it('should return false if group reference is different', ()=>{
+ const newGroupOrder = {
+ group: Object.assign({},groups[0]),
+ index: 0,
+ items: [items[0], items[1], items[2]]
+ }
+ const oldGroupOrder = {
+ group: groups[0],
+ index: 0,
+ items: [items[0], items[1], items[2]]
+ }
+ expect(shallowIsEqualOrderedGroup(newGroupOrder, oldGroupOrder)).toBeFalsy()
+ })
+ it('should return false if different index', ()=>{
+ const newGroupOrder = {
+ group: groups[0],
+ index: 1,
+ items: [items[0], items[1], items[2]]
+ }
+ const oldGroupOrder = {
+ group: groups[0],
+ index: 0,
+ items: [items[0], items[1], items[2]]
+ }
+ expect(shallowIsEqualOrderedGroup(newGroupOrder, oldGroupOrder)).toBeFalsy()
+ })
+ it('should return false if one of the items has different reference', ()=>{
+ const newGroupOrder = {
+ group: groups[0],
+ index: 0,
+ items: [items[0], items[1], items[2]]
+ }
+ const oldGroupOrder = {
+ group: groups[0],
+ index: 0,
+ items: [items[0], Object.assign({},items[1]), items[2]]
+ }
+ expect(shallowIsEqualOrderedGroup(newGroupOrder, oldGroupOrder)).toBeFalsy()
+ })
+})
diff --git a/__tests__/utils/calendar/stack-all.js b/__tests__/utils/calendar/stack-all.js
deleted file mode 100644
index 7d2ba07d1..000000000
--- a/__tests__/utils/calendar/stack-all.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import { stackAll } from 'lib/utility/calendar'
-import {orderedGroups, dimensionItems} from '../../../__fixtures__/groupOrderAndItemDimentions'
-
-const lineHeight = 60
-
-describe('stackAll', () => {
- it('works as expected stacked', () => {
- expect(stackAll(dimensionItems, orderedGroups, lineHeight, true)).toMatchSnapshot()
- })
- it('works as expected not stacked', () => {
- expect(stackAll(dimensionItems, orderedGroups, lineHeight, false)).toMatchSnapshot()
- })
-})
diff --git a/__tests__/utils/calendar/stack-group.js b/__tests__/utils/calendar/stack-group.js
index be91fa399..d51496b36 100644
--- a/__tests__/utils/calendar/stack-group.js
+++ b/__tests__/utils/calendar/stack-group.js
@@ -3,9 +3,9 @@ import { dimensionItems } from '../../../__fixtures__/groupOrderAndItemDimention
describe('stackGroup', ()=>{
it('should stack list of items', ()=>{
- expect(stackGroup(dimensionItems, true, 30, 0)).toMatchSnapshot()
+ expect(stackGroup(dimensionItems, true, 30)).toMatchSnapshot()
})
it('should not stack list of items', ()=>{
- expect(stackGroup(dimensionItems, false, 30, 0)).toMatchSnapshot()
+ expect(stackGroup(dimensionItems, false, 30)).toMatchSnapshot()
})
})
\ No newline at end of file
diff --git a/__tests__/utils/calendar/stack-items.js b/__tests__/utils/calendar/stack-timeline-items.js
similarity index 93%
rename from __tests__/utils/calendar/stack-items.js
rename to __tests__/utils/calendar/stack-timeline-items.js
index fb3f07ff5..c7199bd5a 100644
--- a/__tests__/utils/calendar/stack-items.js
+++ b/__tests__/utils/calendar/stack-timeline-items.js
@@ -26,7 +26,7 @@ describe('stackItems', () => {
state.dragTime,
state.resizingEdge,
state.resizeTime,
- state.newGroupOrder
+ state.newGroupId
)
).toMatchSnapshot()
})
@@ -47,7 +47,7 @@ describe('stackItems', () => {
state.dragTime,
state.resizingEdge,
state.resizeTime,
- state.newGroupOrder
+ state.newGroupId
)
).toMatchSnapshot()
})
@@ -68,7 +68,7 @@ describe('stackItems', () => {
stateMoveItem.dragTime,
stateMoveItem.resizingEdge,
stateMoveItem.resizeTime,
- stateMoveItem.newGroupOrder
+ stateMoveItem.newGroupId
)
).toMatchSnapshot()
})
@@ -89,7 +89,7 @@ describe('stackItems', () => {
stateResizeItemLeft.dragTime,
stateResizeItemLeft.resizingEdge,
stateResizeItemLeft.resizeTime,
- stateResizeItemLeft.newGroupOrder
+ stateResizeItemLeft.newGroupId
)
).toMatchSnapshot()
})
@@ -110,7 +110,7 @@ describe('stackItems', () => {
stateResizeItemRight.dragTime,
stateResizeItemRight.resizingEdge,
stateResizeItemRight.resizeTime,
- stateResizeItemRight.newGroupOrder
+ stateResizeItemRight.newGroupId
)
).toMatchSnapshot()
})
@@ -131,10 +131,10 @@ describe('stackItems', () => {
state.dragTime,
state.resizingEdge,
state.resizeTime,
- state.newGroupOrder
+ state.newGroupId
)
).toMatchObject({
- dimensionItems: [],
+ groupsWithItemsDimensions: {},
height: 0,
groupHeights: [],
groupTops: []
diff --git a/demo/app/demo-controlled-select/index.js b/demo/app/demo-controlled-select/index.js
index 5202868b6..970859a4a 100644
--- a/demo/app/demo-controlled-select/index.js
+++ b/demo/app/demo-controlled-select/index.js
@@ -91,10 +91,10 @@ export default class App extends Component {
console.log('Context Menu: ' + itemId, moment(time).format())
}
- handleItemMove = (itemId, dragTime, newGroupOrder) => {
+ handleItemMove = (itemId, dragTime, newGroupId) => {
const { items, groups } = this.state
- const group = groups[newGroupOrder]
+ const group = groups.find(i => i.id === newGroupId)
this.setState({
items: items.map(
@@ -109,7 +109,7 @@ export default class App extends Component {
)
})
- console.log('Moved', itemId, dragTime, newGroupOrder)
+ console.log('Moved', itemId, dragTime, newGroupId)
}
handleItemResize = (itemId, time, edge) => {
diff --git a/demo/app/demo-custom-info-label/index.js b/demo/app/demo-custom-info-label/index.js
index a2f3b9012..677421ecd 100644
--- a/demo/app/demo-custom-info-label/index.js
+++ b/demo/app/demo-custom-info-label/index.js
@@ -44,10 +44,10 @@ export default class App extends Component {
}
}
- handleItemMove = (itemId, dragTime, newGroupOrder) => {
+ handleItemMove = (itemId, dragTime, newGroupId) => {
const { items, groups } = this.state
- const group = groups[newGroupOrder]
+ const group = groups.find(i => i.id === newGroupId)
this.setState({
items: items.map(
@@ -83,8 +83,8 @@ export default class App extends Component {
})
}
- handleItemDrag = ({ eventType, itemId, time, edge, newGroupOrder }) => {
- const group = this.state.groups[newGroupOrder]
+ handleItemDrag = ({ eventType, itemId, time, edge, newGroupId }) => {
+ const group = this.state.groups.find(i => i.id === newGroupId)
const infoLabelGroupTitle = group ? group.title : ''
const infoLabelTime = moment(time).format('dddd, MMMM Do YYYY')
let heading = ''
diff --git a/demo/app/demo-custom-items/index.js b/demo/app/demo-custom-items/index.js
index 73a3e8d10..f43d31759 100644
--- a/demo/app/demo-custom-items/index.js
+++ b/demo/app/demo-custom-items/index.js
@@ -70,25 +70,25 @@ export default class App extends Component {
console.log('Context Menu: ' + itemId, moment(time).format())
}
- handleItemMove = (itemId, dragTime, newGroupOrder) => {
+ handleItemMove = (itemId, dragTime, newGroupId) => {
const { items, groups } = this.state
- const group = groups[newGroupOrder]
+ const group = groups.find(i => i.id === newGroupId)
this.setState({
items: items.map(
item =>
item.id === itemId
? Object.assign({}, item, {
- start: dragTime,
- end: dragTime + (item.end - item.start),
- group: group.id
- })
+ start: dragTime,
+ end: dragTime + (item.end - item.start),
+ group: group.id
+ })
: item
)
})
- console.log('Moved', itemId, dragTime, newGroupOrder)
+ console.log('Moved', itemId, dragTime, newGroupId)
}
handleItemResize = (itemId, time, edge) => {
diff --git a/demo/app/demo-headers/index.js b/demo/app/demo-headers/index.js
index 459ee48d0..228ed398d 100644
--- a/demo/app/demo-headers/index.js
+++ b/demo/app/demo-headers/index.js
@@ -89,10 +89,10 @@ export default class App extends Component {
console.log('Context Menu: ' + itemId, moment(time).format())
}
- handleItemMove = (itemId, dragTime, newGroupOrder) => {
+ handleItemMove = (itemId, dragTime, newGroupId) => {
const { items, groups } = this.state
- const group = groups[newGroupOrder]
+ const group = groups.find(i => i.id === newGroupId)
this.setState({
items: items.map(
@@ -107,9 +107,8 @@ export default class App extends Component {
)
})
- console.log('Moved', itemId, dragTime, newGroupOrder)
+ console.log('Moved', itemId, dragTime, newGroupId)
}
-
handleItemResize = (itemId, time, edge) => {
const { items } = this.state
diff --git a/demo/app/demo-main/index.js b/demo/app/demo-main/index.js
index 6c8fd3c22..e503a6685 100644
--- a/demo/app/demo-main/index.js
+++ b/demo/app/demo-main/index.js
@@ -1,5 +1,5 @@
/* eslint-disable no-console */
-import React, { Component } from 'react'
+import React, { Component, useEffect } from 'react'
import moment from 'moment'
import Timeline, {
@@ -10,8 +10,14 @@ import Timeline, {
CursorMarker,
CustomHeader,
SidebarHeader,
- DateHeader
+ DateHeader,
+ RowColumns,
+ RowItems,
+ GroupRow,
+ HelpersContext
} from 'react-calendar-timeline'
+import { useDrag, useDrop } from 'react-dnd'
+import * as d3 from 'd3'
import generateFakeData from '../generate-fake-data'
@@ -46,12 +52,122 @@ export default class App extends Component {
.startOf('day')
.add(1, 'day')
.toDate()
-
this.state = {
groups,
items,
defaultTimeStart,
- defaultTimeEnd
+ defaultTimeEnd,
+ timelineLinks: [],
+ itemsToDrag: [
+ {
+ title: 'print',
+ id: '0a',
+ slots: [
+ {
+ groupId: '1',
+ startTime: moment()
+ .startOf('day')
+ .add(2, 'h'),
+ endTime: moment()
+ .startOf('day')
+ .add(4, 'h')
+ },
+ {
+ groupId: '2',
+ startTime: moment()
+ .startOf('day')
+ .add(8, 'h'),
+ endTime: moment()
+ .startOf('day')
+ .add(16, 'h')
+ }
+ ]
+ },
+ {
+ title: 'cut',
+ id: '1a',
+ slots: [
+ {
+ groupId: '2',
+ startTime: moment()
+ .startOf('day')
+ .add(9, 'h'),
+ endTime: moment()
+ .startOf('day')
+ .add(18, 'h')
+ },
+ {
+ groupId: '5',
+ startTime: moment()
+ .startOf('day')
+ .add(2, 'h'),
+ endTime: moment()
+ .startOf('day')
+ .add(10, 'h')
+ }
+ ]
+ },
+ {
+ title: 'fold',
+ id: '2a',
+ slots: [
+ {
+ groupId: '4',
+ startTime: moment()
+ .startOf('day')
+ .add(9, 'h'),
+ endTime: moment()
+ .startOf('day')
+ .add(18, 'h')
+ },
+ {
+ groupId: '6',
+ startTime: moment()
+ .startOf('day')
+ .add(2, 'h'),
+ endTime: moment()
+ .startOf('day')
+ .add(8, 'h')
+ }
+ ]
+ }
+ ],
+ unavailableSlots: {
+ '1': [
+ {
+ id: '0',
+ groupId: '0',
+ startTime: moment()
+ .startOf('day')
+ .add(16, 'h'),
+ endTime: moment()
+ .startOf('day')
+ .add(20, 'h')
+ }
+ ],
+ '3': [
+ {
+ id: '1',
+ groupId: '3',
+ startTime: moment()
+ .startOf('day')
+ .add(13, 'h'),
+ endTime: moment()
+ .startOf('day')
+ .add(15, 'h')
+ },
+ {
+ id: '2',
+ groupId: '3',
+ startTime: moment()
+ .startOf('day')
+ .add(22, 'h'),
+ endTime: moment()
+ .startOf('day')
+ .add(24, 'h')
+ }
+ ]
+ }
}
}
@@ -67,11 +183,29 @@ export default class App extends Component {
console.log('Canvas context menu', group, moment(time).format())
}
+ findItemById = itemId => {
+ return this.state.items.find(i => i.id === itemId)
+ }
+
+ tempItemId = undefined
+
handleItemClick = (itemId, _, time) => {
console.log('Clicked: ' + itemId, moment(time).format())
}
handleItemSelect = (itemId, _, time) => {
+ if (!this.tempItemId) {
+ this.tempItemId = itemId
+ } else {
+ this.setState(
+ state => ({
+ timelineLinks: [...state.timelineLinks, [this.tempItemId, itemId]]
+ }),
+ () => {
+ this.tempItemId = undefined
+ }
+ )
+ }
console.log('Selected: ' + itemId, moment(time).format())
}
@@ -83,10 +217,10 @@ export default class App extends Component {
console.log('Context Menu: ' + itemId, moment(time).format())
}
- handleItemMove = (itemId, dragTime, newGroupOrder) => {
+ handleItemMove = (itemId, dragTime, newGroupId) => {
const { items, groups } = this.state
- const group = groups[newGroupOrder]
+ const group = groups.find(i => i.id === newGroupId)
this.setState({
items: items.map(
@@ -101,7 +235,7 @@ export default class App extends Component {
)
})
- console.log('Moved', itemId, dragTime, newGroupOrder)
+ console.log('Moved', itemId, dragTime, newGroupId)
}
handleItemResize = (itemId, time, edge) => {
@@ -136,15 +270,85 @@ export default class App extends Component {
}
moveResizeValidator = (action, item, time) => {
- if (time < new Date().getTime()) {
- var newTime =
- Math.ceil(new Date().getTime() / (15 * 60 * 1000)) * (15 * 60 * 1000)
- return newTime
+ const unavailableSlots = this.state.unavailableSlots[item.group]
+ const originalItem = this.state.items.find(i => i.id === item.id)
+ const startTimeInMoment = moment(time, 'x')
+ const endTimeInMoment = moment(item.end - item.start + time, 'x')
+ if (unavailableSlots) {
+ const violation = unavailableSlots.find(slot => {
+ const { startTime, endTime } = slot
+ console.log(endTimeInMoment.format(), startTime.format())
+ return (
+ (startTimeInMoment.isAfter(startTime) &&
+ startTimeInMoment.isBefore(endTime)) ||
+ (endTimeInMoment.isAfter(startTime) &&
+ endTimeInMoment.isBefore(endTime))
+ )
+ })
+ if (violation)
+ return (
+ violation.startTime.valueOf() -
+ (originalItem.end - originalItem.start)
+ )
}
-
return time
}
+ handleDrop = (item, slot) => {
+ const fullItem = this.state.itemsToDrag.find(i => i.id === item.id)
+ this.setState(state => ({
+ itemsToDrag: state.itemsToDrag.filter(i => item.id !== i.id),
+ items: [
+ ...state.items,
+ {
+ title: fullItem.title,
+ id: item.id,
+ group: slot.groupId,
+ start: slot.startTime.valueOf(),
+ end: slot.endTime.valueOf()
+ }
+ ]
+ }))
+ }
+
+ rowRenderer = ({
+ rowData,
+ getLayerRootProps,
+ group,
+ itemsWithInteractions
+ }) => {
+ const helpers = React.useContext(HelpersContext)
+ const { itemsToDrag, unavailableSlots, timelineLinks } = rowData
+ const groupUnavailableSlots = unavailableSlots[group.id]
+ ? unavailableSlots[group.id]
+ : []
+ return (
+
+
+
+
+
+
+ )
+ }
+
render() {
const { groups, items, defaultTimeStart, defaultTimeEnd } = this.state
@@ -156,7 +360,7 @@ export default class App extends Component {
sidebarWidth={150}
sidebarContent={Above The Left
}
canMove
- canResize="right"
+ canResize="both"
canSelect
itemsSorted
itemTouchSendsClick={false}
@@ -174,9 +378,68 @@ export default class App extends Component {
onItemResize={this.handleItemResize}
onItemDoubleClick={this.handleItemDoubleClick}
onTimeChange={this.handleTimeChange}
- moveResizeValidator={this.moveResizeValidator}
+ rowRenderer={this.rowRenderer}
+ rowData={{
+ itemsToDrag: this.state.itemsToDrag,
+ unavailableSlots: this.state.unavailableSlots,
+ timelineLinks: this.state.timelineLinks
+ }}
+ // moveResizeValidator={this.moveResizeValidator}
>
-
+
+
+
+ {({
+ headerContext: { intervals },
+ getRootProps,
+ getIntervalProps,
+ showPeriod,
+ data: { itemsToDrag }
+ }) => {
+ const {getLeftOffsetFromDate} = React.useContext(HelpersContext)
+ return (
+
+
+ {itemsToDrag.map(dragItem => {
+ return (
+ console.log('dragEnd', item)}
+ onDragStart={item => console.log('dragStart', item)}
+ >
+ {dragItem.title}
+
+ )
+ })}
+
+
+ )
+ }}
+
+
+ {/*
-
+ */}
)
}
}
+
+function Link({
+ timelineLink,
+ getItemAbsoluteDimensions,
+ getItemDimensions,
+ group,
+ items
+}) {
+ const [startId, endId] = timelineLink
+ const startItem = items.find(i => i.id === startId)
+ if (startItem.group !== group.id) return null
+ const startItemDimensions = getItemAbsoluteDimensions(startId) || {
+ left: 0,
+ top: 0
+ }
+ const endItemDimensions = getItemAbsoluteDimensions(endId) || {
+ left: 0,
+ top: 0
+ }
+ let startLink = [startItemDimensions.left, startItemDimensions.top]
+ let endLink = [endItemDimensions.left, endItemDimensions.top]
+ const isEndLinkBeforeStart =
+ endLink[0] <= startLink[0] || endLink[1] <= startLink[1]
+ let itemLink = isEndLinkBeforeStart
+ ? [endLink, startLink]
+ : [startLink, endLink]
+ const lineGenerator = d3.line()
+ const [startLk, endLk] = itemLink
+ const endPoint = [endLk[0] - startLk[0], endLk[1] - startLk[1]]
+ const itemDimensions = getItemDimensions(startId)
+ return (
+ 2 ? endPoint[0] : 2,
+ pointerEvents: 'none'
+ }}
+ >
+
+
+ )
+}
+
+const Links = React.memo(({
+ timelineLinks,
+ getItemAbsoluteDimensions,
+ getItemDimensions,
+ group,
+ getLayerRootProps,
+ items
+}) => {
+ return (
+
+ {timelineLinks.map((timelineLink, i) => {
+ const [startId, endId] = timelineLink
+ return (
+
+ )
+ })}
+
+ )
+})
+
+function Droppable({ children, itemIdAccepts, style, slot, onDrop, ...rest }) {
+ const [collected, droppableRef] = useDrop({
+ drop: (item, monitor) => {
+ onDrop(item, slot)
+ },
+ accept: itemIdAccepts,
+ collect: monitor => ({
+ canDrop: monitor.canDrop()
+ })
+ })
+ const isVisable = collected.canDrop
+ return (
+
+ {children}
+
+ )
+}
+
+function Draggable({ id, children, onDragStart, onDragEnd, ...rest }) {
+ const [collectedProps, dragRef] = useDrag({
+ item: { id, type: id },
+ begin: monitor => {
+ onDragStart(id)
+ },
+ end: (item, monitor) => {
+ console.log(monitor)
+ onDragEnd(item)
+ }
+ })
+ return (
+
+ {children}
+
+ )
+}
+
+function DroppablesLayer({
+ getLayerRootProps,
+ itemsToDrag,
+ getLeftOffsetFromDate,
+ handleDrop,
+ group
+}) {
+ return (
+
+ {itemsToDrag.map((item, index) => {
+ return item.slots
+ .filter(slot => slot.groupId === group.id)
+ .map(slot => {
+ const left = getLeftOffsetFromDate(slot.startTime.valueOf())
+ const right = getLeftOffsetFromDate(slot.endTime.valueOf())
+ return (
+
+ {item.title}
+
+ )
+ })
+ })}
+
+ )
+}
+
+const UnavailableLayer = (({
+ getLayerRootProps,
+ groupUnavailableSlots,
+ getLeftOffsetFromDate
+}) => {
+ useEffect(() => {
+ return () => {
+ // console.log("unmount UnavailableLayer")
+ }
+ })
+ return (
+
+ {groupUnavailableSlots.map(slot => {
+ const left = getLeftOffsetFromDate(slot.startTime.valueOf())
+ const right = getLeftOffsetFromDate(slot.endTime.valueOf())
+ return (
+
+ unavailable
+
+ )
+ })}
+
+ )
+})
diff --git a/demo/app/demo-performance/index.js b/demo/app/demo-performance/index.js
index 97c940d00..702d1e4ac 100644
--- a/demo/app/demo-performance/index.js
+++ b/demo/app/demo-performance/index.js
@@ -71,10 +71,10 @@ export default class App extends Component {
console.log('Context Menu: ' + itemId, moment(time).format())
}
- handleItemMove = (itemId, dragTime, newGroupOrder) => {
+ handleItemMove = (itemId, dragTime, newGroupId) => {
const { items, groups } = this.state
- const group = groups[newGroupOrder]
+ const group = groups.find(i => i.id === newGroupId)
this.setState({
items: items.map(
@@ -89,7 +89,7 @@ export default class App extends Component {
)
})
- console.log('Moved', itemId, dragTime, newGroupOrder)
+ console.log('Moved', itemId, dragTime, newGroupId)
}
handleItemResize = (itemId, time, edge) => {
diff --git a/demo/app/demo-renderers/index.js b/demo/app/demo-renderers/index.js
index 898dfb426..331cee63c 100644
--- a/demo/app/demo-renderers/index.js
+++ b/demo/app/demo-renderers/index.js
@@ -76,10 +76,10 @@ export default class App extends Component {
console.log('Context Menu: ' + itemId, moment(time).format())
}
- handleItemMove = (itemId, dragTime, newGroupOrder) => {
+ handleItemMove = (itemId, dragTime, newGroupId) => {
const { items, groups } = this.state
- const group = groups[newGroupOrder]
+ const group = groups.find(i => i.id === newGroupId)
this.setState({
items: items.map(
@@ -94,7 +94,7 @@ export default class App extends Component {
)
})
- console.log('Moved', itemId, dragTime, newGroupOrder)
+ console.log('Moved', itemId, dragTime, newGroupId)
}
handleItemResize = (itemId, time, edge) => {
diff --git a/demo/app/generate-fake-data.js b/demo/app/generate-fake-data.js
index ec2f214dd..6e2b9ae34 100644
--- a/demo/app/generate-fake-data.js
+++ b/demo/app/generate-fake-data.js
@@ -1,9 +1,9 @@
import faker from 'faker'
import randomColor from 'randomcolor'
import moment from 'moment'
-
+faker.seed(30);
export default function (groupCount = 30, itemCount = 1000, daysInPast = 30) {
- let randomSeed = Math.floor(Math.random() * 1000)
+ let randomSeed = 10
let groups = []
for (let i = 0; i < groupCount; i++) {
groups.push({
@@ -27,8 +27,8 @@ export default function (groupCount = 30, itemCount = 1000, daysInPast = 30) {
title: faker.hacker.phrase(),
start: startValue,
end: endValue,
- canMove: startValue > new Date().getTime(),
- canResize: startValue > new Date().getTime() ? (endValue > new Date().getTime() ? 'both' : 'left') : (endValue > new Date().getTime() ? 'right' : false),
+ // canMove: startValue > new Date().getTime(),
+ // canResize: startValue > new Date().getTime() ? (endValue > new Date().getTime() ? 'both' : 'left') : (endValue > new Date().getTime() ? 'right' : false),
className: (moment(startDate).day() === 6 || moment(startDate).day() === 0) ? 'item-weekend' : '',
bgColor: randomColor({ luminosity: 'light', seed: randomSeed + i, format:'rgba', alpha:0.6 }),
selectedBgColor: randomColor({ luminosity: 'light', seed: randomSeed + i, format:'rgba', alpha:1 }),
diff --git a/demo/app/index.js b/demo/app/index.js
index 5dcf3b1b3..26512dc9d 100644
--- a/demo/app/index.js
+++ b/demo/app/index.js
@@ -4,6 +4,8 @@ import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { HashRouter as Router, Route, Link, withRouter } from 'react-router-dom'
+import { DndProvider } from 'react-dnd'
+import HTML5Backend from 'react-dnd-html5-backend'
const demos = {
main: require('./demo-main').default,
@@ -60,13 +62,15 @@ class App extends Component {
return (
-
-
-
- {Object.keys(demos).map(key => (
-
- ))}
-
+
+
+
+
+ {Object.keys(demos).map(key => (
+
+ ))}
+
+
)
diff --git a/examples/README.md b/examples/README.md
index 5ee55b387..710a76034 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -84,3 +84,20 @@ Native info label was removed with 0.26.0 and now the responsibility to render t
[Example Codesandbox](https://codesandbox.io/s/timeline-demo-info-label-neec9)
+## Custom header items with helpers
+
+using custom header and helpers, you would be able to render custom items/intervals in the header
+
+[Example Codesandbox](https://codesandbox.io/s/timeline-demo-helpers-doc-example-o24h6)
+
+## Unavailable placeholders
+
+with row renderer and helpers, custom timeslots are rendered with a label rendered on the calendar
+
+[Example Codesandbox](https://codesandbox.io/s/timeline-demo-rowrenderer-doc-example-66pvw)
+
+## Drag and drop from outside the calendar
+
+with row renderer and helpers, you can drag and drop items from outside the calendar into predetermined spots on the calendar.
+
+[Example Codesandbox](https://codesandbox.io/s/timeline-demo-rowrenderer-dnd-from-outside-the-calendar-gz7ns)
diff --git a/package.json b/package.json
index 74edc6b24..cb98211c8 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "react-calendar-timeline",
- "version": "0.26.6",
+ "version": "0.27.0-beta",
"description": "react calendar timeline",
"main": "lib/index.js",
"scripts": {
@@ -12,7 +12,7 @@
"prepublish": "npm run build:lib",
"start": "webpack-dev-server --hot --host 0.0.0.0 --display-modules",
"test": "jest",
- "test:watch": "jest --watch"
+ "test:watch": "jest --watch"
},
"files": [
"lib",
@@ -112,12 +112,15 @@
"@babel/plugin-proposal-object-rest-spread": "^7.5.2",
"@babel/preset-env": "^7.5.2",
"@babel/preset-react": "^7.0.0",
+ "@testing-library/jest-dom": "^4.2.0",
+ "@types/jest": "24",
"babel-eslint": "^7.1.1",
"babel-jest": "^24.8.0",
"babel-loader": "^8.0.6",
"babel-plugin-react-remove-properties": "^0.3.0",
"cross-env": "^5.1.4",
"css-loader": "~0.26.0",
+ "d3": "^5.12.0",
"enzyme": "^3.10.0",
"enzyme-adapter-react-16": "^1.14.0",
"eslint": "^4.16.0",
@@ -131,7 +134,6 @@
"faker": "^4.1.0",
"interactjs": "^1.3.4",
"jest": "^24.8.0",
- "jest-dom": "^3.5.0",
"jest-watch-typeahead": "^0.3.1",
"jsdom": "^11.5.1",
"moment": "^2.11.1",
@@ -140,8 +142,10 @@
"prettier-eslint-cli": "^4.7.0",
"prop-types": "^15.6.2",
"randomcolor": "^0.5.3",
- "react": "^16.2.0",
- "react-dom": "^16.2.0",
+ "react": "^16.10.2",
+ "react-dnd": "^9.3.4",
+ "react-dnd-html5-backend": "^9.3.4",
+ "react-dom": "^16.10.2",
"react-router-dom": "^4.1.1",
"react-testing-library": "^6.0.3",
"regenerator-runtime": "^0.13.2",
diff --git a/rfcs/row-renderer/background.png b/rfcs/row-renderer/background.png
new file mode 100644
index 000000000..19942be1e
Binary files /dev/null and b/rfcs/row-renderer/background.png differ
diff --git a/rfcs/row-renderer/dnd.gif b/rfcs/row-renderer/dnd.gif
new file mode 100644
index 000000000..fd7cab6eb
Binary files /dev/null and b/rfcs/row-renderer/dnd.gif differ
diff --git a/rfcs/row-renderer/index.md b/rfcs/row-renderer/index.md
new file mode 100644
index 000000000..46532aa59
--- /dev/null
+++ b/rfcs/row-renderer/index.md
@@ -0,0 +1,221 @@
+# Summary
+
+Add an API to the calendar part of the timeline. This API would give you control to add custom UI on calendar rows using a render prop. You can control what is rendered by default with the library like Items and Vertical/Horizontal lines, and the renderer will provide you the ability to render custom backgrounds and droppable layers for custom dnd (more application bellow).
+
+# Basic example
+
+```javascript
+ {
+ const { itemsToDrag, unavailableSlots, timelineLinks } = rowData
+ const groupUnavailableSlots = unavailableSlots[group.id]
+ ? unavailableSlots[group.id]
+ : []
+ return (
+ <>
+
+
+ >
+ )
+ }}
+ rowData={{
+ itemsToDrag: this.state.itemsToDrag,
+ unavailableSlots: this.state.unavailableSlots,
+ timelineLinks: this.state.timelineLinks,
+ }}
+/>
+```
+
+_note: this follows the [limited control approach](#limit-control-to-rowrender)_
+
+
+
+
+# Motivation
+
+- add custom layers like unavailable slots, drag and drop into the calendar and gantt.
+- get rid of the top position of the item be based on the whole calendar part not per row
+- enable row virtual scrolling
+- hide implementation details
+- remove plugin system (undocumented)
+- more test coverage
+- inversion of control (solve a lot of issues with examples rather than adding code into the library)
+- get rid of z-index limitations
+- get rid of extra renders to the calendar when we move an item
+
+# Detailed design
+
+
+
+This RFC will change how we render the *calendar* part of the component.
+
+_*Old approach*_
+
+The old approach deals with The calendar part as a group of layers positioned on top of each other using absolute positioning to place items, rows and rows using `top` and `left` properties with relative to the whole calendar `div`
+
+```
+
+
+
+
+
+```
+
+_*New approach*_
+
+The new approach with `rowRenderers` here would split the Calendar part to rows instead of layers and each row here would consist of an item layer, columns layer and any other layer the user would like to add. This will make the positioning of the layers relative to the row `div` and not the whole calendar `div`.
+
+```typescript
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## API
+
+I will be presenting different approaches here of how would we implement the `rowRendererProp`
+
+_please note that both approaches would give helper methods for calculating postions like `getXPositionFromTime`, `getTimeFromXPosition`, `getItemAbsoluteDimensions` and `getItemsDimensions`_
+
+### Prop getters
+
+```javascript
+{
+
+ {itemLayer}
+ {columnLayer}
+
+ droppable layer
+
+
+ }}
+/>
+```
+
+#### cons
+- no control over rendered items,columns...
+
+### Compostion
+
+```javascript
+{
+
+
+
+ droppable area
+ machine downtime
+
+ }}
+/>
+```
+
+### Limit control to `rowRender`
+
+This approach will render the extra layers you pass to the row renderer but the rowRenderer will not be responsible for rendering the items and the columns layers.
+
+
+```javascript
+{
+
+ droppable area
+ machine downtime
+
+}}
+/>
+```
+
+the result of the render function will be rendered bellow the two other layers. This will limit the user from maybe rendering the core layers incorrectly but will limit the inversion of control they own and we will need to keep some props to that are being passed to the timeline instead of taking advantage of the prop getters for the column and items layer
+
+#### Cons
+- can't control z-index
+- can't control row root div (might be important for virtual scrolling)
+
+## Use cases
+
+- Drag and drop from outside to the calendar to inside (specific target or anywhere in the row).
+- Placeholder Items thought the scheduler.
+- Virtual scrolling (maybe)
+- Gantt (maybe).
+
+# Drawbacks
+
+- huge code change
+- changes the mental image of how the library renders
+- need a lot of testing
+- removes plugins
+- might have some issues aligning everything especially vertical lines
+- remove some props (TODO: get the props which will change)
+- add complexity to library usage for custom changes
+- render vertical components that could cover more than 1 row
+- added layers might block some actions
+- adding stop propagation for item events (or any other layers)
+- item can't keep its state because of re-parenting
+
+There are tradeoffs to choosing any path. Attempt to identify them here.
+
+# Alternatives
+
+- keep the plugin system (undocumented)
+
+# Adoption strategy
+
+
+
+- Documentation on the new features
+- Codesandox examples
+- Migration guide
+
+
+
+# Issues might resolved
+
+- [#623](https://github.com/namespace-ee/react-calendar-timeline/issues/623)
+- [#338](https://github.com/namespace-ee/react-calendar-timeline/issues/338)
+- [#156](https://github.com/namespace-ee/react-calendar-timeline/issues/156)
+- [#636](https://github.com/namespace-ee/react-calendar-timeline/issues/636)
+- [#644](https://github.com/namespace-ee/react-calendar-timeline/issues/644)
+- [#477](https://github.com/namespace-ee/react-calendar-timeline/issues/477)
+- [#595](https://github.com/namespace-ee/react-calendar-timeline/issues/595)
+
+# Unresolved questions
+
+When too much control is too much control?
diff --git a/src/index.js b/src/index.js
index 1c1233da9..1fae38407 100644
--- a/src/index.js
+++ b/src/index.js
@@ -10,4 +10,7 @@ export { default as TimelineHeaders } from './lib/headers/TimelineHeaders'
export {default as SidebarHeader} from './lib/headers/SidebarHeader'
export {default as CustomHeader} from './lib/headers/CustomHeader'
export {default as DateHeader} from './lib/headers/DateHeader'
+export {default as RowItems} from './lib/items/Items'
+export {default as GroupRow} from './lib/rows/GroupRow'
+export {default as HelpersContext} from './lib/timeline/HelpersContext'
export default Timeline
diff --git a/src/lib/Timeline.js b/src/lib/Timeline.js
index d0087e114..dc745c5eb 100644
--- a/src/lib/Timeline.js
+++ b/src/lib/Timeline.js
@@ -1,23 +1,20 @@
import PropTypes from 'prop-types'
import React, { Component } from 'react'
-import moment from 'moment'
-import Items from './items/Items'
import Sidebar from './layout/Sidebar'
-import Columns from './columns/Columns'
-import GroupRows from './row/GroupRows'
import ScrollElement from './scroll/ScrollElement'
import MarkerCanvas from './markers/MarkerCanvas'
+import Rows from './rows/Rows'
+
import windowResizeDetector from '../resize-detector/window'
import {
getMinUnit,
- getNextUnit,
calculateTimeForXPosition,
- calculateScrollCanvas,
getCanvasBoundariesFromVisibleTime,
getCanvasWidth,
- stackTimelineItems
+ calculateScrollCanvas,
+ stackTimelineItems,
} from './utility/calendar'
import { _get, _length } from './utility/generic'
import {
@@ -31,7 +28,9 @@ import { TimelineMarkersProvider } from './markers/TimelineMarkersContext'
import { TimelineHeadersProvider } from './headers/HeadersContext'
import TimelineHeaders from './headers/TimelineHeaders'
import DateHeader from './headers/DateHeader'
-import SidebarHeader from './headers/SidebarHeader'
+import DefaultLayer from './rows/DefaultLayer'
+import Columns from './columns/Columns'
+import { HelpersContextProvider } from './timeline/HelpersContext'
export default class ReactCalendarTimeline extends Component {
static propTypes = {
@@ -156,7 +155,11 @@ export default class ReactCalendarTimeline extends Component {
verticalLineClassNamesForTime: PropTypes.func,
- children: PropTypes.node
+ children: PropTypes.node,
+
+ rowRenderer: PropTypes.func,
+ rowData: PropTypes.object,
+ hideHorizontalLines : PropTypes.bool,
}
static defaultProps = {
@@ -231,7 +234,11 @@ export default class ReactCalendarTimeline extends Component {
headerLabelFormats: defaultHeaderLabelFormats,
subHeaderLabelFormats: defaultSubHeaderLabelFormats,
- selected: null
+ selected: null,
+
+ rowRenderer: DefaultLayer,
+ rowData: {},
+ hideHorizontalLines: false,
}
static childContextTypes = {
@@ -300,19 +307,19 @@ export default class ReactCalendarTimeline extends Component {
canvasTimeEnd: canvasTimeEnd,
selectedItem: null,
dragTime: null,
- dragGroupTitle: null,
- resizeTime: null,
resizingItem: null,
- resizingEdge: null
+ resizeTime: undefined,
+ resizingEdge: undefined
}
const canvasWidth = getCanvasWidth(this.state.width)
const {
- dimensionItems,
+ groupsWithItemsDimensions,
height,
groupHeights,
- groupTops
+ groupTops,
+ itemsWithInteractions,
} = stackTimelineItems(
props.items,
props.groups,
@@ -328,14 +335,15 @@ export default class ReactCalendarTimeline extends Component {
this.state.dragTime,
this.state.resizingEdge,
this.state.resizeTime,
- this.state.newGroupOrder
+ this.state.newGroupId
)
/* eslint-disable react/no-direct-mutation-state */
- this.state.dimensionItems = dimensionItems
+ this.state.groupsWithItemsDimensions = groupsWithItemsDimensions
this.state.height = height
this.state.groupHeights = groupHeights
this.state.groupTops = groupTops
+ this.state.itemsWithInteractions = itemsWithInteractions
/* eslint-enable */
}
@@ -405,7 +413,7 @@ export default class ReactCalendarTimeline extends Component {
prevState.dragTime,
prevState.resizingEdge,
prevState.resizeTime,
- prevState.newGroupOrder
+ prevState.newGroupId
)
)
}
@@ -456,7 +464,7 @@ export default class ReactCalendarTimeline extends Component {
let width = containerWidth - props.sidebarWidth - props.rightSidebarWidth
const canvasWidth = getCanvasWidth(width)
const {
- dimensionItems,
+ groupsWithItemsDimensions,
height,
groupHeights,
groupTops
@@ -475,7 +483,7 @@ export default class ReactCalendarTimeline extends Component {
this.state.dragTime,
this.state.resizingEdge,
this.state.resizeTime,
- this.state.newGroupOrder
+ this.state.newGroupId
)
// this is needed by dragItem since it uses pageY from the drag events
@@ -483,7 +491,7 @@ export default class ReactCalendarTimeline extends Component {
this.setState({
width,
- dimensionItems,
+ groupsWithItemsDimensions,
height,
groupHeights,
groupTops
@@ -649,29 +657,25 @@ export default class ReactCalendarTimeline extends Component {
return time
}
- dragItem = (item, dragTime, newGroupOrder) => {
- let newGroup = this.props.groups[newGroupOrder]
- const keys = this.props.keys
-
+ dragItem = (item, dragTime, newGroupId) => {
this.setState({
draggingItem: item,
dragTime: dragTime,
- newGroupOrder: newGroupOrder,
- dragGroupTitle: newGroup ? _get(newGroup, keys.groupLabelKey) : ''
+ newGroupId: newGroupId,
})
this.updatingItem({
eventType: 'move',
itemId: item,
time: dragTime,
- newGroupOrder
+ newGroupId
})
}
- dropItem = (item, dragTime, newGroupOrder) => {
- this.setState({ draggingItem: null, dragTime: null, dragGroupTitle: null })
+ dropItem = (item, dragTime, newGroupId) => {
+ this.setState({ draggingItem: null, dragTime: null })
if (this.props.onItemMove) {
- this.props.onItemMove(item, dragTime, newGroupOrder)
+ this.props.onItemMove(item, dragTime, newGroupId)
}
}
@@ -697,34 +701,12 @@ export default class ReactCalendarTimeline extends Component {
}
}
- updatingItem = ({ eventType, itemId, time, edge, newGroupOrder }) => {
+ updatingItem = ({ eventType, itemId, time, edge, newGroupId }) => {
if (this.props.onItemDrag) {
- this.props.onItemDrag({ eventType, itemId, time, edge, newGroupOrder })
+ this.props.onItemDrag({ eventType, itemId, time, edge, newGroupId })
}
}
- columns(
- canvasTimeStart,
- canvasTimeEnd,
- canvasWidth,
- minUnit,
- timeSteps,
- height
- ) {
- return (
-
- )
- }
-
handleRowClick = (e, rowIndex) => {
// shouldnt this be handled by the user, as far as when to deselect an item?
if (this.hasSelectedItem()) {
@@ -768,67 +750,6 @@ export default class ReactCalendarTimeline extends Component {
}
}
- rows(canvasWidth, groupHeights, groups) {
- return (
-
- )
- }
-
- items(
- canvasTimeStart,
- zoom,
- canvasTimeEnd,
- canvasWidth,
- minUnit,
- dimensionItems,
- groupHeights,
- groupTops
- ) {
- return (
-
- )
- }
-
handleHeaderRef = el => {
this.scrollHeaderRef = el
this.props.headerRef(el)
@@ -876,19 +797,7 @@ export default class ReactCalendarTimeline extends Component {
return child.type.secretKey ===TimelineHeaders.secretKey
}
- childrenWithProps(
- canvasTimeStart,
- canvasTimeEnd,
- canvasWidth,
- dimensionItems,
- groupHeights,
- groupTops,
- height,
- visibleTimeStart,
- visibleTimeEnd,
- minUnit,
- timeSteps
- ) {
+ childrenWithProps() {
if (!this.props.children) {
return null
}
@@ -898,27 +807,9 @@ export default class ReactCalendarTimeline extends Component {
? this.props.children.filter(c => c)
: [this.props.children]
- const childProps = {
- canvasTimeStart,
- canvasTimeEnd,
- canvasWidth,
- visibleTimeStart: visibleTimeStart,
- visibleTimeEnd: visibleTimeEnd,
- dimensionItems,
- items: this.props.items,
- groups: this.props.groups,
- keys: this.props.keys,
- groupHeights: groupHeights,
- groupTops: groupTops,
- selected: this.getSelected(),
- height: height,
- minUnit: minUnit,
- timeSteps: timeSteps
- }
-
return React.Children.map(childArray, child => {
if (!this.isTimelineHeader(child)) {
- return React.cloneElement(child, childProps)
+ return child
} else {
return null
}
@@ -972,7 +863,10 @@ export default class ReactCalendarTimeline extends Component {
sidebarWidth,
rightSidebarWidth,
timeSteps,
- traditionalZoom
+ traditionalZoom,
+ itemRenderer,
+ keys,
+ hideHorizontalLines,
} = this.props
const {
draggingItem,
@@ -983,7 +877,7 @@ export default class ReactCalendarTimeline extends Component {
canvasTimeStart,
canvasTimeEnd
} = this.state
- let { dimensionItems, height, groupHeights, groupTops } = this.state
+ let { groupsWithItemsDimensions, height, groupHeights, groupTops, itemsWithInteractions } = this.state
const zoom = visibleTimeEnd - visibleTimeStart
const canvasWidth = getCanvasWidth(width)
@@ -1007,12 +901,13 @@ export default class ReactCalendarTimeline extends Component {
this.state.dragTime,
this.state.resizingEdge,
this.state.resizeTime,
- this.state.newGroupOrder
+ this.state.newGroupId
)
- dimensionItems = stackResults.dimensionItems
+ groupsWithItemsDimensions = stackResults.groupsWithItemsDimensions
height = stackResults.height
groupHeights = stackResults.groupHeights
groupTops = stackResults.groupTops
+ itemsWithInteractions = stackResults.itemsWithInteractions
}
const outerComponentStyle = {
@@ -1029,6 +924,7 @@ export default class ReactCalendarTimeline extends Component {
showPeriod={this.showPeriod}
timelineUnit={minUnit}
timelineWidth={this.state.width}
+ keys={keys}
>
- (this.container = el)}
- className="react-calendar-timeline"
+
- {this.renderHeaders()}
-
- {sidebarWidth > 0 ? this.sidebar(height, groupHeights) : null}
-
-
- {this.columns(
- canvasTimeStart,
- canvasTimeEnd,
- canvasWidth,
- minUnit,
- timeSteps,
- height
- )}
- {this.rows(canvasWidth, groupHeights, groups)}
- {this.items(
- canvasTimeStart,
- zoom,
- canvasTimeEnd,
- canvasWidth,
- minUnit,
- dimensionItems,
- groupHeights,
- groupTops
- )}
- {this.childrenWithProps(
- canvasTimeStart,
- canvasTimeEnd,
- canvasWidth,
- dimensionItems,
- groupHeights,
- groupTops,
- height,
- visibleTimeStart,
- visibleTimeEnd,
- minUnit,
- timeSteps
- )}
-
-
- {rightSidebarWidth > 0
- ? this.rightSidebar(height, groupHeights)
- : null}
+
(this.container = el)}
+ className="react-calendar-timeline"
+ >
+ {this.renderHeaders()}
+
+ {sidebarWidth > 0 ? this.sidebar(height, groupHeights) : null}
+
+
+ {this.childrenWithProps()}
+
+ {hideHorizontalLines? null : }
+
+
+ {rightSidebarWidth > 0
+ ? this.rightSidebar(height, groupHeights)
+ : null}
+
-
+
diff --git a/src/lib/Timeline.scss b/src/lib/Timeline.scss
index 586b3edf3..c6e23e7a1 100644
--- a/src/lib/Timeline.scss
+++ b/src/lib/Timeline.scss
@@ -17,6 +17,10 @@ $list-item-padding: 0 4px;
$weekend: rgba(250, 246, 225, 0.5);
.react-calendar-timeline {
+ //create local stack context for z-index
+ position: relative;
+ z-index: 0;
+
* {
box-sizing: border-box;
}
@@ -91,10 +95,10 @@ $weekend: rgba(250, 246, 225, 0.5);
// TODO: rename or remove once we make breaking change to rename vertical lines
// to columns
.rct-vertical-lines {
+ height: 100%;
.rct-vl {
position: absolute;
border-left: 1px solid $border-color;
- z-index: 30;
&.rct-vl-first {
border-left-width: 2px;
}
@@ -115,7 +119,6 @@ $weekend: rgba(250, 246, 225, 0.5);
.rct-hl-odd {
border-bottom: $border-width solid $border-color;
box-sizing: border-box;
- z-index: 40;
}
.rct-hl-odd {
background: $row-background-odd;
@@ -129,7 +132,6 @@ $weekend: rgba(250, 246, 225, 0.5);
position: absolute;
width: 2px;
background: $item-background;
- z-index: 51;
}
diff --git a/src/lib/columns/Columns.js b/src/lib/columns/Columns.js
index 7447d596e..ee9154254 100644
--- a/src/lib/columns/Columns.js
+++ b/src/lib/columns/Columns.js
@@ -1,37 +1,32 @@
import PropTypes from 'prop-types'
-import React, { Component } from 'react'
-
+import React, { Component, PureComponent } from 'react'
import { iterateTimes } from '../utility/calendar'
import { TimelineStateConsumer } from '../timeline/TimelineStateContext'
-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 {
+export class Columns extends Component {
static propTypes = {
- ...passThroughPropTypes,
- getLeftOffsetFromDate: PropTypes.func.isRequired
+ canvasTimeStart: PropTypes.number.isRequired,
+ canvasTimeEnd: PropTypes.number.isRequired,
+ lineCount: PropTypes.number.isRequired,
+ minUnit: PropTypes.string.isRequired,
+ timeSteps: PropTypes.object.isRequired,
+ verticalLineClassNamesForTime: PropTypes.func,
+ getLeftOffsetFromDate: PropTypes.func.isRequired,
+ canvasWidth: PropTypes.number.isRequired
}
shouldComponentUpdate(nextProps) {
return !(
nextProps.canvasTimeStart === this.props.canvasTimeStart &&
nextProps.canvasTimeEnd === this.props.canvasTimeEnd &&
- nextProps.canvasWidth === this.props.canvasWidth &&
nextProps.lineCount === this.props.lineCount &&
nextProps.minUnit === this.props.minUnit &&
nextProps.timeSteps === this.props.timeSteps &&
- nextProps.height === this.props.height &&
nextProps.verticalLineClassNamesForTime ===
- this.props.verticalLineClassNamesForTime
+ this.props.verticalLineClassNamesForTime &&
+ //TODO: delete canvasWidth prop
+ //needed to trigger renderer because getLeftOffsetFromDate is dependant on canvasWidth
+ nextProps.canvasWidth === this.props.canvasWidth
)
}
@@ -39,17 +34,13 @@ class Columns extends Component {
const {
canvasTimeStart,
canvasTimeEnd,
- canvasWidth,
minUnit,
timeSteps,
- height,
verticalLineClassNamesForTime,
getLeftOffsetFromDate
} = this.props
- const ratio = canvasWidth / (canvasTimeEnd - canvasTimeStart)
let lines = []
-
iterateTimes(
canvasTimeStart,
canvasTimeEnd,
@@ -75,7 +66,6 @@ class Columns extends Component {
? ` rct-day-${time.day()} `
: '') +
classNamesForTime.join(' ')
-
const left = getLeftOffsetFromDate(time.valueOf())
const right = getLeftOffsetFromDate(nextTime.valueOf())
lines.push(
@@ -87,29 +77,36 @@ class Columns extends Component {
top: '0px',
left: `${left}px`,
width: `${right - left}px`,
- height: `${height}px`
+ height: '100%'
}}
/>
)
}
)
-
return
{lines}
}
}
-const ColumnsWrapper = ({ ...props }) => {
- return (
-
- {({ getLeftOffsetFromDate }) => (
-
- )}
-
- )
-}
-
-ColumnsWrapper.defaultProps = {
- ...passThroughPropTypes
+class ColumnsWrapper extends PureComponent {
+ render() {
+ return (
+
+ {({ getLeftOffsetFromDate, getTimelineState }) => {
+ const {
+ canvasTimeStart,
+ canvasTimeEnd,
+ canvasWidth
+ } = getTimelineState()
+ return (
+
+ )
+ }}
+
+ )
+ }
}
-export default ColumnsWrapper
\ No newline at end of file
+export default ColumnsWrapper
diff --git a/src/lib/headers/CustomHeader.js b/src/lib/headers/CustomHeader.js
index a07bfc8c5..1aecacfb1 100644
--- a/src/lib/headers/CustomHeader.js
+++ b/src/lib/headers/CustomHeader.js
@@ -64,7 +64,7 @@ export class CustomHeader extends React.Component {
return false
}
- componentWillReceiveProps(nextProps) {
+ UNSAFE_componentWillReceiveProps(nextProps) {
if (
nextProps.canvasTimeStart !== this.props.canvasTimeStart ||
nextProps.canvasTimeEnd !== this.props.canvasTimeEnd ||
diff --git a/src/lib/headers/DateHeader.js b/src/lib/headers/DateHeader.js
index 44191e77a..2366c1b3a 100644
--- a/src/lib/headers/DateHeader.js
+++ b/src/lib/headers/DateHeader.js
@@ -7,7 +7,7 @@ import { defaultHeaderFormats } from '../default-config'
import memoize from 'memoize-one'
import { CustomDateHeader } from './CustomDateHeader'
-class DateHeader extends React.Component {
+class DateHeader extends React.PureComponent {
static propTypes = {
unit: PropTypes.string,
style: PropTypes.object,
diff --git a/src/lib/headers/TimelineHeaders.js b/src/lib/headers/TimelineHeaders.js
index 882780efa..79567e110 100644
--- a/src/lib/headers/TimelineHeaders.js
+++ b/src/lib/headers/TimelineHeaders.js
@@ -4,7 +4,7 @@ import { TimelineHeadersConsumer } from './HeadersContext'
import PropTypes from 'prop-types'
import SidebarHeader from './SidebarHeader'
import { RIGHT_VARIANT } from './constants'
-class TimelineHeaders extends React.Component {
+class TimelineHeaders extends React.PureComponent {
static propTypes = {
registerScroll: PropTypes.func.isRequired,
leftSidebarWidth: PropTypes.number.isRequired,
diff --git a/src/lib/items/Item.js b/src/lib/items/Item.js
index 2099a1a1a..14891435a 100644
--- a/src/lib/items/Item.js
+++ b/src/lib/items/Item.js
@@ -27,6 +27,10 @@ export default class Item extends Component {
canvasTimeStart: PropTypes.number.isRequired,
canvasTimeEnd: PropTypes.number.isRequired,
canvasWidth: PropTypes.number.isRequired,
+ visibleTimeEnd: PropTypes.number.isRequired,
+ visibleTimeStart: PropTypes.number.isRequired,
+ timelineWidth: PropTypes.number.isRequired,
+
order: PropTypes.object,
dragSnap: PropTypes.number,
@@ -52,12 +56,21 @@ export default class Item extends Component {
itemProps: PropTypes.object,
canSelect: PropTypes.bool,
dimensions: PropTypes.object,
- groupTops: PropTypes.array,
useResizeHandle: PropTypes.bool,
moveResizeValidator: PropTypes.func,
onItemDoubleClick: PropTypes.func,
- scrollRef: PropTypes.object
+ scrollRef: PropTypes.object,
+
+ dragging: PropTypes.bool.isRequired,
+ resizing: PropTypes.bool.isRequired,
+ dragOffset: PropTypes.number.isRequired,
+ resizeEdge: PropTypes.oneOf(['left', 'right']),
+ resizeStart: PropTypes.number,
+
+ onDragStart: PropTypes.func.isRequired,
+ onDragEnd : PropTypes.func.isRequired,
+ onResizeStart: PropTypes.func.isRequired,
}
static defaultProps = {
@@ -65,38 +78,18 @@ export default class Item extends Component {
itemRenderer: defaultItemRenderer
}
- static contextTypes = {
- getTimelineContext: PropTypes.func
- }
-
constructor(props) {
super(props)
this.cacheDataFromProps(props)
-
- this.state = {
- interactMounted: false,
-
- dragging: null,
- dragStart: null,
- preDragPosition: null,
- dragTime: null,
- dragGroupDelta: null,
-
- resizing: null,
- resizeEdge: null,
- resizeStart: null,
- resizeTime: null
- }
}
+ interactMounted = false;
+
shouldComponentUpdate(nextProps, nextState) {
var shouldUpdate =
- nextState.dragging !== this.state.dragging ||
- nextState.dragTime !== this.state.dragTime ||
- nextState.dragGroupDelta !== this.state.dragGroupDelta ||
- nextState.resizing !== this.state.resizing ||
- nextState.resizeTime !== this.state.resizeTime ||
+ nextProps.dragging !== this.props.dragging ||
+ nextProps.resizing !== this.props.resizing ||
nextProps.keys !== this.props.keys ||
!deepObjectCompare(nextProps.itemProps, this.props.itemProps) ||
nextProps.selected !== this.props.selected ||
@@ -125,6 +118,7 @@ export default class Item extends Component {
: this.itemTitle
this.itemTimeStart = _get(props.item, props.keys.itemTimeStartKey)
this.itemTimeEnd = _get(props.item, props.keys.itemTimeEndKey)
+ this.itemGroupId = _get(props.item, props.keys.itemGroupKey)
}
getTimeRatio() {
@@ -155,8 +149,8 @@ export default class Item extends Component {
dragTime(e) {
const startTime = moment(this.itemTimeStart)
- if (this.state.dragging) {
- return this.dragTimeSnap(this.timeFor(e) + this.state.dragStart.offset, true)
+ if (this.props.dragging) {
+ return this.dragTimeSnap(this.timeFor(e) + this.props.dragOffset, true)
} else {
return startTime
}
@@ -171,40 +165,10 @@ export default class Item extends Component {
return (e.pageX - offset + scrolls.scrollLeft) * ratio + this.props.canvasTimeStart;
}
- dragGroupDelta(e) {
- const { groupTops, order } = this.props
- if (this.state.dragging) {
- if (!this.props.canChangeGroup) {
- return 0
- }
- let groupDelta = 0
-
- const offset = getSumOffset(this.props.scrollRef).offsetTop
- const scrolls = getSumScroll(this.props.scrollRef)
-
- for (var key of Object.keys(groupTops)) {
- var groupTop = groupTops[key]
- if (e.pageY - offset + scrolls.scrollTop > groupTop) {
- groupDelta = parseInt(key, 10) - order.index
- } else {
- break
- }
- }
-
- if (this.props.order.index + groupDelta < 0) {
- return 0 - this.props.order.index
- } else {
- return groupDelta
- }
- } else {
- return 0
- }
- }
-
resizeTimeDelta(e, resizeEdge) {
const length = this.itemTimeEnd - this.itemTimeStart
const timeDelta = this.dragTimeSnap(
- (e.pageX - this.state.resizeStart) * this.getTimeRatio()
+ (e.pageX - this.props.resizeStart) * this.getTimeRatio()
)
if (
@@ -234,161 +198,107 @@ export default class Item extends Component {
bottom: false
},
enabled:
- this.props.selected && (this.canResizeLeft() || this.canResizeRight())
- })
- .draggable({
- enabled: this.props.selected && this.canMove()
+ this.props.selected &&
+ (this.canResizeLeft() || this.canResizeRight())
})
+ .draggable({ enabled: this.props.selected && this.canMove() })
.styleCursor(false)
.on('dragstart', e => {
+ e.stopPropagation()
if (this.props.selected) {
- const clickTime = this.timeFor(e);
- this.setState({
- dragging: true,
- dragStart: {
- x: e.pageX,
- y: e.pageY,
- offset: this.itemTimeStart - clickTime },
- preDragPosition: { x: e.target.offsetLeft, y: e.target.offsetTop },
- dragTime: this.itemTimeStart,
- dragGroupDelta: 0
- })
+ const clickTime = this.timeFor(e)
+ this.props.onDragStart(true, this.itemTimeStart - clickTime, this.itemId)
} else {
return false
}
})
.on('dragmove', e => {
- if (this.state.dragging) {
- let dragTime = this.dragTime(e)
- let dragGroupDelta = this.dragGroupDelta(e)
- if (this.props.moveResizeValidator) {
- dragTime = this.props.moveResizeValidator(
- 'move',
- this.props.item,
- dragTime
- )
- }
-
- if (this.props.onDrag) {
- this.props.onDrag(
- this.itemId,
- dragTime,
- this.props.order.index + dragGroupDelta
- )
+ e.stopPropagation()
+ if (this.props.dragging) {
+ if (e.dropzone) {
+ const newGroupId = e.dropzone.target.dataset.groupid
+ let dragTime = this.dragTime(e)
+ if(dragTime !== _get(this.props.item, this.props.keys.itemTimeStartKey)){
+ if (this.props.moveResizeValidator) {
+ dragTime = this.props.moveResizeValidator('move', this.props.item, dragTime)
+ }
+
+ if (this.props.onDrag) {
+ this.props.onDrag(this.itemId, dragTime, newGroupId)
+ }
+ }
}
-
- this.setState({
- dragTime: dragTime,
- dragGroupDelta: dragGroupDelta
- })
}
})
.on('dragend', e => {
- if (this.state.dragging) {
- if (this.props.onDrop) {
- let dragTime = this.dragTime(e)
-
- if (this.props.moveResizeValidator) {
- dragTime = this.props.moveResizeValidator(
- 'move',
- this.props.item,
- dragTime
- )
+ e.stopPropagation()
+ if (this.props.dragging) {
+ if(e.dropzone){
+
+ const newGroupId = e.dropzone.target.dataset.groupid
+ if (this.props.onDrop) {
+ let dragTime = this.dragTime(e)
+
+ if (this.props.moveResizeValidator) {
+ dragTime = this.props.moveResizeValidator('move', this.props.item, dragTime)
+ }
+
+ this.props.onDrop(this.itemId, dragTime, newGroupId)
}
-
- this.props.onDrop(
- this.itemId,
- dragTime,
- this.props.order.index + this.dragGroupDelta(e)
- )
+
}
-
- this.setState({
- dragging: false,
- dragStart: null,
- preDragPosition: null,
- dragTime: null,
- dragGroupDelta: null
- })
+ this.props.onDragEnd()
}
})
.on('resizestart', e => {
+ e.stopPropagation()
if (this.props.selected) {
- this.setState({
- resizing: true,
- resizeEdge: null, // we don't know yet
- resizeStart: e.pageX,
- resizeTime: 0
- })
+ this.props.onResizeStart(true, this.itemId);
} else {
return false
}
})
.on('resizemove', e => {
- if (this.state.resizing) {
- let resizeEdge = this.state.resizeEdge
+ e.stopPropagation()
+ if (this.props.resizing) {
+ let resizeEdge = this.props.resizeEdge
if (!resizeEdge) {
resizeEdge = e.deltaRect.left !== 0 ? 'left' : 'right'
- this.setState({ resizeEdge })
}
let resizeTime = this.resizeTimeSnap(this.timeFor(e))
-
- if (this.props.moveResizeValidator) {
- resizeTime = this.props.moveResizeValidator(
- 'resize',
- this.props.item,
- resizeTime,
- resizeEdge
- )
- }
-
- if (this.props.onResizing) {
- this.props.onResizing(this.itemId, resizeTime, resizeEdge)
+ const isResizeTimeChangedRight = resizeEdge === 'right' && resizeTime !== _get(this.props.item, this.props.keys.itemTimeEndKey)
+ const isResizeTimeChangedLeft = resizeEdge === 'left' && resizeTime !== _get(this.props.item, this.props.keys.itemTimeStartKey)
+ if(isResizeTimeChangedRight || isResizeTimeChangedLeft){
+ if (this.props.moveResizeValidator) {
+ resizeTime = this.props.moveResizeValidator('resize', this.props.item, resizeTime, resizeEdge)
+ }
+ if (this.props.onResizing) {
+ this.props.onResizing(this.itemId, resizeTime, resizeEdge)
+ }
}
-
- this.setState({
- resizeTime
- })
}
})
.on('resizeend', e => {
- if (this.state.resizing) {
- const { resizeEdge } = this.state
+ if (this.props.resizing) {
+ const { resizeEdge } = this.props
let resizeTime = this.resizeTimeSnap(this.timeFor(e))
if (this.props.moveResizeValidator) {
- resizeTime = this.props.moveResizeValidator(
- 'resize',
- this.props.item,
- resizeTime,
- resizeEdge
- )
+ resizeTime = this.props.moveResizeValidator('resize', this.props.item, resizeTime, resizeEdge)
}
if (this.props.onResized) {
- this.props.onResized(
- this.itemId,
- resizeTime,
- resizeEdge,
- this.resizeTimeDelta(e, resizeEdge)
- )
+ this.props.onResized(this.itemId, resizeTime, resizeEdge, this.resizeTimeDelta(e, resizeEdge))
}
- this.setState({
- resizing: null,
- resizeStart: null,
- resizeEdge: null,
- resizeTime: null
- })
}
})
.on('tap', e => {
+ e.stopPropagation()
this.actualClick(e, e.pointerType === 'mouse' ? 'click' : 'touch')
})
- this.setState({
- interactMounted: true
- })
+ this.interactMounted=true;
}
canResizeLeft(props = this.props) {
@@ -413,7 +323,7 @@ export default class Item extends Component {
componentDidUpdate(prevProps) {
this.cacheDataFromProps(this.props)
- let { interactMounted } = this.state
+ let { interactMounted } = this
const couldDrag = prevProps.selected && this.canMove(prevProps)
const couldResizeLeft =
prevProps.selected && this.canResizeLeft(prevProps)
@@ -455,35 +365,47 @@ export default class Item extends Component {
else{
interactMounted= false;
}
- this.setState({
- interactMounted,
- })
+ this.interactMounted = interactMounted
+
+ }
+ componentDidMount(){
+ if(!!this.item){
+ if (this.props.selected && !this.interactMounted) {
+ this.mountInteract()
+ this.interactMounted =true;
+ }
+ }
}
+
onMouseDown = e => {
- if (!this.state.interactMounted) {
+ e.stopPropagation()
+ if (!this.interactMounted) {
e.preventDefault()
this.startedClicking = true
}
}
onMouseUp = e => {
- if (!this.state.interactMounted && this.startedClicking) {
+ e.stopPropagation()
+ if (!this.interactMounted && this.startedClicking) {
this.startedClicking = false
this.actualClick(e, 'click')
}
}
onTouchStart = e => {
- if (!this.state.interactMounted) {
+ e.stopPropagation()
+ if (!this.interactMounted) {
e.preventDefault()
this.startedTouching = true
}
}
onTouchEnd = e => {
- if (!this.state.interactMounted && this.startedTouching) {
+ e.stopPropagation()
+ if (!this.interactMounted && this.startedTouching) {
this.startedTouching = false
this.actualClick(e, 'touch')
}
@@ -497,6 +419,7 @@ export default class Item extends Component {
}
handleContextMenu = e => {
+ e.stopPropagation()
if (this.props.onContextMenu) {
e.preventDefault()
e.stopPropagation()
@@ -505,11 +428,16 @@ export default class Item extends Component {
}
actualClick(e, clickType) {
+ e.stopPropagation()
if (this.props.canSelect && this.props.onSelect) {
this.props.onSelect(this.itemId, clickType, e)
}
}
+ handleOnClick = e => {
+ e.stopPropagation()
+ }
+
getItemRef = el => (this.item = el)
getDragLeftRef = el => (this.dragLeft = el)
getDragRightRef = el => (this.dragRight = el)
@@ -531,6 +459,7 @@ export default class Item extends Component {
onTouchEnd: composeEvents(this.onTouchEnd, props.onTouchEnd),
onDoubleClick: composeEvents(this.handleDoubleClick, props.onDoubleClick),
onContextMenu: composeEvents(this.handleContextMenu, props.onContextMenu),
+ onClick: composeEvents(this.handleOnClick, props.onClick),
style: Object.assign({}, this.getItemStyle(props))
}
}
@@ -580,7 +509,7 @@ export default class Item extends Component {
this.props.selected & this.canResizeLeft(this.props)
? selectedAndCanResizeLeft
: {},
- this.props.selected & this.canResizeLeft(this.props) & this.state.dragging
+ this.props.selected & this.canResizeLeft(this.props) & this.props.dragging
? selectedAndCanResizeLeftAndDragLeft
: {},
this.props.selected & this.canResizeRight(this.props)
@@ -588,7 +517,7 @@ export default class Item extends Component {
: {},
this.props.selected &
this.canResizeRight(this.props) &
- this.state.dragging
+ this.props.dragging
? selectedAndCanResizeRightAndDragRight
: {},
props.style,
@@ -602,7 +531,15 @@ export default class Item extends Component {
return null
}
- const timelineContext = this.context.getTimelineContext()
+ const timelineContext = {
+ canvasTimeStart: this.props.canvasTimeStart,
+ canvasTimeEnd: this.props.canvasTimeEnd,
+ visibleTimeEnd: this.props.visibleTimeEnd,
+ visibleTimeStart: this.props.visibleTimeStart,
+ timelineWidth: this.props.timelineWidth,
+
+ }
+
const itemContext = {
dimensions: this.props.dimensions,
useResizeHandle: this.props.useResizeHandle,
@@ -611,14 +548,18 @@ export default class Item extends Component {
canResizeLeft: this.canResizeLeft(this.props),
canResizeRight: this.canResizeRight(this.props),
selected: this.props.selected,
- dragging: this.state.dragging,
- dragStart: this.state.dragStart,
- dragTime: this.state.dragTime,
- dragGroupDelta: this.state.dragGroupDelta,
- resizing: this.state.resizing,
- resizeEdge: this.state.resizeEdge,
- resizeStart: this.state.resizeStart,
- resizeTime: this.state.resizeTime,
+ dragging: this.props.dragging,
+ dragOffset: this.props.dragOffset,
+ dragTime: this.itemTimeStart,
+ newGroupId: this.itemGroupId,
+ resizing: this.props.resizing,
+ resizeEdge: this.props.resizeEdge,
+ resizeStart: this.props.resizeStart,
+ resizeTime: this.props.resizeEdge !== undefined ?
+ this.props.resizeEdge === 'right'?
+ this.itemTimeEnd
+ : this.itemTimeStart
+ : null ,
width: this.props.dimensions.width
}
diff --git a/src/lib/items/Items.js b/src/lib/items/Items.js
index 87173f895..ddbc33c3f 100644
--- a/src/lib/items/Items.js
+++ b/src/lib/items/Items.js
@@ -1,10 +1,9 @@
import PropTypes from 'prop-types'
-import React, { Component } from 'react'
+import React, { PureComponent, Component } from 'react'
import Item from './Item'
-// import ItemGroup from './ItemGroup'
-
-import { _get, arraysEqual, keyBy } from '../utility/generic'
-import { getGroupOrders, getVisibleItems } from '../utility/calendar'
+import { TimelineStateConsumer } from '../timeline/TimelineStateContext'
+import { ItemsConsumer } from './ItemsContext'
+import { _get, arraysEqual } from '../utility/generic'
const canResizeLeft = (item, canResize) => {
const value =
@@ -18,14 +17,16 @@ const canResizeRight = (item, canResize) => {
return value === 'right' || value === 'both' || value === true
}
-export default class Items extends Component {
+export class Items extends Component {
static propTypes = {
- groups: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired,
items: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired,
canvasTimeStart: PropTypes.number.isRequired,
canvasTimeEnd: PropTypes.number.isRequired,
canvasWidth: PropTypes.number.isRequired,
+ visibleTimeEnd: PropTypes.number.isRequired,
+ visibleTimeStart: PropTypes.number.isRequired,
+ timelineWidth: PropTypes.number.isRequired,
dragSnap: PropTypes.number,
minResizeWidth: PropTypes.number,
@@ -51,10 +52,18 @@ export default class Items extends Component {
itemRenderer: PropTypes.func,
selected: PropTypes.array,
- dimensionItems: PropTypes.array,
- groupTops: PropTypes.array,
+ groupDimensions: PropTypes.object,
useResizeHandle: PropTypes.bool,
- scrollRef: PropTypes.object
+ scrollRef: PropTypes.object,
+ order: PropTypes.object,
+
+ onDragStart: PropTypes.func.isRequired,
+ onDragEnd: PropTypes.func.isRequired,
+ onResizeStart: PropTypes.func.isRequired,
+ dragging: PropTypes.bool.isRequired,
+ dragOffset: PropTypes.number.isRequired,
+ interactingItemId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ resizeEdge: PropTypes.oneOf(['right', 'left']),
}
static defaultProps = {
@@ -63,9 +72,8 @@ export default class Items extends Component {
shouldComponentUpdate(nextProps) {
return !(
- arraysEqual(nextProps.groups, this.props.groups) &&
arraysEqual(nextProps.items, this.props.items) &&
- arraysEqual(nextProps.dimensionItems, this.props.dimensionItems) &&
+ nextProps.groupDimensions === this.props.groupDimensions &&
nextProps.keys === this.props.keys &&
nextProps.canvasTimeStart === this.props.canvasTimeStart &&
nextProps.canvasTimeEnd === this.props.canvasTimeEnd &&
@@ -77,7 +85,11 @@ export default class Items extends Component {
nextProps.canChangeGroup === this.props.canChangeGroup &&
nextProps.canMove === this.props.canMove &&
nextProps.canResize === this.props.canResize &&
- nextProps.canSelect === this.props.canSelect
+ nextProps.canSelect === this.props.canSelect &&
+ nextProps.dragging === this.props.dragging &&
+ nextProps.resizing === this.props.resizing &&
+ nextProps.resizeEdge === this.props.resizeEdge &&
+ nextProps.interactingItemId === this.props.interactingItemId
)
}
@@ -90,81 +102,114 @@ export default class Items extends Component {
}
}
- getVisibleItems(canvasTimeStart, canvasTimeEnd) {
- const { keys, items } = this.props
-
- return getVisibleItems(items, canvasTimeStart, canvasTimeEnd, keys)
+ isInteractingItem = (item) => {
+ return this.props.interactingItemId === _get(item, this.props.keys.itemIdKey)
}
render() {
const {
- canvasTimeStart,
- canvasTimeEnd,
- dimensionItems,
keys,
- groups
+ groupDimensions,
+ order,
+ items
} = this.props
- const { itemIdKey, itemGroupKey } = keys
-
- const groupOrders = getGroupOrders(groups, keys)
- const visibleItems = this.getVisibleItems(
- canvasTimeStart,
- canvasTimeEnd,
- groupOrders
- )
- const sortedDimensionItems = keyBy(dimensionItems, 'id')
-
+ const { itemIdKey } = keys
return (
- {visibleItems
- .filter(item => sortedDimensionItems[_get(item, itemIdKey)])
- .map(item => (
-
- ))}
+ {items.map((item, i) => {
+ const isInteractingItem = this.isInteractingItem(item)
+ return (
+
+ )})}
)
}
}
+
+class ItemsWrapper extends PureComponent {
+ render() {
+ return (
+
+ {({ getTimelineState }) => {
+ const {
+ canvasTimeStart,
+ canvasTimeEnd,
+ canvasWidth,
+ visibleTimeEnd,
+ visibleTimeStart,
+ timelineWidth,
+ keys
+ } = getTimelineState()
+ return (
+
+ {props => (
+
+ )}
+
+ )
+ }}
+
+ )
+ }
+}
+
+export default ItemsWrapper
\ No newline at end of file
diff --git a/src/lib/items/ItemsContext.js b/src/lib/items/ItemsContext.js
new file mode 100644
index 000000000..043fb80d6
--- /dev/null
+++ b/src/lib/items/ItemsContext.js
@@ -0,0 +1,80 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+
+const defaultContextState = {
+ items: undefined,
+ dragSnap: undefined,
+ minResizeWidth: undefined,
+ selectedItem: undefined,
+ canChangeGroup: undefined,
+ canMove: undefined,
+ canResize: undefined,
+ canSelect: undefined,
+ moveResizeValidator: undefined,
+ itemSelect: undefined,
+ itemDrag: undefined,
+ itemDrop: undefined,
+ itemResizing: undefined,
+ itemResized: undefined,
+ onItemDoubleClick: undefined,
+ onItemContextMenu: undefined,
+ itemRenderer: undefined,
+ selected: undefined,
+ groupDimensions: undefined,
+ useResizeHandle: undefined,
+ scrollRef: undefined,
+ order: undefined,
+ onDragStart: undefined,
+ onDragEnd: undefined,
+ onResizeStart: undefined,
+ resizeEdge: undefined,
+ dragging: undefined,
+ resizing: undefined,
+ dragOffset: undefined,
+ interactingItemId: undefined,
+}
+
+const ItemsContext = React.createContext(defaultContextState)
+
+const { Consumer, Provider } = ItemsContext
+
+export class ItemsContextProvider extends PureComponent {
+ static propTypes = {
+ items: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired,
+ dragSnap: PropTypes.number,
+ minResizeWidth: PropTypes.number,
+ selectedItem: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ canChangeGroup: PropTypes.bool.isRequired,
+ canMove: PropTypes.bool.isRequired,
+ canResize: PropTypes.oneOf([true, false, 'left', 'right', 'both']),
+ canSelect: PropTypes.bool,
+ moveResizeValidator: PropTypes.func,
+ itemSelect: PropTypes.func,
+ itemDrag: PropTypes.func,
+ itemDrop: PropTypes.func,
+ itemResizing: PropTypes.func,
+ itemResized: PropTypes.func,
+ onItemDoubleClick: PropTypes.func,
+ onItemContextMenu: PropTypes.func,
+ itemRenderer: PropTypes.func,
+ selected: PropTypes.array,
+ groupDimensions: PropTypes.object,
+ useResizeHandle: PropTypes.bool,
+ scrollRef: PropTypes.object,
+ order: PropTypes.object,
+ onDragStart: PropTypes.func.isRequired,
+ onDragEnd: PropTypes.func.isRequired,
+ onResizeStart: PropTypes.func.isRequired,
+ dragging: PropTypes.bool.isRequired,
+ dragOffset: PropTypes.number.isRequired,
+ interactingItemId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ resizeEdge: PropTypes.oneOf(['right', 'left']),
+ }
+ render(){
+ const {children,...rest} = this.props
+ return
{children}
+ }
+}
+
+export const ItemsConsumer = Consumer
+export default ItemsContext
diff --git a/src/lib/markers/MarkerCanvas.js b/src/lib/markers/MarkerCanvas.js
index d41750c95..241cbe773 100644
--- a/src/lib/markers/MarkerCanvas.js
+++ b/src/lib/markers/MarkerCanvas.js
@@ -71,8 +71,8 @@ class MarkerCanvas extends React.Component {
onMouseLeave={this.handleMouseLeave}
ref={el => (this.containerEl = el)}
>
-
{this.props.children}
+
)
diff --git a/src/lib/row/GroupRow.js b/src/lib/row/GroupRow.js
deleted file mode 100644
index 65aaa7ff3..000000000
--- a/src/lib/row/GroupRow.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import React, { Component } from 'react'
-import PropTypes from 'prop-types'
-import PreventClickOnDrag from '../interaction/PreventClickOnDrag'
-
-class GroupRow extends Component {
- static propTypes = {
- onClick: PropTypes.func.isRequired,
- onDoubleClick: PropTypes.func.isRequired,
- onContextMenu: PropTypes.func.isRequired,
- isEvenRow: PropTypes.bool.isRequired,
- style: PropTypes.object.isRequired,
- clickTolerance: PropTypes.number.isRequired,
- group: PropTypes.object.isRequired,
- horizontalLineClassNamesForGroup: PropTypes.func
- }
-
- render() {
- const {
- onContextMenu,
- onDoubleClick,
- isEvenRow,
- style,
- onClick,
- clickTolerance,
- horizontalLineClassNamesForGroup,
- group
- } = this.props
-
- let classNamesForGroup = [];
- if (horizontalLineClassNamesForGroup) {
- classNamesForGroup = horizontalLineClassNamesForGroup(group);
- }
-
- return (
-
-
-
- )
- }
-}
-
-export default GroupRow
diff --git a/src/lib/row/GroupRows.js b/src/lib/row/GroupRows.js
deleted file mode 100644
index b7b1ae1d4..000000000
--- a/src/lib/row/GroupRows.js
+++ /dev/null
@@ -1,62 +0,0 @@
-import PropTypes from 'prop-types'
-import React, { Component } from 'react'
-import GroupRow from './GroupRow'
-
-export default class GroupRows extends Component {
- static propTypes = {
- canvasWidth: PropTypes.number.isRequired,
- lineCount: PropTypes.number.isRequired,
- groupHeights: PropTypes.array.isRequired,
- onRowClick: PropTypes.func.isRequired,
- onRowDoubleClick: PropTypes.func.isRequired,
- clickTolerance: PropTypes.number.isRequired,
- groups: PropTypes.array.isRequired,
- horizontalLineClassNamesForGroup: PropTypes.func,
- onRowContextClick: PropTypes.func.isRequired,
- }
-
- shouldComponentUpdate(nextProps) {
- return !(
- nextProps.canvasWidth === this.props.canvasWidth &&
- nextProps.lineCount === this.props.lineCount &&
- nextProps.groupHeights === this.props.groupHeights &&
- nextProps.groups === this.props.groups
- )
- }
-
- render() {
- const {
- canvasWidth,
- lineCount,
- groupHeights,
- onRowClick,
- onRowDoubleClick,
- clickTolerance,
- groups,
- horizontalLineClassNamesForGroup,
- onRowContextClick,
- } = this.props
- let lines = []
-
- for (let i = 0; i < lineCount; i++) {
- lines.push(
- onRowContextClick(evt, i)}
- onClick={evt => onRowClick(evt, i)}
- onDoubleClick={evt => onRowDoubleClick(evt, i)}
- key={`horizontal-line-${i}`}
- isEvenRow={i % 2 === 0}
- group={groups[i]}
- horizontalLineClassNamesForGroup={horizontalLineClassNamesForGroup}
- style={{
- width: `${canvasWidth}px`,
- height: `${groupHeights[i]}px`
- }}
- />
- )
- }
-
- return {lines}
- }
-}
diff --git a/src/lib/rows/DefaultLayer.js b/src/lib/rows/DefaultLayer.js
new file mode 100644
index 000000000..fd1368480
--- /dev/null
+++ b/src/lib/rows/DefaultLayer.js
@@ -0,0 +1,10 @@
+import React from 'react';
+import {GroupRow, RowColumns, RowItems} from '../../index'
+
+const DefaultLayer = () => {
+ return
+
+
+}
+
+export default DefaultLayer;
diff --git a/src/lib/rows/GroupRow.js b/src/lib/rows/GroupRow.js
new file mode 100644
index 000000000..18dcdb2eb
--- /dev/null
+++ b/src/lib/rows/GroupRow.js
@@ -0,0 +1,103 @@
+import React, { Component, PureComponent } from 'react'
+import PropTypes from 'prop-types'
+import PreventClickOnDrag from '../interaction/PreventClickOnDrag'
+import interact from 'interactjs'
+import { _get } from '../utility/generic'
+import { GroupRowConsumer } from './GroupRowContext'
+import { TimelineStateConsumer } from '../timeline/TimelineStateContext'
+
+class GroupRow extends Component {
+ static propTypes = {
+ onClick: PropTypes.func.isRequired,
+ onDoubleClick: PropTypes.func.isRequired,
+ onContextMenu: PropTypes.func.isRequired,
+ isEvenRow: PropTypes.bool.isRequired,
+ canvasWidth: PropTypes.number.isRequired,
+ groupHeight: PropTypes.number.isRequired,
+ clickTolerance: PropTypes.number.isRequired,
+ group: PropTypes.object.isRequired,
+ horizontalLineClassNamesForGroup: PropTypes.func,
+ keys: PropTypes.object
+ }
+
+ ref = React.createRef()
+
+ componentDidMount() {
+ interact(this.ref.current).dropzone({
+ accept: '.rct-item',
+ overlap: 'pointer'
+ })
+ }
+
+ render() {
+ const {
+ onContextMenu,
+ onDoubleClick,
+ isEvenRow,
+ onClick,
+ clickTolerance,
+ horizontalLineClassNamesForGroup,
+ group,
+ children,
+ keys,
+ canvasWidth,
+ groupHeight
+ } = this.props
+ let classNamesForGroup = []
+ if (horizontalLineClassNamesForGroup) {
+ classNamesForGroup = horizontalLineClassNamesForGroup(group)
+ }
+ return (
+
+
+ {children}
+
+
+ )
+ }
+}
+
+class GroupRowWrapper extends PureComponent {
+ render() {
+ return (
+
+ {({ getTimelineState }) => {
+ const { canvasWidth, keys } = getTimelineState()
+ return (
+
+ {props => (
+
+ )}
+
+ )
+ }}
+
+ )
+ }
+}
+
+export default GroupRowWrapper
diff --git a/src/lib/rows/GroupRowContext.js b/src/lib/rows/GroupRowContext.js
new file mode 100644
index 000000000..d72011504
--- /dev/null
+++ b/src/lib/rows/GroupRowContext.js
@@ -0,0 +1,53 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+
+const defaultContextState = {
+ clickTolerance: undefined,
+ onContextMenu: undefined,
+ onClick: undefined,
+ onDoubleClick: undefined,
+ isEvenRow: undefined,
+ group: undefined,
+ horizontalLineClassNamesForGroup: undefined,
+ groupHeight: undefined
+}
+
+const GroupRowContext = React.createContext(defaultContextState)
+
+const { Consumer, Provider } = GroupRowContext
+
+export class GroupRowContextProvider extends PureComponent {
+ static propTypes = {
+ clickTolerance: PropTypes.number.isRequired,
+ onContextMenu: PropTypes.func.isRequired,
+ onClick: PropTypes.func.isRequired,
+ onDoubleClick: PropTypes.func.isRequired,
+ isEvenRow: PropTypes.bool.isRequired,
+ group: PropTypes.object.isRequired,
+ horizontalLineClassNamesForGroup: PropTypes.func,
+ groupHeight: PropTypes.number.isRequired,
+ groupIndex: PropTypes.number.isRequired,
+ }
+ handleContextMenu = (e) => {
+ this.props.onContextMenu(e, this.props.groupIndex)
+ }
+ handleClick = (e) => {
+ this.props.onClick(e, this.props.groupIndex)
+ }
+ handleDoubleClick = (e) => {
+ this.props.onDoubleClick(e, this.props.groupIndex)
+ }
+ render() {
+ const { children, onContextMenu, onClick, onDoubleClick, ...rest } = this.props
+ const value = {
+ ...rest,
+ onContextMenu: this.handleContextMenu,
+ onClick: this.handleClick,
+ onDoubleClick: this.handleDoubleClick
+ }
+ return {children}
+ }
+}
+
+export const GroupRowConsumer = Consumer
+export default GroupRowContext
diff --git a/src/lib/rows/LayerContext.js b/src/lib/rows/LayerContext.js
new file mode 100644
index 000000000..a63d0bd1e
--- /dev/null
+++ b/src/lib/rows/LayerContext.js
@@ -0,0 +1,28 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+
+const defaultContextState = {
+ itemsWithInteractions: undefined,
+ getLayerRootProps: undefined,
+}
+
+const LayerContext = React.createContext(defaultContextState)
+
+const { Consumer, Provider } = LayerContext
+
+export class LayerContextProvider extends PureComponent {
+ static propTypes = {
+ itemsWithInteractions: PropTypes.array.isRequired,
+ getLayerRootProps: PropTypes.func.isRequired,
+ }
+ render() {
+ const { children, ...rest } = this.props
+ const value = {
+ ...rest,
+ }
+ return {children}
+ }
+}
+
+export const LayerConsumer = Consumer
+export default LayerContext
diff --git a/src/lib/rows/Rows.js b/src/lib/rows/Rows.js
new file mode 100644
index 000000000..a2377bcdf
--- /dev/null
+++ b/src/lib/rows/Rows.js
@@ -0,0 +1,252 @@
+import React from 'react'
+import { _get, _length } from '../utility/generic'
+import { ItemsContextProvider } from '../items/ItemsContext'
+import { GroupRowContextProvider } from './GroupRowContext'
+import { LayerContextProvider, LayerConsumer } from './LayerContext'
+
+class Rows extends React.PureComponent {
+ initState = {
+ dragging: false,
+ resizing: false,
+ dragOffset: 0,
+ interactingItemId: undefined
+ }
+
+ state = this.initState
+
+ handleDragStart = (dragging, dragOffset, itemId) => {
+ this.setState({
+ dragging,
+ dragOffset,
+ interactingItemId: itemId
+ })
+ }
+
+ clearState = () => {
+ this.setState(this.initState)
+ }
+
+ handleResizeEnd = (itemId, resizeTime, resizeEdge, timeDelta) => {
+ this.props.itemResized(itemId, resizeTime, resizeEdge, timeDelta)
+ this.clearState()
+ }
+
+ handleDragEnd = () => {
+ this.clearState()
+ }
+
+ handleResizeStart = (resizing, itemId) => {
+ this.setState({
+ resizing,
+ interactingItemId: itemId
+ })
+ }
+
+ getLayerRootProps = () => {
+ return {
+ style: {
+ // height: '100%'
+ }
+ }
+ }
+
+ render() {
+ const {
+ groupHeights,
+ groups,
+ itemRenderer,
+ canChangeGroup,
+ canMove,
+ canResize,
+ canSelect,
+ useResizeHandle,
+ dragSnap,
+ minResizeWidth,
+ itemResizing,
+ moveResizeValidator,
+ itemDrag,
+ itemDrop,
+ onItemDoubleClick,
+ onItemContextMenu,
+ itemSelect,
+ scrollRef,
+ selected,
+ selectedItem,
+ rowRenderer: Layers,
+ rowData,
+ groupsWithItemsDimensions,
+ //row props
+ clickTolerance,
+ onRowClick,
+ onRowDoubleClick,
+ horizontalLineClassNamesForGroup,
+ onRowContextClick,
+ items,
+ keys,
+ resizeEdge
+ } = this.props
+ return (
+
+
+ {groupHeights.map((groupHeight, i) => {
+ const groupId = _get(groups[i], keys.groupIdKey)
+ const group = groupsWithItemsDimensions[groupId]
+ return (
+
+ )
+ })}
+
+
+ )
+ }
+}
+
+class Group extends React.PureComponent {
+ render() {
+ const {
+ clickTolerance,
+ onRowContextClick,
+ onRowClick,
+ onRowDoubleClick,
+ index,
+ groups,
+ horizontalLineClassNamesForGroup,
+ groupHeight,
+ group,
+ dragSnap,
+ minResizeWidth,
+ selectedItem,
+ canChangeGroup,
+ canMove,
+ canResize,
+ canSelect,
+ moveResizeValidator,
+ itemSelect,
+ itemDrag,
+ itemDrop,
+ itemResizing,
+ onItemDoubleClick,
+ onItemContextMenu,
+ itemRenderer,
+ selected,
+ useResizeHandle,
+ scrollRef,
+ resizeEdge,
+ Layers,
+ rowData,
+ itemResized,
+ onDragStart,
+ onDragEnd,
+ onResizeStart,
+ dragging,
+ resizing,
+ dragOffset,
+ interactingItemId
+ } = this.props
+
+ return (
+
+
+
+ {({getLayerRootProps, itemsWithInteractions}) => (
+
+ )}
+
+
+
+ )
+ }
+}
+
+export default Rows
diff --git a/src/lib/timeline/HelpersContext.js b/src/lib/timeline/HelpersContext.js
new file mode 100644
index 000000000..1fb4941ff
--- /dev/null
+++ b/src/lib/timeline/HelpersContext.js
@@ -0,0 +1,147 @@
+import React, { PureComponent } from 'react'
+import PropTypes from 'prop-types'
+import { _get } from '../utility/generic'
+import { TimelineStateConsumer } from '../timeline/TimelineStateContext'
+import memoize from 'memoize-one'
+
+const defaultContextState = {
+ getLeftOffsetFromDate: () => {
+ console.warn('"getLeftOffsetFromDate" default func is being used')
+ },
+ getDateFromLeftOffsetPosition: () => {
+ console.warn('"getDateFromLeftOffsetPosition" default func is being used')
+ },
+ getItemAbsoluteDimensions: () => {
+ console.warn('"getItemAbsoluteDimensions" default func is being used')
+ },
+ getItemDimensions: () => {
+ console.warn('"getItemDimensions" default func is being used')
+ }
+}
+
+const HelpersContext = React.createContext(defaultContextState)
+
+const { Consumer, Provider } = HelpersContext
+
+class HelpersContextProviderCore extends PureComponent {
+ static propTypes = {
+ getLeftOffsetFromDate: PropTypes.func.isRequired,
+ getDateFromLeftOffsetPosition: PropTypes.func.isRequired,
+ groupsWithItemsDimensions: PropTypes.object.isRequired,
+ items: PropTypes.array.isRequired,
+ keys: PropTypes.object.isRequired,
+ groupHeights: PropTypes.array.isRequired,
+ groupTops: PropTypes.array.isRequired
+ }
+
+ getGroupByItemId = itemId => {
+ const { items, keys } = this.props
+ const item = items.find(i => _get(i, keys.itemIdKey) === itemId)
+ const groupId = _get(item, keys.itemGroupKey)
+ return groupId
+ }
+
+ /**
+ * create new instance of getItemDimensions of dependant props have changed (similar to useCallback)
+ */
+ getItemDimensionsCreator = memoize(
+ (groupsWithItemsDimensions, getGroupByItemId) => itemId => {
+ const groupId = getGroupByItemId(itemId)
+ const group = groupsWithItemsDimensions[groupId]
+ const itemDimensions = group.itemDimensions.find(i => i.id === itemId)
+ if (itemDimensions) return itemDimensions.dimensions
+ else return undefined
+ }
+ )
+
+ /**
+ * create new instance of getItemAbsoluteDimensions of dependant props have changed (similar to useCallback)
+ */
+ getItemAbsoluteDimensionsCreator = memoize(
+ (groupHeights, groupsWithItemsDimensions, getGroupByItemId) => itemId => {
+ const groupId = getGroupByItemId(itemId)
+ const group = groupsWithItemsDimensions[groupId]
+ const itemDimensions = group.itemDimensions.find(i => i.id === itemId)
+ if (!itemDimensions) return
+ const groupIndex = group.index
+ const groupTop = groupHeights.reduce((acc, height, index) => {
+ if (index < groupIndex) return acc + height
+ else return acc
+ }, 0)
+ return {
+ left: itemDimensions.dimensions.left,
+ top: groupTop + itemDimensions.dimensions.top,
+ width: itemDimensions.dimensions.width
+ }
+ }
+ )
+
+ /**
+ * create new instance of getGroupDimensionsCreator of dependant props have changed (similar to useCallback)
+ */
+ getGroupDimensionsCreator = memoize((
+ groupsWithItemsDimensions,
+ groupHeights,
+ groupTops
+ ) => groupId => {
+ const group = groupsWithItemsDimensions[groupId]
+ if (!group) return
+ const index = group.index
+ const height = groupHeights[index]
+ const top = groupTops[index]
+ return {
+ height,
+ top
+ }
+ })
+
+ render() {
+ const { children } = this.props
+ return (
+
+ {children}
+
+ )
+ }
+}
+
+export class HelpersContextProvider extends PureComponent {
+ render() {
+ return (
+
+ {({ getLeftOffsetFromDate, getDateFromLeftOffsetPosition }) => {
+ return (
+
+ )
+ }}
+
+ )
+ }
+}
+
+export const HelpersConsumer = Consumer
+export default HelpersContext
diff --git a/src/lib/timeline/TimelineStateContext.js b/src/lib/timeline/TimelineStateContext.js
index 6b87520bb..8317eaab7 100644
--- a/src/lib/timeline/TimelineStateContext.js
+++ b/src/lib/timeline/TimelineStateContext.js
@@ -30,7 +30,9 @@ const defaultContextState = {
}
/* eslint-enable */
-const { Consumer, Provider } = createReactContext(defaultContextState)
+const TimelineStateContext = createReactContext(defaultContextState)
+
+const { Consumer, Provider } = TimelineStateContext
export class TimelineStateProvider extends React.Component {
/* eslint-disable react/no-unused-prop-types */
@@ -46,6 +48,7 @@ export class TimelineStateProvider extends React.Component {
showPeriod: PropTypes.func.isRequired,
timelineUnit: PropTypes.string.isRequired,
timelineWidth: PropTypes.number.isRequired,
+ keys: PropTypes.object.isRequired
}
constructor(props) {
@@ -70,6 +73,7 @@ export class TimelineStateProvider extends React.Component {
canvasWidth,
timelineUnit,
timelineWidth,
+ keys,
} = this.props
return {
visibleTimeStart,
@@ -79,6 +83,7 @@ export class TimelineStateProvider extends React.Component {
canvasWidth,
timelineUnit,
timelineWidth,
+ keys,
} // REVIEW,
}
@@ -112,3 +117,4 @@ export class TimelineStateProvider extends React.Component {
}
export const TimelineStateConsumer = Consumer
+export default TimelineStateContext;
diff --git a/src/lib/utility/calendar.js b/src/lib/utility/calendar.js
index be501951b..6daaa0407 100644
--- a/src/lib/utility/calendar.js
+++ b/src/lib/utility/calendar.js
@@ -1,5 +1,6 @@
import moment from 'moment'
-import { _get } from './generic'
+import { _get, arraysEqual } from './generic'
+import memoize from 'memoize-one';
/**
* Calculate the ms / pixel ratio of the timeline state
@@ -243,36 +244,6 @@ export function getGroupOrders(groups, keys) {
return groupOrders
}
-/**
- * Adds items relevant to each group to the result of getGroupOrders
- * @param {*} items list of all items
- * @param {*} groupOrders the result of getGroupOrders
- */
-export function getGroupedItems(items, groupOrders) {
- var groupedItems = {}
- var keys = Object.keys(groupOrders)
- // Initialize with result object for each group
- for (let i = 0; i < keys.length; i++) {
- const groupOrder = groupOrders[keys[i]]
- groupedItems[i] = {
- index: groupOrder.index,
- group: groupOrder.group,
- items: []
- }
- }
-
- // Populate groups
- for (let i = 0; i < items.length; i++) {
- if (items[i].dimensions.order !== undefined) {
- const groupItem = groupedItems[items[i].dimensions.order.index]
- if (groupItem) {
- groupItem.items.push(items[i])
- }
- }
- }
-
- return groupedItems
-}
export function getVisibleItems(items, canvasTimeStart, canvasTimeEnd, keys) {
const { itemTimeStartKey, itemTimeEndKey } = keys
@@ -308,14 +279,13 @@ export function groupStack(
item,
group,
groupHeight,
- groupTop,
itemIndex
) {
// calculate non-overlapping positions
let curHeight = groupHeight
let verticalMargin = (lineHeight - item.dimensions.height) / 2
if (item.dimensions.stack && item.dimensions.top === null) {
- item.dimensions.top = groupTop + verticalMargin
+ item.dimensions.top = verticalMargin
curHeight = Math.max(curHeight, lineHeight)
do {
var collidingItem = null
@@ -339,7 +309,7 @@ export function groupStack(
item.dimensions.top = collidingItem.dimensions.top + lineHeight
curHeight = Math.max(
curHeight,
- item.dimensions.top + item.dimensions.height + verticalMargin - groupTop
+ item.dimensions.top + item.dimensions.height + verticalMargin
)
}
} while (collidingItem)
@@ -353,10 +323,10 @@ export function groupStack(
}
// Calculate the position of this item for a group that is not being stacked
-export function groupNoStack(lineHeight, item, groupHeight, groupTop) {
+export function groupNoStack(lineHeight, item, groupHeight) {
let verticalMargin = (lineHeight - item.dimensions.height) / 2
if (item.dimensions.top === null) {
- item.dimensions.top = groupTop + verticalMargin
+ item.dimensions.top = verticalMargin
groupHeight = Math.max(groupHeight, lineHeight)
}
return { groupHeight, verticalMargin: 0, itemTop: item.dimensions.top }
@@ -366,58 +336,13 @@ function sum(arr = []) {
return arr.reduce((acc, i) => acc + i, 0)
}
-/**
- * Stack all groups
- * @param {*} items items to be stacked
- * @param {*} groupOrders the groupOrders object
- * @param {*} lineHeight
- * @param {*} stackItems should items be stacked?
- */
-export function stackAll(itemsDimensions, groupOrders, lineHeight, stackItems) {
- var groupHeights = []
- var groupTops = []
-
- var groupedItems = getGroupedItems(itemsDimensions, groupOrders)
-
- for (var index in groupedItems) {
- const groupItems = groupedItems[index]
- const { items: itemsDimensions, group } = groupItems
- const groupTop = sum(groupHeights)
-
- // Is group being stacked?
- const isGroupStacked =
- group.stackItems !== undefined ? group.stackItems : stackItems
- const { groupHeight, verticalMargin } = stackGroup(
- itemsDimensions,
- isGroupStacked,
- lineHeight,
- groupTop
- )
- // If group height is overridden, push new height
- // Do this late as item position still needs to be calculated
- groupTops.push(groupTop)
- if (group.height) {
- groupHeights.push(group.height)
- } else {
- groupHeights.push(Math.max(groupHeight, lineHeight))
- }
- }
-
- return {
- height: sum(groupHeights),
- groupHeights,
- groupTops
- }
-}
-
/**
*
* @param {*} itemsDimensions
* @param {*} isGroupStacked
* @param {*} lineHeight
- * @param {*} groupTop
*/
-export function stackGroup(itemsDimensions, isGroupStacked, lineHeight, groupTop) {
+export function stackGroup(itemsDimensions, isGroupStacked, lineHeight) {
var groupHeight = 0
var verticalMargin = 0
// Find positions for each item in group
@@ -429,16 +354,15 @@ export function stackGroup(itemsDimensions, isGroupStacked, lineHeight, groupTop
itemsDimensions[itemIndex],
itemsDimensions,
groupHeight,
- groupTop,
itemIndex
)
} else {
- r = groupNoStack(lineHeight, itemsDimensions[itemIndex], groupHeight, groupTop)
+ r = groupNoStack(lineHeight, itemsDimensions[itemIndex], groupHeight)
}
groupHeight = r.groupHeight
verticalMargin = r.verticalMargin
}
- return { groupHeight, verticalMargin }
+ return { groupHeight: groupHeight || lineHeight, verticalMargin }
}
/**
@@ -458,7 +382,7 @@ export function stackGroup(itemsDimensions, isGroupStacked, lineHeight, groupTop
* @param {number} dragTime
* @param {left or right} resizingEdge
* @param {number} resizeTime
- * @param {number} newGroupOrder
+ * @param {number} newGroupId
*/
export function stackTimelineItems(
items,
@@ -475,15 +399,10 @@ export function stackTimelineItems(
dragTime,
resizingEdge,
resizeTime,
- newGroupOrder
+ newGroupId
) {
- const visibleItems = getVisibleItems(
- items,
- canvasTimeStart,
- canvasTimeEnd,
- keys
- )
- const visibleItemsWithInteraction = visibleItems.map(item =>
+
+ const itemsWithInteractions = items.map(item =>
getItemWithInteractions({
item,
keys,
@@ -492,45 +411,64 @@ export function stackTimelineItems(
dragTime,
resizingEdge,
resizeTime,
- groups,
- newGroupOrder
+ newGroupId
})
)
+ const visibleItemsWithInteraction = getVisibleItems(
+ itemsWithInteractions,
+ canvasTimeStart,
+ canvasTimeEnd,
+ keys
+ )
+
// if there are no groups return an empty array of dimensions
if (groups.length === 0) {
return {
- dimensionItems: [],
+ groupsWithItemsDimensions: {},
height: 0,
groupHeights: [],
groupTops: []
}
}
- // Get the order of groups based on their id key
- const groupOrders = getGroupOrders(groups, keys)
- let dimensionItems = visibleItemsWithInteraction
- .map(item =>
- getItemDimensions({
- item,
- keys,
- canvasTimeStart,
- canvasTimeEnd,
- canvasWidth,
- groupOrders,
- lineHeight,
- itemHeightRatio
- })
- )
- .filter(item => !!item)
- // Get a new array of groupOrders holding the stacked items
- const { height, groupHeights, groupTops } = stackAll(
- dimensionItems,
- groupOrders,
+ const groupsWithItems = getOrderedGroupsWithItems(
+ groups,
+ visibleItemsWithInteraction,
+ keys
+ )
+ const groupsWithItemsDimensions = getGroupsWithItemDimensions(
+ groupsWithItems,
+ keys,
lineHeight,
- stackItems
+ itemHeightRatio,
+ stackItems,
+ canvasTimeStart,
+ canvasTimeEnd,
+ canvasWidth,
+ groups,
)
- return { dimensionItems, height, groupHeights, groupTops }
+ const groupHeights = groups.map(group => {
+ const groupKey = _get(group, keys.groupIdKey)
+ const groupsWithItemDimensions = groupsWithItemsDimensions[groupKey]
+ return groupsWithItemDimensions.height
+ })
+
+ const groupTops = groupHeights.reduce(
+ (acc, height, index) => {
+ //skip last calculation because we already have 0 as first item in acc
+ if(groupHeights.length -1 === index) return acc
+ const lastIndex = acc.length - 1
+ const lastTop = acc[lastIndex]
+ acc.push(lastTop + height)
+
+ return acc
+ },
+ [0]
+ )
+ const height = groupHeights.reduce((acc, height) => acc + height, 0)
+
+ return { groupsWithItemsDimensions, height, groupHeights, groupTops, itemsWithInteractions }
}
/**
@@ -549,7 +487,6 @@ export function getCanvasWidth(width, buffer = 3) {
* @param {*} canvasTimeStart
* @param {*} canvasTimeEnd
* @param {*} canvasWidth
- * @param {*} groupOrders
* @param {*} lineHeight
* @param {*} itemHeightRatio
*/
@@ -559,7 +496,6 @@ export function getItemDimensions({
canvasTimeStart,
canvasTimeEnd,
canvasWidth,
- groupOrders,
lineHeight,
itemHeightRatio
}) {
@@ -573,7 +509,6 @@ export function getItemDimensions({
})
if (dimension) {
dimension.top = null
- dimension.order = groupOrders[_get(item, keys.itemGroupKey)]
dimension.stack = !item.isOverlay
dimension.height = lineHeight * itemHeightRatio
return {
@@ -594,7 +529,7 @@ export function getItemDimensions({
* @param {*} resizingEdge
* @param {*} resizeTime
* @param {*} groups
- * @param {*} newGroupOrder
+ * @param {*} newGroupId
*/
export function getItemWithInteractions({
item,
@@ -604,13 +539,15 @@ export function getItemWithInteractions({
dragTime,
resizingEdge,
resizeTime,
- groups,
- newGroupOrder
+ newGroupId
}) {
+ //TODO: remove from here. This shouldn't be this function's responsibility
if (!resizingItem && !draggingItem) return item
const itemId = _get(item, keys.itemIdKey)
const isDragging = itemId === draggingItem
const isResizing = itemId === resizingItem
+ //return item if is not being dragged or resized
+ if(!isResizing && !isDragging) return item
const [itemTimeStart, itemTimeEnd] = calculateInteractionNewTimes({
itemTimeStart: _get(item, keys.itemTimeStartKey),
itemTimeEnd: _get(item, keys.itemTimeEndKey),
@@ -620,12 +557,13 @@ export function getItemWithInteractions({
resizingEdge,
resizeTime
})
+
const newItem = {
...item,
[keys.itemTimeStartKey]: itemTimeStart,
[keys.itemTimeEndKey]: itemTimeEnd,
[keys.itemGroupKey]: isDragging
- ? _get(groups[newGroupOrder], keys.groupIdKey)
+ ? newGroupId
: _get(item, keys.itemGroupKey)
}
return newItem
@@ -712,9 +650,155 @@ export function calculateScrollCanvas(
mergedState.dragTime,
mergedState.resizingEdge,
mergedState.resizeTime,
- mergedState.newGroupOrder
+ mergedState.newGroupId
)
)
}
return newState
}
+
+/**
+ * get item dimensions of a group
+ * @param {*} groupWithItems
+ * @param {*} keys
+ * @param {*} canvasTimeStart
+ * @param {*} canvasTimeEnd
+ * @param {*} canvasWidth
+ * @param {*} lineHeight
+ * @param {*} itemHeightRatio
+ * @param {*} stackItems
+ */
+export function getGroupWithItemDimensions(
+ groupWithItems,
+ keys,
+ canvasTimeStart,
+ canvasTimeEnd,
+ canvasWidth,
+ lineHeight,
+ itemHeightRatio,
+ stackItems
+) {
+ const itemDimensions = groupWithItems.items.map(item => {
+ return getItemDimensions({
+ item,
+ keys,
+ canvasTimeStart,
+ canvasTimeEnd,
+ canvasWidth,
+ lineHeight,
+ itemHeightRatio
+ })
+ })
+ const { groupHeight } = stackGroup(itemDimensions, stackItems, lineHeight)
+ return {
+ ...groupWithItems,
+ itemDimensions: itemDimensions,
+ height: groupHeight
+ }
+}
+
+/**
+ * group timeline items by key
+ * returns a key/array pair object
+ * @param {*} items
+ * @param {*} key
+ */
+export function groupItemsByKey(items, key) {
+ return items.reduce((acc, item) => {
+ const itemKey = _get(item, key)
+ if (acc[itemKey]) {
+ acc[itemKey].push(item)
+ } else {
+ acc[itemKey] = [item]
+ }
+ return acc
+ }, {})
+}
+
+export function getOrderedGroupsWithItems(groups, items, keys) {
+ const groupOrders = getGroupOrders(groups, keys)
+ const groupsWithItems = {}
+ const groupKeys = Object.keys(groupOrders)
+ const groupedItems = groupItemsByKey(items, keys.itemGroupKey)
+ // Initialize with result object for each group
+ for (let i = 0; i < groupKeys.length; i++) {
+ const groupOrder = groupOrders[groupKeys[i]]
+ groupsWithItems[groupKeys[i]] = {
+ index: groupOrder.index,
+ group: groupOrder.group,
+ items: groupedItems[_get(groupOrder.group, keys.groupIdKey)] || []
+ }
+ }
+ return groupsWithItems
+}
+
+/**
+ * shallow compare ordered groups with items
+ * if index or group changed reference compare then not equal
+ * if new/old group's items changed array shallow equality then not equal
+ * @param {*} newGroup
+ * @param {*} oldGroup
+ */
+export function shallowIsEqualOrderedGroup(newGroup, oldGroup){
+ if(newGroup.group !== oldGroup.group) return false
+ if(newGroup.index !== oldGroup.index) return false
+ return arraysEqual(newGroup.items, oldGroup.items)
+}
+
+/**
+ * compare getGroupWithItemDimensions params. All params are compared via reference equality
+ * only groups are checked via a custom shallow equality
+ * @param {*} newArgs
+ * @param {*} oldArgs
+ */
+export function isEqualItemWithDimensions(newArgs, oldArgs){
+ const [newGroup, ...newRest] = newArgs;
+ const [oldGroup, ...oldRest] = oldArgs;
+ //shallow equality
+ if(!arraysEqual(newRest, oldRest)) return false;
+ return shallowIsEqualOrderedGroup(newGroup, oldGroup)
+}
+
+/**
+ * returns a cache in the form of dictionary ([groupId]: cachedMethod) for calculating getGroupWithItemDimensions
+ * the cache is cleared if groups or keys changed in reference
+ * @param {*} groups
+ * @param {*} keys
+ */
+export const getGroupsCache = memoize((groups, keys, method)=>{
+ return groups.reduce((acc, group) => {
+ const id = _get(group, keys.groupIdKey);
+ acc[id] = memoize(method, isEqualItemWithDimensions)
+ return acc
+ }, {})
+})
+
+export function getGroupsWithItemDimensions(
+ groupsWithItems,
+ keys,
+ lineHeight,
+ itemHeightRatio,
+ stackItems,
+ canvasTimeStart,
+ canvasTimeEnd,
+ canvasWidth,
+ groups,
+) {
+ const cache = getGroupsCache(groups, keys, getGroupWithItemDimensions)
+ const groupKeys = Object.keys(groupsWithItems)
+ return groupKeys.reduce((acc, groupKey) => {
+ const group = groupsWithItems[groupKey]
+ const cachedGetGroupWithItemDimensions = cache[groupKey];
+ acc[groupKey] = cachedGetGroupWithItemDimensions(
+ group,
+ keys,
+ canvasTimeStart,
+ canvasTimeEnd,
+ canvasWidth,
+ lineHeight,
+ itemHeightRatio,
+ stackItems
+ )
+ return acc
+ }, {})
+}
diff --git a/src/lib/utility/dom-helpers.js b/src/lib/utility/dom-helpers.js
index 36a85c652..c0b5c98af 100644
--- a/src/lib/utility/dom-helpers.js
+++ b/src/lib/utility/dom-helpers.js
@@ -25,7 +25,7 @@ export function getParentPosition(element) {
}
export function getSumScroll(node) {
- if (node === document.body) {
+ if (node === document.body || node === null) {
return {scrollLeft: 0, scrollTop: 0}
} else {
const parent = getSumScroll(node.parentNode)
@@ -37,7 +37,7 @@ export function getSumScroll(node) {
}
export function getSumOffset(node) {
- if (node === document.body) {
+ if (node === document.body || node === null) {
return {offsetLeft: 0, offsetTop: 0}
} else {
const parent = getSumOffset(node.offsetParent)
diff --git a/yarn.lock b/yarn.lock
index adaeacef0..e88147795 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -628,6 +628,13 @@
dependencies:
regenerator-runtime "^0.13.2"
+"@babel/runtime@^7.5.1":
+ version "7.6.3"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.3.tgz#935122c74c73d2240cafd32ddb5fc2a6cd35cf1f"
+ integrity sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==
+ dependencies:
+ regenerator-runtime "^0.13.2"
+
"@babel/template@^7.1.0", "@babel/template@^7.4.0", "@babel/template@^7.4.4":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237"
@@ -812,6 +819,25 @@
version "0.3.2"
resolved "https://registry.yarnpkg.com/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.2.tgz#8013f2af54a2b7d735f71560ff360d3a8176a87b"
+"@testing-library/jest-dom@^4.2.0":
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-4.2.0.tgz#32f8df3a78511b347d39374ea89dc8e0a1c2fb69"
+ integrity sha512-H61OmRhGPWLrj9emyISx0qjp8jvC9RWyRniuLAq75Ny5XfPiOvWfnY3Wm2Tf0HXusX+PG40I94Gw792IAtSKKg==
+ dependencies:
+ "@babel/runtime" "^7.5.1"
+ chalk "^2.4.1"
+ css "^2.2.3"
+ css.escape "^1.5.1"
+ jest-diff "^24.0.0"
+ jest-matcher-utils "^24.0.0"
+ lodash "^4.17.11"
+ pretty-format "^24.0.0"
+ redent "^3.0.0"
+
+"@types/asap@^2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/@types/asap/-/asap-2.0.0.tgz#d529e9608c83499a62ae08c871c5e62271aa2963"
+
"@types/babel__core@^7.1.0":
version "7.1.2"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.2.tgz#608c74f55928033fce18b99b213c16be4b3d114f"
@@ -841,6 +867,17 @@
dependencies:
"@babel/types" "^7.3.0"
+"@types/hoist-non-react-statics@^3.3.1":
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
+ dependencies:
+ "@types/react" "*"
+ hoist-non-react-statics "^3.3.0"
+
+"@types/invariant@^2.2.30":
+ version "2.2.30"
+ resolved "https://registry.yarnpkg.com/@types/invariant/-/invariant-2.2.30.tgz#20efa342807606ada5483731a8137cb1561e5fe9"
+
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff"
@@ -862,10 +899,37 @@
"@types/istanbul-lib-coverage" "*"
"@types/istanbul-lib-report" "*"
+"@types/jest-diff@*":
+ version "20.0.1"
+ resolved "https://registry.yarnpkg.com/@types/jest-diff/-/jest-diff-20.0.1.tgz#35cc15b9c4f30a18ef21852e255fdb02f6d59b89"
+ integrity sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==
+
+"@types/jest@24":
+ version "24.0.19"
+ resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.0.19.tgz#f7036058d2a5844fe922609187c0ad8be430aff5"
+ integrity sha512-YYiqfSjocv7lk5H/T+v5MjATYjaTMsUkbDnjGqSMoO88jWdtJXJV4ST/7DKZcoMHMBvB2SeSfyOzZfkxXHR5xg==
+ dependencies:
+ "@types/jest-diff" "*"
+
"@types/node@*":
version "9.3.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-9.3.0.tgz#3a129cda7c4e5df2409702626892cb4b96546dd5"
+"@types/prop-types@*":
+ version "15.7.1"
+ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.1.tgz#f1a11e7babb0c3cad68100be381d1e064c68f1f6"
+
+"@types/react@*":
+ version "16.9.1"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.1.tgz#862c83b4c9d5cd116e42fd9a4f3694843cd2c051"
+ dependencies:
+ "@types/prop-types" "*"
+ csstype "^2.2.0"
+
+"@types/shallowequal@^1.1.1":
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@types/shallowequal/-/shallowequal-1.1.1.tgz#aad262bb3f2b1257d94c71d545268d592575c9b1"
+
"@types/stack-utils@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
@@ -1260,7 +1324,7 @@ arrify@^1.0.0, arrify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
-asap@~2.0.3:
+asap@^2.0.6, asap@~2.0.3:
version "2.0.6"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
@@ -2048,7 +2112,7 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
dependencies:
delayed-stream "~1.0.0"
-commander@^2.8.1, commander@~2.20.0:
+commander@2, commander@^2.8.1, commander@~2.20.0:
version "2.20.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
@@ -2398,6 +2462,10 @@ cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
dependencies:
cssom "0.3.x"
+csstype@^2.2.0:
+ version "2.6.6"
+ resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.6.tgz#c34f8226a94bbb10c32cc0d714afdf942291fc41"
+
currently-unhandled@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
@@ -2408,6 +2476,222 @@ cyclist@~0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640"
+d3-array@1, d3-array@^1.1.1, d3-array@^1.2.0:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f"
+
+d3-axis@1:
+ version "1.0.12"
+ resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-1.0.12.tgz#cdf20ba210cfbb43795af33756886fb3638daac9"
+
+d3-brush@1:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-1.1.3.tgz#a04900a71fa5390f7f7afe1504b02a382709f380"
+ dependencies:
+ d3-dispatch "1"
+ d3-drag "1"
+ d3-interpolate "1"
+ d3-selection "1"
+ d3-transition "1"
+
+d3-chord@1:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/d3-chord/-/d3-chord-1.0.6.tgz#309157e3f2db2c752f0280fedd35f2067ccbb15f"
+ dependencies:
+ d3-array "1"
+ d3-path "1"
+
+d3-collection@1:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.7.tgz#349bd2aa9977db071091c13144d5e4f16b5b310e"
+
+d3-color@1:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.3.0.tgz#675818359074215b020dc1d41d518136dcb18fa9"
+
+d3-contour@1:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/d3-contour/-/d3-contour-1.3.2.tgz#652aacd500d2264cb3423cee10db69f6f59bead3"
+ dependencies:
+ d3-array "^1.1.1"
+
+d3-dispatch@1:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.5.tgz#e25c10a186517cd6c82dd19ea018f07e01e39015"
+
+d3-drag@1:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-1.2.4.tgz#ba9331d68158ad14cf0b4b28a8afa9e78c7d99ad"
+ dependencies:
+ d3-dispatch "1"
+ d3-selection "1"
+
+d3-dsv@1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-1.1.1.tgz#aaa830ecb76c4b5015572c647cc6441e3c7bb701"
+ dependencies:
+ commander "2"
+ iconv-lite "0.4"
+ rw "1"
+
+d3-ease@1:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-1.0.5.tgz#8ce59276d81241b1b72042d6af2d40e76d936ffb"
+
+d3-fetch@1:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/d3-fetch/-/d3-fetch-1.1.2.tgz#957c8fbc6d4480599ba191b1b2518bf86b3e1be2"
+ dependencies:
+ d3-dsv "1"
+
+d3-force@1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-1.2.1.tgz#fd29a5d1ff181c9e7f0669e4bd72bdb0e914ec0b"
+ dependencies:
+ d3-collection "1"
+ d3-dispatch "1"
+ d3-quadtree "1"
+ d3-timer "1"
+
+d3-format@1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.4.1.tgz#c45f74b17c5a290c072a4ba7039dd19662cd5ce6"
+
+d3-geo@1:
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-1.11.6.tgz#134f2ef035ff75a448075fafdea92702a2e0e0cf"
+ dependencies:
+ d3-array "1"
+
+d3-hierarchy@1:
+ version "1.1.8"
+ resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-1.1.8.tgz#7a6317bd3ed24e324641b6f1e76e978836b008cc"
+
+d3-interpolate@1:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.3.2.tgz#417d3ebdeb4bc4efcc8fd4361c55e4040211fd68"
+ dependencies:
+ d3-color "1"
+
+d3-path@1:
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.8.tgz#4a0606a794d104513ec4a8af43525f374b278719"
+
+d3-polygon@1:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-1.0.5.tgz#9a645a0a64ff6cbf9efda96ee0b4a6909184c363"
+
+d3-quadtree@1:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-1.0.6.tgz#d1ab2a95a7f27bbde88582c94166f6ae35f32056"
+
+d3-random@1:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/d3-random/-/d3-random-1.1.2.tgz#2833be7c124360bf9e2d3fd4f33847cfe6cab291"
+
+d3-scale-chromatic@1:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-1.5.0.tgz#54e333fc78212f439b14641fb55801dd81135a98"
+ dependencies:
+ d3-color "1"
+ d3-interpolate "1"
+
+d3-scale@2:
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-2.2.2.tgz#4e880e0b2745acaaddd3ede26a9e908a9e17b81f"
+ dependencies:
+ d3-array "^1.2.0"
+ d3-collection "1"
+ d3-format "1"
+ d3-interpolate "1"
+ d3-time "1"
+ d3-time-format "2"
+
+d3-selection@1, d3-selection@^1.1.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-1.4.0.tgz#ab9ac1e664cf967ebf1b479cc07e28ce9908c474"
+
+d3-shape@1:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.5.tgz#e81aea5940f59f0a79cfccac012232a8987c6033"
+ dependencies:
+ d3-path "1"
+
+d3-time-format@2:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.1.3.tgz#ae06f8e0126a9d60d6364eac5b1533ae1bac826b"
+ dependencies:
+ d3-time "1"
+
+d3-time@1:
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.0.11.tgz#1d831a3e25cd189eb256c17770a666368762bbce"
+
+d3-timer@1:
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.9.tgz#f7bb8c0d597d792ff7131e1c24a36dd471a471ba"
+
+d3-transition@1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-1.2.0.tgz#f538c0e21b2aa1f05f3e965f8567e81284b3b2b8"
+ dependencies:
+ d3-color "1"
+ d3-dispatch "1"
+ d3-ease "1"
+ d3-interpolate "1"
+ d3-selection "^1.1.0"
+ d3-timer "1"
+
+d3-voronoi@1:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/d3-voronoi/-/d3-voronoi-1.1.4.tgz#dd3c78d7653d2bb359284ae478645d95944c8297"
+
+d3-zoom@1:
+ version "1.8.3"
+ resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-1.8.3.tgz#b6a3dbe738c7763121cd05b8a7795ffe17f4fc0a"
+ dependencies:
+ d3-dispatch "1"
+ d3-drag "1"
+ d3-interpolate "1"
+ d3-selection "1"
+ d3-transition "1"
+
+d3@^5.12.0:
+ version "5.12.0"
+ resolved "https://registry.yarnpkg.com/d3/-/d3-5.12.0.tgz#0ddeac879c28c882317cd439b495290acd59ab61"
+ dependencies:
+ d3-array "1"
+ d3-axis "1"
+ d3-brush "1"
+ d3-chord "1"
+ d3-collection "1"
+ d3-color "1"
+ d3-contour "1"
+ d3-dispatch "1"
+ d3-drag "1"
+ d3-dsv "1"
+ d3-ease "1"
+ d3-fetch "1"
+ d3-force "1"
+ d3-format "1"
+ d3-geo "1"
+ d3-hierarchy "1"
+ d3-interpolate "1"
+ d3-path "1"
+ d3-polygon "1"
+ d3-quadtree "1"
+ d3-random "1"
+ d3-scale "2"
+ d3-scale-chromatic "1"
+ d3-selection "1"
+ d3-shape "1"
+ d3-time "1"
+ d3-time-format "2"
+ d3-timer "1"
+ d3-transition "1"
+ d3-voronoi "1"
+ d3-zoom "1"
+
d@1:
version "1.0.0"
resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"
@@ -2586,6 +2870,16 @@ dlv@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.1.tgz#c79d96bfe659a5568001250ed2aaf653992bdd3f"
+dnd-core@^9.3.4:
+ version "9.3.4"
+ resolved "https://registry.yarnpkg.com/dnd-core/-/dnd-core-9.3.4.tgz#56b5fdc165aa7d102506d3d5a08ec1fa789e0775"
+ dependencies:
+ "@types/asap" "^2.0.0"
+ "@types/invariant" "^2.2.30"
+ asap "^2.0.6"
+ invariant "^2.2.4"
+ redux "^4.0.1"
+
dns-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d"
@@ -3842,6 +4136,12 @@ hoist-non-react-statics@^2.3.0:
version "2.3.1"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.3.1.tgz#343db84c6018c650778898240135a1420ee22ce0"
+hoist-non-react-statics@^3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b"
+ dependencies:
+ react-is "^16.7.0"
+
hosted-git-info@^2.1.4:
version "2.7.1"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047"
@@ -3931,6 +4231,12 @@ https-browserify@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
+iconv-lite@0.4:
+ version "0.4.24"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3"
+
iconv-lite@0.4.19, iconv-lite@^0.4.17, iconv-lite@~0.4.13:
version "0.4.19"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
@@ -3995,10 +4301,15 @@ indent-string@^2.1.0:
dependencies:
repeating "^2.0.0"
-indent-string@^3.0.0, indent-string@^3.1.0, indent-string@^3.2.0:
+indent-string@^3.1.0, indent-string@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289"
+indent-string@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
+ integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
+
indexes-of@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
@@ -4481,19 +4792,6 @@ jest-docblock@^24.3.0:
dependencies:
detect-newline "^2.1.0"
-jest-dom@^3.5.0:
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/jest-dom/-/jest-dom-3.5.0.tgz#715908b545c0d66a0eba9d21fc59357fac024f43"
- dependencies:
- chalk "^2.4.1"
- css "^2.2.3"
- css.escape "^1.5.1"
- jest-diff "^24.0.0"
- jest-matcher-utils "^24.0.0"
- lodash "^4.17.11"
- pretty-format "^24.0.0"
- redent "^2.0.0"
-
jest-each@^24.8.0:
version "24.8.0"
resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-24.8.0.tgz#a05fd2bf94ddc0b1da66c6d13ec2457f35e52775"
@@ -5325,6 +5623,11 @@ mimic-fn@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
+min-indent@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.0.tgz#cfc45c37e9ec0d8f0a0ec3dd4ef7f7c3abe39256"
+ integrity sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY=
+
minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
@@ -6738,19 +7041,40 @@ rc@^1.2.7:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
-react-dom@^16.2.0:
- version "16.4.1"
- resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.4.1.tgz#7f8b0223b3a5fbe205116c56deb85de32685dad6"
+react-dnd-html5-backend@^9.3.4:
+ version "9.3.4"
+ resolved "https://registry.yarnpkg.com/react-dnd-html5-backend/-/react-dnd-html5-backend-9.3.4.tgz#5d1f5ac608206d7b294b7407b9e1a336589eedd7"
+ dependencies:
+ dnd-core "^9.3.4"
+
+react-dnd@^9.3.4:
+ version "9.3.4"
+ resolved "https://registry.yarnpkg.com/react-dnd/-/react-dnd-9.3.4.tgz#ebab4b5b430b72f3580c058a29298054e1f9d2b8"
+ dependencies:
+ "@types/hoist-non-react-statics" "^3.3.1"
+ "@types/shallowequal" "^1.1.1"
+ dnd-core "^9.3.4"
+ hoist-non-react-statics "^3.3.0"
+ shallowequal "^1.1.0"
+
+react-dom@^16.10.2:
+ version "16.11.0"
+ resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.11.0.tgz#7e7c4a5a85a569d565c2462f5d345da2dd849af5"
+ integrity sha512-nrRyIUE1e7j8PaXSPtyRKtz+2y9ubW/ghNgqKFHHAHaeP0fpF5uXR+sq8IMRHC+ZUxw7W9NyCDTBtwWxvkb0iA==
dependencies:
- fbjs "^0.8.16"
loose-envify "^1.1.0"
object-assign "^4.1.1"
- prop-types "^15.6.0"
+ prop-types "^15.6.2"
+ scheduler "^0.17.0"
react-is@^16.4.1:
version "16.4.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.4.1.tgz#d624c4650d2c65dbd52c72622bbf389435d9776e"
+react-is@^16.7.0:
+ version "16.9.0"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.9.0.tgz#21ca9561399aad0ff1a7701c01683e8ca981edcb"
+
react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6:
version "16.8.6"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16"
@@ -6794,14 +7118,14 @@ react-testing-library@^6.0.3:
"@babel/runtime" "^7.4.2"
dom-testing-library "^3.18.2"
-react@^16.2.0:
- version "16.4.1"
- resolved "https://registry.yarnpkg.com/react/-/react-16.4.1.tgz#de51ba5764b5dbcd1f9079037b862bd26b82fe32"
+react@^16.10.2:
+ version "16.11.0"
+ resolved "https://registry.yarnpkg.com/react/-/react-16.11.0.tgz#d294545fe62299ccee83363599bf904e4a07fdbb"
+ integrity sha512-M5Y8yITaLmU0ynd0r1Yvfq98Rmll6q8AxaEe88c8e7LxO8fZ2cNgmFt0aGAS9wzf1Ao32NKXtCl+/tVVtkxq6g==
dependencies:
- fbjs "^0.8.16"
loose-envify "^1.1.0"
object-assign "^4.1.1"
- prop-types "^15.6.0"
+ prop-types "^15.6.2"
read-pkg-up@^1.0.1:
version "1.0.1"
@@ -6887,12 +7211,13 @@ redent@^1.0.0:
indent-string "^2.1.0"
strip-indent "^1.0.1"
-redent@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa"
+redent@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f"
+ integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==
dependencies:
- indent-string "^3.0.0"
- strip-indent "^2.0.0"
+ indent-string "^4.0.0"
+ strip-indent "^3.0.0"
reduce-css-calc@^1.2.6:
version "1.3.0"
@@ -6908,6 +7233,13 @@ reduce-function-call@^1.0.1:
dependencies:
balanced-match "^0.4.2"
+redux@^4.0.1:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.4.tgz#4ee1aeb164b63d6a1bcc57ae4aa0b6e6fa7a3796"
+ dependencies:
+ loose-envify "^1.4.0"
+ symbol-observable "^1.2.0"
+
reflect.ownkeys@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz#749aceec7f3fdf8b63f927a04809e90c5c0b3460"
@@ -7194,6 +7526,10 @@ run-queue@^1.0.0, run-queue@^1.0.3:
dependencies:
aproba "^1.1.1"
+rw@1:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
+
rx-lite-aggregates@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be"
@@ -7271,6 +7607,14 @@ sax@^1.2.1, sax@^1.2.4, sax@~1.2.1:
version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
+scheduler@^0.17.0:
+ version "0.17.0"
+ resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.17.0.tgz#7c9c673e4ec781fac853927916d1c426b6f3ddfe"
+ integrity sha512-7rro8Io3tnCPuY4la/NuI5F2yfESpnfZyT6TtkXnSWVkcu0BCDJ+8gk5ozUaFaxpIyNuWAPXrH0yFcSi28fnDA==
+ dependencies:
+ loose-envify "^1.1.0"
+ object-assign "^4.1.1"
+
schema-utils@^0.4.4, schema-utils@^0.4.5:
version "0.4.5"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.5.tgz#21836f0608aac17b78f9e3e24daff14a5ca13a3e"
@@ -7411,6 +7755,10 @@ shallow-clone@^1.0.0:
kind-of "^5.0.0"
mixin-object "^2.0.1"
+shallowequal@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
+
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
@@ -7766,9 +8114,12 @@ strip-indent@^1.0.1:
dependencies:
get-stdin "^4.0.1"
-strip-indent@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68"
+strip-indent@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001"
+ integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==
+ dependencies:
+ min-indent "^1.0.0"
strip-json-comments@~2.0.1:
version "2.0.1"
@@ -7830,6 +8181,10 @@ symbol-observable@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4"
+symbol-observable@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
+
symbol-tree@^3.2.1:
version "3.2.2"
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"