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 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 { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
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
- // Week number row generation
34
- const weekNumberRow = useMemo(() => {
35
- if (!showWeekNumber || schedulerData.isVerticalResourceView()) return null;
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 year = localeDayjs(new Date(item.time)).year();
43
- const weekNum = localeDayjs(new Date(item.time)).isoWeek();
44
- const weekKey = `${year}-${weekNum}`;
45
- if (currentWeekKey === weekKey) {
46
- colspan += 1;
47
- } else {
48
- if (currentWeekKey !== null) {
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 weekGroups.map(group => {
78
- if (group.week == null || group.year == null) return null;
79
- return /*#__PURE__*/_jsxs("th", {
80
- colSpan: group.colspan,
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
- ...cellStyle,
83
- width: group.colspan * cellWidth,
84
- minWidth: group.colspan * cellWidth
67
+ position: 'sticky',
68
+ left: 8
85
69
  },
86
- children: ["W", group.week]
87
- }, `week-${group.year}-${group.week}`);
88
- });
89
- }, [showWeekNumber, headers, localeDayjs, config.headerBorderColor, cellWidth, schedulerData]);
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: [weekNumberRow && /*#__PURE__*/_jsx("tr", {
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 = dayjs;
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
  }
@@ -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) + (schedulerData.config.showWeekNumber ? schedulerData.config.weekNumberRowHeight || 0 : 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 + (showWeekNumber ? weekNumberRowHeight : 0);
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 + (showWeekNumber ? weekNumberRowHeight : 0),
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 + (showWeekNumber ? weekNumberRowHeight : 0)
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: [showWeekNumber && /*#__PURE__*/_jsx("tr", {
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,
@@ -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.0",
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",