react-timelane 0.0.0 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/dist/components/Timelane.d.ts +15 -0
  2. package/dist/components/TimelaneAside.d.ts +13 -0
  3. package/dist/components/TimelaneBackground.d.ts +5 -0
  4. package/dist/components/TimelaneBody.d.ts +6 -0
  5. package/dist/components/TimelaneBodyInner.d.ts +16 -0
  6. package/dist/components/TimelaneHeader/DaysHeader.d.ts +15 -0
  7. package/dist/components/TimelaneHeader/MonthsHeader.d.ts +15 -0
  8. package/dist/components/TimelaneHeader/TimelaneHeader.d.ts +24 -0
  9. package/dist/components/TimelaneHeader/WeeksHeader.d.ts +15 -0
  10. package/dist/components/TimelaneHeader/index.d.ts +5 -0
  11. package/dist/components/TimelaneHeader/renderingUtils.d.ts +4 -0
  12. package/dist/components/TimelaneSelectionLayer.d.ts +6 -0
  13. package/dist/components/TimelaneSettingsContext.d.ts +7 -0
  14. package/dist/components/TimelaneSettingsProvider.d.ts +7 -0
  15. package/dist/components/TimelaneWrapper.d.ts +20 -0
  16. package/dist/components/core/CoreItem/CoreItemComponent.d.ts +14 -0
  17. package/dist/components/core/CoreItem/DragResizeComponent.d.ts +20 -0
  18. package/dist/components/core/CoreSwimlane/AvailableSpaceIndicator.d.ts +21 -0
  19. package/dist/components/core/CoreSwimlane/CoreSwimlane.d.ts +16 -0
  20. package/dist/components/core/CoreSwimlane/DropPreview.d.ts +9 -0
  21. package/dist/components/core/CoreSwimlane/DropTarget.d.ts +11 -0
  22. package/dist/components/core/CoreSwimlane/OverlapIndicator.d.ts +6 -0
  23. package/dist/components/core/CoreSwimlane/utils.d.ts +13 -0
  24. package/dist/components/core/utils.d.ts +15 -0
  25. package/dist/components/layout/TimelaneLayout.d.ts +23 -0
  26. package/dist/hooks/useScroll.d.ts +10 -0
  27. package/dist/hooks/useTimelaneContext.d.ts +1 -0
  28. package/dist/index.d.ts +13 -0
  29. package/dist/react-timelane.css +1 -0
  30. package/dist/react-timelane.js +4701 -0
  31. package/dist/types/AvailableSpace.d.ts +6 -0
  32. package/dist/types/CoreItem.d.ts +12 -0
  33. package/dist/types/DateBounds.d.ts +4 -0
  34. package/dist/types/Dimensions.d.ts +4 -0
  35. package/dist/types/GrabInfo.d.ts +5 -0
  36. package/dist/types/Grid.d.ts +6 -0
  37. package/dist/types/OffsetBounds.d.ts +4 -0
  38. package/dist/types/Pixels.d.ts +4 -0
  39. package/{src/types/Position.ts → dist/types/Position.d.ts} +2 -2
  40. package/dist/types/Rectangle.d.ts +6 -0
  41. package/dist/types/SwimlaneT.d.ts +5 -0
  42. package/dist/types/TimeRange.d.ts +4 -0
  43. package/dist/types/TimelaneSettings.d.ts +11 -0
  44. package/dist/types/index.d.ts +15 -0
  45. package/package.json +1 -1
  46. package/vite.config.ts +2 -2
  47. package/.github/workflows/static.yml +0 -55
  48. package/docs/README.md +0 -54
  49. package/docs/eslint.config.js +0 -28
  50. package/docs/index.html +0 -12
  51. package/docs/package-lock.json +0 -5101
  52. package/docs/package.json +0 -35
  53. package/docs/src/App.css +0 -5
  54. package/docs/src/App.tsx +0 -59
  55. package/docs/src/assets/react.svg +0 -1
  56. package/docs/src/components/AllocationComponent.tsx +0 -82
  57. package/docs/src/components/Timeline.tsx +0 -183
  58. package/docs/src/constants.ts +0 -42
  59. package/docs/src/hooks/useLocalStorage.ts +0 -21
  60. package/docs/src/main.tsx +0 -9
  61. package/docs/src/models/Allocation.ts +0 -11
  62. package/docs/src/models/AllocationId.ts +0 -1
  63. package/docs/src/models/Resource.ts +0 -8
  64. package/docs/src/models/ResourceId.ts +0 -1
  65. package/docs/src/vite-env.d.ts +0 -1
  66. package/docs/tsconfig.json +0 -27
  67. package/docs/vite.config.ts +0 -8
  68. package/src/components/Timeline.scss +0 -297
  69. package/src/components/TimelineAside.tsx +0 -81
  70. package/src/components/TimelineBackground.tsx +0 -53
  71. package/src/components/TimelineBody.tsx +0 -54
  72. package/src/components/TimelineHeader/DaysHeader.tsx +0 -44
  73. package/src/components/TimelineHeader/MonthsHeader.tsx +0 -62
  74. package/src/components/TimelineHeader/TimelineHeader.tsx +0 -64
  75. package/src/components/TimelineHeader/WeeksHeader.tsx +0 -63
  76. package/src/components/TimelineHeader/index.ts +0 -9
  77. package/src/components/TimelineHeader/renderingUtils.tsx +0 -57
  78. package/src/components/TimelineSelectionLayer.tsx +0 -179
  79. package/src/components/TimelineSettingsContext.tsx +0 -27
  80. package/src/components/TimelineSettingsProvider.tsx +0 -24
  81. package/src/components/TimelineWrapper.tsx +0 -51
  82. package/src/components/core/CoreItem/CoreItemComponent.tsx +0 -69
  83. package/src/components/core/CoreItem/DragResizeComponent.tsx +0 -180
  84. package/src/components/core/CoreSwimlane/AvailableSpaceIndicator.tsx +0 -156
  85. package/src/components/core/CoreSwimlane/CoreSwimlane.tsx +0 -245
  86. package/src/components/core/CoreSwimlane/DropPreview.tsx +0 -30
  87. package/src/components/core/CoreSwimlane/DropTarget.tsx +0 -83
  88. package/src/components/core/CoreSwimlane/OverlapIndicator.tsx +0 -22
  89. package/src/components/core/CoreSwimlane/utils.ts +0 -375
  90. package/src/components/core/utils.ts +0 -154
  91. package/src/components/layout/TimelineLayout.tsx +0 -93
  92. package/src/components/layout/layout.scss +0 -107
  93. package/src/global.d.ts +0 -9
  94. package/src/hooks/useScroll.tsx +0 -71
  95. package/src/hooks/useTimelineContext.tsx +0 -6
  96. package/src/index.ts +0 -15
  97. package/src/types/AvailableSpace.ts +0 -6
  98. package/src/types/CoreItem.ts +0 -23
  99. package/src/types/DateBounds.ts +0 -4
  100. package/src/types/Dimensions.ts +0 -4
  101. package/src/types/GrabInfo.ts +0 -6
  102. package/src/types/Grid.ts +0 -6
  103. package/src/types/OffsetBounds.ts +0 -4
  104. package/src/types/Pixels.ts +0 -4
  105. package/src/types/Rectangle.ts +0 -6
  106. package/src/types/SwimlaneT.ts +0 -6
  107. package/src/types/TimeRange.ts +0 -4
  108. package/src/types/TimelineSettings.ts +0 -11
  109. package/src/types/index.ts +0 -15
  110. package/tsconfig.json +0 -32
  111. /package/{src/types/ItemId.ts → dist/types/ItemId.d.ts} +0 -0
  112. /package/{src/types/SwimlaneId.ts → dist/types/SwimlaneId.d.ts} +0 -0
