@bimetal/calendar-svelte-components 0.29.0 → 0.30.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/dist/components/Calendar.svelte +1 -1
- package/dist/components/EventBar.svelte +6 -0
- package/dist/components/EventBar.svelte.d.ts.map +1 -1
- package/dist/views/agenda/AgendaEvent.svelte +10 -9
- package/dist/views/agenda/AgendaEvent.svelte.d.ts +2 -1
- package/dist/views/agenda/AgendaEvent.svelte.d.ts.map +1 -1
- package/dist/views/agenda/AgendaView.svelte +55 -113
- package/dist/views/agenda/AgendaView.svelte.d.ts +3 -2
- package/dist/views/agenda/AgendaView.svelte.d.ts.map +1 -1
- package/dist/views/month/TimedEntry.svelte +6 -0
- package/dist/views/month/TimedEntry.svelte.d.ts.map +1 -1
- package/dist/views/week/TimeEvent.svelte +13 -0
- package/dist/views/week/TimeEvent.svelte.d.ts.map +1 -1
- package/package.json +8 -8
|
@@ -203,7 +203,7 @@
|
|
|
203
203
|
{:else if snapshot.currentView === 'day'}
|
|
204
204
|
<DayView currentDate={snapshot.currentDate} />
|
|
205
205
|
{:else if snapshot.currentView === 'agenda'}
|
|
206
|
-
<AgendaView
|
|
206
|
+
<AgendaView agenda={snapshot.agenda!} setViewport={ctrl.setViewport} />
|
|
207
207
|
{:else if snapshot.currentView === 'resource'}
|
|
208
208
|
<ResourceView
|
|
209
209
|
currentDate={snapshot.currentDate}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { getCalendarContext, getCalendarConfig, buildDragInfo, getEventSlots, toTimeStr } from '../binding/index.js';
|
|
5
5
|
import type { DragInfo } from '../binding/index.js';
|
|
6
6
|
import { createClickIntent, writeCalendarDragData, installTransparentDragImage, eventBarWantsDarkText } from '@bimetal/calendar-headless';
|
|
7
|
+
import { probeRender } from '@bimetal/svelte';
|
|
7
8
|
|
|
8
9
|
let {
|
|
9
10
|
item,
|
|
@@ -108,6 +109,11 @@
|
|
|
108
109
|
? Object.entries(slots.style).map(([k, v]) => `${k.replace(/[A-Z]/g, m => '-' + m.toLowerCase())}: ${v}`).join('; ')
|
|
109
110
|
: '');
|
|
110
111
|
const fullStyle = $derived(slotStyle ? `${barStyle} ${slotStyle}` : barStyle);
|
|
112
|
+
|
|
113
|
+
// v0.30 Slice 3 perf probe: re-runs (post-DOM) ONLY when this bar's DOM-driving deriveds change.
|
|
114
|
+
// `selectedClass` is equality-gated, so a selection elsewhere does NOT re-run unchanged bars —
|
|
115
|
+
// proving Svelte 5's fine-grained reactivity is identity-true even with the context selection read.
|
|
116
|
+
$effect(() => { void fullStyle; void selectedClass; void renderedTitle; probeRender(event.id); });
|
|
111
117
|
</script>
|
|
112
118
|
|
|
113
119
|
{#if isCompact}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EventBar.svelte.d.ts","sourceRoot":"","sources":["../../src/components/EventBar.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"EventBar.svelte.d.ts","sourceRoot":"","sources":["../../src/components/EventBar.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAO1E,KAAK,gBAAgB,GAAI;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAuJJ,QAAA,MAAM,QAAQ,sDAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
|
|
@@ -1,28 +1,29 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { CalendarEvent } from '@bimetal/calendar-core';
|
|
3
|
-
import { getRecurrenceInstanceMetadata } from '@bimetal/calendar-core';
|
|
4
3
|
import { getEventSlots } from '../../binding/index.js';
|
|
5
4
|
|
|
6
5
|
let {
|
|
7
|
-
|
|
6
|
+
event,
|
|
8
7
|
timeLabel,
|
|
9
8
|
category,
|
|
10
9
|
isSelected,
|
|
10
|
+
instanceDate,
|
|
11
11
|
onEntryMouseDown,
|
|
12
12
|
onEntryClick,
|
|
13
13
|
onEntryDoubleClick,
|
|
14
14
|
}: {
|
|
15
|
-
|
|
15
|
+
event: CalendarEvent;
|
|
16
16
|
timeLabel: string;
|
|
17
17
|
category: string;
|
|
18
18
|
isSelected: boolean;
|
|
19
|
+
instanceDate?: number;
|
|
19
20
|
onEntryMouseDown: () => void;
|
|
20
21
|
onEntryClick: (e: MouseEvent, id: string, instanceDate?: number) => void;
|
|
21
22
|
onEntryDoubleClick: (e: MouseEvent, id: string, instanceDate?: number) => void;
|
|
22
23
|
} = $props();
|
|
23
24
|
|
|
24
|
-
const slots = $derived(getEventSlots(
|
|
25
|
-
const renderedTitle = $derived(slots.title ??
|
|
25
|
+
const slots = $derived(getEventSlots(event));
|
|
26
|
+
const renderedTitle = $derived(slots.title ?? event.title);
|
|
26
27
|
const extraClass = $derived(slots.className ? ' ' + slots.className : '');
|
|
27
28
|
const slotStyleStr = $derived(slots.style
|
|
28
29
|
? Object.entries(slots.style).map(([k, v]) => `${k.replace(/[A-Z]/g, m => '-' + m.toLowerCase())}: ${v}`).join('; ')
|
|
@@ -31,18 +32,18 @@
|
|
|
31
32
|
|
|
32
33
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
33
34
|
<div
|
|
34
|
-
class="agenda-view__event{isSelected ? ' agenda-view__event--selected' : ''}{extraClass}"
|
|
35
|
+
class="agenda-view__row agenda-view__event{isSelected ? ' agenda-view__event--selected' : ''}{extraClass}"
|
|
35
36
|
style={slotStyleStr}
|
|
36
37
|
role="button"
|
|
37
38
|
tabindex="0"
|
|
38
39
|
onmousedown={onEntryMouseDown}
|
|
39
|
-
onclick={(e) => onEntryClick(e,
|
|
40
|
-
ondblclick={(e) => onEntryDoubleClick(e,
|
|
40
|
+
onclick={(e) => onEntryClick(e, event.id, instanceDate)}
|
|
41
|
+
ondblclick={(e) => onEntryDoubleClick(e, event.id, instanceDate)}
|
|
41
42
|
>
|
|
42
43
|
{#if slots.content}
|
|
43
44
|
{#if typeof slots.content === 'string'}{slots.content}{:else}{@render slots.content()}{/if}
|
|
44
45
|
{:else}
|
|
45
|
-
<div class="agenda-view__event-color" style:background-color={
|
|
46
|
+
<div class="agenda-view__event-color" style:background-color={event.metadata.color ?? '#007AFF'}></div>
|
|
46
47
|
<div class="agenda-view__event-content">
|
|
47
48
|
<div class="agenda-view__event-title">{renderedTitle}</div>
|
|
48
49
|
<div class="agenda-view__event-time">{timeLabel}</div>
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { CalendarEvent } from '@bimetal/calendar-core';
|
|
2
2
|
type $$ComponentProps = {
|
|
3
|
-
|
|
3
|
+
event: CalendarEvent;
|
|
4
4
|
timeLabel: string;
|
|
5
5
|
category: string;
|
|
6
6
|
isSelected: boolean;
|
|
7
|
+
instanceDate?: number;
|
|
7
8
|
onEntryMouseDown: () => void;
|
|
8
9
|
onEntryClick: (e: MouseEvent, id: string, instanceDate?: number) => void;
|
|
9
10
|
onEntryDoubleClick: (e: MouseEvent, id: string, instanceDate?: number) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgendaEvent.svelte.d.ts","sourceRoot":"","sources":["../../../src/views/agenda/AgendaEvent.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"AgendaEvent.svelte.d.ts","sourceRoot":"","sources":["../../../src/views/agenda/AgendaEvent.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAG3D,KAAK,gBAAgB,GAAI;IACtB,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,YAAY,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACzE,kBAAkB,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAChF,CAAC;AA2CJ,QAAA,MAAM,WAAW,sDAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import type { CalendarEvent
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
createTimeRange, overlaps, formatDateTime, now,
|
|
7
|
-
getRecurrenceInstanceMetadata, isSingleDayAllDay,
|
|
8
|
-
} from '@bimetal/calendar-core';
|
|
9
|
-
import { getCalendarContext, getCalendarConfig, toDateStr, toTimeStr } from '../../binding/index.js';
|
|
10
|
-
import { DEFAULT_AGENDA_RANGE_DAYS, createClickIntent } from '@bimetal/calendar-headless';
|
|
2
|
+
import type { CalendarEvent } from '@bimetal/calendar-core';
|
|
3
|
+
import type { AgendaWindow } from '@bimetal/calendar-headless';
|
|
4
|
+
import { createClickIntent } from '@bimetal/calendar-headless';
|
|
5
|
+
import { getCalendarContext, getCalendarConfig } from '../../binding/index.js';
|
|
11
6
|
import AgendaEvent from './AgendaEvent.svelte';
|
|
12
7
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
8
|
+
/**
|
|
9
|
+
* The agenda view — a WINDOWED flat list (v0.30 Slice 5b). The controller owns the
|
|
10
|
+
* whole derivation: it flattens the day-grouped agenda to uniform-height rows
|
|
11
|
+
* (header | event), formats every time label, computes selection, and windows the
|
|
12
|
+
* heavy build to the visible slice. This binding only renders `agenda.rows` + the
|
|
13
|
+
* px spacers and reports the scroll container's metrics via `setViewport` — no
|
|
14
|
+
* grouping, no formatting, no window math here.
|
|
15
|
+
*/
|
|
18
16
|
|
|
19
17
|
let {
|
|
20
|
-
|
|
18
|
+
agenda,
|
|
19
|
+
setViewport,
|
|
21
20
|
}: {
|
|
22
|
-
|
|
21
|
+
agenda: AgendaWindow;
|
|
22
|
+
setViewport: (scrollTop: number, viewportHeight: number) => void;
|
|
23
23
|
} = $props();
|
|
24
24
|
|
|
25
25
|
const config = getCalendarConfig();
|
|
@@ -27,60 +27,29 @@
|
|
|
27
27
|
events: CalendarEvent[];
|
|
28
28
|
onEventClick: (eventId: string, anchorRect: DOMRect, instanceDate?: number) => void;
|
|
29
29
|
onSelectEvent: (eventId: string, instanceDate?: number) => void;
|
|
30
|
-
selectedEventId: string | null;
|
|
31
|
-
selectedInstanceDate: number | undefined;
|
|
32
30
|
}>();
|
|
33
31
|
|
|
34
32
|
const click = createClickIntent();
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const evStart = isBefore(ev.timeRange.start, rangeStartDt) ? rangeStartDt : ev.timeRange.start;
|
|
49
|
-
const evEnd = isAfter(ev.timeRange.end, rangeEndDt) ? rangeEndDt : ev.timeRange.end;
|
|
50
|
-
|
|
51
|
-
let d = startOfDay(evStart);
|
|
52
|
-
const end = startOfDay(evEnd);
|
|
53
|
-
const limit = addDays(end, 1);
|
|
54
|
-
while (isBefore(d, limit) && isBefore(d, rangeEndDt)) {
|
|
55
|
-
const ds = toDateStr(d);
|
|
56
|
-
const list = groups.get(ds) || [];
|
|
57
|
-
list.push(ev);
|
|
58
|
-
groups.set(ds, list);
|
|
59
|
-
d = addDays(d, 1);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const result: DayGroup[] = [];
|
|
64
|
-
for (let i = 0; i < DEFAULT_AGENDA_RANGE_DAYS; i++) {
|
|
65
|
-
const date = addDays(rangeStartDt, i);
|
|
66
|
-
const dateStr = toDateStr(date);
|
|
67
|
-
const dayEvents = groups.get(dateStr);
|
|
68
|
-
if (dayEvents && dayEvents.length > 0) {
|
|
69
|
-
dayEvents.sort((a, b) => {
|
|
70
|
-
if (a.allDay !== b.allDay) return a.allDay ? -1 : 1;
|
|
71
|
-
return a.timeRange.start.epochMs - b.timeRange.start.epochMs;
|
|
72
|
-
});
|
|
73
|
-
result.push({ date, dateStr, events: dayEvents });
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
return result;
|
|
34
|
+
let scrollEl: HTMLDivElement | undefined = $state();
|
|
35
|
+
|
|
36
|
+
// Report the scroll container's metrics so the controller windows the rows.
|
|
37
|
+
$effect(() => {
|
|
38
|
+
const el = scrollEl;
|
|
39
|
+
if (!el) return;
|
|
40
|
+
const report = () => setViewport(el.scrollTop, el.clientHeight);
|
|
41
|
+
report();
|
|
42
|
+
el.addEventListener('scroll', report, { passive: true });
|
|
43
|
+
const ro = new ResizeObserver(report);
|
|
44
|
+
ro.observe(el);
|
|
45
|
+
return () => { el.removeEventListener('scroll', report); ro.disconnect(); };
|
|
77
46
|
});
|
|
78
47
|
|
|
79
48
|
function handleMouseDown() {
|
|
80
49
|
click.markMouseDown();
|
|
81
50
|
}
|
|
82
51
|
|
|
83
|
-
function handleEventClick(
|
|
52
|
+
function handleEventClick(_e: MouseEvent, eventId: string, instanceDate?: number) {
|
|
84
53
|
if (!click.accept(config.clickThresholdMs)) return;
|
|
85
54
|
ctx.onSelectEvent(eventId, instanceDate);
|
|
86
55
|
}
|
|
@@ -90,66 +59,39 @@
|
|
|
90
59
|
const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
|
|
91
60
|
ctx.onEventClick(eventId, rect, instanceDate);
|
|
92
61
|
}
|
|
93
|
-
|
|
94
|
-
function isEventSelected(ev: CalendarEvent): boolean {
|
|
95
|
-
const id = getRecurrenceInstanceMetadata(ev)?.instanceDate;
|
|
96
|
-
return ctx.selectedEventId === ev.id && ctx.selectedInstanceDate === id;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function formatEventTime(ev: CalendarEvent, date: CalendarDateTime): string {
|
|
100
|
-
if (ev.allDay) {
|
|
101
|
-
if (isSingleDayAllDay(ev.timeRange)) {
|
|
102
|
-
return config.locale.allDayEvent;
|
|
103
|
-
}
|
|
104
|
-
const startStr = formatDateTime(ev.timeRange.start, { locale: config.locale.code, dateStyle: 'short' });
|
|
105
|
-
const endStr = formatDateTime(addDays(ev.timeRange.end, -1), { locale: config.locale.code, dateStyle: 'short' });
|
|
106
|
-
return `${config.locale.allDayEvent} (${startStr} \u2013 ${endStr})`;
|
|
107
|
-
}
|
|
108
|
-
const isFirst = isSameDay(ev.timeRange.start, date);
|
|
109
|
-
const isLast = isSameDay(ev.timeRange.end, date);
|
|
110
|
-
const startTime = toTimeStr(ev.timeRange.start);
|
|
111
|
-
const endTime = toTimeStr(ev.timeRange.end);
|
|
112
|
-
if (isFirst && isLast) return `${startTime} \u2013 ${endTime}`;
|
|
113
|
-
if (isFirst) return `${config.locale.timeFrom} ${startTime}`;
|
|
114
|
-
if (isLast) return `${config.locale.timeUntil} ${endTime}`;
|
|
115
|
-
return config.locale.allDayEvent;
|
|
116
|
-
}
|
|
117
62
|
</script>
|
|
118
63
|
|
|
119
|
-
<div class="agenda-view">
|
|
120
|
-
{#if
|
|
64
|
+
<div class="agenda-view" bind:this={scrollEl}>
|
|
65
|
+
{#if agenda.empty}
|
|
121
66
|
<div class="agenda-view__empty">{config.locale.noEvents}</div>
|
|
122
67
|
{:else}
|
|
123
|
-
{#
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
</span>
|
|
68
|
+
{#if agenda.offsetTop > 0}
|
|
69
|
+
<div class="agenda-view__spacer" style:height={`${agenda.offsetTop}px`} aria-hidden="true"></div>
|
|
70
|
+
{/if}
|
|
71
|
+
{#each agenda.rows as row (row.key)}
|
|
72
|
+
{#if row.kind === 'header'}
|
|
73
|
+
<div class="agenda-view__row agenda-view__row--header{row.isToday ? ' agenda-view__row--today' : ''}">
|
|
74
|
+
<span class="agenda-view__date-number">{row.dayOfMonth}</span>
|
|
130
75
|
<div class="agenda-view__date-text">
|
|
131
|
-
<span class="agenda-view__date-weekday">
|
|
132
|
-
|
|
133
|
-
</span>
|
|
134
|
-
<span class="agenda-view__date-full">
|
|
135
|
-
{formatDateTime(group.date, { locale: config.locale.code, dateStyle: 'long' }).replace(/\d+\.?\s*/, '')}
|
|
136
|
-
</span>
|
|
76
|
+
<span class="agenda-view__date-weekday">{row.weekday}</span>
|
|
77
|
+
<span class="agenda-view__date-full">{row.dateFull}</span>
|
|
137
78
|
</div>
|
|
138
79
|
</div>
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
</div>
|
|
152
|
-
</div>
|
|
80
|
+
{:else}
|
|
81
|
+
<AgendaEvent
|
|
82
|
+
event={row.event}
|
|
83
|
+
timeLabel={row.timeLabel}
|
|
84
|
+
category={row.category}
|
|
85
|
+
isSelected={row.isSelected}
|
|
86
|
+
instanceDate={row.instanceDate ?? undefined}
|
|
87
|
+
onEntryMouseDown={handleMouseDown}
|
|
88
|
+
onEntryClick={handleEventClick}
|
|
89
|
+
onEntryDoubleClick={handleEventDoubleClick}
|
|
90
|
+
/>
|
|
91
|
+
{/if}
|
|
153
92
|
{/each}
|
|
93
|
+
{#if agenda.offsetBottom > 0}
|
|
94
|
+
<div class="agenda-view__spacer" style:height={`${agenda.offsetBottom}px`} aria-hidden="true"></div>
|
|
95
|
+
{/if}
|
|
154
96
|
{/if}
|
|
155
97
|
</div>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AgendaWindow } from '@bimetal/calendar-headless';
|
|
2
2
|
type $$ComponentProps = {
|
|
3
|
-
|
|
3
|
+
agenda: AgendaWindow;
|
|
4
|
+
setViewport: (scrollTop: number, viewportHeight: number) => void;
|
|
4
5
|
};
|
|
5
6
|
declare const AgendaView: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
6
7
|
type AgendaView = ReturnType<typeof AgendaView>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgendaView.svelte.d.ts","sourceRoot":"","sources":["../../../src/views/agenda/AgendaView.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AgendaView.svelte.d.ts","sourceRoot":"","sources":["../../../src/views/agenda/AgendaView.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAK9D,KAAK,gBAAgB,GAAI;IACtB,MAAM,EAAE,YAAY,CAAC;IACrB,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,KAAK,IAAI,CAAC;CAClE,CAAC;AAyFJ,QAAA,MAAM,UAAU,sDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import type { CalendarEvent } from '@bimetal/calendar-core';
|
|
3
3
|
import { getRecurrenceInstanceMetadata } from '@bimetal/calendar-core';
|
|
4
4
|
import { getEventSlots, toTimeStr } from '../../binding/index.js';
|
|
5
|
+
import { probeRender } from '@bimetal/svelte';
|
|
5
6
|
|
|
6
7
|
let {
|
|
7
8
|
ev,
|
|
@@ -23,6 +24,11 @@
|
|
|
23
24
|
const slotStyleStr = $derived(slots.style
|
|
24
25
|
? Object.entries(slots.style).map(([k, v]) => `${k.replace(/[A-Z]/g, m => '-' + m.toLowerCase())}: ${v}`).join('; ')
|
|
25
26
|
: '');
|
|
27
|
+
|
|
28
|
+
// v0.30 Slice 3 perf probe: re-runs (post-DOM) ONLY when this entry's DOM-driving values change.
|
|
29
|
+
// `isSelected` is a per-leaf prop (so a selection elsewhere doesn't touch this leaf) and `ev` is
|
|
30
|
+
// the Slice-1 ref-stable entity (stable across snapshots unless THIS event changed).
|
|
31
|
+
$effect(() => { void renderedTitle; void slotStyleStr; void extraClass; void isSelected; void ev; probeRender(ev.id); });
|
|
26
32
|
</script>
|
|
27
33
|
|
|
28
34
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimedEntry.svelte.d.ts","sourceRoot":"","sources":["../../../src/views/month/TimedEntry.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"TimedEntry.svelte.d.ts","sourceRoot":"","sources":["../../../src/views/month/TimedEntry.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAK3D,KAAK,gBAAgB,GAAI;IACtB,EAAE,EAAE,aAAa,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;IAC1C,YAAY,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACzE,kBAAkB,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAChF,CAAC;AA8CJ,QAAA,MAAM,UAAU,sDAAwC,CAAC;AACzD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAChD,eAAe,UAAU,CAAC"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { getCalendarContext, getCalendarConfig, toTimeStr, buildDragInfo, getEventSlots } from '../../binding/index.js';
|
|
5
5
|
import type { DragInfo } from '../../binding/index.js';
|
|
6
6
|
import { createClickIntent, writeCalendarDragData, installTransparentDragImage } from '@bimetal/calendar-headless';
|
|
7
|
+
import { probeRender } from '@bimetal/svelte';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Layout-Position eines Termins (Pilot-Direktive 2026-06-21). Zwei
|
|
@@ -132,6 +133,18 @@
|
|
|
132
133
|
? Object.entries(slots.style).map(([k, v]) => `${k.replace(/[A-Z]/g, m => '-' + m.toLowerCase())}: ${v}`).join('; ')
|
|
133
134
|
: '');
|
|
134
135
|
const style = $derived(slotStyleStr ? `${baseStyle} ${slotStyleStr}` : baseStyle);
|
|
136
|
+
|
|
137
|
+
// The week timed-layout rebuilds its `item`/`event` wrappers every snapshot, so the raw `event`
|
|
138
|
+
// prop ref churns even for unchanged events. Route the id through an equality-gated `$derived` so
|
|
139
|
+
// the probe below tracks the STABLE id string, not the churning prop ref (the DOM-driving
|
|
140
|
+
// deriveds `style`/`renderedTitle`/… already gate the same churn to their stable values).
|
|
141
|
+
const eventId = $derived(event.id);
|
|
142
|
+
|
|
143
|
+
// v0.30 Slice 3 perf probe: re-runs (post-DOM) ONLY when this event's DOM-driving deriveds
|
|
144
|
+
// change. `style` folds in all `layout` geometry (top/height/left/width fractions), and
|
|
145
|
+
// `isSelected` is equality-gated — so a selection or geometry change elsewhere does NOT
|
|
146
|
+
// re-run unchanged events, proving fine-grained reactivity even with the context selection read.
|
|
147
|
+
$effect(() => { void style; void isSelected; void renderedTitle; void timeLabel; void duration; probeRender(eventId); });
|
|
135
148
|
</script>
|
|
136
149
|
|
|
137
150
|
<div
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimeEvent.svelte.d.ts","sourceRoot":"","sources":["../../../src/views/week/TimeEvent.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"TimeEvent.svelte.d.ts","sourceRoot":"","sources":["../../../src/views/week/TimeEvent.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAQ5E;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AACF,KAAK,gBAAgB,GAAI;IACtB,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,EAAE,eAAe,CAAC;IACxB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AA6JJ,QAAA,MAAM,SAAS,sDAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bimetal/calendar-svelte-components",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.0",
|
|
4
4
|
"description": "Default Svelte 5 calendar UI components",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"svelte": "./dist/index.js",
|
|
@@ -27,13 +27,13 @@
|
|
|
27
27
|
"prepublishOnly": "npm run build"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@bimetal/svelte": "^0.
|
|
31
|
-
"@bimetal/core": "^0.
|
|
32
|
-
"@bimetal/calendar-core": "^0.
|
|
33
|
-
"@bimetal/calendar-data": "^0.
|
|
34
|
-
"@bimetal/calendar-headless": "^0.
|
|
35
|
-
"@bimetal/calendar-rules": "^0.
|
|
36
|
-
"@bimetal/calendar-themes": "^0.
|
|
30
|
+
"@bimetal/svelte": "^0.30.0",
|
|
31
|
+
"@bimetal/core": "^0.30.0",
|
|
32
|
+
"@bimetal/calendar-core": "^0.30.0",
|
|
33
|
+
"@bimetal/calendar-data": "^0.30.0",
|
|
34
|
+
"@bimetal/calendar-headless": "^0.30.0",
|
|
35
|
+
"@bimetal/calendar-rules": "^0.30.0",
|
|
36
|
+
"@bimetal/calendar-themes": "^0.30.0"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"svelte": "^5.46.4"
|