@fullcalendar/multimonth 7.0.0-beta.4 → 7.0.0-beta.5

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.js DELETED
@@ -1,230 +0,0 @@
1
- import { createPlugin } from '@fullcalendar/core/index.js';
2
- import { buildDayTableModel, createDayHeaderFormatter, buildDateRowConfig, DayTableSlicer, DayGridHeaderRow, DayGridRows, buildDayTableRenderRange, TableDateProfileGenerator } from '@fullcalendar/daygrid/internal.js';
3
- import { DateComponent, memoize, getUniqueDomId, joinClassNames, fracToCssDim, getIsHeightAuto, NowTimer, ViewContainer, Scroller, formatIsoMonthStr, watchWidth, afterSize, createDuration, intersectRanges, createFormatter, injectStyles } from '@fullcalendar/core/internal.js';
4
- import { createElement, createRef } from '@fullcalendar/core/preact.js';
5
-
6
- class SingleMonth extends DateComponent {
7
- constructor() {
8
- super(...arguments);
9
- // memo
10
- this.buildDayTableModel = memoize(buildDayTableModel);
11
- this.createDayHeaderFormatter = memoize(createDayHeaderFormatter);
12
- this.buildDateRowConfig = memoize(buildDateRowConfig);
13
- // internal
14
- this.slicer = new DayTableSlicer();
15
- this.titleId = getUniqueDomId();
16
- }
17
- render() {
18
- const { props, context } = this;
19
- const { dateProfile, forPrint } = props;
20
- const { options } = context;
21
- const dayTableModel = this.buildDayTableModel(dateProfile, context.dateProfileGenerator);
22
- const slicedProps = this.slicer.sliceProps(props, dateProfile, options.nextDayThreshold, context, dayTableModel);
23
- const dayHeaderFormat = this.createDayHeaderFormatter(options.dayHeaderFormat, false, // datesRepDistinctDays
24
- dayTableModel.colCnt);
25
- const rowConfig = this.buildDateRowConfig(dayTableModel.headerDates, false, // datesRepDistinctDays
26
- dateProfile, props.todayRange, dayHeaderFormat, context);
27
- const invAspectRatio = 1 / options.aspectRatio;
28
- const invRowAspectRatio = invAspectRatio / dayTableModel.rowCnt;
29
- const isHeaderSticky = !forPrint;
30
- const isAspectRatio = !forPrint || props.hasLateralSiblings;
31
- return (createElement("div", { role: 'listitem', className: 'fc-multimonth-month-outer', style: { width: props.width } },
32
- createElement("div", { role: 'grid', "aria-labelledby": this.titleId, "data-date": props.isoDateStr, className: joinClassNames('fc-multimonth-month', props.hasLateralSiblings && 'fc-break-inside-avoid') },
33
- createElement("div", { className: "fc-multimonth-header", style: {
34
- marginBottom: isHeaderSticky ? fracToCssDim(invRowAspectRatio) : undefined,
35
- } },
36
- createElement("div", { id: this.titleId, className: 'fc-multimonth-title' }, context.dateEnv.format(props.dateProfile.currentRange.start, props.titleFormat)),
37
- createElement(DayGridHeaderRow, Object.assign({}, rowConfig, { role: 'row', className: 'fc-multimonth-header-row' }))),
38
- createElement("div", { className: joinClassNames('fc-multimonth-body', isAspectRatio && 'fc-rel'), style: {
39
- marginTop: isHeaderSticky ? fracToCssDim(-invRowAspectRatio) : undefined,
40
- paddingBottom: isAspectRatio ? fracToCssDim(invAspectRatio) : undefined,
41
- } },
42
- createElement(DayGridRows, { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: dayTableModel.cellRows, className: isAspectRatio ? 'fc-fill' : '', forPrint: forPrint && !props.hasLateralSiblings, dayMaxEvents: forPrint ? undefined : options.dayMaxEvents, dayMaxEventRows: (forPrint && props.hasLateralSiblings) ? 1 : options.dayMaxEventRows,
43
- // content
44
- fgEventSegs: slicedProps.fgEventSegs, bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventDrag: slicedProps.eventDrag, eventResize: slicedProps.eventResize, eventSelection: slicedProps.eventSelection,
45
- // dimensions
46
- visibleWidth: props.visibleWidth })))));
47
- }
48
- }
49
-
50
- class MultiMonthView extends DateComponent {
51
- constructor() {
52
- super(...arguments);
53
- // memo
54
- this.splitDateProfileByMonth = memoize(splitDateProfileByMonth);
55
- this.buildMonthFormat = memoize(buildMonthFormat);
56
- // ref
57
- this.scrollerRef = createRef();
58
- this.innerElRef = createRef(); // .fc-multimonth-inner
59
- this.scrollDate = null;
60
- this.handleScrollEnd = ({ isUser }) => {
61
- if (isUser) {
62
- this.scrollDate = null;
63
- }
64
- };
65
- }
66
- render() {
67
- const { context, props, state } = this;
68
- const { options } = context;
69
- const verticalScrolling = !props.forPrint && !getIsHeightAuto(options);
70
- const monthDateProfiles = this.splitDateProfileByMonth(context.dateProfileGenerator, props.dateProfile, context.dateEnv, options.fixedWeekCount, options.showNonCurrentDates);
71
- const monthTitleFormat = this.buildMonthFormat(options.multiMonthTitleFormat, monthDateProfiles);
72
- const { multiMonthMinWidth, multiMonthMaxColumns } = options;
73
- const { innerWidth } = state;
74
- let cols;
75
- let computedMonthWidth;
76
- let cssMonthWidth;
77
- let hasLateralSiblings = false;
78
- if (innerWidth != null) {
79
- cols = Math.max(1, Math.min(multiMonthMaxColumns, Math.floor(innerWidth / multiMonthMinWidth)));
80
- if (props.forPrint) {
81
- cols = Math.min(cols, 2);
82
- }
83
- computedMonthWidth = innerWidth / cols;
84
- cssMonthWidth = fracToCssDim(1 / cols);
85
- hasLateralSiblings = cols > 1;
86
- }
87
- return (createElement(NowTimer, { unit: "day" }, (nowDate, todayRange) => (createElement(ViewContainer, { viewSpec: context.viewSpec, className: joinClassNames('fc-multimonth fc-border', (cols === 1) ?
88
- 'fc-multimonth-singlecol' :
89
- 'fc-multimonth-multicol',
90
- // HACK for Safari. Can't do break-inside:avoid with flexbox items, likely b/c it's not standard:
91
- // https://stackoverflow.com/a/60256345
92
- !props.forPrint && 'fc-flex-col') },
93
- createElement(Scroller, { vertical: verticalScrolling, className: verticalScrolling ? 'fc-liquid' : '', ref: this.scrollerRef },
94
- createElement("div", { role: 'list', "aria-labelledby": props.labelId, "aria-label": props.labelStr, className: 'fc-multimonth-inner', ref: this.innerElRef }, monthDateProfiles.map((monthDateProfile) => {
95
- const monthStr = formatIsoMonthStr(monthDateProfile.currentRange.start);
96
- return (createElement(SingleMonth, Object.assign({}, props, { key: monthStr, todayRange: todayRange, isoDateStr: monthStr, titleFormat: monthTitleFormat, dateProfile: monthDateProfile, width: cssMonthWidth, visibleWidth: computedMonthWidth, hasLateralSiblings: hasLateralSiblings })));
97
- })))))));
98
- }
99
- // Lifecycle
100
- // -----------------------------------------------------------------------------------------------
101
- componentDidMount() {
102
- this.resetScroll();
103
- this.scrollerRef.current.addScrollEndListener(this.handleScrollEnd);
104
- this.disconnectInnerWidth = watchWidth(this.innerElRef.current, (innerWidth) => {
105
- afterSize(() => {
106
- this.setState({ innerWidth });
107
- });
108
- });
109
- }
110
- componentDidUpdate(prevProps) {
111
- if (prevProps.dateProfile !== this.props.dateProfile && this.context.options.scrollTimeReset) {
112
- this.resetScroll();
113
- }
114
- else {
115
- // NOT optimal to update so often
116
- // TODO: isolate dependencies of scroll coordinate
117
- this.applyScroll();
118
- }
119
- }
120
- componentWillUnmount() {
121
- this.scrollerRef.current.removeScrollEndListener(this.handleScrollEnd);
122
- this.disconnectInnerWidth();
123
- }
124
- // Scrolling
125
- // -----------------------------------------------------------------------------------------------
126
- resetScroll() {
127
- this.scrollDate = this.props.dateProfile.currentDate;
128
- this.applyScroll();
129
- }
130
- applyScroll() {
131
- if (this.scrollDate != null &&
132
- this.state.innerWidth != null // render completed?
133
- ) {
134
- const scroller = this.scrollerRef.current;
135
- const innerEl = this.innerElRef.current;
136
- const monthEl = innerEl.querySelector(`[data-date="${formatIsoMonthStr(this.scrollDate)}"]`);
137
- const scrollTop = Math.ceil(// for fractions, err on the side of scrolling further
138
- monthEl.getBoundingClientRect().top -
139
- innerEl.getBoundingClientRect().top);
140
- scroller.scrollTo({ y: scrollTop });
141
- }
142
- }
143
- }
144
- // date profile
145
- // -------------------------------------------------------------------------------------------------
146
- const oneMonthDuration = createDuration(1, 'month');
147
- function splitDateProfileByMonth(dateProfileGenerator, dateProfile, dateEnv, fixedWeekCount, showNonCurrentDates) {
148
- const { start, end } = dateProfile.currentRange;
149
- let monthStart = start;
150
- const monthDateProfiles = [];
151
- while (monthStart.valueOf() < end.valueOf()) {
152
- const monthEnd = dateEnv.add(monthStart, oneMonthDuration);
153
- const currentRange = {
154
- // yuck
155
- start: dateProfileGenerator.skipHiddenDays(monthStart),
156
- end: dateProfileGenerator.skipHiddenDays(monthEnd, -1, true),
157
- };
158
- let renderRange = buildDayTableRenderRange({
159
- currentRange,
160
- snapToWeek: true,
161
- fixedWeekCount,
162
- dateEnv,
163
- });
164
- renderRange = {
165
- // yuck
166
- start: dateProfileGenerator.skipHiddenDays(renderRange.start),
167
- end: dateProfileGenerator.skipHiddenDays(renderRange.end, -1, true),
168
- };
169
- const activeRange = dateProfile.activeRange ?
170
- intersectRanges(dateProfile.activeRange, showNonCurrentDates ? renderRange : currentRange) :
171
- null;
172
- monthDateProfiles.push({
173
- currentDate: dateProfile.currentDate,
174
- isValid: dateProfile.isValid,
175
- validRange: dateProfile.validRange,
176
- renderRange,
177
- activeRange,
178
- currentRange,
179
- currentRangeUnit: 'month',
180
- isRangeAllDay: true,
181
- dateIncrement: dateProfile.dateIncrement,
182
- slotMinTime: dateProfile.slotMaxTime,
183
- slotMaxTime: dateProfile.slotMinTime,
184
- });
185
- monthStart = monthEnd;
186
- }
187
- return monthDateProfiles;
188
- }
189
- // date formatting
190
- // -------------------------------------------------------------------------------------------------
191
- const YEAR_MONTH_FORMATTER = createFormatter({ year: 'numeric', month: 'long' });
192
- const YEAR_FORMATTER = createFormatter({ month: 'long' });
193
- function buildMonthFormat(formatOverride, monthDateProfiles) {
194
- return formatOverride ||
195
- ((monthDateProfiles[0].currentRange.start.getUTCFullYear() !==
196
- monthDateProfiles[monthDateProfiles.length - 1].currentRange.start.getUTCFullYear())
197
- ? YEAR_MONTH_FORMATTER
198
- : YEAR_FORMATTER);
199
- }
200
-
201
- const OPTION_REFINERS = {
202
- multiMonthTitleFormat: createFormatter,
203
- multiMonthMaxColumns: Number,
204
- multiMonthMinWidth: Number,
205
- };
206
-
207
- var css_248z = ".fc-media-screen .fc-multimonth-inner{display:flex;flex-direction:row;flex-wrap:wrap}.fc-media-print.fc-direction-ltr .fc-multimonth-inner>*{float:left}.fc-media-print.fc-direction-rtl .fc-multimonth-inner>*{float:right}.fc-media-print .fc-multimonth-inner:after{clear:both;content:\"\";display:block}.fc-multimonth-multicol .fc-multimonth-month{padding:1.2em}.fc-multimonth-singlecol .fc-multimonth-title{padding:.5em 0}.fc-multimonth-multicol .fc-multimonth-title{padding-bottom:1em}.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-body:not(.fc-multimonth-singlecol .fc-multimonth-month-outer:last-child .fc-multimonth-body),.fc-multimonth-header-row{border-bottom:1px solid var(--fc-border-color)}.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}";
208
- injectStyles(css_248z);
209
-
210
- var index = createPlugin({
211
- name: '@fullcalendar/multimonth',
212
- initialView: 'multiMonthYear',
213
- optionRefiners: OPTION_REFINERS,
214
- views: {
215
- multiMonth: {
216
- component: MultiMonthView,
217
- dateProfileGeneratorClass: TableDateProfileGenerator,
218
- multiMonthMinWidth: 350,
219
- multiMonthMaxColumns: 3,
220
- },
221
- multiMonthYear: {
222
- type: 'multiMonth',
223
- duration: { years: 1 },
224
- fixedWeekCount: true,
225
- showNonCurrentDates: false, // TODO: looks bad when single-col layout
226
- },
227
- },
228
- });
229
-
230
- export { index as default };