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