diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 7459266..01aabb1 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,7 +1,7 @@ --- name: Bug Report about: Create a report to help us improve calendar-simple -title: "" +title: "[Bug]: " labels: bug assignees: "" --- @@ -17,16 +17,28 @@ Steps to reproduce the behavior: 3. Scroll down to '....' 4. See error +**Minimal reproduction** +If possible, link a minimal reproduction (StackBlitz, CodeSandbox, or a small repo). This is the fastest way to get a fix. + **Expected behavior** A clear and concise description of what you expected to happen. -**Screenshots** -If applicable, add screenshots to help explain your problem. +**Screenshots / recordings** +If applicable, add screenshots or a short recording to help explain your problem. + +**Affected view(s)** +Which calendar view(s) does this affect? (Month, Week, Day, Custom Days, Schedule, or all) **Environment (please complete the following information):** -- Browser: [e.g. chrome, safari] -- Component Version: [e.g. 1.0.0] +- `calendar-simple` version: [e.g. 1.2.0] +- React version: [e.g. 19.2.0] +- Browser: [e.g. Chrome 124, Safari 17] +- OS: [e.g. Windows 11, macOS 14] +- Is RTL / dark mode / a custom locale enabled? [yes/no — which] + +**Did this work in a previous version?** +If this is a regression, which version last worked? **Additional context** -Add any other context about the problem here. +Add any other context about the problem here (relevant props, event data, console errors). diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 1930a97..dc472cc 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,7 +1,7 @@ --- name: Feature Request -about: Suggest an idea for this project -title: "" +about: Suggest an idea or improvement for calendar-simple +title: "[Feature]: " labels: enhancement assignees: "" --- @@ -12,8 +12,21 @@ A clear and concise description of what the problem is. Ex. I'm always frustrate **Describe the solution you'd like** A clear and concise description of what you want to happen. +**Which area does this affect?** +e.g. a specific view (Month/Week/Day/Custom Days/Schedule), theming, accessibility, localization/RTL, events/layout, or the public API. + +**Proposed API (if applicable)** +If your idea introduces or changes props, callbacks, or types, sketch what the API might look like. + +```tsx +// Example usage of the proposed feature +``` + **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. +**Are you willing to contribute this?** +Would you be open to opening a PR for this feature? (We're happy to help — see [CONTRIBUTING.md](../../CONTRIBUTING.md).) + **Additional context** -Add any other context or screenshots about the feature request here. +Add any other context, mockups, or screenshots about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 4f265b2..c3fdcaa 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,12 +1,11 @@ -## Pull Request Checklist - -- [ ] My code follows the code guidelines of this project -- [ ] I have updated the documentation accordingly (if applicable) -- [ ] Tests and builds pass locally + ## Description -Please include a summary of the change and which issue is fixed. +Please include a summary of the change and the motivation behind it. Fixes # (issue) @@ -16,12 +15,27 @@ Fixes # (issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Documentation update -- [ ] This change requires a documentation update +- [ ] Refactor / chore (no functional change) + +## Pull Request Checklist + +- [ ] My PR targets the `dev` branch +- [ ] My code follows the project's coding guidelines (TypeScript, CSS Modules, Luxon for dates) +- [ ] My commit messages follow the [Conventional Commits](https://www.conventionalcommits.org/) spec +- [ ] I have added or updated tests that cover my change +- [ ] I have added or updated a Storybook story (if applicable) +- [ ] I have updated the documentation (`README.md`, `FEATURES.md`) where relevant +- [ ] All local checks pass: `npm run format:check`, `npm run lint`, `npm test`, `npm run build` ## How Has This Been Tested? -Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. +Please describe the tests you ran to verify your changes and provide instructions to reproduce. + +- [ ] Added/updated automated tests (`npm test`) +- [ ] Verified via Storybook (`npm run storybook`) +- [ ] Verified via the local playground (`cd playground && npm run dev`) +- [ ] Verified the build bundle (`npm run build`) + +## Screenshots / Recordings -- [ ] Tested via Storybook -- [ ] Tested via local playground application -- [ ] Verified build bundle (`npm run build`) +If your change affects the UI, please add before/after screenshots or a short recording. diff --git a/CLAUDE.md b/CLAUDE.md index 90c6d09..ff393ad 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -16,8 +16,8 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ### Code Quality -- `npm run lint` — Check for ESLint violations -- `npm run lint:fix` — Fix ESLint violations automatically +- `npm run lint` — Type-check (`tsc --noEmit`) **and** check for ESLint violations (there is no standalone typecheck script — `lint` covers it) +- `npm run lint:fix` — Type-check, then fix ESLint violations automatically - `npm run format` — Format all code with Prettier - `npm run format:check` — Check if code is formatted correctly @@ -64,6 +64,11 @@ Each view is a separate component receiving props via `useCalendarProps()`: - **ScheduleView** — Continuous scrollable list of events grouped by date - **View** — Wrapper component that renders the appropriate view based on context state +### Loading & Error Handling + +- **Loading states**: The `isLoading` prop has two behaviours. With **no events**, it replaces the body with a view-specific skeleton (`src/components/ui/skeleton/` — `MonthSkeleton`, `TimeGridSkeleton`, `ScheduleSkeleton`) or `renderLoading()` if provided. With **events present**, it keeps the calendar visible behind a non-interactive overlay so stale data stays on screen during a refresh. +- **Error boundary**: `CalendarErrorBoundary` (`src/components/ui/`) wraps the calendar; on a render error it shows an empty `data-testid="calendar-error-boundary"` element and stays silent (the host app's error reporting is expected to handle logging). + ### Prop Distribution Pattern **`useCalendarProps(localProps: T)`** merges context config with local overrides: @@ -77,10 +82,11 @@ This enables prop composition: global calendar props + view-specific overrides. ### Layout & Styling - **CSS Modules**: All styles co-located in `Component.module.css` files -- **Theme system**: `CalendarTheme` type provides color overrides (`default`, `selected`, `today`) +- **Theme system**: `CalendarTheme` provides `default`/`selected`/`today` color overrides. It is **scheme-aware**: flat keys apply to both schemes, while `dark` / `light` sub-objects take precedence when the resolved scheme matches. `width` / `height` props accept a number (px) or any CSS length string. - **Custom classes**: `CalendarClassNames` type allows targeting specific elements -- **CSS Variables**: Layout dimensions (`--calendar-width`, `--calendar-height`) set at root level -- **No Tailwind/SCSS**: Vanilla CSS modules only +- **Color scheme / dark mode**: The `colorScheme` prop (`'light'`/`'dark'`/`'auto'`, default `auto`) is resolved by `useColorScheme` (listens to `prefers-color-scheme`). The resolved value is written as `data-color-scheme="light"|"dark"` on the calendar root, which swaps the CSS custom-property palette defined in `src/styles/variables.css` (`:root` = light, `[data-color-scheme="dark"]` = dark). The `theme` prop still wins over the palette. +- **RTL**: The `direction` prop (`'ltr'`/`'rtl'`) defaults to `rtl` when `locale` is an RTL locale (ar, he, fa, ur, ps, sd, ckb, yi), else `ltr`. An explicit `direction` overrides auto-detection. +- **No Tailwind/SCSS**: Vanilla CSS modules + the global `variables.css` palette only ### Core Hooks (Event & Layout Logic) @@ -90,6 +96,7 @@ This enables prop composition: global calendar props + view-specific overrides. - **`useMonthGrid`** — Builds month calendar grid with week rows; handles adjacent month visibility - **`useScheduleView`** — Groups events by date for schedule layout; handles sorting - **`useResizeObserver`** — Observes container resize; provides width/height for responsive layout +- **`useColorScheme`** — Resolves the `colorScheme` prop to a concrete `'light'`/`'dark'` value, subscribing to the OS `prefers-color-scheme` media query when `auto` ### Event Types & Interfaces @@ -167,8 +174,8 @@ Multi-day events use `startDate` and `endDate` without time components; timed ev ### CSS Patterns - **Selectors**: Use CSS classes defined in module; avoid element selectors for encapsulation -- **Responsive**: Container query style — width/height props + ResizeObserver -- **Theme colors**: Applied via inline `style` prop or `classNames` override, not CSS variables +- **Responsive**: Container query style — width/height props + ResizeObserver; built-in breakpoints at 768px (tablet) and 480px (phone) +- **Color palette**: Light/dark colors live as CSS custom properties in `src/styles/variables.css`, swapped via the `[data-color-scheme="dark"]` attribute selector. Per-event/per-state `theme` prop colors are applied via inline `style`, overriding the palette. - **Layout**: Flexbox/Grid; no absolute positioning except for current-time line ### Git & Commits @@ -180,20 +187,23 @@ Multi-day events use `startDate` and `endDate` without time components; timed ev ## Key Files & Directory Structure -| Path | Purpose | -| --------------------------------- | -------------------------------------------------------------------- | -| `src/Calendar.tsx` | Root component; wraps in provider and dispatches to View | -| `src/context/CalendarContext.tsx` | State management, reducer, provider, and `useCalendar()` hook | -| `src/components/views/` | View implementations (Month, Week, Day, Schedule, CustomDays) | -| `src/components/core/` | Reusable core components (AllDayBanner, DayColumn, EventItems, etc.) | -| `src/hooks/` | Custom hooks (useEvents, useCalendarProps, layout hooks, etc.) | -| `src/utils/date.ts` | Luxon wrappers and date calculations | -| `src/utils/common.ts` | General utilities (event filtering, sorting, etc.) | -| `src/types/` | TypeScript interfaces and type definitions | -| `src/constants/` | Theme defaults, action types, layout constants | -| `src/styles/` | Global CSS variables | -| `src/stories/` | Storybook stories for all features and QA scenarios | -| `dist/` | Build output (auto-generated) | +| Path | Purpose | +| --------------------------------- | -------------------------------------------------------------------------- | +| `src/Calendar.tsx` | Root component; wraps in provider and dispatches to View | +| `src/context/CalendarContext.tsx` | State management, reducer, provider, and `useCalendar()` hook | +| `src/components/views/` | View implementations (Month, Week, Day, Schedule, CustomDays) | +| `src/components/core/` | Reusable core components (AllDayBanner, DayColumn, EventItems, etc.) | +| `src/components/ui/` | Popover, `CalendarErrorBoundary`, and loading skeletons (`skeleton/`) | +| `src/hooks/` | Custom hooks (useEvents, useCalendarProps, useColorScheme, layout hooks) | +| `src/utils/date.ts` | Luxon wrappers and date calculations | +| `src/utils/common.ts` | General utilities (event filtering, sorting, etc.) | +| `src/utils/formatting.ts` | UI string formatting (tooltip text, GMT offset, localized day/month names) | +| `src/utils/contrast.ts` | WCAG contrast helpers for accessible theme colors | +| `src/types/` | TypeScript interfaces and type definitions | +| `src/constants/` | Theme defaults, action types, layout constants | +| `src/styles/variables.css` | Global CSS custom properties + light/dark palette (`data-color-scheme`) | +| `src/stories/` | Storybook stories for all features and QA scenarios | +| `dist/` | Build output (auto-generated) | ## Important Context from Memory diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 1e616be..2c25cec 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -59,7 +59,10 @@ representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders responsible for enforcement. +reported to the community leaders responsible for enforcement by contacting the +project maintainer privately — open a confidential report via GitHub's +[private vulnerability reporting](https://github.com/Jaganath-MSJ/CalendarSimple/security/advisories/new) +or reach out to [@Jaganath-MSJ](https://github.com/Jaganath-MSJ). All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ce708d3..566eff5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,66 +1,105 @@ # Contributing to Calendar Simple -First off, thank you for considering contributing to `calendar-simple`! It's people like you that make open-source such a great community to learn, inspire, and create. +First off, thank you for considering contributing to `calendar-simple`! It's people like you that make open source such a great community to learn, inspire, and create. + +This document explains how to set up the project, the workflow we follow, and the standards we expect. By participating, you agree to abide by our [Code of Conduct](./CODE_OF_CONDUCT.md). ## Where do I go from here? -If you've noticed a bug or have a feature request, make one! It's generally best if you get confirmation of your bug or approval for your feature request this way before starting to code. +If you've noticed a bug or have a feature request, [open an issue](https://github.com/Jaganath-MSJ/CalendarSimple/issues/new/choose) first. It's generally best to get confirmation of a bug or approval for a feature request before you start coding — it saves everyone time. + +For security vulnerabilities, **do not** open a public issue. Follow the process in our [Security Policy](./SECURITY.md) instead. ## Setting up your environment -1. **Fork the repo** and clone it to your local machine: +This is a React 19 + TypeScript library bundled with Vite. You'll need **Node.js ≥ 18 LTS** (the CI matrix runs on 20.x and 22.x). + +1. **Fork the repo** and clone your fork: ```bash git clone https://github.com/YOUR-USERNAME/CalendarSimple.git cd CalendarSimple ``` -2. **Install dependencies**: - We recommend using `npm` to ensure compatibility. +2. **Install dependencies** with `npm` (used in CI and for the lockfile): ```bash npm install ``` -3. **Run the local environment**: - The easiest way to develop and test components is via Storybook or the playground application. +3. **Run the local environment**. There are two ways to develop and test: ```bash - # To run Storybook + # Storybook — the primary way to develop and visually test components (port 6006) npm run storybook - # To run the playground (if applicable) + # The playground — a standalone Vite app that consumes the library locally. + # It lives in ./playground and links the library via "file:..". + cd playground + npm install npm run dev ``` ## Development Workflow -1. **Create a branch**: - Create a new branch for your work: `git checkout -b feature/your-feature-name` or `fix/your-fix-name`. +1. **Create a branch off `dev`.** All work branches from and merges back into `dev` — not `main`. + + ```bash + git checkout dev + git pull + git checkout -b feature/your-feature-name # or fix/your-fix-name + ``` + +2. **Make your changes**, following the existing structure and conventions (TypeScript, React hooks, CSS Modules, Luxon for all date logic). See [CLAUDE.md](./CLAUDE.md) for a detailed architecture overview. -2. **Make your changes**: - Write your code, following the existing structure and keeping things consistent (TypeScript, React hooks, CSS Modules). +3. **Write tests.** This project follows a test-driven approach. Add or update tests alongside your change (see [Testing](#testing) below). -3. **Commit your changes**: - We use `semantic-release`. Please write your commit messages following the Conventional Commits specification. +4. **Commit using Conventional Commits.** We use `semantic-release` and `commitlint`, so commit messages drive versioning and the changelog. Malformed messages are rejected by the commit hook. - `feat: add new schedule view` - `fix: resolve timezone rendering bug` - - `docs: update readme with usage examples` + - `docs: update README with usage examples` + - `test: add coverage for all-day banner collapse` + - `refactor: extract day-event layout hook` + - `chore: bump storybook to v10` + + A Husky + lint-staged pre-commit hook auto-formats and lints staged files. -4. **Verify changes**: - Make sure everything builds correctly before pushing. +5. **Verify everything passes locally** before pushing. These are the same checks CI runs: ```bash - npm run build + npm run format:check # Prettier formatting + npm run lint # tsc --noEmit + ESLint + npm test # Vitest test suite + npm run build # Verify the bundle builds (CJS, ESM, IIFE) ``` -5. **Push and create a Pull Request**: - Push your branch and open a PR against the `main` branch. +6. **Push and open a Pull Request against `dev`.** Fill out the PR template, link the issue it resolves, and describe how you tested the change. + +## Testing + +Tests run with [Vitest](https://vitest.dev/) in a `jsdom` environment. + +```bash +npm test # Run the full suite once +npm run test:watch # Watch mode while developing +npm test -- MonthView # Run a single file by pattern +npm test -- useEvents # Run tests matching a pattern +``` + +Guidelines: + +- **Co-locate tests** next to the code they cover (`Component.test.tsx`, `useHook.test.ts`). +- **Use realistic event fixtures** rather than generic mock factories. +- **Render with ``** and React Testing Library queries; we don't use external mocking libraries for context. +- **Add a Storybook story** demonstrating any new feature or edge case — stories double as integration tests and QA scenarios. ## Coding Guidelines -- **TypeScript**: This project uses TypeScript. Ensure all new features are strictly typed. -- **CSS**: Use vanilla CSS (or CSS Modules if configured) and follow the snake_case naming convention for folders (e.g., `src/components/schedule_view/`). -- **Documentation**: If you are adding a new prop or feature, please update the `README.md` and `DOCUMENTATION.md` files accordingly. +- **TypeScript**: Strictly typed throughout. No implicit `any`; export new public types from `src/index.ts`. +- **Dates**: Use Luxon `DateTime` for all internal date logic. Only convert to/from a JS `Date` at API boundaries. +- **CSS**: Vanilla CSS Modules co-located with components (`Component.module.css`). No Tailwind or SCSS. +- **Folder naming**: Component folders use `snake_case` (e.g. `src/components/views/schedule_view/`, `src/components/core/day_event_item/`); component and hook files keep their PascalCase / `use*` names. +- **Accessibility**: Preserve semantic roles, ARIA attributes, keyboard navigation, and color-contrast utilities. +- **Documentation**: When you add or change a prop or feature, update the relevant docs — [`README.md`](./README.md) and [`FEATURES.md`](./FEATURES.md). -Thank you for contributing! +Thank you for contributing! 🎉 diff --git a/FEATURES.md b/FEATURES.md index 7aedd44..534d4cf 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -123,19 +123,21 @@ The calendar uses Luxon internally for all date formatting. - **`colorScheme="light"`** — Forces the light palette. - **`colorScheme="dark"`** — Forces the dark palette. -Palettes are implemented as CSS custom properties scoped to `[data-color-scheme="light"]` and `[data-color-scheme="dark"]` on the calendar root. Override individual variables for custom theming: +Palettes are implemented as CSS custom properties. The light palette is the `:root` default; the dark palette re-assigns those variables under `[data-color-scheme="dark"]` (the attribute the library sets on the calendar root). Override individual variables for custom theming: ```css +/* Customize the dark palette */ [data-color-scheme="dark"] { - --primary-bg: #1a1a1a; - --primary-text: #ffffff; - --accent-color: #818cf8; + --bg-color: #1a1a1a; + --text-primary: #ffffff; + --primary-color: #818cf8; } -[data-color-scheme="light"] { - --primary-bg: #ffffff; - --primary-text: #000000; - --accent-color: #2563eb; +/* Customize the light palette (the :root default) */ +:root { + --bg-color: #ffffff; + --text-primary: #000000; + --primary-color: #2563eb; } ``` diff --git a/README.md b/README.md index 69293d6..88b8d72 100644 --- a/README.md +++ b/README.md @@ -365,13 +365,13 @@ interface CalendarClassNames { ``` -Override individual CSS custom properties for fine-grained control: +Override individual CSS custom properties for fine-grained control. Light is the `:root` default; dark values live under `[data-color-scheme="dark"]`: ```css [data-color-scheme="dark"] { - --primary-bg: #1a1a1a; - --primary-text: #ffffff; - --accent-color: #818cf8; + --bg-color: #1a1a1a; + --text-primary: #ffffff; + --primary-color: #818cf8; } ``` diff --git a/SECURITY.md b/SECURITY.md index b655574..425f15a 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -15,7 +15,7 @@ Currently, only the latest major version of the library receives security update If you discover a security vulnerability within `calendar-simple`, please **DO NOT** open a public issue on GitHub. -Instead, please send an email privately to [Insert Email Here] or use GitHub's private vulnerability reporting feature if enabled on the repository. +Instead, please report it privately through GitHub's [private vulnerability reporting](https://github.com/Jaganath-MSJ/CalendarSimple/security/advisories/new). If you are unable to use that channel, reach out to the maintainer [@Jaganath-MSJ](https://github.com/Jaganath-MSJ) directly. Please include as much information as possible: @@ -24,6 +24,6 @@ Please include as much information as possible: - Step-by-step instructions on how to reproduce the issue. - The potential impact of the vulnerability. -We will review reports and typically respond within [Insert Target Response Time, e.g., 48 hours] with our initial assessment and next steps. +We aim to acknowledge reports within 5 business days with an initial assessment and next steps. Once a vulnerability is confirmed and patched, we will publish a security advisory and notify users of the update.