@fullcalendar/multimonth 7.0.0-beta.1 → 7.0.0-beta.4

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,13 @@ 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();
19
+ this.titleId = internal_cjs.getUniqueDomId();
17
20
  }
18
21
  render() {
19
22
  const { props, context } = this;
@@ -21,27 +24,30 @@ class SingleMonth extends internal_cjs.DateComponent {
21
24
  const { options } = context;
22
25
  const dayTableModel = this.buildDayTableModel(dateProfile, context.dateProfileGenerator);
23
26
  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
27
+ const dayHeaderFormat = this.createDayHeaderFormatter(options.dayHeaderFormat, false, // datesRepDistinctDays
31
28
  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" },
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 }))));
29
+ const rowConfig = this.buildDateRowConfig(dayTableModel.headerDates, false, // datesRepDistinctDays
30
+ dateProfile, props.todayRange, dayHeaderFormat, context);
31
+ const invAspectRatio = 1 / options.aspectRatio;
32
+ const invRowAspectRatio = invAspectRatio / dayTableModel.rowCnt;
33
+ const isHeaderSticky = !forPrint;
34
+ const isAspectRatio = !forPrint || props.hasLateralSiblings;
35
+ return (preact_cjs.createElement("div", { role: 'listitem', className: 'fc-multimonth-month-outer', style: { width: props.width } },
36
+ preact_cjs.createElement("div", { role: 'grid', "aria-labelledby": this.titleId, "data-date": props.isoDateStr, className: internal_cjs.joinClassNames('fc-multimonth-month', props.hasLateralSiblings && 'fc-break-inside-avoid') },
37
+ preact_cjs.createElement("div", { className: "fc-multimonth-header", style: {
38
+ marginBottom: isHeaderSticky ? internal_cjs.fracToCssDim(invRowAspectRatio) : undefined,
39
+ } },
40
+ preact_cjs.createElement("div", { id: this.titleId, className: 'fc-multimonth-title' }, context.dateEnv.format(props.dateProfile.currentRange.start, props.titleFormat)),
41
+ preact_cjs.createElement(internal_cjs$1.DayGridHeaderRow, Object.assign({}, rowConfig, { role: 'row', 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,
45
+ } },
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,
47
+ // content
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
 
@@ -53,82 +59,57 @@ class MultiMonthView extends internal_cjs.DateComponent {
53
59
  this.buildMonthFormat = internal_cjs.memoize(buildMonthFormat);
54
60
  // ref
55
61
  this.scrollerRef = preact_cjs.createRef();
56
- this.innerElRef = preact_cjs.createRef();
57
- // internal
62
+ this.innerElRef = preact_cjs.createRef(); // .fc-multimonth-inner
58
63
  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
- }
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 });
64
+ this.handleScrollEnd = ({ isUser }) => {
65
+ if (isUser) {
66
+ this.scrollDate = null;
89
67
  }
90
68
  };
91
- this.clearScroll = () => {
92
- this.scrollDate = null;
93
- };
94
69
  }
95
70
  render() {
96
71
  const { context, props, state } = this;
97
72
  const { options } = context;
98
73
  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
74
  const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv, options.fixedWeekCount, options.showNonCurrentDates);
109
75
  const monthTitleFormat = this.buildMonthFormat(options.multiMonthTitleFormat, monthDateProfiles);
110
- const rootClassNames = [
111
- 'fc-multimonth-view',
112
- (colCount === 1) ?
76
+ const { multiMonthMinWidth, multiMonthMaxColumns } = options;
77
+ const { innerWidth } = state;
78
+ let cols;
79
+ let computedMonthWidth;
80
+ let cssMonthWidth;
81
+ let hasLateralSiblings = false;
82
+ if (innerWidth != null) {
83
+ cols = Math.max(1, Math.min(multiMonthMaxColumns, Math.floor(innerWidth / multiMonthMinWidth)));
84
+ if (props.forPrint) {
85
+ cols = Math.min(cols, 2);
86
+ }
87
+ computedMonthWidth = innerWidth / cols;
88
+ cssMonthWidth = internal_cjs.fracToCssDim(1 / cols);
89
+ hasLateralSiblings = cols > 1;
90
+ }
91
+ return (preact_cjs.createElement(internal_cjs.NowTimer, { unit: "day" }, (nowDate, todayRange) => (preact_cjs.createElement(internal_cjs.ViewContainer, { viewSpec: context.viewSpec, className: internal_cjs.joinClassNames('fc-multimonth fc-border', (cols === 1) ?
113
92
  'fc-multimonth-singlecol' :
114
- 'fc-multimonth-multicol',
115
- 'fc-flex-column',
116
- 'fc-border', // BAD to mix this with size-listening?
117
- ];
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) => {
93
+ 'fc-multimonth-multicol',
94
+ // HACK for Safari. Can't do break-inside:avoid with flexbox items, likely b/c it's not standard:
95
+ // https://stackoverflow.com/a/60256345
96
+ !props.forPrint && 'fc-flex-col') },
97
+ preact_cjs.createElement(internal_cjs.Scroller, { vertical: verticalScrolling, className: verticalScrolling ? 'fc-liquid' : '', ref: this.scrollerRef },
98
+ preact_cjs.createElement("div", { role: 'list', "aria-labelledby": props.labelId, "aria-label": props.labelStr, className: 'fc-multimonth-inner', ref: this.innerElRef }, monthDateProfiles.map((monthDateProfile) => {
123
99
  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 })));
100
+ return (preact_cjs.createElement(SingleMonth, Object.assign({}, props, { key: monthStr, todayRange: todayRange, isoDateStr: monthStr, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: cssMonthWidth, visibleWidth: computedMonthWidth, hasLateralSiblings: hasLateralSiblings })));
125
101
  })))))));
