@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
@@ -5,32 +5,34 @@
5
5
 
6
6
  let {chunk, axis, forceDate = undefined, forceMargin = undefined, children} = $props();
7
7
 
8
- let {theme, eventDurationEditable, eventResizableFromStart, editable, _interaction} = getContext('state');
8
+ let {interaction: {action}, options: {editable, eventDurationEditable, eventResizableFromStart, theme}} = $derived(getContext('state'));
9
+ let {snap} = $derived(getContext('view-state')); // timeGrid has snap, others don't
9
10
 
10
11
  let event = $derived(chunk.event);
11
12
  let display = $derived(chunk.event.display);
12
13
 
13
14
  let resizable = $derived(
14
- !bgEvent(display) && !helperEvent(display) && eventResizable(event, $eventDurationEditable, $editable)
15
+ !bgEvent(display) && !helperEvent(display) && eventResizable(event, eventDurationEditable, editable)
15
16
  );
16
17
 
17
18
  function createResizeHandler(start) {
18
- return jsEvent => $_interaction.action.resize(
19
+ return jsEvent => action.resize(
19
20
  event,
20
21
  jsEvent,
21
22
  start,
22
23
  axis,
23
24
  forceDate,
24
25
  forceMargin,
25
- chunk.zeroDuration
26
+ chunk.zeroDuration,
27
+ snap
26
28
  );
27
29
  }
28
30
  </script>
29
31
 
30
- {#if resizable && $eventResizableFromStart}
31
- <div class="{$theme.resizer} {$theme.start}" onpointerdown={createResizeHandler(true)}></div>
32
+ {#if resizable && eventResizableFromStart}
33
+ <div class="{theme.resizer} {theme.start}" onpointerdown={createResizeHandler(true)}></div>
32
34
  {/if}
33
35
  {@render children()}
34
36
  {#if resizable}
35
- <div class="{$theme.resizer}" onpointerdown={createResizeHandler(false)}></div>
37
+ <div class="{theme.resizer}" onpointerdown={createResizeHandler(false)}></div>
36
38
  {/if}
@@ -0,0 +1,37 @@
1
+ import {bgEvent, helperEvent, listen} from '#lib';
2
+ import {eventDraggable} from './lib';
3
+
4
+ export function setIClasses(mainState) {
5
+ return () => {
6
+ // Dependencies
7
+ let {options: {editable, eventStartEditable, theme}} = mainState;
8
+
9
+ mainState.iClasses = (classNames, event) => {
10
+ let {display} = event;
11
+ return [
12
+ ...classNames,
13
+ helperEvent(display)
14
+ ? [theme[display]]
15
+ : (
16
+ !bgEvent(display) && eventDraggable(event, eventStartEditable, editable)
17
+ ? [theme.draggable]
18
+ : []
19
+ )
20
+ ];
21
+ };
22
+ };
23
+ }
24
+
25
+ export function handleScroll(mainState) {
26
+ return () => {
27
+ // Dependencies
28
+ let {interaction, mainEl} = mainState;
29
+
30
+ if (mainEl) {
31
+ return listen(mainEl, 'scroll', () => {
32
+ interaction.action.handleScroll();
33
+ interaction.pointer?.handleScroll();
34
+ });
35
+ }
36
+ };
37
+ }
@@ -1,46 +1,52 @@
1
+ import {assign} from '#lib';
1
2
  import Auxiliary from './Auxiliary.svelte';
2
3
 
3
4
  export default {
4
5
  createOptions(options) {
5
- options.dateClick = undefined;
6
- options.dragConstraint = undefined;
7
- options.dragScroll = true;
8
- options.editable = false;
9
- options.eventDragMinDistance = 5;
10
- options.eventDragStart = undefined;
11
- options.eventDragStop = undefined;
12
- options.eventDrop = undefined;
13
- options.eventDurationEditable = true;
14
- options.eventLongPressDelay = undefined;
15
- options.eventResizableFromStart = false;
16
- options.eventResizeStart = undefined;
17
- options.eventResizeStop = undefined;
18
- options.eventResize = undefined;
19
- options.eventStartEditable = true;
20
- options.longPressDelay = 1000;
21
- options.pointer = false;
22
- options.resizeConstraint = undefined;
23
- options.select = undefined;
24
- options.selectBackgroundColor = undefined; // ec option
25
- options.selectConstraint = undefined;
26
- options.selectLongPressDelay = undefined;
27
- options.selectMinDistance = 5;
28
- options.unselect = undefined;
29
- options.unselectAuto = true;
30
- options.unselectCancel = '';
31
- options.theme.draggable = 'ec-draggable';
32
- options.theme.ghost = 'ec-ghost';
33
- options.theme.preview = 'ec-preview';
34
- options.theme.pointer = 'ec-pointer';
35
- options.theme.resizer = 'ec-resizer';
36
- options.theme.start = 'ec-start';
37
- options.theme.dragging = 'ec-dragging';
38
- options.theme.resizingY = 'ec-resizing-y';
39
- options.theme.resizingX = 'ec-resizing-x';
40
- options.theme.selecting = 'ec-selecting';
6
+ assign(options, {
7
+ dateClick: undefined,
8
+ dragConstraint: undefined,
9
+ dragScroll: true,
10
+ editable: false,
11
+ eventDragMinDistance: 5,
12
+ eventDragStart: undefined,
13
+ eventDragStop: undefined,
14
+ eventDrop: undefined,
15
+ eventDurationEditable: true,
16
+ eventLongPressDelay: undefined,
17
+ eventResizableFromStart: false,
18
+ eventResizeStart: undefined,
19
+ eventResizeStop: undefined,
20
+ eventResize: undefined,
21
+ eventStartEditable: true,
22
+ longPressDelay: 1000,
23
+ pointer: false,
24
+ resizeConstraint: undefined,
25
+ select: undefined,
26
+ selectBackgroundColor: undefined, // ec option
27
+ selectConstraint: undefined,
28
+ selectLongPressDelay: undefined,
29
+ selectMinDistance: 5,
30
+ snapDuration: undefined,
31
+ unselect: undefined,
32
+ unselectAuto: true,
33
+ unselectCancel: ''
34
+ });
35
+ assign(options.theme, {
36
+ draggable: 'ec-draggable',
37
+ ghost: 'ec-ghost',
38
+ preview: 'ec-preview',
39
+ pointer: 'ec-pointer',
40
+ resizer: 'ec-resizer',
41
+ start: 'ec-start',
42
+ dragging: 'ec-dragging',
43
+ resizingY: 'ec-resizing-y',
44
+ resizingX: 'ec-resizing-x',
45
+ selecting: 'ec-selecting'
46
+ });
41
47
  },
42
48
 
43
- createStores(state) {
44
- state._auxiliary.update($_auxiliary => [...$_auxiliary, Auxiliary]);
49
+ initState(mainState) {
50
+ mainState.auxComponents.push(Auxiliary);
45
51
  }
46
52
  }
@@ -13,4 +13,4 @@ export function animate(fn) {
13
13
 
14
14
  export function limit(value, minLimit, maxLimit) {
15
15
  return max(minLimit, min(maxLimit, value));
16
- }
16
+ }
@@ -0,0 +1,12 @@
1
+ import {handleScroll, setIClasses} from './effects.js';
2
+
3
+ export default class AuxState {
4
+ constructor(mainState) {
5
+ this.#setupEffects(mainState);
6
+ }
7
+
8
+ #setupEffects(mainState) {
9
+ $effect.pre(setIClasses(mainState));
10
+ $effect(handleScroll(mainState));
11
+ }
12
+ }
@@ -8,10 +8,11 @@
8
8
 
9
9
  let {date} = $props();
10
10
 
11
- let {_filteredEvents, _intlListDay, _intlListDaySide, highlightedDates, theme, validRange} = getContext('state');
11
+ let {filteredEvents, options: {highlightedDates, theme, validRange}} = $derived(getContext('state'));
12
+ let {intlListDay, intlListDaySide} = $derived(getContext('view-state'));
12
13
 
13
- let highlight = $derived($highlightedDates.some(d => datesEqual(d, date)));
14
- let disabled = $derived(outsideRange(date, $validRange));
14
+ let highlight = $derived(highlightedDates.some(d => datesEqual(d, date)));
15
+ let disabled = $derived(outsideRange(date, validRange));
15
16
  let datetime = $derived(toISOString(date, 10));
16
17
 
17
18
  let chunks = $derived.by(() => {
@@ -19,7 +20,7 @@
19
20
  if (!disabled) {
20
21
  let start = date;
21
22
  let end = addDay(cloneDate(date));
22
- for (let event of $_filteredEvents) {
23
+ for (let event of filteredEvents) {
23
24
  if (!bgEvent(event.display) && eventIntersects(event, start, end)) {
24
25
  let chunk = createEventChunk(event, start, end);
25
26
  chunks.push(chunk);
@@ -33,9 +34,9 @@
33
34
  {#if chunks.length}
34
35
  <BaseDay {date} allDay role="listitem" {disabled} {highlight}>
35
36
  <!-- svelte-ignore a11y_missing_content -->
36
- <h4 class="{$theme.dayHead}">
37
- <time {datetime} {@attach contentFrom($_intlListDay.format(date))}></time>
38
- <time class="{$theme.daySide}" {datetime} {@attach contentFrom($_intlListDaySide.format(date))}></time>
37
+ <h4 class="{theme.dayHead}">
38
+ <time {datetime} {@attach contentFrom(intlListDay.format(date))}></time>
39
+ <time class="{theme.daySide}" {datetime} {@attach contentFrom(intlListDaySide.format(date))}></time>
39
40
  </h4>
40
41
  {#each chunks as chunk (chunk.event)}
41
42
  <Event {chunk}/>
@@ -4,7 +4,7 @@
4
4
 
5
5
  let {chunk} = $props();
6
6
 
7
- let {theme, _interaction} = getContext('state');
7
+ let {interaction, options: {theme}} = $derived(getContext('state'));
8
8
 
9
9
  // Style
10
10
  let styles = $derived(style => {
@@ -14,9 +14,9 @@
14
14
  });
15
15
  </script>
16
16
 
17
- <BaseEvent {chunk} {styles} onpointerdown={$_interaction.action?.noAction}>
17
+ <BaseEvent {chunk} {styles} onpointerdown={interaction.action?.noAction}>
18
18
  {#snippet body(defaultBody, bgColor, txtColor)}
19
- <div class="{$theme.eventTag}" style:background-color={bgColor}></div>
19
+ <div class="{theme.eventTag}" style:background-color={bgColor}></div>
20
20
  {@render defaultBody()}
21
21
  {/snippet}
22
22
  </BaseEvent>
@@ -1,16 +1,21 @@
1
1
  <script>
2
- import {getContext} from 'svelte';
3
- import {addDay, cloneDate, toViewWithLocalDates, contentFrom, bgEvent, isFunction} from '#lib';
2
+ import {getContext, setContext} from 'svelte';
3
+ import {addDay, cloneDate, contentFrom, bgEvent, isFunction, toViewWithLocalDates} from '#lib';
4
+ import ViewState from './state.svelte.js';
4
5
  import Day from './Day.svelte';
5
6
 
6
- let {_mainEl, _filteredEvents, _view, _viewDates, noEventsClick, noEventsContent, theme} = getContext('state');
7
+ let mainState = getContext('state');
8
+ let viewState = new ViewState(mainState);
9
+ setContext('view-state', viewState);
10
+
11
+ let {filteredEvents, view, viewDates, options: {noEventsClick, noEventsContent, theme}} = $derived(mainState);
7
12
 
8
13
  let noEvents = $derived.by(() => {
9
14
  let noEvents = true;
10
- if ($_viewDates.length) {
11
- let start = $_viewDates[0];
12
- let end = addDay(cloneDate($_viewDates.at(-1)));
13
- for (let event of $_filteredEvents) {
15
+ if (viewDates.length) {
16
+ let start = viewDates[0];
17
+ let end = addDay(cloneDate(viewDates.at(-1)));
18
+ for (let event of filteredEvents) {
14
19
  if (!bgEvent(event.display) && event.start < end && event.end > start) {
15
20
  noEvents = false;
16
21
  break;
@@ -20,22 +25,22 @@
20
25
  return noEvents;
21
26
  });
22
27
 
23
- let content = $derived(isFunction($noEventsContent) ? $noEventsContent() : $noEventsContent);
28
+ let content = $derived(isFunction(noEventsContent) ? noEventsContent() : noEventsContent);
24
29
 
25
30
  function onclick(jsEvent) {
26
- if (isFunction($noEventsClick)) {
27
- $noEventsClick({jsEvent, view: toViewWithLocalDates($_view)});
31
+ if (isFunction(noEventsClick)) {
32
+ noEventsClick({jsEvent, view: toViewWithLocalDates(view)});
28
33
  }
29
34
  }
30
35
  </script>
31
36
 
32
- <section bind:this={$_mainEl} class="{$theme.main}">
37
+ <section bind:this={mainState.mainEl} class="{theme.main}">
33
38
  {#if noEvents}
34
39
  <!-- svelte-ignore a11y_click_events_have_key_events -->
35
40
  <!-- svelte-ignore a11y_no_static_element_interactions -->
36
- <div {@attach contentFrom(content)} class="{$theme.noEvents}" {onclick}></div>
41
+ <div {@attach contentFrom(content)} class="{theme.noEvents}" {onclick}></div>
37
42
  {:else}
38
- {#each $_viewDates as date}
43
+ {#each viewDates as date}
39
44
  <Day {date}/>
40
45
  {/each}
41
46
  {/if}
@@ -1,49 +1,57 @@
1
- import {btnTextDay, btnTextWeek, btnTextMonth, btnTextYear, intl, themeView} from '#lib';
1
+ import {btnTextDay, btnTextWeek, btnTextMonth, btnTextYear, themeView, assign} from '#lib';
2
2
  import View from './View.svelte';
3
3
 
4
4
  export default {
5
5
  createOptions(options) {
6
- // Common options
7
- options.buttonText.listDay = 'list';
8
- options.buttonText.listWeek = 'list';
9
- options.buttonText.listMonth = 'list';
10
- options.buttonText.listYear = 'list';
11
- options.listDayFormat = {weekday: 'long'};
12
- options.listDaySideFormat = {year: 'numeric', month: 'long', day: 'numeric'};
13
- options.noEventsClick = undefined; // ec option
14
- options.noEventsContent = 'No events';
15
- options.theme.daySide = 'ec-day-side';
16
- options.theme.eventTag = 'ec-event-tag';
17
- options.theme.noEvents = 'ec-no-events';
18
- options.view = 'listWeek';
19
- options.views.listDay = {
20
- buttonText: btnTextDay,
21
- component: View,
22
- duration: {days: 1},
23
- theme: themeView('ec-list ec-day-view')
24
- };
25
- options.views.listWeek = {
26
- buttonText: btnTextWeek,
27
- component: View,
28
- duration: {weeks: 1},
29
- theme: themeView('ec-list ec-week-view')
30
- };
31
- options.views.listMonth = {
32
- buttonText: btnTextMonth,
33
- component: View,
34
- duration: {months: 1},
35
- theme: themeView('ec-list ec-month-view')
36
- };
37
- options.views.listYear = {
38
- buttonText: btnTextYear,
39
- component: View,
40
- duration: {years: 1},
41
- theme: themeView('ec-list ec-year-view')
42
- };
43
- },
44
-
45
- createStores(state) {
46
- state._intlListDay = intl(state.locale, state.listDayFormat);
47
- state._intlListDaySide = intl(state.locale, state.listDaySideFormat);
6
+ assign(options, {
7
+ listDayFormat: {weekday: 'long'},
8
+ listDaySideFormat: {year: 'numeric', month: 'long', day: 'numeric'},
9
+ noEventsClick: undefined, // ec option
10
+ noEventsContent: 'No events',
11
+ // Common options
12
+ view: 'listWeek'
13
+ });
14
+ assign(options.buttonText, {
15
+ listDay: 'list',
16
+ listWeek: 'list',
17
+ listMonth: 'list',
18
+ listYear: 'list'
19
+ });
20
+ assign(options.theme, {
21
+ daySide: 'ec-day-side',
22
+ eventTag: 'ec-event-tag',
23
+ noEvents: 'ec-no-events'
24
+ });
25
+ assign(options.views, {
26
+ listDay: {
27
+ buttonText: btnTextDay,
28
+ component: initViewComponent,
29
+ duration: {days: 1},
30
+ theme: themeView('ec-list ec-day-view')
31
+ },
32
+ listWeek: {
33
+ buttonText: btnTextWeek,
34
+ component: initViewComponent,
35
+ duration: {weeks: 1},
36
+ theme: themeView('ec-list ec-week-view')
37
+ },
38
+ listMonth: {
39
+ buttonText: btnTextMonth,
40
+ component: initViewComponent,
41
+ duration: {months: 1},
42
+ theme: themeView('ec-list ec-month-view')
43
+ },
44
+ listYear: {
45
+ buttonText: btnTextYear,
46
+ component: initViewComponent,
47
+ duration: {years: 1},
48
+ theme: themeView('ec-list ec-year-view')
49
+ }
50
+ });
48
51
  }
49
52
  }
53
+
54
+ function initViewComponent(mainState) {
55
+ mainState.features = ['list'];
56
+ return View;
57
+ }
@@ -0,0 +1,8 @@
1
+ import {intl} from '#lib';
2
+
3
+ export default class ViewState {
4
+ constructor(mainState) {
5
+ this.intlListDay = $derived.by(intl(mainState, 'listDayFormat'));
6
+ this.intlListDaySide = $derived.by(intl(mainState, 'listDaySideFormat'));
7
+ }
8
+ }
@@ -4,18 +4,18 @@
4
4
 
5
5
  let {resource, date = undefined, setLabel = undefined} = $props();
6
6
 
7
- let {resourceLabelContent, resourceLabelDidMount, _intlDayHeaderAL} = getContext('state');
7
+ let {intlDayHeaderAL, options: {resourceLabelContent, resourceLabelDidMount}} = $derived(getContext('state'));
8
8
 
9
9
  let el = $state();
10
10
  // Content
11
11
  let content = $derived.by(() => {
12
- if ($resourceLabelContent) {
13
- return isFunction($resourceLabelContent)
14
- ? $resourceLabelContent({
12
+ if (resourceLabelContent) {
13
+ return isFunction(resourceLabelContent)
14
+ ? resourceLabelContent({
15
15
  resource,
16
16
  date: date ? toLocalDate(date) : undefined,
17
17
  })
18
- : $resourceLabelContent;
18
+ : resourceLabelContent;
19
19
  } else {
20
20
  return resource.title;
21
21
  }
@@ -26,7 +26,7 @@
26
26
  content;
27
27
  untrack(() => {
28
28
  if (date) {
29
- ariaLabel = $_intlDayHeaderAL.format(date) + ', ' + el.innerText;
29
+ ariaLabel = intlDayHeaderAL.format(date) + ', ' + el.innerText;
30
30
  } else if (setLabel) {
31
31
  ariaLabel = undefined;
32
32
  setLabel(el.innerText);
@@ -35,8 +35,8 @@
35
35
  });
36
36
 
37
37
  onMount(() => {
38
- if (isFunction($resourceLabelDidMount)) {
39
- $resourceLabelDidMount({
38
+ if (isFunction(resourceLabelDidMount)) {
39
+ resourceLabelDidMount({
40
40
  resource,
41
41
  date: date ? toLocalDate(date) : undefined,
42
42
  el
@@ -1,34 +1,55 @@
1
1
  <script>
2
- import {getContext} from 'svelte';
3
- import {createGrid} from './lib.js';
2
+ import {getContext, tick} from 'svelte';
4
3
  import {ColHead, DayHeader} from '#components';
4
+ import {datesEqual, isRtl} from '#lib';
5
+ import ViewState from './state.svelte.js';
5
6
  import Label from './Label.svelte';
6
7
  import View from '../time-grid/View.svelte';
7
8
  import NowIndicator from '../time-grid/NowIndicator.svelte';
8
9
 
9
- let {_viewDates, _viewResources, _slotTimeLimits, datesAboveResources, highlightedDates, validRange, theme} = getContext('state');
10
+ let mainState = getContext('state');
11
+ let viewState = new ViewState(mainState);
12
+
13
+ let {today, mainEl, viewDates, options: {scrollTime, datesAboveResources, theme}} = $derived(mainState);
14
+ let {grid, sidebarWidth} = $derived(viewState);
10
15
 
11
16
  let resourceLabels = $state([]);
17
+
18
+ // Handle scrollTime (scroll to today)
19
+ $effect(() => {
20
+ if (datesAboveResources) {
21
+ viewDates;
22
+ scrollTime;
23
+ tick().then(scrollToTime);
24
+ }
25
+ });
26
+ function scrollToTime() {
27
+ if (today >= viewDates[0] && today <= viewDates.at(-1)) {
28
+ for (let days of grid) {
29
+ let day = days[0];
30
+ if (datesEqual(day.dayStart, today)) {
31
+ mainEl.scrollLeft = (mainEl.scrollWidth - sidebarWidth) / (grid.length * days.length) * (day.gridColumn - 1) * (isRtl() ? -1 : 1);
32
+ break;
33
+ }
34
+ }
35
+ }
36
+ }
12
37
  </script>
13
38
 
14
- <View
15
- createGridFn={() => createGrid(
16
- $_viewDates, $_viewResources, $_slotTimeLimits, $datesAboveResources, $validRange, $highlightedDates
17
- )}
18
- >
19
- {#snippet header(grid)}
39
+ <View {viewState}>
40
+ {#snippet header()}
20
41
  {#each grid as days, i}
21
42
  {@const {dayStart: date, resource, disabled, highlight} = days[0]}
22
43
  <ColHead
23
44
  {date}
24
- className={grid[0].length > 1 ? $theme.colGroup : undefined}
25
- weekday={$datesAboveResources}
45
+ className={grid[0].length > 1 ? theme.colGroup : undefined}
46
+ weekday={datesAboveResources}
26
47
  colSpan={days.length}
27
48
  colIndex={1 + i * days.length}
28
- disabled={$datesAboveResources && disabled}
29
- highlight={$datesAboveResources && highlight}
49
+ disabled={datesAboveResources && disabled}
50
+ highlight={datesAboveResources && highlight}
30
51
  >
31
- {#if $datesAboveResources}
52
+ {#if datesAboveResources}
32
53
  <DayHeader {date}/>
33
54
  {:else}
34
55
  <Label {resource} setLabel={label => resourceLabels[i] = label + ', '}/>
@@ -40,7 +61,7 @@
40
61
  {#each days as day, j}
41
62
  {@const {dayStart: date, resource, disabled, highlight} = day}
42
63
  <ColHead {date} colIndex={1 + j + i * days.length} {disabled} {highlight}>
43
- {#if $datesAboveResources}
64
+ {#if datesAboveResources}
44
65
  <Label {resource} {date}/>
45
66
  {:else}
46
67
  <DayHeader {date} alPrefix={resourceLabels[i]}/>
@@ -51,8 +72,8 @@
51
72
  {/if}
52
73
  {/snippet}
53
74
 
54
- {#snippet nowIndicator(grid)}
55
- {#if $datesAboveResources}
75
+ {#snippet nowIndicator()}
76
+ {#if datesAboveResources}
56
77
  <NowIndicator days={grid.flat()} span={grid[0].length}/>
57
78
  {:else}
58
79
  {#if grid[0].length > 1}
@@ -0,0 +1,67 @@
1
+ import {untrack} from 'svelte';
2
+ import {
3
+ addDay, addDuration, cloneDate, createResources, datesEqual, eventIntersects, outsideRange
4
+ } from '#lib';
5
+
6
+ export function viewResources(mainState) {
7
+ return () => {
8
+ // Dependencies
9
+ let {
10
+ activeRange, filteredEvents, options: {filterResourcesWithEvents, resources}, extensions: {viewResources}
11
+ } = mainState;
12
+
13
+ let result = viewResources ? viewResources(resources) : resources;
14
+
15
+ untrack(() => {
16
+ if (filterResourcesWithEvents) {
17
+ result = resources.filter(
18
+ resource => filteredEvents.some(
19
+ event => eventIntersects(event, activeRange.start, activeRange.end, resource)
20
+ )
21
+ );
22
+ }
23
+ if (!result.length) {
24
+ result = createResources([{}]);
25
+ }
26
+ });
27
+
28
+ return result;
29
+ };
30
+ }
31
+
32
+ export function grid(mainState, viewState) {
33
+ return () => {
34
+ // Dependencies
35
+ let {viewDates, options: {datesAboveResources, highlightedDates, validRange}} = mainState;
36
+ let {slotTimeLimits, viewResources} = viewState;
37
+
38
+ let grid = [];
39
+
40
+ untrack(() => {
41
+ let gridColumn = 1;
42
+ let loop = datesAboveResources ? [viewDates, viewResources] : [viewResources, viewDates];
43
+ for (let item0 of loop[0]) {
44
+ let days = [];
45
+ for (let item1 of loop[1]) {
46
+ let date = datesAboveResources ? item0 : item1;
47
+ let resource = datesAboveResources ? item1 : item0;
48
+ days.push({
49
+ gridColumn,
50
+ gridRow: 1,
51
+ resource,
52
+ start: addDuration(cloneDate(date), slotTimeLimits.min),
53
+ end: addDuration(cloneDate(date), slotTimeLimits.max),
54
+ dayStart: date,
55
+ dayEnd: addDay(cloneDate(date)),
56
+ disabled: outsideRange(date, validRange),
57
+ highlight: highlightedDates.some(d => datesEqual(d, date))
58
+ });
59
+ ++gridColumn;
60
+ }
61
+ grid.push(days);
62
+ }
63
+ });
64
+
65
+ return grid;
66
+ };
67
+ }