{
	"$schema": "https://shadcn-svelte.com/schema/registry-item.json",
	"name": "big-calendar",
	"title": "Big Calendar",
	"type": "registry:ui",
	"description": "A month, week, day, and agenda scheduling surface with exclusive event end dates, fullscreen navigation, and height-aware month rows.",
	"dependencies": [
		"@internationalized/date@^3.12.2",
		"@lucide/svelte@^1.28.0"
	],
	"registryDependencies": [
		"./status-badge.json",
		"button",
		"calendar",
		"card",
		"popover",
		"skeleton",
		"toggle-group"
	],
	"files": [
		{
			"content": "<script lang=\"ts\" generics=\"TData = unknown\">\n\timport { cn } from '$UTILS$.js';\n\n\timport type { BigCalendarEvent } from './big-calendar-types.js';\n\n\timport { isSameDay } from './big-calendar-date.js';\n\timport BigCalendarEventView from './big-calendar-event.svelte';\n\timport { buildAgendaGroups } from './big-calendar-layout.js';\n\timport { formatFullDayLabel } from './big-calendar-presentation.js';\n\n\tlet {\n\t\temptyLabel,\n\t\tend,\n\t\tevents,\n\t\tlocale,\n\t\tonEventClick,\n\t\tstart,\n\t\ttoday\n\t}: {\n\t\temptyLabel: string;\n\t\t/** Exclusive, matching `BigCalendarEvent`. */\n\t\tend: Date;\n\t\tevents: BigCalendarEvent<TData>[];\n\t\tlocale: string;\n\t\tonEventClick?: (event: BigCalendarEvent<TData>) => void;\n\t\tstart: Date;\n\t\ttoday: Date;\n\t} = $props();\n\n\tlet groups = $derived(buildAgendaGroups(events, start, end));\n</script>\n\n{#if groups.length === 0}\n\t<div class=\"flex min-h-48 flex-col items-center justify-center gap-1 px-6 py-10 text-center\">\n\t\t<p class=\"font-medium\">{emptyLabel}</p>\n\t\t<p class=\"max-w-sm text-sm text-muted-foreground\">\n\t\t\tNothing is scheduled in this range. Step forward or pick another date.\n\t\t</p>\n\t</div>\n{:else}\n\t<div class=\"divide-y\">\n\t\t{#each groups as group (group.day.getTime())}\n\t\t\t<div class=\"grid gap-1 px-3 py-2 sm:grid-cols-[12rem_1fr] sm:gap-3\">\n\t\t\t\t<div\n\t\t\t\t\tclass={cn(\n\t\t\t\t\t\t'pt-1.5 text-sm font-medium',\n\t\t\t\t\t\tisSameDay(group.day, today) && 'text-primary'\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t{formatFullDayLabel(group.day, locale)}\n\t\t\t\t</div>\n\t\t\t\t<div class=\"flex min-w-0 flex-col\">\n\t\t\t\t\t{#each group.events as event (event.id)}\n\t\t\t\t\t\t<BigCalendarEventView variant=\"row\" {event} {locale} {onEventClick} />\n\t\t\t\t\t{/each}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t{/each}\n\t</div>\n{/if}\n",
			"type": "registry:file",
			"target": "big-calendar/big-calendar-agenda.svelte"
		},
		{
			"content": "import type { BigCalendarView, BigCalendarWeekday } from './big-calendar-types.js';\n\nexport const MINUTE_MS = 60 * 1000;\nexport const HOUR_MS = 60 * MINUTE_MS;\nexport const DAY_MS = 24 * HOUR_MS;\n\n/**\n * All arithmetic here runs in the viewer's local time zone, so an unparseable\n * or missing anchor would spread `NaN` through every column. Fall back to today.\n */\nexport function resolveCalendarDate(date: Date | undefined, fallback = new Date()): Date {\n\tif (!date || Number.isNaN(date.getTime())) return new Date(fallback);\n\treturn new Date(date);\n}\n\nexport function startOfDay(date: Date): Date {\n\treturn new Date(date.getFullYear(), date.getMonth(), date.getDate());\n}\n\nexport function addDays(date: Date, amount: number): Date {\n\tconst result = new Date(date);\n\tresult.setDate(result.getDate() + amount);\n\treturn result;\n}\n\nexport function addMonths(date: Date, amount: number): Date {\n\treturn new Date(date.getFullYear(), date.getMonth() + amount, 1);\n}\n\nexport function startOfMonth(date: Date): Date {\n\treturn new Date(date.getFullYear(), date.getMonth(), 1);\n}\n\nexport function startOfWeek(date: Date, weekStartsOn: BigCalendarWeekday): Date {\n\tconst result = startOfDay(date);\n\tresult.setDate(result.getDate() - ((result.getDay() - weekStartsOn + 7) % 7));\n\treturn result;\n}\n\nexport function isSameDay(a: Date, b: Date): boolean {\n\treturn (\n\t\ta.getFullYear() === b.getFullYear() &&\n\t\ta.getMonth() === b.getMonth() &&\n\t\ta.getDate() === b.getDate()\n\t);\n}\n\n/** Days between two local dates, ignoring the time of day and DST-shortened days. */\nexport function differenceInDays(later: Date, earlier: Date): number {\n\treturn Math.round((startOfDay(later).getTime() - startOfDay(earlier).getTime()) / DAY_MS);\n}\n\nexport function buildDayRange(start: Date, count: number): Date[] {\n\tconst days: Date[] = [];\n\tfor (let index = 0; index < count; index += 1) days.push(addDays(startOfDay(start), index));\n\treturn days;\n}\n\nexport interface CalendarRange {\n\t/** Exclusive, matching `BigCalendarEvent`. */\n\tend: Date;\n\tstart: Date;\n}\n\n/**\n * The range the view claims to be showing. The month view draws whole weeks, so\n * its rendered grid is wider than this — see `buildMonthWeeks`.\n */\nexport function getPeriodRange(\n\tview: BigCalendarView,\n\tanchor: Date,\n\tweekStartsOn: BigCalendarWeekday,\n\tagendaLength: number\n): CalendarRange {\n\tif (view === 'month') {\n\t\tconst start = startOfMonth(anchor);\n\t\treturn { start, end: addMonths(start, 1) };\n\t}\n\tif (view === 'week') {\n\t\tconst start = startOfWeek(anchor, weekStartsOn);\n\t\treturn { start, end: addDays(start, 7) };\n\t}\n\tif (view === 'day') {\n\t\tconst start = startOfDay(anchor);\n\t\treturn { start, end: addDays(start, 1) };\n\t}\n\tconst start = startOfDay(anchor);\n\treturn { start, end: addDays(start, Math.max(1, agendaLength)) };\n}\n\n/** Days actually drawn, which for the month view is the surrounding whole weeks. */\nexport function getVisibleDays(\n\tview: BigCalendarView,\n\tanchor: Date,\n\tweekStartsOn: BigCalendarWeekday,\n\tagendaLength: number\n): Date[] {\n\tif (view === 'month') return buildMonthWeeks(anchor, weekStartsOn).flat();\n\tconst { start, end } = getPeriodRange(view, anchor, weekStartsOn, agendaLength);\n\treturn buildDayRange(start, differenceInDays(end, start));\n}\n\n/**\n * Whole weeks covering the anchor's month. The row count follows the month\n * rather than being fixed at six, so a short month does not draw a trailing\n * week that belongs entirely to the next one.\n */\nexport function buildMonthWeeks(anchor: Date, weekStartsOn: BigCalendarWeekday): Date[][] {\n\tconst monthStart = startOfMonth(anchor);\n\tconst gridStart = startOfWeek(monthStart, weekStartsOn);\n\tconst monthEnd = addMonths(monthStart, 1);\n\tconst weekCount = Math.ceil(differenceInDays(monthEnd, gridStart) / 7);\n\tconst weeks: Date[][] = [];\n\tfor (let week = 0; week < weekCount; week += 1) {\n\t\tweeks.push(buildDayRange(addDays(gridStart, week * 7), 7));\n\t}\n\treturn weeks;\n}\n\nexport function shiftCalendarDate(\n\tview: BigCalendarView,\n\tanchor: Date,\n\tsteps: number,\n\tagendaLength: number\n): Date {\n\tif (view === 'month') return addMonths(anchor, steps);\n\tif (view === 'week') return addDays(anchor, steps * 7);\n\tif (view === 'day') return addDays(anchor, steps);\n\treturn addDays(anchor, steps * Math.max(1, agendaLength));\n}\n\n/** Minutes from local midnight, used to place blocks in the hour grid. */\nexport function minutesSinceMidnight(date: Date, day: Date): number {\n\treturn (date.getTime() - startOfDay(day).getTime()) / MINUTE_MS;\n}\n",
			"type": "registry:file",
			"target": "big-calendar/big-calendar-date.ts"
		},
		{
			"content": "<script lang=\"ts\" generics=\"TData = unknown\">\n\timport { cn } from '$UTILS$.js';\n\n\timport type { BigCalendarEvent } from './big-calendar-types.js';\n\n\timport {\n\t\tdescribeEvent,\n\t\tformatEventTime,\n\t\tgetContinuationLabel,\n\t\tgetEventDotClass,\n\t\tgetEventToneClass\n\t} from './big-calendar-presentation.js';\n\n\tlet {\n\t\tclass: className,\n\t\tcontinuesAfter = false,\n\t\tcontinuesBefore = false,\n\t\tevent,\n\t\tlocale,\n\t\tonEventClick,\n\t\tvariant\n\t}: {\n\t\tclass?: string;\n\t\tcontinuesAfter?: boolean;\n\t\tcontinuesBefore?: boolean;\n\t\tevent: BigCalendarEvent<TData>;\n\t\tlocale: string;\n\t\tonEventClick?: (event: BigCalendarEvent<TData>) => void;\n\t\t/** `band` spans days, `block` fills an hour-grid slot, `row` is a list line. */\n\t\tvariant: 'band' | 'block' | 'row';\n\t} = $props();\n\n\tlet time = $derived(formatEventTime(event, locale));\n\tlet continuation = $derived(getContinuationLabel(continuesBefore, continuesAfter));\n\tlet label = $derived(\n\t\t[describeEvent(event, locale), continuation].filter(Boolean).join('. ')\n\t);\n\tlet interactive = $derived(Boolean(onEventClick));\n</script>\n\n<svelte:element\n\tthis={interactive ? 'button' : 'div'}\n\ttype={interactive ? 'button' : undefined}\n\trole={interactive ? undefined : 'note'}\n\taria-label={label}\n\ttitle={label}\n\tonclick={onEventClick ? () => onEventClick(event) : undefined}\n\tclass={cn(\n\t\t'w-full min-w-0 overflow-hidden text-left text-xs leading-tight',\n\t\tinteractive &&\n\t\t\t'cursor-pointer transition-opacity hover:opacity-85 focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50',\n\t\tvariant === 'row'\n\t\t\t? 'flex items-start gap-2 rounded-md px-2 py-1.5 hover:bg-accent'\n\t\t\t: getEventToneClass(event.tone),\n\t\tvariant === 'band' && 'flex h-5 items-center gap-1 rounded-sm px-1.5 font-medium',\n\t\tvariant === 'band' && continuesBefore && 'rounded-l-none',\n\t\tvariant === 'band' && continuesAfter && 'rounded-r-none',\n\t\tvariant === 'block' && 'flex h-full flex-col rounded-sm px-1.5 py-0.5',\n\t\tclassName\n\t)}\n>\n\t{#if variant === 'row'}\n\t\t<span class={cn('mt-1 size-2 shrink-0 rounded-full', getEventDotClass(event.tone))}></span>\n\t\t<span class=\"w-36 shrink-0 whitespace-nowrap text-muted-foreground tabular-nums\">{time}</span>\n\t\t<!-- Stacked rather than a third column: the row sits inside a container of\n\t\t     unknown width, and a viewport breakpoint would drop the context at the\n\t\t     widths this list is actually rendered at. -->\n\t\t<span class=\"min-w-0 flex-1\">\n\t\t\t<span class=\"block truncate font-medium\">{event.title}</span>\n\t\t\t{#if event.description}\n\t\t\t\t<span class=\"block truncate text-muted-foreground\">{event.description}</span>\n\t\t\t{/if}\n\t\t</span>\n\t{:else if variant === 'band'}\n\t\t{#if continuesBefore}<span aria-hidden=\"true\">‹</span>{/if}\n\t\t<span class=\"min-w-0 flex-1 truncate\">{event.title}</span>\n\t\t{#if continuesAfter}<span aria-hidden=\"true\">›</span>{/if}\n\t{:else}\n\t\t<span class=\"truncate font-medium\">{event.title}</span>\n\t\t<span class=\"truncate opacity-80\">{time}</span>\n\t{/if}\n</svelte:element>\n",
			"type": "registry:file",
			"target": "big-calendar/big-calendar-event.svelte"
		},
		{
			"content": "import type {\n\tBigCalendarAgendaGroup,\n\tBigCalendarBlock,\n\tBigCalendarDayRow,\n\tBigCalendarEvent,\n\tBigCalendarSegment\n} from './big-calendar-types.js';\n\nimport {\n\taddDays,\n\tDAY_MS,\n\tdifferenceInDays,\n\tminutesSinceMidnight,\n\tstartOfDay\n} from './big-calendar-date.js';\n\n/** Shortest span a normalized event may have, so a point in time still draws. */\nconst MIN_DURATION_MS = 15 * 60 * 1000;\n\nfunction clamp(value: number, min: number, max: number): number {\n\treturn Math.min(Math.max(value, min), max);\n}\n\n/**\n * Events arrive from callers and ultimately from upstream systems, so a missing\n * or reversed range is expected rather than exceptional. Drop what cannot be\n * placed at all and repair what can, instead of laying out `NaN`.\n */\nexport function normalizeEvents<TData>(events: BigCalendarEvent<TData>[]): BigCalendarEvent<TData>[] {\n\tconst normalized: BigCalendarEvent<TData>[] = [];\n\tfor (const event of events) {\n\t\tconst start = event.start instanceof Date ? event.start.getTime() : Number.NaN;\n\t\tconst end = event.end instanceof Date ? event.end.getTime() : Number.NaN;\n\t\tif (Number.isNaN(start)) continue;\n\t\tconst safeEnd = Number.isNaN(end) || end <= start ? start + MIN_DURATION_MS : end;\n\t\tnormalized.push({ ...event, start: new Date(start), end: new Date(safeEnd) });\n\t}\n\treturn sortEvents(normalized);\n}\n\n/** Earliest first, then longest first, so wider bands settle into the top lanes. */\nexport function sortEvents<TData>(events: BigCalendarEvent<TData>[]): BigCalendarEvent<TData>[] {\n\treturn [...events].sort((a, b) => {\n\t\tconst byStart = a.start.getTime() - b.start.getTime();\n\t\tif (byStart !== 0) return byStart;\n\t\tconst byDuration =\n\t\t\tb.end.getTime() - b.start.getTime() - (a.end.getTime() - a.start.getTime());\n\t\tif (byDuration !== 0) return byDuration;\n\t\treturn a.title.localeCompare(b.title);\n\t});\n}\n\nexport function overlapsRange<TData>(event: BigCalendarEvent<TData>, start: Date, end: Date): boolean {\n\treturn event.start.getTime() < end.getTime() && event.end.getTime() > start.getTime();\n}\n\n/**\n * Whether an event belongs in a day-spanning band rather than the hour grid.\n * A timed event that crosses midnight cannot be drawn as one block in a single\n * day column, so it joins the all-day lane alongside explicitly all-day events.\n */\nexport function isAllDayEvent<TData>(event: BigCalendarEvent<TData>): boolean {\n\tif (event.allDay) return true;\n\tif (event.end.getTime() - event.start.getTime() >= DAY_MS) return true;\n\treturn !isSameLocalDay(event.start, new Date(event.end.getTime() - 1));\n}\n\nfunction isSameLocalDay(a: Date, b: Date): boolean {\n\treturn startOfDay(a).getTime() === startOfDay(b).getTime();\n}\n\n/**\n * Lay events out as horizontal bands across a row of days, stacking overlapping\n * bands into lanes. Used for both a month week row and the all-day lane of the\n * week and day grids. `maxLanes` of `null` keeps every lane.\n */\nexport function packDayRow<TData>(\n\tdays: Date[],\n\tevents: BigCalendarEvent<TData>[],\n\tmaxLanes: null | number = null\n): BigCalendarDayRow<TData> {\n\tconst overflowByColumn = days.map(() => 0);\n\tconst segments: BigCalendarSegment<TData>[] = [];\n\tif (days.length === 0) return { days, segments, overflowByColumn, laneCount: 0 };\n\n\tconst rowStart = startOfDay(days[0]);\n\tconst rowEnd = addDays(startOfDay(days[days.length - 1]), 1);\n\tconst lanes: boolean[][] = [];\n\tlet laneCount = 0;\n\n\tfor (const event of sortEvents(events)) {\n\t\tif (!overlapsRange(event, rowStart, rowEnd)) continue;\n\n\t\tconst columnStart = clamp(differenceInDays(event.start, rowStart), 0, days.length - 1);\n\t\t// `end` is exclusive, so the last covered day is the one holding `end - 1ms`.\n\t\tconst lastCovered = new Date(event.end.getTime() - 1);\n\t\tconst columnEnd = clamp(differenceInDays(lastCovered, rowStart), columnStart, days.length - 1);\n\n\t\tlet lane = lanes.findIndex((occupied) => {\n\t\t\tfor (let column = columnStart; column <= columnEnd; column += 1) {\n\t\t\t\tif (occupied[column]) return false;\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\t\tif (lane === -1) {\n\t\t\tlane = lanes.length;\n\t\t\tlanes.push(days.map(() => false));\n\t\t}\n\t\tfor (let column = columnStart; column <= columnEnd; column += 1) lanes[lane][column] = true;\n\n\t\tif (maxLanes !== null && lane >= maxLanes) {\n\t\t\tfor (let column = columnStart; column <= columnEnd; column += 1) overflowByColumn[column] += 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tlaneCount = Math.max(laneCount, lane + 1);\n\t\tsegments.push({\n\t\t\tcolumnStart,\n\t\t\tcontinuesAfter: event.end.getTime() > rowEnd.getTime(),\n\t\t\tcontinuesBefore: event.start.getTime() < rowStart.getTime(),\n\t\t\tevent,\n\t\t\tkey: `${event.id}:${rowStart.getTime()}:${columnStart}`,\n\t\t\tlane,\n\t\t\tspan: columnEnd - columnStart + 1\n\t\t});\n\t}\n\n\treturn { days, segments, overflowByColumn, laneCount };\n}\n\n/**\n * Vertical metrics of a month week row, in rem. They mirror the row's grid\n * template in `big-calendar-month.svelte`; change both together.\n */\nexport const MONTH_ROW_REM = {\n\theader: 1.75,\n\tlane: 1.375,\n\tgap: 0.125,\n\tmore: 1,\n\tpaddingBottom: 0.25\n} as const;\n\n/**\n * Lanes a filled month row can draw at the height it was given. Every lane is\n * shown when they all fit; otherwise room is kept for the \"+N more\" line, and\n * at least one lane always shows so a short row still hints at its contents.\n */\nexport function fitMonthLanes(rowHeightRem: number, laneCount: number): number {\n\tconst { header, lane, gap, more, paddingBottom } = MONTH_ROW_REM;\n\t// The header, the \"+N more\" row and the trailing filler each add a gap.\n\tconst room = rowHeightRem - header - paddingBottom - 2 * gap;\n\tconst fitsAll = Math.floor((room + 1e-6) / (lane + gap));\n\tif (laneCount <= fitsAll) return laneCount;\n\treturn Math.max(1, Math.floor((room - more + 1e-6) / (lane + gap)));\n}\n\n/** Every event touching a day, in display order. Used by the \"+N more\" popover. */\nexport function getEventsForDay<TData>(\n\tday: Date,\n\tevents: BigCalendarEvent<TData>[]\n): BigCalendarEvent<TData>[] {\n\tconst dayStart = startOfDay(day);\n\tconst dayEnd = addDays(dayStart, 1);\n\treturn sortEvents(events.filter((event) => overlapsRange(event, dayStart, dayEnd)));\n}\n\n/**\n * Place timed events inside one day column of the hour grid, splitting mutually\n * overlapping events into side-by-side columns. Ratios are relative to the\n * visible hour window so the caller owns the pixel height.\n */\nexport function buildTimeBlocks<TData>(\n\tday: Date,\n\tevents: BigCalendarEvent<TData>[],\n\tstartHour: number,\n\tendHour: number\n): BigCalendarBlock<TData>[] {\n\tconst windowStart = startHour * 60;\n\tconst windowEnd = endHour * 60;\n\tconst windowLength = windowEnd - windowStart;\n\tif (windowLength <= 0) return [];\n\n\tconst placed: Array<{\n\t\tblock: BigCalendarBlock<TData>;\n\t\tendMinutes: number;\n\t\tstartMinutes: number;\n\t}> = [];\n\n\tfor (const event of sortEvents(events)) {\n\t\tif (isAllDayEvent(event)) continue;\n\t\tconst rawStart = minutesSinceMidnight(event.start, day);\n\t\tconst rawEnd = minutesSinceMidnight(event.end, day);\n\t\tif (rawEnd <= windowStart || rawStart >= windowEnd) continue;\n\n\t\tconst startMinutes = clamp(rawStart, windowStart, windowEnd);\n\t\tconst endMinutes = clamp(rawEnd, windowStart, windowEnd);\n\t\tplaced.push({\n\t\t\tblock: {\n\t\t\t\tcolumn: 0,\n\t\t\t\tcolumnCount: 1,\n\t\t\t\tcontinuesAfter: rawEnd > windowEnd,\n\t\t\t\tcontinuesBefore: rawStart < windowStart,\n\t\t\t\tevent,\n\t\t\t\theightRatio: (endMinutes - startMinutes) / windowLength,\n\t\t\t\tkey: `${event.id}:${startOfDay(day).getTime()}`,\n\t\t\t\ttopRatio: (startMinutes - windowStart) / windowLength\n\t\t\t},\n\t\t\tendMinutes,\n\t\t\tstartMinutes\n\t\t});\n\t}\n\n\t// Split into clusters of transitively overlapping blocks; each cluster is\n\t// divided into as many columns as its widest pile-up requires.\n\tlet cluster: typeof placed = [];\n\tlet clusterEnd = Number.NEGATIVE_INFINITY;\n\tconst flush = (): void => {\n\t\tif (cluster.length === 0) return;\n\t\tconst columnEnds: number[] = [];\n\t\tfor (const item of cluster) {\n\t\t\tlet column = columnEnds.findIndex((end) => end <= item.startMinutes);\n\t\t\tif (column === -1) {\n\t\t\t\tcolumn = columnEnds.length;\n\t\t\t\tcolumnEnds.push(item.endMinutes);\n\t\t\t} else {\n\t\t\t\tcolumnEnds[column] = item.endMinutes;\n\t\t\t}\n\t\t\titem.block.column = column;\n\t\t}\n\t\tfor (const item of cluster) item.block.columnCount = columnEnds.length;\n\t\tcluster = [];\n\t};\n\n\tfor (const item of placed) {\n\t\tif (item.startMinutes >= clusterEnd) {\n\t\t\tflush();\n\t\t\tclusterEnd = item.endMinutes;\n\t\t} else {\n\t\t\tclusterEnd = Math.max(clusterEnd, item.endMinutes);\n\t\t}\n\t\tcluster.push(item);\n\t}\n\tflush();\n\n\treturn placed.map((item) => item.block);\n}\n\n/**\n * Group events by the days they cover within the range. An event spanning three\n * days appears under each of them, so scanning one day tells the whole story.\n */\nexport function buildAgendaGroups<TData>(\n\tevents: BigCalendarEvent<TData>[],\n\tstart: Date,\n\tend: Date\n): BigCalendarAgendaGroup<TData>[] {\n\tconst groups: BigCalendarAgendaGroup<TData>[] = [];\n\tconst dayCount = differenceInDays(end, start);\n\tfor (let index = 0; index < dayCount; index += 1) {\n\t\tconst day = addDays(startOfDay(start), index);\n\t\tconst dayEvents = getEventsForDay(day, events);\n\t\tif (dayEvents.length > 0) groups.push({ day, events: dayEvents });\n\t}\n\treturn groups;\n}\n",
			"type": "registry:file",
			"target": "big-calendar/big-calendar-layout.ts"
		},
		{
			"content": "<script lang=\"ts\" generics=\"TData = unknown\">\n\timport * as Popover from '$UI$/popover/index.js';\n\timport { cn } from '$UTILS$.js';\n\n\timport type {\n\t\tBigCalendarEvent,\n\t\tBigCalendarSlot,\n\t\tBigCalendarWeekday\n\t} from './big-calendar-types.js';\n\n\timport { addDays, buildMonthWeeks, isSameDay, startOfDay } from './big-calendar-date.js';\n\timport BigCalendarEventView from './big-calendar-event.svelte';\n\timport {\n\t\tfitMonthLanes,\n\t\tgetEventsForDay,\n\t\tMONTH_ROW_REM,\n\t\tpackDayRow\n\t} from './big-calendar-layout.js';\n\timport {\n\t\tformatFullDayLabel,\n\t\tformatWeekdayLabel,\n\t\tVIEW_LABELS\n\t} from './big-calendar-presentation.js';\n\n\tlet {\n\t\tanchor,\n\t\tevents,\n\t\tfill,\n\t\tlocale,\n\t\tmaxEventsPerDay,\n\t\tonEventClick,\n\t\tonSlotClick,\n\t\ttoday,\n\t\tweekStartsOn\n\t}: {\n\t\tanchor: Date;\n\t\tevents: BigCalendarEvent<TData>[];\n\t\t/**\n\t\t * Share the height of the container between the week rows, and show as\n\t\t * many lanes as each row's height fits instead of `maxEventsPerDay`.\n\t\t */\n\t\tfill: boolean;\n\t\tlocale: string;\n\t\t/** Lane budget for unfilled rows, and for filled rows until measured. */\n\t\tmaxEventsPerDay: number;\n\t\tonEventClick?: (event: BigCalendarEvent<TData>) => void;\n\t\tonSlotClick?: (slot: BigCalendarSlot) => void;\n\t\ttoday: Date;\n\t\tweekStartsOn: BigCalendarWeekday;\n\t} = $props();\n\n\tlet weeks = $derived(buildMonthWeeks(anchor, weekStartsOn));\n\t/** Measured in the browser only; unmeasured rows fall back to `maxEventsPerDay`. */\n\tlet rowHeights = $state<number[]>([]);\n\tlet rows = $derived(\n\t\tweeks.map((week, index) => {\n\t\t\tconst height = rowHeights[index];\n\t\t\tif (!fill || !height) {\n\t\t\t\tconst row = packDayRow(week, events, maxEventsPerDay);\n\t\t\t\treturn { ...row, lanes: maxEventsPerDay };\n\t\t\t}\n\t\t\tconst rootFontSize = parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;\n\t\t\tconst lanes = fitMonthLanes(height / rootFontSize, packDayRow(week, events).laneCount);\n\t\t\treturn { ...packDayRow(week, events, lanes), lanes: Math.max(1, lanes) };\n\t\t})\n\t);\n\tlet weekdayLabels = $derived(weeks[0].map((day) => formatWeekdayLabel(day, locale)));\n\tlet anchorMonth = $derived(anchor.getMonth());\n\n\tfunction selectDay(day: Date): void {\n\t\tonSlotClick?.({ start: startOfDay(day), end: addDays(startOfDay(day), 1) });\n\t}\n</script>\n\n<div class={cn('flex flex-col', fill && 'flex-1')} aria-label={`${VIEW_LABELS.month} view`}>\n\t<div class=\"grid grid-cols-7 border-b bg-muted/40\">\n\t\t{#each weekdayLabels as label, index (index)}\n\t\t\t<div class=\"px-2 py-1.5 text-center text-xs font-medium text-muted-foreground\">\n\t\t\t\t{label}\n\t\t\t</div>\n\t\t{/each}\n\t</div>\n\n\t{#each rows as row, weekIndex (weekIndex)}\n\t\t<!-- A filled row takes its height from the container, never its lanes, so\n\t\t\t measuring it cannot feed back into how many lanes it draws. -->\n\t\t<div\n\t\t\tclass={cn('relative border-b last:border-b-0', fill && 'min-h-28 flex-1 overflow-hidden')}\n\t\t\tbind:clientHeight={rowHeights[weekIndex]}\n\t\t>\n\t\t\t<!-- Day cells sit underneath so a band can span them without breaking borders. -->\n\t\t\t<div class=\"absolute inset-0 grid grid-cols-7\">\n\t\t\t\t{#each row.days as day (day.getTime())}\n\t\t\t\t\t{@const outside = day.getMonth() !== anchorMonth}\n\t\t\t\t\t{@const cellClass = cn(\n\t\t\t\t\t\t'border-r last:border-r-0',\n\t\t\t\t\t\toutside && 'bg-muted/30',\n\t\t\t\t\t\tisSameDay(day, today) && 'bg-primary/5'\n\t\t\t\t\t)}\n\t\t\t\t\t{#if onSlotClick}\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\taria-label={formatFullDayLabel(day, locale)}\n\t\t\t\t\t\t\tonclick={() => selectDay(day)}\n\t\t\t\t\t\t\tclass={cn(\n\t\t\t\t\t\t\t\tcellClass,\n\t\t\t\t\t\t\t\t'cursor-pointer hover:bg-accent/50 focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-inset focus-visible:ring-ring/50'\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t></button>\n\t\t\t\t\t{:else}\n\t\t\t\t\t\t<div class={cellClass}></div>\n\t\t\t\t\t{/if}\n\t\t\t\t{/each}\n\t\t\t</div>\n\n\t\t\t<div\n\t\t\t\tclass={cn(\n\t\t\t\t\t'pointer-events-none relative grid min-h-28 grid-cols-7',\n\t\t\t\t\tfill && 'h-full'\n\t\t\t\t)}\n\t\t\t\tstyle={`grid-template-rows: ${MONTH_ROW_REM.header}rem repeat(${row.lanes}, ${MONTH_ROW_REM.lane}rem) auto${\n\t\t\t\t\tfill ? ' 1fr' : ''\n\t\t\t\t}; row-gap: ${MONTH_ROW_REM.gap}rem; padding-bottom: ${MONTH_ROW_REM.paddingBottom}rem`}\n\t\t\t>\n\t\t\t\t{#each row.days as day, column (day.getTime())}\n\t\t\t\t\t{@const outside = day.getMonth() !== anchorMonth}\n\t\t\t\t\t<div\n\t\t\t\t\t\tclass=\"flex items-center justify-end px-1 pt-1\"\n\t\t\t\t\t\tstyle={`grid-column: ${column + 1}; grid-row: 1`}\n\t\t\t\t\t>\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tclass={cn(\n\t\t\t\t\t\t\t\t'inline-flex size-6 items-center justify-center rounded-full text-xs font-medium tabular-nums',\n\t\t\t\t\t\t\t\toutside && 'text-muted-foreground/60',\n\t\t\t\t\t\t\t\tisSameDay(day, today) && 'bg-primary text-primary-foreground'\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{day.getDate()}\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t{/each}\n\n\t\t\t\t{#each row.segments as segment (segment.key)}\n\t\t\t\t\t<div\n\t\t\t\t\t\tclass=\"pointer-events-auto min-w-0 px-1\"\n\t\t\t\t\t\tstyle={`grid-column: ${segment.columnStart + 1} / span ${segment.span}; grid-row: ${segment.lane + 2}`}\n\t\t\t\t\t>\n\t\t\t\t\t\t<BigCalendarEventView\n\t\t\t\t\t\t\tvariant=\"band\"\n\t\t\t\t\t\t\tevent={segment.event}\n\t\t\t\t\t\t\tcontinuesAfter={segment.continuesAfter}\n\t\t\t\t\t\t\tcontinuesBefore={segment.continuesBefore}\n\t\t\t\t\t\t\t{locale}\n\t\t\t\t\t\t\t{onEventClick}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t{/each}\n\n\t\t\t\t{#each row.days as day, column (day.getTime())}\n\t\t\t\t\t{#if row.overflowByColumn[column] > 0}\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclass=\"pointer-events-auto min-w-0 px-1\"\n\t\t\t\t\t\t\tstyle={`grid-column: ${column + 1}; grid-row: ${row.lanes + 2}`}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Popover.Root>\n\t\t\t\t\t\t\t\t<Popover.Trigger\n\t\t\t\t\t\t\t\t\tclass=\"w-full truncate rounded-sm px-1.5 text-left text-xs font-medium text-muted-foreground hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t+{row.overflowByColumn[column]} more\n\t\t\t\t\t\t\t\t</Popover.Trigger>\n\t\t\t\t\t\t\t\t<Popover.Content class=\"w-72 p-2\" align=\"start\">\n\t\t\t\t\t\t\t\t\t<p class=\"px-1 pb-1 text-sm font-medium\">\n\t\t\t\t\t\t\t\t\t\t{formatFullDayLabel(day, locale)}\n\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t\t<div class=\"flex flex-col gap-0.5\">\n\t\t\t\t\t\t\t\t\t\t{#each getEventsForDay(day, events) as event (event.id)}\n\t\t\t\t\t\t\t\t\t\t\t<BigCalendarEventView\n\t\t\t\t\t\t\t\t\t\t\t\tvariant=\"row\"\n\t\t\t\t\t\t\t\t\t\t\t\t{event}\n\t\t\t\t\t\t\t\t\t\t\t\t{locale}\n\t\t\t\t\t\t\t\t\t\t\t\t{onEventClick}\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t{/each}\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</Popover.Content>\n\t\t\t\t\t\t\t</Popover.Root>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t{/if}\n\t\t\t\t{/each}\n\t\t\t</div>\n\t\t</div>\n\t{/each}\n</div>\n",
			"type": "registry:file",
			"target": "big-calendar/big-calendar-month.svelte"
		},
		{
			"content": "import type {\n\tBigCalendarEvent,\n\tBigCalendarEventTone,\n\tBigCalendarView\n} from './big-calendar-types.js';\n\nimport { addDays, isSameDay, startOfDay } from './big-calendar-date.js';\nimport { isAllDayEvent } from './big-calendar-layout.js';\n\nexport const VIEW_LABELS: Record<BigCalendarView, string> = {\n\tagenda: 'Agenda',\n\tday: 'Day',\n\tmonth: 'Month',\n\tweek: 'Week'\n};\n\n/** Filled bands, used where the event is the whole affordance. */\nexport function getEventToneClass(tone: BigCalendarEventTone | undefined): string {\n\tif (tone === 'secondary') return 'bg-secondary text-secondary-foreground ring-1 ring-border';\n\tif (tone === 'accent') return 'bg-accent text-accent-foreground ring-1 ring-border';\n\tif (tone === 'muted') return 'bg-muted text-muted-foreground ring-1 ring-border';\n\tif (tone === 'destructive') return 'bg-destructive/15 text-destructive ring-1 ring-destructive/25';\n\tif (tone === 'success') return 'bg-success/15 text-success ring-1 ring-success/25';\n\tif (tone === 'warning') return 'bg-warning/15 text-warning ring-1 ring-warning/25';\n\treturn 'bg-primary text-primary-foreground';\n}\n\n/** The small dot in month chips and agenda rows, where text stays foreground-coloured. */\nexport function getEventDotClass(tone: BigCalendarEventTone | undefined): string {\n\tif (tone === 'secondary') return 'bg-secondary-foreground';\n\tif (tone === 'accent') return 'bg-accent-foreground';\n\tif (tone === 'muted') return 'bg-muted-foreground';\n\tif (tone === 'destructive') return 'bg-destructive';\n\tif (tone === 'success') return 'bg-success';\n\tif (tone === 'warning') return 'bg-warning';\n\treturn 'bg-primary';\n}\n\nfunction formatter(locale: string, options: Intl.DateTimeFormatOptions): Intl.DateTimeFormat {\n\treturn new Intl.DateTimeFormat(locale, options);\n}\n\nexport function formatTime(date: Date, locale: string): string {\n\treturn formatter(locale, { hour: 'numeric', minute: '2-digit' }).format(date);\n}\n\nexport function formatHourLabel(hour: number, locale: string): string {\n\treturn formatter(locale, { hour: 'numeric' }).format(new Date(2000, 0, 1, hour));\n}\n\nexport function formatWeekdayLabel(day: Date, locale: string, short = true): string {\n\treturn formatter(locale, { weekday: short ? 'short' : 'long' }).format(day);\n}\n\nexport function formatDayLabel(day: Date, locale: string): string {\n\treturn formatter(locale, { day: 'numeric', month: 'short' }).format(day);\n}\n\nexport function formatFullDayLabel(day: Date, locale: string): string {\n\treturn formatter(locale, {\n\t\tday: 'numeric',\n\t\tmonth: 'long',\n\t\tweekday: 'long',\n\t\tyear: 'numeric'\n\t}).format(day);\n}\n\n/** The heading for the visible range. `end` is exclusive. */\nexport function formatRangeTitle(\n\tview: BigCalendarView,\n\tstart: Date,\n\tend: Date,\n\tlocale: string\n): string {\n\tif (view === 'month') return formatter(locale, { month: 'long', year: 'numeric' }).format(start);\n\tif (view === 'day') return formatFullDayLabel(start, locale);\n\n\t// `formatRange` collapses the parts the two ends share, in the order the\n\t// locale wants them — \"Aug 17 – 23, 2026\" rather than a hand-assembled string.\n\tconst last = addDays(startOfDay(end), -1);\n\treturn formatter(locale, { day: 'numeric', month: 'short', year: 'numeric' }).formatRange(\n\t\tstart,\n\t\tlast\n\t);\n}\n\n/** The time range shown beside an event title. All-day events report their span. */\nexport function formatEventTime<TData>(event: BigCalendarEvent<TData>, locale: string): string {\n\tif (!isAllDayEvent(event)) {\n\t\treturn `${formatTime(event.start, locale)} – ${formatTime(event.end, locale)}`;\n\t}\n\tconst lastCovered = new Date(event.end.getTime() - 1);\n\tif (isSameDay(event.start, lastCovered)) return 'All day';\n\treturn `${formatDayLabel(event.start, locale)} – ${formatDayLabel(lastCovered, locale)}`;\n}\n\nexport function getContinuationLabel(continuesBefore: boolean, continuesAfter: boolean): string {\n\tif (continuesBefore && continuesAfter) return 'Starts and ends outside this range';\n\tif (continuesBefore) return 'Starts before this range';\n\tif (continuesAfter) return 'Continues past this range';\n\treturn '';\n}\n\n/** The accessible name for an event control, so a chip is not read as bare text. */\nexport function describeEvent<TData>(event: BigCalendarEvent<TData>, locale: string): string {\n\tconst parts = [event.title, formatEventTime(event, locale)];\n\tif (event.description) parts.push(event.description);\n\treturn parts.join(', ');\n}\n",
			"type": "registry:file",
			"target": "big-calendar/big-calendar-presentation.ts"
		},
		{
			"content": "<script lang=\"ts\" generics=\"TData = unknown\">\n\timport { untrack } from 'svelte';\n\n\timport { cn } from '$UTILS$.js';\n\n\timport type { BigCalendarEvent, BigCalendarSlot } from './big-calendar-types.js';\n\n\timport { isSameDay } from './big-calendar-date.js';\n\timport BigCalendarEventView from './big-calendar-event.svelte';\n\timport { buildTimeBlocks, isAllDayEvent, packDayRow } from './big-calendar-layout.js';\n\timport {\n\t\tformatFullDayLabel,\n\t\tformatHourLabel,\n\t\tformatWeekdayLabel\n\t} from './big-calendar-presentation.js';\n\n\t/** Pixels per hour. Fixed, so the grid scrolls rather than compressing. */\n\tconst HOUR_HEIGHT = 48;\n\tconst GUTTER = '3.5rem';\n\n\tlet {\n\t\tdays,\n\t\tevents,\n\t\tlocale,\n\t\tnow,\n\t\tonEventClick,\n\t\tonSlotClick,\n\t\tendHour,\n\t\tscrollToHour,\n\t\tstartHour,\n\t\ttoday\n\t}: {\n\t\tdays: Date[];\n\t\tendHour: number;\n\t\tevents: BigCalendarEvent<TData>[];\n\t\tlocale: string;\n\t\t/** Drives the current-time line; the parent owns the ticking. */\n\t\tnow: Date;\n\t\tonEventClick?: (event: BigCalendarEvent<TData>) => void;\n\t\tonSlotClick?: (slot: BigCalendarSlot) => void;\n\t\tscrollToHour: number;\n\t\tstartHour: number;\n\t\ttoday: Date;\n\t} = $props();\n\n\tlet scrollElement = $state<HTMLDivElement | null>(null);\n\tlet scrolledOnce = false;\n\n\tlet hours = $derived(\n\t\tArray.from({ length: Math.max(1, endHour - startHour) }, (_, index) => startHour + index)\n\t);\n\tlet gridHeight = $derived(hours.length * HOUR_HEIGHT);\n\tlet allDayEvents = $derived(events.filter(isAllDayEvent));\n\tlet allDayRow = $derived(packDayRow(days, allDayEvents));\n\tlet columns = $derived(\n\t\tdays.map((day) => ({ blocks: buildTimeBlocks(day, events, startHour, endHour), day }))\n\t);\n\tlet templateColumns = $derived(`${GUTTER} repeat(${days.length}, minmax(0, 1fr))`);\n\n\t/** Fraction of the visible window the current time sits at, or null when outside it. */\n\tlet nowRatio = $derived.by(() => {\n\t\tconst minutes = now.getHours() * 60 + now.getMinutes();\n\t\tconst windowStart = startHour * 60;\n\t\tconst windowEnd = endHour * 60;\n\t\tif (minutes < windowStart || minutes > windowEnd) return null;\n\t\treturn (minutes - windowStart) / (windowEnd - windowStart);\n\t});\n\n\t$effect(() => {\n\t\tconst element = scrollElement;\n\t\tif (!element || scrolledOnce) return;\n\t\tscrolledOnce = true;\n\t\tconst offset = untrack(() => (Math.max(scrollToHour, startHour) - startHour) * HOUR_HEIGHT);\n\t\t// The hour label straddles its line, so land just above it or it is clipped.\n\t\telement.scrollTop = Math.max(0, offset - 8);\n\t});\n\n\tfunction selectSlot(day: Date, hour: number): void {\n\t\tconst start = new Date(day.getFullYear(), day.getMonth(), day.getDate(), hour);\n\t\tconst end = new Date(day.getFullYear(), day.getMonth(), day.getDate(), hour + 1);\n\t\tonSlotClick?.({ start, end });\n\t}\n</script>\n\n<div class=\"flex min-h-0 flex-col\">\n\t<div class=\"grid border-b\" style={`grid-template-columns: ${templateColumns}`}>\n\t\t<div class=\"border-r\"></div>\n\t\t{#each days as day (day.getTime())}\n\t\t\t<div\n\t\t\t\tclass={cn(\n\t\t\t\t\t'border-r px-2 py-1.5 text-center last:border-r-0',\n\t\t\t\t\tisSameDay(day, today) && 'bg-primary/5'\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<div class=\"text-xs text-muted-foreground\">{formatWeekdayLabel(day, locale)}</div>\n\t\t\t\t<div\n\t\t\t\t\tclass={cn(\n\t\t\t\t\t\t'mx-auto mt-0.5 inline-flex size-6 items-center justify-center rounded-full text-sm font-medium tabular-nums',\n\t\t\t\t\t\tisSameDay(day, today) && 'bg-primary text-primary-foreground'\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t{day.getDate()}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t{/each}\n\t</div>\n\n\t{#if allDayRow.segments.length > 0}\n\t\t<div class=\"grid border-b\" style={`grid-template-columns: ${templateColumns}`}>\n\t\t\t<div class=\"border-r px-2 py-1 text-right text-xs text-muted-foreground\">All day</div>\n\t\t\t<div\n\t\t\t\tclass=\"relative grid gap-y-0.5 py-1\"\n\t\t\t\tstyle={`grid-column: 2 / -1; grid-template-columns: repeat(${days.length}, minmax(0, 1fr))`}\n\t\t\t>\n\t\t\t\t{#each allDayRow.segments as segment (segment.key)}\n\t\t\t\t\t<div\n\t\t\t\t\t\tclass=\"min-w-0 px-0.5\"\n\t\t\t\t\t\tstyle={`grid-column: ${segment.columnStart + 1} / span ${segment.span}; grid-row: ${segment.lane + 1}`}\n\t\t\t\t\t>\n\t\t\t\t\t\t<BigCalendarEventView\n\t\t\t\t\t\t\tvariant=\"band\"\n\t\t\t\t\t\t\tevent={segment.event}\n\t\t\t\t\t\t\tcontinuesAfter={segment.continuesAfter}\n\t\t\t\t\t\t\tcontinuesBefore={segment.continuesBefore}\n\t\t\t\t\t\t\t{locale}\n\t\t\t\t\t\t\t{onEventClick}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t{/each}\n\t\t\t</div>\n\t\t</div>\n\t{/if}\n\n\t<!-- A definite height keeps the hour grid scrollable inside any container. -->\n\t<div bind:this={scrollElement} class=\"max-h-[36rem] min-h-0 flex-1 overflow-y-auto\">\n\t\t<div\n\t\t\tclass=\"relative grid\"\n\t\t\tstyle={`grid-template-columns: ${templateColumns}; height: ${gridHeight}px`}\n\t\t>\n\t\t\t<div class=\"relative border-r\">\n\t\t\t\t{#each hours as hour, index (hour)}\n\t\t\t\t\t{#if index > 0}\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclass=\"absolute right-2 -translate-y-1/2 text-xs text-muted-foreground\"\n\t\t\t\t\t\t\tstyle={`top: ${index * HOUR_HEIGHT}px`}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{formatHourLabel(hour, locale)}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t{/if}\n\t\t\t\t{/each}\n\t\t\t</div>\n\n\t\t\t{#each columns as column (column.day.getTime())}\n\t\t\t\t<div\n\t\t\t\t\tclass={cn(\n\t\t\t\t\t\t'relative border-r last:border-r-0',\n\t\t\t\t\t\tisSameDay(column.day, today) && 'bg-primary/5'\n\t\t\t\t\t)}\n\t\t\t\t\tstyle={`background-image: linear-gradient(to bottom, var(--border) 1px, transparent 1px); background-size: 100% ${HOUR_HEIGHT}px`}\n\t\t\t\t>\n\t\t\t\t\t{#if onSlotClick}\n\t\t\t\t\t\t{#each hours as hour (hour)}\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tclass=\"absolute inset-x-0 cursor-pointer hover:bg-accent/40 focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-inset focus-visible:ring-ring/50\"\n\t\t\t\t\t\t\t\tstyle={`top: ${(hour - startHour) * HOUR_HEIGHT}px; height: ${HOUR_HEIGHT}px`}\n\t\t\t\t\t\t\t\taria-label={`${formatFullDayLabel(column.day, locale)}, ${formatHourLabel(hour, locale)}`}\n\t\t\t\t\t\t\t\tonclick={() => selectSlot(column.day, hour)}\n\t\t\t\t\t\t\t></button>\n\t\t\t\t\t\t{/each}\n\t\t\t\t\t{/if}\n\n\t\t\t\t\t{#each column.blocks as block (block.key)}\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclass=\"absolute p-px\"\n\t\t\t\t\t\t\tstyle={`top: ${block.topRatio * 100}%; height: ${block.heightRatio * 100}%; min-height: 1.25rem; left: ${(block.column / block.columnCount) * 100}%; width: ${(1 / block.columnCount) * 100}%`}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<BigCalendarEventView\n\t\t\t\t\t\t\t\tvariant=\"block\"\n\t\t\t\t\t\t\t\tevent={block.event}\n\t\t\t\t\t\t\t\tcontinuesAfter={block.continuesAfter}\n\t\t\t\t\t\t\t\tcontinuesBefore={block.continuesBefore}\n\t\t\t\t\t\t\t\t{locale}\n\t\t\t\t\t\t\t\t{onEventClick}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t{/each}\n\n\t\t\t\t\t{#if nowRatio !== null && isSameDay(column.day, now)}\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tclass=\"pointer-events-none absolute inset-x-0 z-10 border-t-2 border-destructive\"\n\t\t\t\t\t\t\tstyle={`top: ${nowRatio * 100}%`}\n\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<span class=\"absolute -top-1 -left-1 size-2 rounded-full bg-destructive\"></span>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t{/if}\n\t\t\t\t</div>\n\t\t\t{/each}\n\t\t</div>\n\t</div>\n</div>\n",
			"type": "registry:file",
			"target": "big-calendar/big-calendar-time-grid.svelte"
		},
		{
			"content": "<script lang=\"ts\">\n\timport type { DateValue } from '@internationalized/date';\n\timport type { Snippet } from 'svelte';\n\timport ChevronDownIcon from '@lucide/svelte/icons/chevron-down';\n\timport ChevronLeftIcon from '@lucide/svelte/icons/chevron-left';\n\timport ChevronRightIcon from '@lucide/svelte/icons/chevron-right';\n\timport Maximize2Icon from '@lucide/svelte/icons/maximize-2';\n\timport Minimize2Icon from '@lucide/svelte/icons/minimize-2';\n\n\timport { Button } from '$UI$/button/index.js';\n\timport { Calendar } from '$UI$/calendar/index.js';\n\timport * as Popover from '$UI$/popover/index.js';\n\timport * as ToggleGroup from '$UI$/toggle-group/index.js';\n\n\timport type { BigCalendarView } from './big-calendar-types.js';\n\n\timport { VIEW_LABELS } from './big-calendar-presentation.js';\n\n\tlet {\n\t\tanchorValue,\n\t\tfilters,\n\t\tisFullscreen,\n\t\tlocale,\n\t\tonDatePicked,\n\t\tonGoToToday,\n\t\tonNavigate,\n\t\tonToggleFullscreen,\n\t\tonViewSelect,\n\t\trangeTitle,\n\t\tview,\n\t\tviews\n\t}: {\n\t\tanchorValue: DateValue;\n\t\tfilters?: Snippet;\n\t\tisFullscreen: boolean;\n\t\tlocale: string;\n\t\tonDatePicked: (value: DateValue | undefined) => void;\n\t\tonGoToToday: () => void;\n\t\tonNavigate: (direction: -1 | 1) => void;\n\t\tonToggleFullscreen: () => void;\n\t\tonViewSelect: (view: BigCalendarView) => void;\n\t\trangeTitle: string;\n\t\tview: BigCalendarView;\n\t\tviews: BigCalendarView[];\n\t} = $props();\n\n\tlet datePickerOpen = $state(false);\n\n\tfunction handleDatePicked(value: DateValue | undefined): void {\n\t\tif (!value) return;\n\t\tonDatePicked(value);\n\t\tdatePickerOpen = false;\n\t}\n\n\t/**\n\t * A toggle group returns an empty string when the pressed item is toggled off.\n\t * The calendar always shows exactly one view, so treat that as no change.\n\t */\n\tfunction handleViewChange(value: string): void {\n\t\tif (!value) return;\n\t\tonViewSelect(value as BigCalendarView);\n\t}\n</script>\n\n<div class=\"flex w-full flex-wrap items-center justify-end gap-x-2 gap-y-2\">\n\t\t{#if filters}\n\t\t\t{@render filters()}\n\t\t{/if}\n\t\t{#if views.length > 1}\n\t\t\t<ToggleGroup.Root\n\t\t\t\ttype=\"single\"\n\t\t\t\tvariant=\"outline\"\n\t\t\t\tsize=\"sm\"\n\t\t\t\tvalue={view}\n\t\t\t\tonValueChange={handleViewChange}\n\t\t\t\taria-label=\"Calendar view\"\n\t\t\t>\n\t\t\t\t{#each views as item (item)}\n\t\t\t\t\t<ToggleGroup.Item value={item} aria-label={`${VIEW_LABELS[item]} view`}>\n\t\t\t\t\t\t{VIEW_LABELS[item]}\n\t\t\t\t\t</ToggleGroup.Item>\n\t\t\t\t{/each}\n\t\t\t</ToggleGroup.Root>\n\t\t{/if}\n\t<div class=\"flex items-center gap-1\">\n\t\t<Popover.Root bind:open={datePickerOpen}>\n\t\t\t<Popover.Trigger>\n\t\t\t\t{#snippet child({ props })}\n\t\t\t\t\t<Button\n\t\t\t\t\t\t{...props}\n\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\tclass=\"text-base font-semibold\"\n\t\t\t\t\t\taria-label={`${rangeTitle}, go to date`}\n\t\t\t\t\t>\n\t\t\t\t\t\t{rangeTitle}\n\t\t\t\t\t\t<ChevronDownIcon data-icon=\"inline-end\" />\n\t\t\t\t\t</Button>\n\t\t\t\t{/snippet}\n\t\t\t</Popover.Trigger>\n\t\t\t<Popover.Content class=\"w-auto p-0\" align=\"end\">\n\t\t\t\t<Calendar\n\t\t\t\t\ttype=\"single\"\n\t\t\t\t\t{locale}\n\t\t\t\t\tvalue={anchorValue}\n\t\t\t\t\tonValueChange={handleDatePicked}\n\t\t\t\t\tcaptionLayout=\"dropdown\"\n\t\t\t\t/>\n\t\t\t</Popover.Content>\n\t\t</Popover.Root>\n\t\t<Button variant=\"outline\" size=\"sm\" onclick={onGoToToday}>Today</Button>\n\t\t<Button\n\t\t\tvariant=\"outline\"\n\t\t\tsize=\"icon-sm\"\n\t\t\taria-label=\"Previous period\"\n\t\t\tonclick={() => onNavigate(-1)}\n\t\t>\n\t\t\t<ChevronLeftIcon />\n\t\t</Button>\n\t\t<Button variant=\"outline\" size=\"icon-sm\" aria-label=\"Next period\" onclick={() => onNavigate(1)}>\n\t\t\t<ChevronRightIcon />\n\t\t</Button>\n\t\t<Button\n\t\t\tvariant=\"outline\"\n\t\t\tsize=\"icon-sm\"\n\t\t\taria-label={isFullscreen ? 'Exit full screen' : 'Enter full screen'}\n\t\t\ttitle={isFullscreen ? 'Exit full screen' : 'Enter full screen'}\n\t\t\tonclick={onToggleFullscreen}\n\t\t>\n\t\t\t{#if isFullscreen}\n\t\t\t\t<Minimize2Icon />\n\t\t\t{:else}\n\t\t\t\t<Maximize2Icon />\n\t\t\t{/if}\n\t\t</Button>\n\t</div>\n</div>\n",
			"type": "registry:file",
			"target": "big-calendar/big-calendar-toolbar.svelte"
		},
		{
			"content": "import type { Snippet } from 'svelte';\n\nexport type BigCalendarView = 'agenda' | 'day' | 'month' | 'week';\n\nexport type BigCalendarEventTone =\n\t| 'accent'\n\t| 'destructive'\n\t| 'muted'\n\t| 'primary'\n\t| 'secondary'\n\t| 'success'\n\t| 'warning';\n\n/** Sunday is 0, matching `Date.prototype.getDay`. */\nexport type BigCalendarWeekday = 0 | 1 | 2 | 3 | 4 | 5 | 6;\n\n/**\n * A scheduled entry. `end` is exclusive, matching `GanttEvent` and common\n * calendar APIs. An all-day entry covering July 6–10 passes July 6 as `start`\n * and July 11 as `end`.\n */\nexport interface BigCalendarEvent<TData = unknown> {\n\tallDay?: boolean;\n\tdata?: TData;\n\t/** Secondary line shown in the agenda list and the event tooltip. */\n\tdescription?: string;\n\tend: Date;\n\tid: string;\n\tstart: Date;\n\ttitle: string;\n\ttone?: BigCalendarEventTone;\n}\n\n/** A contiguous run of days one event occupies inside one rendered day row. */\nexport interface BigCalendarSegment<TData = unknown> {\n\t/** Zero-based index of the first day column this segment covers. */\n\tcolumnStart: number;\n\t/** True when the event continues past the last day of this row. */\n\tcontinuesAfter: boolean;\n\t/** True when the event began before the first day of this row. */\n\tcontinuesBefore: boolean;\n\tevent: BigCalendarEvent<TData>;\n\tkey: string;\n\t/** Stacking row within the day row. Zero is the topmost. */\n\tlane: number;\n\t/** Number of day columns covered, at least one. */\n\tspan: number;\n}\n\nexport interface BigCalendarDayRow<TData = unknown> {\n\tdays: Date[];\n\t/** Lanes actually occupied by `segments`, so callers can size the row. */\n\tlaneCount: number;\n\t/** Count of segments hidden by the lane budget, per day column. */\n\toverflowByColumn: number[];\n\t/** Segments that fit within the lane budget. */\n\tsegments: BigCalendarSegment<TData>[];\n}\n\n/** A timed event placed inside one day column of the week or day grid. */\nexport interface BigCalendarBlock<TData = unknown> {\n\t/** Zero-based column within the cluster of mutually overlapping blocks. */\n\tcolumn: number;\n\t/** Total columns the cluster was split into. */\n\tcolumnCount: number;\n\t/** True when the event ends after the visible hour window. */\n\tcontinuesAfter: boolean;\n\t/** True when the event starts before the visible hour window. */\n\tcontinuesBefore: boolean;\n\tevent: BigCalendarEvent<TData>;\n\t/** Height as a fraction of the visible hour window. */\n\theightRatio: number;\n\tkey: string;\n\t/** Offset from the top of the visible hour window, as a fraction of it. */\n\ttopRatio: number;\n}\n\nexport interface BigCalendarAgendaGroup<TData = unknown> {\n\tday: Date;\n\tevents: BigCalendarEvent<TData>[];\n}\n\nexport interface BigCalendarSlot {\n\t/** Exclusive, matching `BigCalendarEvent`. */\n\tend: Date;\n\tstart: Date;\n}\n\nexport interface BigCalendarProps<TData = unknown> {\n\t/** Days covered by one page of the agenda view. */\n\tagendaLength?: number;\n\t/**\n\t * `card` wraps the calendar in its own titled card. Use `bare` when it is\n\t * already inside a card that carries the heading, so the two do not nest.\n\t */\n\tchrome?: 'bare' | 'card';\n\tclass?: string;\n\tdefaultDate?: Date;\n\tdefaultView?: BigCalendarView;\n\t/** Shown when the visible range holds no events. */\n\temptyLabel?: string;\n\t/** Exclusive last hour drawn in the week and day grids, 1–24. */\n\tendHour?: number;\n\tevents: BigCalendarEvent<TData>[];\n\t/**\n\t * Stretch the calendar to the height its container offers instead of sizing\n\t * to its rows. The container must give it a height to fill — inside a\n\t * `flex-1` column the month rows share the leftover space evenly.\n\t */\n\tfill?: boolean;\n\tloading?: boolean;\n\tlocale?: string;\n\t/** Lanes a month cell shows before collapsing the rest into \"+N more\". */\n\tmaxEventsPerDay?: number;\n\tonDateChange?: (date: Date) => void;\n\tonEventClick?: (event: BigCalendarEvent<TData>) => void;\n\t/** Fired when an empty day cell or hour slot is activated. */\n\tonSlotClick?: (slot: BigCalendarSlot) => void;\n\tonViewChange?: (view: BigCalendarView) => void;\n\t/** Hour the week and day grids scroll to on load, 0–23. */\n\tscrollToHour?: number;\n\t/** First hour drawn in the week and day grids, 0–23. */\n\tstartHour?: number;\n\ttitle?: string;\n\t/** Optional controls rendered at the start of the calendar toolbar. */\n\ttoolbarStart?: Snippet;\n\t/** Views offered in the toolbar, in the order given. */\n\tviews?: BigCalendarView[];\n\tweekStartsOn?: BigCalendarWeekday;\n}\n",
			"type": "registry:file",
			"target": "big-calendar/big-calendar-types.ts"
		},
		{
			"content": "<script lang=\"ts\" generics=\"TData = unknown\">\n\timport { CalendarDate, type DateValue, getLocalTimeZone } from '@internationalized/date';\n\timport { flushSync, type Snippet, untrack } from 'svelte';\n\n\timport { Badge } from '$UI$/badge/index.js';\n\timport * as Card from '$UI$/card/index.js';\n\timport { Skeleton } from '$UI$/skeleton/index.js';\n\timport { cn } from '$UTILS$.js';\n\n\timport type { BigCalendarProps, BigCalendarView } from './big-calendar-types.js';\n\n\timport BigCalendarAgenda from './big-calendar-agenda.svelte';\n\timport {\n\t\taddDays,\n\t\tbuildMonthWeeks,\n\t\tgetPeriodRange,\n\t\tresolveCalendarDate,\n\t\tshiftCalendarDate,\n\t\tstartOfDay\n\t} from './big-calendar-date.js';\n\timport { normalizeEvents, overlapsRange } from './big-calendar-layout.js';\n\timport BigCalendarMonth from './big-calendar-month.svelte';\n\timport { formatRangeTitle } from './big-calendar-presentation.js';\n\timport BigCalendarTimeGrid from './big-calendar-time-grid.svelte';\n\timport BigCalendarToolbar from './big-calendar-toolbar.svelte';\n\n\ttype InteractiveBigCalendarProps<TData> = BigCalendarProps<TData> & {\n\t\ttoolbarStart?: Snippet;\n\t};\n\n\t/** How often the current-time line is re-placed in the week and day grids. */\n\tconst NOW_TICK_MS = 60 * 1000;\n\n\tlet {\n\t\tagendaLength = 30,\n\t\tchrome = 'card',\n\t\tclass: className,\n\t\tdefaultDate = new Date(),\n\t\tdefaultView = 'month',\n\t\temptyLabel = 'No events',\n\t\tendHour = 24,\n\t\tevents,\n\t\tfill = false,\n\t\tloading = false,\n\t\tlocale = 'en-US',\n\t\tmaxEventsPerDay = 3,\n\t\tonDateChange,\n\t\tonEventClick,\n\t\tonSlotClick,\n\t\tonViewChange,\n\t\tscrollToHour = 7,\n\t\tstartHour = 0,\n\t\ttitle = 'Calendar',\n\t\ttoolbarStart,\n\t\tviews = ['month', 'week', 'day', 'agenda'],\n\t\tweekStartsOn = 1\n\t}: InteractiveBigCalendarProps<TData> = $props();\n\n\tlet view = $state<BigCalendarView>(untrack(() => defaultView));\n\tlet anchorDate = $state(untrack(() => resolveCalendarDate(defaultDate)));\n\tlet now = $state(new Date());\n\tlet isFullscreen = $state(false);\n\tlet fullscreenTransitioning = $state(false);\n\n\t/** Full screen always fills the viewport, whatever the caller asked for. */\n\tlet filling = $derived(fill || isFullscreen);\n\tlet safeAgendaLength = $derived(Math.max(1, Math.round(agendaLength)));\n\tlet safeStartHour = $derived(Math.min(Math.max(Math.round(startHour), 0), 23));\n\tlet safeEndHour = $derived(Math.min(Math.max(Math.round(endHour), safeStartHour + 1), 24));\n\tlet offeredViews = $derived(views.length > 0 ? views : (['month'] as BigCalendarView[]));\n\t/** A caller can drop the active view from `views`; fall back rather than blank. */\n\tlet activeView = $derived(offeredViews.includes(view) ? view : offeredViews[0]);\n\n\tlet period = $derived(getPeriodRange(activeView, anchorDate, weekStartsOn, safeAgendaLength));\n\t/** The month view draws whole weeks, so more is rendered than the period claims. */\n\tlet renderedRange = $derived.by(() => {\n\t\tif (activeView !== 'month') return period;\n\t\tconst weeks = buildMonthWeeks(anchorDate, weekStartsOn);\n\t\tconst days = weeks.flat();\n\t\treturn { start: days[0], end: addDays(days[days.length - 1], 1) };\n\t});\n\n\tlet normalized = $derived(normalizeEvents(events));\n\tlet visibleEvents = $derived(\n\t\tnormalized.filter((event) => overlapsRange(event, renderedRange.start, renderedRange.end))\n\t);\n\tlet visibleDays = $derived.by(() => {\n\t\tif (activeView === 'day') return [startOfDay(anchorDate)];\n\t\tconst days: Date[] = [];\n\t\tfor (let index = 0; index < 7; index += 1) days.push(addDays(period.start, index));\n\t\treturn days;\n\t});\n\tlet rangeTitle = $derived(formatRangeTitle(activeView, period.start, period.end, locale));\n\tlet anchorValue = $derived<DateValue>(\n\t\tnew CalendarDate(anchorDate.getFullYear(), anchorDate.getMonth() + 1, anchorDate.getDate())\n\t);\n\tlet today = $derived(startOfDay(now));\n\n\t$effect(() => {\n\t\tif (!isFullscreen) return;\n\n\t\tconst root = document.documentElement;\n\t\tconst previousRootOverflow = root.style.overflow;\n\t\tconst previousBodyOverflow = document.body.style.overflow;\n\t\troot.style.overflow = 'hidden';\n\t\tdocument.body.style.overflow = 'hidden';\n\n\t\treturn () => {\n\t\t\troot.style.overflow = previousRootOverflow;\n\t\t\tdocument.body.style.overflow = previousBodyOverflow;\n\t\t};\n\t});\n\n\t$effect(() => {\n\t\tconst timer = setInterval(() => {\n\t\t\tnow = new Date();\n\t\t}, NOW_TICK_MS);\n\t\treturn () => clearInterval(timer);\n\t});\n\n\tfunction goToDate(next: Date): void {\n\t\tanchorDate = startOfDay(next);\n\t\tonDateChange?.(anchorDate);\n\t}\n\n\tfunction navigate(direction: -1 | 1): void {\n\t\tgoToDate(shiftCalendarDate(activeView, anchorDate, direction, safeAgendaLength));\n\t}\n\n\tfunction selectView(next: BigCalendarView): void {\n\t\tif (next === view) return;\n\t\tview = next;\n\t\tonViewChange?.(next);\n\t}\n\n\tfunction handleDatePicked(value: DateValue | undefined): void {\n\t\tif (!value) return;\n\t\tgoToDate(value.toDate(getLocalTimeZone()));\n\t}\n\n\tfunction prefersReducedMotion(): boolean {\n\t\treturn window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\t}\n\n\tfunction setFullscreen(value: boolean): void {\n\t\tconst update = () =>\n\t\t\tflushSync(() => {\n\t\t\t\tisFullscreen = value;\n\t\t\t});\n\t\tif (prefersReducedMotion() || !('startViewTransition' in document)) {\n\t\t\tupdate();\n\t\t\treturn;\n\t\t}\n\n\t\tflushSync(() => {\n\t\t\tfullscreenTransitioning = true;\n\t\t});\n\t\tconst transition = document.startViewTransition(update);\n\t\tconst finish = () => {\n\t\t\tfullscreenTransitioning = false;\n\t\t};\n\t\tvoid transition.finished.then(finish, finish);\n\t}\n\n\tfunction toggleFullscreen(): void {\n\t\tsetFullscreen(!isFullscreen);\n\t}\n\n\tfunction handleWindowKeydown(event: KeyboardEvent): void {\n\t\tif (event.key === 'Escape' && !event.defaultPrevented && isFullscreen) setFullscreen(false);\n\t}\n</script>\n\n<svelte:window onkeydown={handleWindowKeydown} />\n\n{#snippet toolbar()}\n\t<BigCalendarToolbar\n\t\t{anchorValue}\n\t\tfilters={toolbarStart}\n\t\t{isFullscreen}\n\t\t{locale}\n\t\t{rangeTitle}\n\t\tonDatePicked={handleDatePicked}\n\t\tonGoToToday={() => goToDate(new Date())}\n\t\tonNavigate={navigate}\n\t\tonToggleFullscreen={toggleFullscreen}\n\t\tonViewSelect={selectView}\n\t\tview={activeView}\n\t\tviews={offeredViews}\n\t/>\n{/snippet}\n\n{#snippet body()}\n\t{#if loading}\n\t\t<div class=\"flex flex-col gap-2 p-4\" aria-busy=\"true\">\n\t\t\t{#each Array.from({ length: 5 }, (_, index) => index) as row (row)}\n\t\t\t\t<Skeleton class=\"h-14 w-full\" />\n\t\t\t{/each}\n\t\t</div>\n\t{:else if activeView === 'month'}\n\t\t<BigCalendarMonth\n\t\t\tanchor={anchorDate}\n\t\t\tevents={visibleEvents}\n\t\t\tfill={filling}\n\t\t\t{locale}\n\t\t\tmaxEventsPerDay={Math.max(1, Math.round(maxEventsPerDay))}\n\t\t\t{onEventClick}\n\t\t\t{onSlotClick}\n\t\t\t{today}\n\t\t\t{weekStartsOn}\n\t\t/>\n\t{:else if activeView === 'agenda'}\n\t\t<div class={cn(filling && 'min-h-0 flex-1 overflow-auto')}>\n\t\t\t<BigCalendarAgenda\n\t\t\t\t{emptyLabel}\n\t\t\t\tend={period.end}\n\t\t\t\tevents={visibleEvents}\n\t\t\t\t{locale}\n\t\t\t\t{onEventClick}\n\t\t\t\tstart={period.start}\n\t\t\t\t{today}\n\t\t\t/>\n\t\t</div>\n\t{:else}\n\t\t<BigCalendarTimeGrid\n\t\t\tdays={visibleDays}\n\t\t\tendHour={safeEndHour}\n\t\t\tevents={visibleEvents}\n\t\t\t{locale}\n\t\t\t{now}\n\t\t\t{onEventClick}\n\t\t\t{onSlotClick}\n\t\t\t{scrollToHour}\n\t\t\tstartHour={safeStartHour}\n\t\t\t{today}\n\t\t/>\n\t{/if}\n{/snippet}\n\n{#if chrome === 'bare'}\n\t<!-- The surrounding card owns the heading; only the toolbar and grid belong here. -->\n\t<div\n\t\tclass={cn(\n\t\t\t'flex flex-col gap-3',\n\t\t\tfilling && 'min-h-0 flex-1',\n\t\t\tclassName,\n\t\t\tisFullscreen && 'fixed inset-0 z-50 h-dvh w-dvw min-h-0 gap-0 bg-card'\n\t\t)}\n\t\tstyle={`view-transition-name: ${fullscreenTransitioning ? 'big-calendar-fullscreen' : 'none'}`}\n\t>\n\t\t<div class={cn('flex', isFullscreen && 'border-b px-6 py-4')}>\n\t\t\t{@render toolbar()}\n\t\t</div>\n\t\t<div\n\t\t\tclass={cn(\n\t\t\t\t'overflow-hidden rounded-md border',\n\t\t\t\tfilling && 'flex min-h-0 flex-1 flex-col overflow-auto',\n\t\t\t\tisFullscreen && 'rounded-none border-0'\n\t\t\t)}\n\t\t>\n\t\t\t{@render body()}\n\t\t</div>\n\t</div>\n{:else}\n\t<Card.Root\n\t\tclass={cn(\n\t\t\t'gap-0 py-0',\n\t\t\tfilling && 'min-h-0 flex-1',\n\t\t\tclassName,\n\t\t\tisFullscreen && 'fixed inset-0 z-50 h-dvh w-dvw rounded-none'\n\t\t)}\n\t\tstyle={`view-transition-name: ${fullscreenTransitioning ? 'big-calendar-fullscreen' : 'none'}`}\n\t>\n\t\t<div class=\"flex flex-wrap items-center gap-x-6 gap-y-3 border-b px-6 py-3\">\n\t\t\t<Card.Title class=\"flex items-center gap-2\">\n\t\t\t\t{title}\n\t\t\t\t<Badge variant=\"secondary\">{visibleEvents.length}</Badge>\n\t\t\t</Card.Title>\n\t\t\t<div class=\"flex min-w-[min(32rem,100%)] flex-1\">{@render toolbar()}</div>\n\t\t</div>\n\t\t<Card.Content class={cn('p-0', filling && 'flex min-h-0 flex-1 flex-col overflow-auto')}>\n\t\t\t{@render body()}\n\t\t</Card.Content>\n\t</Card.Root>\n{/if}\n",
			"type": "registry:file",
			"target": "big-calendar/big-calendar.svelte"
		},
		{
			"content": "export type {\n\tBigCalendarAgendaGroup,\n\tBigCalendarBlock,\n\tBigCalendarDayRow,\n\tBigCalendarEvent,\n\tBigCalendarEventTone,\n\tBigCalendarProps,\n\tBigCalendarSegment,\n\tBigCalendarSlot,\n\tBigCalendarView,\n\tBigCalendarWeekday\n} from './big-calendar-types.js';\n\nexport { default as BigCalendar } from './big-calendar.svelte';\n",
			"type": "registry:file",
			"target": "big-calendar/index.ts"
		}
	]
}