126
102
  }
127
103
  // Lifecycle
128
104
  // -----------------------------------------------------------------------------------------------
129
105
  componentDidMount() {
130
106
  this.resetScroll();
131
- this.scrollerRef.current.addScrollEndListener(this.clearScroll);
107
+ this.scrollerRef.current.addScrollEndListener(this.handleScrollEnd);
108
+ this.disconnectInnerWidth = internal_cjs.watchWidth(this.innerElRef.current, (innerWidth) => {
109
+ internal_cjs.afterSize(() => {
110
+ this.setState({ innerWidth });
111
+ });
112
+ });
132
113
  }
133
114
  componentDidUpdate(prevProps) {
134
115
  if (prevProps.dateProfile !== this.props.dateProfile && this.context.options.scrollTimeReset) {
@@ -137,17 +118,31 @@ class MultiMonthView extends internal_cjs.DateComponent {
137
118
  else {
138
119
  // NOT optimal to update so often
139
120
  // TODO: isolate dependencies of scroll coordinate
140
- this.updateScroll();
121
+ this.applyScroll();
141
122
  }
142
123
  }
143
124
  componentWillUnmount() {
144
- this.scrollerRef.current.removeScrollEndListener(this.clearScroll);
125
+ this.scrollerRef.current.removeScrollEndListener(this.handleScrollEnd);
126
+ this.disconnectInnerWidth();
145
127
  }
146
128
  // Scrolling
147
129
  // -----------------------------------------------------------------------------------------------
148
130
  resetScroll() {
149
131
  this.scrollDate = this.props.dateProfile.currentDate;
150
- this.updateScroll();
132
+ this.applyScroll();
133
+ }
134
+ applyScroll() {
135
+ if (this.scrollDate != null &&
136
+ this.state.innerWidth != null // render completed?
137
+ ) {
138
+ const scroller = this.scrollerRef.current;
139
+ const innerEl = this.innerElRef.current;
140
+ const monthEl = innerEl.querySelector(`[data-date="${internal_cjs.formatIsoMonthStr(this.scrollDate)}"]`);
141
+ const scrollTop = Math.ceil(// for fractions, err on the side of scrolling further
142
+ monthEl.getBoundingClientRect().top -
143
+ innerEl.getBoundingClientRect().top);
144
+ scroller.scrollTo({ y: scrollTop });
145
+ }
151
146
  }
152
147
  }
153
148
  // date profile
@@ -213,7 +208,7 @@ const OPTION_REFINERS = {
213
208
  multiMonthMinWidth: Number,
214
209
  };
215
210
 
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}";
211
+ 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-outer: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}";
217
212
  internal_cjs.injectStyles(css_248z);
