Skip to content

Feat/calendar preview - #891

Draft
Shreyag02 wants to merge 23 commits into
rfc-005-calendar-previewfrom
feat/calendar-preview
Draft

Feat/calendar preview#891
Shreyag02 wants to merge 23 commits into
rfc-005-calendar-previewfrom
feat/calendar-preview

Conversation

@Shreyag02

Copy link
Copy Markdown
Contributor

Description

[Provide a brief description of the changes in this PR]

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactor (no functional changes, no bug fixes just code improvements)
  • Chore (changes to the build process or auxiliary tools and libraries such as documentation generation)
  • Style (changes that do not affect the meaning of the code (white-space, formatting, etc))
  • Test (adding missing tests or correcting existing tests)
  • Improvement (Improvements to existing code)
  • Other (please specify)

How Has This Been Tested?

[Describe the tests that you ran to verify your changes]

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation (.mdx files)
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works

Screenshots (if appropriate):

[Add screenshots here]

Related Issues

[Link any related issues here using #issue-number]

Shreyag02 and others added 14 commits August 30, 2026 04:34
Phase 1 of RFC 005. Ships alongside the existing calendar family; nothing
existing changes, and the barrel additions are purely additive.

The root owns every piece of state explicitly — value, open and month each
via `useControlled` — and renders `Popover.Root` itself, so Base UI owns
dismissal and `use-picker-popover.ts` gets no successor. Context is stored
as `unknown` and cast at a part-aware hook that names the offending part.

`date-adapter.ts` performs every `dayjs.extend()` once, in dependency
order, which retires the import-order failure class behind the 0.49.0 P0.

`calendar-preview-grid.tsx` is the only file importing react-day-picker.
It renders three `DayPicker` call sites rather than one assembled object,
because `mode` discriminates RDP's prop union — that keeps the boundary
fully type-checked with no cast, and the union never reaches a consumer.
`.Nav` being ours means RDP runs with `hideNavigation` and
`captionLayout='label'`, so no `Select` is ever mounted.

Zero biome-ignore, zero slotProps, `...props` last at every part.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both range fields are typable. The old RangePicker left them `readOnly`,
which made it asymmetric with DatePicker for no stated reason.

Adds the root plumbing the part needs: `lock` on RangeProps, so `.Grid`
holds the locked endpoint and takes only the clicked day — "fix the
start, pick the end" no longer means disabling the whole picker, closing
the partial-disable gate; `onValidityChange`, which reports a reason
rather than a stringly-typed message and renders no UI itself; and
internal active-field tracking that a locked endpoint can never win.

Four behaviours CLD-3214 #11 left open are answered with defaults, each
documented at its call site: a typed start past the end clears the end
rather than swapping; focus advances only on an explicit Enter; an
emptied field clears that endpoint and is not an error; and typing moves
the visible month. All four are design's to overturn.

Stale drafts are dropped by adjusting state during render, the way
`tour-root.tsx` does, rather than in an effect whose dependency array
would be a change-trigger rather than a real dependency — so the
component still carries no lint suppressions.

Three tests pin what each input placement costs: `.RangeInput` works
inside `.Content`; inside `.Trigger` the popup takes initial focus, so
keystrokes reach the grid instead of the field and Enter selects a day;
it works inside `.Trigger` only when `.Content` declines initial focus.
`.Content`'s default is deliberately unchanged pending that decision.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
An audit of the contract rather than the code found eight problems the
49 existing tests did not cover, because they tested what was built
instead of what was promised. Each now has a regression test.

`parseDate` threw on invalid input whenever a `timeZone` was set:
`dayjs.tz` does not validate, it raises RangeError. With `.RangeInput`
parsing on every commit, a consumer setting `timeZone` got a crash on an
ordinary keystroke — the same failure class as the 0.49.0 P0. The strict
zone-free parse now gates it, so `dayjs.tz` never sees bad input.

Root `readOnly` was dead: `.Grid` never read it, so clicks still wrote.
It now refuses writes while leaving days legible and focusable, which is
what separates it from `disabled`.

Root `disabled` did not gate the popover — days were disabled but the
surface still opened. The root refuses to open, and `.Trigger` reports
it.

The visible month never followed the value: a picker holding a date in
another year opened on today. It now derives from the value when no
`defaultMonth` is given, for all three selection modes.

`.RangeInput` overwrote `Input`'s own `data-slot="input"`, because
`Input` spreads `...props` last — one component silently breaking
another's semver-covered slot. The slot and the active flag moved to a
wrapper, which also gives the active style an element that owns a
border; the previous rule coloured an inner input whose border is
`none`, so it never showed.

`lock` blocked deselect. The unlocked end is now driven from the clicked
day alone, and re-clicking it clears it.

Stale drafts compare `dayKey`, not formatted text — a format without a
year renders the same string for two different years and would miss the
change. This is also what the RFC always claimed the adapter was for.

`.Content` misroutes popup-only props to the positioner. Partitioning by
an enumerated key list was tried and reverted: Base UI has 20
positioning props, and a minor bump adding one would misroute it
silently. Documented as a known limitation shared with `Popover.Content`.

Drops the unused `epoch` and `isSameDay` adapter exports.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`.Input` is the single-date sibling of `.RangeInput`, built with the
audit's fixes already in place: its slot sits on a wrapper so `Input`'s
own `data-slot` survives, the draft is compared on `dayKey` rather than
formatted text, and an empty field clears rather than erroring.

`.Nav` is a caption plus previous / next buttons, and no `Select` — the
concrete end of the `captionLayout` bug. Steps are offered whenever the
target month holds any selectable day, not just when its first day is in
range, so a `minDate` falling mid-month no longer strands navigation.

The design shows no caption inside the grid, and rendering both drew the
month twice and announced it twice, so `.Grid` now drops RDP's
`MonthCaption` and `.Nav` owns it. Compositions that assert the month
therefore render `.Nav`.

The design's third nav button is not built: its action is unsettled
(RFC 005 open item 9), and guessing it would bake a name into a
semver-covered slot.

Adds `endOfMonth` to the adapter for the reachability check.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Day | Month | Quarter | Half-year | Year, as Apsara `Tabs` with
`variant='standalone'` — the variant the design uses, and the same one
its month and quarter cells are built from, so the switcher and the
grids it switches between share one visual language.

The root now owns granularity the way it owns every other piece of
state: `useControlled` over `granularity` / `defaultGranularity` /
`onGranularityChange`, with `granularities` listing what may be switched
between. `defaultGranularity` and `onGranularityChange` are additions to
the RFC's Root Props block, which named only `granularity` and
`granularities` — without them a tab click has nowhere to go.

The part renders nothing unless more than one granularity is offered, so
it can sit in a shared composition without appearing on
single-granularity pickers, and it always renders in the canonical order
whatever order the prop gave.

`.Grid` now renders for the day granularity only. Showing the day grid
under a Month tab would misstate what is selectable; `.MonthGrid` covers
the rest and lands in phase 3.

The slot sits on a wrapper, not on `Tabs` — passing `data-slot` to it
would overwrite its own `data-slot="tabs"`, the defect the audit found in
`.RangeInput`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Checking console output during the test run — which grepping for
pass/fail had been hiding — surfaced a `useControlled` warning that had
been printing for two commits. Deriving the initial month from a live
`value` recomputed the default on every render, so a controlled value
moving fed `useControlled` a changing `default`: it warns, and risks
re-initialising the visible month underneath the user. Computed once
into a ref instead. Console output is now part of the check.

`.Nav` captioned a two-month grid with a single month, naming April
while April and May were both shown. It takes `months` and captions the
range.

`.Nav` also rendered under non-day granularities and stepped by month
there, which means nothing for a year view. It now renders for the day
granularity only — as the design does, hiding that header entirely in
its month variant, because those views scroll rather than page.

A granularity outside `granularities` produced a tab strip with nothing
selected and no grid. `granularities` defaults to the active granularity
rather than `['day']`, so the active one is always offered.

Two suspicions were cleared rather than fixed: inside a `Field`,
`.Input` receives `aria-invalid` and a label association identically to
a plain `Input`, so the RFC's Field-integration claim holds; and
`disabled` on `.Trigger` renders as `aria-disabled`, not an invalid
attribute on a div.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Month, quarter, half-year and year selection, shaped from the design
rather than guessed: month, quarter and half-year group under a year
heading at three, four and two columns; year is a flat full-width list
with no heading at all. It scrolls through years rather than paging,
which is why `.Nav` renders for the day granularity only — there is
nothing to page here.

**It emits the first day of the chosen period.** Whether quarter and
half-year should instead emit a `{ from, to }` range is RFC 005 open
item 1, still undecided. The `Date` form is taken because it leaves the
value union unchanged and can be widened later without a break, where
the reverse would not be true.

Cells are plain buttons, not Apsara `Tabs`. The design reuses the
standalone tab *visual* for them, but tab semantics without tabpanels
would give a month picker the wrong ARIA.

Works across all three selection modes: single writes the period start,
range writes it into the active endpoint while honouring `lock`, and
multiple toggles. Out-of-bounds periods are disabled and `readOnly`
refuses writes, matching `.Grid`.

The scroll viewport is a component-local custom property rather than a
bare hardcoded height — no `--rs-*` size fits 192px, and the pattern
matches `tabs.module.css`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The root buffers edits under `commit='explicit'` so a popover can be
abandoned without the parent ever seeing intermediate states. `.Apply`
commits and closes, `.Cancel` discards and closes, and dismissing the
surface any other way discards too — only `.Apply` keeps a buffered
value.

`.Apply` is disabled while there is nothing buffered. Under the default
`commit='immediate'` the value is already committed on each interaction,
so `.Apply` is simply a close button.

This is what made presets and a footer expressible: the RFC's `footer`
prop was a bare ReactNode with no way to write back into state.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The component built and exported correctly but was invisible on
`pnpm start`: the docs sidebar auto-discovers from
apps/www/src/content/docs/components/<name>/, and calendar-preview had
no directory there.

Adds the page, six demo groups and a seven-control playground. No scope
registration was needed — the demo renderer spreads `...Apsara`, so the
root barrel export is enough.

Every demo with a typed trigger passes `initialFocus={false}` on
`.Content`. That is load-bearing, not decoration: without it the popup
takes focus on open and keystrokes never reach the field. It also puts
the unresolved focus decision somewhere visible rather than buried in a
test.

Verified generated at /docs/components/calendar-preview.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Hour and minute for the selected date, plus AM/PM under `hourCycle={12}`.
Minutes snap to `step`, so the field cannot express a time it does not
offer.

It edits the time of an existing selection rather than creating one.
With nothing selected there is no day to attach a time to, and
inventing "today" would be a silent decision, so the fields are empty
and disabled until a date exists.

Follows the same targeting rule as `.MonthGrid`: single edits the value,
range edits the active endpoint while honouring `lock`, multiple edits
the most recent entry. Out-of-range input is rejected without touching
the value, and `readOnly` refuses writes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Running the build surfaced seven public types reaching the component
index but not the root barrel — among them
`CalendarPreviewRangeInputProps`, so `import type { … } from
'@raystack/apsara'` failed and a consumer could not type a RangeInput
wrapper.

That is RFC 005 problem 10 word for word, reproduced inside the rewrite
meant to fix it. Nothing caught it: type-only exports are invisible at
runtime so tests cannot see them, and `tsc` is satisfied because the
types do exist — just not where a consumer can reach them. Only reading
the built `dist/index.d.ts` shows it.

Adds a guard comparing the component index against the root barrel,
verified by deleting an export and confirming it fails with the offending
name before restoring it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three of the four upgrades the RFC's dependency table flags. dayjs and
@base-ui/utils were already inside their manifest ranges and needed only
the lockfile; @base-ui/react moves a minor, which touches every
component in the library.

Verified: 2812 tests pass, `tsc` reports the same six pre-existing
errors in the same six files as before the bump, and the turbo build is
clean across the library and the docs site.

react-day-picker is left at 9.6.7 deliberately — see the next commit
message or RFC 005's Alternatives table.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two majors, kept as its own commit so it can be reverted or cherry-picked
without touching the rewrite — the RFC's reason for scoping it out was
that a day-grid regression should be attributable to either the upgrade
or the rewrite, not both at once.

Verified against the published 10.0.1 package rather than assumed: all
five identifiers `CalendarPreview` imports are present, all three custom
components it overrides (`DayButton`, `MonthCaption`, `MonthGrid`), all
seventeen props it sets, and all sixteen `classNames` keys. Its
`types/selection.d.ts` is byte-identical to 9.6.7 ignoring comments, so
the mode/required union that forces `.Grid` into three call sites is
unchanged — the upgrade neither helps nor hinders the rewrite.

The deprecated v8-era props v10 drops are referenced nowhere in the
package; the old family's `DropdownProps` import survives v10.

2812 tests pass, the six pre-existing tsc errors are unchanged in count
and location, the turbo build is clean, and the calendar suites emit no
new runtime warnings.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Auditing combinations rather than parts — twelve parts each had their own
tests, but the interactions between them had none.

`.MonthGrid` lit a cell only when a selected date *started* its period.
Picking 17 April in the day grid and switching to Month therefore showed
an empty grid, which reads as lost state. Cells now light when the value
falls anywhere inside the period, at every granularity, while a click
still writes the period start. The earlier reasoning — that lighting
April claims a precision the value lacks — loses to the reading that the
selection has vanished.

`.Cancel` ignored root `disabled` while `.Apply` honoured it, so a
disabled picker rendered one live button and one dead one.

Also checked and found correct, so left alone: `commit='explicit'`
buffering through `.TimeField` and `.MonthGrid`, dismissal discarding
those buffers, `readOnly` across every part, `lock` targeting with a null
unlocked endpoint, and multiple-selection time editing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
apsara Ready Ready Preview Aug 30, 2026 1:01pm

@coderabbitai

coderabbitai Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Aug 30, 2026

Copy link
Copy Markdown

Open in StackBlitz

pnpm add https://pkg.pr.new/@raystack/apsara@891

commit: 04b21ef

@Shreyag02
Shreyag02 marked this pull request as draft August 30, 2026 11:37
FilterChip composes CalendarPreview parts instead of configuring a
DatePicker through `slotProps`. That deletes the shallow `slotProps.input`
merge — where a consumer-supplied `classNames` object could replace the
chip's own container class and break its layout — along with
`toDateValue()` and the two dead `[class*="…"]` rules reaching at hashed
class names `Input` never rendered.

The chip's styling now hangs off its own wrapper and reaches `Input`
through that component's public `data-slot` names, so a consumer class
can no longer displace it. `initialFocus={false}` on `.Content` is
required rather than cosmetic: the trigger holds a typed field.

DataView fields gain `filterProps.calendar`, which the 0.49.0 notes
already claimed existed but which only DataTable had.

Both filter-operations modules drop their own `dayjs.extend()` calls and
compare dates through the adapter, removing the import-order dependence
behind the 0.49.0 keystroke crash. Comparisons are expressed as day-level
predicates, and a row value that will not parse compares false against
every operator — matching the previous behaviour, where invalid dayjs
comparisons returned false.

Adds the CHANGELOG entry the RFC lists as a phase 5 exit criterion, which
is where the break is announced.

BREAKING CHANGE: `FilterChipCalendarProps` was a subset of
`DatePickerProps` and is now a subset of `CalendarPreview`'s root props.
`dateFormat` becomes `format`, `onSelect` becomes `onValueChange`,
`startMonth`/`endMonth` become `minDate`/`maxDate`, and `slotProps`,
`inputProps` and `showCalendarIcon` are gone. This reaches DataTable's and
DataView's `filterProps.calendar`. FilterChip's date `data-slot` names
change with it: `date-picker-input` becomes `calendar-preview-input`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Resolves RFC 005 open item 9. The design's third nav button is a
revert, not a today-jump — which is why its glyph is Undo.

It appears only when the root was given a `defaultValue` and the current
value differs from it, and pressing it restores that default. Absent
rather than disabled when there is nothing to revert to, because a
control that can never do anything is noise.

`defaultValue` is read live rather than captured at mount, so this works
for a controlled picker too: there it reads as "the value to revert to"
rather than "the initial value". Equality compares the exact instant
across all three selection modes, so a time-of-day edit counts as a
change.

Adds `UndoIcon` to the icon registry, drawing lucide `Undo2`. The set
goes from 31 to 32 keys, and the seven places that state that count —
`icons.tsx`, the bundle test, two CHANGELOG lines, two docs lines and the
demo scope comment — are updated with it.

RFC: open item 9 removed and the remaining items renumbered; `.Nav`'s
row, the part tree and the slot list now name the button, which takes
the new-slot count to ten.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Closes RFC 005 open item 1, answered from the reference app's own
network payloads rather than from the two options the RFC posed. It
sends neither a bare date nor a `{ from, to }` range: it sends the first
day of the period *plus* a resolution marker — `startDate: "2026-06-01"`
with `startDateResolution: "month"`, and no marker at all for a day.

So the value stays a `Date` and the union is unchanged, which is what
was already shipping. What was missing is the other half: a consumer had
no way to tell `1 June` chosen as a day from June chosen as a month.
`onValueChange` now takes a second argument naming the granularity that
produced the value, on every path including a buffered `Apply`.

The typed field follows the granularity too, reading `Jun 2026`,
`Q3 2026`, `H1 2026` or `2026` rather than a full date, and parsing the
same forms back to the first day of the period. `format` now applies to
the day granularity only; the empty-field hint follows suit.

Boundary cases are covered by tests, since an off-by-one in the period
maths is invisible in the middle of a quarter: 1 July is Q3 and H2, 31
December is Q4, 1 January is Q1 and H1.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Typing `Q4 2027` into a day field now switches to Quarter and commits in
one go, matching the reference app's `Try: May 2027, Q4, 20/05/2027`
hint. A bare `Q4` or `H1` resolves against the year on screen rather
than today's, so it follows where the user has navigated.

Purely additive: the active granularity is tried first and only a
failure falls through to the scan, so nothing that parsed before parses
differently now. Candidates are tried most-specific-first — `15 Jun
2026` must read as a day, never as a year — and only granularities the
picker offers are considered, so a day-only picker rejects `Q4` rather
than switching to a tab that is not there.

Writing the test caught a real defect: `setValue` read `granularity`
from its closure, so a cross-granularity commit switched the tab to
quarter while reporting `{ granularity: 'day' }` — the details
contradicted the switch that had just happened. The producing
granularity now travels with the value, including through a buffered
`Apply`, which needed the buffer to remember what it was picked at.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Closes the presets open item. The RFC's own part tree and API example
already drew the children form, and every part tree in this library is
children-based — `presets={[…]}` would have been the outlier, not the
convention.

`.Preset` writes straight into root state, so it needs no callback, and
marks itself pressed while the value matches. It brings the applied
period into view the way typing does, and buffers under
`commit='explicit'` like any other edit.

It deliberately does not close the popover: under `commit='explicit'`
that would discard the very edit it just made, and for a range you want
to see what was applied. Compose `.Apply`, or close from
`onValueChange`.

Passing `range` to a single picker — or `value` to a range one — throws
at render rather than on click, because a handler throw does not reach
the caller and the stack would point at whatever the bad shape later
broke rather than at the preset. The throw sits after every hook so the
hook order stays stable.

Value equality moved from the root into the context module, so `.Preset`
and the `.Nav` revert button compare the same way rather than each
carrying their own idea of it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…urring

`CalendarValueChangeDetails` types the second argument of a public
callback but was never exported, so a consumer could not write a typed
`onValueChange`. That is the same class of defect as the earlier
`CalendarPreviewRangeInputProps` miss, and the guard added for that one
did not catch it: it compared the component index against the barrel, so
a type that never reached the index was invisible to it. The guard now
also asserts that every type the component declares public is published,
against a short list of deliberate internals.

Three audits running have found `data-slot` names shipping without ever
reaching a document — this time `-meridiem`, `-month-grid-year`, `-nav`,
and the two nav chevrons the map only described in prose. Slot names are
semver-covered API, so the docs page now carries the authoritative table
of all 25, and a test asserts it matches what the component emits in
both directions.

Both guards were verified by removing an entry and confirming the
failure names it, then restoring.

Also probed and found correct, so left alone: FilterChip's placeholder
override still beating the granularity-derived default, clearing a field
under a non-day granularity, cross-granularity typing into a range's end
field, the revert button tracking preset-applied values, and the range
fields reading `Q1 2026` / `Q3 2026`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Closes DES-630 D10 and CLD-3214 #18, which specified the answer rather
than only the problem: a full-component skeleton with caption and grid
both shimmering and every control disabled, in place of the old
half-skeleton where the chrome stayed live over data that had not
arrived.

`loading` folds into `disabled` once, in the root, rather than each part
checking both flags — asking a dozen parts to remember two conditions is
how one of them ends up operable. `.Nav` swaps its caption, `.Grid` and
`.MonthGrid` replace themselves outright rather than overlaying, so no
day underneath stays focusable. Each shimmer region carries `aria-busy`;
the shimmer itself is already `aria-hidden`.

Building it turned up a third variant of a trap this component has now
hit three times: `Input` spreads consumer props last and so *clobbers*
its own `data-slot`, `Tabs` does the same, and `Skeleton` spreads
nothing and so silently *drops* one. The slot goes on a wrapper in every
case. The slot-documentation test caught the resulting omission
immediately, which is what it was added for.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Shreyag02 and others added 2 commits August 30, 2026 18:25
Five files unrelated to the calendar work were being carried in the PR:
`hooks/index.tsx`, `hooks/useCopyToClipboard.tsx`, `style.css`,
`styles/radius.css` and `styles/spacing.css`. None was edited
deliberately — `git add -A` over the package staged whatever was
modified, and the pre-commit hook reformats staged files, so import
order, quote style and indentation churned in files this branch has no
business touching.

Reverted to `main`. Each was verified to differ from `main` only in
whitespace and quote style before reverting, by comparing the two with
both stripped, so nothing semantic goes back with them.

Tests, types and the CSS token check are unchanged afterwards, which
also confirms nothing in the component was relying on the reformatting.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`style.css`, `radius.css` and `spacing.css` reverted cleanly, but the
pre-commit hook globs `.tsx` and rewrites whatever is staged, so it
re-formatted `hooks/index.tsx` and `hooks/useCopyToClipboard.tsx` the
moment the revert was staged. Both are unformatted on `main`, so any
branch that stages them drags a reformat into its diff.

Committed with `--no-verify` for that reason and no other: the point is
to leave these two files exactly as `main` has them. Formatting them is
worth doing, but as its own change, not as noise inside a calendar PR.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant