@event-calendar/core 5.0.5 → 5.1.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.
Files changed (79) hide show
  1. package/README.md +15 -4
  2. package/dist/index.css +2 -2
  3. package/dist/index.js +2201 -2128
  4. package/package.json +2 -2
  5. package/src/Buttons.svelte +36 -37
  6. package/src/Calendar.svelte +34 -37
  7. package/src/Toolbar.svelte +4 -4
  8. package/src/lib/components/BaseDay.svelte +13 -10
  9. package/src/lib/components/BaseEvent.svelte +17 -17
  10. package/src/lib/components/ColHead.svelte +6 -6
  11. package/src/lib/components/DayHeader.svelte +3 -3
  12. package/src/lib/components/InteractableEvent.svelte +7 -8
  13. package/src/lib/derived.js +80 -0
  14. package/src/lib/index.js +1 -2
  15. package/src/lib/slots.js +16 -16
  16. package/src/lib/utils.js +4 -9
  17. package/src/lib/view.js +0 -8
  18. package/src/plugins/day-grid/Day.svelte +25 -23
  19. package/src/plugins/day-grid/Event.svelte +15 -13
  20. package/src/plugins/day-grid/Popup.svelte +12 -12
  21. package/src/plugins/day-grid/View.svelte +24 -36
  22. package/src/plugins/day-grid/derived.js +102 -0
  23. package/src/plugins/day-grid/index.js +47 -36
  24. package/src/plugins/day-grid/state.svelte.js +19 -0
  25. package/src/plugins/interaction/Action.svelte +108 -76
  26. package/src/plugins/interaction/Auxiliary.svelte +9 -38
  27. package/src/plugins/interaction/Pointer.svelte +12 -17
  28. package/src/plugins/interaction/Resizer.svelte +9 -7
  29. package/src/plugins/interaction/effects.js +37 -0
  30. package/src/plugins/interaction/index.js +44 -38
  31. package/src/plugins/interaction/lib/utils.js +1 -1
  32. package/src/plugins/interaction/state.svelte.js +12 -0
  33. package/src/plugins/list/Day.svelte +8 -7
  34. package/src/plugins/list/Event.svelte +3 -3
  35. package/src/plugins/list/View.svelte +18 -13
  36. package/src/plugins/list/index.js +51 -43
  37. package/src/plugins/list/state.svelte.js +8 -0
  38. package/src/plugins/resource-time-grid/Label.svelte +8 -8
  39. package/src/plugins/resource-time-grid/View.svelte +38 -17
  40. package/src/plugins/resource-time-grid/derived.js +67 -0
  41. package/src/plugins/resource-time-grid/index.js +34 -28
  42. package/src/plugins/resource-time-grid/state.svelte.js +21 -0
  43. package/src/plugins/resource-timeline/Day.svelte +9 -4
  44. package/src/plugins/resource-timeline/Event.svelte +7 -6
  45. package/src/plugins/resource-timeline/Expander.svelte +7 -6
  46. package/src/plugins/resource-timeline/NowIndicator.svelte +10 -11
  47. package/src/plugins/resource-timeline/View.svelte +45 -63
  48. package/src/plugins/resource-timeline/derived.js +167 -0
  49. package/src/plugins/resource-timeline/index.js +17 -21
  50. package/src/plugins/resource-timeline/lib.js +4 -65
  51. package/src/plugins/resource-timeline/state.svelte.js +18 -0
  52. package/src/plugins/time-grid/Day.svelte +7 -2
  53. package/src/plugins/time-grid/Event.svelte +6 -6
  54. package/src/plugins/time-grid/NowIndicator.svelte +10 -9
  55. package/src/plugins/time-grid/View.svelte +46 -59
  56. package/src/plugins/time-grid/derived.js +162 -0
  57. package/src/plugins/time-grid/index.js +31 -25
  58. package/src/plugins/time-grid/lib.js +18 -74
  59. package/src/plugins/time-grid/options.js +21 -16
  60. package/src/plugins/time-grid/state.svelte.js +44 -0
  61. package/src/storage/derived.js +144 -0
  62. package/src/storage/effects.js +156 -0
  63. package/src/storage/options.svelte.js +275 -0
  64. package/src/storage/state.svelte.js +69 -0
  65. package/src/styles/events.css +1 -1
  66. package/src/Auxiliary.svelte +0 -47
  67. package/src/lib/debounce.js +0 -20
  68. package/src/lib/stores.js +0 -63
  69. package/src/plugins/day-grid/lib.js +0 -61
  70. package/src/plugins/day-grid/stores.js +0 -5
  71. package/src/plugins/resource-time-grid/lib.js +0 -31
  72. package/src/plugins/resource-time-grid/stores.js +0 -34
  73. package/src/plugins/resource-timeline/Header.svelte +0 -44
  74. package/src/plugins/resource-timeline/Label.svelte +0 -38
  75. package/src/plugins/resource-timeline/stores.js +0 -48
  76. package/src/plugins/time-grid/stores.js +0 -49
  77. package/src/storage/options.js +0 -136
  78. package/src/storage/state.js +0 -168
  79. package/src/storage/stores.js +0 -234
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@event-calendar/core",
3
- "version": "5.0.5",
3
+ "version": "5.1.0",
4
4
  "title": "Event Calendar Core package",