218
213
 
219
214
  var index = index_cjs.createPlugin({
@@ -231,7 +226,7 @@ var index = index_cjs.createPlugin({
231
226
  type: 'multiMonth',
232
227
  duration: { years: 1 },
233
228
  fixedWeekCount: true,
234
- showNonCurrentDates: false,
229
+ showNonCurrentDates: false, // TODO: looks bad when single-col layout
235
230
  },
236
231
  },
237
232
  });
package/index.global.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- FullCalendar Multi-Month Plugin v7.0.0-beta.1
2
+ FullCalendar Multi-Month Plugin v7.0.0-beta.4
3
3
  Docs & License: https://fullcalendar.io/docs/multimonth-grid
4
4
  (c) 2024 Adam Shaw
5
5
  */
@@ -9,10 +9,13 @@ 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();
18
+ this.titleId = internal.getUniqueDomId();
16
19
  }
17
20
  render() {
18
21
  const { props, context } = this;
@@ -20,27 +23,30 @@ FullCalendar.MultiMonth = (function (exports, core, internal$1, internal, preact
20
23
  const { options } = context;
21
24
  const dayTableModel = this.buildDayTableModel(dateProfile, context.dateProfileGenerator);
22
25
  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
26
+ const dayHeaderFormat = this.createDayHeaderFormatter(options.dayHeaderFormat, false, // datesRepDistinctDays
30
27
  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" },
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 }))));
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.createElement("div", { role: 'listitem', className: 'fc-multimonth-month-outer', style: { width: props.width } },
35
+ preact.createElement("div", { role: 'grid', "aria-labelledby": this.titleId, "data-date": props.isoDateStr, className: internal.joinClassNames('fc-multimonth-month', props.hasLateralSiblings && 'fc-break-inside-avoid') },
36
+ preact.createElement("div", { className: "fc-multimonth-header", style: {
37
+ marginBottom: isHeaderSticky ? internal.fracToCssDim(invRowAspectRatio) : undefined,
38
+ } },
39
+ preact.createElement("div", { id: this.titleId, className: 'fc-multimonth-title' }, context.dateEnv.format(props.dateProfile.currentRange.start, props.titleFormat)),
40
+ preact.createElement(internal$1.DayGridHeaderRow, Object.assign({}, rowConfig, { role: 'row', 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,
44
+ } },
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,
46
+ // content
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
 
@@ -52,82 +58,57 @@ FullCalendar.MultiMonth = (function (exports, core, internal$1, internal, preact
52
58
  this.buildMonthFormat = internal.memoize(buildMonthFormat);
53
59
  // ref
54
60
  this.scrollerRef = preact.createRef();
55
- this.innerElRef = preact.createRef();
56
- // internal
61
+ this.innerElRef = preact.createRef(); // .fc-multimonth-inner
57
62
  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
- }
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 });
63
+ this.handleScrollEnd = ({ isUser }) => {
64
+ if (isUser) {
65
+ this.scrollDate = null;
88
66
  }
89
67
  };
90
- this.clearScroll = () => {
91
- this.scrollDate = null;
92
- };
93
68
  }
94
69
  render() {
95
70
  const { context, props, state } = this;
96
71
  const { options } = context;
97
72
  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
73
  const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv, options.fixedWeekCount, options.showNonCurrentDates);
108
74
  const monthTitleFormat = this.buildMonthFormat(options.multiMonthTitleFormat, monthDateProfiles);
109
- const rootClassNames = [
110
- 'fc-multimonth-view',
111
- (colCount === 1) ?
75
+ const { multiMonthMinWidth, multiMonthMaxColumns } = options;
76
+ const { innerWidth } = state;
77
+ let cols;
78
+ let computedMonthWidth;
79
+ let cssMonthWidth;
80
+ let hasLateralSiblings = false;
81
+ if (innerWidth != null) {
82
+ cols = Math.max(1, Math.min(multiMonthMaxColumns, Math.floor(innerWidth / multiMonthMinWidth)));
83
+ if (props.forPrint) {
84
+ cols = Math.min(cols, 2);
85
+ }
86
+ computedMonthWidth = innerWidth / cols;
87
+ cssMonthWidth = internal.fracToCssDim(1 / cols);
88
+ hasLateralSiblings = cols > 1;
89
+ }
90
+ return (preact.createElement(internal.NowTimer, { unit: "day" }, (nowDate, todayRange) => (preact.createElement(internal.ViewContainer, { viewSpec: context.viewSpec, className: internal.joinClassNames('fc-multimonth fc-border', (cols === 1) ?
112
91
  'fc-multimonth-singlecol' :
113
- 'fc-multimonth-multicol',
114
- 'fc-flex-column',
115
- 'fc-border', // BAD to mix this with size-listening?
116
- ];
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) => {
92
+ 'fc-multimonth-multicol',
93
+ // HACK for Safari. Can't do break-inside:avoid with flexbox items, likely b/c it's not standard:
94
+ // https://stackoverflow.com/a/60256345
95
+ !props.forPrint && 'fc-flex-col') },
96
+ preact.createElement(internal.Scroller, { vertical: verticalScrolling, className: verticalScrolling ? 'fc-liquid' : '', ref: this.scrollerRef },
97
+ preact.createElement("div", { role: 'list', "aria-labelledby": props.labelId, "aria-label": props.labelStr, className: 'fc-multimonth-inner', ref: this.innerElRef }, monthDateProfiles.map((monthDateProfile) => {
122
98
  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 })));
99
+ return (preact.createElement(SingleMonth, Object.assign({}, props, { key: monthStr, todayRange: todayRange, isoDateStr: monthStr, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: cssMonthWidth, visibleWidth: computedMonthWidth, hasLateralSiblings: hasLateralSiblings })));
124
100
  })))))));
