@event-calendar/core 2.6.0 → 2.7.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/README.md CHANGED
@@ -4,7 +4,7 @@ See [demo](https://vkurko.github.io/calendar/) and [changelog](CHANGELOG.md).
4
4
 
5
5
  Full-sized drag & drop JavaScript event calendar with resource view:
6
6
 
7
- * Lightweight (32kb [br](https://en.wikipedia.org/wiki/Brotli) compressed)
7
+ * Lightweight (33kb [br](https://en.wikipedia.org/wiki/Brotli) compressed)
8
8
  * Zero-dependency (pre-built bundle)
9
9
  * Used on over 70,000 websites with [Bookly](https://wordpress.org/plugins/bookly-responsive-appointment-booking-tool/)
10
10
 
@@ -22,6 +22,7 @@ Inspired by [FullCalendar](https://fullcalendar.io/), implements similar options
22
22
  - [allDayContent](#alldaycontent)
23
23
  - [allDaySlot](#alldayslot)
24
24
  - [buttonText](#buttontext)
25
+ - [customButtons](#custombuttons)
25
26
  - [date](#date)
26
27
  - [dateClick](#dateclick)
27
28
  - [datesAboveResources](#datesaboveresources)
@@ -45,9 +46,9 @@ Inspired by [FullCalendar](https://fullcalendar.io/), implements similar options
45
46
  - [eventDidMount](#eventdidmount)
46
47
  - [eventDragMinDistance](#eventdragmindistance)
47
48
  - [eventDragStart](#eventdragstart)
48
- - [eventDragStop](#eventdragstop)
49
49
  </td><td>
50
50
 
51
+ - [eventDragStop](#eventdragstop)
51
52
  - [eventDrop](#eventdrop)
52
53
  - [eventDurationEditable](#eventdurationeditable)
53
54
  - [eventLongPressDelay](#eventlongpressdelay)
@@ -74,9 +75,9 @@ Inspired by [FullCalendar](https://fullcalendar.io/), implements similar options
74
75
  - [locale](#locale)
75
76
  - [longPressDelay](#longpressdelay)
76
77
  - [moreLinkContent](#morelinkcontent)
77
- - [noEventsClick](#noeventsclick)
78
78
  </td><td>
79
79
 
80
+ - [noEventsClick](#noeventsclick)
80
81
  - [noEventsContent](#noeventscontent)
81
82
  - [nowIndicator](#nowindicator)
82
83
  - [pointer](#pointer)
@@ -199,8 +200,8 @@ import '@event-calendar/core/index.css';
199
200
  ### Pre-built browser ready bundle
200
201
  Include the following lines of code in the `<head>` section of your page:
201
202
  ```html
202
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@event-calendar/build@2.6.0/event-calendar.min.css">
203
- <script src="https://cdn.jsdelivr.net/npm/@event-calendar/build@2.6.0/event-calendar.min.js"></script>
203
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@event-calendar/build@2.7.0/event-calendar.min.css">
204
+ <script src="https://cdn.jsdelivr.net/npm/@event-calendar/build@2.7.0/event-calendar.min.js"></script>
204
205
  ```
205
206
 
206
207
  <details>
@@ -321,6 +322,54 @@ function (text) {
321
322
  </tr>
322
323
  </table>
323
324
 
325
+ ### customButtons
326
+ - Type `object`
327
+ - Default `undefined`
328
+
329
+ Defines custom buttons that can be used in the [headerToolbar](#headertoolbar).
330
+
331
+ First, specify the custom buttons as key-value pairs. Then reference them from the `headerToolbar` option.
332
+
333
+ <details>
334
+ <summary>Example</summary>
335
+
336
+ ```js
337
+ let options = {
338
+ customButtons: {
339
+ myCustomButton: {
340
+ text: 'custom!',
341
+ click: function() {
342
+ alert('clicked the custom button!');
343
+ }
344
+ }
345
+ },
346
+ headerToolbar: {
347
+ start: 'title myCustomButton',
348
+ center: '',
349
+ end: 'today prev,next'
350
+ }
351
+ };
352
+ ```
353
+ </details>
354
+
355
+ Each `customButton` entry accepts the following properties:
356
+ <table>
357
+ <tr>
358
+ <td>
359
+
360
+ `text `
361
+ </td>
362
+ <td>The text to be display on the button itself</td>
363
+ </tr>
364
+ <tr>
365
+ <td>
366
+
367
+ `click`
368
+ </td>
369
+ <td>A callback function that is called when the button is clicked. Accepts one argument <a href="https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent">mouseEvent</a></td>
370
+ </tr>
371
+ </table>
372
+
324
373
  ### date
325
374
  - Type `Date` or `string`
326
375
  - Default `new Date()`
@@ -1288,7 +1337,27 @@ This option is used instead of the `events` option.
1288
1337
  </td>
1289
1338
  <td>
1290
1339
 
1291
- A URL that the calendar will fetch [Event](#event-object) objects from
1340
+ A URL that the calendar will fetch [Event](#event-object) objects from. HTTP requests with the following parameters will be sent to this URL whenever the calendar needs new event data:
1341
+ <table>
1342
+ <tr>
1343
+ <td>
1344
+
1345
+ `start`
1346
+ </td>
1347
+ <td>
1348
+ Start date of the range the calendar needs events for
1349
+ </td>
1350
+ </tr>
1351
+ <tr>
1352
+ <td>
1353
+
1354
+ `end`
1355
+ </td>
1356
+ <td>
1357
+ End date of the range the calendar needs events for
1358
+ </td>
1359
+ </tr>
1360
+ </table>
1292
1361
  </td>
1293
1362
  </tr>
1294
1363
  <tr>
package/index.js CHANGED
@@ -619,15 +619,53 @@ function intl(locale, format) {
619
619
 
620
620
  function intlRange(locale, format) {
621
621
  return derived([locale, format], ([$locale, $format]) => {
622
- let intl = is_function($format)
623
- ? {formatRange: $format}
624
- : new Intl.DateTimeFormat($locale, $format);
622
+ let formatRange;
623
+ if (is_function($format)) {
624
+ formatRange = $format;
625
+ } else {
626
+ let intl = new Intl.DateTimeFormat($locale, $format);
627
+ formatRange = (start, end) => {
628
+ if (start <= end) {
629
+ return intl.formatRange(start, end);
630
+ } else {
631
+ // In iOS 16 and older, intl.formatRange() throws an exception if the start date is later than the end date.
632
+ // Therefore, we first swap the parameters, and then swap the resulting parts.
633
+ /** @see https://github.com/vkurko/calendar/issues/227 */
634
+ let parts = intl.formatRangeToParts(end, start);
635
+ let result = '';
636
+ let sources = ['startRange', 'endRange'];
637
+ let processed = [false, false];
638
+ for (let part of parts) {
639
+ let i = sources.indexOf(part.source);
640
+ if (i >= 0) {
641
+ if (!processed[i]) {
642
+ result += _getParts(sources[1 - i], parts);
643
+ processed[i] = true;
644
+ }
645
+ } else {
646
+ result += part.value;
647
+ }
648
+ }
649
+ return result;
650
+ }
651
+ };
652
+ }
625
653
  return {
626
- formatRange: (start, end) => intl.formatRange(toLocalDate(start), toLocalDate(end))
654
+ formatRange: (start, end) => formatRange(toLocalDate(start), toLocalDate(end))
627
655
  };
628
656
  });
629
657
  }
630
658
 
659
+ function _getParts(source, parts) {
660
+ let result = '';
661
+ for (let part of parts) {
662
+ if (part.source == source) {
663
+ result += part.value;
664
+ }
665
+ }
666
+ return result;
667
+ }
668
+
631
669
  function createOptions(plugins) {
632
670
  let options = {
633
671
  allDayContent: undefined,
@@ -635,6 +673,7 @@ function createOptions(plugins) {
635
673
  buttonText: {
636
674
  today: 'today',
637
675
  },
676
+ customButtons: {},
638
677
  date: new Date(),
639
678
  datesSet: undefined,
640
679
  dayHeaderFormat: {
@@ -1131,25 +1170,25 @@ function validKey(key, state) {
1131
1170
  return state.hasOwnProperty(key) && key[0] !== '_';
1132
1171
  }
1133
1172
 
1134
- /* packages/core/src/Buttons.svelte generated by Svelte v4.2.8 */
1173
+ /* packages/core/src/Buttons.svelte generated by Svelte v4.2.16 */
1135
1174
 
1136
1175
  function get_each_context$2(ctx, list, i) {
1137
1176
  const child_ctx = ctx.slice();
1138
- child_ctx[23] = list[i];
1177
+ child_ctx[25] = list[i];
1139
1178
  return child_ctx;
1140
1179
  }
1141
1180
 
1142
- // (52:27)
1143
- function create_if_block_4(ctx) {
1181
+ // (57:27)
1182
+ function create_if_block_5(ctx) {
1144
1183
  let button_1;
1145
- let t_value = /*$buttonText*/ ctx[5][/*button*/ ctx[23]] + "";
1184
+ let t_value = /*$buttonText*/ ctx[5][/*button*/ ctx[25]] + "";
1146
1185
  let t;
1147
1186
  let button_1_class_value;
1148
1187
  let mounted;
1149
1188
  let dispose;
1150
1189
 
1151
1190
  function click_handler_1() {
1152
- return /*click_handler_1*/ ctx[20](/*button*/ ctx[23]);
1191
+ return /*click_handler_1*/ ctx[22](/*button*/ ctx[25]);
1153
1192
  }
1154
1193
 
1155
1194
  return {
@@ -1157,9 +1196,9 @@ function create_if_block_4(ctx) {
1157
1196
  button_1 = element("button");
1158
1197
  t = text(t_value);
1159
1198
 
1160
- attr(button_1, "class", button_1_class_value = "" + (/*$theme*/ ctx[3].button + (/*$view*/ ctx[6] === /*button*/ ctx[23]
1199
+ attr(button_1, "class", button_1_class_value = "" + (/*$theme*/ ctx[3].button + (/*$view*/ ctx[7] === /*button*/ ctx[25]
1161
1200
  ? ' ' + /*$theme*/ ctx[3].active
1162
- : '') + " ec-" + /*button*/ ctx[23]));
1201
+ : '') + " ec-" + /*button*/ ctx[25]));
1163
1202
  },
1164
1203
  m(target, anchor) {
1165
1204
  insert(target, button_1, anchor);
@@ -1172,11 +1211,57 @@ function create_if_block_4(ctx) {
1172
1211
  },
1173
1212
  p(new_ctx, dirty) {
1174
1213
  ctx = new_ctx;
1175
- if (dirty & /*$buttonText, buttons*/ 33 && t_value !== (t_value = /*$buttonText*/ ctx[5][/*button*/ ctx[23]] + "")) set_data(t, t_value);
1214
+ if (dirty & /*$buttonText, buttons*/ 33 && t_value !== (t_value = /*$buttonText*/ ctx[5][/*button*/ ctx[25]] + "")) set_data(t, t_value);
1176
1215
 
1177
- if (dirty & /*$theme, $view, buttons*/ 73 && button_1_class_value !== (button_1_class_value = "" + (/*$theme*/ ctx[3].button + (/*$view*/ ctx[6] === /*button*/ ctx[23]
1216
+ if (dirty & /*$theme, $view, buttons*/ 137 && button_1_class_value !== (button_1_class_value = "" + (/*$theme*/ ctx[3].button + (/*$view*/ ctx[7] === /*button*/ ctx[25]
1178
1217
  ? ' ' + /*$theme*/ ctx[3].active
1179
- : '') + " ec-" + /*button*/ ctx[23]))) {
1218
+ : '') + " ec-" + /*button*/ ctx[25]))) {
1219
+ attr(button_1, "class", button_1_class_value);
1220
+ }
1221
+ },
1222
+ d(detaching) {
1223
+ if (detaching) {
1224
+ detach(button_1);
1225
+ }
1226
+
1227
+ mounted = false;
1228
+ dispose();
1229
+ }
1230
+ };
1231
+ }
1232
+
1233
+ // (52:37)
1234
+ function create_if_block_4(ctx) {
1235
+ let button_1;
1236
+ let t_value = /*$customButtons*/ ctx[6][/*button*/ ctx[25]].text + "";
1237
+ let t;
1238
+ let button_1_class_value;
1239
+ let mounted;
1240
+ let dispose;
1241
+
1242
+ return {
1243
+ c() {
1244
+ button_1 = element("button");
1245
+ t = text(t_value);
1246
+ attr(button_1, "class", button_1_class_value = "" + (/*$theme*/ ctx[3].button + " ec-" + /*button*/ ctx[25]));
1247
+ },
1248
+ m(target, anchor) {
1249
+ insert(target, button_1, anchor);
1250
+ append(button_1, t);
1251
+
1252
+ if (!mounted) {
1253
+ dispose = listen(button_1, "click", function () {
1254
+ if (is_function(/*$customButtons*/ ctx[6][/*button*/ ctx[25]].click)) /*$customButtons*/ ctx[6][/*button*/ ctx[25]].click.apply(this, arguments);
1255
+ });
1256
+
1257
+ mounted = true;
1258
+ }
1259
+ },
1260
+ p(new_ctx, dirty) {
1261
+ ctx = new_ctx;
1262
+ if (dirty & /*$customButtons, buttons*/ 65 && t_value !== (t_value = /*$customButtons*/ ctx[6][/*button*/ ctx[25]].text + "")) set_data(t, t_value);
1263
+
1264
+ if (dirty & /*$theme, buttons*/ 9 && button_1_class_value !== (button_1_class_value = "" + (/*$theme*/ ctx[3].button + " ec-" + /*button*/ ctx[25]))) {
1180
1265
  attr(button_1, "class", button_1_class_value);
1181
1266
  }
1182
1267
  },
@@ -1194,7 +1279,7 @@ function create_if_block_4(ctx) {
1194
1279
  // (46:32)
1195
1280
  function create_if_block_3(ctx) {
1196
1281
  let button_1;
1197
- let t_value = /*$buttonText*/ ctx[5][/*button*/ ctx[23]] + "";
1282
+ let t_value = /*$buttonText*/ ctx[5][/*button*/ ctx[25]] + "";
1198
1283
  let t;
1199
1284
  let button_1_class_value;
1200
1285
  let mounted;
@@ -1204,7 +1289,7 @@ function create_if_block_3(ctx) {
1204
1289
  c() {
1205
1290
  button_1 = element("button");
1206
1291
  t = text(t_value);
1207
- attr(button_1, "class", button_1_class_value = "" + (/*$theme*/ ctx[3].button + " ec-" + /*button*/ ctx[23]));
1292
+ attr(button_1, "class", button_1_class_value = "" + (/*$theme*/ ctx[3].button + " ec-" + /*button*/ ctx[25]));
1208
1293
  button_1.disabled = /*isToday*/ ctx[1];
1209
1294
  },
1210
1295
  m(target, anchor) {
@@ -1212,14 +1297,14 @@ function create_if_block_3(ctx) {
1212
1297
  append(button_1, t);
1213
1298
 
1214
1299
  if (!mounted) {
1215
- dispose = listen(button_1, "click", /*click_handler*/ ctx[19]);
1300
+ dispose = listen(button_1, "click", /*click_handler*/ ctx[21]);
1216
1301
  mounted = true;
1217
1302
  }
1218
1303
  },
1219
1304
  p(ctx, dirty) {
1220
- if (dirty & /*$buttonText, buttons*/ 33 && t_value !== (t_value = /*$buttonText*/ ctx[5][/*button*/ ctx[23]] + "")) set_data(t, t_value);
1305
+ if (dirty & /*$buttonText, buttons*/ 33 && t_value !== (t_value = /*$buttonText*/ ctx[5][/*button*/ ctx[25]] + "")) set_data(t, t_value);
1221
1306
 
1222
- if (dirty & /*$theme, buttons*/ 9 && button_1_class_value !== (button_1_class_value = "" + (/*$theme*/ ctx[3].button + " ec-" + /*button*/ ctx[23]))) {
1307
+ if (dirty & /*$theme, buttons*/ 9 && button_1_class_value !== (button_1_class_value = "" + (/*$theme*/ ctx[3].button + " ec-" + /*button*/ ctx[25]))) {
1223
1308
  attr(button_1, "class", button_1_class_value);
1224
1309
  }
1225
1310
 
@@ -1253,8 +1338,8 @@ function create_if_block_2(ctx) {
1253
1338
  c() {
1254
1339
  button_1 = element("button");
1255
1340
  i = element("i");
1256
- attr(i, "class", i_class_value = "" + (/*$theme*/ ctx[3].icon + " ec-" + /*button*/ ctx[23]));
1257
- attr(button_1, "class", button_1_class_value = "" + (/*$theme*/ ctx[3].button + " ec-" + /*button*/ ctx[23]));
1341
+ attr(i, "class", i_class_value = "" + (/*$theme*/ ctx[3].icon + " ec-" + /*button*/ ctx[25]));
1342
+ attr(button_1, "class", button_1_class_value = "" + (/*$theme*/ ctx[3].button + " ec-" + /*button*/ ctx[25]));
1258
1343
  attr(button_1, "aria-label", button_1_aria_label_value = /*$buttonText*/ ctx[5].next);
1259
1344
  attr(button_1, "title", button_1_title_value = /*$buttonText*/ ctx[5].next);
1260
1345
  },
@@ -1263,16 +1348,16 @@ function create_if_block_2(ctx) {
1263
1348
  append(button_1, i);
1264
1349
 
1265
1350
  if (!mounted) {
1266
- dispose = listen(button_1, "click", /*next*/ ctx[17]);
1351
+ dispose = listen(button_1, "click", /*next*/ ctx[19]);
1267
1352
  mounted = true;
1268
1353
  }
1269
1354
  },
1270
1355
  p(ctx, dirty) {
1271
- if (dirty & /*$theme, buttons*/ 9 && i_class_value !== (i_class_value = "" + (/*$theme*/ ctx[3].icon + " ec-" + /*button*/ ctx[23]))) {
1356
+ if (dirty & /*$theme, buttons*/ 9 && i_class_value !== (i_class_value = "" + (/*$theme*/ ctx[3].icon + " ec-" + /*button*/ ctx[25]))) {
1272
1357
  attr(i, "class", i_class_value);
1273
1358
  }
1274
1359
 
1275
- if (dirty & /*$theme, buttons*/ 9 && button_1_class_value !== (button_1_class_value = "" + (/*$theme*/ ctx[3].button + " ec-" + /*button*/ ctx[23]))) {
1360
+ if (dirty & /*$theme, buttons*/ 9 && button_1_class_value !== (button_1_class_value = "" + (/*$theme*/ ctx[3].button + " ec-" + /*button*/ ctx[25]))) {
1276
1361
  attr(button_1, "class", button_1_class_value);
1277
1362
  }
1278
1363
 
@@ -1310,8 +1395,8 @@ function create_if_block_1(ctx) {
1310
1395
  c() {
1311
1396
  button_1 = element("button");
1312
1397
  i = element("i");
1313
- attr(i, "class", i_class_value = "" + (/*$theme*/ ctx[3].icon + " ec-" + /*button*/ ctx[23]));
1314
- attr(button_1, "class", button_1_class_value = "" + (/*$theme*/ ctx[3].button + " ec-" + /*button*/ ctx[23]));
1398
+ attr(i, "class", i_class_value = "" + (/*$theme*/ ctx[3].icon + " ec-" + /*button*/ ctx[25]));
1399
+ attr(button_1, "class", button_1_class_value = "" + (/*$theme*/ ctx[3].button + " ec-" + /*button*/ ctx[25]));
1315
1400
  attr(button_1, "aria-label", button_1_aria_label_value = /*$buttonText*/ ctx[5].prev);
1316
1401
  attr(button_1, "title", button_1_title_value = /*$buttonText*/ ctx[5].prev);
1317
1402
  },
@@ -1320,16 +1405,16 @@ function create_if_block_1(ctx) {
1320
1405
  append(button_1, i);
1321
1406
 
1322
1407
  if (!mounted) {
1323
- dispose = listen(button_1, "click", /*prev*/ ctx[16]);
1408
+ dispose = listen(button_1, "click", /*prev*/ ctx[18]);
1324
1409
  mounted = true;
1325
1410
  }
1326
1411
  },
1327
1412
  p(ctx, dirty) {
1328
- if (dirty & /*$theme, buttons*/ 9 && i_class_value !== (i_class_value = "" + (/*$theme*/ ctx[3].icon + " ec-" + /*button*/ ctx[23]))) {
1413
+ if (dirty & /*$theme, buttons*/ 9 && i_class_value !== (i_class_value = "" + (/*$theme*/ ctx[3].icon + " ec-" + /*button*/ ctx[25]))) {
1329
1414
  attr(i, "class", i_class_value);
1330
1415
  }
1331
1416
 
1332
- if (dirty & /*$theme, buttons*/ 9 && button_1_class_value !== (button_1_class_value = "" + (/*$theme*/ ctx[3].button + " ec-" + /*button*/ ctx[23]))) {
1417
+ if (dirty & /*$theme, buttons*/ 9 && button_1_class_value !== (button_1_class_value = "" + (/*$theme*/ ctx[3].button + " ec-" + /*button*/ ctx[25]))) {
1333
1418
  attr(button_1, "class", button_1_class_value);
1334
1419
  }
1335
1420
 
@@ -1396,11 +1481,12 @@ function create_each_block$2(ctx) {
1396
1481
  let if_block_anchor;
1397
1482
 
1398
1483
  function select_block_type(ctx, dirty) {
1399
- if (/*button*/ ctx[23] == 'title') return create_if_block$1;
1400
- if (/*button*/ ctx[23] == 'prev') return create_if_block_1;
1401
- if (/*button*/ ctx[23] == 'next') return create_if_block_2;
1402
- if (/*button*/ ctx[23] == 'today') return create_if_block_3;
1403
- if (/*button*/ ctx[23] != '') return create_if_block_4;
1484
+ if (/*button*/ ctx[25] == 'title') return create_if_block$1;
1485
+ if (/*button*/ ctx[25] == 'prev') return create_if_block_1;
1486
+ if (/*button*/ ctx[25] == 'next') return create_if_block_2;
1487
+ if (/*button*/ ctx[25] == 'today') return create_if_block_3;
1488
+ if (/*$customButtons*/ ctx[6][/*button*/ ctx[25]]) return create_if_block_4;
1489
+ if (/*button*/ ctx[25] != '') return create_if_block_5;
1404
1490
  }
1405
1491
 
1406
1492
  let current_block_type = select_block_type(ctx);
@@ -1467,7 +1553,7 @@ function create_fragment$3(ctx) {
1467
1553
  insert(target, each_1_anchor, anchor);
1468
1554
  },
1469
1555
  p(ctx, [dirty]) {
1470
- if (dirty & /*$theme, $_viewTitle, buttons, $buttonText, prev, next, isToday, $date, today, $view*/ 229503) {
1556
+ if (dirty & /*$theme, $_viewTitle, buttons, $buttonText, prev, next, isToday, $date, today, $customButtons, $view*/ 917759) {
1471
1557
  each_value = ensure_array_like(/*buttons*/ ctx[0]);
1472
1558
  let i;
1473
1559
 
@@ -1510,17 +1596,19 @@ function instance$3($$self, $$props, $$invalidate) {
1510
1596
  let $theme;
1511
1597
  let $_viewTitle;
1512
1598
  let $buttonText;
1599
+ let $customButtons;
1513
1600
  let $view;
1514
1601
  let { buttons } = $$props;
1515
- let { _currentRange, _viewTitle, buttonText, date, duration, hiddenDays, theme, view } = getContext('state');
1516
- component_subscribe($$self, _currentRange, value => $$invalidate(18, $_currentRange = value));
1602
+ let { _currentRange, _viewTitle, buttonText, customButtons, date, duration, hiddenDays, theme, view } = getContext('state');
1603
+ component_subscribe($$self, _currentRange, value => $$invalidate(20, $_currentRange = value));
1517
1604
  component_subscribe($$self, _viewTitle, value => $$invalidate(4, $_viewTitle = value));
1518
1605
  component_subscribe($$self, buttonText, value => $$invalidate(5, $buttonText = value));
1606
+ component_subscribe($$self, customButtons, value => $$invalidate(6, $customButtons = value));
1519
1607
  component_subscribe($$self, date, value => $$invalidate(2, $date = value));
1520
- component_subscribe($$self, duration, value => $$invalidate(21, $duration = value));
1521
- component_subscribe($$self, hiddenDays, value => $$invalidate(22, $hiddenDays = value));
1608
+ component_subscribe($$self, duration, value => $$invalidate(23, $duration = value));
1609
+ component_subscribe($$self, hiddenDays, value => $$invalidate(24, $hiddenDays = value));
1522
1610
  component_subscribe($$self, theme, value => $$invalidate(3, $theme = value));
1523
- component_subscribe($$self, view, value => $$invalidate(6, $view = value));
1611
+ component_subscribe($$self, view, value => $$invalidate(7, $view = value));
1524
1612
  let today = setMidnight(createDate()), isToday;
1525
1613
 
1526
1614
  function prev() {
@@ -1547,7 +1635,7 @@ function instance$3($$self, $$props, $$invalidate) {
1547
1635
  };
1548
1636
 
1549
1637
  $$self.$$.update = () => {
1550
- if ($$self.$$.dirty & /*$_currentRange*/ 262144) {
1638
+ if ($$self.$$.dirty & /*$_currentRange*/ 1048576) {
1551
1639
  $$invalidate(1, isToday = today >= $_currentRange.start && today < $_currentRange.end || null);
1552
1640
  }
1553
1641
  };
@@ -1559,10 +1647,12 @@ function instance$3($$self, $$props, $$invalidate) {
1559
1647
  $theme,
1560
1648
  $_viewTitle,
1561
1649
  $buttonText,
1650
+ $customButtons,
1562
1651
  $view,
1563
1652
  _currentRange,
1564
1653
  _viewTitle,
1565
1654
  buttonText,
1655
+ customButtons,
1566
1656
  date,
1567
1657
  duration,
1568
1658
  hiddenDays,
@@ -1584,7 +1674,7 @@ class Buttons extends SvelteComponent {
1584
1674
  }
1585
1675
  }
1586
1676
 
1587
- /* packages/core/src/Toolbar.svelte generated by Svelte v4.2.8 */
1677
+ /* packages/core/src/Toolbar.svelte generated by Svelte v4.2.16 */
1588
1678
 
1589
1679
  function get_each_context$1(ctx, list, i) {
1590
1680
  const child_ctx = ctx.slice();
@@ -1970,7 +2060,7 @@ class Toolbar extends SvelteComponent {
1970
2060
  }
1971
2061
  }
1972
2062
 
1973
- /* packages/core/src/Auxiliary.svelte generated by Svelte v4.2.8 */
2063
+ /* packages/core/src/Auxiliary.svelte generated by Svelte v4.2.16 */
1974
2064
 
1975
2065
  function get_each_context(ctx, list, i) {
1976
2066
  const child_ctx = ctx.slice();
@@ -2178,7 +2268,7 @@ class Auxiliary extends SvelteComponent {
2178
2268
  }
2179
2269
  }
2180
2270
 
2181
- /* packages/core/src/Calendar.svelte generated by Svelte v4.2.8 */
2271
+ /* packages/core/src/Calendar.svelte generated by Svelte v4.2.16 */
2182
2272
 
2183
2273
  function create_fragment(ctx) {
2184
2274
  let div;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@event-calendar/core",
3
- "version": "2.6.0",
3
+ "version": "2.7.0",
4
4
  "title": "Event Calendar Core package",
5
5
  "description": "Full-sized drag & drop event calendar with resource view",
6
6
  "keywords": [
@@ -27,6 +27,6 @@
27
27
  "./package.json": "./package.json"
28
28
  },
29
29
  "dependencies": {
30
- "svelte": "^4.2.8"
30
+ "svelte": "^4.2.16"
31
31
  }
32
32
  }
@@ -4,7 +4,7 @@
4
4
 
5
5
  export let buttons;
6
6
 
7
- let {_currentRange, _viewTitle, buttonText, date, duration, hiddenDays, theme, view} = getContext('state');
7
+ let {_currentRange, _viewTitle, buttonText, customButtons, date, duration, hiddenDays, theme, view} = getContext('state');
8
8
 
9
9
  let today = setMidnight(createDate()), isToday;
10
10
 
@@ -49,6 +49,11 @@
49
49
  on:click={() => $date = cloneDate(today)}
50
50
  disabled={isToday}
51
51
  >{$buttonText[button]}</button>
52
+ {:else if $customButtons[button]}
53
+ <button
54
+ class="{$theme.button} ec-{button}"
55
+ on:click={$customButtons[button].click}
56
+ >{$customButtons[button].text}</button>
52
57
  {:else if button != ''}
53
58
  <button
54
59
  class="{$theme.button}{$view === button ? ' ' + $theme.active : ''} ec-{button}"
package/src/lib/stores.js CHANGED
@@ -15,11 +15,49 @@ export function intl(locale, format) {
15
15
 
16
16
  export function intlRange(locale, format) {
17
17
  return derived([locale, format], ([$locale, $format]) => {
18
- let intl = is_function($format)
19
- ? {formatRange: $format}
20
- : new Intl.DateTimeFormat($locale, $format);
18
+ let formatRange;
19
+ if (is_function($format)) {
20
+ formatRange = $format;
21
+ } else {
22
+ let intl = new Intl.DateTimeFormat($locale, $format);
23
+ formatRange = (start, end) => {
24
+ if (start <= end) {
25
+ return intl.formatRange(start, end);
26
+ } else {
27
+ // In iOS 16 and older, intl.formatRange() throws an exception if the start date is later than the end date.
28
+ // Therefore, we first swap the parameters, and then swap the resulting parts.
29
+ /** @see https://github.com/vkurko/calendar/issues/227 */
30
+ let parts = intl.formatRangeToParts(end, start);
31
+ let result = '';
32
+ let sources = ['startRange', 'endRange'];
33
+ let processed = [false, false];
34
+ for (let part of parts) {
35
+ let i = sources.indexOf(part.source);
36
+ if (i >= 0) {
37
+ if (!processed[i]) {
38
+ result += _getParts(sources[1 - i], parts);
39
+ processed[i] = true;
40
+ }
41
+ } else {
42
+ result += part.value;
43
+ }
44
+ }
45
+ return result;
46
+ }
47
+ };
48
+ }
21
49
  return {
22
- formatRange: (start, end) => intl.formatRange(toLocalDate(start), toLocalDate(end))
50
+ formatRange: (start, end) => formatRange(toLocalDate(start), toLocalDate(end))
23
51
  };
24
52
  });
25
53
  }
54
+
55
+ function _getParts(source, parts) {
56
+ let result = '';
57
+ for (let part of parts) {
58
+ if (part.source == source) {
59
+ result += part.value;
60
+ }
61
+ }
62
+ return result;
63
+ }
@@ -7,6 +7,7 @@ export function createOptions(plugins) {
7
7
  buttonText: {
8
8
  today: 'today',
9
9
  },
10
+ customButtons: {},
10
11
  date: new Date(),
11
12
  datesSet: undefined,
12
13
  dayHeaderFormat: {