@fullcalendar/multimonth 7.0.0-beta.0 → 7.0.0-beta.3

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,10 +10,12 @@ 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.slicer = new internal_cjs$1.DayTableSlicer();
14
13
  // memo
15
14
  this.buildDayTableModel = internal_cjs.memoize(internal_cjs$1.buildDayTableModel);
16
15
  this.createDayHeaderFormatter = internal_cjs.memoize(internal_cjs$1.createDayHeaderFormatter);
16
+ this.buildDateRowConfig = internal_cjs.memoize(internal_cjs$1.buildDateRowConfig);
17
+ // internal
18
+ this.slicer = new internal_cjs$1.DayTableSlicer();
17
19
  }
18
20
  render() {
19
21
  const { props, context } = this;
@@ -21,27 +23,31 @@ class SingleMonth extends internal_cjs.DateComponent {
21
23
  const { options } = context;
22
24
  const dayTableModel = this.buildDayTableModel(dateProfile, context.dateProfileGenerator);
23
25
  const slicedProps = this.slicer.sliceProps(props, dateProfile, options.nextDayThreshold, context, dayTableModel);
24
- // ensure single-month has aspect ratio
25
- const tableHeight = typeof props.width === 'number'
26
- ? props.width / options.aspectRatio
27
- : null;
28
- const rowCnt = dayTableModel.cellRows.length;
29
- const rowHeight = tableHeight != null ? tableHeight / rowCnt : null;
30
- const dayHeaderFormat = this.createDayHeaderFormatter(context.options.dayHeaderFormat, false, // datesRepDistinctDays
26
+ const dayHeaderFormat = this.createDayHeaderFormatter(options.dayHeaderFormat, false, // datesRepDistinctDays
31
27
  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 } },
34
- preact_cjs.createElement("div", { className: "fc-multimonth-header", style: { marginBottom: rowHeight }, role: "presentation" },
28
+ const rowConfig = this.buildDateRowConfig(dayTableModel.headerDates, false, // datesRepDistinctDays
29
+ dateProfile, props.todayRange, dayHeaderFormat, context);
30
+ const invAspectRatio = 1 / options.aspectRatio;
31
+ const invRowAspectRatio = invAspectRatio / dayTableModel.rowCnt;
32
+ const isHeaderSticky = !forPrint;
33
+ const isAspectRatio = !forPrint || props.hasLateralSiblings;
34
+ return (preact_cjs.createElement("div", { "data-date": props.isoDateStr, className: internal_cjs.joinClassNames('fc-multimonth-month', props.hasLateralSiblings && 'fc-break-inside-avoid'),
35
+ // override fc-liquid's basis. fc-grow isn't sufficient because doesn't set min-width:0
36
+ style: { width: props.width } },
37
+ preact_cjs.createElement("div", { className: "fc-multimonth-header", style: {
38
+ marginBottom: isHeaderSticky ? internal_cjs.fracToCssDim(invRowAspectRatio) : undefined,
39
+ } },
35
40
  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,
41
+ preact_cjs.createElement(internal_cjs$1.DayGridHeaderRow, Object.assign({}, rowConfig, { className: 'fc-multimonth-header-row' }))),
42
+ preact_cjs.createElement("div", { className: internal_cjs.joinClassNames('fc-multimonth-body', isAspectRatio && 'fc-rel'), style: {
43
+ marginTop: isHeaderSticky ? internal_cjs.fracToCssDim(-invRowAspectRatio) : undefined,
44
+ paddingBottom: isAspectRatio ? internal_cjs.fracToCssDim(invAspectRatio) : undefined,
40
45
  } },
41
- preact_cjs.createElement(internal_cjs$1.DayGridRows // .fc-grow
42
- , { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: dayTableModel.cellRows, forPrint: props.forPrint,
46
+ preact_cjs.createElement(internal_cjs$1.DayGridRows, { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: dayTableModel.cellRows, className: isAspectRatio ? 'fc-fill' : '', forPrint: forPrint && !props.hasLateralSiblings, dayMaxEvents: forPrint ? undefined : options.dayMaxEvents, dayMaxEventRows: (forPrint && props.hasLateralSiblings) ? 1 : options.dayMaxEventRows,
43
47
  // content
44
- fgEventSegs: slicedProps.fgEventSegs, bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventDrag: slicedProps.eventDrag, eventResize: slicedProps.eventResize, eventSelection: slicedProps.eventSelection }))));
48
+ fgEventSegs: slicedProps.fgEventSegs, bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventDrag: slicedProps.eventDrag, eventResize: slicedProps.eventResize, eventSelection: slicedProps.eventSelection,
49
+ // dimensions
50
+ visibleWidth: props.visibleWidth }))));
45
51
  }
46
52
  }
47
53
 
