@fullcalendar/multimonth 6.1.15 → 7.0.0-beta.1

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/index.cjs CHANGED
@@ -10,150 +10,144 @@ var preact_cjs = require('@fullcalendar/core/preact.cjs');
10
10
  class SingleMonth extends internal_cjs.DateComponent {
11
11
  constructor() {
12
12
  super(...arguments);
13
- this.buildDayTableModel = internal_cjs.memoize(internal_cjs$1.buildDayTableModel);
14
13
  this.slicer = new internal_cjs$1.DayTableSlicer();
15
- this.state = {
16
- labelId: internal_cjs.getUniqueDomId(),
17
- };
14
+ // memo
15
+ this.buildDayTableModel = internal_cjs.memoize(internal_cjs$1.buildDayTableModel);
16
+ this.createDayHeaderFormatter = internal_cjs.memoize(internal_cjs$1.createDayHeaderFormatter);
18
17
  }
19
18
  render() {
20
- const { props, state, context } = this;
19
+ const { props, context } = this;
21
20
  const { dateProfile, forPrint } = props;
22
21
  const { options } = context;
23
22
  const dayTableModel = this.buildDayTableModel(dateProfile, context.dateProfileGenerator);
24
23
  const slicedProps = this.slicer.sliceProps(props, dateProfile, options.nextDayThreshold, context, dayTableModel);
25
24
  // ensure single-month has aspect ratio
26
- const tableHeight = props.tableWidth != null ? props.tableWidth / options.aspectRatio : null;
27
- const rowCnt = dayTableModel.cells.length;
25
+ const tableHeight = typeof props.width === 'number'
26
+ ? props.width / options.aspectRatio
27
+ : null;
28
+ const rowCnt = dayTableModel.cellRows.length;
28
29
  const rowHeight = tableHeight != null ? tableHeight / rowCnt : null;
29
- return (preact_cjs.createElement("div", { ref: props.elRef, "data-date": props.isoDateStr, className: "fc-multimonth-month", style: { width: props.width }, role: "grid", "aria-labelledby": state.labelId },
30
+ const dayHeaderFormat = this.createDayHeaderFormatter(context.options.dayHeaderFormat, false, // datesRepDistinctDays
31
+ dayTableModel.colCnt);
32
+ // TODO: tell children if we know dimensions are unstable?
33
+ return (preact_cjs.createElement("div", { "data-date": props.isoDateStr, role: "grid", className: "fc-multimonth-month fc-grow", style: { width: props.width } },
30
34
  preact_cjs.createElement("div", { className: "fc-multimonth-header", style: { marginBottom: rowHeight }, role: "presentation" },
31
- preact_cjs.createElement("div", { className: "fc-multimonth-title", id: state.labelId }, context.dateEnv.format(props.dateProfile.currentRange.start, props.titleFormat)),
32
- preact_cjs.createElement("table", { className: [
33
- 'fc-multimonth-header-table',
34
- context.theme.getClass('table'),
35
- ].join(' '), role: "presentation" },
36
- preact_cjs.createElement("thead", { role: "rowgroup" },
37
- preact_cjs.createElement(internal_cjs.DayHeader, { dateProfile: props.dateProfile, dates: dayTableModel.headerDates, datesRepDistinctDays: false })))),
38
- preact_cjs.createElement("div", { className: [
39
- 'fc-multimonth-daygrid',
40
- 'fc-daygrid',
41
- 'fc-daygrid-body',
42
- !forPrint && 'fc-daygrid-body-balanced',
43
- forPrint && 'fc-daygrid-body-unbalanced',
44
- forPrint && 'fc-daygrid-body-natural',
45
- ].join(' '), style: { marginTop: -rowHeight } },
46
- preact_cjs.createElement("table", { className: [
47
- 'fc-multimonth-daygrid-table',
48
- context.theme.getClass('table'),
49
- ].join(' '), style: { height: forPrint ? '' : tableHeight }, role: "presentation" },
50
- preact_cjs.createElement("tbody", { role: "rowgroup" },
51
- preact_cjs.createElement(internal_cjs$1.TableRows, Object.assign({}, slicedProps, { dateProfile: dateProfile, cells: dayTableModel.cells, eventSelection: props.eventSelection, dayMaxEvents: !forPrint, dayMaxEventRows: !forPrint, showWeekNumbers: options.weekNumbers, clientWidth: props.clientWidth, clientHeight: props.clientHeight, forPrint: forPrint })))))));
35
+ preact_cjs.createElement("div", { className: "fc-multimonth-title" }, context.dateEnv.format(props.dateProfile.currentRange.start, props.titleFormat)),
36
+ preact_cjs.createElement("div", { className: 'fc-multimonth-header-row fc-flex-row' }, dayTableModel.headerDates.map((headerDate) => (preact_cjs.createElement(internal_cjs$1.DayOfWeekHeaderCell, { key: headerDate.getUTCDay(), dow: headerDate.getUTCDay(), dayHeaderFormat: dayHeaderFormat, colWidth: undefined }))))),
37
+ preact_cjs.createElement("div", { className: 'fc-multimonth-body fc-flex-column', style: {
38
+ marginTop: -rowHeight,
39
+ height: forPrint ? '' : tableHeight,
40
+ } },
41
+ preact_cjs.createElement(internal_cjs$1.DayGridRows // .fc-grow
42
+ , { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: dayTableModel.cellRows, forPrint: props.forPrint,
43
+ // content
44
+ fgEventSegs: slicedProps.fgEventSegs, bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventDrag: slicedProps.eventDrag, eventResize: slicedProps.eventResize, eventSelection: slicedProps.eventSelection }))));
52
45
  }
53
46
  }
54
47
 
