react-big-schedule 7.1.1-beta.0 → 7.1.1-beta.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.
- package/README.md +38 -1
- package/dist/components/HeaderView.js +41 -49
- package/dist/components/SchedulerData.js +29 -1
- package/dist/components/index.js +16 -7
- package/dist/config/scheduler.js +3 -0
- package/dist/index.d.ts +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -260,6 +260,30 @@ constructor(date=dayjs().format(DATE_FORMAT), viewType = ViewType.Week,
|
|
|
260
260
|
- `localeDayjs` is a locale dayjs object, which is unified used in react-big-scheduler. If not provided, Scheduler will come
|
|
261
261
|
with English(en, United States) locale strings.
|
|
262
262
|
|
|
263
|
+
#### Using SchedulerData with React state
|
|
264
|
+
|
|
265
|
+
`SchedulerData` is mutable; its methods (`prev`, `next`, `setDate`, `setViewType`, `setEvents`, ...) notify the `Scheduler`, which re-renders itself. With a functional component, keep the same instance in state and call the methods in your handlers, then call `setState` with a new object only if you need the parent to re-render too:
|
|
266
|
+
|
|
267
|
+
```jsx
|
|
268
|
+
const [schedulerData, setSchedulerData] = useState(() => new SchedulerData(dayjs(), ViewType.Week));
|
|
269
|
+
|
|
270
|
+
const prevClick = data => {
|
|
271
|
+
data.prev();
|
|
272
|
+
data.setEvents(events);
|
|
273
|
+
setSchedulerData(Object.assign(Object.create(Object.getPrototypeOf(data)), data)); // optional
|
|
274
|
+
};
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
#### Theming with antd `ConfigProvider`
|
|
278
|
+
|
|
279
|
+
The antd parts (header controls, date picker popover, event popover) pick up an antd `ConfigProvider` placed above `<Scheduler>`, so antd theme tokens apply to them. The timeline grid itself is styled by the scheduler's own CSS.
|
|
280
|
+
|
|
281
|
+
```jsx
|
|
282
|
+
<ConfigProvider theme={{ token: { colorPrimary: '#722ed1' } }}>
|
|
283
|
+
<Scheduler schedulerData={schedulerData} /* ... */ />
|
|
284
|
+
</ConfigProvider>
|
|
285
|
+
```
|
|
286
|
+
|
|
263
287
|
#### setSchedulerLocale
|
|
264
288
|
|
|
265
289
|
```js
|
|
@@ -278,6 +302,8 @@ import * as dayjsLocale from 'dayjs/locale/pt-br';
|
|
|
278
302
|
setSchedulerLocale(dayjsLocale);
|
|
279
303
|
```
|
|
280
304
|
|
|
305
|
+
The locale is kept per `SchedulerData` instance, so several schedulers (and your own dayjs usage) can use different locales without affecting each other.
|
|
306
|
+
|
|
281
307
|
By default, Scheduler comes with English(en, United States)
|
|
282
308
|
|
|
283
309
|
#### setCalendarPopoverLocale
|
|
@@ -987,7 +1013,18 @@ slotItemTemplateResolver: PropTypes.func;
|
|
|
987
1013
|
slotItemTemplateResolver(schedulerData, slot, slotClickedFunc, width, clsName);
|
|
988
1014
|
```
|
|
989
1015
|
|
|
990
|
-
Use this function, you can customize the left slot style.
|
|
1016
|
+
Use this function, you can customize the left slot style. The returned element is rendered inside the resource cell, so a resource name can be any React node:
|
|
1017
|
+
|
|
1018
|
+
```jsx
|
|
1019
|
+
<Scheduler
|
|
1020
|
+
schedulerData={schedulerData}
|
|
1021
|
+
slotItemTemplateResolver={(schedulerData, slot, slotClickedFunc, width, clsName) => (
|
|
1022
|
+
<div className={clsName} style={{ width }} onClick={() => slotClickedFunc?.(schedulerData, slot)}>
|
|
1023
|
+
<Avatar size="small" src={slot.avatar} /> <b>{slot.slotName}</b>
|
|
1024
|
+
</div>
|
|
1025
|
+
)}
|
|
1026
|
+
/>
|
|
1027
|
+
```
|
|
991
1028
|
|
|
992
1029
|
#### nonAgendaCellHeaderTemplateResolver
|
|
993
1030
|
|
|
@@ -11,7 +11,7 @@ import { CellUnit } from '../config/default';
|
|
|
11
11
|
* @returns {JSX.Element} A <thead> element containing the optional week-number row and the
|
|
12
12
|
* main header row for the scheduler table.
|
|
13
13
|
*/
|
|
14
|
-
import {
|
|
14
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
15
15
|
function HeaderView({
|
|
16
16
|
schedulerData,
|
|
17
17
|
nonAgendaCellHeaderTemplateResolver
|
|
@@ -24,49 +24,27 @@ function HeaderView({
|
|
|
24
24
|
} = schedulerData;
|
|
25
25
|
const {
|
|
26
26
|
showWeekNumber,
|
|
27
|
-
weekNumberRowHeight = 24
|
|
27
|
+
weekNumberRowHeight = 24,
|
|
28
|
+
showMonthRow,
|
|
29
|
+
monthRowHeight = 24
|
|
28
30
|
} = config;
|
|
29
31
|
const headerHeight = schedulerData.getTableHeaderHeight();
|
|
30
32
|
const cellWidth = schedulerData.getContentCellWidth();
|
|
31
33
|
const minuteStepsInHour = schedulerData.getMinuteStepsInHour();
|
|
32
34
|
|
|
33
|
-
//
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
const weekGroups = [];
|
|
37
|
-
let currentWeekKey = null;
|
|
38
|
-
let currentWeek = null;
|
|
39
|
-
let currentYear = null;
|
|
40
|
-
let colspan = 0;
|
|
35
|
+
// Group consecutive headers sharing a key into spanning <th>s (week number row, month row)
|
|
36
|
+
const buildGroupRow = useCallback((keyOf, labelOf, stickyLabel = false) => {
|
|
37
|
+
const groups = [];
|
|
41
38
|
headers.forEach(item => {
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
weekGroups.push({
|
|
50
|
-
week: currentWeek,
|
|
51
|
-
year: currentYear,
|
|
52
|
-
colspan
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
currentWeekKey = weekKey;
|
|
56
|
-
currentWeek = weekNum;
|
|
57
|
-
currentYear = year;
|
|
58
|
-
colspan = 1;
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
// Push the last week group
|
|
63
|
-
if (currentWeekKey !== null) {
|
|
64
|
-
weekGroups.push({
|
|
65
|
-
week: currentWeek,
|
|
66
|
-
year: currentYear,
|
|
67
|
-
colspan
|
|
39
|
+
const d = localeDayjs(new Date(item.time));
|
|
40
|
+
const key = keyOf(d);
|
|
41
|
+
const last = groups[groups.length - 1];
|
|
42
|
+
if (last && last.key === key) last.colspan += 1;else groups.push({
|
|
43
|
+
key,
|
|
44
|
+
label: labelOf(d),
|
|
45
|
+
colspan: 1
|
|
68
46
|
});
|
|
69
|
-
}
|
|
47
|
+
});
|
|
70
48
|
const cellStyle = {
|
|
71
49
|
fontSize: '0.85em',
|
|
72
50
|
opacity: 0.7,
|
|
@@ -74,19 +52,28 @@ function HeaderView({
|
|
|
74
52
|
padding: '4px 8px',
|
|
75
53
|
textAlign: 'center'
|
|
76
54
|
};
|
|
77
|
-
return
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
55
|
+
return groups.map(group => /*#__PURE__*/_jsx("th", {
|
|
56
|
+
colSpan: group.colspan,
|
|
57
|
+
style: {
|
|
58
|
+
...cellStyle,
|
|
59
|
+
...(stickyLabel && {
|
|
60
|
+
textAlign: 'left'
|
|
61
|
+
}),
|
|
62
|
+
width: group.colspan * cellWidth,
|
|
63
|
+
minWidth: group.colspan * cellWidth
|
|
64
|
+
},
|
|
65
|
+
children: stickyLabel ? /*#__PURE__*/_jsx("span", {
|
|
81
66
|
style: {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
minWidth: group.colspan * cellWidth
|
|
67
|
+
position: 'sticky',
|
|
68
|
+
left: 8
|
|
85
69
|
},
|
|
86
|
-
children:
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
}, [
|
|
70
|
+
children: group.label
|
|
71
|
+
}) : group.label
|
|
72
|
+
}, group.key));
|
|
73
|
+
}, [headers, localeDayjs, config.headerBorderColor, cellWidth]);
|
|
74
|
+
const isGrouped = !schedulerData.isVerticalResourceView();
|
|
75
|
+
const weekNumberRow = useMemo(() => showWeekNumber && isGrouped ? buildGroupRow(d => `w-${d.year()}-${d.isoWeek()}`, d => `W${d.isoWeek()}`) : null, [showWeekNumber, isGrouped, buildGroupRow]);
|
|
76
|
+
const monthRow = useMemo(() => showMonthRow && isGrouped ? buildGroupRow(d => `m-${d.year()}-${d.month()}`, d => d.format('MMMM YYYY'), true) : null, [showMonthRow, isGrouped, buildGroupRow]);
|
|
90
77
|
|
|
91
78
|
// Extract common style creation logic
|
|
92
79
|
const createCellStyle = useCallback((item, width, isLastCell) => {
|
|
@@ -176,7 +163,12 @@ function HeaderView({
|
|
|
176
163
|
});
|
|
177
164
|
}, [cellUnit, headers, minuteStepsInHour, cellWidth, config, localeDayjs, createCellStyle, getCellFormat, renderCellContent, schedulerData.isVerticalResourceView]);
|
|
178
165
|
return /*#__PURE__*/_jsxs("thead", {
|
|
179
|
-
children: [
|
|
166
|
+
children: [monthRow && /*#__PURE__*/_jsx("tr", {
|
|
167
|
+
style: {
|
|
168
|
+
height: monthRowHeight
|
|
169
|
+
},
|
|
170
|
+
children: monthRow
|
|
171
|
+
}), weekNumberRow && /*#__PURE__*/_jsx("tr", {
|
|
180
172
|
style: {
|
|
181
173
|
height: weekNumberRowHeight
|
|
182
174
|
},
|
|
@@ -35,7 +35,7 @@ export default class SchedulerData {
|
|
|
35
35
|
dayjs.extend(weekday);
|
|
36
36
|
dayjs.extend(utc);
|
|
37
37
|
dayjs.extend(isoWeek);
|
|
38
|
-
this.localeDayjs =
|
|
38
|
+
this.localeDayjs = this._createLocaleDayjs();
|
|
39
39
|
this.config = newConfig === undefined ? config : {
|
|
40
40
|
...config,
|
|
41
41
|
...newConfig
|
|
@@ -51,6 +51,23 @@ export default class SchedulerData {
|
|
|
51
51
|
this._createRenderData();
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
// Per-instance dayjs: the locale is applied to each created date instead of the global dayjs
|
|
55
|
+
// singleton, so schedulers (and the host app) don't overwrite each other's locale (#146).
|
|
56
|
+
_createLocaleDayjs() {
|
|
57
|
+
let locale;
|
|
58
|
+
const localeDayjs = (...args) => {
|
|
59
|
+
const d = dayjs(...args);
|
|
60
|
+
return locale ? d.locale(locale) : d;
|
|
61
|
+
};
|
|
62
|
+
localeDayjs.locale = preset => {
|
|
63
|
+
if (preset === undefined) return locale || dayjs.locale();
|
|
64
|
+
// dayjs accepts a locale name or a locale object; resolve (and register) it once to a name
|
|
65
|
+
locale = dayjs().locale(preset).locale();
|
|
66
|
+
return localeDayjs;
|
|
67
|
+
};
|
|
68
|
+
return localeDayjs;
|
|
69
|
+
}
|
|
70
|
+
|
|
54
71
|
/**
|
|
55
72
|
* Update user-facing labels from the i18n provider
|
|
56
73
|
* This allows apps to provide localized labels via setLabelsProvider()
|
|
@@ -439,6 +456,17 @@ export default class SchedulerData {
|
|
|
439
456
|
});
|
|
440
457
|
return resource;
|
|
441
458
|
}
|
|
459
|
+
|
|
460
|
+
// height of the optional group rows (month / week number) rendered above the main header row
|
|
461
|
+
getHeaderGroupRowsHeight() {
|
|
462
|
+
const {
|
|
463
|
+
showMonthRow,
|
|
464
|
+
monthRowHeight = 24,
|
|
465
|
+
showWeekNumber,
|
|
466
|
+
weekNumberRowHeight = 24
|
|
467
|
+
} = this.config;
|
|
468
|
+
return (showMonthRow ? monthRowHeight : 0) + (showWeekNumber ? weekNumberRowHeight : 0);
|
|
469
|
+
}
|
|
442
470
|
getTableHeaderHeight() {
|
|
443
471
|
return this.config.tableHeaderHeight;
|
|
444
472
|
}
|
package/dist/components/index.js
CHANGED
|
@@ -160,7 +160,7 @@ function Scheduler(props) {
|
|
|
160
160
|
const updateHeaderHeight = node => {
|
|
161
161
|
const rect = node.getBoundingClientRect();
|
|
162
162
|
const style = window.getComputedStyle(node);
|
|
163
|
-
const totalHeight = rect.height + (parseFloat(style.marginTop) || 0) + (parseFloat(style.marginBottom) || 0) +
|
|
163
|
+
const totalHeight = rect.height + (parseFloat(style.marginTop) || 0) + (parseFloat(style.marginBottom) || 0) + schedulerData.getHeaderGroupRowsHeight();
|
|
164
164
|
schedulerData._setSchedulerHeaderHeight(totalHeight);
|
|
165
165
|
};
|
|
166
166
|
updateHeaderHeight(schedulerHeaderEl);
|
|
@@ -176,7 +176,7 @@ function Scheduler(props) {
|
|
|
176
176
|
}
|
|
177
177
|
};
|
|
178
178
|
}
|
|
179
|
-
}, [schedulerHeaderEl, schedulerData, schedulerData.config.showWeekNumber, schedulerData.config.weekNumberRowHeight]);
|
|
179
|
+
}, [schedulerHeaderEl, schedulerData, schedulerData.config.showWeekNumber, schedulerData.config.weekNumberRowHeight, schedulerData.config.showMonthRow, schedulerData.config.monthRowHeight]);
|
|
180
180
|
const resolveScrollbarSize = useCallback(() => {
|
|
181
181
|
const prev = scrollbarSizeRef.current;
|
|
182
182
|
const newContentHeight = schedulerContentRef.current ? schedulerContentRef.current.offsetHeight - schedulerContentRef.current.clientHeight : 17;
|
|
@@ -302,7 +302,9 @@ function Scheduler(props) {
|
|
|
302
302
|
const width = schedulerData.getSchedulerWidth();
|
|
303
303
|
const {
|
|
304
304
|
showWeekNumber,
|
|
305
|
-
weekNumberRowHeight
|
|
305
|
+
weekNumberRowHeight,
|
|
306
|
+
showMonthRow,
|
|
307
|
+
monthRowHeight
|
|
306
308
|
} = config;
|
|
307
309
|
const schedulerDataVersion = schedulerData.getVersion ? schedulerData.getVersion() : 0;
|
|
308
310
|
const schedulerWidth = schedulerData.getContentTableWidth();
|
|
@@ -407,7 +409,7 @@ function Scheduler(props) {
|
|
|
407
409
|
margin: `0px -${contentScrollbarWidth}px 0px 0px`
|
|
408
410
|
};
|
|
409
411
|
if (config.schedulerMaxHeight > 0) {
|
|
410
|
-
const totalHeaderHeight = config.tableHeaderHeight + (
|
|
412
|
+
const totalHeaderHeight = config.tableHeaderHeight + schedulerData.getHeaderGroupRowsHeight();
|
|
411
413
|
schedulerContentStyle = {
|
|
412
414
|
...schedulerContentStyle,
|
|
413
415
|
maxHeight: config.schedulerMaxHeight - totalHeaderHeight
|
|
@@ -435,7 +437,7 @@ function Scheduler(props) {
|
|
|
435
437
|
};
|
|
436
438
|
const resourceHeaderStyle = {
|
|
437
439
|
borderBottom: `1px solid ${config.headerBorderColor ?? '#e9e9e9'}`,
|
|
438
|
-
height: config.tableHeaderHeight + (
|
|
440
|
+
height: config.tableHeaderHeight + schedulerData.getHeaderGroupRowsHeight(),
|
|
439
441
|
...configTableHeaderStyle
|
|
440
442
|
};
|
|
441
443
|
const resourceHeaderScrollStyle = {
|
|
@@ -452,7 +454,7 @@ function Scheduler(props) {
|
|
|
452
454
|
const schedulerHeadWrapperStyle = {
|
|
453
455
|
overflow: 'hidden',
|
|
454
456
|
borderBottom: `1px solid ${config.headerBorderColor ?? '#e9e9e9'}`,
|
|
455
|
-
height: config.tableHeaderHeight + (
|
|
457
|
+
height: config.tableHeaderHeight + schedulerData.getHeaderGroupRowsHeight()
|
|
456
458
|
};
|
|
457
459
|
const schedulerHeadScrollStyle = {
|
|
458
460
|
overflowX: 'scroll',
|
|
@@ -475,7 +477,14 @@ function Scheduler(props) {
|
|
|
475
477
|
children: /*#__PURE__*/_jsx("table", {
|
|
476
478
|
className: "resource-table",
|
|
477
479
|
children: /*#__PURE__*/_jsxs("thead", {
|
|
478
|
-
children: [
|
|
480
|
+
children: [showMonthRow && /*#__PURE__*/_jsx("tr", {
|
|
481
|
+
style: {
|
|
482
|
+
height: monthRowHeight
|
|
483
|
+
},
|
|
484
|
+
children: /*#__PURE__*/_jsx("th", {
|
|
485
|
+
style: weekNumberThStyle
|
|
486
|
+
})
|
|
487
|
+
}), showWeekNumber && /*#__PURE__*/_jsx("tr", {
|
|
479
488
|
style: weekNumberRowStyle,
|
|
480
489
|
children: /*#__PURE__*/_jsx("th", {
|
|
481
490
|
style: weekNumberThStyle,
|
package/dist/config/scheduler.js
CHANGED
|
@@ -56,6 +56,9 @@ export default {
|
|
|
56
56
|
headerBorderColor: '#e9e9e9',
|
|
57
57
|
weekNumberRowHeight: 24,
|
|
58
58
|
showWeekNumber: false,
|
|
59
|
+
// month row above the day cells (month names spanning their days), like the week number row
|
|
60
|
+
showMonthRow: false,
|
|
61
|
+
monthRowHeight: 24,
|
|
59
62
|
startResizable: true,
|
|
60
63
|
endResizable: true,
|
|
61
64
|
movable: true,
|
package/dist/index.d.ts
CHANGED
|
@@ -419,6 +419,8 @@ export interface SchedulerDataConfig {
|
|
|
419
419
|
responsiveByParent?: boolean;
|
|
420
420
|
showWeekNumber?: boolean;
|
|
421
421
|
weekNumberRowHeight?: number;
|
|
422
|
+
showMonthRow?: boolean;
|
|
423
|
+
monthRowHeight?: number;
|
|
422
424
|
weekNumberLabel?: string;
|
|
423
425
|
headerBorderColor?: string;
|
|
424
426
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-big-schedule",
|
|
3
|
-
"version": "7.1.1-beta.
|
|
3
|
+
"version": "7.1.1-beta.2",
|
|
4
4
|
"description": "React Big Schedule is a powerful and intuitive scheduler and resource planning solution built with React. Seamlessly integrate this modern browser-compatible component into your applications to effectively manage time, appointments, and resources. With drag-and-drop functionality, interactive UI, and granular views, react-big-schedule empowers users to effortlessly schedule and allocate resources with precision. Enhance productivity and streamline your workflow with this React-based solution, designed to optimize time management and simplify calendar-based operations. Perfect for applications requiring advanced scheduling capabilities, react-big-schedule offers a seamless and intuitive experience for managing appointments, resource allocation, and time slots. Unlock the potential of your React projects with react-big-schedule and revolutionize the way you handle scheduling and resource planning. It is the updated version of react-big-scheduler",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-big-schedule",
|