@@ -52,91 +58,89 @@ class MultiMonthView extends internal_cjs.DateComponent {
52
58
  this.splitDateProfileByMonth = internal_cjs.memoize(splitDateProfileByMonth);
53
59
  this.buildMonthFormat = internal_cjs.memoize(buildMonthFormat);
54
60
  // ref
55
- this.rootElRef = preact_cjs.createRef(); // also the scroll container
56
- this.innerElRef = preact_cjs.createRef();
57
- this.handleClientWidth = (clientWidth) => {
58
- let { xGap, xPadding } = this.state;
59
- // for first time, assume 2 columns and query gap/padding
60
- if (xGap == null) {
61
+ this.scrollerRef = preact_cjs.createRef();
62
+ this.innerElRef = preact_cjs.createRef(); // .fc-multimonth-inner
63
+ this.scrollDate = null;
64
+ this.updateScroll = () => {
65
+ if (this.scrollDate != null &&
66
+ this.state.innerWidth != null // render completed?
67
+ ) {
68
+ const scroller = this.scrollerRef.current;
61
69
  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(internal_cjs.compareNumbers);
71
- xPadding = clientWidth - xSpan;
72
- }
73
- }
74
- this.setState({ clientWidth, xGap, xPadding });
75
- };
76
- this.timeScrollResponder = new internal_cjs.ScrollResponder((_time) => {
77
- // HACK to scroll to day
78
- if (this.state.clientWidth != null) {
79
- const { currentDate } = this.props.dateProfile;
80
- const rootEl = this.rootElRef.current;
81
- const innerEl = this.innerElRef.current;
82
- const monthEl = innerEl.querySelector(`[data-date="${internal_cjs.formatIsoMonthStr(currentDate)}"]`);
83
- rootEl.scrollTop = Math.ceil(// for fractions, err on the side of scrolling further
70
+ const monthEl = innerEl.querySelector(`[data-date="${internal_cjs.formatIsoMonthStr(this.scrollDate)}"]`);
71
+ const scrollTop = Math.ceil(// for fractions, err on the side of scrolling further
84
72
  monthEl.getBoundingClientRect().top -
85
73
  innerEl.getBoundingClientRect().top);
86
- return true;
74
+ scroller.scrollTo({ y: scrollTop });
87
75
  }
88
- return false;
89
- });
76
+ };
77
+ this.clearScroll = () => {
78
+ this.scrollDate = null;
79
+ };
90
80
  }
91
81
  render() {
92
82
  const { context, props, state } = this;
93
83
  const { options } = context;
94
- const colCount = state.clientWidth == null
95
- ? 2
96
- : Math.min(options.multiMonthMaxColumns, Math.floor((state.clientWidth - state.xPadding + state.xGap) /
97
- (options.multiMonthMinWidth + state.xGap)));
98
- const monthWidth = state.clientWidth == null
99
- ? '34%' // will expand. now small enough to be 1/3. for allowing gap
100
- : Math.floor(// exact values can cause expansion to other rows
101
- (state.clientWidth - state.xPadding - (state.xGap * (colCount - 1))) /
102
- colCount);
84
+ const verticalScrolling = !props.forPrint && !internal_cjs.getIsHeightAuto(options);
103
85
  const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv, options.fixedWeekCount, options.showNonCurrentDates);
104
86
  const monthTitleFormat = this.buildMonthFormat(options.multiMonthTitleFormat, monthDateProfiles);
105
- const rootClassNames = [
106
- 'fc-multimonth-view',
107
- (colCount === 1) ?
87
+ const { multiMonthMinWidth, multiMonthMaxColumns } = options;
88
+ const { innerWidth } = state;
89
+ let cols;
90
+ let computedMonthWidth;
91
+ let cssMonthWidth;
92
+ let hasLateralSiblings = false;
93
+ if (innerWidth != null) {
94
+ cols = Math.max(1, Math.min(multiMonthMaxColumns, Math.floor(innerWidth / multiMonthMinWidth)));
95
+ if (props.forPrint) {
96
+ cols = Math.min(cols, 2);
97
+ }
98
+ computedMonthWidth = innerWidth / cols;
99
+ cssMonthWidth = internal_cjs.fracToCssDim(1 / cols);
100
+ hasLateralSiblings = cols > 1;
101
+ }
102
+ return (preact_cjs.createElement(internal_cjs.NowTimer, { unit: "day" }, (nowDate, todayRange) => (preact_cjs.createElement(internal_cjs.ViewContainer, { className: internal_cjs.joinClassNames('fc-multimonth fc-border', (cols === 1) ?
108
103
  'fc-multimonth-singlecol' :
109
- 'fc-multimonth-multicol',
110
- internal_cjs.getIsHeightAuto(options) ?
111
- '' :
112
- 'fc-multimonth-scroll',
113
- 'fc-border', // BAD to mix this with size-listening?
114
- ];
115
- return (preact_cjs.createElement(internal_cjs.NowTimer, { unit: "day" }, (nowDate, todayRange) => (preact_cjs.createElement(internal_cjs.ViewContainer, { elRef: this.rootElRef, elClasses: rootClassNames, viewSpec: context.viewSpec },
116
- preact_cjs.createElement("div", { ref: this.innerElRef, className: 'fc-multimonth-inner' }, monthDateProfiles.map((monthDateProfile, i) => {
117
- const monthStr = internal_cjs.formatIsoMonthStr(monthDateProfile.currentRange.start);
118
- return (preact_cjs.createElement(SingleMonth, Object.assign({}, props, { key: monthStr, todayRange: todayRange, isoDateStr: monthStr, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: monthWidth })));
119
- }))))));
104
+ 'fc-multimonth-multicol',
105
+ // HACK for Safari. Can't do break-inside:avoid with flexbox items, likely b/c it's not standard:
106
+ // https://stackoverflow.com/a/60256345
107
+ !props.forPrint && 'fc-flex-col'), viewSpec: context.viewSpec },
108
+ preact_cjs.createElement(internal_cjs.Scroller, { vertical: verticalScrolling, className: verticalScrolling ? 'fc-liquid' : '', ref: this.scrollerRef },
109
+ preact_cjs.createElement("div", { ref: this.innerElRef, className: 'fc-multimonth-inner' }, monthDateProfiles.map((monthDateProfile) => {
110
+ const monthStr = internal_cjs.formatIsoMonthStr(monthDateProfile.currentRange.start);
111
+ return (preact_cjs.createElement(SingleMonth, Object.assign({}, props, { key: monthStr, todayRange: todayRange, isoDateStr: monthStr, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: cssMonthWidth, visibleWidth: computedMonthWidth, hasLateralSiblings: hasLateralSiblings })));
112
+ })))))));
120
113
  }
114
+ // Lifecycle
115
+ // -----------------------------------------------------------------------------------------------
121
116
  componentDidMount() {
122
- const { context } = this;
123
- const { options } = context;
124
- this.unwatchWidth = internal_cjs.watchWidth(this.rootElRef.current, this.handleClientWidth);
125
- context.emitter.on('_timeScrollRequest', this.timeScrollResponder.handleScroll);
126
- this.timeScrollResponder.handleScroll(options.scrollTime);
117
+ this.resetScroll();
118
+ this.scrollerRef.current.addScrollEndListener(this.clearScroll);
119
+ this.disconnectInnerWidth = internal_cjs.watchWidth(this.innerElRef.current, (innerWidth) => {
120
+ internal_cjs.afterSize(() => {
121
+ this.setState({ innerWidth });
122
+ });
123
+ });
127
124
  }
128
125
  componentDidUpdate(prevProps) {
129
- const { options } = this.context;
130
- if (prevProps.dateProfile !== this.props.dateProfile && options.scrollTimeReset) {
131
- this.timeScrollResponder.handleScroll(options.scrollTime);
126
+ if (prevProps.dateProfile !== this.props.dateProfile && this.context.options.scrollTimeReset) {
127
+ this.resetScroll();
132
128
  }
133
129
  else {
134
- this.timeScrollResponder.drain();
130
+ // NOT optimal to update so often
131
+ // TODO: isolate dependencies of scroll coordinate
132
+ this.updateScroll();
135
133
  }
136
134
  }
137
135
  componentWillUnmount() {
138
- this.unwatchWidth();
139
- this.context.emitter.off('_timeScrollRequest', this.timeScrollResponder.handleScroll);
136
+ this.scrollerRef.current.removeScrollEndListener(this.clearScroll);
137
+ this.disconnectInnerWidth();
138
+ }
139
+ // Scrolling
140
+ // -----------------------------------------------------------------------------------------------
141
+ resetScroll() {
142
+ this.scrollDate = this.props.dateProfile.currentDate;
143
+ this.updateScroll();
140
144
  }
141
145
  }
142
146
  // date profile
@@ -202,7 +206,7 @@ const OPTION_REFINERS = {
202
206
  multiMonthMinWidth: Number,
203
207
  };
204
208
 
205
- var css_248z = ".fc-multimonth-scroll{overflow-x:hidden;overflow-y:scroll}.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}";
209
+ var css_248z = ".fc-media-screen .fc-multimonth-inner{display:flex;flex-direction:row;flex-wrap:wrap}.fc-media-print.fc-direction-ltr .fc-multimonth-inner>*{float:left}.fc-media-print.fc-direction-rtl .fc-multimonth-inner>*{float:right}.fc-media-print .fc-multimonth-inner:after{clear:both;content:\"\";display:block}.fc-multimonth-multicol .fc-multimonth-month{padding:1.2em}.fc-multimonth-singlecol .fc-multimonth-title{padding:.5em 0}.fc-multimonth-multicol .fc-multimonth-title{padding-bottom:1em}.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-body:not(.fc-multimonth-singlecol .fc-multimonth-month:last-child .fc-multimonth-body),.fc-multimonth-header-row{border-bottom:1px solid var(--fc-border-color)}.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}";
206
210
  internal_cjs.injectStyles(css_248z);
