Repository navigation
Add PDCalendar component - #244
Merged
Merged
Conversation
PDCalendar<TItem> shows any item type through selector delegates, in a month grid, a week time grid or an agenda list, with a Bootstrap toolbar, two-way Date, View and SelectedItem, lazy loading through OnVisibleRangeChanged, keyboard navigation and ARIA grid roles. The date and layout logic is in testable helpers: CalendarMath (view ranges, navigation, time zone aware day boundaries), CalendarLayoutEngine (splitting items by day, greedy overlap column packing) and CalendarTimeAxis (an hour axis that stays aligned across daylight saving changes, giving 23 and 25 hour days their true lengths). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bUnit tests cover the month, week and agenda views, selection, slot selection, keyboard handling, view switching, the toolbar, MinDate and MaxDate bounds, OnVisibleRangeChanged, the current time indicator and its timer, ScrollToHour and disposal. Plain unit tests cover CalendarMath, CalendarLayoutEngine and CalendarTimeAxis, including the Europe/London spring and autumn clock changes, a zone where midnight is skipped and one where it is repeated, items spanning midnight and days, and overlap packing with one, two, three and chained overlaps. NavigateAsync, GoToTodayAsync, GoToDateAsync, SetViewAsync and ShowDayAgendaAsync now re-render the calendar themselves, so a host calling them through a component reference sees the change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The day number in a week view header is centred under the weekday name, and week view items put the title before the times, since a narrow time block has room for little else. The period title is plain text rather than a heading, so it does not disturb the host page's heading outline. Found by checking the demo page in headless Chromium. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The demo shows a two-station radio schedule in Europe/London, loaded lazily through OnVisibleRangeChanged with the busy overlay, with overlapping shows, a late show running past midnight, a festival spanning the weekend and a button for the week the clocks go back (25 October 2026). A second calendar shows ItemTemplate and disabled items in an agenda. The Documentation tab describes the API, events, keyboard support, time zone handling and styling. ComponentDocumentation.md is regenerated with GenerateDocs.ps1. The hand-written PDChat notes that the script would drop are kept, and one generated PDTree line whose source summary contains em dashes is left out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 374 |
| Duplication | 2 |
🟢 Coverage 100.00% diff coverage · +0.01% coverage variation
Metric Results Coverage variation ✅ +0.01% coverage variation Diff coverage ✅ 100.00% diff coverage Coverage variation details
Coverable lines Covered lines Coverage Common ancestor commit (1b4b7bc) 16056 16033 99.86% Head commit (da89ab9) 16679 (+623) 16656 (+623) 99.86% (+0.01%) Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch:
<coverage of head commit> - <coverage of common ancestor commit>Diff coverage details
Coverable lines Covered lines Diff coverage Pull request (#244) 623 623 100.00% Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified:
<covered lines added or modified>/<coverable lines added or modified> * 100%
AI Reviewer: run a review on demand. To trigger the first review automatically, go to your organization or repository integration settings. AI can make mistakes. Always validate suggestions.
TIP This summary will be updated as you push new changes.
- Split long or branchy methods (OnParametersSetAsync, OnAfterRenderAsync, OnKeyDownAsync, CalendarLayoutEngine.SplitByDay) into small helpers; key handling is now a lookup from key to action. - Give conditional expression-bodied members block bodies, so Lizard counts them as methods rather than file-level code. - Move static defaults out of the generic component into a non-generic CalendarDefaults class. - CalendarMath.DaysPerWeek is a static read-only property, and CalendarTimeAxis has an internal constructor. - The minute timer passes the component as its state instead of reusing a discard parameter. - Reorder CSS rules so specificity never descends, add the missing empty line, use inset, flex-flow and :not() selector lists. - The demo page's colours move from scoped CSS with ::deep to an inline style block, as PDTimelinePage does. - Test fakes use all their parameters, and a test property no longer shadows a helper method. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GetDayClass, GetItemClass and GetSlotClass now pass (condition, class) pairs to one JoinClasses helper instead of a chain of if statements, which brings GetDayClass under Lizard's complexity limit. The test JS runtime fake records the identifier of each call. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
PDCalendar<TItem>, a generic calendar for anything with a start and an end in time. It reads items through selector delegates, so any type can be shown without converting it to a calendar model.TimeZone(defaultTimeZoneInfo.Local) decides which day and hour an item falls in. The week view's hour axis is real elapsed time, so the day the clocks go forward shows 23 hours and the day they go back shows 25, with the repeated hour labelled by its UTC offsets. Items spanning midnight are split across day columns.MaxItemsPerDayitems per day with a "+n more" button that opens that day's agenda, and shows multi-day items on every day.OnVisibleRangeChangedis raised whenever the visible range changes, including on first show;IsLoadingshows the library'sPDBusyOverlay.prefers-reduced-motion, and below 576 px the month view collapses items to dots.ScrollToHouris set; that uses the existingsetPropertyhelper incommon.js.Public API
PDCalendar<TItem>parameters:Items,StartSelector,EndSelector,TitleSelector,KeySelector,CssClassSelector,TooltipSelector,IsDisabledSelector,ItemTemplate,TimeZone,Clock(TimeProvider).Date/DateChanged(DateOnly?, null means today),View/ViewChanged,AvailableViews,SelectedItem/SelectedItemChanged,FirstDayOfWeek(default Monday),MinDate,MaxDate,IsLoading.OnItemSelected,OnItemDoubleClick,OnSlotSelected(DateTimeOffset),OnVisibleRangeChanged((DateTimeOffset From, DateTimeOffset To)).FirstVisibleHour,LastVisibleHour,SlotHeight,MinItemHeight,ScrollHeight,ScrollToHour,MaxItemsPerDay,AgendaDays,NowIndicator,ShadeWeekends,WeekendDays,DayCssClassSelector,TimeFormat,ShowToolbar,ShowNavigation,ShowToday,ShowTitle,ShowViewSwitcher,EmptyText,AriaLabel,CssClass.NavigateAsync,GoToTodayAsync,GoToDateAsync,SetViewAsync,ShowDayAgendaAsync,CanNavigate. Read-only properties:Id,CurrentDate,CurrentView,CurrentSelection,VisibleRange,Title.CalendarView(Month,Week,Agenda).CalendarMath(visible dates and ranges, navigation, start and length of a day, wall clock to instant with gap and overlap handling, titles),CalendarLayoutEngine(SplitByDay,PackColumns).CalendarTimeAxis,CalendarAxisRow,CalendarHourSlot,CalendarSegment<TItem>.No existing public member is changed or removed.
Tests and coverage
OnVisibleRangeChanged,MinDateandMaxDate,ItemTemplate, "+n more", the empty state, time zone changes, the current time indicator driven by a testTimeProvider,ScrollToHourand disposal.coverage.config: 576 of 576 lines (100%) and 299 of 300 branches. Because that config leaves out[CompilerGenerated]code, and so async method bodies and Razor lambdas, I also measured with that exclusion removed: 913 of 916 lines (99.7%) and 457 of 474 branches (96.4%). The three lines not covered are theObjectDisposedExceptionguard in the minute timer callback, which only runs if a tick races the renderer's disposal.Command used:
Demo
A new
/pdcalendarpage (Demo | Source | Documentation) shows a two-station radio schedule in Europe/London, loaded lazily with a deliberate delay so the busy overlay shows. It has overlapping shows, a late show running past midnight, a festival spanning a weekend, a button to show the week the clocks go back (25 October 2026), controls for most parameters, and a second agenda-only calendar showingItemTemplateand disabled items. Also added to the NavMenu.ComponentDocumentation.mdis regenerated withGenerateDocs.ps1. The hand-written PDChat notes that the script would have dropped are kept, and one generated PDTree line is left out because its source XML summary contains em dashes.I checked the page by running the Web host and driving it with headless Chromium (Playwright). I confirmed the week, clock-change week, month, "+n more" to agenda, phone-width (no horizontal scroll) and Documentation views, keyboard focus movement and item selection. The only console errors were the existing BlazorMonaco "monaco is undefined" messages, which also appear on other documentation tabs such as
/pdbutton?tab=docs. I did not test with a screen reader or on a real phone.dotnet build PanoramicData.Blazor.slnxgives 0 errors. The 2 warnings are the existing "packaging has been disabled" messages from the Web and WebAssembly.Server hosts.🤖 Generated with Claude Code