125
101
  }
126
102
  // Lifecycle
127
103
  // -----------------------------------------------------------------------------------------------
128
104
  componentDidMount() {
129
105
  this.resetScroll();
130
- this.scrollerRef.current.addScrollEndListener(this.clearScroll);
106
+ this.scrollerRef.current.addScrollEndListener(this.handleScrollEnd);
107
+ this.disconnectInnerWidth = internal.watchWidth(this.innerElRef.current, (innerWidth) => {
108
+ internal.afterSize(() => {
109
+ this.setState({ innerWidth });
110
+ });
111
+ });
131
112
  }
132
113
  componentDidUpdate(prevProps) {
133
114
  if (prevProps.dateProfile !== this.props.dateProfile && this.context.options.scrollTimeReset) {
@@ -136,17 +117,31 @@ FullCalendar.MultiMonth = (function (exports, core, internal$1, internal, preact
136
117
  else {
137
118
  // NOT optimal to update so often
138
119
  // TODO: isolate dependencies of scroll coordinate
139
- this.updateScroll();
120
+ this.applyScroll();
140
121
  }
141
122
  }
142
123
  componentWillUnmount() {
143
- this.scrollerRef.current.removeScrollEndListener(this.clearScroll);
124
+ this.scrollerRef.current.removeScrollEndListener(this.handleScrollEnd);
125
+ this.disconnectInnerWidth();
144
126
  }
145
127
  // Scrolling
146
128
  // -----------------------------------------------------------------------------------------------
147
129
  resetScroll() {
148
130
  this.scrollDate = this.props.dateProfile.currentDate;
149
- this.updateScroll();
131
+ this.applyScroll();
132
+ }
133
+ applyScroll() {
134
+ if (this.scrollDate != null &&
135
+ this.state.innerWidth != null // render completed?
136
+ ) {
137
+ const scroller = this.scrollerRef.current;
138
+ const innerEl = this.innerElRef.current;
139
+ const monthEl = innerEl.querySelector(`[data-date="${internal.formatIsoMonthStr(this.scrollDate)}"]`);
140
+ const scrollTop = Math.ceil(// for fractions, err on the side of scrolling further
141
+ monthEl.getBoundingClientRect().top -
142
+ innerEl.getBoundingClientRect().top);
143
+ scroller.scrollTo({ y: scrollTop });
144
+ }
150
145
  }
151
146
  }
152
147
  // date profile
@@ -212,7 +207,7 @@ FullCalendar.MultiMonth = (function (exports, core, internal$1, internal, preact
212
207
  multiMonthMinWidth: Number,
213
208
  };
214
209
 
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}";
210
+ 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-outer: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}";
216
211
  internal.injectStyles(css_248z);
217
212
 
218
213
  var plugin = core.createPlugin({
@@ -230,7 +225,7 @@ FullCalendar.MultiMonth = (function (exports, core, internal$1, internal, preact
230
225
  type: 'multiMonth',
231
226
  duration: { years: 1 },
232
227
  fixedWeekCount: true,
233
- showNonCurrentDates: false,
228
+ showNonCurrentDates: false, // TODO: looks bad when single-col layout
234
229
  },
235
230
  },
236
231
  });
@@ -1,6 +1,6 @@
1
1
  /*!
2
- FullCalendar Multi-Month Plugin v7.0.0-beta.1
2
+ FullCalendar Multi-Month Plugin v7.0.0-beta.4
3
3
  Docs & License: https://fullcalendar.io/docs/multimonth-grid
4
4
  (c) 2024 Adam Shaw
5
5
  */
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);
6
+ FullCalendar.MultiMonth=function(e,t,i,n,l){"use strict";class r 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,this.titleId=n.getUniqueDomId()}render(){const{props:e,context:t}=this,{dateProfile:r,forPrint:o}=e,{options:a}=t,s=this.buildDayTableModel(r,t.dateProfileGenerator),c=this.slicer.sliceProps(e,r,a.nextDayThreshold,t,s),m=this.createDayHeaderFormatter(a.dayHeaderFormat,!1,s.colCnt),d=this.buildDateRowConfig(s.headerDates,!1,r,e.todayRange,m,t),h=1/a.aspectRatio,u=h/s.rowCnt,f=!o,g=!o||e.hasLateralSiblings;return l.createElement("div",{role:"listitem",className:"fc-multimonth-month-outer",style:{width:e.width}},l.createElement("div",{role:"grid","aria-labelledby":this.titleId,"data-date":e.isoDateStr,className:n.joinClassNames("fc-multimonth-month",e.hasLateralSiblings&&"fc-break-inside-avoid")},l.createElement("div",{className:"fc-multimonth-header",style:{marginBottom:f?n.fracToCssDim(u):void 0}},l.createElement("div",{id:this.titleId,className:"fc-multimonth-title"},t.dateEnv.format(e.dateProfile.currentRange.start,e.titleFormat)),l.createElement(i.DayGridHeaderRow,Object.assign({},d,{role:"row",className:"fc-multimonth-header-row"}))),l.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}},l.createElement(i.DayGridRows,{dateProfile:e.dateProfile,todayRange:e.todayRange,cellRows:s.cellRows,className:g?"fc-fill":"",forPrint:o&&!e.hasLateralSiblings,dayMaxEvents:o?void 0:a.dayMaxEvents,dayMaxEventRows:o&&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 o extends n.DateComponent{constructor(){super(...arguments),this.splitDateProfileByMonth=n.memoize(s),this.buildMonthFormat=n.memoize(d),this.scrollerRef=l.createRef(),this.innerElRef=l.createRef(),this.scrollDate=null,this.handleScrollEnd=({isUser:e})=>{e&&(this.scrollDate=null)}}render(){const{context:e,props:t,state:i}=this,{options:o}=e,a=!t.forPrint&&!n.getIsHeightAuto(o),s=this.splitDateProfileByMonth(e.dateProfileGenerator,t.dateProfile,e.dateEnv,o.fixedWeekCount,o.showNonCurrentDates),c=this.buildMonthFormat(o.multiMonthTitleFormat,s),{multiMonthMinWidth:m,multiMonthMaxColumns:d}=o,{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),l.createElement(n.NowTimer,{unit:"day"},(i,o)=>l.createElement(n.ViewContainer,{viewSpec:e.viewSpec,className:n.joinClassNames("fc-multimonth fc-border",1===u?"fc-multimonth-singlecol":"fc-multimonth-multicol",!t.forPrint&&"fc-flex-col")},l.createElement(n.Scroller,{vertical:a,className:a?"fc-liquid":"",ref:this.scrollerRef},l.createElement("div",{role:"list","aria-labelledby":t.labelId,"aria-label":t.labelStr,className:"fc-multimonth-inner",ref:this.innerElRef},s.map(e=>{const i=n.formatIsoMonthStr(e.currentRange.start);return l.createElement(r,Object.assign({},t,{key:i,todayRange:o,isoDateStr:i,titleFormat:c,dateProfile:e,width:g,visibleWidth:f,hasLateralSiblings:p}))})))))}componentDidMount(){this.resetScroll(),this.scrollerRef.current.addScrollEndListener(this.handleScrollEnd),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.applyScroll()}componentWillUnmount(){this.scrollerRef.current.removeScrollEndListener(this.handleScrollEnd),this.disconnectInnerWidth()}resetScroll(){this.scrollDate=this.props.dateProfile.currentDate,this.applyScroll()}applyScroll(){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)}"]`),l=Math.ceil(i.getBoundingClientRect().top-t.getBoundingClientRect().top);e.scrollTo({y:l})}}}const a=n.createDuration(1,"month");function s(e,t,l,r,o){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=i.buildDayTableRenderRange({currentRange:c,snapToWeek:!0,fixedWeekCount:r,dateEnv:l});h={start:e.skipHiddenDays(h.start),end:e.skipHiddenDays(h.end,-1,!0)};const u=t.activeRange?n.intersectRanges(t.activeRange,o?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-outer: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:o,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,18 @@
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, formatIsoMonthStr, getIsHeightAuto, NowTimer, ViewContainer, Scroller, 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, getUniqueDomId, joinClassNames, fracToCssDim, getIsHeightAuto, NowTimer, ViewContainer, Scroller, formatIsoMonthStr, 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();
15
+ this.titleId = getUniqueDomId();
13
16
  }
14
17
  render() {
15
18
  const { props, context } = this;
@@ -17,27 +20,30 @@ class SingleMonth extends DateComponent {
17
20
  const { options } = context;
18
21
  const dayTableModel = this.buildDayTableModel(dateProfile, context.dateProfileGenerator);
19
22
  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
23
+ const dayHeaderFormat = this.createDayHeaderFormatter(options.dayHeaderFormat, false, // datesRepDistinctDays
27
24
  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" },
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 }))));
25
+ const rowConfig = this.buildDateRowConfig(dayTableModel.headerDates, false, // datesRepDistinctDays
26
+ dateProfile, props.todayRange, dayHeaderFormat, context);
27
+ const invAspectRatio = 1 / options.aspectRatio;
28
+ const invRowAspectRatio = invAspectRatio / dayTableModel.rowCnt;
29
+ const isHeaderSticky = !forPrint;
30
+ const isAspectRatio = !forPrint || props.hasLateralSiblings;
31
+ return (createElement("div", { role: 'listitem', className: 'fc-multimonth-month-outer', style: { width: props.width } },
32
+ createElement("div", { role: 'grid', "aria-labelledby": this.titleId, "data-date": props.isoDateStr, className: joinClassNames('fc-multimonth-month', props.hasLateralSiblings && 'fc-break-inside-avoid') },
33
+ createElement("div", { className: "fc-multimonth-header", style: {
34
+ marginBottom: isHeaderSticky ? fracToCssDim(invRowAspectRatio) : undefined,
35
+ } },
36
+ createElement("div", { id: this.titleId, className: 'fc-multimonth-title' }, context.dateEnv.format(props.dateProfile.currentRange.start, props.titleFormat)),
37
+ createElement(DayGridHeaderRow, Object.assign({}, rowConfig, { role: 'row', 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,
41
+ } },
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,
43
+ // content
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
 
@@ -49,82 +55,57 @@ class MultiMonthView extends DateComponent {
49
55
  this.buildMonthFormat = memoize(buildMonthFormat);
50
56
  // ref
51
57
  this.scrollerRef = createRef();
52
- this.innerElRef = createRef();
53
- // internal
58
+ this.innerElRef = createRef(); // .fc-multimonth-inner
54
59
  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
- }
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 });
60
+ this.handleScrollEnd = ({ isUser }) => {
61
+ if (isUser) {
62
+ this.scrollDate = null;
85
63
  }
86
64
  };
87
- this.clearScroll = () => {
88
- this.scrollDate = null;
89
- };
90
65
  }
91
66
  render() {
92
67
  const { context, props, state } = this;
93
68
  const { options } = context;
94
69
  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
70
  const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv, options.fixedWeekCount, options.showNonCurrentDates);
105
71
  const monthTitleFormat = this.buildMonthFormat(options.multiMonthTitleFormat, monthDateProfiles);
106
- const rootClassNames = [
107
- 'fc-multimonth-view',
108
- (colCount === 1) ?
72
+ const { multiMonthMinWidth, multiMonthMaxColumns } = options;
73
+ const { innerWidth } = state;
74
+ let cols;
75
+ let computedMonthWidth;
76
+ let cssMonthWidth;
77
+ let hasLateralSiblings = false;
78
+ if (innerWidth != null) {
79
+ cols = Math.max(1, Math.min(multiMonthMaxColumns, Math.floor(innerWidth / multiMonthMinWidth)));
80
+ if (props.forPrint) {
81
+ cols = Math.min(cols, 2);
82
+ }
83
+ computedMonthWidth = innerWidth / cols;
84
+ cssMonthWidth = fracToCssDim(1 / cols);
85
+ hasLateralSiblings = cols > 1;
86
+ }
87
+ return (createElement(NowTimer, { unit: "day" }, (nowDate, todayRange) => (createElement(ViewContainer, { viewSpec: context.viewSpec, className: joinClassNames('fc-multimonth fc-border', (cols === 1) ?
109
88
  'fc-multimonth-singlecol' :
110
- 'fc-multimonth-multicol',
111
- 'fc-flex-column',
112
- 'fc-border', // BAD to mix this with size-listening?
113
- ];
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) => {
89
+ 'fc-multimonth-multicol',
90
+ // HACK for Safari. Can't do break-inside:avoid with flexbox items, likely b/c it's not standard:
91
+ // https://stackoverflow.com/a/60256345
92
+ !props.forPrint && 'fc-flex-col') },
93
+ createElement(Scroller, { vertical: verticalScrolling, className: verticalScrolling ? 'fc-liquid' : '', ref: this.scrollerRef },
94
+ createElement("div", { role: 'list', "aria-labelledby": props.labelId, "aria-label": props.labelStr, className: 'fc-multimonth-inner', ref: this.innerElRef }, monthDateProfiles.map((monthDateProfile) => {
119
95
  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 })));
96
+ return (createElement(SingleMonth, Object.assign({}, props, { key: monthStr, todayRange: todayRange, isoDateStr: monthStr, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: cssMonthWidth, visibleWidth: computedMonthWidth, hasLateralSiblings: hasLateralSiblings })));
121
97
  })))))));
