feat: ready to publish
parent
22a02950c3
commit
272678529f
@ -1,217 +1,241 @@
|
|||||||
# React Calendar Component
|
# react-calendario
|
||||||
|
|
||||||
A modern, flexible calendar component built with React, TypeScript, and SCSS modules.
|
A modern, flexible, and highly customizable calendar component library for React with TypeScript support.
|
||||||
|
|
||||||
## Demo
|
|
||||||
|
|
||||||
Check out the live demo at [calendar.code.meow.ch](https://calendar.code.meow.ch)
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- 📅 Multiple calendar views:
|
- 📅 **Multiple Views**: Year, Month, Week, and custom date ranges
|
||||||
- Full year view with configurable month grid
|
- 🎨 **Highly Customizable**: Multiple header styles, sizes, and visual options
|
||||||
- Single month view with customizable layout
|
- 🔍 **Interactive**: Date selection, range picking, and click handlers
|
||||||
- Week view with interactive options
|
- 📱 **Responsive**: Works on all screen sizes
|
||||||
- Date range picker with hover preview
|
- 🎯 **TypeScript**: Full type safety and IntelliSense support
|
||||||
- 🎨 Visual customization:
|
- 🎨 **Themeable**: Customizable colors and styles
|
||||||
- Four header styles: expanded, compacted, tiny, and numeric
|
- 📦 **Lightweight**: Minimal dependencies
|
||||||
- Configurable day sizes (XS to XL)
|
|
||||||
- Adjustable font proportions
|
|
||||||
- Optional magnify effect for selected dates
|
|
||||||
- Weekend highlighting
|
|
||||||
- 🔧 Functional options:
|
|
||||||
- Month cutoff handling (dimmed, truncated, or show all)
|
|
||||||
- Interactive date range selection
|
|
||||||
- Hover states and preview
|
|
||||||
- Responsive design for all screen sizes
|
|
||||||
- 🛠 Technical features:
|
|
||||||
- Built with React + TypeScript
|
|
||||||
- SCSS modules for styling
|
|
||||||
- date-fns for date manipulation
|
|
||||||
- Zero external dependencies beyond core requirements
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install
|
npm install react-calendario date-fns classnames
|
||||||
```
|
```
|
||||||
|
|
||||||
## Development
|
or
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run dev
|
yarn add react-calendario date-fns classnames
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage Examples
|
## Quick Start
|
||||||
|
|
||||||
### Date Range Picker
|
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import React, { useState } from 'react';
|
import { Month } from 'react-calendario';
|
||||||
import { Year } from './components/calendar/Year';
|
|
||||||
import { DateRange } from './types/calendar';
|
|
||||||
|
|
||||||
function DateRangePicker() {
|
function App() {
|
||||||
const [dateRange, setDateRange] = useState<DateRange>({
|
return (
|
||||||
startDate: null,
|
<Month
|
||||||
endDate: null,
|
date={new Date()}
|
||||||
selecting: false,
|
dayHeaderStyle="expanded"
|
||||||
hoverDate: null,
|
size="l"
|
||||||
anchorDate: null
|
/>
|
||||||
});
|
);
|
||||||
|
|
||||||
const handleDateSelect = (date: Date) => {
|
|
||||||
setDateRange(prev => {
|
|
||||||
if (!prev.selecting) {
|
|
||||||
return {
|
|
||||||
startDate: date,
|
|
||||||
endDate: date,
|
|
||||||
selecting: true,
|
|
||||||
hoverDate: date,
|
|
||||||
anchorDate: date
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
// Complete the selection
|
```
|
||||||
return {
|
|
||||||
startDate: prev.anchorDate,
|
## Components
|
||||||
endDate: date,
|
|
||||||
selecting: false,
|
### Year
|
||||||
hoverDate: null,
|
|
||||||
anchorDate: null
|
Display a full year calendar with customizable month grid.
|
||||||
};
|
|
||||||
});
|
```tsx
|
||||||
};
|
import { Year } from 'react-calendario';
|
||||||
|
|
||||||
return (
|
|
||||||
<Year
|
<Year
|
||||||
year={2024}
|
year={2024}
|
||||||
dayHeaderStyle="tiny"
|
dayHeaderStyle="tiny"
|
||||||
monthCutoff="truncate"
|
monthCutoff="truncate"
|
||||||
weekendDays={[6, 0]}
|
size="m"
|
||||||
dateRange={dateRange}
|
|
||||||
onDateSelect={handleDateSelect}
|
|
||||||
onDateHover={(date) => setDateRange(prev => ({ ...prev, hoverDate: date }))}
|
|
||||||
size="l"
|
|
||||||
fontProportion={100}
|
fontProportion={100}
|
||||||
magnify={true}
|
magnify={true}
|
||||||
/>
|
/>
|
||||||
);
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Single Month View
|
### Month
|
||||||
|
|
||||||
|
Display a single month with various layout options.
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import React from 'react';
|
import { Month } from 'react-calendario';
|
||||||
import { Month } from './components/calendar/Month';
|
|
||||||
|
|
||||||
function SingleMonth() {
|
|
||||||
return (
|
|
||||||
<Month
|
<Month
|
||||||
date={new Date()}
|
date={new Date()}
|
||||||
dayHeaderStyle="expanded"
|
dayHeaderStyle="expanded"
|
||||||
direction="column"
|
direction="column"
|
||||||
monthCutoff="dimmed"
|
monthCutoff="dimmed"
|
||||||
weekendDays={[6, 0]}
|
|
||||||
size="xl"
|
size="xl"
|
||||||
fontProportion={100}
|
|
||||||
/>
|
/>
|
||||||
);
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Week View
|
### Week
|
||||||
|
|
||||||
|
Display a single week view.
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import React from 'react';
|
import { Week } from 'react-calendario';
|
||||||
import { Week } from './components/calendar/Week';
|
|
||||||
|
|
||||||
function WeekView() {
|
|
||||||
return (
|
|
||||||
<Week
|
<Week
|
||||||
startDate={new Date()}
|
startDate={new Date()}
|
||||||
headerStyle="compacted"
|
headerStyle="compacted"
|
||||||
referenceMonth={new Date().getMonth()}
|
referenceMonth={0}
|
||||||
weekendDays={[6, 0]}
|
|
||||||
size="l"
|
size="l"
|
||||||
fontProportion={100}
|
|
||||||
/>
|
/>
|
||||||
);
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Compact Year View
|
### DateRange
|
||||||
|
|
||||||
|
Display a custom date range with optional selection and interactivity.
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { DateRange } from 'react-calendario';
|
||||||
|
|
||||||
|
<DateRange
|
||||||
|
from={new Date(2024, 0, 15)}
|
||||||
|
to={new Date(2024, 0, 22)}
|
||||||
|
included={true}
|
||||||
|
selected={true}
|
||||||
|
headerStyle="tiny"
|
||||||
|
size="l"
|
||||||
|
onDateClick={(date) => console.log('Clicked:', date)}
|
||||||
|
activeDates={[new Date(2024, 0, 17)]}
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Props
|
||||||
|
|
||||||
|
### Common Props
|
||||||
|
|
||||||
|
All components share these common props:
|
||||||
|
|
||||||
|
| Prop | Type | Default | Description |
|
||||||
|
|------|------|---------|-------------|
|
||||||
|
| `size` | `'xl' \| 'l' \| 'm' \| 's' \| 'xs' \| 'xxs'` | `'l'` | Day cell size |
|
||||||
|
| `fontProportion` | `number` | `100` | Font size percentage (10-100) |
|
||||||
|
| `magnify` | `boolean` | `false` | Enable magnify effect on selection |
|
||||||
|
| `weekendDays` | `number[]` | `[6, 0]` | Weekend day indices (0=Sunday) |
|
||||||
|
|
||||||
|
### Header Styles
|
||||||
|
|
||||||
|
| Style | Description |
|
||||||
|
|-------|-------------|
|
||||||
|
| `'expanded'` | Full day names (e.g., "Monday") |
|
||||||
|
| `'compacted'` | Three-letter abbreviations (e.g., "Mon") |
|
||||||
|
| `'tiny'` | Two-letter abbreviations (e.g., "Mo") |
|
||||||
|
| `'none'` | Numbers only |
|
||||||
|
|
||||||
|
### Size Options
|
||||||
|
|
||||||
|
- `'xxs'`: Extra extra small (20px height, 1:1.5 header:content ratio)
|
||||||
|
- `'xs'`: Extra small (24px height)
|
||||||
|
- `'s'`: Small (28px height)
|
||||||
|
- `'m'`: Medium (32px height)
|
||||||
|
- `'l'`: Large (36px height)
|
||||||
|
- `'xl'`: Extra large (48px height)
|
||||||
|
|
||||||
|
## Advanced Usage
|
||||||
|
|
||||||
|
### Date Range Selection
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import React from 'react';
|
import { useState } from 'react';
|
||||||
import { Year } from './components/calendar/Year';
|
import { Year } from 'react-calendario';
|
||||||
|
|
||||||
|
function DateRangePicker() {
|
||||||
|
const [dateRange, setDateRange] = useState({
|
||||||
|
startDate: null,
|
||||||
|
endDate: null,
|
||||||
|
selecting: false,
|
||||||
|
hoverDate: null,
|
||||||
|
anchorDate: null
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleDateSelect = (date) => {
|
||||||
|
// Your range selection logic
|
||||||
|
};
|
||||||
|
|
||||||
function CompactYear() {
|
|
||||||
return (
|
return (
|
||||||
<Year
|
<Year
|
||||||
year={2024}
|
year={2024}
|
||||||
dayHeaderStyle="tiny"
|
dateRange={dateRange}
|
||||||
monthCutoff="truncate"
|
onDateSelect={handleDateSelect}
|
||||||
weekendDays={[6, 0]}
|
onDateHover={(date) => setDateRange(prev => ({ ...prev, hoverDate: date }))}
|
||||||
size="xs"
|
|
||||||
fontProportion={80}
|
|
||||||
magnify={true}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Component Props
|
### Interactive Date Range with Active States
|
||||||
|
|
||||||
### Year Component
|
```tsx
|
||||||
```typescript
|
import { DateRange } from 'react-calendario';
|
||||||
interface YearProps {
|
|
||||||
year: number;
|
function InteractiveCalendar() {
|
||||||
dayHeaderStyle: 'expanded' | 'compacted' | 'tiny' | 'none';
|
const [activeDates, setActiveDates] = useState([]);
|
||||||
monthDayOfWeekHeaderStyle?: HeaderStyle;
|
|
||||||
monthCutoff?: 'dimmed' | 'truncate' | undefined;
|
const handleDateClick = (date) => {
|
||||||
weekendDays?: number[];
|
setActiveDates(prev => {
|
||||||
dateRange?: DateRange;
|
const exists = prev.some(d => d.getTime() === date.getTime());
|
||||||
onDateSelect?: (date: Date) => void;
|
return exists
|
||||||
onDateHover?: (date: Date) => void;
|
? prev.filter(d => d.getTime() !== date.getTime())
|
||||||
size?: 'xl' | 'l' | 'm' | 's' | 'xs';
|
: [...prev, date];
|
||||||
fontProportion?: number;
|
});
|
||||||
magnify?: boolean;
|
};
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Month Component
|
return (
|
||||||
```typescript
|
<DateRange
|
||||||
interface MonthProps {
|
from={new Date(2024, 0, 1)}
|
||||||
date: Date;
|
to={new Date(2024, 0, 31)}
|
||||||
dayHeaderStyle: HeaderStyle;
|
onDateClick={handleDateClick}
|
||||||
direction: 'row' | 'column';
|
activeDates={activeDates}
|
||||||
monthCutoff?: MonthCutoffType;
|
/>
|
||||||
weekendDays?: number[];
|
);
|
||||||
dateRange?: DateRange;
|
|
||||||
onDateSelect?: (date: Date) => void;
|
|
||||||
onDateHover?: (date: Date) => void;
|
|
||||||
size?: DaySize;
|
|
||||||
fontProportion?: number;
|
|
||||||
magnify?: boolean;
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Styling
|
## Styling
|
||||||
|
|
||||||
The component uses SCSS modules for styling. Key style files:
|
The components use CSS modules and CSS variables for theming. You can override the default styles by:
|
||||||
|
|
||||||
|
1. Using the built-in props for common customizations
|
||||||
|
2. Overriding CSS variables in your global styles
|
||||||
|
3. Applying custom CSS classes
|
||||||
|
|
||||||
|
### CSS Variables
|
||||||
|
|
||||||
|
```css
|
||||||
|
:root {
|
||||||
|
--color-primary: #2196f3;
|
||||||
|
--color-primary-dark: #1976d2;
|
||||||
|
--color-selected: #e3f2fd;
|
||||||
|
/* ... and more */
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
- `src/components/calendar/shared/_colors.scss`: Color variables
|
## TypeScript
|
||||||
- `src/components/calendar/shared/_variables.scss`: Layout variables
|
|
||||||
- Individual component SCSS modules for specific styling
|
|
||||||
|
|
||||||
## Browser Support
|
Full TypeScript support with exported types:
|
||||||
|
|
||||||
- Chrome (latest)
|
```tsx
|
||||||
- Firefox (latest)
|
import type {
|
||||||
- Safari (latest)
|
DateRange,
|
||||||
- Edge (latest)
|
HeaderStyle,
|
||||||
|
DaySize,
|
||||||
|
MonthCutoffType
|
||||||
|
} from 'react-calendario';
|
||||||
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT
|
MIT
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
||||||
@ -1,25 +1,53 @@
|
|||||||
{
|
{
|
||||||
"name": "react-calendar",
|
"name": "react-calendario",
|
||||||
"private": true,
|
"version": "1.0.0",
|
||||||
"version": "0.0.0",
|
"description": "A modern, flexible calendar component for React with TypeScript support",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"module": "dist/index.es.js",
|
||||||
|
"types": "dist/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"preview": "vite preview"
|
"build:lib": "tsc --declaration --emitDeclarationOnly --outDir dist && vite build --config vite.config.lib.ts",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"prepublishOnly": "npm run build:lib"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"react",
|
||||||
|
"calendar",
|
||||||
|
"date",
|
||||||
|
"datepicker",
|
||||||
|
"date-range",
|
||||||
|
"typescript",
|
||||||
|
"component"
|
||||||
|
],
|
||||||
|
"author": "",
|
||||||
|
"license": "MIT",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/yourusername/react-calendario"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8.0",
|
||||||
|
"react-dom": ">=16.8.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react": "^19.1.0",
|
"classnames": "^2.5.1",
|
||||||
"react-dom": "^19.1.0",
|
"date-fns": "^4.1.0"
|
||||||
"date-fns": "^4.1.0",
|
|
||||||
"classnames": "^2.5.1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/node": "^24.0.14",
|
||||||
"@types/react": "^19.1.8",
|
"@types/react": "^19.1.8",
|
||||||
"@types/react-dom": "^19.1.6",
|
"@types/react-dom": "^19.1.6",
|
||||||
"@vitejs/plugin-react": "^4.6.0",
|
"@vitejs/plugin-react": "^4.6.0",
|
||||||
|
"react": "^19.1.0",
|
||||||
|
"react-dom": "^19.1.0",
|
||||||
|
"sass": "^1.89.2",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"vite": "^7.0.4",
|
"vite": "^7.0.4"
|
||||||
"sass": "^1.89.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue