Repository navigation
Releases: Moltenship/time
Release list
1.0.0-rc.2
The second release candidate for 1.0. It fixes the scrolling day, 3-day and week views on iPhone, where a swipe could move both the hours and the days. The API can still change before 1.0.
Highlights
- A swipe on an iPhone scrolls one way. In the registry's scrolling day, 3-day and week views (
scrolling-time-grid-view), a swipe up or down no longer jumps to the next or previous days, and a swipe sideways no longer moves the hours. Each swipe follows the direction it starts in. The hours now scroll in one element and the days in another inside it. The day header and the all-day row follow the days on a scroll timeline, so they keep up with a swipe on 120 Hz screens, and all-day titles stay in view while their bars' starts are scrolled past. (#261) - Packages are published from CI with provenance. Each release is now built, checked and published by the release workflow through npm trusted publishing, so every package on npm carries a provenance statement. (#258, #259)
Features
@moltenship/calendar-dnd
useCalendarPointerandattachCalendarPointertakesidewaysScrollContainer: an element insidescrollContainerthat scrolls sideways in its place when a drag nears the left or right edge, for a view that scrolls each axis in its own element. It's also available from@moltenship/calendar. (#261)
Fixes
Registry
- In the scrolling day, 3-day and week views on iPhone, a mostly vertical swipe could page the days, and a sideways swipe moved the hours. Safari on iOS locks no direction in an element that scrolls both ways. (#260, #261)
Registry
- Add
scrolling-time-grid-viewagain to get the fix. It now needs@moltenship/calendar@^1.0.0-rc.2, forsidewaysScrollContainer. (#261)- Its
scrolling-time-grid-viewportscrolls the hours only. A newscrolling-time-grid-dayselement scrolls the days and holds the snap points, and the days' scrollbar is hidden. - A sideways swipe or trackpad scroll over the header no longer pages; one over the hours does.
- Its
time-grid-view'sTimeGridAllDayCellsdrops thestickyLabelsprop, which only the scrolling view used. Addtime-grid-viewagain, or remove the prop where your copy passes it. (#261)calendar'sscrolling-axis.tsxjumps rather than animates when focus is anywhere in the view's grid, not only in its scroller. Addcalendaragain, or copy the one-line change. (#261)
Contributors
@Moltenship and Claude Opus 5.5.
Full changelog: v1.0.0-rc.1...v1.0.0-rc.2
1.0.0-rc.1
The first public release, a release candidate for 1.0.0, of @moltenship/calendar, calendar-core, calendar-dnd, calendar-dnd-kit, calendar-react, calendar-recurrence, calendar-temporal, calendar-testing and ics. Time is a React 19 calendar built on the Temporal API. It reads timed, all-day and floating events from your own records through an adapter, handles time zones and daylight saving time, and turns moves, resizes and creates, by pointer, touch or keyboard, into changes you save, through policies such as working hours and conflicts. The week, day, month, year, agenda, resource column and resource timeline views, and views that scroll without end, are shadcn/ui-style source you copy from the registry and own. Recurring series, with edits to one occurrence, the following ones or all, and iCalendar parsing are separate packages. The API can still change before 1.0.0 if the release candidate turns up problems. The notes below cover the work since this changelog started (#46), so some of them describe changes to code that was never released.
- Hooks for animating the calendar from the app, as the new "Animate with Motion" guide does. A
monitorCalendarDragsfollower hearspreview(preview)whenever the view's preview changes, with its boxes in viewport coordinates, the time range it shows and what the policies would say, andend(dropped, landing)gets the preview a release proposed the move at, ornull. A follower withoutclaimsonly watches: the drag behaves as if no one followed, with no copy off the view and the usual auto-scroll. Every view marks an event's titledata-slot="calendar-event-title". @moltenship/calendar-testingtests apps' calendars:createTestEnvironmentfixesnow, the time zone, locale and week rules throughRoot's props;buildEvent,buildAllDayEvent,buildResource,buildRecurringEventandbuildAvailabilitymake typed records;renderCalendarrenders aRootwith controlled events and records everyonEventChangeandonEventChangeResult;hydrateCalendarrenders on the server, hydrates and fails on a mismatch. React DOM 19 is a peer (#45).@moltenship/calendar-testingfinds and drives what a calendar shows:getEvent,getDayCell,getTimeColumnandgetResourcequery by the calendar's own events and the pointer layer's attributes;calendar.keyboardgrabs, steps, resizes, creates, drops and cancels through the keyboard grab mode;calendar.pointerdrags with a mouse, pen or finger in a browser and throws aPointerLayoutErrorin jsdom;settled(),announcements()andplacementOf()wait for saves and read what the calendar said and shows (#45).@moltenship/calendar-testinghas fixtures for contract tests:denseDayFixture,dstWeekFixture({ change })andresourceDayFixture, each with the environment, resources andRootprops it's meant for, andmultiZoneSeriesFixture's series to expand. Their IDs, times and counts change only in a major version (#45).@moltenship/icsis licensedMIT AND Unicode-3.0: its Windows time zone mapping comes from Unicode CLDR. The license text ships in the package'sTHIRD-PARTY-NOTICES.mdand, as a legal comment that bundlers keep, in its built code.- A
RootwithoutonEventChangeis read-only in its views too: they start no drags or keyboard grabs and draw no resize handles. Renderers getisReadOnlyto tell (#201). - Registry components that call hooks, create a context or set event handlers start with
"use client", so a Server Component, such as a page in Next.js's App Router, can import them (#190). - Touch drags start after a 450 ms press instead of 250 ms, so a finger that rests before it scrolls still scrolls. The pointer layer listens for
touchmovefrom the touch's start, so iOS Safari lets a drag hold the page still. On touch screens, editable built-in views select no text and show no callout (#217). - The registry has 3-day views,
createThreeDayViewandcreateScrollingThreeDayView. On touch screens month events and "+N more" are 24 px tall, and the toolbar's title wraps on a phone instead of being cut (#217). Root'seventstakes aCalendarEventSource<TEvent>as well as an array: events in an external store, read throughuseSyncExternalStore, withgetServerSnapshotfor server rendering and hydration. Its getters return event arrays (#200).Root'sonEventChangeResulthears how each proposal ended, from a pointer, the keyboard orproposeEventChange, with theinputthat made it. Your calendar'suseCalendarPendingChanges(selector?)lists the changes still validating, saving, or waiting forevents.proposeEventChangetakes an optional{ input }, and the pointer layer'sonProposegets{ input: "pointer" }. ARootwithoutonEventChangerejects with the change, as a policy does (#199).@moltenship/calendar-recurrenceexpands a year of 200 series about 18% faster.createOccurrenceAdaptershares its revision work between adapters, so one made on every render gives the same revisions and core's snapshot keeps its records (#160).expandRecurrenceRuleends a rule whose INTERVAL never reaches its BY values, such asFREQ=MINUTELY;INTERVAL=2;BYMINUTE=1from an even minute, after its first occurrence instead of running tomaxIterationsand reportingtruncated(#160).recurringEventsFromIcsappliesRANGE=THISANDFUTURE: it splits the series at the override, as a "this and following" edit does, so Apple's "this and future" changes reach later occurrences. It reads Outlook'sX-MICROSOFT-CDO-ALLDAYEVENT:TRUEmidnight-to-midnight events as all-day, and, withouttimeZone, reads UTC dates on all-day and floating series in the zone most of the feed's TZIDs name rather than UTC; passtimeZone: "UTC"for the old reading. A series whose DTSTART falls in a DST gap keeps the length written up to DTEND (#160).resolveRecurrenceEditreplays a change on the series' own clock when it gets the calendar'stimeZone, for drags that also change the time of day, resizes and editor updates as well as drags by days, and for"following"as well as"all". An occurrence a DST gap moved forward, dragged by days, keeps the series' written time. With"all", an occurrence dropped on the later of two equal wall times at DST's end gets an override there. A newoverridesoption takes the series' overrides, so cancelled ones count as hiding occurrences and"following"from the first one left to show is"all"(#160).- Overlap layouts vary per resource and per calendar. The time-grid views take
getEventOverlapLayout, an event's own layout, such as its calendar's. The resource columns view also takesgetResourceOverlapLayout, a resource's layout in its columns, such as"stack"for rooms. A group of overlapping events takes its events' own layout when they all agree, and otherwise its column's: the resource's, thenoverlapLayout.ResourceOverlapLayoutOptionsandTimeGridLayoutOptionsare new,layoutTimeGridtakesgetEventOverlapLayout, and an invalidstackIndentnow throws whatever the layout (#230). - Undo and redo, opt-in:
createEventHistory(options?)records committed changes fromRoot'sonEventChangeResultand undoes and redoes them by proposing the inverse through the same pipeline, so policies run andonEventChangesaves it.useCalendarHistory(history, { messages? })binds a history to aRootand speaks outcomes through itsAnnouncer. A step whose event changed elsewhere is dropped, and an undo waits for a change still saving; recurring events aren't supported yet. A calendar without a history bundles none of it. A create proposal can carry a record asevent, which its change hands on, andonEventChangeResultgets the detail a proposal was made with, which an event history's inverses mark withhistory(#227). conflictPolicytakes a mode per resource,getResourceMode(resourceId), such as"block"for rooms and"warn"for people, and a third mode,"allow". The strictest mode among the resources a change double-books decides, and the reason stays"resource-conflict". Existing calls work as before.ConflictModeis new (#230).- The resource timeline's hour rows can stack overlapping events.
overlapLayout,getResourceOverlapLayoutandgetEventOverlapLayoutwork as in resource columns:"stack"cascades a row's bars a third of a lane apart, never more than two lanes tall, and the other layouts keep a lane per level of overlap. Back-to-back events of a quarter hour or less no longer take a second lane at some times of day, such as 10:00. Bars gettopand rowsheight, both in lanes;ResourceTimelineLayoutOptionsis new, and the timeline views take the root's resource type asTResource(#230). useCalendarHistoryShortcuts(history, { scope })adds undo and redo keys to a calendar: Mod+Z, and Shift+Mod+Z or Ctrl+Y, rebindable, never in text fields or dialogs. The registry'scalendar-history-toastoffers Undo after each change and Redo after an undo, with the keys, and the demo uses it (#227).- Drags from outside the calendar:
startCalendarDrop(source, { input })follows an item dragged in from a list over every view that usesuseCalendarPointer, previews and checks where it would land, scrolls the view near its edges, and proposes once on drop: a create carrying the item's record asevent,durationlong over a time column ordayslong over day cells, in the resource it's dropped in, or witheventIda move. Read-only views take no part.monitorCalendarDrags(monitor)offers each event a view starts to move to drop zones outside the calendar, which can claim the pointer and take the drop; while one follows, a copy of the event follows the pointer outside the view.observeCalendarRegionslists the views on the page. Announcement updates carryoutside: { title? }for such drags, which the registry's English messages name. The pointer layer's `...