122
98
  }
123
99
  // Lifecycle
124
100
  // -----------------------------------------------------------------------------------------------
125
101
  componentDidMount() {
126
102
  this.resetScroll();
127
- this.scrollerRef.current.addScrollEndListener(this.clearScroll);
103
+ this.scrollerRef.current.addScrollEndListener(this.handleScrollEnd);
104
+ this.disconnectInnerWidth = watchWidth(this.innerElRef.current, (innerWidth) => {
105
+ afterSize(() => {
106
+ this.setState({ innerWidth });
107
+ });
108
+ });
128
109
  }
129
110
  componentDidUpdate(prevProps) {
130
111
  if (prevProps.dateProfile !== this.props.dateProfile && this.context.options.scrollTimeReset) {
@@ -133,17 +114,31 @@ class MultiMonthView extends DateComponent {
133
114
  else {
134
115
  // NOT optimal to update so often
135
116
  // TODO: isolate dependencies of scroll coordinate
136
- this.updateScroll();
117
+ this.applyScroll();
137
118
  }
138
119
  }
139
120
  componentWillUnmount() {
140
- this.scrollerRef.current.removeScrollEndListener(this.clearScroll);
121
+ this.scrollerRef.current.removeScrollEndListener(this.handleScrollEnd);
122
+ this.disconnectInnerWidth();
141
123
  }
142
124
  // Scrolling
143
125
  // -----------------------------------------------------------------------------------------------
144
126
  resetScroll() {
145
127
  this.scrollDate = this.props.dateProfile.currentDate;
146
- this.updateScroll();
128
+ this.applyScroll();
129
+ }
130
+ applyScroll() {
131
+ if (this.scrollDate != null &&
132
+ this.state.innerWidth != null // render completed?
133
+ ) {
134
+ const scroller = this.scrollerRef.current;
135
+ const innerEl = this.innerElRef.current;
136
+ const monthEl = innerEl.querySelector(`[data-date="${formatIsoMonthStr(this.scrollDate)}"]`);
137
+ const scrollTop = Math.ceil(// for fractions, err on the side of scrolling further
138
+ monthEl.getBoundingClientRect().top -
139
+ innerEl.getBoundingClientRect().top);
140
+ scroller.scrollTo({ y: scrollTop });
141
+ }
147
142
  }
148
143
  }
149
144
  // date profile
@@ -209,7 +204,7 @@ const OPTION_REFINERS = {
209
204
  multiMonthMinWidth: Number,
210
205
  };
211
206
 
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}";
207
+ 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-outer: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}";
213
208
  injectStyles(css_248z);
214
209
 
215
210
  var index = createPlugin({
@@ -227,7 +222,7 @@ var index = createPlugin({
227
222
  type: 'multiMonth',
228
223
  duration: { years: 1 },
229
224
  fixedWeekCount: true,
230
- showNonCurrentDates: false,
225
+ showNonCurrentDates: false, // TODO: looks bad when single-col layout
231
226
  },
232
227
  },
233
228
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fullcalendar/multimonth",
3
- "version": "7.0.0-beta.1",
3
+ "version": "7.0.0-beta.4",
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.1"
15
+ "@fullcalendar/daygrid": "7.0.0-beta.4"
16
16
  },
17
17
  "peerDependencies": {
18
- "@fullcalendar/core": "7.0.0-beta.1"
18
+ "@fullcalendar/core": "7.0.0-beta.4"
19
19
  },
20
20
  "type": "module",
21
21
  "bugs": "https://fullcalendar.io/reporting-bugs",