@@ -1,63 +0,0 @@
1
- import { MouseEvent, ReactElement } from "react";
2
- import { Pixels, TimeRange } from "../../types";
3
- import {
4
- differenceInCalendarDays,
5
- eachWeekOfInterval,
6
- isSunday,
7
- nextSunday,
8
- } from "date-fns";
9
- import { renderWeekHeader } from "./renderingUtils";
10
-
11
- interface WeeksHeaderProps {
12
- range: TimeRange;
13
- pixels: Pixels;
14
- setFocusedDay?: (day: Date | null) => void;
15
- render?: (firstDay: Date, lastDay: Date) => ReactElement;
16
- onWeekClick?: (params: {
17
- firstDay: Date;
18
- lastDay: Date;
19
- e: MouseEvent;
20
- }) => void;
21
- }
22
-
23
- export function WeeksHeader({
24
- range,
25
- pixels,
26
- setFocusedDay = () => {},
27
- render = renderWeekHeader,
28
- onWeekClick = () => undefined,
29
- }: WeeksHeaderProps) {
30
- return (
31
- <div className="timeline-header-weeks">
32
- {eachWeekOfInterval(range, { weekStartsOn: 1 }).map((firstDay, index) => {
33
- if (firstDay < range.start) {
34
- firstDay = range.start;
35
- }
36
-
37
- let lastDay = isSunday(firstDay) ? firstDay : nextSunday(firstDay);
38
-
39
- if (lastDay > range.end) {
40
- lastDay = range.end;
41
- }
42
-
43
- const numberOfDays = differenceInCalendarDays(lastDay, firstDay) + 1;
44
-
45
- return (
46
- <div
47
- key={index}
48
- className="timeline-header-week-label"
49
- style={{
50
- width: `${pixels.pixelsPerDay * numberOfDays}px`,
51
- }}
52
- onClick={(e) => {
53
- onWeekClick({ firstDay, lastDay, e });
54
- setFocusedDay(firstDay);
55
- }}
56
- >
57
- {render(firstDay, lastDay)}
58
- </div>
59
- );
60
- })}
61
- </div>
62
- );
63
- }
@@ -1,9 +0,0 @@
1
- export { DaysHeader } from "./DaysHeader";
2
- export { WeeksHeader } from "./WeeksHeader";
3
- export { MonthsHeader } from "./MonthsHeader";
4
- export { TimelineHeader } from "./TimelineHeader";
5
- export {
6
- renderDayHeader,
7
- renderMonthHeader,
8
- renderWeekHeader,
9
- } from "./renderingUtils";
@@ -1,57 +0,0 @@
1
- import { differenceInCalendarDays, format } from "date-fns";
2
- import { ReactElement } from "react";
3
-
4
- export function renderMonthHeader(firstDay: Date, lastDay: Date): ReactElement {
5
- const numberOfDays = differenceInCalendarDays(lastDay, firstDay) + 1;
6
-
7
- return <>{numberOfDays > 4 ? format(firstDay, "LLLL yyyy") : <></>}</>;
8
- }
9
-
10
- export function renderWeekHeader(firstDay: Date, lastDay: Date): ReactElement {
11
- const numberOfDays = differenceInCalendarDays(lastDay, firstDay) + 1;
12
-
13
- const title = `KW ${format(firstDay, "w")} (${format(
14
- firstDay,
15
- "MM-dd"
16
- )} - ${format(lastDay, "MM-dd")}`;
17
-
18
- return (
19
- <div title={title}>
20
- {numberOfDays > 2 ? <>KW {format(firstDay, "w")}</> : <></>}
21
- </div>
22
- );
23
- // return (
24
- // <Tooltip
25
- // arrow
26
- // title={
27
- // <div className="timeline-header-tooltip timeline-header-week-tooltip">
28
- // KW {format(firstDay, "w")} ({format(firstDay, "MM-dd")} -{" "}
29
- // {format(lastDay, "MM-dd")}
30
- // </div>
31
- // }
32
- // disableInteractive
33
- // >
34
- // <div>{numberOfDays > 2 ? <>KW {format(firstDay, "w")}</> : <></>}</div>
35
- // </Tooltip>
36
- // );
37
- }
38
-
39
- export function renderDayHeader(day: Date): ReactElement {
40
- const title = `${format(day, "yyyy-MM-dd")}`;
41
-
42
- return <div title={title}>{format(day, "d")}</div>;
43
-
44
- // return (
45
- // <Tooltip
46
- // arrow
47
- // title={
48
- // <div className="timeline-header-tooltip timeline-header-day-tooltip">
49
- // {format(day, "yyyy-MM-dd")}
50
- // </div>
51
- // }
52
- // disableInteractive
53
- // >
54
- // <div>{format(day, "d")}</div>
55
- // </Tooltip>
56
- // );
57
- }
@@ -1,179 +0,0 @@
1
- import { PropsWithChildren, useEffect, useRef, useState } from "react";
2
- import { ItemId, Rectangle } from "../types";
3
- import { doOverlap } from "./core/CoreSwimlane/utils";
4
- import { MouseEvent } from "react";
5
- import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
6
-
7
- interface TimelineSelectionLayerProps {
8
- onSelect: (selection: number[]) => void;
9
- }
10
-
11
- export function TimelineSelectionLayer({
12
- children,
13
- onSelect,
14
- }: PropsWithChildren<TimelineSelectionLayerProps>) {
15
- const [selectedItemIds, setSelectedItemIds] = useState<ItemId[]>([]);
16
-
17
- const callbackRef = useRef<EventListener | null>(null);
18
-
19
- const [mouseDownPos, setMouseDownPos] = useState<{
20
- x: number;
21
- y: number;
22
- } | null>(null);
23
-
24
- const [selectionRect, setSelectionRect] = useState<{
25
- x: number;
26
- y: number;
27
- width: number;
28
- height: number;
29
- } | null>(null);
30
-
31
- useEffect(() => {
32
- return monitorForElements({
33
- onDragStart: (args) => {
34
- setSelectedItemIds([args.source.data.id as number]);
35
- },
36
- });
37
- }, []);
38
-
39
- useEffect(() => {
40
- onSelect(selectedItemIds);
41
- }, [onSelect, selectedItemIds]);
42
-
43
- function handleMouseDown(e: MouseEvent) {
44
- if (!e.shiftKey && !e.ctrlKey) {
45
- setSelectedItemIds([]);
46
- }
47
- setMouseDownPos({ x: e.clientX, y: e.clientY });
48
- }
49
-
50
- function handleMouseMove(e: MouseEvent) {
51
- if (mouseDownPos) {
52
- const selectedRect = {
53
- x: Math.min(e.clientX, mouseDownPos.x),
54
- y: Math.min(e.clientY, mouseDownPos.y),
55
- width: Math.abs(e.clientX - mouseDownPos.x),
56
- height: Math.abs(e.clientY - mouseDownPos.y),
57
- };
58
-
59
- const rect = e.currentTarget.getBoundingClientRect();
60
- setSelectionRect({
61
- ...selectedRect,
62
- x: selectedRect.x - rect.left,
63
- y: selectedRect.y - rect.top,
64
- });
65
-
66
- document.querySelectorAll(".timeline-drop-target").forEach((row) => {
67
- if (doOverlap(row.getBoundingClientRect(), selectedRect)) {
68
- row.querySelectorAll(".timeline-item").forEach((item) => {
69
- if (doOverlap(item.getBoundingClientRect(), selectedRect)) {
70
- item.classList.add("timeline-item-marked");
71
- } else {
72
- item.classList.remove("timeline-item-marked");
73
- }
74
- });
75
- }
76
- });
77
-
78
- if (
79
- (selectedRect.width > 5 || selectedRect.height > 5) &&
80
- !callbackRef.current
81
- ) {
82
- callbackRef.current = captureClick;
83
- window.addEventListener("click", captureClick, true);
84
- }
85
- }
86
- }
87
-
88
- function handleMouseUp(e: MouseEvent) {
89
- if (mouseDownPos && selectionRect) {
90
- e.stopPropagation();
91
- const selectedRect = {
92
- x: Math.min(e.clientX, mouseDownPos.x),
93
- y: Math.min(e.clientY, mouseDownPos.y),
94
- width: Math.abs(e.clientX - mouseDownPos.x),
95
- height: Math.abs(e.clientY - mouseDownPos.y),
96
- };
97
-
98
- const ids: ItemId[] = Array.from(
99
- document.querySelectorAll(".timeline-drop-target")
100
- )
101
- .filter((row) => doOverlap(row.getBoundingClientRect(), selectedRect))
102
- .map((row) => Array.from(row.querySelectorAll(".timeline-item")))
103
- .flatMap((elements) => elements)
104
- .filter((el) => doOverlap(el.getBoundingClientRect(), selectedRect))
105
- .map((el) => {
106
- if (el instanceof HTMLElement) {
107
- return Number.parseInt(el.dataset.timelineItemId || "-1");
108
- } else {
109
- return -1;
110
- }
111
- })
112
- .filter((id) => id > 0);
113
-
114
- if (ids.length > 0) {
115
- if (e.shiftKey || e.ctrlKey) {
116
- setSelectedItemIds((prev) => {
117
- return Array.from(new Set([...prev, ...ids]));
118
- });
119
- } else {
120
- setSelectedItemIds(ids);
121
- }
122
- }
123
-
124
- document.querySelectorAll(".timeline-item-marked").forEach((el) => {
125
- el.classList.remove("timeline-item-marked");
126
- });
127
- }
128
-
129
- setMouseDownPos(null);
130
- setSelectionRect(null);
131
-
132
- requestAnimationFrame(() => {
133
- if (callbackRef.current && callbackRef.current !== null) {
134
- window.removeEventListener("click", callbackRef.current, true);
135
- callbackRef.current = null;
136
- }
137
- });
138
- }
139
-
140
- return (
141
- <div
142
- onMouseDown={handleMouseDown}
143
- onMouseMove={handleMouseMove}
144
- onMouseUp={handleMouseUp}
145
- style={{
146
- position: "relative",
147
- }}
148
- >
149
- {selectionRect && <MouseSelectionIndicator rect={selectionRect} />}
150
- {children}
151
- </div>
152
- );
153
- }
154
-
155
- const captureClick = (e: any) => {
156
- e.preventDefault();
157
- e.stopPropagation();
158
- };
159
-
160
- interface MouseSelectionIndicatorProps {
161
- rect: Rectangle;
162
- }
163
-
164
- function MouseSelectionIndicator({ rect }: MouseSelectionIndicatorProps) {
165
- return (
166
- <div
167
- id="mouse-selection-indicator"
168
- style={{
169
- border: "1px dashed blue",
170
- position: "absolute",
171
- top: `${rect.y}px`,
172
- left: `${rect.x}px`,
173
- width: `${rect.width}px`,
174
- height: `${rect.height}px`,
175
- zIndex: 1000000,
176
- }}
177
- ></div>
178
- );
179
- }
@@ -1,27 +0,0 @@
1
- import { createContext, Dispatch, SetStateAction } from "react";
2
- import { TimelineSettings } from "../types/TimelineSettings";
3
-
4
- const defaultTimelineSettings: TimelineSettings = {
5
- start: new Date(2025, 1, 1),
6
- end: new Date(2025, 5, 1),
7
- pixelsPerDay: 30,
8
- pixelsPerResource: 100,
9
- showMonths: true,
10
- showWeeks: true,
11
- showDays: true,
12
- allowOverlaps: true,
13
- focusedDate: null,
14
- };
15
-
16
- export interface TimelineContextOuter {
17
- settings: TimelineSettings;
18
- setSettings: Dispatch<SetStateAction<TimelineSettings>>;
19
- }
20
-
21
- const defaultContext: TimelineContextOuter = {
22
- settings: defaultTimelineSettings,
23
- setSettings: () => undefined,
24
- };
25
-
26
- export const TimelineSettingsContext =
27
- createContext<TimelineContextOuter>(defaultContext);
@@ -1,24 +0,0 @@
1
- import { PropsWithChildren, useEffect, useState } from "react";
2
- import { TimelineSettings } from "../types/TimelineSettings";
3
- import { TimelineSettingsContext } from "./TimelineSettingsContext";
4
-
5
- interface TimelineSettingsProviderProps {
6
- settings: TimelineSettings;
7
- }
8
-
9
- export const TimelineSettingsProvider = ({
10
- settings: _settings,
11
- children,
12
- }: PropsWithChildren<TimelineSettingsProviderProps>) => {
13
- const [settings, setSettings] = useState<TimelineSettings>(_settings);
14
-
15
- useEffect(() => {
16
- setSettings((prev) => ({ ...prev, _settings }));
17
- }, [_settings]);
18
-
19
- return (
20
- <TimelineSettingsContext.Provider value={{ settings, setSettings }}>
21
- {children}
22
- </TimelineSettingsContext.Provider>
23
- );
24
- };
@@ -1,51 +0,0 @@
1
- import { PropsWithChildren } from "react";
2
- import { TimelineSettingsProvider } from "./TimelineSettingsProvider";
3
- import { SwimlaneT } from "../types";
4
- import "./Timeline.scss";
5
-
6
- interface TimelineWrapperProps {
7
- focusedDay?: Date | null;
8
- focusedSwimlane?: SwimlaneT | null;
9
- start?: Date;
10
- end?: Date;
11
- pixelsPerDay?: number;
12
- pixelsPerResource?: number;
13
- showMonths?: boolean;
14
- showWeeks?: boolean;
15
- showDays?: boolean;
16
- allowOverlaps?: boolean;
17
- focusedDate?: Date | null;
18
- }
19
-
20
- export default function TimelineWrapper({
21
- children,
22
- start = new Date(2025, 1, 1),
23
- end = new Date(2025, 5, 1),
24
- pixelsPerDay = 30,
25
- pixelsPerResource = 100,
26
- showMonths = true,
27
- showWeeks = true,
28
- showDays = true,
29
- allowOverlaps = true,
30
- focusedDate = null,
31
- }: PropsWithChildren<TimelineWrapperProps>) {
32
- return (
33
- <div className="timeline">
34
- <TimelineSettingsProvider
35
- settings={{
36
- start,
37
- end,
38
- pixelsPerDay,
39
- pixelsPerResource,
40
- showDays,
41
- showMonths,
42
- showWeeks,
43
- allowOverlaps,
44
- focusedDate,
45
- }}
46
- >
47
- {children}
48
- </TimelineSettingsProvider>
49
- </div>
50
- );
51
- }
@@ -1,69 +0,0 @@
1
- import DragResizeComponent from "./DragResizeComponent";
2
- import {
3
- getDropTargetDimensions,
4
- getItemRectangle as getItemRectangle,
5
- getUpdatedItem as getUpdatedItem,
6
- } from "../utils";
7
- import { PropsWithChildren } from "react";
8
- import {
9
- CoreItem,
10
- Position,
11
- Rectangle,
12
- SwimlaneT,
13
- TimelineSettings,
14
- } from "../../../types";
15
-
16
- interface CoreItemComponentProps<T> {
17
- item: CoreItem<T>;
18
- swimlane: SwimlaneT;
19
- settings: TimelineSettings;
20
- onDragStart: (grabPosition: Position, relativeGrabPosition: Position) => void;
21
- onDrop: () => void;
22
- onDrag: () => void;
23
- onUpdate: (updatedItem: CoreItem<T>) => void;
24
- onResizeStart: () => void;
25
- }
26
-
27
- export default function CoreItemComponent<T>({
28
- swimlane,
29
- item,
30
- settings,
31
- children,
32
- onDragStart,
33
- onDrag,
34
- onDrop,
35
- onUpdate,
36
- onResizeStart,
37
- }: PropsWithChildren<CoreItemComponentProps<T>>) {
38
- const rectangle = getItemRectangle(item, swimlane, settings, settings);
39
- const boundingRectangle = getDropTargetDimensions(
40
- swimlane,
41
- settings,
42
- settings
43
- );
44
-
45
- return (
46
- <DragResizeComponent<T>
47
- item={item}
48
- rectangle={rectangle}
49
- boundingRectangle={boundingRectangle}
50
- onDrag={onDrag}
51
- onDragStart={onDragStart}
52
- onDrop={onDrop}
53
- onUpdate={(rectangle: Rectangle) => {
54
- const updatedItem: CoreItem<T> = getUpdatedItem(
55
- item,
56
- swimlane,
57
- rectangle,
58
- settings,
59
- settings
60
- );
61
-
62
- onUpdate(updatedItem);
63
- }}
64
- onResizeStart={onResizeStart}
65
- >
66
- {children}
67
- </DragResizeComponent>
68
- );
69
- }
@@ -1,180 +0,0 @@
1
- import { PropsWithChildren, useEffect, useRef, useState } from "react";
2
- import invariant from "tiny-invariant";
3
- import { draggable } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
4
- import { getGrabPosition } from "../utils";
5
- import { Resizable } from "re-resizable";
6
- import { Position, Rectangle, Dimensions, CoreItem } from "../../../types";
7
-
8
- interface DragResizeComponentProps<T> {
9
- item: CoreItem<T>;
10
- rectangle: Rectangle;
11
- boundingRectangle: Dimensions;
12
- onDragStart: (grabPosition: Position, relativeGrabPosition: Position) => void;
13
- onDrag: () => void;
14
- onDrop: () => void;
15
- onUpdate: (rectangle: Rectangle) => void;
16
- onResizeStart: () => void;
17
- }
18
-
19
- /**
20
- * takes care of pixel-level drag-and-drop and resizing.
21
- * will emit every event through event handlers.
22
- * @param param0 t
23
- * @returns
24
- */
25
- export default function DragResizeComponent<T>({
26
- item,
27
- rectangle,
28
- boundingRectangle,
29
- children,
30
- onDrag,
31
- onDragStart,
32
- onDrop,
33
- onUpdate,
34
- onResizeStart,
35
- }: PropsWithChildren<DragResizeComponentProps<T>>) {
36
- const ref = useRef<HTMLDivElement>(null);
37
- const handleRef = useRef<HTMLDivElement>(null);
38
-
39
- const [tmpRectangle, setTmpRectangle] = useState<Rectangle>(rectangle);
40
-
41
- useEffect(() => {
42
- setTmpRectangle(rectangle);
43
- }, [rectangle]);
44
-
45
- useEffect(() => {
46
- invariant(ref.current);
47
- invariant(handleRef.current);
48
-
49
- return draggable({
50
- element: ref.current,
51
- dragHandle: handleRef.current,
52
- onDragStart: ({ source, location }) => {
53
- const grabPos = getGrabPosition(source, location);
54
- onDragStart(grabPos.absolute, grabPos.relative);
55
- },
56
- onDrag: () => {
57
- onDrag();
58
- },
59
-
60
- onDrop: () => {
61
- onDrop();
62
- },
63
- getInitialData: () => ({ ...item }),
64
- });
65
- }, [item, onDrag, onDragStart, onDrop]);
66
-
67
- return (
68
- <div
69
- id={`timeline-item-${item.id}`}
70
- className="timeline-item"
71
- data-timeline-item-id={item.id}
72
- ref={ref}
73
- style={{
74
- width: `${tmpRectangle.width}px`,
75
- height: `${tmpRectangle.height}px`,
76
- minWidth: `${tmpRectangle.width}px`,
77
- minHeight: `${tmpRectangle.height}px`,
78
- maxWidth: `${tmpRectangle.width}px`,
79
- maxHeight: `${tmpRectangle.height}px`,
80
- top: `${tmpRectangle.y}px`,
81
- left: `${tmpRectangle.x}px`,
82
- }}
83
- onMouseDown={(e) => {
84
- e.stopPropagation();
85
- }}
86
- onClick={(e) => {
87
- e.stopPropagation();
88
- }}
89
- >
90
- <Resizable
91
- enable={{
92
- right: true,
93
- left: true,
94
- top: true,
95
- bottom: true,
96
- }}
97
- handleClasses={{
98
- left: "timeline-item-resize-handle timeline-item-resize-handle-left",
99
- right:
100
- "timeline-item-resize-handle timeline-item-resize-handle-right",
101
- }}
102
- size={{
103
- width: tmpRectangle.width,
104
- height: tmpRectangle.height,
105
- }}
106
- onResizeStart={() => {
107
- onResizeStart();
108
- }}
109
- onResize={(e, direction, ref, d) => {
110
- setTmpRectangle((el) => {
111
- if (direction === "right") {
112
- return {
113
- ...el,
114
- width: rectangle.width + d.width,
115
- };
116
- } else if (direction === "left") {
117
- return {
118
- ...el,
119
- x: rectangle.x - d.width,
120
- width: rectangle.width + d.width,
121
- };
122
- } else if (direction === "bottom") {
123
- return {
124
- ...el,
125
- height: Math.min(
126
- rectangle.height + d.height,
127
- boundingRectangle.height - rectangle.y
128
- ),
129
- };
130
- } else if (direction === "top") {
131
- return {
132
- ...el,
133
- y: rectangle.y - d.height,
134
- height: rectangle.height + d.height,
135
- };
136
- } else {
137
- return el;
138
- }
139
- });
140
- }}
141
- onResizeStop={(_, direction, ref, d) => {
142
- let newRectangle = rectangle;
143
- if (direction === "right") {
144
- newRectangle = {
145
- ...rectangle,
146
- width: rectangle.width + d.width,
147
- };
148
- } else if (direction === "left") {
149
- newRectangle = {
150
- ...rectangle,
151
- x: rectangle.x - d.width,
152
- width: rectangle.width + d.width,
153
- };
154
- } else if (direction === "bottom") {
155
- newRectangle = {
156
- ...rectangle,
157
- height: Math.min(
158
- rectangle.height + d.height,
159
- boundingRectangle.height - rectangle.y
160
- ),
161
- };
162
- } else if (direction === "top") {
163
- newRectangle = {
164
- ...rectangle,
165
- y: rectangle.y - d.height,
166
- height: rectangle.height + d.height,
167
- };
168
- }
169
-
170
- onUpdate(newRectangle);
171
- }}
172
- style={{ overflow: "hidden" }}
173
- >
174
- <div className="timeline-item-drag-handle" ref={handleRef}>
175
- {children}
176
- </div>
177
- </Resizable>
178
- </div>
179
- );
180
- }