# Persian DatePicker Component (Svelte 5)

**🌟 [Live Demo](https://hamedf62.github.io/svelte-persian-datepicker/) 🌟**

A highly customizable and feature-rich date picker component built with Svelte 5, supporting Persian (Jalali), Gregorian, and Arabic calendars. This component is inspired by and converted from [Alireza's Vue3 Persian DatePicker](https://github.com/alireza-ab/vue3-persian-datepicker).

## ✨ Features

### 📅 Selection Modes

- **Single Date**: Select one date
- **Date Range**: Select from one date to another
- **Multiple Dates**: Select multiple individual dates (click to toggle)
- **Time Only**: Select time without date
- **DateTime**: Select both date and time
- **DateTime Range**: Select from one datetime to another datetime

### 🌍 Localization & Calendar Support

- **Persian (Jalali)**: Full support for Persian calendar
- **Gregorian**: Standard international calendar
- **Arabic**: Arabic calendar support
- **RTL/LTR**: Automatic direction support based on locale

### 🎨 Customization

- **Colors**: Multiple color themes (blue, red, pink, orange, green, purple, gray)
- **Formats**: Customizable display formats, input formats
- **Styles**: Full CSS customization support
- **Icons**: Custom icon support
- **Shortcuts**: Predefined shortcuts for quick selections

### 💡 User Experience

- **Clearable Input**: Option to clear selected dates
- **Auto Submit**: Automatic submission on selection
- **Keyboard Navigation**: Full keyboard support
- **Modal Mode**: Can be displayed as modal
- **Dual Input**: Separate inputs for range selection
- **Validation**: Built-in date validation and disable rules
- **Smart Range Selection**:
  - **Cross-Month Preview**: See your selected range highlight even when navigating between months.
  - **Dynamic Disabling**: Automatically disables dates before the start date during range selection.
  - **Easy Reset**: Clicking a new date when a range is already selected resets and starts a new selection.
- **Reactive Model**: Seamlessly syncs with parent state changes, supporting asynchronous data loading.

## 🚀 Installation

```bash
npm install @hamedf/svelte-persian-datepicker
# or
pnpm install @hamedf/svelte-persian-datepicker
# or
yarn add @hamedf/svelte-persian-datepicker
```

## 📖 Basic Usage

```svelte
<script>
	import DatePicker from '@hamedf/svelte-persian-datepicker';

	let selectedDate = $state(''); // Svelte 5 rune

	function handleSubmit(date) {
		console.log('Selected date:', date);
	}
</script>

<DatePicker
	bind:model={selectedDate}
	mode="single"
	type="date"
	submit={handleSubmit}
	color="blue"
	clearable={true}
/>
```

> **Note**: For more advanced examples including range selection, async loading, and disabling dates, check out the [demo route](src/routes/default-value/+page.svelte) in the repository.

## 🎯 Usage Examples

### Single Date Selection

```svelte
<DatePicker
	bind:model={singleDate}
	mode="single"
	type="date"
	submit={handleSingleDate}
	color="blue"
/>
```

### Date Range Selection

```svelte
<DatePicker
	bind:model={dateRange}
	mode="range"
	type="date"
	submit={handleDateRange}
	color="green"
/>
```

### Disable Previous Dates (Select from Today)

```svelte
<DatePicker bind:model={selectedDate} from={new Date()} color="orange" label="Select future date" />
```

## 🤖 GitHub Copilot Integration

This package includes a specialized instruction file for GitHub Copilot. When you use this package in your project, Copilot will automatically understand the Svelte 5 runes, the Gregorian model requirement, and the various selection modes.

You can find the detailed instructions in [.github/copilot-instructions.md](.github/copilot-instructions.md).

### Multiple Date Selection

```svelte
<DatePicker
	bind:model={multipleDates}
	mode="multiple"
	type="date"
	submit={handleMultipleDates}
	color="purple"
	auto_submit={false}
/>
```

### Time Selection

```svelte
<DatePicker
	bind:model={selectedTime}
	mode="single"
	type="time"
	input_format="HH:mm"
	submit={handleTime}
	color="orange"
/>
```

### DateTime Selection

```svelte
<DatePicker
	bind:model={selectedDateTime}
	mode="single"
	type="datetime"
	input_format="YYYY-MM-DD HH:mm"
	submit={handleDateTime}
	color="red"
/>
```

### DateTime Range Selection

```svelte
<DatePicker
	bind:model={dateTimeRange}
	mode="range"
	type="datetime"
	input_format="YYYY-MM-DD HH:mm"
	submit={handleDateTimeRange}
	color="pink"
/>
```

## ⚙️ Props

| Prop             | Type                                                                     | Default      | Description                      |
| ---------------- | ------------------------------------------------------------------------ | ------------ | -------------------------------- |
| `model`          | `string \| string[] \| PersianDate \| PersianDate[]`                     | `undefined`  | The selected value(s) (Bindable) |
| `mode`           | `'single' \| 'range' \| 'multiple'`                                      | `'single'`   | Selection mode                   |
| `type`           | `'date' \| 'time' \| 'datetime'`                                         | `'date'`     | Type of picker                   |
| `format`         | `string`                                                                 | `undefined`  | Output format (Gregorian)        |
| `input_format`   | `string`                                                                 | `undefined`  | Input parsing format             |
| `display_format` | `string`                                                                 | `undefined`  | UI display format                |
| `color`          | `'blue' \| 'red' \| 'pink' \| 'orange' \| 'green' \| 'purple' \| 'gray'` | `undefined`  | Color theme                      |
| `locale`         | `string`                                                                 | `'fa'`       | Locale (fa, en, ar)              |
| `clearable`      | `boolean`                                                                | `true`       | Show clear button                |
| `auto_submit`    | `boolean`                                                                | `true`       | Auto submit on selection         |
| `modal`          | `boolean`                                                                | `false`      | Display as modal                 |
| `dual_input`     | `boolean`                                                                | `false`      | Separate inputs for range        |
| `shortcut`       | `boolean \| object`                                                      | `false`      | Enable shortcuts                 |
| `column`         | `number \| object`                                                       | `1`          | Number of calendar columns       |
| `from`           | `Date \| string`                                                         | `1921-03-22` | Minimum selectable date          |
| `to`             | `Date \| string`                                                         | `2051-03-21` | Maximum selectable date          |
| `disable`        | `string[] \| function \| RegExp`                                         | `undefined`  | Custom disable rules             |

## 🎨 Events

| Event    | Parameters                           | Description                  |
| -------- | ------------------------------------ | ---------------------------- |
| `submit` | `date: PersianDate \| PersianDate[]` | Fired when date is submitted |
| `select` | `date: PersianDate`                  | Fired when date is selected  |
| `clear`  | `none`                               | Fired when picker is cleared |
| `open`   | `none`                               | Fired when picker opens      |
| `close`  | `none`                               | Fired when picker closes     |

## 🎨 Styling

The component supports full CSS customization. You can override the default styles by targeting the component classes:

```css
/* Custom styling for multiple selection */
:global(.pdp-multiple .pdp-day.selected) {
	background-color: #8b5cf6 !important;
	color: white !important;
	border-radius: 4px;
	font-weight: 600;
}

/* Custom range styling */
:global(.pdp-range .pdp-day.start-range) {
	background-color: your-color;
}
```

## 🔧 Development

### Prerequisites

- Node.js 18+
- pnpm

### Setup

```bash
# Clone the repository
git clone https://github.com/hamedf62/svelte-persian-datepicker

# Install dependencies
pnpm install

# Start development server
pnpm dev

# Run tests
pnpm test

# Build for production
pnpm build
```

## 📂 Project Structure

```
src/
├── lib/
│   ├── DatePicker.svelte          # Main component
│   ├── components/                # Sub-components
│   │   ├── PDPArrow.svelte
│   │   ├── PDPIcon.svelte
│   │   └── PDPAlt.svelte
│   ├── modules/
│   │   ├── core.ts               # Core logic
│   │   └── types.ts              # TypeScript types
│   └── assets/sass/              # Styles
└── routes/
    └── +page.svelte              # Demo page
```

## 🧪 Testing

The component includes comprehensive tests using Cypress:

```bash
# Run component tests
pnpm test:component

# Run e2e tests
pnpm test:e2e

# Open Cypress UI
pnpm cypress:open
```

## 📄 Documentation

For detailed documentation and API reference, visit [Alireza's Documentation](https://alireza-ab.ir/datepicker) as this component maintains compatibility with the original Vue3 version.

## 🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## 📝 License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## 🙏 Acknowledgments

- [Alireza-ab](https://github.com/alireza-ab) for the original Vue3 Persian DatePicker
- Persian calendar calculations and localization support
- Svelte community for the amazing framework

## 📊 Features Comparison

| Feature               | Single | Range | Multiple | Time | DateTime | DateTime Range |
| --------------------- | ------ | ----- | -------- | ---- | -------- | -------------- |
| Select one date       | ✅     | ❌    | ❌       | ❌   | ✅       | ❌             |
| Select date range     | ❌     | ✅    | ❌       | ❌   | ❌       | ✅             |
| Select multiple dates | ❌     | ❌    | ✅       | ❌   | ❌       | ❌             |
| Time selection        | ❌     | ❌    | ❌       | ✅   | ✅       | ✅             |
| Persian calendar      | ✅     | ✅    | ✅       | ✅   | ✅       | ✅             |
| Keyboard navigation   | ✅     | ✅    | ✅       | ✅   | ✅       | ✅             |
| Custom validation     | ✅     | ✅    | ✅       | ✅   | ✅       | ✅             |

## 🤖 AI/LLM Integration Guide

This component has been optimized for AI coding assistants and LLMs. Here's how to work with it effectively:

### 📋 Quick Reference for AI Agents

```javascript
// COMPONENT SIGNATURE FOR AI REFERENCE
/**
 * @component PersianDatePicker
 * @description A comprehensive Svelte 5 Persian/Jalali DateTime picker
 * @props {Object} Props - See interface below for all available props
 * @bindable model - The selected date(s) value
 * @example
 * // Single date selection
 * <DatePicker bind:model={selectedDate} />
 *
 * // Range selection
 * <DatePicker mode="range" bind:model={dateRange} />
 *
 * // Multiple dates
 * <DatePicker mode="multiple" bind:model={multipleDates} />
 *
 * // With custom validation
 * <DatePicker
 *   bind:model={date}
 *   from="1400/01/01"
 *   to="1405/12/29"
 *   disable={['1403/01/01', '1403/05/15']}
 * />
 */
```

### 🎯 Common AI Prompts & Solutions

#### For Setting Up Basic Date Selection:

```typescript
// AI: "Create a basic Persian date picker"
let selectedDate: string;

<DatePicker
  bind:model={selectedDate}
  locale="fa"
  type="date"
  mode="single"
/>
```

#### For Range Selection:

```typescript
// AI: "Create a date range picker for Persian calendar"
let dateRange: string[];

<DatePicker
  bind:model={dateRange}
  mode="range"
  locale="fa"
  dual_input={true}
/>
```

#### For Time Selection:

```typescript
// AI: "Add time picker functionality"
let selectedTime: string;

<DatePicker
  bind:model={selectedTime}
  type="time"
  from="08:00"
  to="20:00"
/>
```

#### For Multi-Calendar Support:

```typescript
// AI: "Support both Persian and Gregorian calendars"
let date: string;

<DatePicker
  bind:model={date}
  locale="fa,en"
  input_calendar="auto"
/>
```

### 🔧 Props Reference for AI

**Essential Props for Common Use Cases:**

- `bind:model` - The selected date value(s) - **ALWAYS BINDABLE & REACTIVE**
- `mode` - Selection type: "single" | "range" | "multiple"
- `type` - Picker type: "date" | "time" | "datetime"
- `locale` - Language/calendar: "fa" | "en" | "ar" | "fa,en"
- `from`/`to` - Date boundaries (supports `Date` objects or strings)
- `disable` - Disabled dates/times (array, function, or regex)

**Styling & UI Props:**

- `color` - Theme: "blue" | "red" | "pink" | "orange" | "green" | "purple" | "gray"
- `dual_input` - Separate inputs for range mode
- `modal` - Show as modal overlay
- `clearable` - Show clear button

**Advanced Props:**

- `format` - Model data format (always Gregorian)
- `input_format` - Input parsing format
- `display_format` - UI display format
- `input_calendar` - Calendar for input: "auto" | "jalali" | "gregorian"

### 💡 AI Best Practices

1. **Always use `bind:model`** for data binding. The component will automatically sync if the parent updates the value.
2. **Range Selection**: The component handles the flow (Start -> End). If a range is already selected, the next click resets it.
3. **Date Boundaries**: Use `from={new Date()}` to disable all previous dates easily.
4. **Model Format**: Remember that the `model` always uses Gregorian format (`YYYY-MM-DD`) for consistency, regardless of the displayed calendar.
5. **Async Data**: You can initialize the `model` with an empty string and update it later (e.g., after a fetch); the component will react accordingly.
6. **Use `from`/`to` props** for date boundaries
7. **Use `disable` prop** for validation rules
8. **Set `locale` appropriately** for language/calendar
9. **Consider `dual_input`** for better range UX
