@fullcalendar/multimonth 6.1.0

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/LICENSE.md ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Adam Shaw
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,32 @@
1
+
2
+ # FullCalendar Multi-Month Plugin
3
+
4
+ Display a sequence or grid of multiple months
5
+
6
+ ## Installation
7
+
8
+ Install the necessary packages:
9
+
10
+ ```sh
11
+ npm install @fullcalendar/core @fullcalendar/multimonth
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ Instantiate a Calendar with the necessary plugin:
17
+
18
+ ```js
19
+ import { Calendar } from '@fullcalendar/core'
20
+ import multiMonthPlugin from '@fullcalendar/multimonth'
21
+
22
+ const calendarEl = document.getElementById('calendar')
23
+ const calendar = new Calendar(calendarEl, {
24
+ plugins: [multiMonthPlugin],
25
+ initialView: 'multiMonthYear',
26
+ events: [
27
+ { title: 'Meeting', start: new Date() }
28
+ ]
29
+ })
30
+
31
+ calendar.render()
32
+ ```
package/index.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ import { PluginDef } from '@fullcalendar/core';
2
+ import { createFormatter } from '@fullcalendar/core/internal';
3
+
4
+ declare const OPTION_REFINERS: {
5
+ multiMonthTitleFormat: typeof createFormatter;
6
+ multiMonthMaxColumns: NumberConstructor;
7
+ multiMonthMinWidth: NumberConstructor;
8
+ };
9
+
10
+ type ExtraOptionRefiners = typeof OPTION_REFINERS;
11
+ declare module '@fullcalendar/core/internal' {
12
+ interface BaseOptionRefiners extends ExtraOptionRefiners {
13
+ }
14
+ }
15
+ //# sourceMappingURL=ambient.d.ts.map
16
+
17
+ declare const _default: PluginDef;
18
+ //# sourceMappingURL=index.d.ts.map
19
+
20
+ export { _default as default };
package/index.esm.js ADDED
@@ -0,0 +1,238 @@
1
+ import { createPlugin } from '@fullcalendar/core';
2
+ import { buildDayTableModel, DayTableSlicer, TableRows, buildDayTableRenderRange, TableDateProfileGenerator } from '@fullcalendar/daygrid/internal';
3
+ import { DateComponent, memoize, getUniqueDomId, DayHeader, ViewContainer, formatIsoMonthStr, isPropsEqual, createDuration, intersectRanges, createFormatter, injectStyles } from '@fullcalendar/core/internal';
4
+ import { createElement, createRef } from '@fullcalendar/core/preact';
5
+
6
+ class SingleMonth extends DateComponent {
7
+ constructor() {
8
+ super(...arguments);
9
+ this.buildDayTableModel = memoize(buildDayTableModel);
10
+ this.slicer = new DayTableSlicer();
11
+ this.state = {
12
+ labelId: getUniqueDomId(),
13
+ };
14
+ }
15
+ render() {
16
+ const { props, state, context } = this;
17
+ const { dateProfile, forPrint } = props;
18
+ const { options } = context;
19
+ const dayTableModel = this.buildDayTableModel(dateProfile, context.dateProfileGenerator);
20
+ const slicedProps = this.slicer.sliceProps(props, dateProfile, options.nextDayThreshold, context, dayTableModel);
21
+ // ensure single-month has aspect ratio
22
+ const tableHeight = props.tableWidth != null ? props.tableWidth / options.aspectRatio : null;
23
+ const rowCnt = dayTableModel.cells.length;
24
+ const rowHeight = tableHeight != null ? tableHeight / rowCnt : null;
25
+ return (createElement("div", { ref: props.elRef, "data-date": props.isoDateStr, className: "fc-multimonth-month", style: { width: props.width }, role: "grid", "aria-labelledby": state.labelId },
26
+ createElement("div", { className: "fc-multimonth-header", style: { marginBottom: rowHeight }, role: "presentation" },
27
+ createElement("div", { className: "fc-multimonth-title", id: state.labelId }, context.dateEnv.format(props.dateProfile.currentRange.start, props.titleFormat)),
28
+ createElement("table", { className: [
29
+ 'fc-multimonth-header-table',
30
+ context.theme.getClass('table'),
31
+ ].join(' '), role: "presentation" },
32
+ createElement("thead", { role: "rowgroup" },
33
+ createElement(DayHeader, { dateProfile: props.dateProfile, dates: dayTableModel.headerDates, datesRepDistinctDays: false })))),
34
+ createElement("div", { className: [
35
+ 'fc-multimonth-daygrid',
36
+ 'fc-daygrid',
37
+ 'fc-daygrid-body',
38
+ !forPrint && 'fc-daygrid-body-balanced',
39
+ forPrint && 'fc-daygrid-body-unbalanced',
40
+ forPrint && 'fc-daygrid-body-natural',
41
+ ].join(' '), style: { marginTop: -rowHeight } },
42
+ createElement("table", { className: [
43
+ 'fc-multimonth-daygrid-table',
44
+ context.theme.getClass('table'),
45
+ ].join(' '), style: { height: forPrint ? '' : tableHeight }, role: "presentation" },
46
+ createElement("tbody", { role: "rowgroup" },
47
+ createElement(TableRows, Object.assign({}, slicedProps, { dateProfile: dateProfile, cells: dayTableModel.cells, eventSelection: props.eventSelection, dayMaxEvents: !forPrint, dayMaxEventRows: !forPrint, showWeekNumbers: options.weekNumbers, clientWidth: props.clientWidth, clientHeight: props.clientHeight, forPrint: forPrint })))))));
48
+ }
49
+ }
50
+
51
+ class MultiMonthView extends DateComponent {
52
+ constructor() {
53
+ super(...arguments);
54
+ this.splitDateProfileByMonth = memoize(splitDateProfileByMonth);
55
+ this.buildMonthFormat = memoize(buildMonthFormat);
56
+ this.scrollElRef = createRef();
57
+ this.firstMonthElRef = createRef();
58
+ this.needsScrollReset = false;
59
+ this.handleSizing = (isForced) => {
60
+ if (isForced) {
61
+ this.updateSize();
62
+ }
63
+ };
64
+ }
65
+ render() {
66
+ const { context, props, state } = this;
67
+ const { options } = context;
68
+ const { clientWidth, clientHeight } = state;
69
+ const monthHPadding = state.monthHPadding || 0;
70
+ const colCount = Math.min(clientWidth != null ?
71
+ Math.floor(clientWidth / (options.multiMonthMinWidth + monthHPadding)) :
72
+ 1, options.multiMonthMaxColumns) || 1;
73
+ const monthWidthPct = (100 / colCount) + '%';
74
+ const monthTableWidth = clientWidth == null ? null :
75
+ (clientWidth / colCount) - monthHPadding;
76
+ const isLegitSingleCol = clientWidth != null && colCount === 1;
77
+ const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv, isLegitSingleCol ? false : options.fixedWeekCount, options.showNonCurrentDates);
78
+ const monthTitleFormat = this.buildMonthFormat(options.multiMonthTitleFormat, monthDateProfiles);
79
+ const rootClassNames = [
80
+ 'fc-multimonth',
81
+ isLegitSingleCol ?
82
+ 'fc-multimonth-singlecol' :
83
+ 'fc-multimonth-multicol',
84
+ (monthTableWidth != null && monthTableWidth < 400) ?
85
+ 'fc-multimonth-compact' :
86
+ '',
87
+ ];
88
+ return (createElement(ViewContainer, { elRef: this.scrollElRef, elClasses: rootClassNames, viewSpec: context.viewSpec }, monthDateProfiles.map((monthDateProfile, i) => {
89
+ const monthStr = formatIsoMonthStr(monthDateProfile.currentRange.start);
90
+ return (createElement(SingleMonth, Object.assign({}, props, { key: monthStr, isoDateStr: monthStr, elRef: i === 0 ? this.firstMonthElRef : undefined, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: monthWidthPct, tableWidth: monthTableWidth, clientWidth: clientWidth, clientHeight: clientHeight })));
91
+ })));
92
+ }
93
+ componentDidMount() {
94
+ this.updateSize();
95
+ this.context.addResizeHandler(this.handleSizing);
96
+ this.requestScrollReset();
97
+ }
98
+ componentDidUpdate(prevProps) {
99
+ if (!isPropsEqual(prevProps, this.props)) { // an external change?
100
+ this.handleSizing(false);
101
+ }
102
+ if (prevProps.dateProfile !== this.props.dateProfile) {
103
+ this.requestScrollReset();
104
+ }
105
+ else {
106
+ this.flushScrollReset();
107
+ }
108
+ }
109
+ componentWillUnmount() {
110
+ this.context.removeResizeHandler(this.handleSizing);
111
+ }
112
+ updateSize() {
113
+ const scrollEl = this.scrollElRef.current;
114
+ const firstMonthEl = this.firstMonthElRef.current;
115
+ if (scrollEl) {
116
+ this.setState({
117
+ clientWidth: scrollEl.clientWidth,
118
+ clientHeight: scrollEl.clientHeight,
119
+ });
120
+ }
121
+ if (firstMonthEl && scrollEl) {
122
+ if (this.state.monthHPadding == null) { // always remember initial non-zero value
123
+ this.setState({
124
+ monthHPadding: scrollEl.clientWidth - // go within padding
125
+ firstMonthEl.firstChild.offsetWidth,
126
+ });
127
+ }
128
+ }
129
+ }
130
+ requestScrollReset() {
131
+ this.needsScrollReset = true;
132
+ this.flushScrollReset();
133
+ }
134
+ flushScrollReset() {
135
+ if (this.needsScrollReset &&
136
+ this.state.monthHPadding != null // indicates sizing already happened
137
+ ) {
138
+ const { currentDate } = this.props.dateProfile;
139
+ const scrollEl = this.scrollElRef.current;
140
+ const monthEl = scrollEl.querySelector(`[data-date="${formatIsoMonthStr(currentDate)}"]`);
141
+ scrollEl.scrollTop = monthEl.getBoundingClientRect().top -
142
+ this.firstMonthElRef.current.getBoundingClientRect().top;
143
+ this.needsScrollReset = false;
144
+ }
145
+ }
146
+ // workaround for when queued setState render (w/ clientWidth) gets cancelled because
147
+ // subsequent update and shouldComponentUpdate says not to render :(
148
+ shouldComponentUpdate() {
149
+ return true;
150
+ }
151
+ }
152
+ // date profile
153
+ // -------------------------------------------------------------------------------------------------
154
+ const oneMonthDuration = createDuration(1, 'month');
155
+ function splitDateProfileByMonth(dateProfileGenerator, dateProfile, dateEnv, fixedWeekCount, showNonCurrentDates) {
156
+ const { start, end } = dateProfile.currentRange;
157
+ let monthStart = start;
158
+ const monthDateProfiles = [];
159
+ while (monthStart.valueOf() < end.valueOf()) {
160
+ const monthEnd = dateEnv.add(monthStart, oneMonthDuration);
161
+ const currentRange = {
162
+ // yuck
163
+ start: dateProfileGenerator.skipHiddenDays(monthStart),
164
+ end: dateProfileGenerator.skipHiddenDays(monthEnd, -1, true),
165
+ };
166
+ let renderRange = buildDayTableRenderRange({
167
+ currentRange,
168
+ snapToWeek: true,
169
+ fixedWeekCount,
170
+ dateEnv,
171
+ });
172
+ renderRange = {
173
+ // yuck
174
+ start: dateProfileGenerator.skipHiddenDays(renderRange.start),
175
+ end: dateProfileGenerator.skipHiddenDays(renderRange.end, -1, true),
176
+ };
177
+ const activeRange = dateProfile.activeRange ?
178
+ intersectRanges(dateProfile.activeRange, showNonCurrentDates ? renderRange : currentRange) :
179
+ null;
180
+ monthDateProfiles.push({
181
+ currentDate: dateProfile.currentDate,
182
+ isValid: dateProfile.isValid,
183
+ validRange: dateProfile.validRange,
184
+ renderRange,
185
+ activeRange,
186
+ currentRange,
187
+ currentRangeUnit: 'month',
188
+ isRangeAllDay: true,
189
+ dateIncrement: dateProfile.dateIncrement,
190
+ slotMinTime: dateProfile.slotMaxTime,
191
+ slotMaxTime: dateProfile.slotMinTime,
192
+ });
193
+ monthStart = monthEnd;
194
+ }
195
+ return monthDateProfiles;
196
+ }
197
+ // date formatting
198
+ // -------------------------------------------------------------------------------------------------
199
+ const YEAR_MONTH_FORMATTER = createFormatter({ year: 'numeric', month: 'long' });
200
+ const YEAR_FORMATTER = createFormatter({ month: 'long' });
201
+ function buildMonthFormat(formatOverride, monthDateProfiles) {
202
+ return formatOverride ||
203
+ ((monthDateProfiles[0].currentRange.start.getUTCFullYear() !==
204
+ monthDateProfiles[monthDateProfiles.length - 1].currentRange.start.getUTCFullYear())
205
+ ? YEAR_MONTH_FORMATTER
206
+ : YEAR_FORMATTER);
207
+ }
208
+
209
+ const OPTION_REFINERS = {
210
+ multiMonthTitleFormat: createFormatter,
211
+ multiMonthMaxColumns: Number,
212
+ multiMonthMinWidth: Number,
213
+ };
214
+
215
+ var css_248z = ".fc .fc-multimonth{border:1px solid var(--fc-border-color);display:flex;flex-wrap:wrap;overflow-x:hidden;overflow-y:auto}.fc .fc-multimonth-title{font-size:1.2em;font-weight:700;padding:1em 0;text-align:center}.fc .fc-multimonth-daygrid{background:var(--fc-page-bg-color)}.fc .fc-multimonth-daygrid-table,.fc .fc-multimonth-header-table{table-layout:fixed;width:100%}.fc .fc-multimonth-daygrid-table{border-top-style:hidden!important}.fc .fc-multimonth-singlecol .fc-multimonth{position:relative}.fc .fc-multimonth-singlecol .fc-multimonth-header{background:var(--fc-page-bg-color);position:relative;top:0;z-index:2}.fc .fc-multimonth-singlecol .fc-multimonth-daygrid{position:relative;z-index:1}.fc .fc-multimonth-singlecol .fc-multimonth-daygrid-table,.fc .fc-multimonth-singlecol .fc-multimonth-header-table{border-left-style:hidden;border-right-style:hidden}.fc .fc-multimonth-singlecol .fc-multimonth-month:last-child .fc-multimonth-daygrid-table{border-bottom-style:hidden}.fc .fc-multimonth-multicol{line-height:1}.fc .fc-multimonth-multicol .fc-multimonth-month{padding:0 1.2em 1.2em}.fc .fc-multimonth-multicol .fc-daygrid-more-link{border:1px solid var(--fc-event-border-color);display:block;float:none;padding:1px}.fc .fc-multimonth-compact{line-height:1}.fc .fc-multimonth-compact .fc-multimonth-daygrid-table,.fc .fc-multimonth-compact .fc-multimonth-header-table{font-size:.9em}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-header{position:sticky}.fc-media-print .fc-multimonth{overflow:visible}";
216
+ injectStyles(css_248z);
217
+
218
+ var index = createPlugin({
219
+ name: '@fullcalendar/multimonth',
220
+ initialView: 'multiMonthYear',
221
+ optionRefiners: OPTION_REFINERS,
222
+ views: {
223
+ multiMonth: {
224
+ component: MultiMonthView,
225
+ dateProfileGeneratorClass: TableDateProfileGenerator,
226
+ multiMonthMinWidth: 350,
227
+ multiMonthMaxColumns: 3,
228
+ },
229
+ multiMonthYear: {
230
+ type: 'multiMonth',
231
+ duration: { years: 1 },
232
+ fixedWeekCount: true,
233
+ showNonCurrentDates: false,
234
+ },
235
+ },
236
+ });
237
+
238
+ export { index as default };
@@ -0,0 +1,249 @@
1
+ /*!
2
+ FullCalendar Multi-Month Plugin v6.1.0
3
+ Docs & License: https://fullcalendar.io/docs/multimonth-view
4
+ (c) 2022 Adam Shaw
5
+ */
6
+ FullCalendar.MultiMonth = (function (exports, core, internal$1, internal, preact) {
7
+ 'use strict';
8
+
9
+ class SingleMonth extends internal.DateComponent {
10
+ constructor() {
11
+ super(...arguments);
12
+ this.buildDayTableModel = internal.memoize(internal$1.buildDayTableModel);
13
+ this.slicer = new internal$1.DayTableSlicer();
14
+ this.state = {
15
+ labelId: internal.getUniqueDomId(),
16
+ };
17
+ }
18
+ render() {
19
+ const { props, state, context } = this;
20
+ const { dateProfile, forPrint } = props;
21
+ const { options } = context;
22
+ const dayTableModel = this.buildDayTableModel(dateProfile, context.dateProfileGenerator);
23
+ const slicedProps = this.slicer.sliceProps(props, dateProfile, options.nextDayThreshold, context, dayTableModel);
24
+ // ensure single-month has aspect ratio
25
+ const tableHeight = props.tableWidth != null ? props.tableWidth / options.aspectRatio : null;
26
+ const rowCnt = dayTableModel.cells.length;
27
+ const rowHeight = tableHeight != null ? tableHeight / rowCnt : null;
28
+ return (preact.createElement("div", { ref: props.elRef, "data-date": props.isoDateStr, className: "fc-multimonth-month", style: { width: props.width }, role: "grid", "aria-labelledby": state.labelId },
29
+ preact.createElement("div", { className: "fc-multimonth-header", style: { marginBottom: rowHeight }, role: "presentation" },
30
+ preact.createElement("div", { className: "fc-multimonth-title", id: state.labelId }, context.dateEnv.format(props.dateProfile.currentRange.start, props.titleFormat)),
31
+ preact.createElement("table", { className: [
32
+ 'fc-multimonth-header-table',
33
+ context.theme.getClass('table'),
34
+ ].join(' '), role: "presentation" },
35
+ preact.createElement("thead", { role: "rowgroup" },
36
+ preact.createElement(internal.DayHeader, { dateProfile: props.dateProfile, dates: dayTableModel.headerDates, datesRepDistinctDays: false })))),
37
+ preact.createElement("div", { className: [
38
+ 'fc-multimonth-daygrid',
39
+ 'fc-daygrid',
40
+ 'fc-daygrid-body',
41
+ !forPrint && 'fc-daygrid-body-balanced',
42
+ forPrint && 'fc-daygrid-body-unbalanced',
43
+ forPrint && 'fc-daygrid-body-natural',
44
+ ].join(' '), style: { marginTop: -rowHeight } },
45
+ preact.createElement("table", { className: [
46
+ 'fc-multimonth-daygrid-table',
47
+ context.theme.getClass('table'),
48
+ ].join(' '), style: { height: forPrint ? '' : tableHeight }, role: "presentation" },
49
+ preact.createElement("tbody", { role: "rowgroup" },
50
+ preact.createElement(internal$1.TableRows, Object.assign({}, slicedProps, { dateProfile: dateProfile, cells: dayTableModel.cells, eventSelection: props.eventSelection, dayMaxEvents: !forPrint, dayMaxEventRows: !forPrint, showWeekNumbers: options.weekNumbers, clientWidth: props.clientWidth, clientHeight: props.clientHeight, forPrint: forPrint })))))));
51
+ }
52
+ }
53
+
54
+ class MultiMonthView extends internal.DateComponent {
55
+ constructor() {
56
+ super(...arguments);
57
+ this.splitDateProfileByMonth = internal.memoize(splitDateProfileByMonth);
58
+ this.buildMonthFormat = internal.memoize(buildMonthFormat);
59
+ this.scrollElRef = preact.createRef();
60
+ this.firstMonthElRef = preact.createRef();
61
+ this.needsScrollReset = false;
62
+ this.handleSizing = (isForced) => {
63
+ if (isForced) {
64
+ this.updateSize();
65
+ }
66
+ };
67
+ }
68
+ render() {
69
+ const { context, props, state } = this;
70
+ const { options } = context;
71
+ const { clientWidth, clientHeight } = state;
72
+ const monthHPadding = state.monthHPadding || 0;
73
+ const colCount = Math.min(clientWidth != null ?
74
+ Math.floor(clientWidth / (options.multiMonthMinWidth + monthHPadding)) :
75
+ 1, options.multiMonthMaxColumns) || 1;
76
+ const monthWidthPct = (100 / colCount) + '%';
77
+ const monthTableWidth = clientWidth == null ? null :
78
+ (clientWidth / colCount) - monthHPadding;
79
+ const isLegitSingleCol = clientWidth != null && colCount === 1;
80
+ const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv, isLegitSingleCol ? false : options.fixedWeekCount, options.showNonCurrentDates);
81
+ const monthTitleFormat = this.buildMonthFormat(options.multiMonthTitleFormat, monthDateProfiles);
82
+ const rootClassNames = [
83
+ 'fc-multimonth',
84
+ isLegitSingleCol ?
85
+ 'fc-multimonth-singlecol' :
86
+ 'fc-multimonth-multicol',
87
+ (monthTableWidth != null && monthTableWidth < 400) ?
88
+ 'fc-multimonth-compact' :
89
+ '',
90
+ ];
91
+ return (preact.createElement(internal.ViewContainer, { elRef: this.scrollElRef, elClasses: rootClassNames, viewSpec: context.viewSpec }, monthDateProfiles.map((monthDateProfile, i) => {
92
+ const monthStr = internal.formatIsoMonthStr(monthDateProfile.currentRange.start);
93
+ return (preact.createElement(SingleMonth, Object.assign({}, props, { key: monthStr, isoDateStr: monthStr, elRef: i === 0 ? this.firstMonthElRef : undefined, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: monthWidthPct, tableWidth: monthTableWidth, clientWidth: clientWidth, clientHeight: clientHeight })));
94
+ })));
95
+ }
96
+ componentDidMount() {
97
+ this.updateSize();
98
+ this.context.addResizeHandler(this.handleSizing);
99
+ this.requestScrollReset();
100
+ }
101
+ componentDidUpdate(prevProps) {
102
+ if (!internal.isPropsEqual(prevProps, this.props)) { // an external change?
103
+ this.handleSizing(false);
104
+ }
105
+ if (prevProps.dateProfile !== this.props.dateProfile) {
106
+ this.requestScrollReset();
107
+ }
108
+ else {
109
+ this.flushScrollReset();
110
+ }
111
+ }
112
+ componentWillUnmount() {
113
+ this.context.removeResizeHandler(this.handleSizing);
114
+ }
115
+ updateSize() {
116
+ const scrollEl = this.scrollElRef.current;
117
+ const firstMonthEl = this.firstMonthElRef.current;
118
+ if (scrollEl) {
119
+ this.setState({
120
+ clientWidth: scrollEl.clientWidth,
121
+ clientHeight: scrollEl.clientHeight,
122
+ });
123
+ }
124
+ if (firstMonthEl && scrollEl) {
125
+ if (this.state.monthHPadding == null) { // always remember initial non-zero value
126
+ this.setState({
127
+ monthHPadding: scrollEl.clientWidth - // go within padding
128
+ firstMonthEl.firstChild.offsetWidth,
129
+ });
130
+ }
131
+ }
132
+ }
133
+ requestScrollReset() {
134
+ this.needsScrollReset = true;
135
+ this.flushScrollReset();
136
+ }
137
+ flushScrollReset() {
138
+ if (this.needsScrollReset &&
139
+ this.state.monthHPadding != null // indicates sizing already happened
140
+ ) {
141
+ const { currentDate } = this.props.dateProfile;
142
+ const scrollEl = this.scrollElRef.current;
143
+ const monthEl = scrollEl.querySelector(`[data-date="${internal.formatIsoMonthStr(currentDate)}"]`);
144
+ scrollEl.scrollTop = monthEl.getBoundingClientRect().top -
145
+ this.firstMonthElRef.current.getBoundingClientRect().top;
146
+ this.needsScrollReset = false;
147
+ }
148
+ }
149
+ // workaround for when queued setState render (w/ clientWidth) gets cancelled because
150
+ // subsequent update and shouldComponentUpdate says not to render :(
151
+ shouldComponentUpdate() {
152
+ return true;
153
+ }
154
+ }
155
+ // date profile
156
+ // -------------------------------------------------------------------------------------------------
157
+ const oneMonthDuration = internal.createDuration(1, 'month');
158
+ function splitDateProfileByMonth(dateProfileGenerator, dateProfile, dateEnv, fixedWeekCount, showNonCurrentDates) {
159
+ const { start, end } = dateProfile.currentRange;
160
+ let monthStart = start;
161
+ const monthDateProfiles = [];
162
+ while (monthStart.valueOf() < end.valueOf()) {
163
+ const monthEnd = dateEnv.add(monthStart, oneMonthDuration);
164
+ const currentRange = {
165
+ // yuck
166
+ start: dateProfileGenerator.skipHiddenDays(monthStart),
167
+ end: dateProfileGenerator.skipHiddenDays(monthEnd, -1, true),
168
+ };
169
+ let renderRange = internal$1.buildDayTableRenderRange({
170
+ currentRange,
171
+ snapToWeek: true,
172
+ fixedWeekCount,
173
+ dateEnv,
174
+ });
175
+ renderRange = {
176
+ // yuck
177
+ start: dateProfileGenerator.skipHiddenDays(renderRange.start),
178
+ end: dateProfileGenerator.skipHiddenDays(renderRange.end, -1, true),
179
+ };
180
+ const activeRange = dateProfile.activeRange ?
181
+ internal.intersectRanges(dateProfile.activeRange, showNonCurrentDates ? renderRange : currentRange) :
182
+ null;
183
+ monthDateProfiles.push({
184
+ currentDate: dateProfile.currentDate,
185
+ isValid: dateProfile.isValid,
186
+ validRange: dateProfile.validRange,
187
+ renderRange,
188
+ activeRange,
189
+ currentRange,
190
+ currentRangeUnit: 'month',
191
+ isRangeAllDay: true,
192
+ dateIncrement: dateProfile.dateIncrement,
193
+ slotMinTime: dateProfile.slotMaxTime,
194
+ slotMaxTime: dateProfile.slotMinTime,
195
+ });
196
+ monthStart = monthEnd;
197
+ }
198
+ return monthDateProfiles;
199
+ }
200
+ // date formatting
201
+ // -------------------------------------------------------------------------------------------------
202
+ const YEAR_MONTH_FORMATTER = internal.createFormatter({ year: 'numeric', month: 'long' });
203
+ const YEAR_FORMATTER = internal.createFormatter({ month: 'long' });
204
+ function buildMonthFormat(formatOverride, monthDateProfiles) {
205
+ return formatOverride ||
206
+ ((monthDateProfiles[0].currentRange.start.getUTCFullYear() !==
207
+ monthDateProfiles[monthDateProfiles.length - 1].currentRange.start.getUTCFullYear())
208
+ ? YEAR_MONTH_FORMATTER
209
+ : YEAR_FORMATTER);
210
+ }
211
+
212
+ const OPTION_REFINERS = {
213
+ multiMonthTitleFormat: internal.createFormatter,
214
+ multiMonthMaxColumns: Number,
215
+ multiMonthMinWidth: Number,
216
+ };
217
+
218
+ var css_248z = ".fc .fc-multimonth{border:1px solid var(--fc-border-color);display:flex;flex-wrap:wrap;overflow-x:hidden;overflow-y:auto}.fc .fc-multimonth-title{font-size:1.2em;font-weight:700;padding:1em 0;text-align:center}.fc .fc-multimonth-daygrid{background:var(--fc-page-bg-color)}.fc .fc-multimonth-daygrid-table,.fc .fc-multimonth-header-table{table-layout:fixed;width:100%}.fc .fc-multimonth-daygrid-table{border-top-style:hidden!important}.fc .fc-multimonth-singlecol .fc-multimonth{position:relative}.fc .fc-multimonth-singlecol .fc-multimonth-header{background:var(--fc-page-bg-color);position:relative;top:0;z-index:2}.fc .fc-multimonth-singlecol .fc-multimonth-daygrid{position:relative;z-index:1}.fc .fc-multimonth-singlecol .fc-multimonth-daygrid-table,.fc .fc-multimonth-singlecol .fc-multimonth-header-table{border-left-style:hidden;border-right-style:hidden}.fc .fc-multimonth-singlecol .fc-multimonth-month:last-child .fc-multimonth-daygrid-table{border-bottom-style:hidden}.fc .fc-multimonth-multicol{line-height:1}.fc .fc-multimonth-multicol .fc-multimonth-month{padding:0 1.2em 1.2em}.fc .fc-multimonth-multicol .fc-daygrid-more-link{border:1px solid var(--fc-event-border-color);display:block;float:none;padding:1px}.fc .fc-multimonth-compact{line-height:1}.fc .fc-multimonth-compact .fc-multimonth-daygrid-table,.fc .fc-multimonth-compact .fc-multimonth-header-table{font-size:.9em}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-header{position:sticky}.fc-media-print .fc-multimonth{overflow:visible}";
219
+ internal.injectStyles(css_248z);
220
+
221
+ var plugin = core.createPlugin({
222
+ name: '@fullcalendar/multimonth',
223
+ initialView: 'multiMonthYear',
224
+ optionRefiners: OPTION_REFINERS,
225
+ views: {
226
+ multiMonth: {
227
+ component: MultiMonthView,
228
+ dateProfileGeneratorClass: internal$1.TableDateProfileGenerator,
229
+ multiMonthMinWidth: 350,
230
+ multiMonthMaxColumns: 3,
231
+ },
232
+ multiMonthYear: {
233
+ type: 'multiMonth',
234
+ duration: { years: 1 },
235
+ fixedWeekCount: true,
236
+ showNonCurrentDates: false,
237
+ },
238
+ },
239
+ });
240
+
241
+ core.globalPlugins.push(plugin);
242
+
243
+ exports["default"] = plugin;
244
+
245
+ Object.defineProperty(exports, '__esModule', { value: true });
246
+
247
+ return exports;
248
+
249
+ })({}, FullCalendar, FullCalendar.DayGrid.Internal, FullCalendar.Internal, FullCalendar.Preact);
@@ -0,0 +1,6 @@
1
+ /*!
2
+ FullCalendar Multi-Month Plugin v6.1.0
3
+ Docs & License: https://fullcalendar.io/docs/multimonth-view
4
+ (c) 2022 Adam Shaw
5
+ */
6
+ FullCalendar.MultiMonth=function(t,e,l,i,n){"use strict";class o extends i.DateComponent{constructor(){super(...arguments),this.buildDayTableModel=i.memoize(l.buildDayTableModel),this.slicer=new l.DayTableSlicer,this.state={labelId:i.getUniqueDomId()}}render(){const{props:t,state:e,context:o}=this,{dateProfile:a,forPrint:r}=t,{options:s}=o,c=this.buildDayTableModel(a,o.dateProfileGenerator),d=this.slicer.sliceProps(t,a,s.nextDayThreshold,o,c),m=null!=t.tableWidth?t.tableWidth/s.aspectRatio:null,h=c.cells.length,u=null!=m?m/h:null;return n.createElement("div",{ref:t.elRef,"data-date":t.isoDateStr,className:"fc-multimonth-month",style:{width:t.width},role:"grid","aria-labelledby":e.labelId},n.createElement("div",{className:"fc-multimonth-header",style:{marginBottom:u},role:"presentation"},n.createElement("div",{className:"fc-multimonth-title",id:e.labelId},o.dateEnv.format(t.dateProfile.currentRange.start,t.titleFormat)),n.createElement("table",{className:["fc-multimonth-header-table",o.theme.getClass("table")].join(" "),role:"presentation"},n.createElement("thead",{role:"rowgroup"},n.createElement(i.DayHeader,{dateProfile:t.dateProfile,dates:c.headerDates,datesRepDistinctDays:!1})))),n.createElement("div",{className:["fc-multimonth-daygrid","fc-daygrid","fc-daygrid-body",!r&&"fc-daygrid-body-balanced",r&&"fc-daygrid-body-unbalanced",r&&"fc-daygrid-body-natural"].join(" "),style:{marginTop:-u}},n.createElement("table",{className:["fc-multimonth-daygrid-table",o.theme.getClass("table")].join(" "),style:{height:r?"":m},role:"presentation"},n.createElement("tbody",{role:"rowgroup"},n.createElement(l.TableRows,Object.assign({},d,{dateProfile:a,cells:c.cells,eventSelection:t.eventSelection,dayMaxEvents:!r,dayMaxEventRows:!r,showWeekNumbers:s.weekNumbers,clientWidth:t.clientWidth,clientHeight:t.clientHeight,forPrint:r}))))))}}class a extends i.DateComponent{constructor(){super(...arguments),this.splitDateProfileByMonth=i.memoize(s),this.buildMonthFormat=i.memoize(m),this.scrollElRef=n.createRef(),this.firstMonthElRef=n.createRef(),this.needsScrollReset=!1,this.handleSizing=t=>{t&&this.updateSize()}}render(){const{context:t,props:e,state:l}=this,{options:a}=t,{clientWidth:r,clientHeight:s}=l,c=l.monthHPadding||0,d=Math.min(null!=r?Math.floor(r/(a.multiMonthMinWidth+c)):1,a.multiMonthMaxColumns)||1,m=100/d+"%",h=null==r?null:r/d-c,u=null!=r&&1===d,f=this.splitDateProfileByMonth(t.dateProfileGenerator,e.dateProfile,t.dateEnv,!u&&a.fixedWeekCount,a.showNonCurrentDates),g=this.buildMonthFormat(a.multiMonthTitleFormat,f),p=["fc-multimonth",u?"fc-multimonth-singlecol":"fc-multimonth-multicol",null!=h&&h<400?"fc-multimonth-compact":""];return n.createElement(i.ViewContainer,{elRef:this.scrollElRef,elClasses:p,viewSpec:t.viewSpec},f.map((t,l)=>{const a=i.formatIsoMonthStr(t.currentRange.start);return n.createElement(o,Object.assign({},e,{key:a,isoDateStr:a,elRef:0===l?this.firstMonthElRef:void 0,titleFormat:g,dateProfile:t,width:m,tableWidth:h,clientWidth:r,clientHeight:s}))}))}componentDidMount(){this.updateSize(),this.context.addResizeHandler(this.handleSizing),this.requestScrollReset()}componentDidUpdate(t){i.isPropsEqual(t,this.props)||this.handleSizing(!1),t.dateProfile!==this.props.dateProfile?this.requestScrollReset():this.flushScrollReset()}componentWillUnmount(){this.context.removeResizeHandler(this.handleSizing)}updateSize(){const t=this.scrollElRef.current,e=this.firstMonthElRef.current;t&&this.setState({clientWidth:t.clientWidth,clientHeight:t.clientHeight}),e&&t&&null==this.state.monthHPadding&&this.setState({monthHPadding:t.clientWidth-e.firstChild.offsetWidth})}requestScrollReset(){this.needsScrollReset=!0,this.flushScrollReset()}flushScrollReset(){if(this.needsScrollReset&&null!=this.state.monthHPadding){const{currentDate:t}=this.props.dateProfile,e=this.scrollElRef.current,l=e.querySelector(`[data-date="${i.formatIsoMonthStr(t)}"]`);e.scrollTop=l.getBoundingClientRect().top-this.firstMonthElRef.current.getBoundingClientRect().top,this.needsScrollReset=!1}}shouldComponentUpdate(){return!0}}const r=i.createDuration(1,"month");function s(t,e,n,o,a){const{start:s,end:c}=e.currentRange;let d=s;const m=[];for(;d.valueOf()<c.valueOf();){const s=n.add(d,r),c={start:t.skipHiddenDays(d),end:t.skipHiddenDays(s,-1,!0)};let h=l.buildDayTableRenderRange({currentRange:c,snapToWeek:!0,fixedWeekCount:o,dateEnv:n});h={start:t.skipHiddenDays(h.start),end:t.skipHiddenDays(h.end,-1,!0)};const u=e.activeRange?i.intersectRanges(e.activeRange,a?h:c):null;m.push({currentDate:e.currentDate,isValid:e.isValid,validRange:e.validRange,renderRange:h,activeRange:u,currentRange:c,currentRangeUnit:"month",isRangeAllDay:!0,dateIncrement:e.dateIncrement,slotMinTime:e.slotMaxTime,slotMaxTime:e.slotMinTime}),d=s}return m}const c=i.createFormatter({year:"numeric",month:"long"}),d=i.createFormatter({month:"long"});function m(t,e){return t||(e[0].currentRange.start.getUTCFullYear()!==e[e.length-1].currentRange.start.getUTCFullYear()?c:d)}const h={multiMonthTitleFormat:i.createFormatter,multiMonthMaxColumns:Number,multiMonthMinWidth:Number};i.injectStyles(".fc .fc-multimonth{border:1px solid var(--fc-border-color);display:flex;flex-wrap:wrap;overflow-x:hidden;overflow-y:auto}.fc .fc-multimonth-title{font-size:1.2em;font-weight:700;padding:1em 0;text-align:center}.fc .fc-multimonth-daygrid{background:var(--fc-page-bg-color)}.fc .fc-multimonth-daygrid-table,.fc .fc-multimonth-header-table{table-layout:fixed;width:100%}.fc .fc-multimonth-daygrid-table{border-top-style:hidden!important}.fc .fc-multimonth-singlecol .fc-multimonth{position:relative}.fc .fc-multimonth-singlecol .fc-multimonth-header{background:var(--fc-page-bg-color);position:relative;top:0;z-index:2}.fc .fc-multimonth-singlecol .fc-multimonth-daygrid{position:relative;z-index:1}.fc .fc-multimonth-singlecol .fc-multimonth-daygrid-table,.fc .fc-multimonth-singlecol .fc-multimonth-header-table{border-left-style:hidden;border-right-style:hidden}.fc .fc-multimonth-singlecol .fc-multimonth-month:last-child .fc-multimonth-daygrid-table{border-bottom-style:hidden}.fc .fc-multimonth-multicol{line-height:1}.fc .fc-multimonth-multicol .fc-multimonth-month{padding:0 1.2em 1.2em}.fc .fc-multimonth-multicol .fc-daygrid-more-link{border:1px solid var(--fc-event-border-color);display:block;float:none;padding:1px}.fc .fc-multimonth-compact{line-height:1}.fc .fc-multimonth-compact .fc-multimonth-daygrid-table,.fc .fc-multimonth-compact .fc-multimonth-header-table{font-size:.9em}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-header{position:sticky}.fc-media-print .fc-multimonth{overflow:visible}");var u=e.createPlugin({name:"@fullcalendar/multimonth",initialView:"multiMonthYear",optionRefiners:h,views:{multiMonth:{component:a,dateProfileGeneratorClass:l.TableDateProfileGenerator,multiMonthMinWidth:350,multiMonthMaxColumns:3},multiMonthYear:{type:"multiMonth",duration:{years:1},fixedWeekCount:!0,showNonCurrentDates:!1}}});return e.globalPlugins.push(u),t.default=u,Object.defineProperty(t,"__esModule",{value:!0}),t}({},FullCalendar,FullCalendar.DayGrid.Internal,FullCalendar.Internal,FullCalendar.Preact);
package/index.js ADDED
@@ -0,0 +1,242 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var core = require('@fullcalendar/core');
6
+ var internal$1 = require('@fullcalendar/daygrid/internal');
7
+ var internal = require('@fullcalendar/core/internal');
8
+ var preact = require('@fullcalendar/core/preact');
9
+
10
+ class SingleMonth extends internal.DateComponent {
11
+ constructor() {
12
+ super(...arguments);
13
+ this.buildDayTableModel = internal.memoize(internal$1.buildDayTableModel);
14
+ this.slicer = new internal$1.DayTableSlicer();
15
+ this.state = {
16
+ labelId: internal.getUniqueDomId(),
17
+ };
18
+ }
19
+ render() {
20
+ const { props, state, context } = this;
21
+ const { dateProfile, forPrint } = props;
22
+ const { options } = context;
23
+ const dayTableModel = this.buildDayTableModel(dateProfile, context.dateProfileGenerator);
24
+ const slicedProps = this.slicer.sliceProps(props, dateProfile, options.nextDayThreshold, context, dayTableModel);
25
+ // ensure single-month has aspect ratio
26
+ const tableHeight = props.tableWidth != null ? props.tableWidth / options.aspectRatio : null;
27
+ const rowCnt = dayTableModel.cells.length;
28
+ const rowHeight = tableHeight != null ? tableHeight / rowCnt : null;
29
+ return (preact.createElement("div", { ref: props.elRef, "data-date": props.isoDateStr, className: "fc-multimonth-month", style: { width: props.width }, role: "grid", "aria-labelledby": state.labelId },
30
+ preact.createElement("div", { className: "fc-multimonth-header", style: { marginBottom: rowHeight }, role: "presentation" },
31
+ preact.createElement("div", { className: "fc-multimonth-title", id: state.labelId }, context.dateEnv.format(props.dateProfile.currentRange.start, props.titleFormat)),
32
+ preact.createElement("table", { className: [
33
+ 'fc-multimonth-header-table',
34
+ context.theme.getClass('table'),
35
+ ].join(' '), role: "presentation" },
36
+ preact.createElement("thead", { role: "rowgroup" },
37
+ preact.createElement(internal.DayHeader, { dateProfile: props.dateProfile, dates: dayTableModel.headerDates, datesRepDistinctDays: false })))),
38
+ preact.createElement("div", { className: [
39
+ 'fc-multimonth-daygrid',
40
+ 'fc-daygrid',
41
+ 'fc-daygrid-body',
42
+ !forPrint && 'fc-daygrid-body-balanced',
43
+ forPrint && 'fc-daygrid-body-unbalanced',
44
+ forPrint && 'fc-daygrid-body-natural',
45
+ ].join(' '), style: { marginTop: -rowHeight } },
46
+ preact.createElement("table", { className: [
47
+ 'fc-multimonth-daygrid-table',
48
+ context.theme.getClass('table'),
49
+ ].join(' '), style: { height: forPrint ? '' : tableHeight }, role: "presentation" },
50
+ preact.createElement("tbody", { role: "rowgroup" },
51
+ preact.createElement(internal$1.TableRows, Object.assign({}, slicedProps, { dateProfile: dateProfile, cells: dayTableModel.cells, eventSelection: props.eventSelection, dayMaxEvents: !forPrint, dayMaxEventRows: !forPrint, showWeekNumbers: options.weekNumbers, clientWidth: props.clientWidth, clientHeight: props.clientHeight, forPrint: forPrint })))))));
52
+ }
53
+ }
54
+
55
+ class MultiMonthView extends internal.DateComponent {
56
+ constructor() {
57
+ super(...arguments);
58
+ this.splitDateProfileByMonth = internal.memoize(splitDateProfileByMonth);
59
+ this.buildMonthFormat = internal.memoize(buildMonthFormat);
60
+ this.scrollElRef = preact.createRef();
61
+ this.firstMonthElRef = preact.createRef();
62
+ this.needsScrollReset = false;
63
+ this.handleSizing = (isForced) => {
64
+ if (isForced) {
65
+ this.updateSize();
66
+ }
67
+ };
68
+ }
69
+ render() {
70
+ const { context, props, state } = this;
71
+ const { options } = context;
72
+ const { clientWidth, clientHeight } = state;
73
+ const monthHPadding = state.monthHPadding || 0;
74
+ const colCount = Math.min(clientWidth != null ?
75
+ Math.floor(clientWidth / (options.multiMonthMinWidth + monthHPadding)) :
76
+ 1, options.multiMonthMaxColumns) || 1;
77
+ const monthWidthPct = (100 / colCount) + '%';
78
+ const monthTableWidth = clientWidth == null ? null :
79
+ (clientWidth / colCount) - monthHPadding;
80
+ const isLegitSingleCol = clientWidth != null && colCount === 1;
81
+ const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv, isLegitSingleCol ? false : options.fixedWeekCount, options.showNonCurrentDates);
82
+ const monthTitleFormat = this.buildMonthFormat(options.multiMonthTitleFormat, monthDateProfiles);
83
+ const rootClassNames = [
84
+ 'fc-multimonth',
85
+ isLegitSingleCol ?
86
+ 'fc-multimonth-singlecol' :
87
+ 'fc-multimonth-multicol',
88
+ (monthTableWidth != null && monthTableWidth < 400) ?
89
+ 'fc-multimonth-compact' :
90
+ '',
91
+ ];
92
+ return (preact.createElement(internal.ViewContainer, { elRef: this.scrollElRef, elClasses: rootClassNames, viewSpec: context.viewSpec }, monthDateProfiles.map((monthDateProfile, i) => {
93
+ const monthStr = internal.formatIsoMonthStr(monthDateProfile.currentRange.start);
94
+ return (preact.createElement(SingleMonth, Object.assign({}, props, { key: monthStr, isoDateStr: monthStr, elRef: i === 0 ? this.firstMonthElRef : undefined, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: monthWidthPct, tableWidth: monthTableWidth, clientWidth: clientWidth, clientHeight: clientHeight })));
95
+ })));
96
+ }
97
+ componentDidMount() {
98
+ this.updateSize();
99
+ this.context.addResizeHandler(this.handleSizing);
100
+ this.requestScrollReset();
101
+ }
102
+ componentDidUpdate(prevProps) {
103
+ if (!internal.isPropsEqual(prevProps, this.props)) { // an external change?
104
+ this.handleSizing(false);
105
+ }
106
+ if (prevProps.dateProfile !== this.props.dateProfile) {
107
+ this.requestScrollReset();
108
+ }
109
+ else {
110
+ this.flushScrollReset();
111
+ }
112
+ }
113
+ componentWillUnmount() {
114
+ this.context.removeResizeHandler(this.handleSizing);
115
+ }
116
+ updateSize() {
117
+ const scrollEl = this.scrollElRef.current;
118
+ const firstMonthEl = this.firstMonthElRef.current;
119
+ if (scrollEl) {
120
+ this.setState({
121
+ clientWidth: scrollEl.clientWidth,
122
+ clientHeight: scrollEl.clientHeight,
123
+ });
124
+ }
125
+ if (firstMonthEl && scrollEl) {
126
+ if (this.state.monthHPadding == null) { // always remember initial non-zero value
127
+ this.setState({
128
+ monthHPadding: scrollEl.clientWidth - // go within padding
129
+ firstMonthEl.firstChild.offsetWidth,
130
+ });
131
+ }
132
+ }
133
+ }
134
+ requestScrollReset() {
135
+ this.needsScrollReset = true;
136
+ this.flushScrollReset();
137
+ }
138
+ flushScrollReset() {
139
+ if (this.needsScrollReset &&
140
+ this.state.monthHPadding != null // indicates sizing already happened
141
+ ) {
142
+ const { currentDate } = this.props.dateProfile;
143
+ const scrollEl = this.scrollElRef.current;
144
+ const monthEl = scrollEl.querySelector(`[data-date="${internal.formatIsoMonthStr(currentDate)}"]`);
145
+ scrollEl.scrollTop = monthEl.getBoundingClientRect().top -
146
+ this.firstMonthElRef.current.getBoundingClientRect().top;
147
+ this.needsScrollReset = false;
148
+ }
149
+ }
150
+ // workaround for when queued setState render (w/ clientWidth) gets cancelled because
151
+ // subsequent update and shouldComponentUpdate says not to render :(
152
+ shouldComponentUpdate() {
153
+ return true;
154
+ }
155
+ }
156
+ // date profile
157
+ // -------------------------------------------------------------------------------------------------
158
+ const oneMonthDuration = internal.createDuration(1, 'month');
159
+ function splitDateProfileByMonth(dateProfileGenerator, dateProfile, dateEnv, fixedWeekCount, showNonCurrentDates) {
160
+ const { start, end } = dateProfile.currentRange;
161
+ let monthStart = start;
162
+ const monthDateProfiles = [];
163
+ while (monthStart.valueOf() < end.valueOf()) {
164
+ const monthEnd = dateEnv.add(monthStart, oneMonthDuration);
165
+ const currentRange = {
166
+ // yuck
167
+ start: dateProfileGenerator.skipHiddenDays(monthStart),
168
+ end: dateProfileGenerator.skipHiddenDays(monthEnd, -1, true),
169
+ };
170
+ let renderRange = internal$1.buildDayTableRenderRange({
171
+ currentRange,
172
+ snapToWeek: true,
173
+ fixedWeekCount,
174
+ dateEnv,
175
+ });
176
+ renderRange = {
177
+ // yuck
178
+ start: dateProfileGenerator.skipHiddenDays(renderRange.start),
179
+ end: dateProfileGenerator.skipHiddenDays(renderRange.end, -1, true),
180
+ };
181
+ const activeRange = dateProfile.activeRange ?
182
+ internal.intersectRanges(dateProfile.activeRange, showNonCurrentDates ? renderRange : currentRange) :
183
+ null;
184
+ monthDateProfiles.push({
185
+ currentDate: dateProfile.currentDate,
186
+ isValid: dateProfile.isValid,
187
+ validRange: dateProfile.validRange,
188
+ renderRange,
189
+ activeRange,
190
+ currentRange,
191
+ currentRangeUnit: 'month',
192
+ isRangeAllDay: true,
193
+ dateIncrement: dateProfile.dateIncrement,
194
+ slotMinTime: dateProfile.slotMaxTime,
195
+ slotMaxTime: dateProfile.slotMinTime,
196
+ });
197
+ monthStart = monthEnd;
198
+ }
199
+ return monthDateProfiles;
200
+ }
201
+ // date formatting
202
+ // -------------------------------------------------------------------------------------------------
203
+ const YEAR_MONTH_FORMATTER = internal.createFormatter({ year: 'numeric', month: 'long' });
204
+ const YEAR_FORMATTER = internal.createFormatter({ month: 'long' });
205
+ function buildMonthFormat(formatOverride, monthDateProfiles) {
206
+ return formatOverride ||
207
+ ((monthDateProfiles[0].currentRange.start.getUTCFullYear() !==
208
+ monthDateProfiles[monthDateProfiles.length - 1].currentRange.start.getUTCFullYear())
209
+ ? YEAR_MONTH_FORMATTER
210
+ : YEAR_FORMATTER);
211
+ }
212
+
213
+ const OPTION_REFINERS = {
214
+ multiMonthTitleFormat: internal.createFormatter,
215
+ multiMonthMaxColumns: Number,
216
+ multiMonthMinWidth: Number,
217
+ };
218
+
219
+ var css_248z = ".fc .fc-multimonth{border:1px solid var(--fc-border-color);display:flex;flex-wrap:wrap;overflow-x:hidden;overflow-y:auto}.fc .fc-multimonth-title{font-size:1.2em;font-weight:700;padding:1em 0;text-align:center}.fc .fc-multimonth-daygrid{background:var(--fc-page-bg-color)}.fc .fc-multimonth-daygrid-table,.fc .fc-multimonth-header-table{table-layout:fixed;width:100%}.fc .fc-multimonth-daygrid-table{border-top-style:hidden!important}.fc .fc-multimonth-singlecol .fc-multimonth{position:relative}.fc .fc-multimonth-singlecol .fc-multimonth-header{background:var(--fc-page-bg-color);position:relative;top:0;z-index:2}.fc .fc-multimonth-singlecol .fc-multimonth-daygrid{position:relative;z-index:1}.fc .fc-multimonth-singlecol .fc-multimonth-daygrid-table,.fc .fc-multimonth-singlecol .fc-multimonth-header-table{border-left-style:hidden;border-right-style:hidden}.fc .fc-multimonth-singlecol .fc-multimonth-month:last-child .fc-multimonth-daygrid-table{border-bottom-style:hidden}.fc .fc-multimonth-multicol{line-height:1}.fc .fc-multimonth-multicol .fc-multimonth-month{padding:0 1.2em 1.2em}.fc .fc-multimonth-multicol .fc-daygrid-more-link{border:1px solid var(--fc-event-border-color);display:block;float:none;padding:1px}.fc .fc-multimonth-compact{line-height:1}.fc .fc-multimonth-compact .fc-multimonth-daygrid-table,.fc .fc-multimonth-compact .fc-multimonth-header-table{font-size:.9em}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-header{position:sticky}.fc-media-print .fc-multimonth{overflow:visible}";
220
+ internal.injectStyles(css_248z);
221
+
222
+ var index = core.createPlugin({
223
+ name: '@fullcalendar/multimonth',
224
+ initialView: 'multiMonthYear',
225
+ optionRefiners: OPTION_REFINERS,
226
+ views: {
227
+ multiMonth: {
228
+ component: MultiMonthView,
229
+ dateProfileGeneratorClass: internal$1.TableDateProfileGenerator,
230
+ multiMonthMinWidth: 350,
231
+ multiMonthMaxColumns: 3,
232
+ },
233
+ multiMonthYear: {
234
+ type: 'multiMonth',
235
+ duration: { years: 1 },
236
+ fixedWeekCount: true,
237
+ showNonCurrentDates: false,
238
+ },
239
+ },
240
+ });
241
+
242
+ exports["default"] = index;
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@fullcalendar/multimonth",
3
+ "version": "6.1.0",
4
+ "title": "FullCalendar Multi-Month Plugin",
5
+ "description": "Display a sequence or grid of multiple months",
6
+ "keywords": [
7
+ "calendar",
8
+ "event",
9
+ "full-sized",
10
+ "fullcalendar",
11
+ "month"
12
+ ],
13
+ "homepage": "https://fullcalendar.io/docs/multimonth-view",
14
+ "dependencies": {
15
+ "@fullcalendar/daygrid": "~6.1.0"
16
+ },
17
+ "peerDependencies": {
18
+ "@fullcalendar/core": "~6.1.0"
19
+ },
20
+ "type": "module",
21
+ "bugs": "https://fullcalendar.io/reporting-bugs",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/fullcalendar/fullcalendar.git",
25
+ "directory": "packages/multimonth"
26
+ },
27
+ "license": "MIT",
28
+ "author": {
29
+ "name": "Adam Shaw",
30
+ "email": "arshaw@arshaw.com",
31
+ "url": "http://arshaw.com/"
32
+ },
33
+ "copyright": "2022 Adam Shaw",
34
+ "types": "./index.d.ts",
35
+ "main": "./index.js",
36
+ "module": "./index.esm.js",
37
+ "unpkg": "./index.global.min.js",
38
+ "jsdelivr": "./index.global.min.js",
39
+ "exports": {
40
+ "./package.json": "./package.json",
41
+ ".": {
42
+ "types": "./index.d.ts",
43
+ "require": "./index.js",
44
+ "import": "./index.esm.js"
45
+ },
46
+ "./internal": {
47
+ "types": "./internal.d.ts",
48
+ "require": "./internal.js",
49
+ "import": "./internal.esm.js"
50
+ }
51
+ },
52
+ "sideEffects": false
53
+ }