@fullcalendar/multimonth 6.1.15 → 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 +89 -106
- package/index.global.js +90 -107
- package/index.global.min.js +2 -2
- package/index.js +91 -108
- package/package.json +3 -3
package/index.cjs
CHANGED
@@ -10,150 +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
|
-
'fc-multimonth-compact' :
|
90
|
-
'',
|
91
|
-
props.isHeightAuto ?
|
110
|
+
internal_cjs.getIsHeightAuto(options) ?
|
92
111
|
'' :
|
93
|
-
'fc-
|
112
|
+
'fc-multimonth-scroll',
|
113
|
+
'fc-border', // BAD to mix this with size-listening?
|
94
114
|
];
|
95
|
-
return (preact_cjs.createElement(internal_cjs.ViewContainer, { elRef: this.
|
96
|
-
|
97
|
-
|
98
|
-
|
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
|
+
}))))));
|
99
120
|
}
|
100
121
|
componentDidMount() {
|
101
|
-
this
|
102
|
-
|
103
|
-
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);
|
104
127
|
}
|
105
128
|
componentDidUpdate(prevProps) {
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
if (prevProps.dateProfile !== this.props.dateProfile) {
|
110
|
-
this.requestScrollReset();
|
129
|
+
const { options } = this.context;
|
130
|
+
if (prevProps.dateProfile !== this.props.dateProfile && options.scrollTimeReset) {
|
131
|
+
this.timeScrollResponder.handleScroll(options.scrollTime);
|
111
132
|
}
|
112
133
|
else {
|
113
|
-
this.
|
134
|
+
this.timeScrollResponder.drain();
|
114
135
|
}
|
115
136
|
}
|
116
137
|
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
|
-
}
|
152
|
-
}
|
153
|
-
// workaround for when queued setState render (w/ clientWidth) gets cancelled because
|
154
|
-
// subsequent update and shouldComponentUpdate says not to render :(
|
155
|
-
shouldComponentUpdate() {
|
156
|
-
return true;
|
138
|
+
this.unwatchWidth();
|
139
|
+
this.context.emitter.off('_timeScrollRequest', this.timeScrollResponder.handleScroll);
|
157
140
|
}
|
158
141
|
}
|
159
142
|
// date profile
|
@@ -219,7 +202,7 @@ const OPTION_REFINERS = {
|
|
219
202
|
multiMonthMinWidth: Number,
|
220
203
|
};
|
221
204
|
|
222
|
-
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}";
|
223
206
|
internal_cjs.injectStyles(css_248z);
|
224
207
|
|
225
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,150 +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
|
-
'fc-multimonth-compact' :
|
89
|
-
'',
|
90
|
-
props.isHeightAuto ?
|
109
|
+
internal.getIsHeightAuto(options) ?
|
91
110
|
'' :
|
92
|
-
'fc-
|
111
|
+
'fc-multimonth-scroll',
|
112
|
+
'fc-border', // BAD to mix this with size-listening?
|
93
113
|
];
|
94
|
-
return (preact.createElement(internal.ViewContainer, { elRef: this.
|
95
|
-
|
96
|
-
|
97
|
-
|
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
|
+
}))))));
|
98
119
|
}
|
99
120
|
componentDidMount() {
|
100
|
-
this
|
101
|
-
|
102
|
-
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);
|
103
126
|
}
|
104
127
|
componentDidUpdate(prevProps) {
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
if (prevProps.dateProfile !== this.props.dateProfile) {
|
109
|
-
this.requestScrollReset();
|
128
|
+
const { options } = this.context;
|
129
|
+
if (prevProps.dateProfile !== this.props.dateProfile && options.scrollTimeReset) {
|
130
|
+
this.timeScrollResponder.handleScroll(options.scrollTime);
|
110
131
|
}
|
111
132
|
else {
|
112
|
-
this.
|
133
|
+
this.timeScrollResponder.drain();
|
113
134
|
}
|
114
135
|
}
|
115
136
|
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
|
-
}
|
151
|
-
}
|
152
|
-
// workaround for when queued setState render (w/ clientWidth) gets cancelled because
|
153
|
-
// subsequent update and shouldComponentUpdate says not to render :(
|
154
|
-
shouldComponentUpdate() {
|
155
|
-
return true;
|
137
|
+
this.unwatchWidth();
|
138
|
+
this.context.emitter.off('_timeScrollRequest', this.timeScrollResponder.handleScroll);
|
156
139
|
}
|
157
140
|
}
|
158
141
|
// date profile
|
@@ -218,7 +201,7 @@ FullCalendar.MultiMonth = (function (exports, core, internal$1, internal, preact
|
|
218
201
|
multiMonthMinWidth: Number,
|
219
202
|
};
|
220
203
|
|
221
|
-
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}";
|
222
205
|
internal.injectStyles(css_248z);
|
223
206
|
|
224
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,155 +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
|
-
'fc-multimonth-compact' :
|
86
|
-
'',
|
87
|
-
props.isHeightAuto ?
|
106
|
+
getIsHeightAuto(options) ?
|
88
107
|
'' :
|
89
|
-
'fc-
|
108
|
+
'fc-multimonth-scroll',
|
109
|
+
'fc-border', // BAD to mix this with size-listening?
|
90
110
|
];
|
91
|
-
return (createElement(ViewContainer, { elRef: this.
|
92
|
-
|
93
|
-
|
94
|
-
|
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
|
+
}))))));
|
95
116
|
}
|
96
117
|
componentDidMount() {
|
97
|
-
this
|
98
|
-
|
99
|
-
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);
|
100
123
|
}
|
101
124
|
componentDidUpdate(prevProps) {
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
if (prevProps.dateProfile !== this.props.dateProfile) {
|
106
|
-
this.requestScrollReset();
|
125
|
+
const { options } = this.context;
|
126
|
+
if (prevProps.dateProfile !== this.props.dateProfile && options.scrollTimeReset) {
|
127
|
+
this.timeScrollResponder.handleScroll(options.scrollTime);
|
107
128
|
}
|
108
129
|
else {
|
109
|
-
this.
|
130
|
+
this.timeScrollResponder.drain();
|
110
131
|
}
|
111
132
|
}
|
112
133
|
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
|
-
}
|
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;
|
134
|
+
this.unwatchWidth();
|
135
|
+
this.context.emitter.off('_timeScrollRequest', this.timeScrollResponder.handleScroll);
|
153
136
|
}
|
154
137
|
}
|
155
138
|
// date profile
|
@@ -215,7 +198,7 @@ const OPTION_REFINERS = {
|
|
215
198
|
multiMonthMinWidth: Number,
|
216
199
|
};
|
217
200
|
|
218
|
-
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}";
|
219
202
|
injectStyles(css_248z);
|
220
203
|
|
221
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",
|