@svar-ui/svelte-calendar 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.
Files changed (60) hide show
  1. package/dist/components/Calendar.svelte +13 -4
  2. package/dist/components/Calendar.svelte.d.ts +50 -19
  3. package/dist/components/ContextMenu.svelte +13 -5
  4. package/dist/components/Editor.svelte +29 -34
  5. package/dist/components/EventDatesForm.svelte +121 -0
  6. package/dist/components/EventDatesForm.svelte.d.ts +15 -0
  7. package/dist/components/Layout.svelte +18 -5
  8. package/dist/components/Layout.svelte.d.ts +2 -0
  9. package/dist/components/Navigation.svelte +20 -12
  10. package/dist/components/Navigation.svelte.d.ts +1 -0
  11. package/dist/components/Render/BarSection.svelte +3 -0
  12. package/dist/components/Render/EventProjection.svelte +36 -0
  13. package/dist/components/Render/EventProjection.svelte.d.ts +9 -0
  14. package/dist/components/Render/GridSection.svelte +5 -2
  15. package/dist/components/Render/GridSection.svelte.d.ts +2 -1
  16. package/dist/components/Render/ScrollableSection.svelte +22 -3
  17. package/dist/components/Render/ScrollableSection.svelte.d.ts +1 -0
  18. package/dist/components/Render/SectionContent.svelte +1 -0
  19. package/dist/components/Render/Sections.svelte +46 -9
  20. package/dist/components/Render/Sections.svelte.d.ts +1 -0
  21. package/dist/components/Render/YearSection.svelte +8 -1
  22. package/dist/components/Render/resolveEventPosition.d.ts +5 -0
  23. package/dist/components/Render/resolveEventPosition.js +35 -0
  24. package/dist/components/pro_RecurringForm.svelte +346 -0
  25. package/dist/components/pro_RecurringForm.svelte.d.ts +15 -0
  26. package/dist/components/pro_rrule-form.d.ts +23 -0
  27. package/dist/components/pro_rrule-form.js +121 -0
  28. package/dist/components/{Render/useEventOverlay.svelte.d.ts → useEventOverlay.svelte.d.ts} +1 -1
  29. package/dist/components/{Render/useEventOverlay.svelte.js → useEventOverlay.svelte.js} +1 -1
  30. package/dist/context.tx +0 -0
  31. package/dist/defaults.d.ts +18 -0
  32. package/dist/defaults.js +15 -0
  33. package/dist/directives/clickevent.d.ts +1 -0
  34. package/dist/directives/clickevent.js +11 -8
  35. package/dist/directives/drag.js +11 -7
  36. package/dist/directives/dragresize.js +6 -3
  37. package/dist/helpers/pro_export.d.ts +5 -0
  38. package/dist/helpers/pro_export.js +22 -0
  39. package/dist/index.d.ts +5 -4
  40. package/dist/index.js +4 -2
  41. package/dist/pro_export/Calendar.svelte +30 -0
  42. package/dist/pro_export/Calendar.svelte.d.ts +16 -0
  43. package/dist/pro_export/Event.svelte +5 -0
  44. package/dist/pro_export/Event.svelte.d.ts +11 -0
  45. package/dist/pro_export.d.ts +3 -0
  46. package/dist/pro_export.js +15 -0
  47. package/dist/themes/Print.svelte +89 -0
  48. package/dist/themes/Print.svelte.d.ts +13 -0
  49. package/dist/themes/PrintBW.svelte +111 -0
  50. package/dist/themes/PrintBW.svelte.d.ts +13 -0
  51. package/dist/{components/types.d.ts → types.d.ts} +5 -0
  52. package/package.json +17 -17
  53. package/readme.md +2 -2
  54. package/dist/Demo.svelte +0 -7
  55. package/dist/Demo.svelte.d.ts +0 -26
  56. package/dist/components/editorItems.d.ts +0 -15
  57. package/dist/components/editorItems.js +0 -20
  58. package/dist/init.d.ts +0 -1
  59. package/dist/init.js +0 -5
  60. /package/dist/{components/types.js → types.js} +0 -0
@@ -13,7 +13,7 @@ let { events, init, view = "day", date, views = [
13
13
  "day",
14
14
  "week",
15
15
  "month"
16
- ], toolbar, cellCss, eventCss, eventContent, recurring = false, readonly = false, children, tooltip, eventPopup, ...restProps } = $props();
16
+ ], toolbar, cellCss, eventCss, eventContent, recurring = false, history = false, readonly = false, children, tooltip, eventPopup, eventProjection, ...restProps } = $props();
17
17
  // uses same logic as the Locale component
