@fullcalendar/multimonth 6.1.14 → 7.0.0-beta.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/index.cjs +90 -104
- package/index.global.js +91 -105
- package/index.global.min.js +2 -2
- package/index.js +92 -106
- package/package.json +3 -3
package/index.cjs
CHANGED
@@ -10,147 +10,133 @@ 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
|
-
this.
|
64
|
-
|
65
|
-
|
54
|
+
// ref
|
55
|
+
this.rootElRef = preact_cjs.createRef(); // also the scroll container
|
56
|
+
this.innerElRef = preact_cjs.createRef();
|
57
|
+
this.handleClientWidth = (clientWidth) => {
|
58
|
+
let { xGap, xPadding } = this.state;
|
59
|
+
// for first time, assume 2 columns and query gap/padding
|
60
|
+
if (xGap == null) {
|
61
|
+
const innerEl = this.innerElRef.current;
|
62
|
+
const children = innerEl.childNodes;
|
63
|
+
if (children.length > 1) {
|
64
|
+
const box0 = children[0].getBoundingClientRect();
|
65
|
+
const box1 = children[1].getBoundingClientRect();
|
66
|
+
let xSpan;
|
67
|
+
[xGap, xSpan] = [
|
68
|
+
Math.abs(box0.left - box1.right),
|
69
|
+
Math.abs(box0.right - box1.left),
|
70
|
+
].sort(internal_cjs.compareNumbers);
|
71
|
+
xPadding = clientWidth - xSpan;
|
72
|
+
}
|
66
73
|
}
|
74
|
+
this.setState({ clientWidth, xGap, xPadding });
|
67
75
|
};
|
76
|
+
this.timeScrollResponder = new internal_cjs.ScrollResponder((_time) => {
|
77
|
+
// HACK to scroll to day
|
78
|
+
if (this.state.clientWidth != null) {
|
79
|
+
const { currentDate } = this.props.dateProfile;
|
80
|
+
const rootEl = this.rootElRef.current;
|
81
|
+
const innerEl = this.innerElRef.current;
|
82
|
+
const monthEl = innerEl.querySelector(`[data-date="${internal_cjs.formatIsoMonthStr(currentDate)}"]`);
|
83
|
+
rootEl.scrollTop = Math.ceil(// for fractions, err on the side of scrolling further
|
84
|
+
monthEl.getBoundingClientRect().top -
|
85
|
+
innerEl.getBoundingClientRect().top);
|
86
|
+
return true;
|
87
|
+
}
|
88
|
+
return false;
|
89
|
+
});
|
68
90
|
}
|
69
91
|
render() {
|
70
92
|
const { context, props, state } = this;
|
71
93
|
const { options } = context;
|
72
|
-
const
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
(clientWidth
|
80
|
-
|
81
|
-
const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv,
|
94
|
+
const colCount = state.clientWidth == null
|
95
|
+
? 2
|
96
|
+
: Math.min(options.multiMonthMaxColumns, Math.floor((state.clientWidth - state.xPadding + state.xGap) /
|
97
|
+
(options.multiMonthMinWidth + state.xGap)));
|
98
|
+
const monthWidth = state.clientWidth == null
|
99
|
+
? '34%' // will expand. now small enough to be 1/3. for allowing gap
|
100
|
+
: Math.floor(// exact values can cause expansion to other rows
|
101
|
+
(state.clientWidth - state.xPadding - (state.xGap * (colCount - 1))) /
|
102
|
+
colCount);
|
103
|
+
const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv, options.fixedWeekCount, options.showNonCurrentDates);
|
82
104
|
const monthTitleFormat = this.buildMonthFormat(options.multiMonthTitleFormat, monthDateProfiles);
|
83
105
|
const rootClassNames = [
|
84
|
-
'fc-multimonth',
|
85
|
-
|
106
|
+
'fc-multimonth-view',
|
107
|
+
(colCount === 1) ?
|
86
108
|
'fc-multimonth-singlecol' :
|
87
109
|
'fc-multimonth-multicol',
|
88
|
-
(
|
89
|
-
'
|
90
|
-
'',
|
110
|
+
internal_cjs.getIsHeightAuto(options) ?
|
111
|
+
'' :
|
112
|
+
'fc-multimonth-scroll',
|
113
|
+
'fc-border', // BAD to mix this with size-listening?
|
91
114
|
];
|
92
|
-
return (preact_cjs.createElement(internal_cjs.ViewContainer, { elRef: this.
|
93
|
-
|
94
|
-
|
95
|
-
|
115
|
+
return (preact_cjs.createElement(internal_cjs.NowTimer, { unit: "day" }, (nowDate, todayRange) => (preact_cjs.createElement(internal_cjs.ViewContainer, { elRef: this.rootElRef, elClasses: rootClassNames, viewSpec: context.viewSpec },
|
116
|
+
preact_cjs.createElement("div", { ref: this.innerElRef, className: 'fc-multimonth-inner' }, monthDateProfiles.map((monthDateProfile, i) => {
|
117
|
+
const monthStr = internal_cjs.formatIsoMonthStr(monthDateProfile.currentRange.start);
|
118
|
+
return (preact_cjs.createElement(SingleMonth, Object.assign({}, props, { key: monthStr, todayRange: todayRange, isoDateStr: monthStr, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: monthWidth })));
|
119
|
+
}))))));
|
96
120
|
}
|
97
121
|
componentDidMount() {
|
98
|
-
this
|
99
|
-
|
100
|
-
this.
|
122
|
+
const { context } = this;
|
123
|
+
const { options } = context;
|
124
|
+
this.unwatchWidth = internal_cjs.watchWidth(this.rootElRef.current, this.handleClientWidth);
|
125
|
+
context.emitter.on('_timeScrollRequest', this.timeScrollResponder.handleScroll);
|
126
|
+
this.timeScrollResponder.handleScroll(options.scrollTime);
|
101
127
|
}
|
102
128
|
componentDidUpdate(prevProps) {
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
if (prevProps.dateProfile !== this.props.dateProfile) {
|
107
|
-
this.requestScrollReset();
|
129
|
+
const { options } = this.context;
|
130
|
+
if (prevProps.dateProfile !== this.props.dateProfile && options.scrollTimeReset) {
|
131
|
+
this.timeScrollResponder.handleScroll(options.scrollTime);
|
108
132
|
}
|
109
133
|
else {
|
110
|
-
this.
|
134
|
+
this.timeScrollResponder.drain();
|
111
135
|
}
|
112
136
|
}
|
113
137
|
componentWillUnmount() {
|
114
|
-
this.
|
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_cjs.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;
|
138
|
+
this.unwatchWidth();
|
139
|
+
this.context.emitter.off('_timeScrollRequest', this.timeScrollResponder.handleScroll);
|
154
140
|
}
|
155
141
|
}
|
156
142
|
// date profile
|
@@ -216,7 +202,7 @@ const OPTION_REFINERS = {
|
|
216
202
|
multiMonthMinWidth: Number,
|
217
203
|
};
|
218
204
|
|
219
|
-
var css_248z = ".fc
|
205
|
+
var css_248z = ".fc-multimonth-scroll{overflow-x:hidden;overflow-y:scroll}.fc-multimonth-inner{display:flex;flex-wrap:wrap}.fc-multimonth-multicol .fc-multimonth-month{margin:0 1.2em 1.2em}.fc-multimonth-multicol .fc-multimonth-title{padding:1em 0}.fc-multimonth-singlecol .fc-multimonth-title{padding:.5em 0}.fc-multimonth-title{font-size:1.2em;font-weight:700;text-align:center}.fc-multimonth-header-row{border-top:1px solid var(--fc-border-color)}.fc-multimonth-header-row,.fc-multimonth-month{border-bottom:1px solid var(--fc-border-color)}.fc-multimonth-singlecol .fc-multimonth-month:last-child{border-bottom:0}.fc-multimonth-multicol .fc-multimonth-body,.fc-multimonth-multicol .fc-multimonth-header-row{border-left:1px solid var(--fc-border-color);border-right:1px solid var(--fc-border-color);font-size:.9em;line-height:1}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-header{background:var(--fc-page-bg-color);position:sticky;top:0;z-index:2}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-body{position:relative;z-index:1}";
|
220
206
|
internal_cjs.injectStyles(css_248z);
|
221
207
|
|
222
208
|
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.0
|
3
3
|
Docs & License: https://fullcalendar.io/docs/multimonth-grid
|
4
4
|
(c) 2024 Adam Shaw
|
5
5
|
*/
|
@@ -9,147 +9,133 @@ 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
|
-
this.
|
63
|
-
|
64
|
-
|
53
|
+
// ref
|
54
|
+
this.rootElRef = preact.createRef(); // also the scroll container
|
55
|
+
this.innerElRef = preact.createRef();
|
56
|
+
this.handleClientWidth = (clientWidth) => {
|
57
|
+
let { xGap, xPadding } = this.state;
|
58
|
+
// for first time, assume 2 columns and query gap/padding
|
59
|
+
if (xGap == null) {
|
60
|
+
const innerEl = this.innerElRef.current;
|
61
|
+
const children = innerEl.childNodes;
|
62
|
+
if (children.length > 1) {
|
63
|
+
const box0 = children[0].getBoundingClientRect();
|
64
|
+
const box1 = children[1].getBoundingClientRect();
|
65
|
+
let xSpan;
|
66
|
+
[xGap, xSpan] = [
|
67
|
+
Math.abs(box0.left - box1.right),
|
68
|
+
Math.abs(box0.right - box1.left),
|
69
|
+
].sort(internal.compareNumbers);
|
70
|
+
xPadding = clientWidth - xSpan;
|
71
|
+
}
|
65
72
|
}
|
73
|
+
this.setState({ clientWidth, xGap, xPadding });
|
66
74
|
};
|
75
|
+
this.timeScrollResponder = new internal.ScrollResponder((_time) => {
|
76
|
+
// HACK to scroll to day
|
77
|
+
if (this.state.clientWidth != null) {
|
78
|
+
const { currentDate } = this.props.dateProfile;
|
79
|
+
const rootEl = this.rootElRef.current;
|
80
|
+
const innerEl = this.innerElRef.current;
|
81
|
+
const monthEl = innerEl.querySelector(`[data-date="${internal.formatIsoMonthStr(currentDate)}"]`);
|
82
|
+
rootEl.scrollTop = Math.ceil(// for fractions, err on the side of scrolling further
|
83
|
+
monthEl.getBoundingClientRect().top -
|
84
|
+
innerEl.getBoundingClientRect().top);
|
85
|
+
return true;
|
86
|
+
}
|
87
|
+
return false;
|
88
|
+
});
|
67
89
|
}
|
68
90
|
render() {
|
69
91
|
const { context, props, state } = this;
|
70
92
|
const { options } = context;
|
71
|
-
const
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
(clientWidth
|
79
|
-
|
80
|
-
const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv,
|
93
|
+
const colCount = state.clientWidth == null
|
94
|
+
? 2
|
95
|
+
: Math.min(options.multiMonthMaxColumns, Math.floor((state.clientWidth - state.xPadding + state.xGap) /
|
96
|
+
(options.multiMonthMinWidth + state.xGap)));
|
97
|
+
const monthWidth = state.clientWidth == null
|
98
|
+
? '34%' // will expand. now small enough to be 1/3. for allowing gap
|
99
|
+
: Math.floor(// exact values can cause expansion to other rows
|
100
|
+
(state.clientWidth - state.xPadding - (state.xGap * (colCount - 1))) /
|
101
|
+
colCount);
|
102
|
+
const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv, options.fixedWeekCount, options.showNonCurrentDates);
|
81
103
|
const monthTitleFormat = this.buildMonthFormat(options.multiMonthTitleFormat, monthDateProfiles);
|
82
104
|
const rootClassNames = [
|
83
|
-
'fc-multimonth',
|
84
|
-
|
105
|
+
'fc-multimonth-view',
|
106
|
+
(colCount === 1) ?
|
85
107
|
'fc-multimonth-singlecol' :
|
86
108
|
'fc-multimonth-multicol',
|
87
|
-
(
|
88
|
-
'
|
89
|
-
'',
|
109
|
+
internal.getIsHeightAuto(options) ?
|
110
|
+
'' :
|
111
|
+
'fc-multimonth-scroll',
|
112
|
+
'fc-border', // BAD to mix this with size-listening?
|
90
113
|
];
|
91
|
-
return (preact.createElement(internal.ViewContainer, { elRef: this.
|
92
|
-
|
93
|
-
|
94
|
-
|
114
|
+
return (preact.createElement(internal.NowTimer, { unit: "day" }, (nowDate, todayRange) => (preact.createElement(internal.ViewContainer, { elRef: this.rootElRef, elClasses: rootClassNames, viewSpec: context.viewSpec },
|
115
|
+
preact.createElement("div", { ref: this.innerElRef, className: 'fc-multimonth-inner' }, monthDateProfiles.map((monthDateProfile, i) => {
|
116
|
+
const monthStr = internal.formatIsoMonthStr(monthDateProfile.currentRange.start);
|
117
|
+
return (preact.createElement(SingleMonth, Object.assign({}, props, { key: monthStr, todayRange: todayRange, isoDateStr: monthStr, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: monthWidth })));
|
118
|
+
}))))));
|
95
119
|
}
|
96
120
|
componentDidMount() {
|
97
|
-
this
|
98
|
-
|
99
|
-
this.
|
121
|
+
const { context } = this;
|
122
|
+
const { options } = context;
|
123
|
+
this.unwatchWidth = internal.watchWidth(this.rootElRef.current, this.handleClientWidth);
|
124
|
+
context.emitter.on('_timeScrollRequest', this.timeScrollResponder.handleScroll);
|
125
|
+
this.timeScrollResponder.handleScroll(options.scrollTime);
|
100
126
|
}
|
101
127
|
componentDidUpdate(prevProps) {
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
if (prevProps.dateProfile !== this.props.dateProfile) {
|
106
|
-
this.requestScrollReset();
|
128
|
+
const { options } = this.context;
|
129
|
+
if (prevProps.dateProfile !== this.props.dateProfile && options.scrollTimeReset) {
|
130
|
+
this.timeScrollResponder.handleScroll(options.scrollTime);
|
107
131
|
}
|
108
132
|
else {
|
109
|
-
this.
|
133
|
+
this.timeScrollResponder.drain();
|
110
134
|
}
|
111
135
|
}
|
112
136
|
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="${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;
|
137
|
+
this.unwatchWidth();
|
138
|
+
this.context.emitter.off('_timeScrollRequest', this.timeScrollResponder.handleScroll);
|
153
139
|
}
|
154
140
|
}
|
155
141
|
// date profile
|
@@ -215,7 +201,7 @@ FullCalendar.MultiMonth = (function (exports, core, internal$1, internal, preact
|
|
215
201
|
multiMonthMinWidth: Number,
|
216
202
|
};
|
217
203
|
|
218
|
-
var css_248z = ".fc
|
204
|
+
var css_248z = ".fc-multimonth-scroll{overflow-x:hidden;overflow-y:scroll}.fc-multimonth-inner{display:flex;flex-wrap:wrap}.fc-multimonth-multicol .fc-multimonth-month{margin:0 1.2em 1.2em}.fc-multimonth-multicol .fc-multimonth-title{padding:1em 0}.fc-multimonth-singlecol .fc-multimonth-title{padding:.5em 0}.fc-multimonth-title{font-size:1.2em;font-weight:700;text-align:center}.fc-multimonth-header-row{border-top:1px solid var(--fc-border-color)}.fc-multimonth-header-row,.fc-multimonth-month{border-bottom:1px solid var(--fc-border-color)}.fc-multimonth-singlecol .fc-multimonth-month:last-child{border-bottom:0}.fc-multimonth-multicol .fc-multimonth-body,.fc-multimonth-multicol .fc-multimonth-header-row{border-left:1px solid var(--fc-border-color);border-right:1px solid var(--fc-border-color);font-size:.9em;line-height:1}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-header{background:var(--fc-page-bg-color);position:sticky;top:0;z-index:2}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-body{position:relative;z-index:1}";
|
219
205
|
internal.injectStyles(css_248z);
|
220
206
|
|
221
207
|
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.0
|
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,n,o,l){"use strict";class i extends o.DateComponent{constructor(){super(...arguments),this.slicer=new n.DayTableSlicer,this.buildDayTableModel=o.memoize(n.buildDayTableModel),this.createDayHeaderFormatter=o.memoize(n.createDayHeaderFormatter)}render(){const{props:e,context:t}=this,{dateProfile:o,forPrint:i}=e,{options:r}=t,a=this.buildDayTableModel(o,t.dateProfileGenerator),s=this.slicer.sliceProps(e,o,r.nextDayThreshold,t,a),c="number"==typeof e.width?e.width/r.aspectRatio:null,m=a.cellRows.length,d=null!=c?c/m:null,h=this.createDayHeaderFormatter(t.options.dayHeaderFormat,!1,a.colCnt);return l.createElement("div",{"data-date":e.isoDateStr,role:"grid",className:"fc-multimonth-month fc-grow",style:{width:e.width}},l.createElement("div",{className:"fc-multimonth-header",style:{marginBottom:d},role:"presentation"},l.createElement("div",{className:"fc-multimonth-title"},t.dateEnv.format(e.dateProfile.currentRange.start,e.titleFormat)),l.createElement("div",{className:"fc-multimonth-header-row fc-flex-row"},a.headerDates.map(e=>l.createElement(n.DayOfWeekHeaderCell,{key:e.getUTCDay(),dow:e.getUTCDay(),dayHeaderFormat:h,colWidth:void 0})))),l.createElement("div",{className:"fc-multimonth-body fc-flex-column",style:{marginTop:-d,height:i?"":c}},l.createElement(n.DayGridRows,{dateProfile:e.dateProfile,todayRange:e.todayRange,cellRows:a.cellRows,forPrint:e.forPrint,fgEventSegs:s.fgEventSegs,bgEventSegs:s.bgEventSegs,businessHourSegs:s.businessHourSegs,dateSelectionSegs:s.dateSelectionSegs,eventDrag:s.eventDrag,eventResize:s.eventResize,eventSelection:s.eventSelection})))}}class r extends o.DateComponent{constructor(){super(...arguments),this.splitDateProfileByMonth=o.memoize(s),this.buildMonthFormat=o.memoize(d),this.rootElRef=l.createRef(),this.innerElRef=l.createRef(),this.handleClientWidth=e=>{let{xGap:t,xPadding:n}=this.state;if(null==t){const l=this.innerElRef.current.childNodes;if(l.length>1){const i=l[0].getBoundingClientRect(),r=l[1].getBoundingClientRect();let a;[t,a]=[Math.abs(i.left-r.right),Math.abs(i.right-r.left)].sort(o.compareNumbers),n=e-a}}this.setState({clientWidth:e,xGap:t,xPadding:n})},this.timeScrollResponder=new o.ScrollResponder(e=>{if(null!=this.state.clientWidth){const{currentDate:e}=this.props.dateProfile,t=this.rootElRef.current,n=this.innerElRef.current,l=n.querySelector(`[data-date="${o.formatIsoMonthStr(e)}"]`);return t.scrollTop=Math.ceil(l.getBoundingClientRect().top-n.getBoundingClientRect().top),!0}return!1})}render(){const{context:e,props:t,state:n}=this,{options:r}=e,a=null==n.clientWidth?2:Math.min(r.multiMonthMaxColumns,Math.floor((n.clientWidth-n.xPadding+n.xGap)/(r.multiMonthMinWidth+n.xGap))),s=null==n.clientWidth?"34%":Math.floor((n.clientWidth-n.xPadding-n.xGap*(a-1))/a),c=this.splitDateProfileByMonth(e.dateProfileGenerator,t.dateProfile,e.dateEnv,r.fixedWeekCount,r.showNonCurrentDates),m=this.buildMonthFormat(r.multiMonthTitleFormat,c),d=["fc-multimonth-view",1===a?"fc-multimonth-singlecol":"fc-multimonth-multicol",o.getIsHeightAuto(r)?"":"fc-multimonth-scroll","fc-border"];return l.createElement(o.NowTimer,{unit:"day"},(n,r)=>l.createElement(o.ViewContainer,{elRef:this.rootElRef,elClasses:d,viewSpec:e.viewSpec},l.createElement("div",{ref:this.innerElRef,className:"fc-multimonth-inner"},c.map((e,n)=>{const a=o.formatIsoMonthStr(e.currentRange.start);return l.createElement(i,Object.assign({},t,{key:a,todayRange:r,isoDateStr:a,titleFormat:m,dateProfile:e,width:s}))}))))}componentDidMount(){const{context:e}=this,{options:t}=e;this.unwatchWidth=o.watchWidth(this.rootElRef.current,this.handleClientWidth),e.emitter.on("_timeScrollRequest",this.timeScrollResponder.handleScroll),this.timeScrollResponder.handleScroll(t.scrollTime)}componentDidUpdate(e){const{options:t}=this.context;e.dateProfile!==this.props.dateProfile&&t.scrollTimeReset?this.timeScrollResponder.handleScroll(t.scrollTime):this.timeScrollResponder.drain()}componentWillUnmount(){this.unwatchWidth(),this.context.emitter.off("_timeScrollRequest",this.timeScrollResponder.handleScroll)}}const a=o.createDuration(1,"month");function s(e,t,l,i,r){const{start:s,end:c}=t.currentRange;let m=s;const d=[];for(;m.valueOf()<c.valueOf();){const s=l.add(m,a),c={start:e.skipHiddenDays(m),end:e.skipHiddenDays(s,-1,!0)};let h=n.buildDayTableRenderRange({currentRange:c,snapToWeek:!0,fixedWeekCount:i,dateEnv:l});h={start:e.skipHiddenDays(h.start),end:e.skipHiddenDays(h.end,-1,!0)};const u=t.activeRange?o.intersectRanges(t.activeRange,r?h:c):null;d.push({currentDate:t.currentDate,isValid:t.isValid,validRange:t.validRange,renderRange:h,activeRange:u,currentRange:c,currentRangeUnit:"month",isRangeAllDay:!0,dateIncrement:t.dateIncrement,slotMinTime:t.slotMaxTime,slotMaxTime:t.slotMinTime}),m=s}return d}const c=o.createFormatter({year:"numeric",month:"long"}),m=o.createFormatter({month:"long"});function d(e,t){return e||(t[0].currentRange.start.getUTCFullYear()!==t[t.length-1].currentRange.start.getUTCFullYear()?c:m)}const h={multiMonthTitleFormat:o.createFormatter,multiMonthMaxColumns:Number,multiMonthMinWidth:Number};o.injectStyles(".fc-multimonth-scroll{overflow-x:hidden;overflow-y:scroll}.fc-multimonth-inner{display:flex;flex-wrap:wrap}.fc-multimonth-multicol .fc-multimonth-month{margin:0 1.2em 1.2em}.fc-multimonth-multicol .fc-multimonth-title{padding:1em 0}.fc-multimonth-singlecol .fc-multimonth-title{padding:.5em 0}.fc-multimonth-title{font-size:1.2em;font-weight:700;text-align:center}.fc-multimonth-header-row{border-top:1px solid var(--fc-border-color)}.fc-multimonth-header-row,.fc-multimonth-month{border-bottom:1px solid var(--fc-border-color)}.fc-multimonth-singlecol .fc-multimonth-month:last-child{border-bottom:0}.fc-multimonth-multicol .fc-multimonth-body,.fc-multimonth-multicol .fc-multimonth-header-row{border-left:1px solid var(--fc-border-color);border-right:1px solid var(--fc-border-color);font-size:.9em;line-height:1}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-header{background:var(--fc-page-bg-color);position:sticky;top:0;z-index:2}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-body{position:relative;z-index:1}");var u=t.createPlugin({name:"@fullcalendar/multimonth",initialView:"multiMonthYear",optionRefiners:h,views:{multiMonth:{component:r,dateProfileGeneratorClass:n.TableDateProfileGenerator,multiMonthMinWidth:350,multiMonthMaxColumns:3},multiMonthYear:{type:"multiMonth",duration:{years:1},fixedWeekCount:!0,showNonCurrentDates:!1}}});return t.globalPlugins.push(u),e.default=u,Object.defineProperty(e,"__esModule",{value:!0}),e}({},FullCalendar,FullCalendar.DayGrid.Internal,FullCalendar.Internal,FullCalendar.Preact);
|
package/index.js
CHANGED
@@ -1,152 +1,138 @@
|
|
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, ScrollResponder, formatIsoMonthStr, getIsHeightAuto, NowTimer, ViewContainer, watchWidth, 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
|
-
this.
|
60
|
-
|
61
|
-
|
50
|
+
// ref
|
51
|
+
this.rootElRef = createRef(); // also the scroll container
|
52
|
+
this.innerElRef = createRef();
|
53
|
+
this.handleClientWidth = (clientWidth) => {
|
54
|
+
let { xGap, xPadding } = this.state;
|
55
|
+
// for first time, assume 2 columns and query gap/padding
|
56
|
+
if (xGap == null) {
|
57
|
+
const innerEl = this.innerElRef.current;
|
58
|
+
const children = innerEl.childNodes;
|
59
|
+
if (children.length > 1) {
|
60
|
+
const box0 = children[0].getBoundingClientRect();
|
61
|
+
const box1 = children[1].getBoundingClientRect();
|
62
|
+
let xSpan;
|
63
|
+
[xGap, xSpan] = [
|
64
|
+
Math.abs(box0.left - box1.right),
|
65
|
+
Math.abs(box0.right - box1.left),
|
66
|
+
].sort(compareNumbers);
|
67
|
+
xPadding = clientWidth - xSpan;
|
68
|
+
}
|
62
69
|
}
|
70
|
+
this.setState({ clientWidth, xGap, xPadding });
|
63
71
|
};
|
72
|
+
this.timeScrollResponder = new ScrollResponder((_time) => {
|
73
|
+
// HACK to scroll to day
|
74
|
+
if (this.state.clientWidth != null) {
|
75
|
+
const { currentDate } = this.props.dateProfile;
|
76
|
+
const rootEl = this.rootElRef.current;
|
77
|
+
const innerEl = this.innerElRef.current;
|
78
|
+
const monthEl = innerEl.querySelector(`[data-date="${formatIsoMonthStr(currentDate)}"]`);
|
79
|
+
rootEl.scrollTop = Math.ceil(// for fractions, err on the side of scrolling further
|
80
|
+
monthEl.getBoundingClientRect().top -
|
81
|
+
innerEl.getBoundingClientRect().top);
|
82
|
+
return true;
|
83
|
+
}
|
84
|
+
return false;
|
85
|
+
});
|
64
86
|
}
|
65
87
|
render() {
|
66
88
|
const { context, props, state } = this;
|
67
89
|
const { options } = context;
|
68
|
-
const
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
(clientWidth
|
76
|
-
|
77
|
-
const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv,
|
90
|
+
const colCount = state.clientWidth == null
|
91
|
+
? 2
|
92
|
+
: Math.min(options.multiMonthMaxColumns, Math.floor((state.clientWidth - state.xPadding + state.xGap) /
|
93
|
+
(options.multiMonthMinWidth + state.xGap)));
|
94
|
+
const monthWidth = state.clientWidth == null
|
95
|
+
? '34%' // will expand. now small enough to be 1/3. for allowing gap
|
96
|
+
: Math.floor(// exact values can cause expansion to other rows
|
97
|
+
(state.clientWidth - state.xPadding - (state.xGap * (colCount - 1))) /
|
98
|
+
colCount);
|
99
|
+
const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv, options.fixedWeekCount, options.showNonCurrentDates);
|
78
100
|
const monthTitleFormat = this.buildMonthFormat(options.multiMonthTitleFormat, monthDateProfiles);
|
79
101
|
const rootClassNames = [
|
80
|
-
'fc-multimonth',
|
81
|
-
|
102
|
+
'fc-multimonth-view',
|
103
|
+
(colCount === 1) ?
|
82
104
|
'fc-multimonth-singlecol' :
|
83
105
|
'fc-multimonth-multicol',
|
84
|
-
(
|
85
|
-
'
|
86
|
-
'',
|
106
|
+
getIsHeightAuto(options) ?
|
107
|
+
'' :
|
108
|
+
'fc-multimonth-scroll',
|
109
|
+
'fc-border', // BAD to mix this with size-listening?
|
87
110
|
];
|
88
|
-
return (createElement(ViewContainer, { elRef: this.
|
89
|
-
|
90
|
-
|
91
|
-
|
111
|
+
return (createElement(NowTimer, { unit: "day" }, (nowDate, todayRange) => (createElement(ViewContainer, { elRef: this.rootElRef, elClasses: rootClassNames, viewSpec: context.viewSpec },
|
112
|
+
createElement("div", { ref: this.innerElRef, className: 'fc-multimonth-inner' }, monthDateProfiles.map((monthDateProfile, i) => {
|
113
|
+
const monthStr = formatIsoMonthStr(monthDateProfile.currentRange.start);
|
114
|
+
return (createElement(SingleMonth, Object.assign({}, props, { key: monthStr, todayRange: todayRange, isoDateStr: monthStr, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: monthWidth })));
|
115
|
+
}))))));
|
92
116
|
}
|
93
117
|
componentDidMount() {
|
94
|
-
this
|
95
|
-
|
96
|
-
this.
|
118
|
+
const { context } = this;
|
119
|
+
const { options } = context;
|
120
|
+
this.unwatchWidth = watchWidth(this.rootElRef.current, this.handleClientWidth);
|
121
|
+
context.emitter.on('_timeScrollRequest', this.timeScrollResponder.handleScroll);
|
122
|
+
this.timeScrollResponder.handleScroll(options.scrollTime);
|
97
123
|
}
|
98
124
|
componentDidUpdate(prevProps) {
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
if (prevProps.dateProfile !== this.props.dateProfile) {
|
103
|
-
this.requestScrollReset();
|
125
|
+
const { options } = this.context;
|
126
|
+
if (prevProps.dateProfile !== this.props.dateProfile && options.scrollTimeReset) {
|
127
|
+
this.timeScrollResponder.handleScroll(options.scrollTime);
|
104
128
|
}
|
105
129
|
else {
|
106
|
-
this.
|
130
|
+
this.timeScrollResponder.drain();
|
107
131
|
}
|
108
132
|
}
|
109
133
|
componentWillUnmount() {
|
110
|
-
this.
|
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;
|
134
|
+
this.unwatchWidth();
|
135
|
+
this.context.emitter.off('_timeScrollRequest', this.timeScrollResponder.handleScroll);
|
150
136
|
}
|
151
137
|
}
|
152
138
|
// date profile
|
@@ -212,7 +198,7 @@ const OPTION_REFINERS = {
|
|
212
198
|
multiMonthMinWidth: Number,
|
213
199
|
};
|
214
200
|
|
215
|
-
var css_248z = ".fc
|
201
|
+
var css_248z = ".fc-multimonth-scroll{overflow-x:hidden;overflow-y:scroll}.fc-multimonth-inner{display:flex;flex-wrap:wrap}.fc-multimonth-multicol .fc-multimonth-month{margin:0 1.2em 1.2em}.fc-multimonth-multicol .fc-multimonth-title{padding:1em 0}.fc-multimonth-singlecol .fc-multimonth-title{padding:.5em 0}.fc-multimonth-title{font-size:1.2em;font-weight:700;text-align:center}.fc-multimonth-header-row{border-top:1px solid var(--fc-border-color)}.fc-multimonth-header-row,.fc-multimonth-month{border-bottom:1px solid var(--fc-border-color)}.fc-multimonth-singlecol .fc-multimonth-month:last-child{border-bottom:0}.fc-multimonth-multicol .fc-multimonth-body,.fc-multimonth-multicol .fc-multimonth-header-row{border-left:1px solid var(--fc-border-color);border-right:1px solid var(--fc-border-color);font-size:.9em;line-height:1}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-header{background:var(--fc-page-bg-color);position:sticky;top:0;z-index:2}.fc-media-screen .fc-multimonth-singlecol .fc-multimonth-body{position:relative;z-index:1}";
|
216
202
|
injectStyles(css_248z);
|
217
203
|
|
218
204
|
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.0",
|
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.0"
|
16
16
|
},
|
17
17
|
"peerDependencies": {
|
18
|
-
"@fullcalendar/core": "
|
18
|
+
"@fullcalendar/core": "7.0.0-beta.0"
|
19
19
|
},
|
20
20
|
"type": "module",
|
21
21
|
"bugs": "https://fullcalendar.io/reporting-bugs",
|