@fullcalendar/icalendar 7.0.0-beta.6 → 7.0.0-beta.8

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/README.md CHANGED
@@ -14,7 +14,7 @@ npm install ical.js
14
14
  Then, install the FullCalendar core package, the iCalendar plugin, and any other plugins (like [daygrid](https://fullcalendar.io/docs/month-view)):
15
15
 
16
16
  ```sh
17
- npm install @fullcalendar/core @fullcalendar/icalendar @fullcalendar/daygrid
17
+ npm install fullcalendar @fullcalendar/icalendar temporal-polyfill
18
18
  ```
19
19
 
20
20
  ## Usage
@@ -22,14 +22,14 @@ npm install @fullcalendar/core @fullcalendar/icalendar @fullcalendar/daygrid
22
22
  Instantiate a Calendar with the necessary plugins and options:
23
23
 
24
24
  ```js
25
- import { Calendar } from '@fullcalendar/core'
25
+ import { Calendar } from 'fullcalendar'
26
+ import classicThemePlugin from 'fullcalendar/themes/classic'
27
+ import dayGridPlugin from 'fullcalendar/daygrid'
26
28
  import iCalendarPlugin from '@fullcalendar/icalendar'
27
- import dayGridPlugin from '@fullcalendar/daygrid'
28
- import classicThemePlugin from '@fullcalendar/theme-classic'
29
29
 
30
- import '@fullcalendar/core/skeleton.css'
31
- import '@fullcalendar/theme-classic/theme.css'
32
- import '@fullcalendar/theme-classic/palette.css'
30
+ import 'fullcalendar/skeleton.css'
31
+ import 'fullcalendar/themes/classic/theme.css'
32
+ import 'fullcalendar/themes/classic/palette.css'
33
33
 
34
34
  const calendarEl = document.getElementById('calendar')
35
35
  const calendar = new Calendar(calendarEl, {
package/global.js CHANGED
@@ -1,14 +1,39 @@
1
1
  /*!
2
- FullCalendar iCalendar Plugin v7.0.0-beta.6
2
+ FullCalendar iCalendar Plugin v7.0.0-beta.8
3
3
  Docs & License: https://fullcalendar.io/docs/icalendar
4
4
  (c) 2025 Adam Shaw
5
5
  */
6
- FullCalendar.ICalendar = (function (exports, core, internal, ICAL) {
6
+ (function (ICAL) {
7
7
  'use strict';
8
8
 
9
- function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
9
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
10
10
 
11
- var ICAL__default = /*#__PURE__*/_interopDefault(ICAL);
11
+ var ICAL__default = /*#__PURE__*/_interopDefaultLegacy(ICAL);
12
+
13
+ function addDays(m, n) {
14
+ let a = dateToUtcArray(m);
15
+ a[2] += n;
16
+ return arrayToUtcDate(a);
17
+ }
18
+ function dateToUtcArray(date) {
19
+ return [
20
+ date.getUTCFullYear(),
21
+ date.getUTCMonth(),
22
+ date.getUTCDate(),
23
+ date.getUTCHours(),
24
+ date.getUTCMinutes(),
25
+ date.getUTCSeconds(),
26
+ date.getUTCMilliseconds(),
27
+ ];
28
+ }
29
+ function arrayToUtcDate(a) {
30
+ // according to web standards (and Safari), a month index is required.
31
+ // massage if only given a year.
32
+ if (a.length === 1) {
33
+ a = a.concat([0]);
34
+ }
35
+ return new Date(Date.UTC(...a));
36
+ }
12
37
 
13
38
  /* eslint-disable */
14
39
  class IcalExpander {
@@ -120,7 +145,8 @@ FullCalendar.ICalendar = (function (exports, core, internal, ICAL) {
120
145
  }
121
146
  return null;
122
147
  },
123
- fetch(arg, successCallback, errorCallback) {
148
+ fetch(arg, successCallback, // any
149
+ errorCallback) {
124
150
  let meta = arg.eventSource.meta;
125
151
  let { internalState } = meta;
126
152
  /*
@@ -152,8 +178,8 @@ FullCalendar.ICalendar = (function (exports, core, internal, ICAL) {
152
178
  function expandICalEvents(iCalExpander, range) {
153
179
  // expand the range. because our `range` is timeZone-agnostic UTC
154
180
  // or maybe because ical.js always produces dates in local time? i forget
155
- let rangeStart = internal.addDays(range.start, -1);
156
- let rangeEnd = internal.addDays(range.end, 1);
181
+ let rangeStart = addDays(range.start, -1);
182
+ let rangeEnd = addDays(range.end, 1);
157
183
  let iCalRes = iCalExpander.between(rangeStart, rangeEnd); // end inclusive. will give extra results
158
184
  let expanded = [];
159
185
  // TODO: instead of using startDate/endDate.toString to communicate allDay,
@@ -193,17 +219,11 @@ FullCalendar.ICalendar = (function (exports, core, internal, ICAL) {
193
219
  Boolean(iCalEvent.component.getFirstProperty('duration'));
194
220
  }
195
221
 
196
- var plugin = core.createPlugin({
197
- name: '@fullcalendar/icalendar',
222
+ var plugin = {
223
+ name: 'icalendar',
198
224
  eventSourceDefs: [eventSourceDef],
199
- });
200
-
201
- core.globalPlugins.push(plugin);
202
-
203
- exports["default"] = plugin;
204
-
205
- Object.defineProperty(exports, '__esModule', { value: true });
225
+ };
206
226
 
207
- return exports;
227
+ FullCalendar.globalPlugins.push(plugin);
208
228
 
209
- })({}, FullCalendar, FullCalendar.Internal, ICAL);
229
+ })(ICAL);
package/index.d.ts ADDED
@@ -0,0 +1,60 @@
1
+ import ICAL from 'ical.js';
2
+ import * as _full_ui_headless_calendar from '@full-ui/headless-calendar';
3
+
4
+ declare class IcalExpander {
5
+ constructor(opts: any);
6
+ maxIterations: any;
7
+ skipInvalidDates: any;
8
+ jCalData: any;
9
+ component: ICAL.Component;
10
+ events: ICAL.Event[];
11
+ between(after: any, before: any): {
12
+ events: any[];
13
+ occurrences: any[];
14
+ };
15
+ before(before: any): {
16
+ events: any[];
17
+ occurrences: any[];
18
+ };
19
+ after(after: any): {
20
+ events: any[];
21
+ occurrences: any[];
22
+ };
23
+ all(): {
24
+ events: any[];
25
+ occurrences: any[];
26
+ };
27
+ }
28
+
29
+ interface ICalFeedMeta {
30
+ url: string;
31
+ format: 'ics';
32
+ internalState?: InternalState;
33
+ }
34
+ interface InternalState {
35
+ iCalExpanderPromise: Promise<IcalExpander>;
36
+ response: Response | null;
37
+ }
38
+
39
+ declare const _default: {
40
+ name: string;
41
+ eventSourceDefs: {
42
+ parseMeta(refined: {
43
+ url: string;
44
+ format: string;
45
+ }): {
46
+ url: string;
47
+ format: string;
48
+ };
49
+ fetch(arg: {
50
+ isRefetch: boolean;
51
+ range: _full_ui_headless_calendar.DateRange;
52
+ eventSource: {
53
+ meta: ICalFeedMeta;
54
+ };
55
+ }, successCallback: any, errorCallback: any): void;
56
+ }[];
57
+ };
58
+ //# sourceMappingURL=index.d.ts.map
59
+
60
+ export { _default as default };
@@ -1,5 +1,4 @@
1
- import { createPlugin } from '@fullcalendar/core';
2
- import { addDays } from '@fullcalendar/core/internal';
1
+ import { addDays } from '@full-ui/headless-calendar';
3
2
  import ICAL from 'ical.js';
4
3
 
5
4
  /* eslint-disable */
@@ -112,7 +111,8 @@ const eventSourceDef = {
112
111
  }
113
112
  return null;
114
113
  },
115
- fetch(arg, successCallback, errorCallback) {
114
+ fetch(arg, successCallback, // any
115
+ errorCallback) {
116
116
  let meta = arg.eventSource.meta;
117
117
  let { internalState } = meta;
118
118
  /*
@@ -185,9 +185,9 @@ function specifiesEnd(iCalEvent) {
185
185
  Boolean(iCalEvent.component.getFirstProperty('duration'));
186
186
  }
187
187
 
188
- var index = createPlugin({
189
- name: '@fullcalendar/icalendar',
188
+ var index = {
189
+ name: 'icalendar',
190
190
  eventSourceDefs: [eventSourceDef],
191
- });
191
+ };
192
192
 
193
193
  export { index as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fullcalendar/icalendar",
3
- "version": "7.0.0-beta.6",
3
+ "version": "7.0.0-beta.8",
4
4
  "title": "FullCalendar iCalendar Plugin",
5
5
  "description": "Display events from a public iCalendar feed",
6
6
  "keywords": [
@@ -12,9 +12,13 @@
12
12
  "ics"
13
13
  ],
14
14
  "homepage": "https://fullcalendar.io/docs/icalendar",
15
+ "dependencies": {
16
+ "@full-ui/headless-calendar": "7.0.0-beta.8",
17
+ "@fullcalendar/core": "7.0.0-beta.8"
18
+ },
15
19
  "peerDependencies": {
16
- "@fullcalendar/core": "7.0.0-beta.6",
17
- "ical.js": "^2.0.0"
20
+ "ical.js": "^2.0.0",
21
+ "temporal-polyfill": "^0.3.2"
18
22
  },
19
23
  "type": "module",
20
24
  "bugs": "https://fullcalendar.io/reporting-bugs",
@@ -30,23 +34,16 @@
30
34
  "url": "http://arshaw.com/"
31
35
  },
32
36
  "copyright": "2025 Adam Shaw",
33
- "types": "./esm/index.d.ts",
34
- "module": "./esm/index.js",
35
- "main": "./cjs/index.cjs",
36
- "unpkg": "./global.min.js",
37
- "jsdelivr": "./global.min.js",
37
+ "types": "./index.d.ts",
38
+ "main": "./index.js",
38
39
  "exports": {
39
40
  "./package.json": "./package.json",
40
41
  ".": {
41
- "import": {
42
- "types": "./esm/index.d.ts",
43
- "default": "./esm/index.js"
44
- },
45
- "require": "./cjs/index.cjs"
42
+ "types": "./index.d.ts",
43
+ "default": "./index.js"
46
44
  }
47
45
  },
48
46
  "sideEffects": [
49
- "./global.js",
50
- "./global.min.js"
47
+ "./global.js"
51
48
  ]
52
49
  }
package/cjs/index.cjs DELETED
@@ -1,201 +0,0 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- var core = require('@fullcalendar/core');
6
- var internal = require('@fullcalendar/core/internal');
7
- var ICAL = require('ical.js');
8
-
9
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
10
-
11
- var ICAL__default = /*#__PURE__*/_interopDefaultLegacy(ICAL);
12
-
13
- /* eslint-disable */
14
- class IcalExpander {
15
- constructor(opts) {
16
- this.maxIterations = opts.maxIterations != null ? opts.maxIterations : 1000;
17
- this.skipInvalidDates = opts.skipInvalidDates != null ? opts.skipInvalidDates : false;
18
- this.jCalData = ICAL__default["default"].parse(opts.ics);
19
- this.component = new ICAL__default["default"].Component(this.jCalData);
20
- this.events = this.component.getAllSubcomponents('vevent').map(vevent => new ICAL__default["default"].Event(vevent));
21
- if (this.skipInvalidDates) {
22
- this.events = this.events.filter((evt) => {
23
- try {
24
- evt.startDate.toJSDate();
25
- evt.endDate.toJSDate();
26
- return true;
27
- }
28
- catch (err) {
29
- // skipping events with invalid time
30
- return false;
31
- }
32
- });
33
- }
34
- }
35
- between(after, before) {
36
- function isEventWithinRange(startTime, endTime) {
37
- return (!after || endTime >= after.getTime()) &&
38
- (!before || startTime <= before.getTime());
39
- }
40
- function getTimes(eventOrOccurrence) {
41
- const startTime = eventOrOccurrence.startDate.toJSDate().getTime();
42
- let endTime = eventOrOccurrence.endDate.toJSDate().getTime();
43
- // If it is an all day event, the end date is set to 00:00 of the next day
44
- // So we need to make it be 23:59:59 to compare correctly with the given range
45
- if (eventOrOccurrence.endDate.isDate && (endTime > startTime)) {
46
- endTime -= 1;
47
- }
48
- return { startTime, endTime };
49
- }
50
- const exceptions = [];
51
- this.events.forEach((event) => {
52
- if (event.isRecurrenceException())
53
- exceptions.push(event);
54
- });
55
- const ret = {
56
- events: [],
57
- occurrences: [],
58
- };
59
- this.events.filter(e => !e.isRecurrenceException()).forEach((event) => {
60
- const exdates = [];
61
- event.component.getAllProperties('exdate').forEach((exdateProp) => {
62
- const exdate = exdateProp.getFirstValue();
63
- exdates.push(exdate.toJSDate().getTime());
64
- });
65
- // Recurring event is handled differently
66
- if (event.isRecurring()) {
67
- const iterator = event.iterator();
68
- let next;
69
- let i = 0;
70
- do {
71
- i += 1;
72
- next = iterator.next();
73
- if (next) {
74
- const occurrence = event.getOccurrenceDetails(next);
75
- const { startTime, endTime } = getTimes(occurrence);
76
- const isOccurrenceExcluded = exdates.indexOf(startTime) !== -1;
77
- // TODO check that within same day?
78
- const exception = exceptions.find(ex => ex.uid === event.uid && ex.recurrenceId.toJSDate().getTime() === occurrence.startDate.toJSDate().getTime());
79
- // We have passed the max date, stop
80
- if (before && startTime > before.getTime())
81
- break;
82
- // Check that we are within our range
83
- if (isEventWithinRange(startTime, endTime)) {
84
- if (exception) {
85
- ret.events.push(exception);
86
- }
87
- else if (!isOccurrenceExcluded) {
88
- ret.occurrences.push(occurrence);
89
- }
90
- }
91
- }
92
- } while (next && (!this.maxIterations || i < this.maxIterations));
93
- return;
94
- }
95
- // Non-recurring event:
96
- const { startTime, endTime } = getTimes(event);
97
- if (isEventWithinRange(startTime, endTime))
98
- ret.events.push(event);
99
- });
100
- return ret;
101
- }
102
- before(before) {
103
- return this.between(undefined, before);
104
- }
105
- after(after) {
106
- return this.between(after);
107
- }
108
- all() {
109
- return this.between();
110
- }
111
- }
112
-
113
- const eventSourceDef = {
114
- parseMeta(refined) {
115
- if (refined.url && refined.format === 'ics') {
116
- return {
117
- url: refined.url,
118
- format: 'ics',
119
- };
120
- }
121
- return null;
122
- },
123
- fetch(arg, successCallback, errorCallback) {
124
- let meta = arg.eventSource.meta;
125
- let { internalState } = meta;
126
- /*
127
- NOTE: isRefetch is a HACK. we would do the recurring-expanding in a separate plugin hook,
128
- but we couldn't leverage built-in allDay-guessing, among other things.
129
- */
130
- if (!internalState || arg.isRefetch) {
131
- internalState = meta.internalState = {
132
- response: null,
133
- iCalExpanderPromise: fetch(meta.url, { method: 'GET' }).then((response) => {
134
- return response.text().then((icsText) => {
135
- internalState.response = response;
136
- return new IcalExpander({
137
- ics: icsText,
138
- skipInvalidDates: true,
139
- });
140
- });
141
- }),
142
- };
143
- }
144
- internalState.iCalExpanderPromise.then((iCalExpander) => {
145
- successCallback({
146
- rawEvents: expandICalEvents(iCalExpander, arg.range),
147
- response: internalState.response,
148
- });
149
- }, errorCallback);
150
- },
151
- };
152
- function expandICalEvents(iCalExpander, range) {
153
- // expand the range. because our `range` is timeZone-agnostic UTC
154
- // or maybe because ical.js always produces dates in local time? i forget
155
- let rangeStart = internal.addDays(range.start, -1);
156
- let rangeEnd = internal.addDays(range.end, 1);
157
- let iCalRes = iCalExpander.between(rangeStart, rangeEnd); // end inclusive. will give extra results
158
- let expanded = [];
159
- // TODO: instead of using startDate/endDate.toString to communicate allDay,
160
- // we can query startDate/endDate.isDate. More efficient to avoid formatting/reparsing.
161
- // single events
162
- for (let iCalEvent of iCalRes.events) {
163
- expanded.push(Object.assign(Object.assign({}, buildNonDateProps(iCalEvent)), { start: iCalEvent.startDate.toString(), end: (specifiesEnd(iCalEvent) && iCalEvent.endDate)
164
- ? iCalEvent.endDate.toString()
165
- : null }));
166
- }
167
- // recurring event instances
168
- for (let iCalOccurence of iCalRes.occurrences) {
169
- let iCalEvent = iCalOccurence.item;
170
- expanded.push(Object.assign(Object.assign({}, buildNonDateProps(iCalEvent)), { start: iCalOccurence.startDate.toString(), end: (specifiesEnd(iCalEvent) && iCalOccurence.endDate)
171
- ? iCalOccurence.endDate.toString()
172
- : null }));
173
- }
174
- return expanded;
175
- }
176
- function buildNonDateProps(iCalEvent) {
177
- return {
178
- title: iCalEvent.summary,
179
- url: extractEventUrl(iCalEvent),
180
- extendedProps: {
181
- location: iCalEvent.location,
182
- organizer: iCalEvent.organizer,
183
- description: iCalEvent.description,
184
- },
185
- };
186
- }
187
- function extractEventUrl(iCalEvent) {
188
- let urlProp = iCalEvent.component.getFirstProperty('url');
189
- return urlProp ? urlProp.getFirstValue() : '';
190
- }
191
- function specifiesEnd(iCalEvent) {
192
- return Boolean(iCalEvent.component.getFirstProperty('dtend')) ||
193
- Boolean(iCalEvent.component.getFirstProperty('duration'));
194
- }
195
-
196
- var index = core.createPlugin({
197
- name: '@fullcalendar/icalendar',
198
- eventSourceDefs: [eventSourceDef],
199
- });
200
-
201
- exports["default"] = index;
package/esm/index.d.ts DELETED
@@ -1,6 +0,0 @@
1
- import { PluginDef } from '@fullcalendar/core';
2
-
3
- declare const _default: PluginDef;
4
- //# sourceMappingURL=index.d.ts.map
5
-
6
- export { _default as default };
package/global.min.js DELETED
@@ -1,6 +0,0 @@
1
- /*!
2
- FullCalendar iCalendar Plugin v7.0.0-beta.6
3
- Docs & License: https://fullcalendar.io/docs/icalendar
4
- (c) 2025 Adam Shaw
5
- */
6
- FullCalendar.ICalendar=function(e,t,n,r){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}var s=a(r);class i{constructor(e){this.maxIterations=null!=e.maxIterations?e.maxIterations:1e3,this.skipInvalidDates=null!=e.skipInvalidDates&&e.skipInvalidDates,this.jCalData=s.default.parse(e.ics),this.component=new s.default.Component(this.jCalData),this.events=this.component.getAllSubcomponents("vevent").map(e=>new s.default.Event(e)),this.skipInvalidDates&&(this.events=this.events.filter(e=>{try{return e.startDate.toJSDate(),e.endDate.toJSDate(),!0}catch(e){return!1}}))}between(e,t){function n(n,r){return(!e||r>=e.getTime())&&(!t||n<=t.getTime())}function r(e){const t=e.startDate.toJSDate().getTime();let n=e.endDate.toJSDate().getTime();return e.endDate.isDate&&n>t&&(n-=1),{startTime:t,endTime:n}}const a=[];this.events.forEach(e=>{e.isRecurrenceException()&&a.push(e)});const s={events:[],occurrences:[]};return this.events.filter(e=>!e.isRecurrenceException()).forEach(e=>{const i=[];if(e.component.getAllProperties("exdate").forEach(e=>{const t=e.getFirstValue();i.push(t.toJSDate().getTime())}),e.isRecurring()){const o=e.iterator();let l,u=0;do{if(u+=1,l=o.next(),l){const o=e.getOccurrenceDetails(l),{startTime:u,endTime:c}=r(o),d=-1!==i.indexOf(u),p=a.find(t=>t.uid===e.uid&&t.recurrenceId.toJSDate().getTime()===o.startDate.toJSDate().getTime());if(t&&u>t.getTime())break;n(u,c)&&(p?s.events.push(p):d||s.occurrences.push(o))}}while(l&&(!this.maxIterations||u<this.maxIterations));return}const{startTime:o,endTime:l}=r(e);n(o,l)&&s.events.push(e)}),s}before(e){return this.between(void 0,e)}after(e){return this.between(e)}all(){return this.between()}}const o={parseMeta:e=>e.url&&"ics"===e.format?{url:e.url,format:"ics"}:null,fetch(e,t,n){let r=e.eventSource.meta,{internalState:a}=r;a&&!e.isRefetch||(a=r.internalState={response:null,iCalExpanderPromise:fetch(r.url,{method:"GET"}).then(e=>e.text().then(t=>(a.response=e,new i({ics:t,skipInvalidDates:!0}))))}),a.iCalExpanderPromise.then(n=>{t({rawEvents:l(n,e.range),response:a.response})},n)}};function l(e,t){let r=n.addDays(t.start,-1),a=n.addDays(t.end,1),s=e.between(r,a),i=[];for(let e of s.events)i.push(Object.assign(Object.assign({},u(e)),{start:e.startDate.toString(),end:d(e)&&e.endDate?e.endDate.toString():null}));for(let e of s.occurrences){let t=e.item;i.push(Object.assign(Object.assign({},u(t)),{start:e.startDate.toString(),end:d(t)&&e.endDate?e.endDate.toString():null}))}return i}function u(e){return{title:e.summary,url:c(e),extendedProps:{location:e.location,organizer:e.organizer,description:e.description}}}function c(e){let t=e.component.getFirstProperty("url");return t?t.getFirstValue():""}function d(e){return Boolean(e.component.getFirstProperty("dtend"))||Boolean(e.component.getFirstProperty("duration"))}var p=t.createPlugin({name:"@fullcalendar/icalendar",eventSourceDefs:[o]});return t.globalPlugins.push(p),e.default=p,Object.defineProperty(e,"__esModule",{value:!0}),e}({},FullCalendar,FullCalendar.Internal,ICAL);