react-weekly-planning 1.0.43 → 1.0.45
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.
- package/README.md +36 -24
- package/dist/components/CalendarForWeek.js +1 -1
- package/dist/components/CalendarForday.js +6 -5
- package/dist/components/TaskContainer/TaskVirtual.js +3 -3
- package/dist/components/VirtualGroupCell.js +33 -0
- package/dist/components/VirtualGroupRow.js +6 -6
- package/dist/components/VirtualGroupRowDay.js +10 -10
- package/dist/components/index.js +1 -3
- package/dist/components/style.css +46 -3
- package/dist/contexts/CalendarTaskContext.js +1 -1
- package/dist/hooks/useCalendarDateState.js +3 -4
- package/dist/hooks/useCalendarDateStateForDay.js +19 -0
- package/dist/hooks/useCalendarTask.js +5 -1
- package/dist/hooks/useContainerScroll.js +87 -8
- package/dist/hooks/useGridContainer.js +10 -10
- package/dist/hooks/useIntersectionObserver.js +8 -2
- package/dist/index.js +1 -0
- package/dist/types/components/TaskContainer/TaskVirtual.d.ts +4 -1
- package/dist/types/components/VirtualGroupCell.d.ts +20 -0
- package/dist/types/components/VirtualGroupRowDay.d.ts +1 -0
- package/dist/types/components/index.d.ts +0 -1
- package/dist/types/definitions/index.d.ts +1 -3
- package/dist/types/hooks/useCalendarDateState.d.ts +13 -3
- package/dist/types/hooks/useCalendarDateStateForDay.d.ts +17 -0
- package/dist/types/hooks/useCalendarTask.d.ts +1 -0
- package/dist/types/hooks/useContainerScroll.d.ts +6 -2
- package/dist/types/hooks/useIntersectionObserver.d.ts +4 -1
- package/dist/types/index.d.ts +1 -0
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -54,27 +54,7 @@ It is possible to use either Weekoffset or Date, or even both simultaneously.
|
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
#### `scope`
|
|
58
57
|
|
|
59
|
-
- **Description**: This prop sets the view scope of the calendar.
|
|
60
|
-
- **Type**: `"day" | "week"`
|
|
61
|
-
- **Use Case**: Use this prop to define whether the calendar should display a full week or only a single day. If omitted, it defaults to a weekly view.
|
|
62
|
-
|
|
63
|
-
**Example**:
|
|
64
|
-
```jsx
|
|
65
|
-
<Calendar scope="day" dayOffset={0} ... />
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
#### `dayOffset`
|
|
69
|
-
|
|
70
|
-
- **Description**: This prop specifies which day of the week to display when the scope is set to "day".
|
|
71
|
-
- **Type**: `0 | 1 | 2 | 3 | 4 | 5 | 6`
|
|
72
|
-
- **Use Case**: If `scope="day"`, use this prop to target a specific day of the week (`0` being the first day of the week, up to `6`).
|
|
73
|
-
|
|
74
|
-
**Example**:
|
|
75
|
-
```jsx
|
|
76
|
-
<Calendar scope="day" dayOffset={2} ... />
|
|
77
|
-
```
|
|
78
58
|
|
|
79
59
|
|
|
80
60
|
---
|
|
@@ -106,7 +86,6 @@ const App = () => {
|
|
|
106
86
|
date={date}
|
|
107
87
|
weekOffset={0}
|
|
108
88
|
groups={groups}
|
|
109
|
-
scope="week"
|
|
110
89
|
/>
|
|
111
90
|
</div>
|
|
112
91
|
</CalendarTaskContextProvider>
|
|
@@ -126,8 +105,6 @@ Props for the Calendar component.
|
|
|
126
105
|
| Prop Name | Type | Description |
|
|
127
106
|
|------------------------------|---------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------|
|
|
128
107
|
| `weekOffset` | number | Offset for the week (e.g., -7 for last week, 0 for current week, 7 for next week). |
|
|
129
|
-
| `scope` | "day" \| "week" | Sets the calendar view to either a full week or a single day. |
|
|
130
|
-
| `dayOffset` | 0 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6 | Offset index for the day column (0 = first day of week, …, 6 = last day) when scope is "day". |
|
|
131
108
|
| `groups` | GroupFeildsType[] | Array of group data to be displayed in the calendar. |
|
|
132
109
|
| `className` | string | Additional class names for the calendar component. |
|
|
133
110
|
| `style` | React.CSSProperties \| undefined | Additional styles for the calendar component. |
|
|
@@ -300,7 +277,7 @@ const App = () => (
|
|
|
300
277
|
|
|
301
278
|
### 2. Default Behavior of `<Calendar />`
|
|
302
279
|
|
|
303
|
-
It's important to note that the main `<Calendar />` component uses the `"
|
|
280
|
+
It's important to note that the main `<Calendar />` component uses the `"day"` hash scope by default. If you use the standard component, you are implicitly using this scope. Explicitly defining a `hashScope` on the `CalendarTaskContextProvider` is only necessary when you want to change how tasks are indexed or when building a fully custom UI as shown above.
|
|
304
281
|
|
|
305
282
|
### 3. Understanding Hashes and Scopes
|
|
306
283
|
|
|
@@ -488,4 +465,39 @@ to create an organization that truly reflects you.
|
|
|
488
465
|
};
|
|
489
466
|
```
|
|
490
467
|
|
|
468
|
+
### `useIntersectionObserver`
|
|
469
|
+
|
|
470
|
+
- **Description**: Utility hook designed to help virtualize scrolling components. It leverages the Intersection Observer API to detect when an element enters or leaves the viewport, allowing you to mount or unmount heavy DOM elements dynamically for better performance in long lists or large grids.
|
|
471
|
+
👉 **Watch the performance demo (rendering 7,000 tasks in a single week):**
|
|
472
|
+
[](https://youtu.be/st4QmsaHoDM)
|
|
473
|
+
- **Parameters**:
|
|
474
|
+
- `ref` (React.RefObject): The ref assigned to the DOM element you want to observe.
|
|
475
|
+
- `options` (IntersectionObserverInit, optional): Configuration object (e.g., `rootMargin`, `threshold`).
|
|
476
|
+
- **Returns**: An object containing `{ entry, height }`. `entry` is the `IntersectionObserverEntry` which can be used to check `isIntersecting`. `height` provides the element's cached height when it is unmounted to maintain scroll position consistency.
|
|
477
|
+
|
|
478
|
+
**Example**:
|
|
479
|
+
```tsx
|
|
480
|
+
import React, { useRef } from "react";
|
|
481
|
+
import { useIntersectionObserver } from "react-pweekly-planning";
|
|
482
|
+
|
|
483
|
+
const VirtualItem = ({ children }) => {
|
|
484
|
+
const ref = useRef(null);
|
|
485
|
+
const { entry, height } = useIntersectionObserver(ref, {
|
|
486
|
+
rootMargin: "600px",
|
|
487
|
+
threshold: 0
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
const isVisible = !!entry?.isIntersecting;
|
|
491
|
+
|
|
492
|
+
return (
|
|
493
|
+
<div
|
|
494
|
+
ref={ref}
|
|
495
|
+
style={{ minHeight: isVisible ? "auto" : `${height}px` }}
|
|
496
|
+
>
|
|
497
|
+
{isVisible ? children : null}
|
|
498
|
+
</div>
|
|
499
|
+
);
|
|
500
|
+
};
|
|
501
|
+
```
|
|
502
|
+
|
|
491
503
|
---
|
|
@@ -13,7 +13,7 @@ const CalendarForWeek = (props) => {
|
|
|
13
13
|
const { dailyHours, weekDays } = useCalendarDateState(props.date, props.weekOffset, props.timeZone);
|
|
14
14
|
const memoizedHeader = useMemo(() => (_jsx("div", { className: "planningCalendarHeader", children: _jsxs("div", { className: `planningCalendarRow ${props.rowsClassName}`, style: Object.assign(Object.assign({}, theadTrStyle), props.rowsStyle), children: [_jsx("div", { className: `dayTh ${props.groupsColsClassName}`, style: Object.assign({}, props.groupsColsStyle), children: _jsx(GroupsHeadContainer, { className: `${props.groupHeadContainerClassName}`, style: props.groupHeadContainerStyle, groupsHeadRender: props.groupsHeadRender }) }), weekDays.map((day, i) => (_jsx("div", { className: `dayCol ${props.daysColsClassName}`, style: Object.assign({}, props.daysColsStyle), children: _jsx(DayContainer, { style: props.dayStyle, className: props.dayClassName, dayIndex: i, dayRender: props.dayRender, day: day.day, dayOfTheMonth: day.dayOfTheMonth, dayMonth: day.dayMonth, dayYear: day.dayYear }) }, i)))] }, "header") })), [weekDays, props.rowsClassName, props.rowsStyle, props.groupsColsClassName, props.groupsColsStyle, props.groupHeadContainerClassName, props.groupHeadContainerStyle, props.groupsHeadRender, props.daysColsClassName, props.daysColsStyle, props.dayStyle, props.dayClassName, props.dayRender]);
|
|
15
15
|
const offset = useMemo(() => updateOffsetWithDateCalendar(props.date), [props.date]);
|
|
16
|
-
return (_jsx("div", { className: "calendarForWeek", style: { position: "relative" }, children: _jsxs("div", { className: `planningCalendar ${props.className}`, style: Object.assign({}, props.style), children: [memoizedHeader, _jsx("div", { className: "planningCalendarBody", children: (_a = props.groups) === null || _a === void 0 ? void 0 : _a.map((group, i) => {
|
|
16
|
+
return (_jsx("div", { className: "calendarForWeek", style: { position: "relative" }, children: _jsxs("div", { className: `planningCalendar ${props.className}`, style: Object.assign({}, props.style), children: [memoizedHeader, _jsx("div", { className: "planningCalendarBody", style: {}, children: (_a = props.groups) === null || _a === void 0 ? void 0 : _a.map((group, i) => {
|
|
17
17
|
var _a;
|
|
18
18
|
const scope = hashScope || "week";
|
|
19
19
|
const groupHash = getHash(offset, group.id);
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import "./style.css";
|
|
3
3
|
import { memo, useMemo } from "react";
|
|
4
|
-
import useCalendarDateState from "../hooks/useCalendarDateState";
|
|
5
4
|
import VirtualGroupRowDay from "./VirtualGroupRowDay";
|
|
6
5
|
import DayContainer from "./DayContainer";
|
|
7
6
|
import { useCalendarTaskContext } from "../contexts/CalendarTaskContext";
|
|
7
|
+
import useCalendarDateStateForDay from "../hooks/useCalendarDateStateForDay";
|
|
8
8
|
function CalendarForDay(props) {
|
|
9
|
-
const { dailyHours, weekDays } =
|
|
9
|
+
const { dailyHours, weekDays, weekOffset: currentWeekOffset } = useCalendarDateStateForDay(props.date, props.weekOffset, props.timeZone, props.dayOffset);
|
|
10
10
|
const { getTasks, isValidTask, addTask, deleteTask, updateTask, getTask, hashScope, tasks } = useCalendarTaskContext();
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
|
|
11
|
+
const dayIndex = props.dayOffset !== undefined ? props.dayOffset : props.date.getDay();
|
|
12
|
+
const currentDay = weekDays[dayIndex];
|
|
13
|
+
const memoizedHeader = useMemo(() => (currentDay ? (_jsx(DayContainer, { style: props.dayStyle, className: props.dayClassName, dayIndex: dayIndex, dayRender: props.dayRender, day: currentDay.day, dayOfTheMonth: currentDay.dayOfTheMonth, dayMonth: currentDay.dayMonth, dayYear: currentDay.dayYear })) : null), [weekDays, dayIndex, props.dayStyle, props.dayClassName, props.dayRender]);
|
|
14
|
+
return (_jsxs("div", { className: `CalendarTableForDay ${props.className}`, style: Object.assign({ position: "relative" }, props.style), children: [memoizedHeader, _jsx("div", { className: `CalendarTableForDayTasksContainer`, children: props.groups.map((group, i) => (_jsx(VirtualGroupRowDay, { group: group, i: i, props: props, getTasks: getTasks, isValidTask: isValidTask, addTask: addTask, deleteTask: deleteTask, updateTask: updateTask, getTask: getTask, dailyHours: dailyHours, dayOffset: dayIndex, weekOffset: currentWeekOffset, hashScope: hashScope || "day", tasks: tasks }, `${group.id}-${i}`))) })] }));
|
|
14
15
|
}
|
|
15
16
|
export default memo(CalendarForDay, (prevProps, nextProps) => {
|
|
16
17
|
var _a, _b;
|
|
@@ -4,15 +4,15 @@ import { useIntersectionObserver } from "../../hooks/useIntersectionObserver";
|
|
|
4
4
|
import TaskContainer from ".";
|
|
5
5
|
const TaskVirtual = (props) => {
|
|
6
6
|
const ref = useRef(null);
|
|
7
|
-
const entry = useIntersectionObserver(ref, {
|
|
7
|
+
const { entry, height } = useIntersectionObserver(ref, {
|
|
8
8
|
rootMargin: "200px", // Margin to pre-render tasks before they appear
|
|
9
9
|
threshold: 0,
|
|
10
10
|
});
|
|
11
11
|
const isVisible = !!(entry === null || entry === void 0 ? void 0 : entry.isIntersecting);
|
|
12
12
|
return (_jsx("div", { ref: ref, style: {
|
|
13
|
-
minHeight: isVisible ? "auto" :
|
|
13
|
+
minHeight: isVisible ? "auto" : `${height}px`,
|
|
14
14
|
width: "100%",
|
|
15
15
|
marginBottom: "4px"
|
|
16
|
-
}, children: isVisible ? (_jsx(TaskContainer, Object.assign({}, props))) : (_jsx("div", { style: { height:
|
|
16
|
+
}, "data-index": props.index, children: isVisible ? (_jsx(TaskContainer, Object.assign({}, props))) : (_jsx("div", { style: { height: `${height}px`, backgroundColor: "rgba(200, 200, 200, 0.1)", borderRadius: "4px" } })) }));
|
|
17
17
|
};
|
|
18
18
|
export default React.memo(TaskVirtual);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { v4 as uuidv4 } from "uuid";
|
|
3
|
+
import TaskVirtual from "./TaskContainer/TaskVirtual";
|
|
4
|
+
import AddTask from "./AddTask";
|
|
5
|
+
import { getNewTaskForDropOrPaste, getUniqueId, } from "../lib/utils";
|
|
6
|
+
import { memo } from "react";
|
|
7
|
+
const VirtualGroupCell = ({ group, i, props, getTasks, isValidTask, addTask, deleteTask, getTask, day, hash, tasks, tasksStore, start, end }) => {
|
|
8
|
+
return (_jsx("div", { onDragOver: (e) => e.preventDefault(), onDrop: (event) => {
|
|
9
|
+
const dropInfo = getNewTaskForDropOrPaste(day.positionDay, group.id, getTask, hash);
|
|
10
|
+
if (!dropInfo)
|
|
11
|
+
return;
|
|
12
|
+
if (props.drop === "copy") {
|
|
13
|
+
addTask(Object.assign(Object.assign({}, dropInfo.newTask), { id: uuidv4() }));
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
deleteTask(dropInfo.newTask.draghash, dropInfo.newTask.id);
|
|
17
|
+
addTask(Object.assign(Object.assign({}, dropInfo.newTask), { id: getUniqueId() }));
|
|
18
|
+
}, id: `col-${group.id}day-i`, className: `dayCol ${props.dayColsClassName}`, style: Object.assign(Object.assign({}, props.dayColsStyle), { minHeight: '60px' }), children: _jsxs("div", { style: {
|
|
19
|
+
display: "flex",
|
|
20
|
+
width: "100%",
|
|
21
|
+
height: "100%",
|
|
22
|
+
flexDirection: "column",
|
|
23
|
+
padding: "5px",
|
|
24
|
+
}, children: [tasks.slice(start, end).map((task) => {
|
|
25
|
+
if (task.dayIndex === day.positionDay &&
|
|
26
|
+
task.groupId === group.id && isValidTask(task)) {
|
|
27
|
+
return (_jsx(TaskVirtual, { handleDragTask: props.handleDragTask, taskRender: props.taskRender, handleDragTaskEnd: props.handleDragTaskEnd, style: props.taskContainerStyle, className: `${props.taskContainerClassName}`, currentTask: task, handleClickTask: props.handleClickTask }, `${task.id} task`));
|
|
28
|
+
}
|
|
29
|
+
else
|
|
30
|
+
return null;
|
|
31
|
+
}), _jsx(AddTask, { addTaskStyle: props.addTaskStyle, addTaskClassName: props.addTaskClassName, currentGroup: group, dayInfo: day, addTaskRender: props.addTaskRender, handleAddTask: props.handleAddTask })] }) }, `col-${group.id}day-i${day.positionDay}`));
|
|
32
|
+
};
|
|
33
|
+
export default memo(VirtualGroupCell);
|
|
@@ -7,9 +7,9 @@ import TaskVirtual from "./TaskContainer/TaskVirtual";
|
|
|
7
7
|
import AddTask from "./AddTask";
|
|
8
8
|
import { getHash, getNewTaskForDropOrPaste, getUniqueId, updateOffsetWithDateCalendar, } from "../lib/utils";
|
|
9
9
|
import { groupTdStyle } from "../lib/slyles";
|
|
10
|
-
const VirtualGroupRow = ({ group, i, props, getTasks, isValidTask, addTask, deleteTask, getTask, dailyHours, hashScope, tasks, sumHoursByGroupsCount }) => {
|
|
10
|
+
const VirtualGroupRow = ({ group, i, props, getTasks, isValidTask, addTask, deleteTask, getTask, dailyHours, hashScope, tasks, sumHoursByGroupsCount, }) => {
|
|
11
11
|
const ref = useRef(null);
|
|
12
|
-
const entry = useIntersectionObserver(ref, {
|
|
12
|
+
const { entry, height } = useIntersectionObserver(ref, {
|
|
13
13
|
rootMargin: "600px",
|
|
14
14
|
threshold: 0,
|
|
15
15
|
});
|
|
@@ -28,7 +28,7 @@ const VirtualGroupRow = ({ group, i, props, getTasks, isValidTask, addTask, dele
|
|
|
28
28
|
};
|
|
29
29
|
});
|
|
30
30
|
}, [isVisible, offset, group.id, dailyHours, hashScope, getTasks, isValidTask, tasks]);
|
|
31
|
-
return (_jsx("div", { ref: ref, className: `planningCalendarRow ${props.rowsClassName}`, style: Object.assign(Object.assign({}, props.rowsStyle), { minHeight: isVisible ? "auto" :
|
|
31
|
+
return (_jsx("div", { ref: ref, className: `planningCalendarRow ${props.rowsClassName}`, style: Object.assign(Object.assign({}, props.rowsStyle), { minHeight: isVisible ? "auto" : `${height}px` }), "data-index": i, children: isVisible ? (_jsxs(_Fragment, { children: [_jsx("div", { className: `groupCol ${props.groupsColsClassName}`, style: Object.assign(Object.assign({}, groupTdStyle), props.groupsColsStyle), children: _jsx(GroupContainer, { style: props.groupContainerStyle, className: props.groupContainerClassName, groupRender: props.groupRender, currentGroup: group, handleClickGroup: props.handleClickGroup }) }, group.id), cellData.map((cell) => {
|
|
32
32
|
return (_jsx("div", { onDragOver: (e) => e.preventDefault(), onDrop: (event) => {
|
|
33
33
|
const dropInfo = getNewTaskForDropOrPaste(cell.positionDay, group.id, getTask, cell.hash);
|
|
34
34
|
if (!dropInfo)
|
|
@@ -45,15 +45,15 @@ const VirtualGroupRow = ({ group, i, props, getTasks, isValidTask, addTask, dele
|
|
|
45
45
|
height: "100%",
|
|
46
46
|
flexDirection: "column",
|
|
47
47
|
padding: "5px",
|
|
48
|
-
}, children: [cell.tasks.map((task) => {
|
|
48
|
+
}, children: [cell.tasks.map((task, index) => {
|
|
49
49
|
if (task.dayIndex === cell.positionDay &&
|
|
50
50
|
task.groupId === group.id && isValidTask(task)) {
|
|
51
|
-
return (_jsx(TaskVirtual, { handleDragTask: props.handleDragTask, taskRender: props.taskRender, handleDragTaskEnd: props.handleDragTaskEnd, style: props.taskContainerStyle, className: `${props.taskContainerClassName}`, currentTask: task, handleClickTask: props.handleClickTask }, `${task.id} task`));
|
|
51
|
+
return (_jsx(TaskVirtual, { index: index, handleDragTask: props.handleDragTask, taskRender: props.taskRender, handleDragTaskEnd: props.handleDragTaskEnd, style: props.taskContainerStyle, className: `${props.taskContainerClassName}`, currentTask: task, handleClickTask: props.handleClickTask }, `${task.id} task`));
|
|
52
52
|
}
|
|
53
53
|
else
|
|
54
54
|
return null;
|
|
55
55
|
}), _jsx(AddTask, { addTaskStyle: props.addTaskStyle, addTaskClassName: props.addTaskClassName, currentGroup: group, dayInfo: dailyHours[cell.positionDay], addTaskRender: props.addTaskRender, handleAddTask: props.handleAddTask })] }) }, `col-${group.id}day-i${cell.positionDay}`));
|
|
56
|
-
})] })) : (_jsx("div", { style: { height:
|
|
56
|
+
})] })) : (_jsx("div", { style: { height: `${height}px`, width: "100%" } })) }));
|
|
57
57
|
};
|
|
58
58
|
export default memo(VirtualGroupRow, (prev, next) => {
|
|
59
59
|
return (prev.group.id === next.group.id &&
|
|
@@ -4,22 +4,21 @@ import { useIntersectionObserver } from "../hooks/useIntersectionObserver";
|
|
|
4
4
|
import GroupContainer from "./GroupContainer";
|
|
5
5
|
import TaskVirtual from "./TaskContainer/TaskVirtual";
|
|
6
6
|
import AddTask from "./AddTask";
|
|
7
|
-
import { getHash, getNewTaskForDropOrPaste, getUniqueId,
|
|
8
|
-
const VirtualGroupRowDay = ({ group, i, props, getTasks, isValidTask, addTask, deleteTask, updateTask, getTask, dailyHours, dayOffset, hashScope, tasks, }) => {
|
|
7
|
+
import { getHash, getNewTaskForDropOrPaste, getUniqueId, } from "../lib/utils";
|
|
8
|
+
const VirtualGroupRowDay = ({ group, i, props, getTasks, isValidTask, addTask, deleteTask, updateTask, getTask, dailyHours, dayOffset, weekOffset, hashScope, tasks, }) => {
|
|
9
9
|
const ref = useRef(null);
|
|
10
|
-
const entry = useIntersectionObserver(ref, {
|
|
10
|
+
const { entry, height } = useIntersectionObserver(ref, {
|
|
11
11
|
rootMargin: "600px",
|
|
12
12
|
threshold: 0,
|
|
13
13
|
});
|
|
14
14
|
const isVisible = !!(entry === null || entry === void 0 ? void 0 : entry.isIntersecting);
|
|
15
|
-
const offset = useMemo(() => updateOffsetWithDateCalendar(props.date), [props.date]);
|
|
16
15
|
const currentDailyHours = dailyHours[dayOffset];
|
|
17
|
-
const hash = useMemo(() => getHash(
|
|
16
|
+
const hash = useMemo(() => getHash(weekOffset, group.id, dayOffset), [weekOffset, group.id, dayOffset]);
|
|
18
17
|
const cellTasks = useMemo(() => getTasks(hash[hashScope]), [getTasks, hash, hashScope, tasks]);
|
|
19
18
|
const handleDragOver = (event) => {
|
|
20
19
|
event.preventDefault();
|
|
21
20
|
};
|
|
22
|
-
return (_jsx("div", { ref: ref, style: Object.assign({ width: "100%", height: "auto", padding: "5px", borderBottom: "1.5px solid #0f52737e", borderRight: "0.74px solid rgba(198, 219, 225, 0.68)", borderLeft: "0.74px solid rgba(198, 219, 225, 0.68)", minHeight: isVisible ? "auto" :
|
|
21
|
+
return (_jsx("div", { ref: ref, style: Object.assign({ width: "100%", height: "auto", padding: "5px", borderBottom: "1.5px solid #0f52737e", borderRight: "0.74px solid rgba(198, 219, 225, 0.68)", borderLeft: "0.74px solid rgba(198, 219, 225, 0.68)", minHeight: isVisible ? "auto" : `${height}px` }, props.rowsStyle), className: `CalendarTableForDayRow ${props.rowsClassName}`, children: isVisible ? (_jsxs(_Fragment, { children: [_jsx("div", { style: Object.assign({ width: "auto", height: "auto" }, props.groupsColsStyle), className: props.groupsColsClassName, children: _jsx(GroupContainer, { style: props.groupContainerStyle, className: props.groupContainerClassName, groupRender: props.groupRender, currentGroup: group, handleClickGroup: props.handleClickGroup }) }), _jsxs("div", { className: "CalendarTableForDayGroupTasks", onDragOver: handleDragOver, onDrop: (event) => {
|
|
23
22
|
if (!cellTasks)
|
|
24
23
|
return;
|
|
25
24
|
const dropInfo = getNewTaskForDropOrPaste(currentDailyHours.positionDay, group.id, getTask, hash[hashScope]);
|
|
@@ -30,20 +29,21 @@ const VirtualGroupRowDay = ({ group, i, props, getTasks, isValidTask, addTask, d
|
|
|
30
29
|
return;
|
|
31
30
|
}
|
|
32
31
|
updateTask(hash[hashScope], dropInfo.newTask.id, dropInfo.newTask);
|
|
33
|
-
}, children: [cellTasks.map((task) => {
|
|
32
|
+
}, children: [cellTasks.map((task, index) => {
|
|
34
33
|
if (task.dayIndex === dayOffset &&
|
|
35
34
|
task.groupId === group.id &&
|
|
36
35
|
isValidTask(task)) {
|
|
37
|
-
return (_jsx(TaskVirtual, { handleDragTask: props.handleDragTask, taskRender: props.taskRender, handleDragTaskEnd: props.handleDragTaskEnd, style: props.taskContainerStyle, className: `${props.taskContainerClassName}`, currentTask: task, handleClickTask: props.handleClickTask }, `${task.id} task`));
|
|
36
|
+
return (_jsx(TaskVirtual, { index: index, handleDragTask: props.handleDragTask, taskRender: props.taskRender, handleDragTaskEnd: props.handleDragTaskEnd, style: props.taskContainerStyle, className: `${props.taskContainerClassName}`, currentTask: task, handleClickTask: props.handleClickTask }, `${task.id} task`));
|
|
38
37
|
}
|
|
39
38
|
else
|
|
40
39
|
return null;
|
|
41
|
-
}), _jsx(AddTask, { addTaskStyle: props.addTaskStyle, addTaskClassName: props.addTaskClassName, currentGroup: group, dayInfo: currentDailyHours, addTaskRender: props.addTaskRender, handleAddTask: props.handleAddTask })] })] })) : (_jsx("div", { style: { height:
|
|
40
|
+
}), _jsx(AddTask, { addTaskStyle: props.addTaskStyle, addTaskClassName: props.addTaskClassName, currentGroup: group, dayInfo: currentDailyHours, addTaskRender: props.addTaskRender, handleAddTask: props.handleAddTask })] })] })) : (_jsx("div", { style: { height: `${height}px`, width: "100%" } })) }));
|
|
42
41
|
};
|
|
43
42
|
export default memo(VirtualGroupRowDay, (prev, next) => {
|
|
44
43
|
return (prev.group.id === next.group.id &&
|
|
45
44
|
prev.i === next.i &&
|
|
46
45
|
prev.tasks === next.tasks &&
|
|
47
46
|
prev.props.date.getTime() === next.props.date.getTime() &&
|
|
48
|
-
prev.dayOffset === next.dayOffset
|
|
47
|
+
prev.dayOffset === next.dayOffset &&
|
|
48
|
+
prev.weekOffset === next.weekOffset);
|
|
49
49
|
});
|
package/dist/components/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import "./style.css";
|
|
3
3
|
import CalendarForWeek from "./CalendarForWeek";
|
|
4
|
-
import CalendarForDay from "./CalendarForday";
|
|
5
4
|
import CalendarTaskContextProvider from "../contexts/CalendarTaskContext";
|
|
6
5
|
/**
|
|
7
6
|
* Calendar component to display tasks and groups in a weekly view.
|
|
@@ -58,13 +57,12 @@ import CalendarTaskContextProvider from "../contexts/CalendarTaskContext";
|
|
|
58
57
|
* @param {() => React.ReactNode} [props.sumHoursHeadRender] - Custom render function for the sum-of-hours header.
|
|
59
58
|
* @param {(currentTask: TaskFeildsType) => void} [props.handleClickTask] - Handler function for clicking a task.
|
|
60
59
|
* @param {(currentGroup: GroupFeildsType) => void} [props.handleClickGroup] - Handler function for clicking a group.
|
|
61
|
-
* @param {0|1|2|3|4|5|6} [props.dayOffset] - Offset index for the day column (0 = first day of week, …, 6 = last day).
|
|
62
60
|
* @param {React.CSSProperties} [props.dayColsStyle] - Additional styles for the day columns.
|
|
63
61
|
* @param {string} [props.dayColsClassName] - Additional class names for the day columns.
|
|
64
62
|
* @param {React.CSSProperties} [props.hoursColsStyle] - Additional styles for the hours columns.
|
|
65
63
|
* @param {string} [props.hoursColsClassName] - Additional class names for the hours columns.
|
|
66
64
|
*/
|
|
67
65
|
const Calendar = (props) => {
|
|
68
|
-
return (_jsx(CalendarTaskContextProvider, { hashScope: "
|
|
66
|
+
return (_jsx(CalendarTaskContextProvider, { hashScope: "day", children: _jsx(CalendarForWeek, Object.assign({}, props)) }));
|
|
69
67
|
};
|
|
70
68
|
export default Calendar;
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
display: flex;
|
|
60
60
|
flex-direction: column;
|
|
61
61
|
border: 0.74px solid rgba(198, 219, 225, 0.68);
|
|
62
|
-
|
|
62
|
+
border-bottom: none;
|
|
63
63
|
background-color: white;
|
|
64
64
|
|
|
65
65
|
}
|
|
@@ -70,6 +70,8 @@
|
|
|
70
70
|
z-index: 200;
|
|
71
71
|
border-bottom: 1.5px solid #0f52737e;
|
|
72
72
|
background-color: #fff;
|
|
73
|
+
position: sticky;
|
|
74
|
+
top: 0px;
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
.planningCalendarRow {
|
|
@@ -85,24 +87,66 @@
|
|
|
85
87
|
.planningCalendar .dayTh,
|
|
86
88
|
.planningCalendar .groupCol {
|
|
87
89
|
flex: 0 0 150px;
|
|
90
|
+
min-width: 150px;
|
|
88
91
|
color: #0f5173;
|
|
89
92
|
padding-left: 5px;
|
|
90
93
|
display: flex;
|
|
91
94
|
align-items: center;
|
|
95
|
+
background-color: inherit;
|
|
92
96
|
}
|
|
93
97
|
|
|
94
98
|
.planningCalendar .dayCol {
|
|
95
99
|
flex: 1;
|
|
100
|
+
min-width: 120px;
|
|
96
101
|
border-left: 0.74px solid rgba(198, 219, 225, 0.68);
|
|
97
|
-
min-width: 0;
|
|
98
102
|
display: flex;
|
|
99
103
|
flex-direction: column;
|
|
100
104
|
justify-content: center;
|
|
101
105
|
}
|
|
102
106
|
|
|
107
|
+
@media (max-width: 768px) {
|
|
108
|
+
|
|
109
|
+
.planningCalendar .dayTh,
|
|
110
|
+
.planningCalendar .groupCol {
|
|
111
|
+
flex: 0 0 100px;
|
|
112
|
+
min-width: 100px;
|
|
113
|
+
font-size: 13px;
|
|
114
|
+
position: sticky;
|
|
115
|
+
left: 0;
|
|
116
|
+
z-index: 50;
|
|
117
|
+
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.05);
|
|
118
|
+
background-color: #fff;
|
|
119
|
+
overflow: hidden;
|
|
120
|
+
white-space: nowrap;
|
|
121
|
+
text-overflow: ellipsis;
|
|
122
|
+
padding-left: 10px;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.planningCalendar .dayCol {
|
|
126
|
+
min-width: 120px;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.planningCalendarHeader {
|
|
130
|
+
z-index: 201;
|
|
131
|
+
/* Layer over the sticky row column */
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/* Make sure the group container labels also truncate */
|
|
135
|
+
.groupCol label {
|
|
136
|
+
overflow: hidden;
|
|
137
|
+
text-overflow: ellipsis;
|
|
138
|
+
max-width: 100%;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.planningCalendar {
|
|
142
|
+
width: auto;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
103
146
|
.planningCalendar .totalTh,
|
|
104
147
|
.planningCalendar .totalCol {
|
|
105
148
|
flex: 0 0 50px;
|
|
149
|
+
min-width: 50px;
|
|
106
150
|
color: #0f5173;
|
|
107
151
|
text-align: right;
|
|
108
152
|
padding-right: 5px;
|
|
@@ -156,7 +200,6 @@
|
|
|
156
200
|
flex: 1;
|
|
157
201
|
overflow: auto;
|
|
158
202
|
position: relative;
|
|
159
|
-
|
|
160
203
|
}
|
|
161
204
|
|
|
162
205
|
.calendarForWeek-container {
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { createContext, useContext } from "react";
|
|
3
3
|
import { useCalendarTask } from "../hooks/useCalendarTask";
|
|
4
4
|
const CalendarTaskContext = createContext({
|
|
5
|
-
tasks: { buckets: {}, dataLength: 0, taskCache: {} },
|
|
5
|
+
tasks: { buckets: {}, dataLength: 0, taskCache: {}, maxBucketSize: 0 },
|
|
6
6
|
addTask: () => { },
|
|
7
7
|
getTasks: () => [],
|
|
8
8
|
updateTask: () => { },
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useMemo } from "react";
|
|
2
2
|
import { calculateWeekDifference, getDateObjectInTimeZone, getDayHourly, getWeekDays, } from "../lib/utils";
|
|
3
3
|
function useCalendarDateState(date, weekOffset, timeZone) {
|
|
4
|
-
|
|
5
|
-
useEffect(() => {
|
|
4
|
+
let calendarDateState = useMemo(() => {
|
|
6
5
|
const weekOffsetByDate = timeZone
|
|
7
6
|
? calculateWeekDifference(getDateObjectInTimeZone(timeZone), timeZone)
|
|
8
7
|
: calculateWeekDifference(date, timeZone);
|
|
@@ -12,7 +11,7 @@ function useCalendarDateState(date, weekOffset, timeZone) {
|
|
|
12
11
|
dailyHours: dailyHours,
|
|
13
12
|
weekDays,
|
|
14
13
|
};
|
|
15
|
-
|
|
14
|
+
return calData;
|
|
16
15
|
}, [date, weekOffset]);
|
|
17
16
|
return Object.assign({}, calendarDateState);
|
|
18
17
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { calculateWeekDifference, getDateObjectInTimeZone, getDayHourly, getWeekDays, } from "../lib/utils";
|
|
3
|
+
function useCalendarDateStateForDay(date, weekOffset, timeZone, dayOffset) {
|
|
4
|
+
let calendarDateState = useMemo(() => {
|
|
5
|
+
const currentWeekOffset = (weekOffset !== undefined) ? weekOffset : (timeZone
|
|
6
|
+
? calculateWeekDifference(getDateObjectInTimeZone(timeZone), timeZone)
|
|
7
|
+
: calculateWeekDifference(date, timeZone));
|
|
8
|
+
const weekDays = getWeekDays(currentWeekOffset, timeZone);
|
|
9
|
+
const dailyHours = getDayHourly(currentWeekOffset, timeZone);
|
|
10
|
+
const calData = {
|
|
11
|
+
dailyHours: dailyHours,
|
|
12
|
+
weekDays,
|
|
13
|
+
weekOffset: currentWeekOffset,
|
|
14
|
+
};
|
|
15
|
+
return calData;
|
|
16
|
+
}, [date, weekOffset, dayOffset, timeZone]);
|
|
17
|
+
return Object.assign({}, calendarDateState);
|
|
18
|
+
}
|
|
19
|
+
export default useCalendarDateStateForDay;
|
|
@@ -2,7 +2,8 @@ import { useEffect, useRef, useState, useMemo } from "react";
|
|
|
2
2
|
import { getHash, updateOffsetWithDateCalendar } from "../lib/utils";
|
|
3
3
|
const STORAGE_KEY = "calendar_tasks";
|
|
4
4
|
export function useCalendarTask(hashScope, timeZone) {
|
|
5
|
-
const tasksRef = useRef({ buckets: {}, dataLength: 0, taskCache: {} });
|
|
5
|
+
const tasksRef = useRef({ buckets: {}, dataLength: 0, taskCache: {}, maxBucketSize: 0 });
|
|
6
|
+
const bucketSizeCountsRef = useRef({});
|
|
6
7
|
const scheduleCleanRef = useRef(null);
|
|
7
8
|
const [render, forceRender] = useState(0);
|
|
8
9
|
const cleanExpiredTasks = () => {
|
|
@@ -110,6 +111,7 @@ export function useCalendarTask(hashScope, timeZone) {
|
|
|
110
111
|
const bucket = tasksRef.current.buckets[hash];
|
|
111
112
|
const index = bucket.list.length;
|
|
112
113
|
bucket.list.push(Object.assign(Object.assign({}, task), { hash }));
|
|
114
|
+
tasksRef.current.maxBucketSize = Math.max(tasksRef.current.maxBucketSize, bucket.list.length);
|
|
113
115
|
bucket.indexMap[task.id] = index;
|
|
114
116
|
bucket.sumOfTaskDuration += task.taskEnd - task.taskStart;
|
|
115
117
|
tasksRef.current.dataLength++;
|
|
@@ -148,6 +150,7 @@ export function useCalendarTask(hashScope, timeZone) {
|
|
|
148
150
|
}
|
|
149
151
|
}
|
|
150
152
|
bucket.list[index] = Object.assign(Object.assign({}, bucket.list[index]), updatedTask);
|
|
153
|
+
tasksRef.current.maxBucketSize = Math.max(tasksRef.current.maxBucketSize, bucket.list.length);
|
|
151
154
|
saveToStorage();
|
|
152
155
|
scheduleClean();
|
|
153
156
|
forceRender((x) => x + 1);
|
|
@@ -172,6 +175,7 @@ export function useCalendarTask(hashScope, timeZone) {
|
|
|
172
175
|
delete bucket.indexMap[taskId];
|
|
173
176
|
bucket.sumOfTaskDuration -= oldTAskDuration;
|
|
174
177
|
tasksRef.current.dataLength--;
|
|
178
|
+
tasksRef.current.maxBucketSize = Math.max(tasksRef.current.maxBucketSize, bucket.list.length);
|
|
175
179
|
saveToStorage();
|
|
176
180
|
scheduleClean();
|
|
177
181
|
forceRender((x) => x + 1);
|
|
@@ -1,14 +1,93 @@
|
|
|
1
|
-
import { useState, useEffect } from "react";
|
|
2
|
-
export function useContainerScroll(mainContaierRef, cardHeight,
|
|
3
|
-
const [
|
|
1
|
+
import { useState, useEffect, useRef } from "react";
|
|
2
|
+
export function useContainerScroll(mainContaierRef, cardHeight, gridContaineRef) {
|
|
3
|
+
const [rowSliceIndexStart, setRowSliceIndexStart] = useState(0);
|
|
4
|
+
const [rowSliceIndexEnd, setRowSliceIndexEnd] = useState(15);
|
|
5
|
+
const [taskSliceIdexStart, setTaskSliceIdexStart] = useState(0);
|
|
6
|
+
const [taskSLiceIdexEnd, setTaskSLiceIdexEnd] = useState(30);
|
|
7
|
+
const [rowHeight, setRowHeight] = useState(0);
|
|
8
|
+
const visibleRows = useRef(new Set());
|
|
4
9
|
useEffect(() => {
|
|
5
10
|
const mainContainer = mainContaierRef.current;
|
|
11
|
+
const gridContainer = gridContaineRef.current;
|
|
12
|
+
if (!mainContainer || !gridContainer)
|
|
13
|
+
return;
|
|
14
|
+
const observer = new IntersectionObserver((entries) => {
|
|
15
|
+
entries.forEach((entry) => {
|
|
16
|
+
const row = entry.target;
|
|
17
|
+
const indexAttr = row.getAttribute('data-index');
|
|
18
|
+
if (!indexAttr)
|
|
19
|
+
return;
|
|
20
|
+
const index = parseInt(indexAttr, 10);
|
|
21
|
+
if (entry.isIntersecting) {
|
|
22
|
+
visibleRows.current.add(index);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
visibleRows.current.delete(index);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}, {
|
|
29
|
+
root: mainContainer,
|
|
30
|
+
threshold: 0,
|
|
31
|
+
});
|
|
32
|
+
const observedElements = new Set();
|
|
33
|
+
const observeChildren = () => {
|
|
34
|
+
if (!gridContainer.children)
|
|
35
|
+
return;
|
|
36
|
+
for (let i = 0; i < gridContainer.children.length; i++) {
|
|
37
|
+
const element = gridContainer.children[i];
|
|
38
|
+
if (!observedElements.has(element)) {
|
|
39
|
+
observer.observe(element);
|
|
40
|
+
observedElements.add(element);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const mutationObserver = new MutationObserver(() => {
|
|
45
|
+
observeChildren();
|
|
46
|
+
});
|
|
47
|
+
observeChildren();
|
|
48
|
+
mutationObserver.observe(gridContainer, { childList: true });
|
|
6
49
|
const handleScroll = () => {
|
|
7
|
-
const
|
|
8
|
-
|
|
50
|
+
const scrollTop = mainContainer.scrollTop;
|
|
51
|
+
const containerHeight = mainContainer.clientHeight || 800;
|
|
52
|
+
// ---- CALCUL POUR LES ROWS ----
|
|
53
|
+
const baseRowHeight = 72;
|
|
54
|
+
let startRowIndex = Math.floor(scrollTop / baseRowHeight);
|
|
55
|
+
if (visibleRows.current.size > 0) {
|
|
56
|
+
const firstVisibleRowIndex = Math.min(...Array.from(visibleRows.current));
|
|
57
|
+
if (startRowIndex > firstVisibleRowIndex) {
|
|
58
|
+
startRowIndex = firstVisibleRowIndex;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Calcul de la fin (avec un buffer de vue de 2 éléments)
|
|
62
|
+
const visibleRowsCount = Math.ceil(containerHeight / baseRowHeight);
|
|
63
|
+
const endRowIndex = startRowIndex + visibleRowsCount + 2;
|
|
64
|
+
// ---- CALCUL POUR LES TASKS ----
|
|
65
|
+
// Base théorique pour une task (environ 40px minimum)
|
|
66
|
+
const baseTaskHeight = 40;
|
|
67
|
+
// Attention : Ceci est une estimation globale. Si chaque ROW scrolle individuellement,
|
|
68
|
+
// cette formule devra être ajustée.
|
|
69
|
+
const startTaskIndex = Math.floor(Math.max(0, scrollTop) / baseTaskHeight);
|
|
70
|
+
const visibleTasksCount = Math.ceil(containerHeight / baseTaskHeight);
|
|
71
|
+
const endTaskIndex = startTaskIndex + visibleTasksCount + 5;
|
|
72
|
+
setRowSliceIndexStart(startRowIndex);
|
|
73
|
+
setRowSliceIndexEnd(endRowIndex);
|
|
74
|
+
setTaskSliceIdexStart(startTaskIndex);
|
|
75
|
+
setTaskSLiceIdexEnd(endTaskIndex);
|
|
9
76
|
};
|
|
10
77
|
mainContainer.addEventListener("scroll", handleScroll);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
78
|
+
// Exécution initiale
|
|
79
|
+
handleScroll();
|
|
80
|
+
return () => {
|
|
81
|
+
mainContainer.removeEventListener("scroll", handleScroll);
|
|
82
|
+
observer.disconnect();
|
|
83
|
+
mutationObserver.disconnect();
|
|
84
|
+
};
|
|
85
|
+
}, [mainContaierRef, gridContaineRef]);
|
|
86
|
+
return {
|
|
87
|
+
rowSliceIndexStart,
|
|
88
|
+
rowSliceIndexEnd,
|
|
89
|
+
taskSliceIdexStart,
|
|
90
|
+
taskSLiceIdexEnd,
|
|
91
|
+
rowHeight
|
|
92
|
+
};
|
|
14
93
|
}
|
|
@@ -8,17 +8,17 @@ export const useGridContainer = (gridContaineRef) => {
|
|
|
8
8
|
useEffect(() => {
|
|
9
9
|
if (typeof window === "undefined")
|
|
10
10
|
return;
|
|
11
|
-
//si le parent n'a aucun enfant on sort
|
|
11
|
+
// //si le parent n'a aucun enfant on sort
|
|
12
12
|
if (gridContaineRef.current.hasChildNodes() === false)
|
|
13
13
|
return;
|
|
14
|
-
//la hauteur du premier enfant de la grid
|
|
15
|
-
const cardH = gridContaineRef.current.firstChild.clientHeight;
|
|
16
|
-
if (cardH !== cardCompH) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
14
|
+
// //la hauteur du premier enfant de la grid
|
|
15
|
+
// const cardH = gridContaineRef.current.firstChild.clientHeight;
|
|
16
|
+
// if (cardH !== cardCompH) {
|
|
17
|
+
// const gridW = gridContaineRef.current.clientWidth;
|
|
18
|
+
// const cardW = gridContaineRef.current.firstChild.clientWidth;
|
|
19
|
+
// setCardCompH(cardH);
|
|
20
|
+
// setItemsByLines(Math.floor(gridW / cardW));
|
|
21
|
+
// }
|
|
22
22
|
}, [width]);
|
|
23
|
-
return { cardCompH, cardRef, itemsByLine };
|
|
23
|
+
return { cardCompH: 65, cardRef, itemsByLine: 1 };
|
|
24
24
|
};
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
2
|
export function useIntersectionObserver(elementRef, { threshold = 0, root = null, rootMargin = "0%", freezeOnceVisible = false, } = {}) {
|
|
3
3
|
const [entry, setEntry] = useState();
|
|
4
|
+
const [height, setHeight] = useState(60);
|
|
4
5
|
const frozen = (entry === null || entry === void 0 ? void 0 : entry.isIntersecting) && freezeOnceVisible;
|
|
5
6
|
const updateEntry = ([entry]) => {
|
|
6
7
|
setEntry(entry);
|
|
8
|
+
if (entry.boundingClientRect) {
|
|
9
|
+
if (entry.boundingClientRect.height > 0) {
|
|
10
|
+
setHeight(entry.boundingClientRect.height);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
7
13
|
};
|
|
8
14
|
useEffect(() => {
|
|
9
|
-
const node = elementRef === null || elementRef === void 0 ? void 0 : elementRef.current;
|
|
15
|
+
const node = elementRef === null || elementRef === void 0 ? void 0 : elementRef.current;
|
|
10
16
|
const hasIOSupport = !!window.IntersectionObserver;
|
|
11
17
|
if (!hasIOSupport || frozen || !node)
|
|
12
18
|
return;
|
|
@@ -15,5 +21,5 @@ export function useIntersectionObserver(elementRef, { threshold = 0, root = null
|
|
|
15
21
|
observer.observe(node);
|
|
16
22
|
return () => observer.disconnect();
|
|
17
23
|
}, [elementRef, JSON.stringify(threshold), root, rootMargin, frozen]);
|
|
18
|
-
return entry;
|
|
24
|
+
return { entry, height };
|
|
19
25
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { TaskContainerPropsType } from "../../definitions";
|
|
3
|
-
|
|
3
|
+
interface TaskVirtualProps extends TaskContainerPropsType {
|
|
4
|
+
index?: number;
|
|
5
|
+
}
|
|
6
|
+
declare const _default: React.MemoExoticComponent<(props: TaskVirtualProps) => import("react/jsx-runtime").JSX.Element>;
|
|
4
7
|
export default _default;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { CalendarTablePropsType, GroupFeildsType, TaskType, TasksStore, TasksType, dayInfoType } from "../definitions";
|
|
2
|
+
import React from "react";
|
|
3
|
+
interface VirtualGroupCellProps {
|
|
4
|
+
group: GroupFeildsType;
|
|
5
|
+
i: number;
|
|
6
|
+
props: CalendarTablePropsType;
|
|
7
|
+
getTasks: (hash: string) => TasksType;
|
|
8
|
+
isValidTask: (task: TaskType) => boolean;
|
|
9
|
+
addTask: (task: TaskType) => void;
|
|
10
|
+
deleteTask: (hash: string, taskId: string) => void;
|
|
11
|
+
getTask: (hash: string, taskId: string) => TaskType | undefined;
|
|
12
|
+
day: dayInfoType;
|
|
13
|
+
hash: string;
|
|
14
|
+
tasks: TasksType;
|
|
15
|
+
tasksStore: TasksStore;
|
|
16
|
+
start: number;
|
|
17
|
+
end: number;
|
|
18
|
+
}
|
|
19
|
+
declare const _default: React.NamedExoticComponent<VirtualGroupCellProps>;
|
|
20
|
+
export default _default;
|
|
@@ -55,7 +55,6 @@ import { CalendarPropsType } from "../definitions";
|
|
|
55
55
|
* @param {() => React.ReactNode} [props.sumHoursHeadRender] - Custom render function for the sum-of-hours header.
|
|
56
56
|
* @param {(currentTask: TaskFeildsType) => void} [props.handleClickTask] - Handler function for clicking a task.
|
|
57
57
|
* @param {(currentGroup: GroupFeildsType) => void} [props.handleClickGroup] - Handler function for clicking a group.
|
|
58
|
-
* @param {0|1|2|3|4|5|6} [props.dayOffset] - Offset index for the day column (0 = first day of week, …, 6 = last day).
|
|
59
58
|
* @param {React.CSSProperties} [props.dayColsStyle] - Additional styles for the day columns.
|
|
60
59
|
* @param {string} [props.dayColsClassName] - Additional class names for the day columns.
|
|
61
60
|
* @param {React.CSSProperties} [props.hoursColsStyle] - Additional styles for the hours columns.
|
|
@@ -96,7 +96,6 @@ export type DayPropsType = {
|
|
|
96
96
|
*/
|
|
97
97
|
export type CalendarPropsType = {
|
|
98
98
|
drop?: "copy" | "move";
|
|
99
|
-
scope?: "day" | "week";
|
|
100
99
|
/** Offset for the week (e.g., -7 for last week, 0 for current week, 7 for next week). */
|
|
101
100
|
weekOffset?: number;
|
|
102
101
|
/** Array of group data to be displayed in the calendar. */
|
|
@@ -194,8 +193,6 @@ export type CalendarPropsType = {
|
|
|
194
193
|
handleClickGroup?: (currentGroup: GroupFeildsType) => void;
|
|
195
194
|
/** your timezones */
|
|
196
195
|
timeZone?: TimeZone;
|
|
197
|
-
/** day id */
|
|
198
|
-
dayOffset?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
199
196
|
/**day columns styles */
|
|
200
197
|
dayColsStyle?: React.CSSProperties | undefined;
|
|
201
198
|
/**day columns className*/
|
|
@@ -413,5 +410,6 @@ export type TasksStore = {
|
|
|
413
410
|
buckets: Record<string, TaskBucket>;
|
|
414
411
|
dataLength: number;
|
|
415
412
|
taskCache: Record<string, Task[]>;
|
|
413
|
+
maxBucketSize: number;
|
|
416
414
|
};
|
|
417
415
|
export {};
|
|
@@ -1,6 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TimeZone } from "../definitions";
|
|
2
2
|
declare function useCalendarDateState(date: Date, weekOffset: number | undefined, timeZone: TimeZone | undefined): {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
dailyHours: {
|
|
4
|
+
positionDay: number;
|
|
5
|
+
day: Date;
|
|
6
|
+
start: number;
|
|
7
|
+
end: number;
|
|
8
|
+
}[];
|
|
9
|
+
weekDays: {
|
|
10
|
+
day: string;
|
|
11
|
+
dayMonth: string;
|
|
12
|
+
dayYear: number;
|
|
13
|
+
dayOfTheMonth: number;
|
|
14
|
+
}[];
|
|
5
15
|
};
|
|
6
16
|
export default useCalendarDateState;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { TimeZone } from "../definitions";
|
|
2
|
+
declare function useCalendarDateStateForDay(date: Date, weekOffset: number | undefined, timeZone: TimeZone | undefined, dayOffset: number | undefined): {
|
|
3
|
+
dailyHours: {
|
|
4
|
+
positionDay: number;
|
|
5
|
+
day: Date;
|
|
6
|
+
start: number;
|
|
7
|
+
end: number;
|
|
8
|
+
}[];
|
|
9
|
+
weekDays: {
|
|
10
|
+
day: string;
|
|
11
|
+
dayMonth: string;
|
|
12
|
+
dayYear: number;
|
|
13
|
+
dayOfTheMonth: number;
|
|
14
|
+
}[];
|
|
15
|
+
weekOffset: number;
|
|
16
|
+
};
|
|
17
|
+
export default useCalendarDateStateForDay;
|
|
@@ -4,6 +4,7 @@ export declare function useCalendarTask(hashScope: "week" | "group" | "day", tim
|
|
|
4
4
|
buckets: Record<string, import("../definitions").TaskBucket>;
|
|
5
5
|
dataLength: number;
|
|
6
6
|
taskCache: Record<string, Task[]>;
|
|
7
|
+
maxBucketSize: number;
|
|
7
8
|
};
|
|
8
9
|
addTask: (task: Task) => void;
|
|
9
10
|
getTasks: (hash: string) => Task[];
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
export declare function useContainerScroll(mainContaierRef: React.RefObject<any>, cardHeight: number,
|
|
2
|
-
|
|
1
|
+
export declare function useContainerScroll(mainContaierRef: React.RefObject<any>, cardHeight: number, gridContaineRef: React.RefObject<any>): {
|
|
2
|
+
rowSliceIndexStart: number;
|
|
3
|
+
rowSliceIndexEnd: number;
|
|
4
|
+
taskSliceIdexStart: number;
|
|
5
|
+
taskSLiceIdexEnd: number;
|
|
6
|
+
rowHeight: number;
|
|
3
7
|
};
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
interface UseIntersectionObserverProps extends IntersectionObserverInit {
|
|
2
2
|
freezeOnceVisible?: boolean;
|
|
3
3
|
}
|
|
4
|
-
export declare function useIntersectionObserver(elementRef: React.RefObject<Element | null>, { threshold, root, rootMargin, freezeOnceVisible, }?: UseIntersectionObserverProps):
|
|
4
|
+
export declare function useIntersectionObserver(elementRef: React.RefObject<Element | null>, { threshold, root, rootMargin, freezeOnceVisible, }?: UseIntersectionObserverProps): {
|
|
5
|
+
entry: IntersectionObserverEntry | undefined;
|
|
6
|
+
height: number;
|
|
7
|
+
};
|
|
5
8
|
export {};
|
package/dist/types/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-weekly-planning",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.45",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/types/index.d.ts",
|
|
6
6
|
"exports": {
|
|
@@ -63,6 +63,10 @@
|
|
|
63
63
|
"./components/GroupContainer": {
|
|
64
64
|
"types": "./dist/types/components/GroupContainer.d.ts",
|
|
65
65
|
"default": "./dist/components/GroupContainer.js"
|
|
66
|
+
},
|
|
67
|
+
"./hooks/useIntersectionObserver": {
|
|
68
|
+
"types": "./dist/types/hooks/useIntersectionObserver.d.ts",
|
|
69
|
+
"default": "./dist/hooks/useIntersectionObserver.js"
|
|
66
70
|
}
|
|
67
71
|
},
|
|
68
72
|
"files": [
|