5
5
  "description": "Full-sized drag & drop event calendar with resource & timeline views",
6
6
  "keywords": [
@@ -32,6 +32,6 @@
32
32
  "#components": "./src/lib/components/index.js"
33
33
  },
34
34
  "dependencies": {
35
- "svelte": "^5.46.0"
35
+ "svelte": "^5.46.1"
36
36
  }
37
37
  }
@@ -4,10 +4,9 @@
4
4
 
5
5
  let {buttons} = $props();
6
6
 
7
- let {
8
- _currentRange, _today, _viewTitle, _viewDates, buttonText, customButtons, date, duration, hiddenDays, theme,
9
- validRange, view
10
- } = getContext('state');
7
+ let mainState = getContext('state');
8
+ let {currentRange, today, viewTitle, viewDates, options: {buttonText, customButtons, date, duration, hiddenDays,
9
+ theme, validRange, view}} = $derived(mainState);
11
10
 
12
11
  let prevDisabled = $state(false);
13
12
  let nextDisabled = $state(false);
@@ -15,28 +14,28 @@
15
14
 
16
15
  let running = false;
17
16
  $effect.pre(() => {
18
- $_viewDates;
19
- $validRange;
17
+ viewDates;
18
+ validRange;
20
19
  buttons;
21
20
  untrack(() => {
22
21
  if (!running) {
23
22
  running = true;
24
23
  if (buttons.includes('prev')) {
25
24
  prevDisabled = false;
26
- if ($validRange.start) {
25
+ if (validRange.start) {
27
26
  prevDisabled = test(prev);
28
27
  }
29
28
  }
30
29
  if (buttons.includes('next')) {
31
30
  nextDisabled = false;
32
- if ($validRange.end) {
31
+ if (validRange.end) {
33
32
  nextDisabled = test(next);
34
33
  }
35
34
  }
36
35
  if (buttons.includes('today')) {
37
- todayDisabled = $_today >= $_currentRange.start && $_today < $_currentRange.end;
38
- if (!todayDisabled && ($validRange.start || $validRange.end)) {
39
- todayDisabled = test(today);
36
+ todayDisabled = today >= currentRange.start && today < currentRange.end;
37
+ if (!todayDisabled && (validRange.start || validRange.end)) {
38
+ todayDisabled = test(setToday);
40
39
  }
41
40
  }
42
41
  tick().then(() => running = false);
@@ -45,63 +44,63 @@
45
44
  });
46
45
 
47
46
  function test(fn) {
48
- let currentDate = cloneDate($date);
47
+ let currentDate = date;
49
48
  fn();
50
- let result = $_viewDates.every(date => outsideRange(date, $validRange));
51
- $date = currentDate;
49
+ let result = viewDates.every(date => outsideRange(date, validRange));
50
+ mainState.setOption('date', currentDate);
52
51
  return result;
53
52
  }
54
53
 
55
54
  function prev() {
56
- $date = prevDate($date, $duration, $hiddenDays);
55
+ mainState.setOption('date', prevDate(cloneDate(date), duration, hiddenDays));
57
56
  }
58
57
 
59
58
  function next() {
60
- $date = nextDate($date, $duration);
59
+ mainState.setOption('date', nextDate(cloneDate(date), duration));
61
60
  }
62
61
 
63
- function today() {
64
- $date = cloneDate($_today);
62
+ function setToday() {
63
+ mainState.setOption('date', cloneDate(today));
65
64
  }
66
65
  </script>
67
66
 
68
67
  {#each buttons as button}
69
68
  {#if button === 'title'}
70
69
  <!-- svelte-ignore a11y_missing_content -->
71
- <h2 class="{$theme.title}" {@attach contentFrom($_viewTitle)}></h2>
70
+ <h2 class="{theme.title}" {@attach contentFrom(viewTitle)}></h2>
72
71
  {:else if button === 'prev'}
73
72
  <button
74
- class="{$theme.button} ec-{button}"
75
- aria-label={$buttonText.prev}
76
- title={$buttonText.prev}
73
+ class="{theme.button} ec-{button}"
74
+ aria-label={buttonText.prev}
75
+ title={buttonText.prev}
77
76
  onclick={prev}
78
77
  disabled={prevDisabled}
79
- ><i class="{$theme.icon} ec-{button}"></i></button>
78
+ ><i class="{theme.icon} ec-{button}"></i></button>
80
79
  {:else if button === 'next'}
81
80
  <button
82
- class="{$theme.button} ec-{button}"
83
- aria-label={$buttonText.next}
84
- title={$buttonText.next}
81
+ class="{theme.button} ec-{button}"
82
+ aria-label={buttonText.next}
83
+ title={buttonText.next}
85
84
  onclick={next}
86
85
  disabled={nextDisabled}
87
- ><i class="{$theme.icon} ec-{button}"></i></button>
86
+ ><i class="{theme.icon} ec-{button}"></i></button>
88
87
  {:else if button === 'today'}
89
88
  <button
90
- class="{$theme.button} ec-{button}"
91
- onclick={today}
89
+ class="{theme.button} ec-{button}"
90
+ onclick={setToday}
92
91
  disabled={todayDisabled}
93
- >{$buttonText[button]}</button>
94
- {:else if $customButtons[button]}
92
+ >{buttonText[button]}</button>
93
+ {:else if customButtons[button]}
95
94
  <!-- svelte-ignore a11y_consider_explicit_label -->
96
95
  <button
97
- class={[$theme.button, `ec-${button}`, $customButtons[button].active && $theme.active]}
98
- onclick={$customButtons[button].click}
99
- {@attach contentFrom($customButtons[button].text)}
96
+ class={[theme.button, `ec-${button}`, customButtons[button].active && theme.active]}
97
+ onclick={customButtons[button].click}
98
+ {@attach contentFrom(customButtons[button].text)}
100
99
  ></button>
101
100
  {:else if button !== ''}
102
101
  <button
103
- class={[$theme.button, `ec-${button}`, $view === button && $theme.active]}
104
- onclick={() => $view = button}
105
- >{$buttonText[button]}</button>
102
+ class={[theme.button, `ec-${button}`, view === button && theme.active]}
103
+ onclick={() => mainState.setOption('view', button)}
104
+ >{buttonText[button]}</button>
106
105
  {/if}
107
106
  {/each}
@@ -1,31 +1,29 @@
1
1
  <script>
2
2
  import './styles/index.css';
3
3
  import {setContext, untrack} from 'svelte';
4
- import {get} from 'svelte/store';
5
- import {diff} from './storage/options.js';
6
- import State from './storage/state.js';
7
- import Toolbar from './Toolbar.svelte';
8
- import Auxiliary from './Auxiliary.svelte';
9
4
  import {
10
- assign, createEvents, getElementWithPayload, getPayload, listView, nextDate,
5
+ assign, cloneDate, createEvents, getElementWithPayload, getPayload, nextDate,
11
6
  prevDate, toEventWithLocalDates, toLocalDate, toViewWithLocalDates
12
7
  } from '#lib';
8
+ import MainState from './storage/state.svelte.js';
9
+ import {diff} from './storage/options.svelte.js';
10
+ import Toolbar from './Toolbar.svelte';
13
11
 
14
12
  let {plugins = [], options = {}} = $props();
15
13
 
16
14
  // svelte-ignore state_referenced_locally
17
- let state = new State(plugins, options);
18
- setContext('state', state);
15
+ let mainState = new MainState(plugins, options);
16
+ setContext('state', mainState);
19
17
 
20
18
  let {
21
- _viewComponent, _interaction, _iClass, _events,
22
- date, duration, hiddenDays, height, theme, view
23
- } = state;
19
+ auxComponents, features, events, interaction, iClass, view, viewComponent: View,
20
+ options: {date, duration, height, hiddenDays, theme}
21
+ } = $derived(mainState);
24
22
 
25
23
  // Reactively update options that did change
26
24
  // svelte-ignore state_referenced_locally
27
25
  let prevOptions = {...options};
28
- $effect(() => {
26
+ $effect.pre(() => {
29
27
  for (let [name, value] of diff(options, prevOptions)) {
30
28
  untrack(() => {
31
29
  setOption(name, value);
@@ -35,27 +33,28 @@
35
33
  });
36
34
 
37
35
  export function setOption(name, value) {
38
- state._set(name, value);
36
+ mainState.setOption(name, value, false);
39
37
  return this;
40
38
  }
41
39
 
42
40
  export function getOption(name) {
43
- let value = state._get(name);
41
+ let value = mainState.options[name];
44
42
  return value instanceof Date ? toLocalDate(value) : value;
45
43
  }
46
44
 
47
45
  export function refetchEvents() {
48
- state._fetchedRange.set({start: undefined, end: undefined});
46
+ mainState.fetchedRange = {start: undefined, end: undefined};
49
47
  return this;
50
48
  }
51
49
 
52
50
  export function getEvents() {
53
- return $_events.map(toEventWithLocalDates);
51
+ return events.map(toEventWithLocalDates);
54
52
  }
55
53
 
56
54
  export function getEventById(id) {
57
- for (let event of $_events) {
58
- if (event.id == id) {
55
+ id = String(id);
56
+ for (let event of events) {
57
+ if (event.id === id) {
59
58
  return toEventWithLocalDates(event);
60
59
  }
61
60
  }
@@ -64,17 +63,16 @@
64
63
 
65
64
  export function addEvent(event) {
66
65
  event = createEvents([event])[0];
67
- $_events.push(event);
68
- $_events = $_events;
66
+ events.push(event);
69
67
  return toEventWithLocalDates(event);
70
68
  }
71
69
 
72
70
  export function updateEvent(event) {
73
71
  let id = String(event.id);
74
- let idx = $_events.findIndex(event => event.id === id);
72
+ let idx = events.findIndex(event => event.id === id);
75
73
  if (idx >= 0) {
76
74
  event = createEvents([event])[0];
77
- $_events[idx] = event;
75
+ events[idx] = event;
78
76
  return toEventWithLocalDates(event);
79
77
  }
80
78
  return null;
@@ -82,20 +80,19 @@
82
80
 
83
81
  export function removeEventById(id) {
84
82
  id = String(id);
85
- let idx = $_events.findIndex(event => event.id === id);
83
+ let idx = events.findIndex(event => event.id === id);
86
84
  if (idx >= 0) {
87
- $_events.splice(idx, 1);
88
- $_events = $_events;
85
+ events.splice(idx, 1);
89
86
  }
90
87
  return this;
91
88
  }
92
89
 
93
90
  export function getView() {
94
- return toViewWithLocalDates(get(state._view));
91
+ return toViewWithLocalDates(view);
95
92
  }
96
93
 
97
94
  export function unselect() {
98
- $_interaction.action?.unselect();
95
+ interaction.action?.unselect();
99
96
  return this;
100
97
  }
101
98
 
@@ -111,28 +108,28 @@
111
108
  }
112
109
 
113
110
  export function next() {
114
- $date = nextDate($date, $duration);
111
+ mainState.setOption('date', nextDate(cloneDate(date), duration));
115
112
  return this;
116
113
  }
117
114
 
118
115
  export function prev() {
119
- $date = prevDate($date, $duration, $hiddenDays);
116
+ mainState.setOption('date', prevDate(cloneDate(date), duration, hiddenDays));
120
117
  return this;
121
118
  }
122
-
123
- let View = $derived($_viewComponent);
124
119
  </script>
125
120
 
126
121
  <div
127
122
  class={[
128
- $theme.calendar,
129
- $theme.view,
130
- $_iClass && $theme[$_iClass]
123
+ theme.calendar,
124
+ theme.view,
125
+ iClass && theme[iClass]
131
126
  ]}
132
- style:height={$height}
133
- role="{listView($view) ? 'list' : 'table'}"
127
+ style:height
128
+ role="{features.includes('list') ? 'list' : 'table'}"
134
129
  >
135
130
  <Toolbar/>
136
131
  <View/>
132
+ {#each auxComponents as AuxComponent}
133
+ <AuxComponent/>
134
+ {/each}
137
135
  </div>
138
- <Auxiliary/>
@@ -3,23 +3,23 @@
3
3
  import {keys} from '#lib';
4
4
  import Buttons from './Buttons.svelte';
5
5
 
6
- let {headerToolbar, theme} = getContext('state');
6
+ let {options: {headerToolbar, theme}} = $derived(getContext('state'));
7
7
 
8
8
  let sections = $derived.by(() => {
9
9
  let sections = {};
10
10
  for (let key of ['start', 'center', 'end']) {
11
- sections[key] = $headerToolbar[key]?.split(' ').map(group => group.split(',')) ?? [];
11
+ sections[key] = headerToolbar[key]?.split(' ').map(group => group.split(',')) ?? [];
12
12
  }
13
13
  return sections;
14
14
  });
15
15
  </script>
16
16
 
17
- <nav class="{$theme.toolbar}">
17
+ <nav class="{theme.toolbar}">
18
18
  {#each keys(sections) as key}
19
19
  <div class="ec-{key}">
20
20
  {#each sections[key] as buttons}
21
21
  {#if buttons.length > 1}
22
- <div class="{$theme.buttonGroup}">
22
+ <div class="{theme.buttonGroup}">
23
23
  <Buttons {buttons}/>
24
24
  </div>
25
25
  {:else}
@@ -17,19 +17,20 @@
17
17
  children
18
18
  } = $props();
19
19
 
20
- let {_interaction, _today, theme} = getContext('state');
20
+ let {today, interaction: {action}, options: {theme}} = $derived(getContext('state'));
21
+ let {snap} = $derived(getContext('view-state')); // timeGrid has snap, others don't
21
22
 
22
- let isToday = $derived(datesEqual(date, $_today));
23
+ let isToday = $derived(datesEqual(date, today));
23
24
 
24
25
  // Class
25
26
  let classNames = $derived(classes([
26
- $theme.day,
27
- $theme.weekdays?.[date.getUTCDay()],
28
- isToday && $theme.today,
29
- highlight && $theme.highlight,
30
- disabled && $theme.disabled,
31
- noIeb && $theme.noIeb,
32
- noBeb && $theme.noBeb
27
+ theme.day,
28
+ theme.weekdays?.[date.getUTCDay()],
29
+ isToday && theme.today,
30
+ highlight && theme.highlight,
31
+ disabled && theme.disabled,
32
+ noIeb && theme.noIeb,
33
+ noBeb && theme.noBeb
33
34
  ]));
34
35
 
35
36
  // dateFromPoint
@@ -44,11 +45,13 @@
44
45
  };
45
46
  });
46
47
  });
48
+
49
+ let onpointerdown = $derived(!disabled && action ? jsEvent => action.select(jsEvent, snap) : undefined);
47
50
  </script>
48
51
 
49
52
  <div
50
53
  bind:this={el}
51
54
  class={classNames}
52
55
  {role}
53
- onpointerdown={!disabled ? $_interaction.action?.select : undefined}
56
+ {onpointerdown}
54
57
  >{@render children?.()}</div>
@@ -14,54 +14,54 @@
14
14
  body
15
15
  } = $props();
16
16
 
17
- let {
17
+ let {intlEventTime, view, options: {
18
18
  displayEventEnd, eventBackgroundColor, eventColor, eventContent, eventClick, eventDidMount, eventClassNames,
19
- eventMouseEnter, eventMouseLeave, eventTextColor, resources, theme, _view, _intlEventTime
20
- } = getContext('state');
19
+ eventMouseEnter, eventMouseLeave, eventTextColor, resources, theme
20
+ }} = $derived(getContext('state'));
21
21
 
22
22
  let event = $derived(chunk.event);
23
23
  let display = $derived(chunk.event.display);
24
24
 
25
25
  // Style
26
- let bgColor = $derived(event.backgroundColor ?? resourceBackgroundColor(event, $resources) ?? $eventBackgroundColor ?? $eventColor);
27
- let txtColor = $derived(event.textColor ?? resourceTextColor(event, $resources) ?? $eventTextColor);
26
+ let bgColor = $derived(event.backgroundColor ?? resourceBackgroundColor(event, resources) ?? eventBackgroundColor ?? eventColor);
27
+ let txtColor = $derived(event.textColor ?? resourceTextColor(event, resources) ?? eventTextColor);
28
28
  let style = $derived(entries(styles(
29
29
  {'background-color': bgColor, 'color': txtColor}
30
30
  )).map(entry => `${entry[0]}:${entry[1]}`).concat(event.styles).join(';'));
31
31
 
32
32
  // Class
33
33
  let classNames = $derived(classes([
34
- bgEvent(display) ? $theme.bgEvent : $theme.event,
35
- ...createEventClasses($eventClassNames, event, $_view)
34
+ bgEvent(display) ? theme.bgEvent : theme.event,
35
+ ...createEventClasses(eventClassNames, event, view)
36
36
  ]));
37
37
 
38
38
  // Content
39
39
  let [timeText, content] = $derived(createEventContent(
40
- chunk, $displayEventEnd, $eventContent, $theme, $_intlEventTime, $_view
40
+ chunk, displayEventEnd, eventContent, theme, intlEventTime, view
41
41
  ));
42
42
 
43
43
  onMount(() => {
44
- if (isFunction($eventDidMount)) {
45
- $eventDidMount({
44
+ if (isFunction(eventDidMount)) {
45
+ eventDidMount({
46
46
  event: toEventWithLocalDates(event),
47
47
  timeText,
48
48
  el,
49
- view: toViewWithLocalDates($_view)
49
+ view: toViewWithLocalDates(view)
50
50
  });
51
51
  }
52
52
  });
53
53
 
54
54
  function createHandler(fn, display) {
55
- return !helperEvent(display) && isFunction(fn)
56
- ? jsEvent => fn({event: toEventWithLocalDates(event), el, jsEvent, view: toViewWithLocalDates($_view)})
55
+ return isFunction(fn) && !helperEvent(display)
56
+ ? jsEvent => fn({event: toEventWithLocalDates(event), el, jsEvent, view: toViewWithLocalDates(view)})
57
57
  : undefined;
58
58
  }
59
59
 
60
60
  // Handlers
61
- let onclick = $derived(!bgEvent(display) && createHandler($eventClick, display) || undefined);
61
+ let onclick = $derived(!bgEvent(display) && createHandler(eventClick, display) || undefined);
62
62
  let onkeydown = $derived(onclick && keyEnter(onclick));
63
- let onmouseenter = $derived(createHandler($eventMouseEnter, display));
64
- let onmouseleave = $derived(createHandler($eventMouseLeave, display));
63
+ let onmouseenter = $derived(createHandler(eventMouseEnter, display));
64
+ let onmouseleave = $derived(createHandler(eventMouseLeave, display));
65
65
  </script>
66
66
 
67
67
  <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
@@ -78,7 +78,7 @@
78
78
  {onpointerdown}
79
79
  >
80
80
  {#snippet defaultBody()}
81
- <div class={$theme.eventBody} {@attach contentFrom(content)}></div>
81
+ <div class={theme.eventBody} {@attach contentFrom(content)}></div>
82
82
  {/snippet}
83
83
  {#if body}
84
84
  {@render body(defaultBody, bgColor, txtColor)}
@@ -14,16 +14,16 @@
14
14
  children
15
15
  } = $props();
16
16
 
17
- let {_today, theme} = getContext('state');
17
+ let {today, options: {theme}} = $derived(getContext('state'));
18
18
  </script>
19
19
 
20
20
  <div
21
21
  class={[
22
- className ?? $theme.colHead,
23
- weekday && $theme.weekdays?.[date.getUTCDay()],
24
- weekday && datesEqual(date, $_today) && $theme.today,
25
- highlight && $theme.highlight,
26
- disabled && $theme.disabled
22
+ className ?? theme.colHead,
23
+ weekday && theme.weekdays?.[date.getUTCDay()],
24
+ weekday && datesEqual(date, today) && theme.today,
25
+ highlight && theme.highlight,
26
+ disabled && theme.disabled
27
27
  ]}
28
28
  role="{ariaHidden ? null : 'columnheader'}"
29
29
  aria-colspan="{ariaHidden || colSpan <= 1 ? null : colSpan}"
@@ -4,11 +4,11 @@
4
4
 
5
5
  let {date, alPrefix = ''} = $props();
6
6
 
7
- let {_intlDayHeader, _intlDayHeaderAL} = getContext('state');
7
+ let {intlDayHeader, intlDayHeaderAL} = $derived(getContext('state'));
8
8
  </script>
9
9
 
10
10
  <time
11
11
  datetime="{toISOString(date, 10)}"
12
- aria-label="{alPrefix}{$_intlDayHeaderAL.format(date)}"
13
- {@attach contentFrom($_intlDayHeader.format(date))}
12
+ aria-label="{alPrefix}{intlDayHeaderAL.format(date)}"
13
+ {@attach contentFrom(intlDayHeader.format(date))}
14
14
  ></time>
@@ -1,7 +1,7 @@
1
1
  <script>
2
2
  import {getContext} from 'svelte';
3
3
  import BaseEvent from './BaseEvent.svelte';
4
- import {bgEvent, helperEvent} from "#lib";
4
+ import {bgEvent, helperEvent} from '#lib';
5
5
 
6
6
  let {
7
7
  el = $bindable(),
@@ -12,22 +12,21 @@
12
12
  forceMargin
13
13
  } = $props();
14
14
 
15
- let {_interaction, _iClasses} = getContext('state');
15
+ let {iClasses, interaction: {action, resizer: Resizer}} = $derived(getContext('state'));
16
+ let {snap} = $derived(getContext('view-state')); // timeGrid has snap, others don't
16
17
 
17
18
  let event = $derived(chunk.event);
18
19
  let display = $derived(chunk.event.display);
19
20
 
20
21
  // Class
21
- let classes = $derived(classNames => $_iClasses(classNames, event));
22
+ let classes = $derived(classNames => iClasses(classNames, event));
22
23
 
23
24
  function createDragHandler(event) {
24
- return $_interaction.action?.draggable(event)
25
- ? jsEvent => $_interaction.action.drag(event, jsEvent, forceDate, forceMargin)
26
- : $_interaction.action?.noAction;
25
+ return action?.draggable(event)
26
+ ? jsEvent => action.drag(event, jsEvent, forceDate, forceMargin, snap)
27
+ : action?.noAction;
27
28
  }
28
29
  let onpointerdown = $derived(!bgEvent(display) && !helperEvent(display) ? createDragHandler(event) : undefined);
29
-
30
- let Resizer = $derived($_interaction.resizer);
31
30
  </script>
32
31
 
33
32
  <BaseEvent bind:el {chunk} {classes} {styles} {onpointerdown}>
@@ -0,0 +1,80 @@
1
+ import {untrack} from 'svelte';
2
+ import {isFunction} from './utils.js';
3
+ import {toLocalDate} from './date.js';
4
+
5
+ export function intl(mainState, option) {
6
+ return () => {
7
+ // Dependencies
8
+ let {options: {locale}} = mainState;
9
+ let format = mainState.options[option];
10
+
11
+ let intl;
12
+
13
+ untrack(() => {
14
+ intl = isFunction(format)
15
+ ? {format}
16
+ : new Intl.DateTimeFormat(locale, format);
17
+ });
18
+
19
+ return {
20
+ format: date => intl.format(toLocalDate(date))
21
+ };
22
+ };
23
+ }
24
+
25
+ export function intlRange(mainState, option) {
26
+ return () => {
27
+ // Dependencies
28
+ let {options: {locale}} = mainState;
29
+ let format = mainState.options[option];
30
+
31
+ let formatRange;
32
+
33
+ untrack(() => {
34
+ if (isFunction(format)) {
35
+ formatRange = format;
36
+ } else {
37
+ let intl = new Intl.DateTimeFormat(locale, format);
38
+ formatRange = (start, end) => {
39
+ if (start <= end) {
40
+ return intl.formatRange(start, end);
41
+ } else {
42
+ // In iOS 16 and older, intl.formatRange() throws an exception if the start date is later than the end date.
43
+ // Therefore, we first swap the parameters, and then swap the resulting parts.
44
+ /** @see https://github.com/vkurko/calendar/issues/227 */
45
+ let parts = intl.formatRangeToParts(end, start);
46
+ let result = '';
47
+ let sources = ['startRange', 'endRange'];
48
+ let processed = [false, false];
49
+ for (let part of parts) {
50
+ let i = sources.indexOf(part.source);
51
+ if (i >= 0) {
52
+ if (!processed[i]) {
53
+ result += _getParts(sources[1 - i], parts);
54
+ processed[i] = true;
55
+ }
56
+ } else {
57
+ result += part.value;
58
+ }
59
+ }
60
+ return result;
61
+ }
62
+ };
63
+ }
64
+ });
65
+
66
+ return {
67
+ formatRange: (start, end) => formatRange(toLocalDate(start), toLocalDate(end))
68
+ };
69
+ };
70
+ }
71
+
72
+ function _getParts(source, parts) {
73
+ let result = '';
74
+ for (let part of parts) {
75
+ if (part.source == source) {
76
+ result += part.value;
77
+ }
78
+ }
79
+ return result;
80
+ }
package/src/lib/index.js CHANGED
@@ -2,7 +2,7 @@ export * from './a11y.js';
2
2
  export * from './attachments.js';
3
3
  export * from './chunks.js';
4
4
  export * from './date.js';
5
- export * from './debounce.js';
5
+ export * from './derived.js';
6
6
  export * from './dom.js';
7
7
  export * from './events.js';
8
8
  export * from './options.js';
@@ -10,6 +10,5 @@ export * from './payload.js';
10
10
  export * from './range.js';
11
11
  export * from './resources.js';
12
12
  export * from './slots.js';
13
- export * from './stores.js';
14
13
  export * from './utils.js';
15
14
  export * from './view.js';