A calendar, with the dates computed rather than asked for - #79
Merged
Conversation
The second slice of #64. A month as a grid, with per-day styling: marks for days with something on, a selected day, an optional header and weekday row, and a week that starts on Monday or Sunday. The interesting decision is that no host calendar is consulted anywhere. Every language this library is ported to has a different date type -- different epochs, different month numbering, different opinions about time zones -- and a widget whose output depends on any of that cannot be held to a fixture. So the arithmetic is here, in terms every port already has: integers. Sakamoto's method for the weekday, the full Gregorian leap rule, and a test that greps the TypeScript source to make sure nobody quietly reaches for `Date` later. Three things that are easy to get wrong and are pinned by tests: The leap rule is the whole rule -- every four years, except centuries, except every fourth century. Truncating it at "every four years" is right for 1901-2099 and wrong for 1900 and 2100, which is the kind of bug that sits quietly for decades. The leap count divides towards negative infinity. Go, C++ and Zig all truncate towards zero by default, which is off by one for years before 1; each port uses a floor division rather than the operator. A month is four, five or six week rows depending on where its first day falls. `calendarHeight` returns the month's own, and a test walks all twelve months of a year asserting that what was reserved is what got drawn -- reserving five for everything leaves some months a row short and others a blank row long. Six ports and five fixtures, all additive. The Ruby, PHP and Perl bridges gained a calendar node and COBOL a CALENDAR/CALDAY pair, which both COBOL bridges render identically. The widget gallery is now 31. Verified: 322 TS tests under bun and node; 81 widget scenes matching the reference in Rust, Go, Python, Zig and C++; 11/11 ctest; the bindings check; all eleven galleries; both COBOL bridges diff clean; the site builds. Part of #64 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Df2FNu5DhinMV2soRz3cy
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.
The second slice of #64. A month as a grid, with per-day styling: marks for days with something on, a selected day, an optional header and weekday row, and a week that starts on Monday or Sunday.
No host calendar is consulted, anywhere
Every language this library is ported to has a different date type — different epochs, different month numbering, different opinions about time zones — and a widget whose output depends on any of that cannot be held to a fixture. So the arithmetic is here, in terms every port already has: integers. Sakamoto's method for the weekday, the full Gregorian leap rule, and a test that greps the TypeScript source to make sure nobody quietly reaches for
Datelater.Three things that are easy to get wrong
The leap rule is the whole rule — every four years, except centuries, except every fourth century. Truncating it at "every four years" is right for 1901-2099 and wrong for 1900 and 2100, which is the kind of bug that sits quietly for decades.
The leap count divides towards negative infinity. Go, C++ and Zig all truncate towards zero by default, which is off by one for years before 1; each port uses a floor division rather than the operator.
A month is four, five or six week rows depending on where its first day falls.
calendarHeightreturns the month's own, and a test walks all twelve months of a year asserting that what was reserved is what got drawn — reserving five for everything leaves some months a row short and others a blank row long.Scope
Six ports and five fixtures, all additive. The Ruby, PHP and Perl bridges gained a
calendarnode and COBOL aCALENDAR/CALDAYpair, which both COBOL bridges render identically. The widget gallery is now 31. This is one slice of #64; the bounds-aware canvas and Shadow are still open there, which is why this closes nothing.Verified
bun testandnode --test, typecheck cleanports/bindings/tests/check.py, all eleven galleriesdiffclean)next buildfor the site🤖 Generated with Claude Code
https://claude.ai/code/session_017Df2FNu5DhinMV2soRz3cy