18
18
  const words = {
19
19
  ...coreEn,
@@ -34,7 +34,8 @@ const fmt = (format) => {
34
34
  const dataStore = new CalendarStore(writable, {
35
35
  recurring,
36
36
  weekStart: rawLocale?.calendar?.weekStart ?? 1,
37
- dateFormat: fmt
37
+ dateFormat: fmt,
38
+ history
38
39
  });
39
40
  // define event route
40
41
  let firstInRoute = dataStore.in;
@@ -75,12 +76,17 @@ const stateStore = {
75
76
  getReactiveState,
76
77
  exec,
77
78
  getEvent,
78
- fmt
79
+ fmt,
80
+ getBrandmark: () => dataStore.getBrandmark()
79
81
  };
80
82
  setContext("calendar-api", stateStore);
81
83
  let init_once = true;
84
+ let lastOptions = null;
82
85
  const reinitStore = () => {
83
- dataStore.configureViews(viewOptions);
86
+ if (lastOptions !== viewOptions) {
87
+ lastOptions = viewOptions;
88
+ dataStore.configureViews(viewOptions);
89
+ }
84
90
  dataStore.init({
85
91
  currentView: view,
86
92
  currentDate: date,
@@ -89,6 +95,7 @@ const reinitStore = () => {
89
95
  if (init_once && init) {
90
96
  init(api);
91
97
  init_once = false;
98
+ dataStore.postInit();
92
99
  }
93
100
  };
94
101
  reinitStore();
@@ -107,4 +114,6 @@ $effect(reinitStore);
107
114
  {tooltip}
108
115
  {eventPopup}
109
116
  {readonly}
117
+ {history}
118
+ {eventProjection}
110
119
  />
@@ -1,8 +1,8 @@
1
1
  import type { Snippet } from "svelte";
2
2
  import { CalendarStore } from "@svar-ui/calendar-store";
3
3
  import type { ViewConfig } from "@svar-ui/calendar-store";
4
- import type { CalendarInstanceApi } from "./types.js";
5
- import type { ToolbarItem, CellCss, EventCss } from "@svar-ui/calendar-store";
4
+ import type { CalendarInstanceApi } from "../types.js";
5
+ import type { ToolbarItem, CellCss, EventCss, EventProjection } from "@svar-ui/calendar-store";
6
6
  type Props = {
7
7
  events: any;
8
8
  init?: (api: CalendarInstanceApi) => void;
@@ -18,9 +18,12 @@ type Props = {
18
18
  eventContent?: any;
19
19
  date?: Date;
20
20
  recurring?: boolean;
21
+ history?: boolean;
21
22
  children?: Snippet;
22
23
  tooltip?: any;
23
24
  eventPopup?: any;
25
+ eventProjection?: EventProjection | null;
26
+ [key: `on${string}`]: ((ev: any) => void) | undefined;
24
27
  };
25
28
  declare const Calendar: import("svelte").Component<Props, {
26
29
  getState: () => import("@svar-ui/calendar-store").State;
@@ -35,7 +38,11 @@ declare const Calendar: import("svelte").Component<Props, {
35
38
  events: import("@svar-ui/lib-state").IPublicWritable<import("@svar-ui/calendar-store").EventsStore>;
36
39
  viewData: import("@svar-ui/lib-state").IPublicWritable<any>;
37
40
  filters: import("@svar-ui/lib-state").IPublicWritable<Map<string, (obj: any) => boolean>>;
38
- editorData: import("@svar-ui/lib-state").IPublicWritable<import("@svar-ui/calendar-store").CalendarEvent | null>;
41
+ editorData: import("@svar-ui/lib-state").IPublicWritable<import("@svar-ui/calendar-store").EditorData | null>;
42
+ history: import("@svar-ui/lib-state").IPublicWritable<{
43
+ undo: number;
44
+ redo: number;
45
+ }>;
39
46
  _view: import("@svar-ui/lib-state").IPublicWritable<import("@svar-ui/calendar-store").ViewModel>;
40
47
  };
41
48
  getStores: () => {
@@ -52,23 +59,29 @@ declare const Calendar: import("svelte").Component<Props, {
52
59
  event: Partial<import("@svar-ui/calendar-store").CalendarEvent>;
53
60
  edit?: boolean;
54
61
  id?: import("@svar-ui/calendar-store").EventID;
62
+ rawId?: import("@svar-ui/calendar-store").EventID;
55
63
  } | {
56
64
  id: import("@svar-ui/calendar-store").EventID;
65
+ rawId?: import("@svar-ui/calendar-store").EventID;
57
66
  event: Partial<import("@svar-ui/calendar-store").CalendarEvent>;
58
67
  mode?: "single" | "following";
59
- originalDate?: string;
60
68
  } | {
61
69
  id: import("@svar-ui/calendar-store").EventID;
70
+ rawId?: import("@svar-ui/calendar-store").EventID;
71
+ cascade?: boolean;
62
72
  } | {
63
73
  id: import("@svar-ui/calendar-store").EventID | null;
74
+ rawId?: import("@svar-ui/calendar-store").EventID | null;
75
+ mode?: import("@svar-ui/calendar-store").RecurringEditMode | null;
64
76
  } | {
65
77
  id: import("@svar-ui/calendar-store").EventID;
66
- x: number;
67
- y: number;
78
+ rawId?: import("@svar-ui/calendar-store").EventID;
79
+ event: Partial<import("@svar-ui/calendar-store").CalendarEvent>;
80
+ mode?: "single" | "following";
68
81
  } | {
69
82
  filter?: ((obj: any) => boolean) | null;
70
83
  tag?: string;
71
- }) => Promise<{
84
+ } | import("@svar-ui/calendar-store").RequestDataAction | import("@svar-ui/calendar-store").ProvideDataAction) => Promise<{
72
85
  date?: Date;
73
86
  view?: string;
74
87
  } | {
@@ -77,23 +90,29 @@ declare const Calendar: import("svelte").Component<Props, {
77
90
  event: Partial<import("@svar-ui/calendar-store").CalendarEvent>;
78
91
  edit?: boolean;
79
92
  id?: import("@svar-ui/calendar-store").EventID;
93
+ rawId?: import("@svar-ui/calendar-store").EventID;
80
94
  } | {
81
95
  id: import("@svar-ui/calendar-store").EventID;
96
+ rawId?: import("@svar-ui/calendar-store").EventID;
82
97
  event: Partial<import("@svar-ui/calendar-store").CalendarEvent>;
83
98
  mode?: "single" | "following";
84
- originalDate?: string;
85
99
  } | {
86
100
  id: import("@svar-ui/calendar-store").EventID;
101
+ rawId?: import("@svar-ui/calendar-store").EventID;
102
+ cascade?: boolean;
87
103
  } | {
88
104
  id: import("@svar-ui/calendar-store").EventID | null;
105
+ rawId?: import("@svar-ui/calendar-store").EventID | null;
106
+ mode?: import("@svar-ui/calendar-store").RecurringEditMode | null;
89
107
  } | {
90
108
  id: import("@svar-ui/calendar-store").EventID;
91
- x: number;
92
- y: number;
109
+ rawId?: import("@svar-ui/calendar-store").EventID;
110
+ event: Partial<import("@svar-ui/calendar-store").CalendarEvent>;
111
+ mode?: "single" | "following";
93
112
  } | {
94
113
  filter?: ((obj: any) => boolean) | null;
95
114
  tag?: string;
96
- }>;
115
+ } | import("@svar-ui/calendar-store").RequestDataAction | import("@svar-ui/calendar-store").ProvideDataAction>;
97
116
  setNext: (ev: any) => any;
98
117
  intercept: (name: keyof import("@svar-ui/calendar-store").StoreActions, handler: (v: {
99
118
  date?: Date;
@@ -104,23 +123,29 @@ declare const Calendar: import("svelte").Component<Props, {
104
123
  event: Partial<import("@svar-ui/calendar-store").CalendarEvent>;
105
124
  edit?: boolean;
106
125
  id?: import("@svar-ui/calendar-store").EventID;
126
+ rawId?: import("@svar-ui/calendar-store").EventID;
107
127
  } | {
108
128
  id: import("@svar-ui/calendar-store").EventID;
129
+ rawId?: import("@svar-ui/calendar-store").EventID;
109
130
  event: Partial<import("@svar-ui/calendar-store").CalendarEvent>;
110
131
  mode?: "single" | "following";
111
- originalDate?: string;
112
132
  } | {
113
133
  id: import("@svar-ui/calendar-store").EventID;
134
+ rawId?: import("@svar-ui/calendar-store").EventID;
135
+ cascade?: boolean;
114
136
  } | {
115
137
  id: import("@svar-ui/calendar-store").EventID | null;
138
+ rawId?: import("@svar-ui/calendar-store").EventID | null;
139
+ mode?: import("@svar-ui/calendar-store").RecurringEditMode | null;
116
140
  } | {
117
141
  id: import("@svar-ui/calendar-store").EventID;
118
- x: number;
119
- y: number;
142
+ rawId?: import("@svar-ui/calendar-store").EventID;
143
+ event: Partial<import("@svar-ui/calendar-store").CalendarEvent>;
144
+ mode?: "single" | "following";
120
145
  } | {
121
146
  filter?: ((obj: any) => boolean) | null;
122
147
  tag?: string;
123
- }) => void | boolean | Promise<boolean>, config?: import("@svar-ui/lib-state").IEventConfig) => void;
148
+ } | import("@svar-ui/calendar-store").RequestDataAction | import("@svar-ui/calendar-store").ProvideDataAction) => void | boolean | Promise<boolean>, config?: import("@svar-ui/lib-state").IEventConfig) => void;
124
149
  on: (name: keyof import("@svar-ui/calendar-store").StoreActions, handler: (v: {
125
150
  date?: Date;
126
151
  view?: string;
@@ -130,23 +155,29 @@ declare const Calendar: import("svelte").Component<Props, {
130
155
  event: Partial<import("@svar-ui/calendar-store").CalendarEvent>;
131
156
  edit?: boolean;
132
157
  id?: import("@svar-ui/calendar-store").EventID;
158
+ rawId?: import("@svar-ui/calendar-store").EventID;
133
159
  } | {
134
160
  id: import("@svar-ui/calendar-store").EventID;
161
+ rawId?: import("@svar-ui/calendar-store").EventID;
135
162
  event: Partial<import("@svar-ui/calendar-store").CalendarEvent>;
136
163
  mode?: "single" | "following";
137
- originalDate?: string;
138
164
  } | {
139
165
  id: import("@svar-ui/calendar-store").EventID;
166
+ rawId?: import("@svar-ui/calendar-store").EventID;
167
+ cascade?: boolean;
140
168
  } | {
141
169
  id: import("@svar-ui/calendar-store").EventID | null;
170
+ rawId?: import("@svar-ui/calendar-store").EventID | null;
171
+ mode?: import("@svar-ui/calendar-store").RecurringEditMode | null;
142
172
  } | {
143
173
  id: import("@svar-ui/calendar-store").EventID;
144
- x: number;
145
- y: number;
174
+ rawId?: import("@svar-ui/calendar-store").EventID;
175
+ event: Partial<import("@svar-ui/calendar-store").CalendarEvent>;
176
+ mode?: "single" | "following";
146
177
  } | {
147
178
  filter?: ((obj: any) => boolean) | null;
148
179
  tag?: string;
149
- }) => void | boolean | Promise<boolean>, config?: import("@svar-ui/lib-state").IEventConfig) => void;
180
+ } | import("@svar-ui/calendar-store").RequestDataAction | import("@svar-ui/calendar-store").ProvideDataAction) => void | boolean | Promise<boolean>, config?: import("@svar-ui/lib-state").IEventConfig) => void;
150
181
  detach: (tag: number | string | symbol) => void;
151
182
  }, "">;
152
183
  type Calendar = ReturnType<typeof Calendar>;
@@ -6,6 +6,7 @@ import { en as coreEn } from "@svar-ui/core-locales";
6
6
  import { getMenuOptions } from "@svar-ui/calendar-store";
7
7
  let { options = [], api = null, resolver = null, filter = null, at = "point", children, onclick, css } = $props();
8
8
  let activeId = null;
9
+ let rawId = null;
9
10
  // set locale
10
11
  let l = getContext("wx-i18n");
11
12
  if (!l) {
@@ -29,15 +30,16 @@ function getOptions() {
29
30
  const base = options.length ? options : getMenuOptions();
30
31
  return applyLocale(base);
31
32
  }
32
- function itemResolver(rawId, ev) {
33
- if (!rawId || !api) return null;
34
- const event = api.getEvent(rawId);
33
+ function itemResolver(id, ev) {
34
+ if (!id || !api) return null;
35
+ const event = api.getEvent(id);
35
36
  if (!event) return null;
36
37
  if (resolver) {
37
38
  const result = resolver(event, ev);
38
39
  if (!result) return null;
39
40
  }
40
41
  activeId = event.id;
42
+ rawId = id;
41
43
  return event;
42
44
  }
43
45
  function menuAction(ev) {
@@ -45,9 +47,15 @@ function menuAction(ev) {
45
47
  if (!action) return;
46
48
  const id = typeof activeId === "object" ? activeId.id : activeId;
47
49
  if (action.id === "edit-event") {
48
- api.exec("select-event", { id });
50
+ api.exec("select-event", {
51
+ id,
52
+ rawId
53
+ });
49
54
  } else if (action.id === "delete-event") {
50
- api.exec("delete-event", { id });
55
+ api.exec("delete-event", {
56
+ id,
57
+ rawId
58
+ });
51
59
  }
52
60
  onclick?.(ev);
53
61
  }
@@ -4,9 +4,11 @@ import { locale } from "@svar-ui/lib-dom";
4
4
  import { en } from "@svar-ui/calendar-locales";
5
5
  import { en as coreEn } from "@svar-ui/core-locales";
6
6
  import DateTimePicker from "./DateTimePicker.svelte";
7
- import { getEditorItems } from "./editorItems.js";
7
+ import EventDatesForm from "./EventDatesForm.svelte";
8
+ import { getEditorItems } from "../defaults.js";
8
9
  registerEditorItem("date-time-picker", DateTimePicker);
9
- let { api, values, items = getEditorItems(), placement = "sidebar", layout = "default", focus = true, css = "", topBar, autoSave = true, onchange, onsave, onaction, ...editorProps } = $props();
10
+ registerEditorItem("event-dates", EventDatesForm);
11
+ let { api, values, items, placement, layout = "default", focus = true, css = "", topBar, autoSave = true, onchange, onsave, onaction, ...editorProps } = $props();
10
12
  // svelte-ignore state_referenced_locally
11
13
  void values;
12
14
  // svelte-ignore state_referenced_locally
@@ -30,9 +32,10 @@ function applyLocale(list) {
30
32
  return next;
31
33
  });
32
34
  }
33
- let generation = $state(1);
34
- const allDay = $derived(generation > 0 ? $editorData?.allDay : false);
35
- const cItems = $derived(applyLocale(items));
35
+ const calendarCtx = getContext("calendar-api");
36
+ const finalPlacement = $derived(placement ?? (calendarCtx?.isCompact() ? "fullscreen" : "sidebar"));
37
+ const useRecurringForm = $derived(!!$editorData?.recurring && ($editorData?.recurringMode ?? "series") !== "single");
38
+ const cItems = $derived(applyLocale(items ?? getEditorItems(useRecurringForm)));
36
39
  const defaultTopBar = { items: [
37
40
  {
38
41
  comp: "icon",
@@ -49,49 +52,44 @@ const defaultTopBar = { items: [
49
52
  }
50
53
  ] };
51
54
  const editorTopBar = $derived(topBar === undefined ? defaultTopBar : topBar);
52
- const editorCss = $derived([
53
- "wx-editor-calendar",
54
- allDay ? "wx-editor-all-day" : "",
55
- css
56
- ].filter(Boolean).join(" "));
55
+ const editorCss = $derived(["wx-editor-calendar", css].filter(Boolean).join(" "));
57
56
  function handleSave(ev) {
58
57
  onsave?.(ev);
59
58
  const data = $editorData;
60
59
  if (!data) return;
60
+ const mode = data.recurringMode ?? "series";
61
+ // a series save must not carry the clicked occurrence's context in
62
+ // rawId, or the store would treat it as a single-occurrence edit
61
63
  api.exec("update-event", {
62
64
  id: data.id,
63
- event: { ...ev.values }
65
+ rawId: mode === "series" ? data.id : data.rawId,
66
+ event: { ...ev.values },
67
+ ...data.recurringOriginalDate && mode !== "series" ? { mode } : {}
64
68
  });
65
69
  }
66
- function sameDay(a, b) {
67
- return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
68
- }
69
70
  function handleChange(ev) {
70
- const { key, value, update } = ev;
71
- const prev = $editorData;
72
- generation++;
73
- if (prev && key === "start" && !update.allDay) {
74
- const oldStart = prev.start;
75
- const oldEnd = prev.end;
76
- if (oldStart instanceof Date && oldEnd instanceof Date && sameDay(oldStart, oldEnd) && value instanceof Date) {
77
- const newEnd = new Date(oldEnd);
78
- newEnd.setFullYear(value.getFullYear(), value.getMonth(), value.getDate());
79
- update.end = newEnd;
80
- }
81
- }
82
71
  onchange?.(ev);
83
72
  }
84
73
  function handleDelete() {
85
74
  const data = $editorData;
86
75
  if (!data) return;
87
- api.exec("delete-event", { id: data.id });
88
- api.exec("select-event", { id: null });
76
+ api.exec("delete-event", {
77
+ id: data.id,
78
+ rawId: data.rawId
79
+ });
80
+ api.exec("select-event", {
81
+ id: null,
82
+ rawId: null
83
+ });
89
84
  }
90
85
  function handleAction(ev) {
91
86
  onaction?.(ev);
92
87
  const { item } = ev;
93
88
  if (item.id === "close" && !!item.comp) {
94
- api.exec("select-event", { id: null });
89
+ api.exec("select-event", {
90
+ id: null,
91
+ rawId: null
92
+ });
95
93
  }
96
94
  }
97
95
  </script>
@@ -106,9 +104,9 @@ function handleAction(ev) {
106
104
  onchange={handleChange}
107
105
  onaction={handleAction}
108
106
  onsave={handleSave}
109
- {placement}
107
+ placement={finalPlacement}
110
108
  {layout}
111
- values={$editorData}
109
+ values={$editorData.values}
112
110
  css={editorCss}
113
111
  />
114
112
  {/if}
@@ -117,7 +115,4 @@ function handleAction(ev) {
117
115
  :global(.wx-sidearea .wx-editor-calendar) {
118
116
  width: 450px;
119
117
  }
120
- :global(.wx-editor-calendar.wx-editor-all-day .wx-timepicker) {
121
- visibility: hidden;
122
- }
123
118
  </style>
@@ -0,0 +1,121 @@
1
+ <script lang="ts">import { getContext, setContext } from "svelte";
2
+ import { Checkbox, DatePicker, TimePicker } from "@svar-ui/svelte-core";
3
+ const locale = getContext("wx-i18n");
4
+ const _ = locale ? locale.getGroup("eventCalendar") : (v) => v;
5
+ let { value, error, onchange } = $props();
6
+ setContext("wx-input-id", "");
7
+ function sameDay(a, b) {
8
+ return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
9
+ }
10
+ function update(part) {
11
+ onchange({ value: {
12
+ ...value,
13
+ ...part
14
+ } });
15
+ }
16
+ function pickDate(key, day) {
17
+ if (!day) return;
18
+ const current = value[key];
19
+ const next = new Date(day);
20
+ if (current) {
21
+ next.setHours(current.getHours(), current.getMinutes(), 0, 0);
22
+ }
23
+ if (key === "start" && sameDay(value.start, value.end)) {
24
+ const end = new Date(value.end);
25
+ end.setFullYear(next.getFullYear(), next.getMonth(), next.getDate());
26
+ update({
27
+ start: next,
28
+ end
29
+ });
30
+ } else {
31
+ update({ [key]: next });
32
+ }
33
+ }
34
+ function pickTime(key, time) {
35
+ const next = new Date(value[key]);
36
+ next.setHours(time.getHours(), time.getMinutes(), 0, 0);
37
+ update({ [key]: next });
38
+ }
39
+ </script>
40
+
41
+ <div class="wx-event-dates" class:wx-error={!!error}>
42
+ <div class="wx-date-row">
43
+ <span class="wx-date-label">{_("Start date")}</span>
44
+ <div class="wx-date-control">
45
+ <DatePicker
46
+ value={value.start}
47
+ buttons={false}
48
+ onchange={ev => pickDate("start", ev.value)}
49
+ />
50
+ </div>
51
+ {#if !value.allDay}
52
+ <div class="wx-time-control">
53
+ <TimePicker
54
+ value={value.start}
55
+ onchange={ev => pickTime("start", ev.value)}
56
+ />
57
+ </div>
58
+ {/if}
59
+ </div>
60
+
61
+ <div class="wx-date-row">
62
+ <span class="wx-date-label">{_("End date")}</span>
63
+ <div class="wx-date-control">
64
+ <DatePicker
65
+ value={value.end}
66
+ buttons={false}
67
+ onchange={ev => pickDate("end", ev.value)}
68
+ />
69
+ </div>
70
+ {#if !value.allDay}
71
+ <div class="wx-time-control">
72
+ <TimePicker
73
+ value={value.end}
74
+ onchange={ev => pickTime("end", ev.value)}
75
+ />
76
+ </div>
77
+ {/if}
78
+ </div>
79
+
80
+ <div class="wx-date-row">
81
+ <span class="wx-date-label"></span>
82
+ <Checkbox
83
+ label={_("All day")}
84
+ value={!!value.allDay}
85
+ onchange={ev => update({ allDay: ev.value })}
86
+ />
87
+ </div>
88
+ </div>
89
+
90
+ <style>
91
+ .wx-event-dates {
92
+ display: flex;
93
+ flex-direction: column;
94
+ gap: var(--wx-padding);
95
+ }
96
+
97
+ .wx-date-row {
98
+ display: flex;
99
+ align-items: center;
100
+ gap: var(--wx-padding);
101
+ }
102
+
103
+ .wx-date-label {
104
+ flex: none;
105
+ width: 72px;
106
+ }
107
+
108
+ .wx-date-control {
109
+ flex: 1;
110
+ min-width: 0;
111
+ }
112
+
113
+ .wx-time-control {
114
+ flex: none;
115
+ width: 96px;
116
+ }
117
+
118
+ .wx-error :global(.wx-input) {
119
+ border-color: var(--wx-color-danger);
120
+ }
121
+ </style>
@@ -0,0 +1,15 @@
1
+ type Value = {
2
+ start: Date;
3
+ end: Date;
4
+ allDay?: boolean;
5
+ };
6
+ type $$ComponentProps = {
7
+ value: Value;
8
+ error?: unknown;
9
+ onchange: (ev: {
10
+ value: Value;
11
+ }) => void;
12
+ };
13
+ declare const EventDatesForm: import("svelte").Component<$$ComponentProps, {}, "">;
14
+ type EventDatesForm = ReturnType<typeof EventDatesForm>;
15
+ export default EventDatesForm;
@@ -2,24 +2,37 @@
2
2
  import Navigation from "./Navigation.svelte";
3
3
  import Sections from "./Render/Sections.svelte";
4
4
  import ScrollableSection from "./Render/ScrollableSection.svelte";
5
+ const COMPACT_WIDTH = 480;
5
6
  const _ = getContext("wx-i18n").getGroup("eventCalendar");
6
- const { store, views, toolbar, cellCss, eventCss, eventContent, children, tooltip, eventPopup, brandmark, readonly = false } = $props();
7
+ const { store, views, toolbar, cellCss, eventCss, eventContent, children, tooltip, eventPopup, brandmark, readonly = false, history = false, eventProjection } = $props();
7
8
  // svelte-ignore state_referenced_locally
8
9
  const { viewData, currentView, _view } = store.getReactiveState();
9
10
  const renderMode = $derived($_view?.render);
11
+ let isCompact = false;
12
+ // svelte-ignore state_referenced_locally
13
+ store.isCompact = () => isCompact;
14
+ function observeSize(node) {
15
+ store.getRootNode = () => node;
16
+ const observer = new ResizeObserver((entries) => {
17
+ isCompact = entries[0].contentRect.width < COMPACT_WIDTH;
18
+ node.classList.toggle("wx-calendar--compact", isCompact);
19
+ });
20
+ observer.observe(node);
21
+ return { destroy: () => observer.disconnect() };
22
+ }
10
23
  </script>
11
24
 
12
25
  {#snippet viewContent()}
13
26
  {#if renderMode === "scrollable"}
14
- <ScrollableSection data={$viewData} {cellCss} {eventCss} {eventContent} view={$currentView} {tooltip} {eventPopup} {readonly} />
27
+ <ScrollableSection data={$viewData} {cellCss} {eventCss} {eventContent} view={$currentView} {tooltip} {eventPopup} {readonly} {eventProjection} />
15
28
  {:else}
16
- <Sections data={$viewData} {cellCss} {eventCss} {eventContent} view={$currentView} {tooltip} {eventPopup} {readonly} />
29
+ <Sections data={$viewData} {cellCss} {eventCss} {eventContent} view={$currentView} {tooltip} {eventPopup} {readonly} {eventProjection} />
17
30
  {/if}
18
31
  {/snippet}
19
32
 
20
- <div class="wx-calendar" role="region" aria-label={_("Calendar")}>
33
+ <div class="wx-calendar" role="region" aria-label={_("Calendar")} use:observeSize>
21
34
  {#if toolbar !== null}
22
- <Navigation {views} toolbar={toolbar} {readonly} />
35
+ <Navigation {views} toolbar={toolbar} {readonly} {history} />
23
36
  {/if}
24
37
  {#if children}
25
38
  <div class="wx-calendar-content">
@@ -15,6 +15,8 @@ type $$ComponentProps = {
15
15
  eventPopup?: any;
16
16
  brandmark?: Brandmark;
17
17
  readonly?: boolean;
18
+ history?: boolean;
19
+ eventProjection?: any;
18
20
  };
19
21
  declare const Layout: import("svelte").Component<$$ComponentProps, {}, "">;
20
22
  type Layout = ReturnType<typeof Layout>;
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">import { getContext } from "svelte";
2
- import { Toolbar, registerToolbarItem } from "@svar-ui/svelte-toolbar";
2
+ import { Toolbar, registerToolbarItem, ButtonList } from "@svar-ui/svelte-toolbar";
3
3
  import { RichSelect, Segmented } from "@svar-ui/svelte-core";
4
4
  import { getToolbarItems } from "@svar-ui/calendar-store";
5
5
  import DateNav from "./DateNav.svelte";
@@ -8,36 +8,42 @@ import DateLabel from "./DateLabel.svelte";
8
8
  import MenuButton from "./MenuButton.svelte";
9
9
  import AddEventButton from "./AddEventButton.svelte";
10
10
  registerToolbarItem("richselect", RichSelect);
11
+ registerToolbarItem("richselect-navigation", RichSelect);
12
+ registerToolbarItem("richselect-navigation", ButtonList, { menu: true });
11
13
  registerToolbarItem("segmented", Segmented);
14
+ registerToolbarItem("segmented-navigation", Segmented);
15
+ registerToolbarItem("segmented-navigation", ButtonList, { menu: true });
16
+ registerToolbarItem("segmented", ButtonList, { menu: true });
12
17
  registerToolbarItem("dateNav", DateNav);
13
18
  registerToolbarItem("todayButton", TodayButton);
14
19
  registerToolbarItem("dateLabel", DateLabel);
15
20
  registerToolbarItem("menuButton", MenuButton);
16
21
  registerToolbarItem("addEventButton", AddEventButton);
17
22
  const store = getContext("calendar-api");
18
- const { views, toolbar = { items: getToolbarItems() }, readonly = false } = $props();
19
- const { currentView } = store.getReactiveState();
23
+ const { views, toolbar, readonly = false, history = false } = $props();
24
+ const reactiveState = store.getReactiveState();
25
+ const { currentView } = reactiveState;
20
26
  const _ = getContext("wx-i18n").getGroup("eventCalendar");
21
27
  const items = $derived.by(() => {
22
- const base = toolbar?.items;
28
+ const base = toolbar ? toolbar.items : getToolbarItems({ history });
23
29
  const viewOptions = views.map((v) => ({
24
30
  id: v.id,
25
31
  label: _(v.label || v.id.charAt(0).toUpperCase() + v.id.slice(1))
26
32
  }));
27
33
  const res = [...base ?? []].map((item) => {
28
- if (item.id === "modes") {
34
+ let next = item;
35
+ if (next.id === "modes") {
29
36
  if (viewOptions.length > 1) {
30
37
  return {
31
- ...item,
38
+ ...next,
32
39
  value: $currentView,
33
40
  options: viewOptions
34
41
  };
35
42
  } else {
36
43
  return null;
37
44
  }
38
- }
39
- if (readonly && item.comp === "addEventButton") return null;
40
- return item;
45
+ } else if (!readonly) {} else if (next.comp === "addEventButton" || next.id === "undo" || next.id === "redo") return null;
46
+ return next;
41
47
  }).filter(Boolean);
42
48
  return res;
43
49
  });
@@ -48,9 +54,11 @@ const onchange = ({ item, value }) => {
48
54
  };
49
55
  </script>
50
56
 
51
- <div class="wx-navigation" role="navigation" aria-label={_("Calendar controls")}>
52
- <Toolbar {items} {onchange} css={toolbar?.css}></Toolbar>
53
- </div>
57
+ {#if items.length}
58
+ <div class="wx-navigation" role="navigation" aria-label={_("Calendar controls")}>
59
+ <Toolbar {items} {onchange} css={toolbar?.css}></Toolbar>
60
+ </div>
61
+ {/if}
54
62
 
55
63
  <style>
56
64
  .wx-navigation {
@@ -6,6 +6,7 @@ type $$ComponentProps = {
6
6
  css?: string;
7
7
  };
8
8
  readonly?: boolean;
9
+ history?: boolean;
9
10
  };
10
11
  declare const Navigation: import("svelte").Component<$$ComponentProps, {}, "">;
11
12
  type Navigation = ReturnType<typeof Navigation>;
@@ -73,6 +73,9 @@ function css(p) {
73
73
  box-shadow: none;
74
74
  border-radius: 0;
75
75
  }
76
+ .wx-bar-single-day:global(.wx-dragging) {
77
+ background-color: var(--wx-background);
78
+ }
76
79
  .wx-bar-single-day:hover {
77
80
  background-color: var(--wx-color-secondary-hover);
78
81
  box-shadow: none;