207
211
 
208
212
  var index = index_cjs.createPlugin({
@@ -220,7 +224,7 @@ var index = index_cjs.createPlugin({
220
224
  type: 'multiMonth',
221
225
  duration: { years: 1 },
222
226
  fixedWeekCount: true,
223
- showNonCurrentDates: false,
227
+ showNonCurrentDates: false, // TODO: looks bad when single-col layout
224
228
  },
225
229
  },
226
230
  });
package/index.global.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- FullCalendar Multi-Month Plugin v7.0.0-beta.0
2
+ FullCalendar Multi-Month Plugin v7.0.0-beta.3
3
3
  Docs & License: https://fullcalendar.io/docs/multimonth-grid
4
4
  (c) 2024 Adam Shaw
5
5
  */
@@ -9,10 +9,12 @@ 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.slicer = new internal$1.DayTableSlicer();
13
12
  // memo
14
13
  this.buildDayTableModel = internal.memoize(internal$1.buildDayTableModel);
15
14
  this.createDayHeaderFormatter = internal.memoize(internal$1.createDayHeaderFormatter);
15
+ this.buildDateRowConfig = internal.memoize(internal$1.buildDateRowConfig);
16
+ // internal
17
+ this.slicer = new internal$1.DayTableSlicer();
16
18
  }
17
19
  render() {
18
20
  const { props, context } = this;
@@ -20,27 +22,31 @@ FullCalendar.MultiMonth = (function (exports, core, internal$1, internal, preact
20
22
  const { options } = context;
21
23
  const dayTableModel = this.buildDayTableModel(dateProfile, context.dateProfileGenerator);
22
24
  const slicedProps = this.slicer.sliceProps(props, dateProfile, options.nextDayThreshold, context, dayTableModel);
23
- // ensure single-month has aspect ratio
24
- const tableHeight = typeof props.width === 'number'
25
- ? props.width / options.aspectRatio
26
- : null;
27
- const rowCnt = dayTableModel.cellRows.length;
28
- const rowHeight = tableHeight != null ? tableHeight / rowCnt : null;
29
- const dayHeaderFormat = this.createDayHeaderFormatter(context.options.dayHeaderFormat, false, // datesRepDistinctDays
25
+ const dayHeaderFormat = this.createDayHeaderFormatter(options.dayHeaderFormat, false, // datesRepDistinctDays
30
26
  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 } },
33
- preact.createElement("div", { className: "fc-multimonth-header", style: { marginBottom: rowHeight }, role: "presentation" },
27
+ const rowConfig = this.buildDateRowConfig(dayTableModel.headerDates, false, // datesRepDistinctDays
28
+ dateProfile, props.todayRange, dayHeaderFormat, context);
29
+ const invAspectRatio = 1 / options.aspectRatio;
30
+ const invRowAspectRatio = invAspectRatio / dayTableModel.rowCnt;
31
+ const isHeaderSticky = !forPrint;
32
+ const isAspectRatio = !forPrint || props.hasLateralSiblings;
33
+ return (preact.createElement("div", { "data-date": props.isoDateStr, className: internal.joinClassNames('fc-multimonth-month', props.hasLateralSiblings && 'fc-break-inside-avoid'),
34
+ // override fc-liquid's basis. fc-grow isn't sufficient because doesn't set min-width:0
35
+ style: { width: props.width } },
36
+ preact.createElement("div", { className: "fc-multimonth-header", style: {
37
+ marginBottom: isHeaderSticky ? internal.fracToCssDim(invRowAspectRatio) : undefined,
38
+ } },
34
39
  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,
40
+ preact.createElement(internal$1.DayGridHeaderRow, Object.assign({}, rowConfig, { className: 'fc-multimonth-header-row' }))),
41
+ preact.createElement("div", { className: internal.joinClassNames('fc-multimonth-body', isAspectRatio && 'fc-rel'), style: {
42
+ marginTop: isHeaderSticky ? internal.fracToCssDim(-invRowAspectRatio) : undefined,
43
+ paddingBottom: isAspectRatio ? internal.fracToCssDim(invAspectRatio) : undefined,
39
44
  } },
40
- preact.createElement(internal$1.DayGridRows // .fc-grow
41
- , { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: dayTableModel.cellRows, forPrint: props.forPrint,
45
+ preact.createElement(internal$1.DayGridRows, { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: dayTableModel.cellRows, className: isAspectRatio ? 'fc-fill' : '', forPrint: forPrint && !props.hasLateralSiblings, dayMaxEvents: forPrint ? undefined : options.dayMaxEvents, dayMaxEventRows: (forPrint && props.hasLateralSiblings) ? 1 : options.dayMaxEventRows,
42
46
  // content
43
- fgEventSegs: slicedProps.fgEventSegs, bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventDrag: slicedProps.eventDrag, eventResize: slicedProps.eventResize, eventSelection: slicedProps.eventSelection }))));
47
+ fgEventSegs: slicedProps.fgEventSegs, bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventDrag: slicedProps.eventDrag, eventResize: slicedProps.eventResize, eventSelection: slicedProps.eventSelection,
48
+ // dimensions
49
+ visibleWidth: props.visibleWidth }))));
44
50
  }
45
51
  }
46
52
 
