| BLOCKING |
Import |
OneCalendar/OneCalendar.test.tsx:1 |
import React from "react" — default import is forbidden |
Remove entirely (React 17+ JSX transform) |
| BLOCKING |
Folder structure |
OneCalendar/OneCalendar.test.tsx |
Test file is at component root, not inside __tests__/ subfolder |
Move to OneCalendar/__tests__/OneCalendar.test.tsx |
| BLOCKING |
Folder structure |
OneCalendar/OneCalendar.stories.tsx |
Story file is at component root, not inside __stories__/ subfolder |
Move to OneCalendar/__stories__/OneCalendar.stories.tsx |
| BLOCKING |
Story |
OneCalendar/OneCalendar.stories.tsx |
No Snapshot story with withSnapshot({}) for Chromatic |
Add export const Snapshot: Story = { parameters: withSnapshot({}) } |
| BLOCKING |
Story tags |
OneCalendar/OneCalendar.stories.tsx:24 |
tags: ["autodocs"] missing stability tag |
Add "stable" or "experimental" |
| BLOCKING |
displayName |
OneCalendar/OneCalendar.tsx |
OneCalendarInternal function component has no displayName |
Add OneCalendarInternal.displayName = "OneCalendarInternal" |
| BLOCKING |
Encapsulation |
OneCalendar/OneCalendar.tsx |
OneCalendarInternal exported publicly — internal implementation detail leaked |
Export from a separate internal entry point, not the main public file |
| BLOCKING |
Internal type leak |
OneCalendar/OneCalendar.stories.tsx:65 |
type OneCalendarInternalStory = StoryObj<Meta<typeof OneCalendarInternal>> wraps private OneCalendarInternal in the public story file |
Move compact/internal stories to a separate __stories__/OneCalendarInternal.stories.tsx |
| BLOCKING |
Animation / Reduced Motion |
granularities/day/DayView.tsx:1 |
AnimatePresence + motion.div with duration: 0.15 and x-axis translation — no useReducedMotion() guard |
Import useReducedMotion from motion/react; set duration: 0 and skip translate variants when true |
| BLOCKING |
Animation / Reduced Motion |
granularities/month/MonthView.tsx:1 |
Same — motion.div slide animation with duration: 0.15, no useReducedMotion() check |
Same fix |
| BLOCKING |
Animation / Reduced Motion |
granularities/year/YearView.tsx:1 |
AnimatePresence + motion.div, no useReducedMotion() import or check |
Same fix |
| BLOCKING |
Animation / Reduced Motion |
granularities/week/WeekView.tsx:1 |
motion.div with duration: compact ? 0.1 : 0.15, no reduced-motion guard |
Same fix |
| BLOCKING |
Animation / Reduced Motion |
granularities/quarter/QuarterView.tsx:1 |
AnimatePresence + motion.div, no useReducedMotion() guard |
Same fix |
| BLOCKING |
Animation / Reduced Motion |
granularities/halfyear/HalfyearView.tsx:1 |
AnimatePresence + motion.div, no useReducedMotion() guard |
Same fix |
| BLOCKING |
Form semantics |
granularities/quarter/QuarterView.tsx |
Quarter <button> elements missing type="button" — will submit ancestor forms |
Add type="button" to every quarter button |
| BLOCKING |
Form semantics |
granularities/halfyear/HalfyearView.tsx |
Halfyear <button> elements missing type="button" |
Add type="button" to every halfyear button |
| BLOCKING |
Form semantics |
granularities/year/YearView.tsx |
Year <button> elements missing type="button" |
Add type="button" to every year button |
| BLOCKING |
Tests missing |
OneCalendar/granularities/range/ |
No test file for range granularity — range/index.tsx has zero coverage |
Create range/__tests__/index.test.tsx covering toRange, toRangeString, toString, fromString, navigate, getPrevNext |
| BLOCKING |
Story type |
OneEmptyState/__stories__/OneEmptyState.stories.tsx:20 |
type Story = StoryObj<typeof OneEmptyState> — must be StoryObj<typeof meta> |
Change to type Story = StoryObj<typeof meta> |
| BLOCKING |
Story |
OneEmptyState/__stories__/OneEmptyState.stories.tsx |
No Snapshot story with withSnapshot({}) |
Add export const Snapshot: Story = { parameters: withSnapshot({}) } |
| BLOCKING |
displayName |
OneEmptyState/OneEmptyState.tsx |
_OneEmptyState has no displayName |
Add _OneEmptyState.displayName = "OneEmptyState" |
| BLOCKING |
Tests missing |
OneEmptyState/ |
No __tests__/ directory — entire component is untested |
Create OneEmptyState/__tests__/OneEmptyState.test.tsx with render, variant, action, and dataTestId tests |
| BLOCKING |
Direct lucide-react import |
OneEmptyState/__stories__/OneEmptyState.stories.tsx:3 |
import { Plus } from "lucide-react" — must use @/icons/app wrapper |
Replace with import { Plus } from "@/icons/app" |
Component Group: OneCalendar / OneEmptyState
Sequential stability audit — part of the component-by-component quality sweep.
Reviewers: Code Review · A11y · Storybook · Test Coverage
BLOCKING
OneCalendar/OneCalendar.test.tsx:1import React from "react"— default import is forbiddenOneCalendar/OneCalendar.test.tsx__tests__/subfolderOneCalendar/__tests__/OneCalendar.test.tsxOneCalendar/OneCalendar.stories.tsx__stories__/subfolderOneCalendar/__stories__/OneCalendar.stories.tsxOneCalendar/OneCalendar.stories.tsxSnapshotstory withwithSnapshot({})for Chromaticexport const Snapshot: Story = { parameters: withSnapshot({}) }OneCalendar/OneCalendar.stories.tsx:24tags: ["autodocs"]missing stability tag"stable"or"experimental"OneCalendar/OneCalendar.tsxOneCalendarInternalfunction component has nodisplayNameOneCalendarInternal.displayName = "OneCalendarInternal"OneCalendar/OneCalendar.tsxOneCalendarInternalexported publicly — internal implementation detail leakedOneCalendar/OneCalendar.stories.tsx:65type OneCalendarInternalStory = StoryObj<Meta<typeof OneCalendarInternal>>wraps privateOneCalendarInternalin the public story file__stories__/OneCalendarInternal.stories.tsxgranularities/day/DayView.tsx:1AnimatePresence+motion.divwithduration: 0.15and x-axis translation — nouseReducedMotion()guarduseReducedMotionfrommotion/react; setduration: 0and skip translate variants when truegranularities/month/MonthView.tsx:1motion.divslide animation withduration: 0.15, nouseReducedMotion()checkgranularities/year/YearView.tsx:1AnimatePresence+motion.div, nouseReducedMotion()import or checkgranularities/week/WeekView.tsx:1motion.divwithduration: compact ? 0.1 : 0.15, no reduced-motion guardgranularities/quarter/QuarterView.tsx:1AnimatePresence+motion.div, nouseReducedMotion()guardgranularities/halfyear/HalfyearView.tsx:1AnimatePresence+motion.div, nouseReducedMotion()guardgranularities/quarter/QuarterView.tsx<button>elements missingtype="button"— will submit ancestor formstype="button"to every quarter buttongranularities/halfyear/HalfyearView.tsx<button>elements missingtype="button"type="button"to every halfyear buttongranularities/year/YearView.tsx<button>elements missingtype="button"type="button"to every year buttonOneCalendar/granularities/range/rangegranularity —range/index.tsxhas zero coveragerange/__tests__/index.test.tsxcoveringtoRange,toRangeString,toString,fromString,navigate,getPrevNextOneEmptyState/__stories__/OneEmptyState.stories.tsx:20type Story = StoryObj<typeof OneEmptyState>— must beStoryObj<typeof meta>type Story = StoryObj<typeof meta>OneEmptyState/__stories__/OneEmptyState.stories.tsxSnapshotstory withwithSnapshot({})export const Snapshot: Story = { parameters: withSnapshot({}) }OneEmptyState/OneEmptyState.tsx_OneEmptyStatehas nodisplayName_OneEmptyState.displayName = "OneEmptyState"OneEmptyState/__tests__/directory — entire component is untestedOneEmptyState/__tests__/OneEmptyState.test.tsxwith render, variant, action, anddataTestIdtestsOneEmptyState/__stories__/OneEmptyState.stories.tsx:3import { Plus } from "lucide-react"— must use@/icons/appwrapperimport { Plus } from "@/icons/app"SUGGESTION
OneCalendar/OneCalendar.tsxOne*prefix is legacy namingF0Calendarat a breaking-change windowOneEmptyState/OneEmptyState.tsxOne*prefix is legacy namingF0EmptyStateat a breaking-change windowOneCalendar/types.tsCalendarView,CalendarMode, and other public types usetype— preferinterfacefor public prop shapesinterfaceOneEmptyState/types.tsActionProps,OneEmptyStatePropsusetype— preferinterfaceinterfaceOneCalendar/OneCalendar.stories.tsx:37options: [0,1,2,3,4,5,6]hardcoded instead of referencing exportedWeekStartDayObject.values(WeekStartDay)OneCalendar/OneCalendar.stories.tsx:619–772CompactMonthSingle,CompactMonthRange,CompactWeek,CompactDayRange, andRegularVsCompactrender<OneCalendarInternal>directly, bypassing the public APIcompactas a public prop, or move these to a private story fileOneCalendar/OneCalendar.stories.tsxdefaultMonthnot set in several stories — calendar may show unexpected months if MockDate were removeddefaultMonthin each storyOneCalendar/OneCalendar.tsxnavigate,getHeaderLabel, andhandleSelectare plainconstinside render — recreated every renderuseCallbackOneCalendar/OneCalendar.tsxuseEffecthooks suppress missing-dep warnings via eslint-disableOneCalendar/utils.tsimport * as locales from "date-fns/locale"— namespace import pulls in entire locale bundlegranularities/month/MonthView.tsxaria-current— AT users cannot identify today's montharia-current="date"whenisCurrentis truegranularities/year/YearView.tsxaria-currentaria-current="date"whenisCurrentis truegranularities/quarter/QuarterView.tsxaria-currentaria-current="date"whenisCurrentis truegranularities/halfyear/HalfyearView.tsxaria-currentaria-current="date"whenisCurrentis truegranularities/quarter/QuarterView.tsx<div>elements forisStart/isEndlackaria-hidden="true"aria-hidden="true"to both decorative divsgranularities/halfyear/HalfyearView.tsxaria-hidden="true"aria-hidden="true"to both decorative divsOneCalendar/OneCalendar.tsx<div>with noaria-livearia-live="polite"andaria-atomic="true"to the header label containerOneCalendar/OneCalendar.tsxroleoraria-label— AT users cannot identify this widgetrole="group"witharia-labelfromuseI18n()OneEmptyState/OneEmptyState.tsx<p>— screen reader users cannot navigate to it via heading shortcuts<h2>by default, or accept aheadingLevelpropOneEmptyState/OneEmptyState.tsxemoji!non-null assertion whenemojiis optionalemoji && <F0AvatarEmoji emoji={emoji} ... />OneEmptyState/OneEmptyState.tsxaction.labelused askeyin actions.map()— labels not guaranteed uniqueidfield toActionPropsor use index as keyOneCalendar/__tests__/OneCalendar.test.tsxonSelectcallbackgranularities/day/__tests__/index.test.tsx:10const i18n = {}typed as empty object — may mask type errorsTranslationsTypeshapeOneEmptyState/__tests__/(to create)UpsellingButtonaction variantCopy-pasteable agent fix prompt