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