The height the all-day band occupies above the time grid: enough for every
stacked lane plus the band's top/bottom padding, or 0 when there are no
all-day events or the band is disabled (PlannerConfig.showAllDayBand) —
the band is then omitted entirely. Drives both the band widget's height and
the controller's scroll-clamp reservation.
The all-day events (#48), packed into stacked lanes for the all-day band.
Built from entries whose PlannerTime.allDay is set; those are kept out of
events (the hour-positioned grid) entirely. Empty — so the band is
omitted and allDayBandHeight is zero — when none are all-day or the band
is disabled (PlannerConfig.showAllDayBand is false, the default).
Fires PlannerConfig.onEntryDelete for an all-day chip — the band's
counterpart to deleteEvent, reached by the context menu or the chip's
a11y "dismiss" action (#72).
The drag a press at localPos (planner-local coordinates) would begin, or
DragType.none when it lands on no draggable event. Drives the desktop
hover cursor (move over an event body, resize over its top/bottom edge) and
shares Event.dragTypeForGridPoint with startDrag, so the cursor matches
the drag a press there would start. Spanning events are read-only (#47), so
they report DragType.none (no move/resize affordance).
Fires PlannerConfig.onEntryEdit for an all-day chip — the band's
counterpart to editEvent, reached by double-tap, the context menu, or the
chip's a11y "activate" action (#72). All-day chips have no time axis, so
(unlike timed events) they expose no move/nudge — only edit and delete.
The all-day chip under bandLocalPos, or null if the point hits empty
band space (#72). bandLocalPos is in the band canvas's own coordinate
space — the same space AllDayEvent.screenRect lives in (full planner
width, horizontal scroll already applied) — so a chip is hit when its
on-screen rect contains the point. A linear scan: all-day chips are few and
aren't day-bucketed like the timed events.
The all-day PlannerTime a tap on empty band space at bandLocalPos
(band-canvas coordinates) maps to — the band's counterpart to
getTimeAtPos on the grid (#72). Undoes the horizontal scroll and the
hour-gutter offset to find the column under the point, clamps it to a valid
column, and flags it PlannerTime.allDay so create-on-empty-band yields an
all-day entry. There is no hour/minute — an all-day time isn't positioned.
Shifts event by hourDelta whole hours, clamped to
[config.minHour, config.maxHour], then re-lays out overlaps, repaints,
and fires PlannerConfig.onEntryMove. A screen-reader user can't drag, so
the accessibility layer exposes "Move earlier"/"Move later" nudges — the
keyboard-friendly equivalent of a drag-move. A nudge that would leave the
hour unchanged (already at the bound) is a no-op and fires nothing.
Snaps minutes to a multiple of activeSnapMinutes. The single snapping
primitive shared by create (getTimeAtPos) and drag/resize
(Event.endDrag), so the two stay in lockstep. An interval <= 1 leaves
minutes untouched (minute precision); it truncates rather than rounds so
a within-hour offset can't spill into the next hour (e.g. 58 -> 45, never
60, at a 15-minute snap).
Refreshes the planner data in place when the host Planner widget is
rebuilt with new config or entries. The controller is preserved, so
the current scroll/zoom position survives the rebuild instead of being
reset — which is what the previous static controller state hacked around.