55
48
  class MultiMonthView extends internal_cjs.DateComponent {
56
49
  constructor() {
57
50
  super(...arguments);
51
+ // memo
58
52
  this.splitDateProfileByMonth = internal_cjs.memoize(splitDateProfileByMonth);
59
53
  this.buildMonthFormat = internal_cjs.memoize(buildMonthFormat);
60
- this.scrollElRef = preact_cjs.createRef();
61
- this.firstMonthElRef = preact_cjs.createRef();
62
- this.needsScrollReset = false;
63
- this.handleSizing = (isForced) => {
64
- if (isForced) {
65
- this.updateSize();
54
+ // ref
55
+ this.scrollerRef = preact_cjs.createRef();
56
+ this.innerElRef = preact_cjs.createRef();
57
+ // internal
58
+ this.scrollDate = null;
59
+ // Sizing
60
+ // -----------------------------------------------------------------------------------------------
61
+ this.handleWidth = (width) => {
62
+ let { xGap, xPadding } = this.state;
63
+ // for first time, assume 2 columns and query gap/padding
64
+ if (xGap == null) {
65
+ const innerEl = this.innerElRef.current;
66
+ const children = innerEl.childNodes;
67
+ if (children.length > 1) {
68
+ const box0 = children[0].getBoundingClientRect();
69
+ const box1 = children[1].getBoundingClientRect();
70
+ let xSpan;
71
+ [xGap, xSpan] = [
72
+ Math.abs(box0.left - box1.right),
73
+ Math.abs(box0.right - box1.left),
74
+ ].sort(internal_cjs.compareNumbers);
75
+ xPadding = width - xSpan;
76
+ }
66
77
  }
78
+ this.setState({ width, xGap, xPadding });
79
+ };
80
+ this.updateScroll = () => {
81
+ if (this.scrollDate != null && this.state.width != null) {
82
+ const scroller = this.scrollerRef.current;
83
+ const innerEl = this.innerElRef.current;
84
+ const monthEl = innerEl.querySelector(`[data-date="${internal_cjs.formatIsoMonthStr(this.scrollDate)}"]`);
85
+ const scrollTop = Math.ceil(// for fractions, err on the side of scrolling further
86
+ monthEl.getBoundingClientRect().top -
87
+ innerEl.getBoundingClientRect().top);
88
+ scroller.scrollTo({ y: scrollTop });
89
+ }
90
+ };
91
+ this.clearScroll = () => {
92
+ this.scrollDate = null;
67
93
  };
68
94
  }
69
95
  render() {
70
96
  const { context, props, state } = this;
71
97
  const { options } = context;
72
- const { clientWidth, clientHeight } = state;
73
- const monthHPadding = state.monthHPadding || 0;
74
- const colCount = Math.min(clientWidth != null ?
75
- Math.floor(clientWidth / (options.multiMonthMinWidth + monthHPadding)) :
76
- 1, options.multiMonthMaxColumns) || 1;
77
- const monthWidthPct = (100 / colCount) + '%';
78
- const monthTableWidth = clientWidth == null ? null :
79
- (clientWidth / colCount) - monthHPadding;
80
- const isLegitSingleCol = clientWidth != null && colCount === 1;
81
- const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv, isLegitSingleCol ? false : options.fixedWeekCount, options.showNonCurrentDates);
98
+ const verticalScrolling = !props.forPrint && !internal_cjs.getIsHeightAuto(options);
99
+ const colCount = state.width == null
100
+ ? 2
101
+ : Math.min(options.multiMonthMaxColumns, Math.floor((state.width - state.xPadding + state.xGap) /
102
+ (options.multiMonthMinWidth + state.xGap)));
103
+ const monthWidth = state.width == null
104
+ ? '34%' // will expand. now small enough to be 1/3. for allowing gap
105
+ : Math.floor(// exact values can cause expansion to other rows
106
+ (state.width - state.xPadding - (state.xGap * (colCount - 1))) /
107
+ colCount);
108
+ const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv, options.fixedWeekCount, options.showNonCurrentDates);
82
109
  const monthTitleFormat = this.buildMonthFormat(options.multiMonthTitleFormat, monthDateProfiles);
83
110
  const rootClassNames = [
84
- 'fc-multimonth',
85
- isLegitSingleCol ?
111
+ 'fc-multimonth-view',
112
+ (colCount === 1) ?
86
113
  'fc-multimonth-singlecol' :
87
114
  'fc-multimonth-multicol',
88
- (monthTableWidth != null && monthTableWidth < 400) ?
89
- 'fc-multimonth-compact' :
90
- '',
91
- props.isHeightAuto ?
92
- '' :
93
- 'fc-scroller', // for AutoScroller
115
+ 'fc-flex-column',
116
+ 'fc-border', // BAD to mix this with size-listening?
94
117
  ];
95
- return (preact_cjs.createElement(internal_cjs.ViewContainer, { elRef: this.scrollElRef, elClasses: rootClassNames, viewSpec: context.viewSpec }, monthDateProfiles.map((monthDateProfile, i) => {
96
- const monthStr = internal_cjs.formatIsoMonthStr(monthDateProfile.currentRange.start);
97
- return (preact_cjs.createElement(SingleMonth, Object.assign({}, props, { key: monthStr, isoDateStr: monthStr, elRef: i === 0 ? this.firstMonthElRef : undefined, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: monthWidthPct, tableWidth: monthTableWidth, clientWidth: clientWidth, clientHeight: clientHeight })));
98
- })));
118
+ return (preact_cjs.createElement(internal_cjs.NowTimer, { unit: "day" }, (nowDate, todayRange) => (preact_cjs.createElement(internal_cjs.ViewContainer, { elClasses: rootClassNames, viewSpec: context.viewSpec },
119
+ preact_cjs.createElement(internal_cjs.Scroller, { vertical: verticalScrolling, elClassNames: [
120
+ verticalScrolling ? 'fc-liquid' : '',
121
+ ], ref: this.scrollerRef, widthRef: this.handleWidth },
122
+ preact_cjs.createElement("div", { ref: this.innerElRef, className: 'fc-multimonth-inner' }, monthDateProfiles.map((monthDateProfile, i) => {
123
+ const monthStr = internal_cjs.formatIsoMonthStr(monthDateProfile.currentRange.start);
124
+ return (preact_cjs.createElement(SingleMonth, Object.assign({}, props, { key: monthStr, todayRange: todayRange, isoDateStr: monthStr, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: monthWidth })));
125
+ })))))));
99
126
  }
127
+ // Lifecycle
128
+ // -----------------------------------------------------------------------------------------------
100
129
  componentDidMount() {
101
- this.updateSize();
102
- this.context.addResizeHandler(this.handleSizing);
103
- this.requestScrollReset();
130
+ this.resetScroll();
131
+ this.scrollerRef.current.addScrollEndListener(this.clearScroll);
104
132
  }
105
133
  componentDidUpdate(prevProps) {
106
- if (!internal_cjs.isPropsEqual(prevProps, this.props)) { // an external change?
107
- this.handleSizing(false);
108
- }
109
- if (prevProps.dateProfile !== this.props.dateProfile) {
110
- this.requestScrollReset();
134
+ if (prevProps.dateProfile !== this.props.dateProfile && this.context.options.scrollTimeReset) {
135
+ this.resetScroll();
111
136
  }
112
137
  else {
113
- this.flushScrollReset();
138
+ // NOT optimal to update so often
139
+ // TODO: isolate dependencies of scroll coordinate
140
+ this.updateScroll();
114
141
  }
115
142
  }
116
143
  componentWillUnmount() {
117
- this.context.removeResizeHandler(this.handleSizing);
118
- }
119
- updateSize() {
120
- const scrollEl = this.scrollElRef.current;
121
- const firstMonthEl = this.firstMonthElRef.current;
122
- if (scrollEl) {
123
- this.setState({
124
- clientWidth: scrollEl.clientWidth,
125
- clientHeight: scrollEl.clientHeight,
126
- });
127
- }
128
- if (firstMonthEl && scrollEl) {
129
- if (this.state.monthHPadding == null) { // always remember initial non-zero value
130
- this.setState({
131
- monthHPadding: scrollEl.clientWidth - // go within padding
132
- firstMonthEl.firstChild.offsetWidth,
133
- });
134
- }
135
- }
136
- }
137
- requestScrollReset() {
138
- this.needsScrollReset = true;
139
- this.flushScrollReset();
140
- }
141
- flushScrollReset() {
142
- if (this.needsScrollReset &&
143
- this.state.monthHPadding != null // indicates sizing already happened
144
- ) {
145
- const { currentDate } = this.props.dateProfile;
146
- const scrollEl = this.scrollElRef.current;
147
- const monthEl = scrollEl.querySelector(`[data-date="${internal_cjs.formatIsoMonthStr(currentDate)}"]`);
148
- scrollEl.scrollTop = monthEl.getBoundingClientRect().top -
149
- this.firstMonthElRef.current.getBoundingClientRect().top;
150
- this.needsScrollReset = false;
151
- }
144
+ this.scrollerRef.current.removeScrollEndListener(this.clearScroll);
152
145
  }
153
- // workaround for when queued setState render (w/ clientWidth) gets cancelled because
154
- // subsequent update and shouldComponentUpdate says not to render :(
155
- shouldComponentUpdate() {
156
- return true;
146
+ // Scrolling
147
+ // -----------------------------------------------------------------------------------------------
148
+ resetScroll() {
149
+ this.scrollDate = this.props.dateProfile.currentDate;
150
+ this.updateScroll();
157
151
  }
158
152
  }
159
153
  // date profile
@@ -219,7 +213,7 @@ const OPTION_REFINERS = {
219
213
  multiMonthMinWidth: Number,
220
214
  };
221
215
 
222
- var css_248z = ".fc .fc-multimonth{border:1px solid var(--fc-border-color);display:flex;flex-wrap:wrap;overflow-x:hidden;overflow-y:auto}.fc .fc-multimonth-title{font-size:1.2em;font-weight:700;padding:1em 0;text-align:center}.fc .fc-multimonth-daygrid{background:var(--fc-page-bg-color)}.fc .fc-multimonth-daygrid-table,.fc .fc-multimonth-header-table{table-layout:fixed;width:100%}.fc .fc-multimonth-daygrid-table{border-top-style:hidden!important}.fc .fc-multimonth-singlecol .fc-multimonth{position:relative}.fc .fc-multimonth-singlecol .fc-multimonth-header{background:var(--fc-page-bg-color);position:relative;top:0;z-index:2}.fc .fc-multimonth-singlecol .fc-multimonth-daygrid{position:relative;z-index:1}.fc .fc-multimonth-singlecol .fc-multimonth-daygrid-table,.fc .fc-multimonth-singlecol .fc-multimonth-header-table{border-left-style:hidden;border-right-style:hidden}.fc .fc-multimonth-singlecol .fc-multimonth-month:last-child .fc-multimonth-daygrid-table{border-bottom-style:hidden}.fc .fc-multimonth-multicol{line-height:1}.fc .fc-multimonth-multicol .fc-multimonth-month{padding:0 1.2em 1.2em}.fc .fc-multimonth-multicol .fc-daygrid-more-link{border:1px solid var(--fc-event-border-color);display:block;float:none;padding:1px}.fc .fc-multimonth-compact{line-height:1}.fc .fc-multimonth-compact .fc-multimonth-daygrid-table,.fc .fc-multimonth-compact .fc-multimonth-header-table{font-size:.9em}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-header{position:sticky}.fc-media-print .fc-multimonth{overflow:visible}";
216
+ var css_248z = ".fc-multimonth-inner{display:flex;flex-wrap:wrap}.fc-multimonth-multicol .fc-multimonth-month{margin:0 1.2em 1.2em}.fc-multimonth-multicol .fc-multimonth-title{padding:1em 0}.fc-multimonth-singlecol .fc-multimonth-title{padding:.5em 0}.fc-multimonth-title{font-size:1.2em;font-weight:700;text-align:center}.fc-multimonth-header-row{border-top:1px solid var(--fc-border-color)}.fc-multimonth-header-row,.fc-multimonth-month{border-bottom:1px solid var(--fc-border-color)}.fc-multimonth-singlecol .fc-multimonth-month:last-child{border-bottom:0}.fc-multimonth-multicol .fc-multimonth-body,.fc-multimonth-multicol .fc-multimonth-header-row{border-left:1px solid var(--fc-border-color);border-right:1px solid var(--fc-border-color);font-size:.9em;line-height:1}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-header{background:var(--fc-page-bg-color);position:sticky;top:0;z-index:2}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-body{position:relative;z-index:1}";
223
217
  internal_cjs.injectStyles(css_248z);
224
218
 
225
219
  var index = index_cjs.createPlugin({
package/index.global.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- FullCalendar Multi-Month Plugin v6.1.15
2
+ FullCalendar Multi-Month Plugin v7.0.0-beta.1
3
3
  Docs & License: https://fullcalendar.io/docs/multimonth-grid
4
4
  (c) 2024 Adam Shaw
5
5
  */
@@ -9,150 +9,144 @@ FullCalendar.MultiMonth = (function (exports, core, internal$1, internal, preact
9
9
  class SingleMonth extends internal.DateComponent {
10
10
  constructor() {
11
11
  super(...arguments);
12
- this.buildDayTableModel = internal.memoize(internal$1.buildDayTableModel);
13
12
  this.slicer = new internal$1.DayTableSlicer();
14
- this.state = {
15
- labelId: internal.getUniqueDomId(),
16
- };
13
+ // memo
14
+ this.buildDayTableModel = internal.memoize(internal$1.buildDayTableModel);
15
+ this.createDayHeaderFormatter = internal.memoize(internal$1.createDayHeaderFormatter);
17
16
  }
18
17
  render() {
19
- const { props, state, context } = this;
18
+ const { props, context } = this;
20
19
  const { dateProfile, forPrint } = props;
21
20
  const { options } = context;
22
21
  const dayTableModel = this.buildDayTableModel(dateProfile, context.dateProfileGenerator);
23
22
  const slicedProps = this.slicer.sliceProps(props, dateProfile, options.nextDayThreshold, context, dayTableModel);
24
23
  // ensure single-month has aspect ratio
25
- const tableHeight = props.tableWidth != null ? props.tableWidth / options.aspectRatio : null;
26
- const rowCnt = dayTableModel.cells.length;
24
+ const tableHeight = typeof props.width === 'number'
25
+ ? props.width / options.aspectRatio
26
+ : null;
27
+ const rowCnt = dayTableModel.cellRows.length;
27
28
  const rowHeight = tableHeight != null ? tableHeight / rowCnt : null;
28
- return (preact.createElement("div", { ref: props.elRef, "data-date": props.isoDateStr, className: "fc-multimonth-month", style: { width: props.width }, role: "grid", "aria-labelledby": state.labelId },
29
+ const dayHeaderFormat = this.createDayHeaderFormatter(context.options.dayHeaderFormat, false, // datesRepDistinctDays
30
+ dayTableModel.colCnt);
31
+ // TODO: tell children if we know dimensions are unstable?
32
+ return (preact.createElement("div", { "data-date": props.isoDateStr, role: "grid", className: "fc-multimonth-month fc-grow", style: { width: props.width } },
29
33
  preact.createElement("div", { className: "fc-multimonth-header", style: { marginBottom: rowHeight }, role: "presentation" },
30
- preact.createElement("div", { className: "fc-multimonth-title", id: state.labelId }, context.dateEnv.format(props.dateProfile.currentRange.start, props.titleFormat)),
31
- preact.createElement("table", { className: [
32
- 'fc-multimonth-header-table',
33
- context.theme.getClass('table'),
34
- ].join(' '), role: "presentation" },
35
- preact.createElement("thead", { role: "rowgroup" },
36
- preact.createElement(internal.DayHeader, { dateProfile: props.dateProfile, dates: dayTableModel.headerDates, datesRepDistinctDays: false })))),
37
- preact.createElement("div", { className: [
38
- 'fc-multimonth-daygrid',
39
- 'fc-daygrid',
40
- 'fc-daygrid-body',
41
- !forPrint && 'fc-daygrid-body-balanced',
42
- forPrint && 'fc-daygrid-body-unbalanced',
43
- forPrint && 'fc-daygrid-body-natural',
44
- ].join(' '), style: { marginTop: -rowHeight } },
45
- preact.createElement("table", { className: [
46
- 'fc-multimonth-daygrid-table',
47
- context.theme.getClass('table'),
48
- ].join(' '), style: { height: forPrint ? '' : tableHeight }, role: "presentation" },
49
- preact.createElement("tbody", { role: "rowgroup" },
50
- preact.createElement(internal$1.TableRows, Object.assign({}, slicedProps, { dateProfile: dateProfile, cells: dayTableModel.cells, eventSelection: props.eventSelection, dayMaxEvents: !forPrint, dayMaxEventRows: !forPrint, showWeekNumbers: options.weekNumbers, clientWidth: props.clientWidth, clientHeight: props.clientHeight, forPrint: forPrint })))))));
34
+ preact.createElement("div", { className: "fc-multimonth-title" }, context.dateEnv.format(props.dateProfile.currentRange.start, props.titleFormat)),
35
+ preact.createElement("div", { className: 'fc-multimonth-header-row fc-flex-row' }, dayTableModel.headerDates.map((headerDate) => (preact.createElement(internal$1.DayOfWeekHeaderCell, { key: headerDate.getUTCDay(), dow: headerDate.getUTCDay(), dayHeaderFormat: dayHeaderFormat, colWidth: undefined }))))),
36
+ preact.createElement("div", { className: 'fc-multimonth-body fc-flex-column', style: {
37
+ marginTop: -rowHeight,
38
+ height: forPrint ? '' : tableHeight,
39
+ } },
40
+ preact.createElement(internal$1.DayGridRows // .fc-grow
41
+ , { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: dayTableModel.cellRows, forPrint: props.forPrint,
42
+ // content
43
+ fgEventSegs: slicedProps.fgEventSegs, bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventDrag: slicedProps.eventDrag, eventResize: slicedProps.eventResize, eventSelection: slicedProps.eventSelection }))));
51
44
  }
52
45
  }
53
46
 
54
47
  class MultiMonthView extends internal.DateComponent {
55
48
  constructor() {
56
49
  super(...arguments);
50
+ // memo
57
51
  this.splitDateProfileByMonth = internal.memoize(splitDateProfileByMonth);
58
52
  this.buildMonthFormat = internal.memoize(buildMonthFormat);
59
- this.scrollElRef = preact.createRef();
60
- this.firstMonthElRef = preact.createRef();
61
- this.needsScrollReset = false;
62
- this.handleSizing = (isForced) => {
63
- if (isForced) {
64
- this.updateSize();
53
+ // ref
54
+ this.scrollerRef = preact.createRef();
55
+ this.innerElRef = preact.createRef();
56
+ // internal
57
+ this.scrollDate = null;
58
+ // Sizing
59
+ // -----------------------------------------------------------------------------------------------
60
+ this.handleWidth = (width) => {
61
+ let { xGap, xPadding } = this.state;
62
+ // for first time, assume 2 columns and query gap/padding
63
+ if (xGap == null) {
64
+ const innerEl = this.innerElRef.current;
65
+ const children = innerEl.childNodes;
66
+ if (children.length > 1) {
67
+ const box0 = children[0].getBoundingClientRect();
68
+ const box1 = children[1].getBoundingClientRect();
69
+ let xSpan;
70
+ [xGap, xSpan] = [
71
+ Math.abs(box0.left - box1.right),
72
+ Math.abs(box0.right - box1.left),
73
+ ].sort(internal.compareNumbers);
74
+ xPadding = width - xSpan;
75
+ }
65
76
  }
77
+ this.setState({ width, xGap, xPadding });
78
+ };
79
+ this.updateScroll = () => {
80
+ if (this.scrollDate != null && this.state.width != null) {
81
+ const scroller = this.scrollerRef.current;
82
+ const innerEl = this.innerElRef.current;
83
+ const monthEl = innerEl.querySelector(`[data-date="${internal.formatIsoMonthStr(this.scrollDate)}"]`);
84
+ const scrollTop = Math.ceil(// for fractions, err on the side of scrolling further
85
+ monthEl.getBoundingClientRect().top -
86
+ innerEl.getBoundingClientRect().top);
87
+ scroller.scrollTo({ y: scrollTop });
88
+ }
89
+ };
90
+ this.clearScroll = () => {
91
+ this.scrollDate = null;
66
92
  };
67
93
  }
68
94
  render() {
69
95
  const { context, props, state } = this;
70
96
  const { options } = context;
71
- const { clientWidth, clientHeight } = state;
72
- const monthHPadding = state.monthHPadding || 0;
73
- const colCount = Math.min(clientWidth != null ?
74
- Math.floor(clientWidth / (options.multiMonthMinWidth + monthHPadding)) :
75
- 1, options.multiMonthMaxColumns) || 1;
76
- const monthWidthPct = (100 / colCount) + '%';
77
- const monthTableWidth = clientWidth == null ? null :
78
- (clientWidth / colCount) - monthHPadding;
79
- const isLegitSingleCol = clientWidth != null && colCount === 1;
80
- const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv, isLegitSingleCol ? false : options.fixedWeekCount, options.showNonCurrentDates);
97
+ const verticalScrolling = !props.forPrint && !internal.getIsHeightAuto(options);
98
+ const colCount = state.width == null
99
+ ? 2
100
+ : Math.min(options.multiMonthMaxColumns, Math.floor((state.width - state.xPadding + state.xGap) /
101
+ (options.multiMonthMinWidth + state.xGap)));
102
+ const monthWidth = state.width == null
103
+ ? '34%' // will expand. now small enough to be 1/3. for allowing gap
104
+ : Math.floor(// exact values can cause expansion to other rows
105
+ (state.width - state.xPadding - (state.xGap * (colCount - 1))) /
106
+ colCount);
107
+ const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv, options.fixedWeekCount, options.showNonCurrentDates);
81
108
  const monthTitleFormat = this.buildMonthFormat(options.multiMonthTitleFormat, monthDateProfiles);
82
109
  const rootClassNames = [
83
- 'fc-multimonth',
84
- isLegitSingleCol ?
110
+ 'fc-multimonth-view',
111
+ (colCount === 1) ?
85
112
  'fc-multimonth-singlecol' :
86
113
  'fc-multimonth-multicol',
87
- (monthTableWidth != null && monthTableWidth < 400) ?
88
- 'fc-multimonth-compact' :
89
- '',
90
- props.isHeightAuto ?
91
- '' :
92
- 'fc-scroller', // for AutoScroller
114
+ 'fc-flex-column',
115
+ 'fc-border', // BAD to mix this with size-listening?
93
116
  ];
94
- return (preact.createElement(internal.ViewContainer, { elRef: this.scrollElRef, elClasses: rootClassNames, viewSpec: context.viewSpec }, monthDateProfiles.map((monthDateProfile, i) => {
95
- const monthStr = internal.formatIsoMonthStr(monthDateProfile.currentRange.start);
96
- return (preact.createElement(SingleMonth, Object.assign({}, props, { key: monthStr, isoDateStr: monthStr, elRef: i === 0 ? this.firstMonthElRef : undefined, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: monthWidthPct, tableWidth: monthTableWidth, clientWidth: clientWidth, clientHeight: clientHeight })));
97
- })));
117
+ return (preact.createElement(internal.NowTimer, { unit: "day" }, (nowDate, todayRange) => (preact.createElement(internal.ViewContainer, { elClasses: rootClassNames, viewSpec: context.viewSpec },
118
+ preact.createElement(internal.Scroller, { vertical: verticalScrolling, elClassNames: [
119
+ verticalScrolling ? 'fc-liquid' : '',
120
+ ], ref: this.scrollerRef, widthRef: this.handleWidth },
121
+ preact.createElement("div", { ref: this.innerElRef, className: 'fc-multimonth-inner' }, monthDateProfiles.map((monthDateProfile, i) => {
122
+ const monthStr = internal.formatIsoMonthStr(monthDateProfile.currentRange.start);
123
+ return (preact.createElement(SingleMonth, Object.assign({}, props, { key: monthStr, todayRange: todayRange, isoDateStr: monthStr, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: monthWidth })));
124
+ })))))));
98
125
  }
126
+ // Lifecycle
127
+ // -----------------------------------------------------------------------------------------------
99
128
  componentDidMount() {
100
- this.updateSize();
101
- this.context.addResizeHandler(this.handleSizing);
102
- this.requestScrollReset();
129
+ this.resetScroll();
130
+ this.scrollerRef.current.addScrollEndListener(this.clearScroll);
103
131
  }
104
132
  componentDidUpdate(prevProps) {
105
- if (!internal.isPropsEqual(prevProps, this.props)) { // an external change?
106
- this.handleSizing(false);
107
- }
108
- if (prevProps.dateProfile !== this.props.dateProfile) {
109
- this.requestScrollReset();
133
+ if (prevProps.dateProfile !== this.props.dateProfile && this.context.options.scrollTimeReset) {
134
+ this.resetScroll();
110
135
  }
111
136
  else {
112
- this.flushScrollReset();
137
+ // NOT optimal to update so often
138
+ // TODO: isolate dependencies of scroll coordinate
139
+ this.updateScroll();
113
140
  }
114
141
  }
115
142
  componentWillUnmount() {
116
- this.context.removeResizeHandler(this.handleSizing);
117
- }
118
- updateSize() {
119
- const scrollEl = this.scrollElRef.current;
120
- const firstMonthEl = this.firstMonthElRef.current;
121
- if (scrollEl) {
122
- this.setState({
123
- clientWidth: scrollEl.clientWidth,
124
- clientHeight: scrollEl.clientHeight,
125
- });
126
- }
127
- if (firstMonthEl && scrollEl) {
128
- if (this.state.monthHPadding == null) { // always remember initial non-zero value
129
- this.setState({
130
- monthHPadding: scrollEl.clientWidth - // go within padding
131
- firstMonthEl.firstChild.offsetWidth,
132
- });
133
- }
134
- }
135
- }
136
- requestScrollReset() {
137
- this.needsScrollReset = true;
138
- this.flushScrollReset();
139
- }
140
- flushScrollReset() {
141
- if (this.needsScrollReset &&
142
- this.state.monthHPadding != null // indicates sizing already happened
143
- ) {
144
- const { currentDate } = this.props.dateProfile;
145
- const scrollEl = this.scrollElRef.current;
146
- const monthEl = scrollEl.querySelector(`[data-date="${internal.formatIsoMonthStr(currentDate)}"]`);
147
- scrollEl.scrollTop = monthEl.getBoundingClientRect().top -
148
- this.firstMonthElRef.current.getBoundingClientRect().top;
149
- this.needsScrollReset = false;
150
- }
143
+ this.scrollerRef.current.removeScrollEndListener(this.clearScroll);
151
144
  }
152
- // workaround for when queued setState render (w/ clientWidth) gets cancelled because
153
- // subsequent update and shouldComponentUpdate says not to render :(
154
- shouldComponentUpdate() {
155
- return true;
145
+ // Scrolling
146
+ // -----------------------------------------------------------------------------------------------
147
+ resetScroll() {
148
+ this.scrollDate = this.props.dateProfile.currentDate;
149
+ this.updateScroll();
156
150
  }
157
151
  }
158
152
  // date profile
@@ -218,7 +212,7 @@ FullCalendar.MultiMonth = (function (exports, core, internal$1, internal, preact
218
212
  multiMonthMinWidth: Number,
219
213
  };
220
214
 
221
- var css_248z = ".fc .fc-multimonth{border:1px solid var(--fc-border-color);display:flex;flex-wrap:wrap;overflow-x:hidden;overflow-y:auto}.fc .fc-multimonth-title{font-size:1.2em;font-weight:700;padding:1em 0;text-align:center}.fc .fc-multimonth-daygrid{background:var(--fc-page-bg-color)}.fc .fc-multimonth-daygrid-table,.fc .fc-multimonth-header-table{table-layout:fixed;width:100%}.fc .fc-multimonth-daygrid-table{border-top-style:hidden!important}.fc .fc-multimonth-singlecol .fc-multimonth{position:relative}.fc .fc-multimonth-singlecol .fc-multimonth-header{background:var(--fc-page-bg-color);position:relative;top:0;z-index:2}.fc .fc-multimonth-singlecol .fc-multimonth-daygrid{position:relative;z-index:1}.fc .fc-multimonth-singlecol .fc-multimonth-daygrid-table,.fc .fc-multimonth-singlecol .fc-multimonth-header-table{border-left-style:hidden;border-right-style:hidden}.fc .fc-multimonth-singlecol .fc-multimonth-month:last-child .fc-multimonth-daygrid-table{border-bottom-style:hidden}.fc .fc-multimonth-multicol{line-height:1}.fc .fc-multimonth-multicol .fc-multimonth-month{padding:0 1.2em 1.2em}.fc .fc-multimonth-multicol .fc-daygrid-more-link{border:1px solid var(--fc-event-border-color);display:block;float:none;padding:1px}.fc .fc-multimonth-compact{line-height:1}.fc .fc-multimonth-compact .fc-multimonth-daygrid-table,.fc .fc-multimonth-compact .fc-multimonth-header-table{font-size:.9em}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-header{position:sticky}.fc-media-print .fc-multimonth{overflow:visible}";
215
+ var css_248z = ".fc-multimonth-inner{display:flex;flex-wrap:wrap}.fc-multimonth-multicol .fc-multimonth-month{margin:0 1.2em 1.2em}.fc-multimonth-multicol .fc-multimonth-title{padding:1em 0}.fc-multimonth-singlecol .fc-multimonth-title{padding:.5em 0}.fc-multimonth-title{font-size:1.2em;font-weight:700;text-align:center}.fc-multimonth-header-row{border-top:1px solid var(--fc-border-color)}.fc-multimonth-header-row,.fc-multimonth-month{border-bottom:1px solid var(--fc-border-color)}.fc-multimonth-singlecol .fc-multimonth-month:last-child{border-bottom:0}.fc-multimonth-multicol .fc-multimonth-body,.fc-multimonth-multicol .fc-multimonth-header-row{border-left:1px solid var(--fc-border-color);border-right:1px solid var(--fc-border-color);font-size:.9em;line-height:1}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-header{background:var(--fc-page-bg-color);position:sticky;top:0;z-index:2}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-body{position:relative;z-index:1}";
222
216
  internal.injectStyles(css_248z);
223
217
 
224
218
  var plugin = core.createPlugin({
@@ -1,6 +1,6 @@
1
1
  /*!
2
- FullCalendar Multi-Month Plugin v6.1.15
2
+ FullCalendar Multi-Month Plugin v7.0.0-beta.1
3
3
  Docs & License: https://fullcalendar.io/docs/multimonth-grid
4
4
  (c) 2024 Adam Shaw
5
5
  */
6
- FullCalendar.MultiMonth=function(t,e,l,i,n){"use strict";class o extends i.DateComponent{constructor(){super(...arguments),this.buildDayTableModel=i.memoize(l.buildDayTableModel),this.slicer=new l.DayTableSlicer,this.state={labelId:i.getUniqueDomId()}}render(){const{props:t,state:e,context:o}=this,{dateProfile:a,forPrint:r}=t,{options:s}=o,c=this.buildDayTableModel(a,o.dateProfileGenerator),d=this.slicer.sliceProps(t,a,s.nextDayThreshold,o,c),m=null!=t.tableWidth?t.tableWidth/s.aspectRatio:null,h=c.cells.length,u=null!=m?m/h:null;return n.createElement("div",{ref:t.elRef,"data-date":t.isoDateStr,className:"fc-multimonth-month",style:{width:t.width},role:"grid","aria-labelledby":e.labelId},n.createElement("div",{className:"fc-multimonth-header",style:{marginBottom:u},role:"presentation"},n.createElement("div",{className:"fc-multimonth-title",id:e.labelId},o.dateEnv.format(t.dateProfile.currentRange.start,t.titleFormat)),n.createElement("table",{className:["fc-multimonth-header-table",o.theme.getClass("table")].join(" "),role:"presentation"},n.createElement("thead",{role:"rowgroup"},n.createElement(i.DayHeader,{dateProfile:t.dateProfile,dates:c.headerDates,datesRepDistinctDays:!1})))),n.createElement("div",{className:["fc-multimonth-daygrid","fc-daygrid","fc-daygrid-body",!r&&"fc-daygrid-body-balanced",r&&"fc-daygrid-body-unbalanced",r&&"fc-daygrid-body-natural"].join(" "),style:{marginTop:-u}},n.createElement("table",{className:["fc-multimonth-daygrid-table",o.theme.getClass("table")].join(" "),style:{height:r?"":m},role:"presentation"},n.createElement("tbody",{role:"rowgroup"},n.createElement(l.TableRows,Object.assign({},d,{dateProfile:a,cells:c.cells,eventSelection:t.eventSelection,dayMaxEvents:!r,dayMaxEventRows:!r,showWeekNumbers:s.weekNumbers,clientWidth:t.clientWidth,clientHeight:t.clientHeight,forPrint:r}))))))}}class a extends i.DateComponent{constructor(){super(...arguments),this.splitDateProfileByMonth=i.memoize(s),this.buildMonthFormat=i.memoize(m),this.scrollElRef=n.createRef(),this.firstMonthElRef=n.createRef(),this.needsScrollReset=!1,this.handleSizing=t=>{t&&this.updateSize()}}render(){const{context:t,props:e,state:l}=this,{options:a}=t,{clientWidth:r,clientHeight:s}=l,c=l.monthHPadding||0,d=Math.min(null!=r?Math.floor(r/(a.multiMonthMinWidth+c)):1,a.multiMonthMaxColumns)||1,m=100/d+"%",h=null==r?null:r/d-c,u=null!=r&&1===d,f=this.splitDateProfileByMonth(t.dateProfileGenerator,e.dateProfile,t.dateEnv,!u&&a.fixedWeekCount,a.showNonCurrentDates),g=this.buildMonthFormat(a.multiMonthTitleFormat,f),p=["fc-multimonth",u?"fc-multimonth-singlecol":"fc-multimonth-multicol",null!=h&&h<400?"fc-multimonth-compact":"",e.isHeightAuto?"":"fc-scroller"];return n.createElement(i.ViewContainer,{elRef:this.scrollElRef,elClasses:p,viewSpec:t.viewSpec},f.map((t,l)=>{const a=i.formatIsoMonthStr(t.currentRange.start);return n.createElement(o,Object.assign({},e,{key:a,isoDateStr:a,elRef:0===l?this.firstMonthElRef:void 0,titleFormat:g,dateProfile:t,width:m,tableWidth:h,clientWidth:r,clientHeight:s}))}))}componentDidMount(){this.updateSize(),this.context.addResizeHandler(this.handleSizing),this.requestScrollReset()}componentDidUpdate(t){i.isPropsEqual(t,this.props)||this.handleSizing(!1),t.dateProfile!==this.props.dateProfile?this.requestScrollReset():this.flushScrollReset()}componentWillUnmount(){this.context.removeResizeHandler(this.handleSizing)}updateSize(){const t=this.scrollElRef.current,e=this.firstMonthElRef.current;t&&this.setState({clientWidth:t.clientWidth,clientHeight:t.clientHeight}),e&&t&&null==this.state.monthHPadding&&this.setState({monthHPadding:t.clientWidth-e.firstChild.offsetWidth})}requestScrollReset(){this.needsScrollReset=!0,this.flushScrollReset()}flushScrollReset(){if(this.needsScrollReset&&null!=this.state.monthHPadding){const{currentDate:t}=this.props.dateProfile,e=this.scrollElRef.current,l=e.querySelector(`[data-date="${i.formatIsoMonthStr(t)}"]`);e.scrollTop=l.getBoundingClientRect().top-this.firstMonthElRef.current.getBoundingClientRect().top,this.needsScrollReset=!1}}shouldComponentUpdate(){return!0}}const r=i.createDuration(1,"month");function s(t,e,n,o,a){const{start:s,end:c}=e.currentRange;let d=s;const m=[];for(;d.valueOf()<c.valueOf();){const s=n.add(d,r),c={start:t.skipHiddenDays(d),end:t.skipHiddenDays(s,-1,!0)};let h=l.buildDayTableRenderRange({currentRange:c,snapToWeek:!0,fixedWeekCount:o,dateEnv:n});h={start:t.skipHiddenDays(h.start),end:t.skipHiddenDays(h.end,-1,!0)};const u=e.activeRange?i.intersectRanges(e.activeRange,a?h:c):null;m.push({currentDate:e.currentDate,isValid:e.isValid,validRange:e.validRange,renderRange:h,activeRange:u,currentRange:c,currentRangeUnit:"month",isRangeAllDay:!0,dateIncrement:e.dateIncrement,slotMinTime:e.slotMaxTime,slotMaxTime:e.slotMinTime}),d=s}return m}const c=i.createFormatter({year:"numeric",month:"long"}),d=i.createFormatter({month:"long"});function m(t,e){return t||(e[0].currentRange.start.getUTCFullYear()!==e[e.length-1].currentRange.start.getUTCFullYear()?c:d)}const h={multiMonthTitleFormat:i.createFormatter,multiMonthMaxColumns:Number,multiMonthMinWidth:Number};i.injectStyles(".fc .fc-multimonth{border:1px solid var(--fc-border-color);display:flex;flex-wrap:wrap;overflow-x:hidden;overflow-y:auto}.fc .fc-multimonth-title{font-size:1.2em;font-weight:700;padding:1em 0;text-align:center}.fc .fc-multimonth-daygrid{background:var(--fc-page-bg-color)}.fc .fc-multimonth-daygrid-table,.fc .fc-multimonth-header-table{table-layout:fixed;width:100%}.fc .fc-multimonth-daygrid-table{border-top-style:hidden!important}.fc .fc-multimonth-singlecol .fc-multimonth{position:relative}.fc .fc-multimonth-singlecol .fc-multimonth-header{background:var(--fc-page-bg-color);position:relative;top:0;z-index:2}.fc .fc-multimonth-singlecol .fc-multimonth-daygrid{position:relative;z-index:1}.fc .fc-multimonth-singlecol .fc-multimonth-daygrid-table,.fc .fc-multimonth-singlecol .fc-multimonth-header-table{border-left-style:hidden;border-right-style:hidden}.fc .fc-multimonth-singlecol .fc-multimonth-month:last-child .fc-multimonth-daygrid-table{border-bottom-style:hidden}.fc .fc-multimonth-multicol{line-height:1}.fc .fc-multimonth-multicol .fc-multimonth-month{padding:0 1.2em 1.2em}.fc .fc-multimonth-multicol .fc-daygrid-more-link{border:1px solid var(--fc-event-border-color);display:block;float:none;padding:1px}.fc .fc-multimonth-compact{line-height:1}.fc .fc-multimonth-compact .fc-multimonth-daygrid-table,.fc .fc-multimonth-compact .fc-multimonth-header-table{font-size:.9em}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-header{position:sticky}.fc-media-print .fc-multimonth{overflow:visible}");var u=e.createPlugin({name:"@fullcalendar/multimonth",initialView:"multiMonthYear",optionRefiners:h,views:{multiMonth:{component:a,dateProfileGeneratorClass:l.TableDateProfileGenerator,multiMonthMinWidth:350,multiMonthMaxColumns:3},multiMonthYear:{type:"multiMonth",duration:{years:1},fixedWeekCount:!0,showNonCurrentDates:!1}}});return e.globalPlugins.push(u),t.default=u,Object.defineProperty(t,"__esModule",{value:!0}),t}({},FullCalendar,FullCalendar.DayGrid.Internal,FullCalendar.Internal,FullCalendar.Preact);
6
+ FullCalendar.MultiMonth=function(e,t,l,n,r){"use strict";class o extends n.DateComponent{constructor(){super(...arguments),this.slicer=new l.DayTableSlicer,this.buildDayTableModel=n.memoize(l.buildDayTableModel),this.createDayHeaderFormatter=n.memoize(l.createDayHeaderFormatter)}render(){const{props:e,context:t}=this,{dateProfile:n,forPrint:o}=e,{options:i}=t,a=this.buildDayTableModel(n,t.dateProfileGenerator),s=this.slicer.sliceProps(e,n,i.nextDayThreshold,t,a),c="number"==typeof e.width?e.width/i.aspectRatio:null,m=a.cellRows.length,d=null!=c?c/m:null,h=this.createDayHeaderFormatter(t.options.dayHeaderFormat,!1,a.colCnt);return r.createElement("div",{"data-date":e.isoDateStr,role:"grid",className:"fc-multimonth-month fc-grow",style:{width:e.width}},r.createElement("div",{className:"fc-multimonth-header",style:{marginBottom:d},role:"presentation"},r.createElement("div",{className:"fc-multimonth-title"},t.dateEnv.format(e.dateProfile.currentRange.start,e.titleFormat)),r.createElement("div",{className:"fc-multimonth-header-row fc-flex-row"},a.headerDates.map(e=>r.createElement(l.DayOfWeekHeaderCell,{key:e.getUTCDay(),dow:e.getUTCDay(),dayHeaderFormat:h,colWidth:void 0})))),r.createElement("div",{className:"fc-multimonth-body fc-flex-column",style:{marginTop:-d,height:o?"":c}},r.createElement(l.DayGridRows,{dateProfile:e.dateProfile,todayRange:e.todayRange,cellRows:a.cellRows,forPrint:e.forPrint,fgEventSegs:s.fgEventSegs,bgEventSegs:s.bgEventSegs,businessHourSegs:s.businessHourSegs,dateSelectionSegs:s.dateSelectionSegs,eventDrag:s.eventDrag,eventResize:s.eventResize,eventSelection:s.eventSelection})))}}class i extends n.DateComponent{constructor(){super(...arguments),this.splitDateProfileByMonth=n.memoize(s),this.buildMonthFormat=n.memoize(d),this.scrollerRef=r.createRef(),this.innerElRef=r.createRef(),this.scrollDate=null,this.handleWidth=e=>{let{xGap:t,xPadding:l}=this.state;if(null==t){const r=this.innerElRef.current.childNodes;if(r.length>1){const o=r[0].getBoundingClientRect(),i=r[1].getBoundingClientRect();let a;[t,a]=[Math.abs(o.left-i.right),Math.abs(o.right-i.left)].sort(n.compareNumbers),l=e-a}}this.setState({width:e,xGap:t,xPadding:l})},this.updateScroll=()=>{if(null!=this.scrollDate&&null!=this.state.width){const e=this.scrollerRef.current,t=this.innerElRef.current,l=t.querySelector(`[data-date="${n.formatIsoMonthStr(this.scrollDate)}"]`),r=Math.ceil(l.getBoundingClientRect().top-t.getBoundingClientRect().top);e.scrollTo({y:r})}},this.clearScroll=()=>{this.scrollDate=null}}render(){const{context:e,props:t,state:l}=this,{options:i}=e,a=!t.forPrint&&!n.getIsHeightAuto(i),s=null==l.width?2:Math.min(i.multiMonthMaxColumns,Math.floor((l.width-l.xPadding+l.xGap)/(i.multiMonthMinWidth+l.xGap))),c=null==l.width?"34%":Math.floor((l.width-l.xPadding-l.xGap*(s-1))/s),m=this.splitDateProfileByMonth(e.dateProfileGenerator,t.dateProfile,e.dateEnv,i.fixedWeekCount,i.showNonCurrentDates),d=this.buildMonthFormat(i.multiMonthTitleFormat,m),h=["fc-multimonth-view",1===s?"fc-multimonth-singlecol":"fc-multimonth-multicol","fc-flex-column","fc-border"];return r.createElement(n.NowTimer,{unit:"day"},(l,i)=>r.createElement(n.ViewContainer,{elClasses:h,viewSpec:e.viewSpec},r.createElement(n.Scroller,{vertical:a,elClassNames:[a?"fc-liquid":""],ref:this.scrollerRef,widthRef:this.handleWidth},r.createElement("div",{ref:this.innerElRef,className:"fc-multimonth-inner"},m.map((e,l)=>{const a=n.formatIsoMonthStr(e.currentRange.start);return r.createElement(o,Object.assign({},t,{key:a,todayRange:i,isoDateStr:a,titleFormat:d,dateProfile:e,width:c}))})))))}componentDidMount(){this.resetScroll(),this.scrollerRef.current.addScrollEndListener(this.clearScroll)}componentDidUpdate(e){e.dateProfile!==this.props.dateProfile&&this.context.options.scrollTimeReset?this.resetScroll():this.updateScroll()}componentWillUnmount(){this.scrollerRef.current.removeScrollEndListener(this.clearScroll)}resetScroll(){this.scrollDate=this.props.dateProfile.currentDate,this.updateScroll()}}const a=n.createDuration(1,"month");function s(e,t,r,o,i){const{start:s,end:c}=t.currentRange;let m=s;const d=[];for(;m.valueOf()<c.valueOf();){const s=r.add(m,a),c={start:e.skipHiddenDays(m),end:e.skipHiddenDays(s,-1,!0)};let h=l.buildDayTableRenderRange({currentRange:c,snapToWeek:!0,fixedWeekCount:o,dateEnv:r});h={start:e.skipHiddenDays(h.start),end:e.skipHiddenDays(h.end,-1,!0)};const u=t.activeRange?n.intersectRanges(t.activeRange,i?h:c):null;d.push({currentDate:t.currentDate,isValid:t.isValid,validRange:t.validRange,renderRange:h,activeRange:u,currentRange:c,currentRangeUnit:"month",isRangeAllDay:!0,dateIncrement:t.dateIncrement,slotMinTime:t.slotMaxTime,slotMaxTime:t.slotMinTime}),m=s}return d}const c=n.createFormatter({year:"numeric",month:"long"}),m=n.createFormatter({month:"long"});function d(e,t){return e||(t[0].currentRange.start.getUTCFullYear()!==t[t.length-1].currentRange.start.getUTCFullYear()?c:m)}const h={multiMonthTitleFormat:n.createFormatter,multiMonthMaxColumns:Number,multiMonthMinWidth:Number};n.injectStyles(".fc-multimonth-inner{display:flex;flex-wrap:wrap}.fc-multimonth-multicol .fc-multimonth-month{margin:0 1.2em 1.2em}.fc-multimonth-multicol .fc-multimonth-title{padding:1em 0}.fc-multimonth-singlecol .fc-multimonth-title{padding:.5em 0}.fc-multimonth-title{font-size:1.2em;font-weight:700;text-align:center}.fc-multimonth-header-row{border-top:1px solid var(--fc-border-color)}.fc-multimonth-header-row,.fc-multimonth-month{border-bottom:1px solid var(--fc-border-color)}.fc-multimonth-singlecol .fc-multimonth-month:last-child{border-bottom:0}.fc-multimonth-multicol .fc-multimonth-body,.fc-multimonth-multicol .fc-multimonth-header-row{border-left:1px solid var(--fc-border-color);border-right:1px solid var(--fc-border-color);font-size:.9em;line-height:1}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-header{background:var(--fc-page-bg-color);position:sticky;top:0;z-index:2}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-body{position:relative;z-index:1}");var u=t.createPlugin({name:"@fullcalendar/multimonth",initialView:"multiMonthYear",optionRefiners:h,views:{multiMonth:{component:i,dateProfileGeneratorClass:l.TableDateProfileGenerator,multiMonthMinWidth:350,multiMonthMaxColumns:3},multiMonthYear:{type:"multiMonth",duration:{years:1},fixedWeekCount:!0,showNonCurrentDates:!1}}});return t.globalPlugins.push(u),e.default=u,Object.defineProperty(e,"__esModule",{value:!0}),e}({},FullCalendar,FullCalendar.DayGrid.Internal,FullCalendar.Internal,FullCalendar.Preact);
package/index.js CHANGED
@@ -1,155 +1,149 @@
1
1
  import { createPlugin } from '@fullcalendar/core/index.js';
2
- import { buildDayTableModel, DayTableSlicer, TableRows, buildDayTableRenderRange, TableDateProfileGenerator } from '@fullcalendar/daygrid/internal.js';
3
- import { DateComponent, memoize, getUniqueDomId, DayHeader, ViewContainer, formatIsoMonthStr, isPropsEqual, createDuration, intersectRanges, createFormatter, injectStyles } from '@fullcalendar/core/internal.js';
2
+ import { DayTableSlicer, buildDayTableModel, createDayHeaderFormatter, DayOfWeekHeaderCell, DayGridRows, buildDayTableRenderRange, TableDateProfileGenerator } from '@fullcalendar/daygrid/internal.js';
3
+ import { DateComponent, memoize, compareNumbers, formatIsoMonthStr, getIsHeightAuto, NowTimer, ViewContainer, Scroller, createDuration, intersectRanges, createFormatter, injectStyles } from '@fullcalendar/core/internal.js';
4
4
  import { createElement, createRef } from '@fullcalendar/core/preact.js';
5
5
 
6
6
  class SingleMonth extends DateComponent {
7
7
  constructor() {
8
8
  super(...arguments);
9
- this.buildDayTableModel = memoize(buildDayTableModel);
10
9
  this.slicer = new DayTableSlicer();
11
- this.state = {
12
- labelId: getUniqueDomId(),
13
- };
10
+ // memo
11
+ this.buildDayTableModel = memoize(buildDayTableModel);
12
+ this.createDayHeaderFormatter = memoize(createDayHeaderFormatter);
14
13
  }
15
14
  render() {
16
- const { props, state, context } = this;
15
+ const { props, context } = this;
17
16
  const { dateProfile, forPrint } = props;
18
17
  const { options } = context;
19
18
  const dayTableModel = this.buildDayTableModel(dateProfile, context.dateProfileGenerator);
20
19
  const slicedProps = this.slicer.sliceProps(props, dateProfile, options.nextDayThreshold, context, dayTableModel);
21
20
  // ensure single-month has aspect ratio
22
- const tableHeight = props.tableWidth != null ? props.tableWidth / options.aspectRatio : null;
23
- const rowCnt = dayTableModel.cells.length;
21
+ const tableHeight = typeof props.width === 'number'
22
+ ? props.width / options.aspectRatio
23
+ : null;
24
+ const rowCnt = dayTableModel.cellRows.length;
24
25
  const rowHeight = tableHeight != null ? tableHeight / rowCnt : null;
25
- return (createElement("div", { ref: props.elRef, "data-date": props.isoDateStr, className: "fc-multimonth-month", style: { width: props.width }, role: "grid", "aria-labelledby": state.labelId },
26
+ const dayHeaderFormat = this.createDayHeaderFormatter(context.options.dayHeaderFormat, false, // datesRepDistinctDays
27
+ dayTableModel.colCnt);
28
+ // TODO: tell children if we know dimensions are unstable?
29
+ return (createElement("div", { "data-date": props.isoDateStr, role: "grid", className: "fc-multimonth-month fc-grow", style: { width: props.width } },
26
30
  createElement("div", { className: "fc-multimonth-header", style: { marginBottom: rowHeight }, role: "presentation" },
27
- createElement("div", { className: "fc-multimonth-title", id: state.labelId }, context.dateEnv.format(props.dateProfile.currentRange.start, props.titleFormat)),
28
- createElement("table", { className: [
29
- 'fc-multimonth-header-table',
30
- context.theme.getClass('table'),
31
- ].join(' '), role: "presentation" },
32
- createElement("thead", { role: "rowgroup" },
33
- createElement(DayHeader, { dateProfile: props.dateProfile, dates: dayTableModel.headerDates, datesRepDistinctDays: false })))),
34
- createElement("div", { className: [
35
- 'fc-multimonth-daygrid',
36
- 'fc-daygrid',
37
- 'fc-daygrid-body',
38
- !forPrint && 'fc-daygrid-body-balanced',
39
- forPrint && 'fc-daygrid-body-unbalanced',
40
- forPrint && 'fc-daygrid-body-natural',
41
- ].join(' '), style: { marginTop: -rowHeight } },
42
- createElement("table", { className: [
43
- 'fc-multimonth-daygrid-table',
44
- context.theme.getClass('table'),
45
- ].join(' '), style: { height: forPrint ? '' : tableHeight }, role: "presentation" },
46
- createElement("tbody", { role: "rowgroup" },
47
- createElement(TableRows, Object.assign({}, slicedProps, { dateProfile: dateProfile, cells: dayTableModel.cells, eventSelection: props.eventSelection, dayMaxEvents: !forPrint, dayMaxEventRows: !forPrint, showWeekNumbers: options.weekNumbers, clientWidth: props.clientWidth, clientHeight: props.clientHeight, forPrint: forPrint })))))));
31
+ createElement("div", { className: "fc-multimonth-title" }, context.dateEnv.format(props.dateProfile.currentRange.start, props.titleFormat)),
32
+ createElement("div", { className: 'fc-multimonth-header-row fc-flex-row' }, dayTableModel.headerDates.map((headerDate) => (createElement(DayOfWeekHeaderCell, { key: headerDate.getUTCDay(), dow: headerDate.getUTCDay(), dayHeaderFormat: dayHeaderFormat, colWidth: undefined }))))),
33
+ createElement("div", { className: 'fc-multimonth-body fc-flex-column', style: {
34
+ marginTop: -rowHeight,
35
+ height: forPrint ? '' : tableHeight,
36
+ } },
37
+ createElement(DayGridRows // .fc-grow
38
+ , { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: dayTableModel.cellRows, forPrint: props.forPrint,
39
+ // content
40
+ fgEventSegs: slicedProps.fgEventSegs, bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventDrag: slicedProps.eventDrag, eventResize: slicedProps.eventResize, eventSelection: slicedProps.eventSelection }))));
48
41
  }
49
42
  }
50
43
 
51
44
  class MultiMonthView extends DateComponent {
52
45
  constructor() {
53
46
  super(...arguments);
47
+ // memo
54
48
  this.splitDateProfileByMonth = memoize(splitDateProfileByMonth);
55
49
  this.buildMonthFormat = memoize(buildMonthFormat);
56
- this.scrollElRef = createRef();
57
- this.firstMonthElRef = createRef();
58
- this.needsScrollReset = false;
59
- this.handleSizing = (isForced) => {
60
- if (isForced) {
61
- this.updateSize();
50
+ // ref
51
+ this.scrollerRef = createRef();
52
+ this.innerElRef = createRef();
53
+ // internal
54
+ this.scrollDate = null;
55
+ // Sizing
56
+ // -----------------------------------------------------------------------------------------------
57
+ this.handleWidth = (width) => {
58
+ let { xGap, xPadding } = this.state;
59
+ // for first time, assume 2 columns and query gap/padding
60
+ if (xGap == null) {
61
+ const innerEl = this.innerElRef.current;
62
+ const children = innerEl.childNodes;
63
+ if (children.length > 1) {
64
+ const box0 = children[0].getBoundingClientRect();
65
+ const box1 = children[1].getBoundingClientRect();
66
+ let xSpan;
67
+ [xGap, xSpan] = [
68
+ Math.abs(box0.left - box1.right),
69
+ Math.abs(box0.right - box1.left),
70
+ ].sort(compareNumbers);
71
+ xPadding = width - xSpan;
72
+ }
62
73
  }
74
+ this.setState({ width, xGap, xPadding });
75
+ };
76
+ this.updateScroll = () => {
77
+ if (this.scrollDate != null && this.state.width != null) {
78
+ const scroller = this.scrollerRef.current;
79
+ const innerEl = this.innerElRef.current;
80
+ const monthEl = innerEl.querySelector(`[data-date="${formatIsoMonthStr(this.scrollDate)}"]`);
81
+ const scrollTop = Math.ceil(// for fractions, err on the side of scrolling further
82
+ monthEl.getBoundingClientRect().top -
83
+ innerEl.getBoundingClientRect().top);
84
+ scroller.scrollTo({ y: scrollTop });
85
+ }
86
+ };
87
+ this.clearScroll = () => {
88
+ this.scrollDate = null;
63
89
  };
64
90
  }
65
91
  render() {
66
92
  const { context, props, state } = this;
67
93
  const { options } = context;
68
- const { clientWidth, clientHeight } = state;
69
- const monthHPadding = state.monthHPadding || 0;
70
- const colCount = Math.min(clientWidth != null ?
71
- Math.floor(clientWidth / (options.multiMonthMinWidth + monthHPadding)) :
72
- 1, options.multiMonthMaxColumns) || 1;
73
- const monthWidthPct = (100 / colCount) + '%';
74
- const monthTableWidth = clientWidth == null ? null :
75
- (clientWidth / colCount) - monthHPadding;
76
- const isLegitSingleCol = clientWidth != null && colCount === 1;
77
- const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv, isLegitSingleCol ? false : options.fixedWeekCount, options.showNonCurrentDates);
94
+ const verticalScrolling = !props.forPrint && !getIsHeightAuto(options);
95
+ const colCount = state.width == null
96
+ ? 2
97
+ : Math.min(options.multiMonthMaxColumns, Math.floor((state.width - state.xPadding + state.xGap) /
98
+ (options.multiMonthMinWidth + state.xGap)));
99
+ const monthWidth = state.width == null
100
+ ? '34%' // will expand. now small enough to be 1/3. for allowing gap
101
+ : Math.floor(// exact values can cause expansion to other rows
102
+ (state.width - state.xPadding - (state.xGap * (colCount - 1))) /
103
+ colCount);
104
+ const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv, options.fixedWeekCount, options.showNonCurrentDates);
78
105
  const monthTitleFormat = this.buildMonthFormat(options.multiMonthTitleFormat, monthDateProfiles);
79
106
  const rootClassNames = [
80
- 'fc-multimonth',
81
- isLegitSingleCol ?
107
+ 'fc-multimonth-view',
108
+ (colCount === 1) ?
82
109
  'fc-multimonth-singlecol' :
83
110
  'fc-multimonth-multicol',
84
- (monthTableWidth != null && monthTableWidth < 400) ?
85
- 'fc-multimonth-compact' :
86
- '',
87
- props.isHeightAuto ?
88
- '' :
89
- 'fc-scroller', // for AutoScroller
111
+ 'fc-flex-column',
112
+ 'fc-border', // BAD to mix this with size-listening?
90
113
  ];
91
- return (createElement(ViewContainer, { elRef: this.scrollElRef, elClasses: rootClassNames, viewSpec: context.viewSpec }, monthDateProfiles.map((monthDateProfile, i) => {
92
- const monthStr = formatIsoMonthStr(monthDateProfile.currentRange.start);
93
- return (createElement(SingleMonth, Object.assign({}, props, { key: monthStr, isoDateStr: monthStr, elRef: i === 0 ? this.firstMonthElRef : undefined, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: monthWidthPct, tableWidth: monthTableWidth, clientWidth: clientWidth, clientHeight: clientHeight })));
94
- })));
114
+ return (createElement(NowTimer, { unit: "day" }, (nowDate, todayRange) => (createElement(ViewContainer, { elClasses: rootClassNames, viewSpec: context.viewSpec },
115
+ createElement(Scroller, { vertical: verticalScrolling, elClassNames: [
116
+ verticalScrolling ? 'fc-liquid' : '',
117
+ ], ref: this.scrollerRef, widthRef: this.handleWidth },
118
+ createElement("div", { ref: this.innerElRef, className: 'fc-multimonth-inner' }, monthDateProfiles.map((monthDateProfile, i) => {
119
+ const monthStr = formatIsoMonthStr(monthDateProfile.currentRange.start);
120
+ return (createElement(SingleMonth, Object.assign({}, props, { key: monthStr, todayRange: todayRange, isoDateStr: monthStr, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: monthWidth })));
121
+ })))))));
95
122
  }
123
+ // Lifecycle
124
+ // -----------------------------------------------------------------------------------------------
96
125
  componentDidMount() {
97
- this.updateSize();
98
- this.context.addResizeHandler(this.handleSizing);
99
- this.requestScrollReset();
126
+ this.resetScroll();
127
+ this.scrollerRef.current.addScrollEndListener(this.clearScroll);
100
128
  }
101
129
  componentDidUpdate(prevProps) {
102
- if (!isPropsEqual(prevProps, this.props)) { // an external change?
103
- this.handleSizing(false);
104
- }
105
- if (prevProps.dateProfile !== this.props.dateProfile) {
106
- this.requestScrollReset();
130
+ if (prevProps.dateProfile !== this.props.dateProfile && this.context.options.scrollTimeReset) {
131
+ this.resetScroll();
107
132
  }
108
133
  else {
109
- this.flushScrollReset();
134
+ // NOT optimal to update so often
135
+ // TODO: isolate dependencies of scroll coordinate
136
+ this.updateScroll();
110
137
  }
111
138
  }
112
139
  componentWillUnmount() {
113
- this.context.removeResizeHandler(this.handleSizing);
114
- }
115
- updateSize() {
116
- const scrollEl = this.scrollElRef.current;
117
- const firstMonthEl = this.firstMonthElRef.current;
118
- if (scrollEl) {
119
- this.setState({
120
- clientWidth: scrollEl.clientWidth,
121
- clientHeight: scrollEl.clientHeight,
122
- });
123
- }
124
- if (firstMonthEl && scrollEl) {
125
- if (this.state.monthHPadding == null) { // always remember initial non-zero value
126
- this.setState({
127
- monthHPadding: scrollEl.clientWidth - // go within padding
128
- firstMonthEl.firstChild.offsetWidth,
129
- });
130
- }
131
- }
132
- }
133
- requestScrollReset() {
134
- this.needsScrollReset = true;
135
- this.flushScrollReset();
136
- }
137
- flushScrollReset() {
138
- if (this.needsScrollReset &&
139
- this.state.monthHPadding != null // indicates sizing already happened
140
- ) {
141
- const { currentDate } = this.props.dateProfile;
142
- const scrollEl = this.scrollElRef.current;
143
- const monthEl = scrollEl.querySelector(`[data-date="${formatIsoMonthStr(currentDate)}"]`);
144
- scrollEl.scrollTop = monthEl.getBoundingClientRect().top -
145
- this.firstMonthElRef.current.getBoundingClientRect().top;
146
- this.needsScrollReset = false;
147
- }
140
+ this.scrollerRef.current.removeScrollEndListener(this.clearScroll);
148
141
  }
149
- // workaround for when queued setState render (w/ clientWidth) gets cancelled because
150
- // subsequent update and shouldComponentUpdate says not to render :(
151
- shouldComponentUpdate() {
152
- return true;
142
+ // Scrolling
143
+ // -----------------------------------------------------------------------------------------------
144
+ resetScroll() {
145
+ this.scrollDate = this.props.dateProfile.currentDate;
146
+ this.updateScroll();
153
147
  }
154
148
  }
155
149
  // date profile
@@ -215,7 +209,7 @@ const OPTION_REFINERS = {
215
209
  multiMonthMinWidth: Number,
216
210
  };
217
211
 
218
- var css_248z = ".fc .fc-multimonth{border:1px solid var(--fc-border-color);display:flex;flex-wrap:wrap;overflow-x:hidden;overflow-y:auto}.fc .fc-multimonth-title{font-size:1.2em;font-weight:700;padding:1em 0;text-align:center}.fc .fc-multimonth-daygrid{background:var(--fc-page-bg-color)}.fc .fc-multimonth-daygrid-table,.fc .fc-multimonth-header-table{table-layout:fixed;width:100%}.fc .fc-multimonth-daygrid-table{border-top-style:hidden!important}.fc .fc-multimonth-singlecol .fc-multimonth{position:relative}.fc .fc-multimonth-singlecol .fc-multimonth-header{background:var(--fc-page-bg-color);position:relative;top:0;z-index:2}.fc .fc-multimonth-singlecol .fc-multimonth-daygrid{position:relative;z-index:1}.fc .fc-multimonth-singlecol .fc-multimonth-daygrid-table,.fc .fc-multimonth-singlecol .fc-multimonth-header-table{border-left-style:hidden;border-right-style:hidden}.fc .fc-multimonth-singlecol .fc-multimonth-month:last-child .fc-multimonth-daygrid-table{border-bottom-style:hidden}.fc .fc-multimonth-multicol{line-height:1}.fc .fc-multimonth-multicol .fc-multimonth-month{padding:0 1.2em 1.2em}.fc .fc-multimonth-multicol .fc-daygrid-more-link{border:1px solid var(--fc-event-border-color);display:block;float:none;padding:1px}.fc .fc-multimonth-compact{line-height:1}.fc .fc-multimonth-compact .fc-multimonth-daygrid-table,.fc .fc-multimonth-compact .fc-multimonth-header-table{font-size:.9em}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-header{position:sticky}.fc-media-print .fc-multimonth{overflow:visible}";
212
+ var css_248z = ".fc-multimonth-inner{display:flex;flex-wrap:wrap}.fc-multimonth-multicol .fc-multimonth-month{margin:0 1.2em 1.2em}.fc-multimonth-multicol .fc-multimonth-title{padding:1em 0}.fc-multimonth-singlecol .fc-multimonth-title{padding:.5em 0}.fc-multimonth-title{font-size:1.2em;font-weight:700;text-align:center}.fc-multimonth-header-row{border-top:1px solid var(--fc-border-color)}.fc-multimonth-header-row,.fc-multimonth-month{border-bottom:1px solid var(--fc-border-color)}.fc-multimonth-singlecol .fc-multimonth-month:last-child{border-bottom:0}.fc-multimonth-multicol .fc-multimonth-body,.fc-multimonth-multicol .fc-multimonth-header-row{border-left:1px solid var(--fc-border-color);border-right:1px solid var(--fc-border-color);font-size:.9em;line-height:1}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-header{background:var(--fc-page-bg-color);position:sticky;top:0;z-index:2}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-body{position:relative;z-index:1}";
219
213
  injectStyles(css_248z);
220
214
 
221
215
  var index = createPlugin({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fullcalendar/multimonth",
3
- "version": "6.1.15",
3
+ "version": "7.0.0-beta.1",
4
4
  "title": "FullCalendar Multi-Month Plugin",
5
5
  "description": "Display a sequence or grid of multiple months",
6
6
  "keywords": [
@@ -12,10 +12,10 @@
12
12
  ],
13
13
  "homepage": "https://fullcalendar.io/docs/multimonth-grid",
14
14
  "dependencies": {
15
- "@fullcalendar/daygrid": "~6.1.15"
15
+ "@fullcalendar/daygrid": "7.0.0-beta.1"
16
16
  },
17
17
  "peerDependencies": {
18
- "@fullcalendar/core": "~6.1.15"
18
+ "@fullcalendar/core": "7.0.0-beta.1"
19
19
  },
20
20
  "type": "module",
21
21
  "bugs": "https://fullcalendar.io/reporting-bugs",