@@ -51,91 +57,89 @@ FullCalendar.MultiMonth = (function (exports, core, internal$1, internal, preact
51
57
  this.splitDateProfileByMonth = internal.memoize(splitDateProfileByMonth);
52
58
  this.buildMonthFormat = internal.memoize(buildMonthFormat);
53
59
  // ref
54
- this.rootElRef = preact.createRef(); // also the scroll container
55
- this.innerElRef = preact.createRef();
56
- this.handleClientWidth = (clientWidth) => {
57
- let { xGap, xPadding } = this.state;
58
- // for first time, assume 2 columns and query gap/padding
59
- if (xGap == null) {
60
+ this.scrollerRef = preact.createRef();
61
+ this.innerElRef = preact.createRef(); // .fc-multimonth-inner
62
+ this.scrollDate = null;
63
+ this.updateScroll = () => {
64
+ if (this.scrollDate != null &&
65
+ this.state.innerWidth != null // render completed?
66
+ ) {
67
+ const scroller = this.scrollerRef.current;
60
68
  const innerEl = this.innerElRef.current;
61
- const children = innerEl.childNodes;
62
- if (children.length > 1) {
63
- const box0 = children[0].getBoundingClientRect();
64
- const box1 = children[1].getBoundingClientRect();
65
- let xSpan;
66
- [xGap, xSpan] = [
67
- Math.abs(box0.left - box1.right),
68
- Math.abs(box0.right - box1.left),
69
- ].sort(internal.compareNumbers);
70
- xPadding = clientWidth - xSpan;
71
- }
72
- }
73
- this.setState({ clientWidth, xGap, xPadding });
74
- };
75
- this.timeScrollResponder = new internal.ScrollResponder((_time) => {
76
- // HACK to scroll to day
77
- if (this.state.clientWidth != null) {
78
- const { currentDate } = this.props.dateProfile;
79
- const rootEl = this.rootElRef.current;
80
- const innerEl = this.innerElRef.current;
81
- const monthEl = innerEl.querySelector(`[data-date="${internal.formatIsoMonthStr(currentDate)}"]`);
82
- rootEl.scrollTop = Math.ceil(// for fractions, err on the side of scrolling further
69
+ const monthEl = innerEl.querySelector(`[data-date="${internal.formatIsoMonthStr(this.scrollDate)}"]`);
70
+ const scrollTop = Math.ceil(// for fractions, err on the side of scrolling further
83
71
  monthEl.getBoundingClientRect().top -
84
72
  innerEl.getBoundingClientRect().top);
85
- return true;
73
+ scroller.scrollTo({ y: scrollTop });
86
74
  }
87
- return false;
88
- });
75
+ };
76
+ this.clearScroll = () => {
77
+ this.scrollDate = null;
78
+ };
89
79
  }
90
80
  render() {
91
81
  const { context, props, state } = this;
92
82
  const { options } = context;
93
- const colCount = state.clientWidth == null
94
- ? 2
95
- : Math.min(options.multiMonthMaxColumns, Math.floor((state.clientWidth - state.xPadding + state.xGap) /
96
- (options.multiMonthMinWidth + state.xGap)));
97
- const monthWidth = state.clientWidth == null
98
- ? '34%' // will expand. now small enough to be 1/3. for allowing gap
99
- : Math.floor(// exact values can cause expansion to other rows
100
- (state.clientWidth - state.xPadding - (state.xGap * (colCount - 1))) /
101
- colCount);
83
+ const verticalScrolling = !props.forPrint && !internal.getIsHeightAuto(options);
102
84
  const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv, options.fixedWeekCount, options.showNonCurrentDates);
103
85
  const monthTitleFormat = this.buildMonthFormat(options.multiMonthTitleFormat, monthDateProfiles);
104
- const rootClassNames = [
105
- 'fc-multimonth-view',
106
- (colCount === 1) ?
86
+ const { multiMonthMinWidth, multiMonthMaxColumns } = options;
87
+ const { innerWidth } = state;
88
+ let cols;
89
+ let computedMonthWidth;
90
+ let cssMonthWidth;
91
+ let hasLateralSiblings = false;
92
+ if (innerWidth != null) {
93
+ cols = Math.max(1, Math.min(multiMonthMaxColumns, Math.floor(innerWidth / multiMonthMinWidth)));
94
+ if (props.forPrint) {
95
+ cols = Math.min(cols, 2);
96
+ }
97
+ computedMonthWidth = innerWidth / cols;
98
+ cssMonthWidth = internal.fracToCssDim(1 / cols);
99
+ hasLateralSiblings = cols > 1;
100
+ }
101
+ return (preact.createElement(internal.NowTimer, { unit: "day" }, (nowDate, todayRange) => (preact.createElement(internal.ViewContainer, { className: internal.joinClassNames('fc-multimonth fc-border', (cols === 1) ?
107
102
  'fc-multimonth-singlecol' :
108
- 'fc-multimonth-multicol',
109
- internal.getIsHeightAuto(options) ?
110
- '' :
111
- 'fc-multimonth-scroll',
112
- 'fc-border', // BAD to mix this with size-listening?
113
- ];
114
- return (preact.createElement(internal.NowTimer, { unit: "day" }, (nowDate, todayRange) => (preact.createElement(internal.ViewContainer, { elRef: this.rootElRef, elClasses: rootClassNames, viewSpec: context.viewSpec },
115
- preact.createElement("div", { ref: this.innerElRef, className: 'fc-multimonth-inner' }, monthDateProfiles.map((monthDateProfile, i) => {
116
- const monthStr = internal.formatIsoMonthStr(monthDateProfile.currentRange.start);
117
- return (preact.createElement(SingleMonth, Object.assign({}, props, { key: monthStr, todayRange: todayRange, isoDateStr: monthStr, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: monthWidth })));
118
- }))))));
103
+ 'fc-multimonth-multicol',
104
+ // HACK for Safari. Can't do break-inside:avoid with flexbox items, likely b/c it's not standard:
105
+ // https://stackoverflow.com/a/60256345
106
+ !props.forPrint && 'fc-flex-col'), viewSpec: context.viewSpec },
107
+ preact.createElement(internal.Scroller, { vertical: verticalScrolling, className: verticalScrolling ? 'fc-liquid' : '', ref: this.scrollerRef },
108
+ preact.createElement("div", { ref: this.innerElRef, className: 'fc-multimonth-inner' }, monthDateProfiles.map((monthDateProfile) => {
109
+ const monthStr = internal.formatIsoMonthStr(monthDateProfile.currentRange.start);
110
+ return (preact.createElement(SingleMonth, Object.assign({}, props, { key: monthStr, todayRange: todayRange, isoDateStr: monthStr, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: cssMonthWidth, visibleWidth: computedMonthWidth, hasLateralSiblings: hasLateralSiblings })));
111
+ })))))));
119
112
  }
113
+ // Lifecycle
114
+ // -----------------------------------------------------------------------------------------------
120
115
  componentDidMount() {
121
- const { context } = this;
122
- const { options } = context;
123
- this.unwatchWidth = internal.watchWidth(this.rootElRef.current, this.handleClientWidth);
124
- context.emitter.on('_timeScrollRequest', this.timeScrollResponder.handleScroll);
125
- this.timeScrollResponder.handleScroll(options.scrollTime);
116
+ this.resetScroll();
117
+ this.scrollerRef.current.addScrollEndListener(this.clearScroll);
118
+ this.disconnectInnerWidth = internal.watchWidth(this.innerElRef.current, (innerWidth) => {
119
+ internal.afterSize(() => {
120
+ this.setState({ innerWidth });
121
+ });
122
+ });
126
123
  }
127
124
  componentDidUpdate(prevProps) {
128
- const { options } = this.context;
129
- if (prevProps.dateProfile !== this.props.dateProfile && options.scrollTimeReset) {
130
- this.timeScrollResponder.handleScroll(options.scrollTime);
125
+ if (prevProps.dateProfile !== this.props.dateProfile && this.context.options.scrollTimeReset) {
126
+ this.resetScroll();
131
127
  }
132
128
  else {
133
- this.timeScrollResponder.drain();
129
+ // NOT optimal to update so often
130
+ // TODO: isolate dependencies of scroll coordinate
131
+ this.updateScroll();
134
132
  }
135
133
  }
136
134
  componentWillUnmount() {
137
- this.unwatchWidth();
138
- this.context.emitter.off('_timeScrollRequest', this.timeScrollResponder.handleScroll);
135
+ this.scrollerRef.current.removeScrollEndListener(this.clearScroll);
136
+ this.disconnectInnerWidth();
137
+ }
138
+ // Scrolling
139
+ // -----------------------------------------------------------------------------------------------
140
+ resetScroll() {
141
+ this.scrollDate = this.props.dateProfile.currentDate;
142
+ this.updateScroll();
139
143
  }
140
144
  }
141
145
  // date profile
@@ -201,7 +205,7 @@ FullCalendar.MultiMonth = (function (exports, core, internal$1, internal, preact
201
205
  multiMonthMinWidth: Number,
202
206
  };
203
207
 
204
- var css_248z = ".fc-multimonth-scroll{overflow-x:hidden;overflow-y:scroll}.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}";
208
+ var css_248z = ".fc-media-screen .fc-multimonth-inner{display:flex;flex-direction:row;flex-wrap:wrap}.fc-media-print.fc-direction-ltr .fc-multimonth-inner>*{float:left}.fc-media-print.fc-direction-rtl .fc-multimonth-inner>*{float:right}.fc-media-print .fc-multimonth-inner:after{clear:both;content:\"\";display:block}.fc-multimonth-multicol .fc-multimonth-month{padding:1.2em}.fc-multimonth-singlecol .fc-multimonth-title{padding:.5em 0}.fc-multimonth-multicol .fc-multimonth-title{padding-bottom:1em}.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-body:not(.fc-multimonth-singlecol .fc-multimonth-month:last-child .fc-multimonth-body),.fc-multimonth-header-row{border-bottom:1px solid var(--fc-border-color)}.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}";
205
209
  internal.injectStyles(css_248z);
206
210
 
207
211
  var plugin = core.createPlugin({
@@ -219,7 +223,7 @@ FullCalendar.MultiMonth = (function (exports, core, internal$1, internal, preact
219
223
  type: 'multiMonth',
220
224
  duration: { years: 1 },
221
225
  fixedWeekCount: true,
222
- showNonCurrentDates: false,
226
+ showNonCurrentDates: false, // TODO: looks bad when single-col layout
223
227
  },
224
228
  },
225
229
  });
@@ -1,6 +1,6 @@
1
1
  /*!
2
- FullCalendar Multi-Month Plugin v7.0.0-beta.0
2
+ FullCalendar Multi-Month Plugin v7.0.0-beta.3
3
3
  Docs & License: https://fullcalendar.io/docs/multimonth-grid
4
4
  (c) 2024 Adam Shaw
5
5
  */
6
- FullCalendar.MultiMonth=function(e,t,n,o,l){"use strict";class i extends o.DateComponent{constructor(){super(...arguments),this.slicer=new n.DayTableSlicer,this.buildDayTableModel=o.memoize(n.buildDayTableModel),this.createDayHeaderFormatter=o.memoize(n.createDayHeaderFormatter)}render(){const{props:e,context:t}=this,{dateProfile:o,forPrint:i}=e,{options:r}=t,a=this.buildDayTableModel(o,t.dateProfileGenerator),s=this.slicer.sliceProps(e,o,r.nextDayThreshold,t,a),c="number"==typeof e.width?e.width/r.aspectRatio:null,m=a.cellRows.length,d=null!=c?c/m:null,h=this.createDayHeaderFormatter(t.options.dayHeaderFormat,!1,a.colCnt);return l.createElement("div",{"data-date":e.isoDateStr,role:"grid",className:"fc-multimonth-month fc-grow",style:{width:e.width}},l.createElement("div",{className:"fc-multimonth-header",style:{marginBottom:d},role:"presentation"},l.createElement("div",{className:"fc-multimonth-title"},t.dateEnv.format(e.dateProfile.currentRange.start,e.titleFormat)),l.createElement("div",{className:"fc-multimonth-header-row fc-flex-row"},a.headerDates.map(e=>l.createElement(n.DayOfWeekHeaderCell,{key:e.getUTCDay(),dow:e.getUTCDay(),dayHeaderFormat:h,colWidth:void 0})))),l.createElement("div",{className:"fc-multimonth-body fc-flex-column",style:{marginTop:-d,height:i?"":c}},l.createElement(n.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 r extends o.DateComponent{constructor(){super(...arguments),this.splitDateProfileByMonth=o.memoize(s),this.buildMonthFormat=o.memoize(d),this.rootElRef=l.createRef(),this.innerElRef=l.createRef(),this.handleClientWidth=e=>{let{xGap:t,xPadding:n}=this.state;if(null==t){const l=this.innerElRef.current.childNodes;if(l.length>1){const i=l[0].getBoundingClientRect(),r=l[1].getBoundingClientRect();let a;[t,a]=[Math.abs(i.left-r.right),Math.abs(i.right-r.left)].sort(o.compareNumbers),n=e-a}}this.setState({clientWidth:e,xGap:t,xPadding:n})},this.timeScrollResponder=new o.ScrollResponder(e=>{if(null!=this.state.clientWidth){const{currentDate:e}=this.props.dateProfile,t=this.rootElRef.current,n=this.innerElRef.current,l=n.querySelector(`[data-date="${o.formatIsoMonthStr(e)}"]`);return t.scrollTop=Math.ceil(l.getBoundingClientRect().top-n.getBoundingClientRect().top),!0}return!1})}render(){const{context:e,props:t,state:n}=this,{options:r}=e,a=null==n.clientWidth?2:Math.min(r.multiMonthMaxColumns,Math.floor((n.clientWidth-n.xPadding+n.xGap)/(r.multiMonthMinWidth+n.xGap))),s=null==n.clientWidth?"34%":Math.floor((n.clientWidth-n.xPadding-n.xGap*(a-1))/a),c=this.splitDateProfileByMonth(e.dateProfileGenerator,t.dateProfile,e.dateEnv,r.fixedWeekCount,r.showNonCurrentDates),m=this.buildMonthFormat(r.multiMonthTitleFormat,c),d=["fc-multimonth-view",1===a?"fc-multimonth-singlecol":"fc-multimonth-multicol",o.getIsHeightAuto(r)?"":"fc-multimonth-scroll","fc-border"];return l.createElement(o.NowTimer,{unit:"day"},(n,r)=>l.createElement(o.ViewContainer,{elRef:this.rootElRef,elClasses:d,viewSpec:e.viewSpec},l.createElement("div",{ref:this.innerElRef,className:"fc-multimonth-inner"},c.map((e,n)=>{const a=o.formatIsoMonthStr(e.currentRange.start);return l.createElement(i,Object.assign({},t,{key:a,todayRange:r,isoDateStr:a,titleFormat:m,dateProfile:e,width:s}))}))))}componentDidMount(){const{context:e}=this,{options:t}=e;this.unwatchWidth=o.watchWidth(this.rootElRef.current,this.handleClientWidth),e.emitter.on("_timeScrollRequest",this.timeScrollResponder.handleScroll),this.timeScrollResponder.handleScroll(t.scrollTime)}componentDidUpdate(e){const{options:t}=this.context;e.dateProfile!==this.props.dateProfile&&t.scrollTimeReset?this.timeScrollResponder.handleScroll(t.scrollTime):this.timeScrollResponder.drain()}componentWillUnmount(){this.unwatchWidth(),this.context.emitter.off("_timeScrollRequest",this.timeScrollResponder.handleScroll)}}const a=o.createDuration(1,"month");function s(e,t,l,i,r){const{start:s,end:c}=t.currentRange;let m=s;const d=[];for(;m.valueOf()<c.valueOf();){const s=l.add(m,a),c={start:e.skipHiddenDays(m),end:e.skipHiddenDays(s,-1,!0)};let h=n.buildDayTableRenderRange({currentRange:c,snapToWeek:!0,fixedWeekCount:i,dateEnv:l});h={start:e.skipHiddenDays(h.start),end:e.skipHiddenDays(h.end,-1,!0)};const u=t.activeRange?o.intersectRanges(t.activeRange,r?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=o.createFormatter({year:"numeric",month:"long"}),m=o.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:o.createFormatter,multiMonthMaxColumns:Number,multiMonthMinWidth:Number};o.injectStyles(".fc-multimonth-scroll{overflow-x:hidden;overflow-y:scroll}.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:r,dateProfileGeneratorClass:n.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);
6
+ FullCalendar.MultiMonth=function(e,t,i,n,r){"use strict";class o extends n.DateComponent{constructor(){super(...arguments),this.buildDayTableModel=n.memoize(i.buildDayTableModel),this.createDayHeaderFormatter=n.memoize(i.createDayHeaderFormatter),this.buildDateRowConfig=n.memoize(i.buildDateRowConfig),this.slicer=new i.DayTableSlicer}render(){const{props:e,context:t}=this,{dateProfile:o,forPrint:l}=e,{options:a}=t,s=this.buildDayTableModel(o,t.dateProfileGenerator),c=this.slicer.sliceProps(e,o,a.nextDayThreshold,t,s),m=this.createDayHeaderFormatter(a.dayHeaderFormat,!1,s.colCnt),d=this.buildDateRowConfig(s.headerDates,!1,o,e.todayRange,m,t),h=1/a.aspectRatio,u=h/s.rowCnt,f=!l,g=!l||e.hasLateralSiblings;return r.createElement("div",{"data-date":e.isoDateStr,className:n.joinClassNames("fc-multimonth-month",e.hasLateralSiblings&&"fc-break-inside-avoid"),style:{width:e.width}},r.createElement("div",{className:"fc-multimonth-header",style:{marginBottom:f?n.fracToCssDim(u):void 0}},r.createElement("div",{className:"fc-multimonth-title"},t.dateEnv.format(e.dateProfile.currentRange.start,e.titleFormat)),r.createElement(i.DayGridHeaderRow,Object.assign({},d,{className:"fc-multimonth-header-row"}))),r.createElement("div",{className:n.joinClassNames("fc-multimonth-body",g&&"fc-rel"),style:{marginTop:f?n.fracToCssDim(-u):void 0,paddingBottom:g?n.fracToCssDim(h):void 0}},r.createElement(i.DayGridRows,{dateProfile:e.dateProfile,todayRange:e.todayRange,cellRows:s.cellRows,className:g?"fc-fill":"",forPrint:l&&!e.hasLateralSiblings,dayMaxEvents:l?void 0:a.dayMaxEvents,dayMaxEventRows:l&&e.hasLateralSiblings?1:a.dayMaxEventRows,fgEventSegs:c.fgEventSegs,bgEventSegs:c.bgEventSegs,businessHourSegs:c.businessHourSegs,dateSelectionSegs:c.dateSelectionSegs,eventDrag:c.eventDrag,eventResize:c.eventResize,eventSelection:c.eventSelection,visibleWidth:e.visibleWidth})))}}class l 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.updateScroll=()=>{if(null!=this.scrollDate&&null!=this.state.innerWidth){const e=this.scrollerRef.current,t=this.innerElRef.current,i=t.querySelector(`[data-date="${n.formatIsoMonthStr(this.scrollDate)}"]`),r=Math.ceil(i.getBoundingClientRect().top-t.getBoundingClientRect().top);e.scrollTo({y:r})}},this.clearScroll=()=>{this.scrollDate=null}}render(){const{context:e,props:t,state:i}=this,{options:l}=e,a=!t.forPrint&&!n.getIsHeightAuto(l),s=this.splitDateProfileByMonth(e.dateProfileGenerator,t.dateProfile,e.dateEnv,l.fixedWeekCount,l.showNonCurrentDates),c=this.buildMonthFormat(l.multiMonthTitleFormat,s),{multiMonthMinWidth:m,multiMonthMaxColumns:d}=l,{innerWidth:h}=i;let u,f,g,p=!1;return null!=h&&(u=Math.max(1,Math.min(d,Math.floor(h/m))),t.forPrint&&(u=Math.min(u,2)),f=h/u,g=n.fracToCssDim(1/u),p=u>1),r.createElement(n.NowTimer,{unit:"day"},(i,l)=>r.createElement(n.ViewContainer,{className:n.joinClassNames("fc-multimonth fc-border",1===u?"fc-multimonth-singlecol":"fc-multimonth-multicol",!t.forPrint&&"fc-flex-col"),viewSpec:e.viewSpec},r.createElement(n.Scroller,{vertical:a,className:a?"fc-liquid":"",ref:this.scrollerRef},r.createElement("div",{ref:this.innerElRef,className:"fc-multimonth-inner"},s.map(e=>{const i=n.formatIsoMonthStr(e.currentRange.start);return r.createElement(o,Object.assign({},t,{key:i,todayRange:l,isoDateStr:i,titleFormat:c,dateProfile:e,width:g,visibleWidth:f,hasLateralSiblings:p}))})))))}componentDidMount(){this.resetScroll(),this.scrollerRef.current.addScrollEndListener(this.clearScroll),this.disconnectInnerWidth=n.watchWidth(this.innerElRef.current,e=>{n.afterSize(()=>{this.setState({innerWidth:e})})})}componentDidUpdate(e){e.dateProfile!==this.props.dateProfile&&this.context.options.scrollTimeReset?this.resetScroll():this.updateScroll()}componentWillUnmount(){this.scrollerRef.current.removeScrollEndListener(this.clearScroll),this.disconnectInnerWidth()}resetScroll(){this.scrollDate=this.props.dateProfile.currentDate,this.updateScroll()}}const a=n.createDuration(1,"month");function s(e,t,r,o,l){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=i.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,l?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-media-screen .fc-multimonth-inner{display:flex;flex-direction:row;flex-wrap:wrap}.fc-media-print.fc-direction-ltr .fc-multimonth-inner>*{float:left}.fc-media-print.fc-direction-rtl .fc-multimonth-inner>*{float:right}.fc-media-print .fc-multimonth-inner:after{clear:both;content:"";display:block}.fc-multimonth-multicol .fc-multimonth-month{padding:1.2em}.fc-multimonth-singlecol .fc-multimonth-title{padding:.5em 0}.fc-multimonth-multicol .fc-multimonth-title{padding-bottom:1em}.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-body:not(.fc-multimonth-singlecol .fc-multimonth-month:last-child .fc-multimonth-body),.fc-multimonth-header-row{border-bottom:1px solid var(--fc-border-color)}.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:l,dateProfileGeneratorClass:i.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,15 +1,17 @@
1
1
  import { createPlugin } from '@fullcalendar/core/index.js';
2
- import { DayTableSlicer, buildDayTableModel, createDayHeaderFormatter, DayOfWeekHeaderCell, DayGridRows, buildDayTableRenderRange, TableDateProfileGenerator } from '@fullcalendar/daygrid/internal.js';
3
- import { DateComponent, memoize, compareNumbers, ScrollResponder, formatIsoMonthStr, getIsHeightAuto, NowTimer, ViewContainer, watchWidth, createDuration, intersectRanges, createFormatter, injectStyles } from '@fullcalendar/core/internal.js';
2
+ import { buildDayTableModel, createDayHeaderFormatter, buildDateRowConfig, DayTableSlicer, DayGridHeaderRow, DayGridRows, buildDayTableRenderRange, TableDateProfileGenerator } from '@fullcalendar/daygrid/internal.js';
3
+ import { DateComponent, memoize, joinClassNames, fracToCssDim, formatIsoMonthStr, getIsHeightAuto, NowTimer, ViewContainer, Scroller, watchWidth, afterSize, 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.slicer = new DayTableSlicer();
10
9
  // memo
11
10
  this.buildDayTableModel = memoize(buildDayTableModel);
12
11
  this.createDayHeaderFormatter = memoize(createDayHeaderFormatter);
12
+ this.buildDateRowConfig = memoize(buildDateRowConfig);
13
+ // internal
14
+ this.slicer = new DayTableSlicer();
13
15
  }
14
16
  render() {
15
17
  const { props, context } = this;
@@ -17,27 +19,31 @@ class SingleMonth extends DateComponent {
17
19
  const { options } = context;
18
20
  const dayTableModel = this.buildDayTableModel(dateProfile, context.dateProfileGenerator);
19
21
  const slicedProps = this.slicer.sliceProps(props, dateProfile, options.nextDayThreshold, context, dayTableModel);
20
- // ensure single-month has aspect ratio
21
- const tableHeight = typeof props.width === 'number'
22
- ? props.width / options.aspectRatio
23
- : null;
24
- const rowCnt = dayTableModel.cellRows.length;
25
- const rowHeight = tableHeight != null ? tableHeight / rowCnt : null;
26
- const dayHeaderFormat = this.createDayHeaderFormatter(context.options.dayHeaderFormat, false, // datesRepDistinctDays
22
+ const dayHeaderFormat = this.createDayHeaderFormatter(options.dayHeaderFormat, false, // datesRepDistinctDays
27
23
  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 } },
30
- createElement("div", { className: "fc-multimonth-header", style: { marginBottom: rowHeight }, role: "presentation" },
24
+ const rowConfig = this.buildDateRowConfig(dayTableModel.headerDates, false, // datesRepDistinctDays
25
+ dateProfile, props.todayRange, dayHeaderFormat, context);
26
+ const invAspectRatio = 1 / options.aspectRatio;
27
+ const invRowAspectRatio = invAspectRatio / dayTableModel.rowCnt;
28
+ const isHeaderSticky = !forPrint;
29
+ const isAspectRatio = !forPrint || props.hasLateralSiblings;
30
+ return (createElement("div", { "data-date": props.isoDateStr, className: joinClassNames('fc-multimonth-month', props.hasLateralSiblings && 'fc-break-inside-avoid'),
31
+ // override fc-liquid's basis. fc-grow isn't sufficient because doesn't set min-width:0
32
+ style: { width: props.width } },
33
+ createElement("div", { className: "fc-multimonth-header", style: {
34
+ marginBottom: isHeaderSticky ? fracToCssDim(invRowAspectRatio) : undefined,
35
+ } },
31
36
  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,
37
+ createElement(DayGridHeaderRow, Object.assign({}, rowConfig, { className: 'fc-multimonth-header-row' }))),
38
+ createElement("div", { className: joinClassNames('fc-multimonth-body', isAspectRatio && 'fc-rel'), style: {
39
+ marginTop: isHeaderSticky ? fracToCssDim(-invRowAspectRatio) : undefined,
40
+ paddingBottom: isAspectRatio ? fracToCssDim(invAspectRatio) : undefined,
36
41
  } },
37
- createElement(DayGridRows // .fc-grow
38
- , { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: dayTableModel.cellRows, forPrint: props.forPrint,
42
+ createElement(DayGridRows, { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: dayTableModel.cellRows, className: isAspectRatio ? 'fc-fill' : '', forPrint: forPrint && !props.hasLateralSiblings, dayMaxEvents: forPrint ? undefined : options.dayMaxEvents, dayMaxEventRows: (forPrint && props.hasLateralSiblings) ? 1 : options.dayMaxEventRows,
39
43
  // content
40
- fgEventSegs: slicedProps.fgEventSegs, bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventDrag: slicedProps.eventDrag, eventResize: slicedProps.eventResize, eventSelection: slicedProps.eventSelection }))));
44
+ fgEventSegs: slicedProps.fgEventSegs, bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventDrag: slicedProps.eventDrag, eventResize: slicedProps.eventResize, eventSelection: slicedProps.eventSelection,
45
+ // dimensions
46
+ visibleWidth: props.visibleWidth }))));
41
47
  }
42
48
  }
43
49
 
@@ -48,91 +54,89 @@ class MultiMonthView extends DateComponent {
48
54
  this.splitDateProfileByMonth = memoize(splitDateProfileByMonth);
49
55
  this.buildMonthFormat = memoize(buildMonthFormat);
50
56
  // ref
51
- this.rootElRef = createRef(); // also the scroll container
52
- this.innerElRef = createRef();
53
- this.handleClientWidth = (clientWidth) => {
54
- let { xGap, xPadding } = this.state;
55
- // for first time, assume 2 columns and query gap/padding
56
- if (xGap == null) {
57
+ this.scrollerRef = createRef();
58
+ this.innerElRef = createRef(); // .fc-multimonth-inner
59
+ this.scrollDate = null;
60
+ this.updateScroll = () => {
61
+ if (this.scrollDate != null &&
62
+ this.state.innerWidth != null // render completed?
63
+ ) {
64
+ const scroller = this.scrollerRef.current;
57
65
  const innerEl = this.innerElRef.current;
58
- const children = innerEl.childNodes;
59
- if (children.length > 1) {
60
- const box0 = children[0].getBoundingClientRect();
61
- const box1 = children[1].getBoundingClientRect();
62
- let xSpan;
63
- [xGap, xSpan] = [
64
- Math.abs(box0.left - box1.right),
65
- Math.abs(box0.right - box1.left),
66
- ].sort(compareNumbers);
67
- xPadding = clientWidth - xSpan;
68
- }
69
- }
70
- this.setState({ clientWidth, xGap, xPadding });
71
- };
72
- this.timeScrollResponder = new ScrollResponder((_time) => {
73
- // HACK to scroll to day
74
- if (this.state.clientWidth != null) {
75
- const { currentDate } = this.props.dateProfile;
76
- const rootEl = this.rootElRef.current;
77
- const innerEl = this.innerElRef.current;
78
- const monthEl = innerEl.querySelector(`[data-date="${formatIsoMonthStr(currentDate)}"]`);
79
- rootEl.scrollTop = Math.ceil(// for fractions, err on the side of scrolling further
66
+ const monthEl = innerEl.querySelector(`[data-date="${formatIsoMonthStr(this.scrollDate)}"]`);
67
+ const scrollTop = Math.ceil(// for fractions, err on the side of scrolling further
80
68
  monthEl.getBoundingClientRect().top -
81
69
  innerEl.getBoundingClientRect().top);
82
- return true;
70
+ scroller.scrollTo({ y: scrollTop });
83
71
  }
84
- return false;
85
- });
72
+ };
73
+ this.clearScroll = () => {
74
+ this.scrollDate = null;
75
+ };
86
76
  }
87
77
  render() {
88
78
  const { context, props, state } = this;
89
79
  const { options } = context;
90
- const colCount = state.clientWidth == null
91
- ? 2
92
- : Math.min(options.multiMonthMaxColumns, Math.floor((state.clientWidth - state.xPadding + state.xGap) /
93
- (options.multiMonthMinWidth + state.xGap)));
94
- const monthWidth = state.clientWidth == null
95
- ? '34%' // will expand. now small enough to be 1/3. for allowing gap
96
- : Math.floor(// exact values can cause expansion to other rows
97
- (state.clientWidth - state.xPadding - (state.xGap * (colCount - 1))) /
98
- colCount);
80
+ const verticalScrolling = !props.forPrint && !getIsHeightAuto(options);
99
81
  const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv, options.fixedWeekCount, options.showNonCurrentDates);
100
82
  const monthTitleFormat = this.buildMonthFormat(options.multiMonthTitleFormat, monthDateProfiles);
101
- const rootClassNames = [
102
- 'fc-multimonth-view',
103
- (colCount === 1) ?
83
+ const { multiMonthMinWidth, multiMonthMaxColumns } = options;
84
+ const { innerWidth } = state;
85
+ let cols;
86
+ let computedMonthWidth;
87
+ let cssMonthWidth;
88
+ let hasLateralSiblings = false;
89
+ if (innerWidth != null) {
90
+ cols = Math.max(1, Math.min(multiMonthMaxColumns, Math.floor(innerWidth / multiMonthMinWidth)));
91
+ if (props.forPrint) {
92
+ cols = Math.min(cols, 2);
93
+ }
94
+ computedMonthWidth = innerWidth / cols;
95
+ cssMonthWidth = fracToCssDim(1 / cols);
96
+ hasLateralSiblings = cols > 1;
97
+ }
98
+ return (createElement(NowTimer, { unit: "day" }, (nowDate, todayRange) => (createElement(ViewContainer, { className: joinClassNames('fc-multimonth fc-border', (cols === 1) ?
104
99
  'fc-multimonth-singlecol' :
105
- 'fc-multimonth-multicol',
106
- getIsHeightAuto(options) ?
107
- '' :
108
- 'fc-multimonth-scroll',
109
- 'fc-border', // BAD to mix this with size-listening?
110
- ];
111
- return (createElement(NowTimer, { unit: "day" }, (nowDate, todayRange) => (createElement(ViewContainer, { elRef: this.rootElRef, elClasses: rootClassNames, viewSpec: context.viewSpec },
112
- createElement("div", { ref: this.innerElRef, className: 'fc-multimonth-inner' }, monthDateProfiles.map((monthDateProfile, i) => {
113
- const monthStr = formatIsoMonthStr(monthDateProfile.currentRange.start);
114
- return (createElement(SingleMonth, Object.assign({}, props, { key: monthStr, todayRange: todayRange, isoDateStr: monthStr, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: monthWidth })));
115
- }))))));
100
+ 'fc-multimonth-multicol',
101
+ // HACK for Safari. Can't do break-inside:avoid with flexbox items, likely b/c it's not standard:
102
+ // https://stackoverflow.com/a/60256345
103
+ !props.forPrint && 'fc-flex-col'), viewSpec: context.viewSpec },
104
+ createElement(Scroller, { vertical: verticalScrolling, className: verticalScrolling ? 'fc-liquid' : '', ref: this.scrollerRef },
105
+ createElement("div", { ref: this.innerElRef, className: 'fc-multimonth-inner' }, monthDateProfiles.map((monthDateProfile) => {
106
+ const monthStr = formatIsoMonthStr(monthDateProfile.currentRange.start);
107
+ return (createElement(SingleMonth, Object.assign({}, props, { key: monthStr, todayRange: todayRange, isoDateStr: monthStr, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: cssMonthWidth, visibleWidth: computedMonthWidth, hasLateralSiblings: hasLateralSiblings })));
108
+ })))))));
116
109
  }
110
+ // Lifecycle
111
+ // -----------------------------------------------------------------------------------------------
117
112
  componentDidMount() {
118
- const { context } = this;
119
- const { options } = context;
120
- this.unwatchWidth = watchWidth(this.rootElRef.current, this.handleClientWidth);
121
- context.emitter.on('_timeScrollRequest', this.timeScrollResponder.handleScroll);
122
- this.timeScrollResponder.handleScroll(options.scrollTime);
113
+ this.resetScroll();
114
+ this.scrollerRef.current.addScrollEndListener(this.clearScroll);
115
+ this.disconnectInnerWidth = watchWidth(this.innerElRef.current, (innerWidth) => {
116
+ afterSize(() => {
117
+ this.setState({ innerWidth });
118
+ });
119
+ });
123
120
  }
124
121
  componentDidUpdate(prevProps) {
125
- const { options } = this.context;
126
- if (prevProps.dateProfile !== this.props.dateProfile && options.scrollTimeReset) {
127
- this.timeScrollResponder.handleScroll(options.scrollTime);
122
+ if (prevProps.dateProfile !== this.props.dateProfile && this.context.options.scrollTimeReset) {
123
+ this.resetScroll();
128
124
  }
129
125
  else {
130
- this.timeScrollResponder.drain();
126
+ // NOT optimal to update so often
127
+ // TODO: isolate dependencies of scroll coordinate
128
+ this.updateScroll();
131
129
  }
132
130
  }
133
131
  componentWillUnmount() {
134
- this.unwatchWidth();
135
- this.context.emitter.off('_timeScrollRequest', this.timeScrollResponder.handleScroll);
132
+ this.scrollerRef.current.removeScrollEndListener(this.clearScroll);
133
+ this.disconnectInnerWidth();
134
+ }
135
+ // Scrolling
136
+ // -----------------------------------------------------------------------------------------------
137
+ resetScroll() {
138
+ this.scrollDate = this.props.dateProfile.currentDate;
139
+ this.updateScroll();
136
140
  }
137
141
  }
138
142
  // date profile
@@ -198,7 +202,7 @@ const OPTION_REFINERS = {
198
202
  multiMonthMinWidth: Number,
199
203
  };
200
204
 
201
- var css_248z = ".fc-multimonth-scroll{overflow-x:hidden;overflow-y:scroll}.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}";
205
+ var css_248z = ".fc-media-screen .fc-multimonth-inner{display:flex;flex-direction:row;flex-wrap:wrap}.fc-media-print.fc-direction-ltr .fc-multimonth-inner>*{float:left}.fc-media-print.fc-direction-rtl .fc-multimonth-inner>*{float:right}.fc-media-print .fc-multimonth-inner:after{clear:both;content:\"\";display:block}.fc-multimonth-multicol .fc-multimonth-month{padding:1.2em}.fc-multimonth-singlecol .fc-multimonth-title{padding:.5em 0}.fc-multimonth-multicol .fc-multimonth-title{padding-bottom:1em}.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-body:not(.fc-multimonth-singlecol .fc-multimonth-month:last-child .fc-multimonth-body),.fc-multimonth-header-row{border-bottom:1px solid var(--fc-border-color)}.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}";
202
206
  injectStyles(css_248z);
203
207
 
204
208
  var index = createPlugin({
@@ -216,7 +220,7 @@ var index = createPlugin({
216
220
  type: 'multiMonth',
217
221
  duration: { years: 1 },
218
222
  fixedWeekCount: true,
219
- showNonCurrentDates: false,
223
+ showNonCurrentDates: false, // TODO: looks bad when single-col layout
220
224
  },
221
225
  },
222
226
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fullcalendar/multimonth",
3
- "version": "7.0.0-beta.0",
3
+ "version": "7.0.0-beta.3",
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": "7.0.0-beta.0"
15
+ "@fullcalendar/daygrid": "7.0.0-beta.3"
16
16
  },
17
17
  "peerDependencies": {
18
- "@fullcalendar/core": "7.0.0-beta.0"
18
+ "@fullcalendar/core": "7.0.0-beta.3"
19
19
  },
20
20
  "type": "module",
21
21
  "bugs": "https://fullcalendar.io/reporting-bugs",