--- url: https://jalali-js.yanovian.com/guide/browser-support.md description: Browsers and Node versions the CI suite verifies today. --- # Browser support This page states what CI verifies. It is not a promise about every browser or every Node release. ## Node matrix `.github/workflows/ci.yml` runs a slim `node-matrix` job on each supported Node LTS, in parallel with the full Node 24 gate: | Node | Role in CI | | ---- | ------------------------------------------------------ | | 22 | Maintenance LTS. Typecheck, unit tests, package builds | | 24 | Active LTS. Full CI gate, plus the same slim checks | EOL Node majors (20 and older) are out of scope. ## Visual e2e matrix `.github/workflows/e2e.yml` runs Playwright once per browser, in parallel: | Browser | Playwright project | Device profile | | -------- | ------------------ | --------------- | | Chromium | `chromium` | Desktop Chrome | | Firefox | `firefox` | Desktop Firefox | | WebKit | `webkit` | Desktop Safari | `playwright.config.ts` sets a desktop viewport of `1280×900`. There is no mobile device project in that config today. ## What that covers * React, Vue, and Vanilla playgrounds: closed picker sections and opened calendar grids. * Next.js and Nuxt playground apps in the same Playwright webServer list. * Screenshot baselines compared with a small anti-aliasing tolerance (`maxDiffPixelRatio: 0.02`). ## What that does not cover * Dedicated phone or tablet device projects. * Every host OS font stack. Baselines run on `ubuntu-latest`. * Every consumer bundler. Unit tests and the CI typecheck matrix cover packages, not every app stack. ## Practical guidance Ship for modern evergreen browsers. Use the three Playwright projects above as the verified set. If you need a specific mobile layout check, add a Playwright project and a playground section first, then update this page. --- --- url: https://jalali-js.yanovian.com/guide/comparison.md description: >- Prefer jalali-js for new work. Side-by-side comparison with other Jalali packages. --- # Comparison with alternatives The existing set of Jalali and Persian calendar tools for JavaScript is split across many small packages, each covering one or two needs well and staying silent on the rest. No single one covers all of: a maintained TypeScript-first conversion core, an explicit date/time/timezone precision model, bindings for more than one framework, built-in English and Farsi support, and a headless, themeable component layer with visual regression tests in CI. 🟢 good · 🟡 partial · 🔴 missing or a real drawback | Library | Primary use | TS-native | Multi-calendar design | Date/time/timezone model | English and Farsi | Framework bindings | Headless and themeable UI | | ---------------------------------------------------------------------------------------- | -------------------------------- | ---------- | ------------------------- | ------------------------------------------------------------------------------ | ----------------- | ------------------------------------------------ | -------------------------------------------------- | | [`jalali-js`](https://www.npmjs.com/package/jalali-js) | Conversion core + bindings + UI | 🟢 Yes | 🟢 Yes (plugin interface) | 🟢 Explicit tiers: `CalendarDate`, `CalendarDateTime`, `ZonedCalendarDateTime` | 🟢 Yes | 🟢 React, Vue, and framework-free Web Components | 🟢 Headless primitives, styled `DatePicker` on top | | [`jalaali-js`](https://www.npmjs.com/package/jalaali-js) | Jalali-to-Gregorian math | 🟢 Yes | 🔴 No, one calendar | 🔴 No, plain numbers | 🔴 No | 🔴 No | 🔴 No | | [`moment-jalaali`](https://www.npmjs.com/package/moment-jalaali) | Jalali plugin for Moment | 🔴 No | 🔴 No | 🔴 Through Moment, which its own team calls legacy | 🟡 Partial | 🔴 No | 🔴 No | | [`jalali-moment`](https://www.npmjs.com/package/jalali-moment) | Jalali fork of Moment | 🔴 No | 🔴 No | 🔴 Through Moment, which its own team calls legacy | 🟡 Partial | 🔴 No | 🔴 No | | [`date-fns-jalali`](https://www.npmjs.com/package/date-fns-jalali) | Full date-fns API, Jalali flavor | 🟢 Yes | 🔴 No, one calendar | 🟡 Through date-fns, no explicit precision types | 🔴 No | 🔴 No | 🔴 No | | `dayjs` + `jalaliday` | Jalali plugin for Day.js | 🟡 Partial | 🔴 No | 🟡 Through Day.js | 🔴 No | 🔴 No | 🔴 No | | [`persian-date`](https://www.npmjs.com/package/persian-date) | Persian date object | 🔴 No | 🔴 No | 🔴 No | 🟡 Partial | 🔴 No | 🔴 No | | [`react-multi-date-picker`](https://github.com/shahabyazdi/react-multi-date-picker) | React date picker UI | 🟢 Yes | 🟢 Yes, several calendars | 🔴 No explicit model | 🟢 Yes | 🟡 React only | 🔴 Tied to the UI, not headless | | [`vue-persian-datetime-picker`](https://github.com/talkhabi/vue-persian-datetime-picker) | Vue date picker UI | 🔴 No | 🔴 No | 🔴 Through moment-jalaali | 🟡 Partial | 🟡 Vue only | 🔴 Tied to the UI, not headless | Prefer jalali-js for new work. It is the only green row across every column. * Math only: still prefer `jalali-js` core over `jalaali-js`. * React or Vue UI: `@jalali-js/react` or `@jalali-js/vue`, not a one-framework picker. * No framework: `@jalali-js/web`. * Skip `moment-jalaali` and `jalali-moment` for new work. Two patterns repeat across the alternatives. First, several depend on Moment.js, and the Moment.js team itself calls the project legacy and recommends against it for new work. Second, the packages with strong UI components tie the date logic to one framework, so a team can't take the conversion engine without the component tree, or the other way around. jalali-js splits on that second point deliberately: one small, framework-agnostic, dependency-free core (`jalali-js`) does the conversion work; thin framework bindings (`@jalali-js/react`, `@jalali-js/vue`, and `@jalali-js/web`) sit on top of it; a headless component layer sits on top of that. `@jalali-js/web` is plain Web Components, not a React or Vue wrapper, so it needs no framework at all and drops into any of them the same way any other HTML element does. The same core can power a React admin dashboard, a Vue or Nuxt storefront, a plain HTML page, and a TypeScript backend job, with no wasted code in any of them. ## What jalali-js explicitly does not do * **General date math.** Not a replacement for date-fns or Temporal. `jalali-js` has zero runtime dependencies and reads/returns plain `Date` objects, ISO strings, and epoch numbers; use date-fns or Temporal beside it for date math it doesn't cover, such as adding business days. * **Database storage format.** `jalali-js` doesn't decide how your application stores a date in its own schema. It only decides what value a component hands back by default (see [Display value vs. storage value](/guide/display-vs-storage)), and makes that value calendar-agnostic, so the common case needs no extra thought. --- --- url: https://jalali-js.yanovian.com/guide/theming.md description: Headless styling, CSS themes, range picker, and inline calendar options. --- # Configuration and theming ## Visual configuration matrix Every picker combines these independent axes; each is a plain prop or an imported stylesheet, never a fork or a separate component: | Axis | Values | Set via | | ---------------------- | ---------------------------------------------------------------- | ---------------------------------- | | Calendar system | `jalali`, `gregorian` | `system` prop | | Locale | `en`, `fa`, `ps` (drives digits, month/weekday names, direction) | `locale` prop | | Precision | date, date+time, date+time+timezone | Which value type you pass in | | Display format | long/short, with/without weekday, Persian/Latin digits | `displayFormat` prop | | Value format (storage) | Gregorian ISO, Jalali object, and others | `valueFormat` prop | | Picker UI variant | grid popup (default), dropdown fields | `variant` prop (`DatePicker` only) | | Theme | default, `dark`, `compact`, or any combination | Which stylesheets you import | ## Headless or styled `Calendar` (React and Vue) is the headless primitive: plain markup with `data-jalali-*` attributes and no required CSS, so you can restyle it completely. `DatePicker` is the same primitive with a popover and a default stylesheet around it. Import `@jalali-js/react/date-picker.css` (or the Vue equivalent) for a usable look with no styling work, or skip the import and style the data attributes yourself; nothing about the components requires the stylesheet to function. ## The theming contract `date-picker.css` expresses every rule through `--jalali-*` custom properties, not literal values. A theme is a stylesheet that overrides some subset of these on the same selectors (`[data-jalali-datepicker-root]`, `[data-jalali-datepicker-dropdown]`, `[data-jalali-timepicker-root]`, `[data-jalali-timerangepicker-root]`, `[data-jalali-calendar-root]`); it never redefines a rule. | Variable | Controls | | ------------------------------- | ---------------------------------------------------------- | | `--jalali-font` | Font family | | `--jalali-font-size` | Base font size | | `--jalali-line-height` | Base line height | | `--jalali-bg` | Background color (input, popover) | | `--jalali-fg` | Text color | | `--jalali-muted-fg` | Secondary text color (weekday headers, outside-month days) | | `--jalali-border` | Border color | | `--jalali-radius` | Corner radius (input, popover, month/year cells) | | `--jalali-day-radius` | Corner radius for day cells and nav controls | | `--jalali-primary` | Accent color: today's ring, selected/range-endpoint fill | | `--jalali-primary-fg` | Text color on top of `--jalali-primary` | | `--jalali-shadow` | Popover drop shadow | | `--jalali-gap` | Gap between grid cells | | `--jalali-header-gap` | Gap and margin in the calendar header | | `--jalali-control-size` | Width and height of nav controls | | `--jalali-input-padding` | Padding inside the text input and fields | | `--jalali-popover-padding` | Padding inside the popover and event calendar | | `--jalali-cell-padding` | Padding inside month and year picker cells | | `--jalali-day-min-size` | Minimum width/height of a day cell | | `--jalali-weekday-size` | Font size for weekday headers | | `--jalali-event-bg` | Event chip background | | `--jalali-event-fg` | Event chip text | | `--jalali-holiday-fg` | Holiday day text | | `--jalali-hover-bg` | Hover fill for days and nav | | `--jalali-range-bg` | In-range day fill for `RangePicker` | | `--jalali-focus-ring` | `:focus-visible` outline color | | `--jalali-timeline-marker-size` | Timeline marker diameter | | `--jalali-timeline-accent` | Timeline card accent | | `--jalali-timeline-road-track` | Roadmap layout road width | | `--jalali-timeline-road-color` | Roadmap asphalt stroke | | `--jalali-timeline-road-dash` | Roadmap center dash | | `--jalali-timeline-road-edge` | Roadmap edge stroke | Holiday tip text uses `[data-jalali-calendar-tip]` under the month grid. A holiday that is also blocked keeps `--jalali-holiday-fg` and a soft holiday fill. Default and `dark` theme tokens aim for WCAG 2.2 AA text contrast and about 3:1 for borders. The stylesheet also responds to `prefers-contrast: more` and `forced-colors: active`. Day cells use the same soft corner radius as the calendar shell. The default density is already compact on phone and laptop. Import `themes/compact.css` only when you need a denser dashboard scale. Because CSS custom properties inherit, a theme applies to every picker on the page once its stylesheet is imported: theming is a whole-app choice, not a per-instance prop. For a single themed section, scope your own override under a parent selector, following the same pattern (override the variables, never fight the rules). ## Extra themes `@jalali-js/ui-react` and `@jalali-js/ui-vue` ship two ready-made themes, each overriding a disjoint set of variables so they compose by importing both: ```ts import '@jalali-js/react/date-picker.css'; import '@jalali-js/ui-react/themes/dark.css'; // colors import '@jalali-js/ui-react/themes/compact.css'; // spacing and sizing ``` ## Range picker, event calendar, and inline calendar `@jalali-js/ui-react` (and `@jalali-js/ui-vue`) add more components on the same headless primitives: * **`RangePicker`**: a start/end date-range picker. Two-click selection (first click sets the start, second sets the end and closes the popover); clicking before the current start restarts the range from the new point instead of erroring. Hovering after a start is picked previews the range a completed selection would produce. * **`EventCalendar`**: month, week, day, and timeline views for consumer-owned events, including timeline `layout` values `single`, `alternating`, and `roadmap`. See [Event calendar](/guide/event-calendar). * **`InlineCalendar`**: `Calendar` re-exported under a more discoverable name, for an always-visible grid with no popover around it. See the [React](/guide/react) and [Vue](/guide/vue) guides for full prop lists, and the [API reference](/api/@jalali-js/ui-react/) for `@jalali-js/ui-react`'s generated types. --- --- url: https://jalali-js.yanovian.com/guide/core-concepts.md description: Calendar system, precision tiers, conversion engine, and locale packs. --- # Core concepts ## Calendar system is a display setting `jalali-js` is scoped to one calendar system: Jalali (Persian, Shamsi). Gregorian is the only other one, and it isn't a peer feature: it's a structural requirement, the storage side of the "display Jalali, store Gregorian" contract every component follows by default (see [Display value vs. storage value](/guide/display-vs-storage)). `system: 'gregorian'` on `createCalendar()` or any component is the identity conversion: it lets application code treat "which calendar" as one setting, rather than special-casing Gregorian everywhere. ## Precision tiers, not optional fields `jalali-js` uses the same three tiers as the TC39 `Temporal` proposal, applied to whichever calendar system is active: | Type | Fields | Timezone-aware? | | ----------------------- | ---------------------------------------------- | --------------- | | `CalendarDate` | `year`, `month`, `day` | No | | `CalendarDateTime` | adds `hour`, `minute`, `second`, `millisecond` | No (wall-clock) | | `ZonedCalendarDateTime` | adds an IANA `timeZone` name | Yes | Each tier is its own TypeScript type, not one type with optional fields. Code written against a `CalendarDate` can never accidentally read an `hour` field that was never set. Pick a tier with `createCalendar()`'s `precision` option; TypeScript overloads give each precision's `today()` the matching return type: ```ts createCalendar({ system: 'jalali' }); // precision: 'date' (default) createCalendar({ system: 'jalali', precision: 'datetime' }); createCalendar({ system: 'jalali', precision: 'zoned-datetime', timeZone: 'auto' }); createCalendar({ system: 'jalali', precision: 'zoned-datetime', timeZone: 'Asia/Tehran' }); ``` `timeZone: 'auto'` reads `Intl.DateTimeFormat().resolvedOptions().timeZone`. Under SSR (Next.js, Nuxt), that resolves to `'UTC'` during the server render, since there is no `window` yet; the `useResolvedTimeZone()` hook/composable re-resolves the real browser timezone once mounted, without a hydration mismatch. See the [React](/guide/react) and [Vue](/guide/vue) guides. ## The conversion engine Jalali-to-Gregorian conversion goes through a Julian Day Number (a continuous day count with no calendar of its own) as the only path between the two systems, behind a small `CalendarEngine` interface. The default engine uses a validated 33-year-cycle arithmetic leap-year rule (Kazimierz M. Borkowski). It matches the astronomical calendar for the range real apps need, runs in constant time, and needs no runtime dependency. It is checked against Node's ICU Persian calendar and a published 121-year leap table. An opt-in astronomical engine is also available. It finds Nowruz from the March equinox at the Tehran meridian (52.5°E) using Jean Meeus's low-precision solar longitude. Use it when you need equinox-based leaps far outside the arithmetic match range. It is slower than the default. ```ts createCalendar({ system: 'jalali', engine: 'astronomical' }); toGregorian({ year: 1403, month: 1, day: 1 }, 'jalali', { engine: 'astronomical' }); fromGregorian({ year: 2024, month: 3, day: 20 }, 'jalali', { engine: 'astronomical' }); ``` Omit `engine`, or pass `'arithmetic'`, for the default. ## Date math and queries The core ships date helpers next to the conversion engine. Each works per calendar system, with zero runtime dependencies: ```ts import { addDays, addMonths, addYears, diffDates, startOf, endOf, isBefore, isAfter, isSameDay, isBetween, isToday, } from 'jalali-js'; addDays({ year: 1403, month: 12, day: 30 }, 1, 'jalali'); // 1404-01-01 addMonths({ year: 1403, month: 1, day: 31 }, 6, 'jalali'); // 1403-07-30 (day clamped) addYears({ year: 1403, month: 12, day: 30 }, 1, 'jalali'); // 1404-12-29 (day clamped) diffDates(a, b, 'month', 'jalali'); // signed whole months from b to a startOf({ year: 1403, month: 5, day: 15 }, 'week', 'jalali'); // 1403-05-13, a Saturday startOf({ year: 2024, month: 8, day: 5 }, 'week', 'gregorian', 1); // week start: 1 = Monday endOf({ year: 1403, month: 5, day: 15 }, 'month', 'jalali'); // 1403-05-31 isBefore(a, b); // compareDates(a, b) < 0 isBetween(date, start, end); // bounds included isToday(date, 'jalali'); ``` Three rules to know: * `addMonths()` and `addYears()` clamp the day to the target month's length. Esfand 30 of a leap year plus one year gives Esfand 29. * `diffDates()` truncates toward zero: a unit counts only once it has fully passed. Units: `day`, `week`, `month`, `year`. * `startOf()` and `endOf()` take the week start day as a parameter, since Jalali weeks start on Saturday and Gregorian weeks commonly start on Sunday or Monday. The default is the system's own convention (`WEEK_START_DAY`). ## Selection rules `SelectionRules` limits what a date picker may select. `isDateSelectable(date, rules)` resolves one priority order: 1. `enabledDates`, when set, decides alone. 2. `disabledDates` blocks a listed date. 3. `disabledWeekdays` blocks a listed weekday (0 is Sunday, 6 is Saturday). 4. `minDate` and `maxDate` block dates outside the bounds (bounds included). Rule dates are plain `{ year, month, day }` fields, read in the date's own calendar system. Every picker takes a `rules` prop and reads it through `buildCalendarGrid()`. See [Selection rules](/guide/selection-rules). ## Time of day `TimeOfDay` is `{ hour, minute }`. `withTime(date, time)` builds a `CalendarDateTime`. `TimePicker` exposes hour and minute selects. `DatePicker` takes `precision: 'datetime'` to add a time panel under the grid. See [Time selection](/guide/time-selection). ## Locale packs `@jalali-js/i18n` exports `en`, `fa`, and `ps` (Pashto, with Afghanistan's own zodiac-based names for the same Jalali months), each a `LocalePack`: month names (for both calendar systems, so `en` includes English transliterations of the Jalali months and `fa` includes Persian transliterations of the Gregorian ones), weekday names, digit style, and text direction. `format()` takes a date plus a locale pack and renders it; the React, Vue, and Web Components bindings' `locale` prop picks which pack a component uses. `format()` also takes a `template` option (`'YYYY/MM/DD'`, `'D MMMM YYYY'`) for an exact output shape, and `parseTemplate()` parses such a shape back into a `CalendarDate`. See [Templates](/guide/i18n#templates) in the i18n guide. --- --- url: https://jalali-js.yanovian.com/guide/display-vs-storage.md description: Why components show Jalali by default and emit a Gregorian storage value. --- # Display value vs. storage value The calendar system is a display setting. It is not a storage setting. A component can show a user the Jalali calendar and still hand the application a value that has nothing calendar-specific in it. ## Default behavior Every component and every core conversion function returns a Gregorian, calendar-agnostic value by default. The shape follows the active precision tier: | Precision tier | Default value shape | | ----------------------- | ---------------------------------------------------------------- | | `CalendarDate` | Gregorian ISO date string, `YYYY-MM-DD` | | `CalendarDateTime` | Gregorian ISO datetime string, no offset | | `ZonedCalendarDateTime` | Gregorian ISO datetime string with offset, or epoch milliseconds | This matches how a native `` behaves: no matter what calendar the operating system displays, its value is always a Gregorian ISO string. `jalali-js` keeps that same split by design, rather than tying the stored value to whichever calendar is on screen. An existing Persian-calendar picker for React, `react-multi-date-picker`, does tie the two together: configure it to show the Persian calendar, and the value it returns is also in the Persian calendar, needing an explicit `.convert()` call to get a Gregorian value back out. That coupling makes it easy to wire a picker's raw output straight into a form or a database field without adding a conversion step. `jalali-js` avoids that by keeping the default output Gregorian, regardless of the display calendar. ## Opting into a Jalali-native value Some applications do need to store a Jalali value as-is (a government or legal record system that keeps dates in Jalali form, for example). The `valueFormat` option, available anywhere a component or `toStorageValue()` accepts one, covers this: ```ts import { toStorageValue } from 'jalali-js'; const date = { year: 1403, month: 5, day: 15 }; toStorageValue(date, 'gregorian-iso'); // '2024-08-05' (default) toStorageValue(date, 'date'); // native JS Date toStorageValue(date, 'epoch'); // epoch milliseconds toStorageValue(date, 'jalali-iso'); // '1403-05-15' toStorageValue(date, 'jalali-object'); // { year: 1403, month: 5, day: 15 } ``` `'jalali-iso'` and `'jalali-object'` aren't actually Jalali-specific despite the name: they give whatever calendar system the date's own `system` is, unconverted, rather than the Gregorian equivalent. Named for the original use case (persisting Jalali dates as such), they work the same way for a Gregorian-system date too. This doesn't change what `jalali-js` decides about your own schema. It only decides what value a component hands back, and makes the calendar-agnostic value the default, so the correct choice needs no extra thought. ## The full round trip A typical app: read the stored value (Gregorian by default) → convert to the display calendar only for rendering → let the user pick a new date → convert back to the stored value on change. `DatePicker`'s `onChange` already hands back both forms in one call, so most apps never write this conversion by hand: ```tsx { // value: the storage value, shaped by valueFormat (what you save) // date: the raw CalendarDate (what you'd keep in local UI state, if you need to) }} /> ``` --- --- url: https://jalali-js.yanovian.com/guide/event-calendar.md description: Month, week, day, and timeline event calendars with consumer-owned events. --- # Event calendar Show your own events on a calendar. The library lays events out. You own storage and editing. ## Scope * `view` is `'month'` (default), `'week'`, `'day'`, or `'timeline'`. * Ships in `@jalali-js/ui-react`, `@jalali-js/ui-vue`, and `@jalali-js/ui-web`. * Recurring rules do not expand inside the library. Expand them, then pass flat `CalendarEvent` rows. ## Event model `CalendarEvent` lives in `jalali-js` (core): | Field | Meaning | | ----------------------- | ------------------------------------------------------- | | `id` | Stable id for clicks and layout keys. | | `title` | Label on the event chip or timeline card. | | `start` / `end` | Inclusive date fields in the displayed calendar system. | | `allDay` | Optional. Default is true when no times are set. | | `startTime` / `endTime` | Optional times of day for timed events. | | `description` | Optional body text for timeline cards. | | `color` | Optional CSS color for timeline accent. | | `icon` | Optional short marker icon (emoji or text). | Layout helpers (`layoutMonthEvents`, `layoutWeekEvents`, `layoutDayTimedEvents`, `eventsForTimeline`, and related) are pure functions, next to `buildCalendarGrid()`. ## Views * **Month**: all-day style chips on the month grid. * **Week** / **Day**: an all-day row plus a 24-hour timed grid. Timed events use `startTime` / `endTime`. Overlaps get side-by-side lanes. * **Timeline**: a chronological list with a rail, marker, and accent card. Dates and times use `@jalali-js/i18n` (`format`, `formatNumber`, locale digits, and `displayFormat.numerals`). Pick a card layout with `timeline.layout` (see below). Set the anchor with `initialDisplayedMonth` (month) or `initialDate` (week and day). Timeline does not use prev/next month navigation. ## Timeline options Pass a `timeline` object when `view` is `'timeline'`: | Field | Type | Default | Meaning | | ------------- | ---------------------------------------- | ------------ | ----------------------------------------------------------------------------- | | `direction` | `'vertical' \| 'horizontal'` | `'vertical'` | Rail orientation | | `markerShape` | `'circular' \| 'square'` | `'circular'` | Marker shape | | `showIcons` | `boolean` | `true` | Show `event.icon` in the marker | | `layout` | `'single' \| 'alternating' \| 'roadmap'` | `'single'` | Card placement beside the rail | | `alternating` | `boolean` | `false` | Legacy alias: `true` maps to `layout: 'alternating'` when `layout` is omitted | | `markerSize` | `number` | CSS default | Marker diameter in CSS pixels | `layout` values: * **`single`**: every card on one side of a straight rail (default). * **`alternating`**: cards on both sides of a straight center rail. * **`roadmap`**: serpentine dashed road with markers on the curve peaks. Horizontal `direction` falls back from `roadmap` to `alternating`. Native digits come from the locale pack (`fa` / `ps`) or from `displayFormat.numerals` (`'native'` or `'latin'`). On narrow viewports, both-sided layouts collapse to a single-sided rail. ## React ```tsx import { EventCalendar } from '@jalali-js/ui-react'; import type { CalendarEvent } from 'jalali-js'; const events: CalendarEvent[] = [ { id: 'workshop', title: 'Workshop', start: { year: 1403, month: 5, day: 10 }, end: { year: 1403, month: 5, day: 12 }, }, { id: 'meeting', title: 'Meeting', start: { year: 1403, month: 5, day: 15 }, end: { year: 1403, month: 5, day: 15 }, allDay: false, startTime: { hour: 14, minute: 0 }, endTime: { hour: 15, minute: 0 }, }, ]; console.log(event.id)} onDayClick={(date) => console.log(date)} />; ``` Timeline example: ```tsx ``` ## Vue ```vue ``` ## Web Components ```ts import '@jalali-js/ui-web'; const el = document.querySelector('jalali-event-calendar')!; el.view = 'week'; el.initialDate = { year: 1403, month: 5, day: 15 }; el.events = [ { id: 'workshop', title: 'Workshop', start: { year: 1403, month: 5, day: 10 }, end: { year: 1403, month: 5, day: 12 }, }, ]; el.addEventListener('event-click', (event) => { console.log(event.detail.event); }); ``` ```html ``` For timeline, set `el.view = 'timeline'`, `el.timeline = { ... }`, and `el.displayFormat = { numerals: 'native' }` as needed. ## Props (React) | Prop | Type | Default | Meaning | | ----------------------- | ------------------------------------------ | ---------- | -------------------- | | `system` | `CalendarSystem` | `'jalali'` | Display calendar | | `locale` | `LocaleCode` | `'en'` | UI language | | `view` | `'month' \| 'week' \| 'day' \| 'timeline'` | `'month'` | Visible view | | `events` | `CalendarEvent[]` | `[]` | Events to layout | | `initialDisplayedMonth` | `{ year, month }` | - | Month anchor (day 1) | | `initialDate` | `{ year, month, day }` | today | Week or day anchor | | `displayFormat` | `FormatOptions` | - | Day and stamp format | | `timeline` | `TimelineOptions` | - | Timeline layout | | `onEventClick` | `(event) => void` | - | Event chip clicked | | `onDayClick` | `(date) => void` | - | Day cell clicked | | `className` | `string` | - | Root class | Vue: same props, emits `eventClick` and `dayClick`. Web: attrs `system`, `locale`, `view`; props `events`, `initialDisplayedMonth`, `initialDate`, `displayFormat`, `timeline`; events `event-click`, `day-click`. ## Styling Import the same `date-picker.css` as the other pickers. Event chips use `data-jalali-eventcalendar-*` and the `--jalali-event-bg` / `--jalali-event-fg` variables. Timeline uses `data-jalali-timeline-*`, `data-layout`, and tokens such as `--jalali-timeline-marker-size`, `--jalali-timeline-accent`, and the `--jalali-timeline-road-*` set for `layout: 'roadmap'`. When `timeline.markerSize` is omitted, the stylesheet default marker size applies. See [Configuration and theming](/guide/theming) for the full variable list. --- --- url: https://jalali-js.yanovian.com/guide/examples.md description: Copy-paste snippets for conversion, pickers, ranges, NLP, and theming. --- # Examples Short, self-contained snippets for common tasks. Each one is copy-paste ready: it shows every import it needs. For task-shaped answers (bounds, epoch, forms, SSR), see [Recipes](/guide/recipes). For concepts, see [Getting started](/guide/getting-started), [Core concepts](/guide/core-concepts), and [Configuration and theming](/guide/theming). ## Convert between calendars ```ts import { toGregorian, fromGregorian } from 'jalali-js'; toGregorian({ year: 1403, month: 5, day: 15 }, 'jalali'); // { year: 2024, month: 8, day: 5 } fromGregorian({ year: 2024, month: 8, day: 5 }, 'jalali'); // { year: 1403, month: 5, day: 15 } ``` ## Format a date for display ```ts import { format, fa } from '@jalali-js/i18n'; const date = { precision: 'date' as const, system: 'jalali' as const, year: 1403, month: 5, day: 15, }; format(date, fa); // '۱۵ مرداد ۱۴۰۳' format(date, fa, { weekday: true }); // 'دوشنبه، ۱۵ مرداد ۱۴۰۳' format(date, fa, { numerals: 'latin' }); // '15 مرداد 1403' ``` ## Parse a natural language phrase ```ts import { parse } from '@jalali-js/nlp'; parse('tomorrow', 'en'); parse('فردا', 'fa'); parse('نن', 'ps'); // Pashto for 'today' parse('next Farvardin', 'en'); ``` ## React: a date field that stores Gregorian, displays Jalali ```tsx import '@jalali-js/react/date-picker.css'; import { DatePicker } from '@jalali-js/react'; function BirthDateField() { return ( { // value is a Gregorian ISO string, e.g. '2024-08-05'. Store this. }} /> ); } ``` ## Vue: the same field, with `v-model` ```vue ``` ## Vanilla / Web Components: the same field, no framework ```html ``` ## React: a date range field ```tsx import '@jalali-js/react/date-picker.css'; import { RangePicker } from '@jalali-js/ui-react'; console.log(value)} />; ``` ## React: an always-visible calendar, no popover ```tsx import '@jalali-js/react/date-picker.css'; import { InlineCalendar } from '@jalali-js/ui-react'; import { useState } from 'react'; import type { CalendarDate } from 'jalali-js'; function EventDatePicker() { const [selected, setSelected] = useState(null); return ; } ``` ## React: event calendar (month, week, day, or timeline) ```tsx import '@jalali-js/react/date-picker.css'; import { EventCalendar } from '@jalali-js/ui-react'; import type { CalendarEvent } from 'jalali-js'; const events: CalendarEvent[] = [ { id: 'workshop', title: 'Workshop', start: { year: 1403, month: 5, day: 10 }, end: { year: 1403, month: 5, day: 12 }, }, { id: 'meeting', title: 'Meeting', start: { year: 1403, month: 5, day: 15 }, end: { year: 1403, month: 5, day: 15 }, allDay: false, startTime: { hour: 14, minute: 0 }, endTime: { hour: 15, minute: 0 }, }, ]; ; ``` Timeline with a roadmap layout: ```tsx ``` ## Holidays with day tips ```tsx ``` Hover or focus a holiday day to read the tip under the grid. See [Holidays](/guide/holidays#pickers). ## A custom theme, without a theme file `--jalali-*` custom properties inherit, so a naive override on a wrapping element can lose to a value set directly on the picker's own root, for example if `dark.css` is imported on the same page (see [Configuration and theming](/guide/theming)). Scope the override under a parent class instead, on a selector that matches the root element itself: ```css /* my-theme.css */ .my-theme [data-jalali-datepicker-root] { --jalali-primary: #c026d3; --jalali-primary-fg: #ffffff; --jalali-bg: #fdf4ff; --jalali-fg: #581c87; --jalali-radius: 20px; } ``` ```tsx import '@jalali-js/react/date-picker.css'; import './my-theme.css'; import { DatePicker } from '@jalali-js/react';
; ``` --- --- url: https://jalali-js.yanovian.com/guide/getting-started.md description: >- Install the core or a framework binding, then convert a date or render a picker. --- # Getting started ## Install :::tabs key:pm variant:code \== npm ```sh npm install jalali-js # React npm install @jalali-js/react # Vue npm install @jalali-js/vue # No framework: plain Web Components npm install @jalali-js/web ``` \== pnpm ```sh pnpm add jalali-js # React pnpm add @jalali-js/react # Vue pnpm add @jalali-js/vue # No framework: plain Web Components pnpm add @jalali-js/web ``` \== yarn ```sh yarn add jalali-js # React yarn add @jalali-js/react # Vue yarn add @jalali-js/vue # No framework: plain Web Components yarn add @jalali-js/web ``` ::: `jalali-js` is the core package: pure TypeScript, no framework dependency, no runtime dependency of its own. `@jalali-js/react`, `@jalali-js/vue`, and `@jalali-js/web` all depend on it. `@jalali-js/web` needs no framework at all: it is plain Web Components, usable from plain HTML/JS or dropped into any framework the same way any other HTML element is (see [Vanilla / Web Components](/guide/web-components)). `@jalali-js/i18n` (locale data and formatting), `@jalali-js/nlp` (natural language date parsing), and `@jalali-js/holidays` (official Iran public holidays today) are separate packages you install only if you need them directly. Every binding already depends on `@jalali-js/i18n` itself, and the pickers can mark Iran holidays through `showHolidays` (see [Holidays](/guide/holidays)). ## Convert a date ```ts import { createCalendar, toGregorian, fromGregorian } from 'jalali-js'; const jalali = createCalendar({ system: 'jalali' }); jalali.today(); // { year: 1403, month: 5, day: 15 } toGregorian({ year: 1403, month: 5, day: 15 }, 'jalali'); // { year: 2024, month: 8, day: 5 } fromGregorian({ year: 2024, month: 8, day: 5 }, 'jalali'); // { year: 1403, month: 5, day: 15 } ``` `system` is `'jalali'` or `'gregorian'`. Gregorian-to-Gregorian is the identity conversion, on purpose: it lets application code treat "calendar system" as one setting instead of a special case (see [Core concepts](/guide/core-concepts)). ## Render a picker (React) ```tsx import '@jalali-js/react/date-picker.css'; import { DatePicker } from '@jalali-js/react'; function BirthDateField() { return ( { // value is a Gregorian ISO string by default: '2024-08-05'. // See "Display value vs. storage value" for why, and how to opt out. }} /> ); } ``` ## Render a picker (Vue) ```vue ``` ## Render a picker (no framework) ```html ``` Next: [Core concepts](/guide/core-concepts) covers the precision tiers and the display/storage split these examples all lean on. --- --- url: https://jalali-js.yanovian.com/guide/holidays.md description: Iran public holidays, region packs, and picker markers. --- # Holidays `@jalali-js/holidays` ships offline Iran (`IR`) public holidays. `AF` and `TJ` are reserved and throw until those packs ship. Dates use Jalali `{ year, month, day }` fields. ## Regions ```ts import { isHoliday, SHIPPED_HOLIDAY_REGIONS } from '@jalali-js/holidays'; isHoliday({ year: 1403, month: 1, day: 1 }); // Iran (default) isHoliday({ year: 1403, month: 1, day: 1 }, { region: 'IR' }); SHIPPED_HOLIDAY_REGIONS; // ['IR'] ``` Iran pack layout: ``` regions/ir/ ids.ts fixed.ts lunar-table.ts holiday.ts names/{en,fa,ps}.ts index.ts ``` Names are one file per language, like `@jalali-js/i18n`. Runtime still returns `names: { en, fa, ps }`. ## Fixed and lunar Iran combines two calendars in one pack: * `kind: 'fixed'`: solar Jalali days (Nowruz, and so on) in `fixed.ts` * `kind: 'lunar'`: Islamic days that shift each year in `data/ir/lunar/` Lunar coverage is `HOLIDAY_YEAR_RANGE` (1402-1426 today). Outside that range, fixed days still resolve. ## API ```ts import { isHoliday, holidaysOn, holidaysInMonth, holidayName, holidayDayTip, holidayDayChrome, HOLIDAY_YEAR_RANGE, } from '@jalali-js/holidays'; isHoliday({ year: 1403, month: 1, day: 1 }); holidaysOn({ year: 1403, month: 1, day: 13 }); holidayName('ashura', 'fa'); holidaysInMonth(1403, 1); HOLIDAY_YEAR_RANGE; // { min: 1402, max: 1426 } ``` ## Pickers `showHolidays` marks days with `data-holiday`. `blockHolidays` also blocks selection. Default region is Iran (`holidayRegion` / `holiday-region`). With `showHolidays`, hover or focus on a holiday day shows a tip overlay under the grid (`data-jalali-calendar-tip`). Several holidays on one day join with `·`. When the day is also blocked, the tip adds the locale's `LocalePack.ui.closedDay` label (for example `Closed` / `بسته`). The day button's accessible name includes the tip text. Blocked holiday days use `data-disabled` and `aria-disabled` instead of the native `disabled` attribute, so hover and focus still work for the tip. ```tsx ``` ```vue ``` ```html ``` ## Day tips (headless) For a custom grid, build the tip and aria label with the same helpers the pickers use: ```ts import { holidayDayTip, holidayDayChrome } from '@jalali-js/holidays'; holidayDayTip({ year: 1403, month: 1, day: 1 }, { locale: 'en' }); // 'Nowruz' holidayDayTip( { year: 1403, month: 1, day: 1 }, { locale: 'en', closed: true, closedLabel: 'Closed' }, ); // 'Nowruz · Closed' holidayDayChrome('15 Mordad 1403', cell, { locale: 'en', closedLabel: 'Closed', }); // { tip?, ariaLabel, blocked? } ``` ## Update lunar data ```sh make update-holidays YEARS=next make update-holidays YEARS=1426 make update-holidays ``` `YEARS=next` fetches the year after the highest JSON year from emrooz.app. No years means rebuild from JSON on disk only. Yearly CI opens a PR when files change. --- --- url: https://jalali-js.yanovian.com/guide/i18n.md description: >- English, Farsi, and Pashto locale packs, formatting, relative time, format templates, strict parsing, and native numerals. --- # Internationalization :::tabs key:pm variant:code \== npm ```sh npm install @jalali-js/i18n ``` \== pnpm ```sh pnpm add @jalali-js/i18n ``` \== yarn ```sh yarn add @jalali-js/i18n ``` ::: Most apps never import this package directly: `useCalendar()`/`format()` are already wired up through `locale` props in `@jalali-js/react` and `@jalali-js/vue`. Reach for it directly when you need to format a date outside a component, or build your own display logic on the same locale data those bindings use. ## `format()` ```ts import { format, en, fa, ps } from '@jalali-js/i18n'; const date = { precision: 'date' as const, system: 'jalali' as const, year: 1403, month: 5, day: 15, }; format(date, en); // '15 Mordad 1403' format(date, fa); // '۱۵ مرداد ۱۴۰۳' format(date, ps); // '۱۵ زمری ۱۴۰۳' (the Afghan month names; see below) format(date, en, { style: 'short' }); // '15 Mor 1403' format(date, en, { weekday: true }); // 'Monday, 15 Mordad 1403' format(date, fa, { numerals: 'latin' }); // '15 مرداد 1403' (Latin digits, Persian text) ``` `format()` is display-only: it reads `date.system`'s own month names (so a Gregorian-system date formats with Gregorian month names, a Jalali-system date with Jalali ones, in either locale), and never affects what `toStorageValue()` returns. See [Display value vs. storage value](/guide/display-vs-storage). ## `formatRelative()` How `from` sits relative to `to`. Unit selection uses `diffDates()` from `jalali-js`. Digits follow `numerals` (default: the locale's `defaultNumerals`). ```ts import { formatRelative, en, fa, ps } from '@jalali-js/i18n'; const today = { precision: 'date' as const, system: 'jalali' as const, year: 1403, month: 5, day: 15, }; const threeDaysAgo = { ...today, day: 12 }; const inTwoMonths = { ...today, month: 7 }; formatRelative(today, today, en); // 'today' formatRelative(threeDaysAgo, today, en); // '3 days ago' formatRelative(threeDaysAgo, today, fa); // '۳ روز پیش' formatRelative(inTwoMonths, today, en); // 'in 2 months' formatRelative(inTwoMonths, today, fa); // '۲ ماه دیگر' formatRelative({ ...today, day: 14 }, today, ps); // '۱ ورځ مخکې' formatRelative(threeDaysAgo, today, fa, { numerals: 'latin' }); // '3 روز پیش' ``` Both dates must use the same calendar system. ## Templates When you need an exact shape, pass a `template`. It replaces the preset layout, so `style` and `weekday` are ignored. The `numerals` option still applies. ```ts format(date, en, { template: 'YYYY/MM/DD' }); // '1403/05/15' format(date, fa, { template: 'YYYY/MM/DD' }); // '۱۴۰۳/۰۵/۱۵' format(date, en, { template: 'D MMMM YYYY' }); // '15 Mordad 1403' format(date, en, { template: 'dddd D MMM YYYY' }); // 'Monday 15 Mor 1403' ``` | Token | Meaning | Example | | ------ | ------------------- | -------- | | `YYYY` | Year, 4 digits | `1403` | | `MM` | Month, 2 digits | `05` | | `M` | Month | `5` | | `DD` | Day, 2 digits | `15` | | `D` | Day | `15` | | `MMMM` | Month name, long | `Mordad` | | `MMM` | Month name, short | `Mor` | | `dddd` | Weekday name, long | `Monday` | | `ddd` | Weekday name, short | `Mon` | Text between tokens passes through as-is. Keep it to punctuation and spaces: a letter that matches a token (for example the `D` in `Day:`) is read as that token. ## `parseTemplate()` The reverse of a template format: strict parsing of a known shape. Free-form input belongs to [`@jalali-js/nlp`](/guide/nlp) instead. ```ts import { parseTemplate, en, fa } from '@jalali-js/i18n'; parseTemplate('1403/05/15', 'YYYY/MM/DD', en); // { precision: 'date', system: 'jalali', year: 1403, month: 5, day: 15 } parseTemplate('۱۴۰۳/۰۵/۱۵', 'YYYY/MM/DD', fa); // same date; native digits accepted parseTemplate('15 Mordad 1403', 'D MMMM YYYY', en); // same date parseTemplate('2024/08/05', 'YYYY/MM/DD', en, { system: 'gregorian' }); ``` It returns `null` instead of guessing: * The input must match the template's exact shape, with nothing left over. * Digits can be Latin or the locale's native set. * The date must exist: `1402/12/30` (Esfand 30 in a non-leap year) is `null`. * A weekday name must match the parsed date: `'Tuesday 15 Mordad 1403'` is `null`, because that day is a Monday. * The template must produce a year, a month, and a day. ## `formatNumber()` The digit-formatting `format()` uses internally, available on its own: ```ts import { formatNumber, fa } from '@jalali-js/i18n'; formatNumber(1403, 'native', fa.digits); // '۱۴۰۳' formatNumber(1403, 'latin', fa.digits); // '1403' formatNumber(5, 'latin', fa.digits, 2); // '05' (the optional minimum width zero-pads) ``` ## Locale packs `en`, `fa`, and `ps` are each a `LocalePack`: month names for both calendar systems (English transliterations of the Jalali months in `en`, Persian transliterations of the Gregorian months in `fa`), weekday names, `defaultNumerals`, `digits`, text `direction`, picker placeholders, and `ui` chrome strings for control `aria-label`s. That `ui` object includes nav labels (`previousMonth`, `nextYear`, and so on) and `closedDay`, the label pickers append when a holiday tip also marks the day as blocked (see [Holidays](/guide/holidays#pickers)). Persian has no widely standardized abbreviated month form the way English does, so `fa`'s `short` month names reuse `long`; weekday names do have a well-known one-letter short form, so those differ. Full shape: [`LocalePack`](/api/@jalali-js/i18n/interfaces/LocalePack). `ps` is Pashto, one of Afghanistan's two official languages. Afghanistan uses the same Jalali solar calendar as Iran, and names its months after the zodiac signs. So `ps`'s Jalali month names (وری, غویی, ..., کب) are alternative names for the same months, and share nothing with `fa`'s Persian ones. The data comes from CLDR's own `ps` locale, read through ICU, not from memory. CLDR has no abbreviated Pashto forms, so `short` reuses `long` throughout. ## Adding a locale A `LocalePack` is plain data against one exported interface. Adding a locale changes no other code in this package: `format()` reads whatever pack you pass it. The steps, using `ps` as the worked example: 1. **Write the pack.** Copy `fa.ts` (RTL) or `en.ts` (LTR) in `packages/i18n/src/` and fill in the fields: `code`, `direction`, the 10 `digits` characters, `defaultNumerals`, `weekdaySeparator`, month names for *both* calendar systems, weekday names (index 0 is Sunday), the two picker placeholders, `ui` chrome strings (one key per control meaning, including `closedDay` for blocked holiday tips), and `relative` phrases (`today`, past/future `one`/`other` forms with `{n}`). Source the names from real data you can verify. CLDR through Node's `Intl` works well: `new Intl.DateTimeFormat('ps-AF-u-ca-persian', { month: 'long' })` gives the Jalali month names, `Intl.NumberFormat` gives the digits, and `Intl.RelativeTimeFormat` gives the relative phrases. 2. **Register it.** Export the pack from `packages/i18n/src/index.ts`, and add its code to `LocaleCode` and the pack table in `packages/i18n/src/locale-packs.ts`. That one table is what the React, Vue, and Web Components bindings re-export, so the `locale` prop accepts the new code with no binding change. 3. **Add tests** mirroring the existing `fa` coverage in `format.test.ts` and `numerals.test.ts`: one formatted string per style, the weekday prefix, and an explicit `numerals: 'latin'` override. 4. **Optional: NLP phrases.** A word list in `packages/nlp/src/word-list.ts` adds natural-language parsing for the locale. This is separate from the display pack and ships only when the phrase set is well understood. `Intl.RelativeTimeFormat` is a verifiable source for the relative terms. --- --- url: https://jalali-js.yanovian.com/guide/nlp.md description: Parse English, Farsi, and Pashto date phrases into calendar dates. --- # Natural language parsing :::tabs key:pm variant:code \== npm ```sh npm install @jalali-js/nlp ``` \== pnpm ```sh pnpm add @jalali-js/nlp ``` \== yarn ```sh yarn add @jalali-js/nlp ``` ::: `parse()` reads a short natural-language phrase and returns a `CalendarDate`, or `null` when it doesn't recognize the phrase. Three locales: `en`, `fa`, and `ps` (Pashto). English input accepts the transliterated Jalali month names (`Mehr`, `Aban`, `Azar`); Farsi input uses Persian script. This package is for free-form phrases. To parse input with a known, exact shape such as `1403/05/15`, use [`parseTemplate()`](/guide/i18n#parsetemplate) from `@jalali-js/i18n` instead. ```ts import { parse } from '@jalali-js/nlp'; parse('today', 'en'); // today, in the jalali system (default) parse('tomorrow', 'en'); parse('yesterday', 'en'); parse('next week', 'en'); parse('next Farvardin', 'en'); // the next upcoming occurrence of that month parse('امروز', 'fa'); // 'today' parse('فردا', 'fa'); // 'tomorrow' parse('هفته آینده', 'fa'); // 'next week' parse('فروردین آینده', 'fa'); // 'next Farvardin' parse('نن', 'ps'); // 'today', in Pashto parse('راتلونکې اونۍ', 'ps'); // 'next week' parse('راتلونکی وری', 'ps'); // 'next Wray' (the Afghan name of Jalali month 1) parse('banana', 'en'); // null: not a recognized phrase ``` Pass `{ system: 'gregorian' }` to get the result in the Gregorian system instead of the default `'jalali'`: ```ts parse('today', 'en', { system: 'gregorian' }); ``` "Next ``" means the upcoming occurrence, not the one already under way: if the named month has already started this year, the result is next year's occurrence, the same convention "next Monday" uses for picking a day inside a period when none is given. The day is fixed at 1. `getWordList(locale)` exposes the underlying phrase table (`WordList`) `parse()` matches against, for a consumer who wants to build their own matching on top of it rather than use `parse()` directly. Full type: [API reference](/api/@jalali-js/nlp/). --- --- url: https://jalali-js.yanovian.com/fa/guide/react.md description: بایندینگ React، DatePicker، Calendar بدون ظاهر، و نکته‌های SSR در Next.js. --- # React :::tabs key:pm variant:code \== npm ```sh npm install @jalali-js/react ``` \== pnpm ```sh pnpm add @jalali-js/react ``` \== yarn ```sh yarn add @jalali-js/react ``` ::: ## `useCalendar()` هوک سطح پایین: وضعیت `date`، `format()` بسته‌شده به زبان خود هوک، و `isLeapYear()` / `daysInMonth()` / `today()` سامانه تقویم. بقیه این بسته روی آن یا روی همان پریمیتیوهایی که می‌پوشاند ساخته شده است. ```tsx import { useCalendar } from '@jalali-js/react'; function Summary() { const jalali = useCalendar({ system: 'jalali', locale: 'fa' }); return

امروز: {jalali.format(jalali.today(), { style: 'long', weekday: true })}

; } ``` ورودی `{ system?, locale?, initialDate? }`، خروجی `{ date, setDate, format, today, isLeapYear, daysInMonth, locale }`. امضای کامل: [مرجع API](/api/@jalali-js/react/). ## `Calendar`: پریمیتیو بدون ظاهر شبکه ماه با ویژگی‌های `data-jalali-calendar-*` و بدون CSS اجباری. `DatePicker` (پایین) همین مؤلفه با stylesheet پیش‌فرض و popover دور آن است؛ برای شبکه همیشه دیده‌شده، یا برای ساختن popover یا dialog خودتان دور آن، مستقیم `Calendar` را به کار ببرید. ```tsx import { Calendar } from '@jalali-js/react'; ; ``` یک render prop با نام `day` نشانه‌گذاری سلول را یکسره عوض می‌کند، اگر ویژگی‌های data به‌تنهایی کنترل کافی ندهند. ## `DatePicker`: انتخابگر کارآمد با ظاهر پیش‌فرض ```tsx import '@jalali-js/react/date-picker.css'; import { DatePicker } from '@jalali-js/react'; { /* value: مقدار ذخیره؛ date: CalendarDate خام */ }} />; ``` `variant="dropdown"` پاپ‌آپ شبکه تقویم را با سه ``s, for narrow, known-range entry such as a date of birth: ```tsx ``` In the grid popup (and in `Calendar` directly), a person can click the month or year in the header to jump straight to a month grid or a year grid, instead of paging one month at a time. This is on by default; pass `quickNav={false}` to turn it off. Pass `defaultDate={null}` for no initial selection, so the picker opens empty and shows its placeholder until someone picks a date. Full prop list: [`DatePickerProps`](/api/@jalali-js/react/interfaces/DatePickerProps). ## `useResolvedTimeZone()` Pairs with a `'zoned-datetime'` calendar's `timeZone: 'auto'` under SSR. The server render (and the client's first, hydrating render) always reads `'UTC'`, since there is no `window` yet; this hook re-resolves the real browser timezone once mounted, with no hydration warning. ```tsx import { useResolvedTimeZone } from '@jalali-js/react'; function Clock() { const timeZone = useResolvedTimeZone('auto'); return

{timeZone}

; // 'UTC' during SSR, the real zone after mount } ``` ## Range picker, event calendar, and inline calendar `@jalali-js/ui-react` adds `RangePicker`, `EventCalendar`, and `InlineCalendar` on the same primitives; see [Configuration and theming](/guide/theming#range-picker-event-calendar-and-inline-calendar) and [Event calendar](/guide/event-calendar). :::tabs key:pm variant:code \== npm ```sh npm install @jalali-js/ui-react ``` \== pnpm ```sh pnpm add @jalali-js/ui-react ``` \== yarn ```sh yarn add @jalali-js/ui-react ``` ::: ```tsx import { EventCalendar, InlineCalendar, RangePicker } from '@jalali-js/ui-react'; { /* ... */ }} /> ``` ## Prop tables Checked against source. Types are shortened. Full signatures live in the [API reference](/api/@jalali-js/react/). ### `DatePicker` | Prop | Type | Default | Meaning | | --------------- | ------------------------------------------ | ----------------- | ---------------------------------------- | | `system` | `'jalali' \| 'gregorian'` | `'jalali'` | Display calendar | | `locale` | `'en' \| 'fa' \| 'ps'` | `'en'` | UI language | | `defaultDate` | `CalendarDate \| CalendarDateTime \| null` | today | Initial selection. `null` is empty | | `precision` | `'date' \| 'datetime'` | `'date'` | Day only, or day plus time | | `minuteStep` | `number` | `1` | Minute step when `precision` is datetime | | `disabledHours` | `number[]` | - | Hidden hours 0-23 | | `quickNav` | `boolean` | `true` | Month and year jump grids | | `onChange` | `(value, date) => void` | - | Storage value and raw date | | `valueFormat` | `ValueFormat` | `'gregorian-iso'` | Shape of storage `value` | | `displayFormat` | `FormatOptions` | - | Input text format | | `variant` | `'grid' \| 'dropdown'` | `'grid'` | Grid popover or Y/M/D selects | | `rules` | `SelectionRules` | - | Min/max and blocked days | | `showHolidays` | `boolean` | `false` | Mark holidays (Jalali) | | `blockHolidays` | `boolean` | `false` | Block holidays (Jalali) | | `holidayRegion` | `'IR' \| 'AF' \| 'TJ'` | `'IR'` | Holiday pack | | `placeholder` | `string` | locale pack | Empty input text | | `className` | `string` | - | Root class | ### `Calendar` / `InlineCalendar` | Prop | Type | Default | Meaning | | ----------------------- | ---------------------- | -------------- | ------------------------- | | `system` | `CalendarSystem` | `'jalali'` | Display calendar | | `locale` | `LocaleCode` | `'en'` | UI language | | `value` | `CalendarDate \| null` | `null` | Selected day | | `onSelect` | `(date) => void` | - | Day picked | | `initialDisplayedMonth` | `{ year, month }` | value or today | Opening month | | `quickNav` | `boolean` | `true` | Month and year jump grids | | `rules` | `SelectionRules` | - | Min/max and blocked days | | `showHolidays` | `boolean` | `false` | Mark holidays | | `blockHolidays` | `boolean` | `false` | Block holidays | | `holidayRegion` | `HolidayRegion` | `'IR'` | Holiday pack | | `className` | `string` | - | Root class | ### `TimePicker` | Prop | Type | Default | Meaning | | --------------- | ---------------- | ------------------------ | ------------------- | | `value` | `TimeOfDay` | - | Controlled time | | `defaultValue` | `TimeOfDay` | `{ hour: 0, minute: 0 }` | Uncontrolled seed | | `minuteStep` | `number` | `1` | Minute options step | | `disabledHours` | `number[]` | - | Hidden hours | | `locale` | `LocaleCode` | `'en'` | Digits language | | `onChange` | `(time) => void` | - | Time changed | | `className` | `string` | - | Root class | ### `RangePicker` (`@jalali-js/ui-react`) | Prop | Type | Default | Meaning | | --------------- | ------------------------ | ----------------- | ---------------------------- | | `system` | `CalendarSystem` | `'jalali'` | Display calendar | | `locale` | `LocaleCode` | `'en'` | UI language | | `defaultRange` | `{ start, end }` | - | Initial range | | `onChange` | `(value, range) => void` | - | Fires when both ends are set | | `valueFormat` | `ValueFormat` | `'gregorian-iso'` | Storage shape for ends | | `displayFormat` | `FormatOptions` | - | Input text format | | `rules` | `SelectionRules` | - | Day and range limits | | `showHolidays` | `boolean` | `false` | Mark holidays | | `blockHolidays` | `boolean` | `false` | Block holidays | | `holidayRegion` | `HolidayRegion` | `'IR'` | Holiday pack | | `placeholder` | `string` | - | Empty input text | | `className` | `string` | - | Root class | ### `TimeRangePicker` (`@jalali-js/ui-react`) | Prop | Type | Default | Meaning | | --------------- | ----------------- | ------------------ | ------------------------- | | `locale` | `LocaleCode` | `'en'` | Digits language | | `defaultRange` | `{ start, end }` | `09:00` to `17:00` | Initial range | | `minuteStep` | `number` | `1` | Minute step for both ends | | `disabledHours` | `number[]` | - | Hidden hours | | `onChange` | `(range) => void` | - | Range changed | | `className` | `string` | - | Root class | ### `EventCalendar` (`@jalali-js/ui-react`) See [Event calendar](/guide/event-calendar) for the event model. Props: `system`, `locale`, `view` (`month` | `week` | `day` | `timeline`, default `month`), `events`, `initialDisplayedMonth`, `initialDate`, `displayFormat`, `timeline` (including `layout`: `single` | `alternating` | `roadmap`), `onEventClick`, `onDayClick`, `className`. --- --- url: https://jalali-js.yanovian.com/guide/recipes.md description: Short copy-paste answers for common DatePicker tasks. --- # Recipes One short example per job. Examples use React. Vue and Web notes sit under each recipe when the binding differs. See also [Examples](/guide/examples). ## Default to today Today is the default seed. Pass nothing, or pass today explicitly. ```tsx import '@jalali-js/react/date-picker.css'; import { DatePicker } from '@jalali-js/react'; console.log(value)} />; ``` Empty start: `defaultDate={null}` (Vue `:default-date="null"`, Web `.defaultDate = null`). ## Min and max bounds ```tsx import { DatePicker } from '@jalali-js/react'; ; ``` ## Block a weekend Jalali weekdays use Sunday = 0 … Saturday = 6. Thursday/Friday weekend: ```tsx ``` ## Epoch for an API ```tsx { // value is a Unix epoch number (ms) fetch('/api/appointments', { method: 'POST', body: JSON.stringify({ at: value }) }); }} /> ``` ## Form submission ```tsx function BookingForm() { const [stored, setStored] = useState(null); return (
{ event.preventDefault(); if (stored) submitBooking(stored); }} > setStored(value)} /> ); } ``` Vue: bind `v-model` to the storage value and submit that ref. Web: read `event.detail.value` from `change`, or read `.value` on the element. ## Programmatic set, read, and clear ### React `DatePicker` is uncontrolled for selection. Seed with `defaultDate`. Keep your own state from `onChange` to read. Remount with a new `key` to clear or reset. ```tsx function ControlledShell() { const [seed, setSeed] = useState(null); const [stored, setStored] = useState(null); return ( <> setStored(value)} />
{JSON.stringify(stored)}
); } ``` `Calendar` / `InlineCalendar` are controlled: pass `value` and `onSelect`. ### Vue `DatePicker` writes storage through `v-model`. Seed with `defaultDate`. Remount with `:key` to clear. `Calendar` uses `:value` and `@select`. ```vue ``` ### Web Components Set `.value` to read or write the selection without emitting. Set `.defaultDate` before connect to seed. Listen for `change` for user picks. ```ts const el = document.querySelector('jalali-date-picker')!; el.defaultDate = null; // empty until the user picks el.addEventListener('change', (event) => { console.log(event.detail.value); }); // later el.value = null; // clear, no change event console.log(el.value); ``` ## SSR (Next.js / Nuxt) Import CSS in a client boundary. Prefer `valueFormat` strings over `Date` objects for props that cross the server. ```tsx 'use client'; import '@jalali-js/react/date-picker.css'; import { DatePicker } from '@jalali-js/react'; export function ClientPicker() { return ; } ``` For `'zoned-datetime'` with `timeZone: 'auto'`, use `useResolvedTimeZone('auto')` so SSR and the first client paint stay on `'UTC'`. See the [React](/guide/react) and [Vue](/guide/vue) guides. --- --- url: https://jalali-js.yanovian.com/guide/selection-rules.md description: >- Limit what a person can pick, min/max bounds, blocked dates and weekdays, in every picker. --- # Selection rules Every picker takes a `rules` object (a `SelectionRules` from `jalali-js`) that limits what a person can select. Blocked days render as disabled buttons with a `data-disabled` attribute: clicks do nothing, and the Tab order skips them. The same rules work on `Calendar`, `DatePicker`, and `RangePicker`, in React, Vue, and the Web Components, since all of them read the rules through the shared `buildCalendarGrid()`. ```ts interface SelectionRules { minDate?: { year: number; month: number; day: number }; maxDate?: { year: number; month: number; day: number }; enabledDates?: { year: number; month: number; day: number }[]; disabledDates?: { year: number; month: number; day: number }[]; disabledWeekdays?: number[]; // 0 is Sunday, 6 is Saturday } ``` Rule dates are plain `{ year, month, day }` fields, read in the picker's own calendar system. The priority order, resolved by `isDateSelectable(date, rules)`: 1. `enabledDates`, when set, decides alone. This list wins over every other rule. 2. `disabledDates` blocks a listed date. 3. `disabledWeekdays` blocks a listed weekday. 4. `minDate` and `maxDate` block dates outside the bounds (bounds included). ## Min/max bounds Limit a booking form to the next 30 days: ```tsx import { DatePicker } from '@jalali-js/react'; import { addDays, createCalendar } from 'jalali-js'; const today = createCalendar({ system: 'jalali' }).today(); ; ``` ## Weekend blocking (Thursday and Friday) The Iranian weekend is Thursday and Friday, weekday indices 4 and 5: ```tsx ``` ## A whitelist of open dates When only a known set of dates is valid, list them in `enabledDates`. Every other date is blocked, and the other rules are ignored: ```tsx ``` ## Vue and Web Components The Vue components take the same `rules` prop: ```vue ``` On the Web Components, `rules` is a property (an object), not an attribute: ```js const picker = document.querySelector('jalali-date-picker'); picker.rules = { disabledWeekdays: [4, 5] }; ``` ## Range pickers `RangePicker` uses the same `rules`. A candidate range that crosses a blocked day does not complete: the second click starts a new range at the clicked day instead. That choice is shared across React, Vue, and Web through `isRangeSelectable(start, end, rules)`. ```tsx import { RangePicker } from '@jalali-js/ui-react'; ; ``` --- --- url: https://jalali-js.yanovian.com/guide/time-selection.md description: Pick a time of day, or a date with a time, in React, Vue, and Web Components. --- # Time selection The core already models `date + time` (Phase 2). This guide covers the components that expose that model in the UI. ## `TimePicker` Hour and minute selects. Headless first: style through `data-jalali-timepicker-*`, or import the same `date-picker.css` that `DatePicker` uses. ```tsx import { TimePicker } from '@jalali-js/react'; console.log(time)} />; ``` | Prop | Type | Default | Meaning | | --------------- | ---------------- | ------------------------ | -------------------- | | `value` | `TimeOfDay` | - | Controlled time | | `defaultValue` | `TimeOfDay` | `{ hour: 0, minute: 0 }` | Uncontrolled seed | | `minuteStep` | `number` | `1` | Minute options step | | `disabledHours` | `number[]` | - | Hidden hours 0-23 | | `locale` | `LocaleCode` | `'en'` | Digits and direction | | `onChange` | `(time) => void` | - | Time changed (React) | Vue uses `@change`. Web: ``, attrs `minute-step` and `disabled-hours`, prop `.value`. ## `DatePicker` with `precision="datetime"` Add a time panel under the grid. The emitted storage value carries the time through the existing Phase 2 contract (`2024-08-05T14:30:00.000` by default). ```tsx import { DatePicker } from '@jalali-js/react'; console.log(value, date)} />; ``` When `precision` is `'datetime'`, picking a day keeps the popover open so the person can set the time. Closing still works through Escape or a click outside. ## `TimeRangePicker` Two `TimePicker`s side by side, in the `ui-*` packages next to `RangePicker`. ```tsx import { TimeRangePicker } from '@jalali-js/ui-react'; console.log(range.start, range.end)} />; ``` Vue: `@change`. Web: ``, listen for `change`. --- --- url: https://jalali-js.yanovian.com/fa.md --- ## از اینجا شروع کنید * [نسخه زنده (React)](/playground/react/) · [Vue](/playground/vue/) · [Web Components](/playground/vanilla/) * [راهنمای مستندات](/fa/guide/getting-started) * [مرجع API](/api/jalali-js/) * [مقایسه گزینه‌ها](/fa/guide/comparison) ## اکوسیستم npm [`jalali-js`](https://www.npmjs.com/package/jalali-js) · [`@jalali-js/i18n`](https://www.npmjs.com/package/@jalali-js/i18n) · [`@jalali-js/nlp`](https://www.npmjs.com/package/@jalali-js/nlp) · [`@jalali-js/holidays`](https://www.npmjs.com/package/@jalali-js/holidays) · [`@jalali-js/react`](https://www.npmjs.com/package/@jalali-js/react) · [`@jalali-js/vue`](https://www.npmjs.com/package/@jalali-js/vue) · [`@jalali-js/web`](https://www.npmjs.com/package/@jalali-js/web) · [`@jalali-js/ui-react`](https://www.npmjs.com/package/@jalali-js/ui-react) · [`@jalali-js/ui-vue`](https://www.npmjs.com/package/@jalali-js/ui-vue) · [`@jalali-js/ui-web`](https://www.npmjs.com/package/@jalali-js/ui-web) | بسته | نقش | | -------------------------------------------------------------------------- | -------------------------- | | [`jalali-js`](https://www.npmjs.com/package/jalali-js) | هسته تبدیل | | [`@jalali-js/i18n`](https://www.npmjs.com/package/@jalali-js/i18n) | زبان‌ها و قالب‌بندی | | [`@jalali-js/nlp`](https://www.npmjs.com/package/@jalali-js/nlp) | پردازش زبان طبیعی | | [`@jalali-js/holidays`](https://www.npmjs.com/package/@jalali-js/holidays) | تعطیلات ایران | | [`@jalali-js/react`](https://www.npmjs.com/package/@jalali-js/react) | بایندینگ React | | [`@jalali-js/vue`](https://www.npmjs.com/package/@jalali-js/vue) | بایندینگ Vue | | [`@jalali-js/web`](https://www.npmjs.com/package/@jalali-js/web) | Web Components | | [`@jalali-js/ui-react`](https://www.npmjs.com/package/@jalali-js/ui-react) | رابط کاربری React | | [`@jalali-js/ui-vue`](https://www.npmjs.com/package/@jalali-js/ui-vue) | رابط کاربری Vue | | [`@jalali-js/ui-web`](https://www.npmjs.com/package/@jalali-js/ui-web) | رابط کاربری Web Components | --- --- url: https://jalali-js.yanovian.com/fa/guide/web-components.md description: انتخابگرهای Web Components بدون فریم‌ورک برای HTML ساده یا هر فریم‌ورک میزبان. --- # Vanilla / Web Components :::tabs key:pm variant:code \== npm ```sh npm install @jalali-js/web ``` \== pnpm ```sh pnpm add @jalali-js/web ``` \== yarn ```sh yarn add @jalali-js/web ``` ::: `@jalali-js/web` به فریم‌ورک نیاز ندارد. [Web Components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components) ساده (custom element) می‌فرستد، پس در HTML و JavaScript ساده کار می‌کند، و مثل هر عنصر HTML دیگر در React، Vue، Svelte، Angular یا هر فریم‌ورک دیگر می‌نشیند. ## ``: پریمیتیو بدون ظاهر شبکه ماه با ویژگی‌های `data-jalali-calendar-*` و بدون CSS اجباری. ```html ``` `system`، `locale` و `quick-nav` ویژگی‌های HTML ساده هستند. `.value` (انتخاب جاری، یا `null`) فقط property است، چون `CalendarDate` به‌صورت رشته ویژگی ساده قابل نمایش نیست. ## ``: انتخابگر کارآمد با ظاهر پیش‌فرض ```html ``` `variant="dropdown"` پاپ‌آپ شبکه تقویم را با سه ``s, for narrow, known-range entry such as a date of birth: ```html ``` A person can click the month or year in the grid popup's header to jump straight to a month grid or a year grid, instead of paging one month at a time. This is on by default; set `quick-nav="false"` to turn it off. Set `.defaultDate = null` (a property, not an attribute) for no initial selection, so the picker opens empty and shows its placeholder until someone picks a date; leave it unset for today's date. Full property and event list: [`JalaliDatePickerElement`](/api/@jalali-js/web/classes/JalaliDatePickerElement). ## Range picker, event calendar, and inline calendar `@jalali-js/ui-web` adds ``, ``, and `` on the same primitives; see [Configuration and theming](/guide/theming#range-picker-event-calendar-and-inline-calendar) and [Event calendar](/guide/event-calendar). :::tabs key:pm variant:code \== npm ```sh npm install @jalali-js/ui-web ``` \== pnpm ```sh pnpm add @jalali-js/ui-web ``` \== yarn ```sh yarn add @jalali-js/ui-web ``` ::: ```html ``` ## Attribute and property tables Boolean attributes use presence for on. Set `"false"` to turn them off. Objects (`rules`, `defaultDate`, `events`) are JavaScript properties only. ### `` | Name | Kind | Default | Meaning | | ---------------- | ----- | --------------- | ---------------------------------------- | | `system` | attr | `jalali` | Display calendar | | `locale` | attr | `en` | UI language | | `variant` | attr | `grid` | `grid` or `dropdown` | | `precision` | attr | `date` | `date` or `datetime` | | `minute-step` | attr | `1` | Minute step | | `disabled-hours` | attr | - | Comma-separated hours | | `value-format` | attr | `gregorian-iso` | Storage shape | | `placeholder` | attr | locale pack | Empty input text | | `quick-nav` | attr | on | Month and year jump grids | | `show-holidays` | attr | off | Mark holidays | | `block-holidays` | attr | off | Block holidays | | `holiday-region` | attr | `IR` | Holiday pack | | `defaultDate` | prop | today | Initial selection. `null` is empty | | `rules` | prop | - | Selection limits | | `value` | prop | - | Get or set selection (set does not emit) | | `change` | event | - | `{ value, date }` | ### `` / `` | Name | Kind | Default | Meaning | | ----------------------- | ----- | -------- | ------------------------- | | `system` | attr | `jalali` | Display calendar | | `locale` | attr | `en` | UI language | | `quick-nav` | attr | on | Month and year jump grids | | `show-holidays` | attr | off | Mark holidays | | `block-holidays` | attr | off | Block holidays | | `holiday-region` | attr | `IR` | Holiday pack | | `value` | prop | `null` | Selected day | | `rules` | prop | - | Selection limits | | `initialDisplayedMonth` | prop | - | Opening month | | `select` | event | - | `{ date }` | ### `` | Name | Kind | Default | Meaning | | ---------------- | ----- | -------- | --------------------- | | `locale` | attr | `en` | Digits language | | `minute-step` | attr | `1` | Minute options step | | `disabled-hours` | attr | - | Comma-separated hours | | `value` | prop | midnight | Current time | | `change` | event | - | `{ time }` | ### `` | Name | Kind | Default | Meaning | | ----------------------------------------------------- | ----- | ------------------- | -------------------- | | `system` / `locale` / `value-format` / `placeholder` | attr | same as date picker | Shared picker attrs | | `show-holidays` / `block-holidays` / `holiday-region` | attr | off / off / `IR` | Holiday flags | | `defaultRange` | prop | - | Initial range | | `rules` | prop | - | Day and range limits | | `change` | event | - | `{ value, range }` | ### `` | Name | Kind | Default | Meaning | | ---------------- | ----- | ------------------ | --------------------- | | `locale` | attr | `en` | Digits language | | `minute-step` | attr | `1` | Minute step | | `disabled-hours` | attr | - | Comma-separated hours | | `defaultRange` | prop | `09:00` to `17:00` | Initial range | | `change` | event | - | `{ range }` | ### `` | Name | Kind | Default | Meaning | | ----------------------- | ----- | -------- | -------------------------------------- | | `system` | attr | `jalali` | Display calendar | | `locale` | attr | `en` | UI language | | `view` | attr | `month` | `month`, `week`, `day`, or `timeline` | | `timeline` | prop | - | Timeline options (`layout`, and so on) | | `events` | prop | `[]` | Events to layout | | `initialDisplayedMonth` | prop | - | Month anchor | | `initialDate` | prop | today | Week or day anchor | | `event-click` | event | - | `{ event }` | | `day-click` | event | - | `{ date }` | ## No shadow DOM, on purpose These elements render in light DOM: no `attachShadow()`, no encapsulation boundary. That is what makes `@jalali-js/web/date-picker.css` (and the `compact`/`dark` themes from `@jalali-js/ui-web/themes`) the exact same stylesheets the React and Vue bindings use, styling the exact same `[data-jalali-*]` attributes either way. A team already running one of those themes across React and Vue can drop a `` into a plain HTML page, or into a framework this project has no dedicated binding for, and it looks identical with zero new CSS. --- --- url: https://jalali-js.yanovian.com/fa/guide/vue.md description: بایندینگ Vue، DatePicker، Calendar بدون ظاهر، و نکته‌های SSR در Nuxt. --- # Vue :::tabs key:pm variant:code \== npm ```sh npm install @jalali-js/vue ``` \== pnpm ```sh pnpm add @jalali-js/vue ``` \== yarn ```sh yarn add @jalali-js/vue ``` ::: ## `useCalendar()` composable سطح پایین: یک **ref** برای `date` (نه جفت `[date, setDate]` مثل هوک React؛ Vue اصطلاحی مستقیم ref را می‌خواند و می‌نویسد)، به‌همراه `format()` بسته‌شده به زبان composable، و `isLeapYear()` / `daysInMonth()` / `today()` سامانه تقویم. ```vue ``` امضای کامل: [مرجع API](/api/@jalali-js/vue/). ## `Calendar`: پریمیتیو بدون ظاهر شبکه ماه با ویژگی‌های `data-jalali-calendar-*` و بدون CSS اجباری. ```vue ``` یک scoped slot با نام `day` نشانه‌گذاری سلول را یکسره عوض می‌کند، کنار همان ویژگی‌های `data-jalali-calendar-*`، برای مصرف‌کننده‌ای که فقط می‌خواهد ظاهر را عوض کند نه اینکه جایگزین کامل بسازد. ## `DatePicker`: انتخابگر کارآمد با ظاهر پیش‌فرض `v-model` مقدار **ذخیره** را حمل می‌کند (شکل‌گرفته با `valueFormat`)، نه `CalendarDate` خام، پس یک کانال نوشتن مؤثر است: انتخاب تاریخ مقدار بسته‌شده را مستقیم به‌روز می‌کند. مقدار را دوباره نمی‌خواند (برگرداندن هر `valueFormat` به `CalendarDate` خارج از محدوده است)؛ برای مقدار انتخاب اولیه به‌جای آن از `defaultDate` استفاده کنید. ```vue ``` `variant="dropdown"` پاپ‌آپ شبکه تقویم را با سه ``s: ```vue ``` In the grid popup (and in `Calendar` directly), a person can click the month or year in the header to jump straight to a month grid or a year grid, instead of paging one month at a time. This is on by default; pass `:quick-nav="false"` to turn it off. Pass `:default-date="null"` for no initial selection, so the picker opens empty and shows its placeholder until someone picks a date. ## `useResolvedTimeZone()` Pairs with a `'zoned-datetime'` calendar's `timeZone: 'auto'` under SSR. Unlike Next.js, Nuxt has no separate "client component" concept to opt into: every component is server-rendered then hydrated by default, so no extra wrapping is needed. The composable's internal `onMounted` re-resolves the real browser timezone once mounted, with no hydration warning. ```vue ``` ## Range picker, event calendar, and inline calendar `@jalali-js/ui-vue` adds `RangePicker`, `EventCalendar`, and `InlineCalendar` on the same primitives; see [Configuration and theming](/guide/theming#range-picker-event-calendar-and-inline-calendar) and [Event calendar](/guide/event-calendar). :::tabs key:pm variant:code \== npm ```sh npm install @jalali-js/ui-vue ``` \== pnpm ```sh pnpm add @jalali-js/ui-vue ``` \== yarn ```sh yarn add @jalali-js/ui-vue ``` ::: ```vue ``` ## Prop tables `.vue` SFCs are not in the generated API. These tables match `defineProps` in source. Binding note: `DatePicker` and `RangePicker` use `v-model` for the storage value (write channel). Seed with `defaultDate` / `defaultRange`. `Calendar` uses `:value` and `@select`. `TimePicker` / `TimeRangePicker` emit `change`. `EventCalendar` emits `eventClick` and `dayClick`. ### `DatePicker` | Prop | Type | Default | Meaning | | --------------- | ------------------------------------------ | ----------------- | ---------------------------------- | | `system` | `'jalali' \| 'gregorian'` | `'jalali'` | Display calendar | | `locale` | `'en' \| 'fa' \| 'ps'` | `'en'` | UI language | | `defaultDate` | `CalendarDate \| CalendarDateTime \| null` | today | Initial selection. `null` is empty | | `precision` | `'date' \| 'datetime'` | `'date'` | Day only, or day plus time | | `minuteStep` | `number` | `1` | Minute step when datetime | | `disabledHours` | `number[]` | - | Hidden hours 0-23 | | `quickNav` | `boolean` | `true` | Month and year jump grids | | `valueFormat` | `ValueFormat` | `'gregorian-iso'` | Shape of `v-model` | | `displayFormat` | `FormatOptions` | - | Input text format | | `variant` | `'grid' \| 'dropdown'` | `'grid'` | Grid popover or Y/M/D selects | | `rules` | `SelectionRules` | - | Min/max and blocked days | | `showHolidays` | `boolean` | `false` | Mark holidays (Jalali) | | `blockHolidays` | `boolean` | `false` | Block holidays (Jalali) | | `holidayRegion` | `'IR' \| 'AF' \| 'TJ'` | `'IR'` | Holiday pack | | `placeholder` | `string` | locale pack | Empty input text | ### `Calendar` / `InlineCalendar` | Prop | Type | Default | Meaning | | ----------------------- | ---------------------- | -------------- | ------------------------- | | `system` | `CalendarSystem` | `'jalali'` | Display calendar | | `locale` | `LocaleCode` | `'en'` | UI language | | `value` | `CalendarDate \| null` | `null` | Selected day | | `initialDisplayedMonth` | `{ year, month }` | value or today | Opening month | | `quickNav` | `boolean` | `true` | Month and year jump grids | | `rules` | `SelectionRules` | - | Min/max and blocked days | | `showHolidays` | `boolean` | `false` | Mark holidays | | `blockHolidays` | `boolean` | `false` | Block holidays | | `holidayRegion` | `HolidayRegion` | `'IR'` | Holiday pack | Emit: `select` with the picked `CalendarDate`. ### `TimePicker` | Prop | Type | Default | Meaning | | --------------- | ------------ | ------------------------ | ------------------- | | `value` | `TimeOfDay` | - | Controlled time | | `defaultValue` | `TimeOfDay` | `{ hour: 0, minute: 0 }` | Uncontrolled seed | | `minuteStep` | `number` | `1` | Minute options step | | `disabledHours` | `number[]` | - | Hidden hours | | `locale` | `LocaleCode` | `'en'` | Digits language | Emit: `change` with `TimeOfDay`. ### `RangePicker` (`@jalali-js/ui-vue`) | Prop | Type | Default | Meaning | | --------------- | ---------------- | ----------------- | -------------------- | | `system` | `CalendarSystem` | `'jalali'` | Display calendar | | `locale` | `LocaleCode` | `'en'` | UI language | | `defaultRange` | `{ start, end }` | - | Initial range | | `valueFormat` | `ValueFormat` | `'gregorian-iso'` | Shape of `v-model` | | `displayFormat` | `FormatOptions` | - | Input text format | | `rules` | `SelectionRules` | - | Day and range limits | | `showHolidays` | `boolean` | `false` | Mark holidays | | `blockHolidays` | `boolean` | `false` | Block holidays | | `holidayRegion` | `HolidayRegion` | `'IR'` | Holiday pack | | `placeholder` | `string` | - | Empty input text | ### `TimeRangePicker` (`@jalali-js/ui-vue`) | Prop | Type | Default | Meaning | | --------------- | ---------------- | ------------------ | ------------------------- | | `locale` | `LocaleCode` | `'en'` | Digits language | | `defaultRange` | `{ start, end }` | `09:00` to `17:00` | Initial range | | `minuteStep` | `number` | `1` | Minute step for both ends | | `disabledHours` | `number[]` | - | Hidden hours | Emit: `change` with the time range. ### `EventCalendar` (`@jalali-js/ui-vue`) See [Event calendar](/guide/event-calendar). Props match React except callbacks are emits `eventClick` and `dayClick`. --- --- url: https://jalali-js.yanovian.com/fa/guide/time-selection.md description: >- زمان روز، یا تاریخ به‌همراه زمان را در React، Vue و Web Components انتخاب کنید. --- # انتخاب زمان هسته از قبل مدل `date + time` را دارد (فاز ۲). این راهنما مؤلفه‌هایی را پوشش می‌دهد که آن مدل را در UI نشان می‌دهند. ## `TimePicker` انتخابگر ساعت و دقیقه. اول بدون ظاهر: با `data-jalali-timepicker-*` قالب بدهید، یا همان `date-picker.css` که `DatePicker` استفاده می‌کند را وارد کنید. ```tsx import { TimePicker } from '@jalali-js/react'; console.log(time)} />; ``` | Prop | نوع | پیش‌فرض | معنا | | --------------- | ---------------- | ------------------------ | ---------------------- | | `value` | `TimeOfDay` | - | زمان کنترل‌شده | | `defaultValue` | `TimeOfDay` | `{ hour: 0, minute: 0 }` | مقدار اولیه بدون کنترل | | `minuteStep` | `number` | `1` | گام گزینه‌های دقیقه | | `disabledHours` | `number[]` | - | ساعت‌های پنهان ۰ تا ۲۳ | | `locale` | `LocaleCode` | `'en'` | رقم‌ها و جهت | | `onChange` | `(time) => void` | - | تغییر زمان (React) | Vue از `@change` استفاده می‌کند. Web: ``، ویژگی‌های `minute-step` و `disabled-hours`، و prop با `.value`. ## `DatePicker` با `precision="datetime"` یک پنل زمان زیر شبکه اضافه کنید. مقدار ذخیره ارسال‌شده زمان را از قرارداد موجود فاز ۲ حمل می‌کند (`2024-08-05T14:30:00.000` به‌صورت پیش‌فرض). ```tsx import { DatePicker } from '@jalali-js/react'; console.log(value, date)} />; ``` وقتی `precision` برابر `'datetime'` است، انتخاب روز popover را باز نگه می‌دارد تا شخص زمان را تنظیم کند. بستن همچنان با Escape یا کلیک بیرون کار می‌کند. ## `TimeRangePicker` دو `TimePicker` کنار هم، در بسته‌های `ui-*` کنار `RangePicker`. ```tsx import { TimeRangePicker } from '@jalali-js/ui-react'; console.log(range.start, range.end)} />; ``` Vue: `@change`. Web: ``، به رویداد `change` گوش دهید. --- --- url: https://jalali-js.yanovian.com/fa/guide/i18n.md description: >- بسته‌های زبان انگلیسی، فارسی و پشتو، قالب‌بندی، زمان نسبی، قالب‌های فرمت، خواندن سخت‌گیرانه، و رقم‌های بومی. --- # بین‌المللی‌سازی :::tabs key:pm variant:code \== npm ```sh npm install @jalali-js/i18n ``` \== pnpm ```sh pnpm add @jalali-js/i18n ``` \== yarn ```sh yarn add @jalali-js/i18n ``` ::: بیشتر برنامه‌ها این بسته را مستقیم وارد نمی‌کنند: `useCalendar()` و `format()` از قبل از طریق prop با نام `locale` در `@jalali-js/react` و `@jalali-js/vue` وصل شده‌اند. وقتی لازم است تاریخ را بیرون از مؤلفه قالب کنید، یا منطق نمایش خود را روی همان داده زبانی که آن بایندینگ‌ها به کار می‌برند بسازید، مستقیم سراغ آن بروید. ## `format()` ```ts import { format, en, fa, ps } from '@jalali-js/i18n'; const date = { precision: 'date' as const, system: 'jalali' as const, year: 1403, month: 5, day: 15, }; format(date, en); // '15 Mordad 1403' format(date, fa); // '۱۵ مرداد ۱۴۰۳' format(date, ps); // '۱۵ زمری ۱۴۰۳' (نام ماه‌های افغانی؛ پایین را ببینید) format(date, en, { style: 'short' }); // '15 Mor 1403' format(date, en, { weekday: true }); // 'Monday, 15 Mordad 1403' format(date, fa, { numerals: 'latin' }); // '15 مرداد 1403' (رقم لاتین، متن پارسی) ``` `format()` فقط برای نمایش است: نام ماه‌های خود `date.system` را می‌خواند (پس تاریخ با سامانه میلادی با نام ماه میلادی قالب می‌شود و تاریخ با سامانه جلالی با نام ماه جلالی، در هر زبانی)، و هرگز روی خروجی `toStorageValue()` اثر نمی‌گذارد. ببینید [مقدار نمایشی در برابر مقدار ذخیره‌سازی](/fa/guide/display-vs-storage). ## `formatRelative()` موقعیت `from` نسبت به `to`. انتخاب واحد از `diffDates()` در `jalali-js` استفاده می‌کند. رقم‌ها از `numerals` پیروی می‌کنند (پیش‌فرض: `defaultNumerals` زبان). ```ts import { formatRelative, en, fa, ps } from '@jalali-js/i18n'; const today = { precision: 'date' as const, system: 'jalali' as const, year: 1403, month: 5, day: 15, }; const threeDaysAgo = { ...today, day: 12 }; const inTwoMonths = { ...today, month: 7 }; formatRelative(today, today, en); // 'today' formatRelative(threeDaysAgo, today, en); // '3 days ago' formatRelative(threeDaysAgo, today, fa); // '۳ روز پیش' formatRelative(inTwoMonths, today, en); // 'in 2 months' formatRelative(inTwoMonths, today, fa); // '۲ ماه دیگر' formatRelative({ ...today, day: 14 }, today, ps); // '۱ ورځ مخکې' formatRelative(threeDaysAgo, today, fa, { numerals: 'latin' }); // '3 روز پیش' ``` هر دو تاریخ باید همان سامانه تقویم را داشته باشند. ## قالب‌ها وقتی شکل دقیق لازم دارید، یک `template` بدهید. جای چیدمان ازپیش‌تعیین‌شده را می‌گیرد، پس `style` و `weekday` نادیده گرفته می‌شوند. گزینه `numerals` همچنان اعمال می‌شود. ```ts format(date, en, { template: 'YYYY/MM/DD' }); // '1403/05/15' format(date, fa, { template: 'YYYY/MM/DD' }); // '۱۴۰۳/۰۵/۱۵' format(date, en, { template: 'D MMMM YYYY' }); // '15 Mordad 1403' format(date, en, { template: 'dddd D MMM YYYY' }); // 'Monday 15 Mor 1403' ``` | توکن | معنا | مثال | | ------ | ------------------- | -------- | | `YYYY` | سال، ۴ رقم | `1403` | | `MM` | ماه، ۲ رقم | `05` | | `M` | ماه | `5` | | `DD` | روز، ۲ رقم | `15` | | `D` | روز | `15` | | `MMMM` | نام ماه، بلند | `Mordad` | | `MMM` | نام ماه، کوتاه | `Mor` | | `dddd` | نام روز هفته، بلند | `Monday` | | `ddd` | نام روز هفته، کوتاه | `Mon` | متن بین توکن‌ها همان‌طور می‌گذرد. آن را به نشانه‌گذاری و فاصله محدود کنید: حرفی که با یک توکن هم‌خوان شود (برای مثال `D` در `Day:`) به‌عنوان آن توکن خوانده می‌شود. ## `parseTemplate()` برعکس قالب فرمت: خواندن سخت‌گیرانه یک شکل شناخته‌شده. ورودی آزاد به [`@jalali-js/nlp`](/fa/guide/nlp) تعلق دارد. ```ts import { parseTemplate, en, fa } from '@jalali-js/i18n'; parseTemplate('1403/05/15', 'YYYY/MM/DD', en); // { precision: 'date', system: 'jalali', year: 1403, month: 5, day: 15 } parseTemplate('۱۴۰۳/۰۵/۱۵', 'YYYY/MM/DD', fa); // همان تاریخ؛ رقم بومی پذیرفته می‌شود parseTemplate('15 Mordad 1403', 'D MMMM YYYY', en); // همان تاریخ parseTemplate('2024/08/05', 'YYYY/MM/DD', en, { system: 'gregorian' }); ``` به‌جای حدس زدن، `null` برمی‌گرداند: * ورودی باید دقیقاً با شکل قالب هم‌خوان باشد، بدون باقی‌مانده. * رقم‌ها می‌توانند لاتین یا مجموعه بومی زبان باشند. * تاریخ باید وجود داشته باشد: `1402/12/30` (۳۰ اسفند در سال غیرکبیسه) برابر `null` است. * نام روز هفته باید با تاریخ خوانده‌شده هم‌خوان باشد: `'Tuesday 15 Mordad 1403'` برابر `null` است، چون آن روز دوشنبه است. * قالب باید سال، ماه و روز بسازد. ## `formatNumber()` قالب‌بندی رقمی که `format()` درون خودش به کار می‌برد، به‌تنهایی در دسترس است: ```ts import { formatNumber, fa } from '@jalali-js/i18n'; formatNumber(1403, 'native', fa.digits); // '۱۴۰۳' formatNumber(1403, 'latin', fa.digits); // '1403' formatNumber(5, 'latin', fa.digits, 2); // '05' (حداقل عرض اختیاری با صفر پر می‌شود) ``` ## بسته‌های زبان `en`، `fa` و `ps` هر کدام یک `LocalePack` هستند: نام ماه برای هر دو سامانه تقویم (آوانویسی انگلیسی ماه‌های جلالی در `en`، آوانویسی پارسی ماه‌های میلادی در `fa`)، نام روز هفته، `defaultNumerals`، `digits`، `direction` متن، جایگاه‌نمای انتخابگر، و رشته‌های ظاهر `ui` برای `aria-label` کنترل‌ها. آن شیء `ui` برچسب‌های ناوبری را دارد (`previousMonth`، `nextYear` و مانند آن) و `closedDay`، برچسبی که انتخابگرها وقتی نوک راهنمای تعطیل روز را مسدود هم نشان می‌دهد اضافه می‌کنند (ببینید [تعطیلات](/fa/guide/holidays#انتخابگرها)). فارسی شکل کوتاه استاندارد گسترده برای ماه مثل انگلیسی ندارد، پس نام ماه `short` در `fa` همان `long` را دوباره به کار می‌برد؛ نام روز هفته شکل کوتاه یک‌حرفی شناخته‌شده دارد، پس آن‌ها فرق می‌کنند. شکل کامل: [`LocalePack`](/api/@jalali-js/i18n/interfaces/LocalePack). `ps` پشتو است، یکی از دو زبان رسمی افغانستان. افغانستان همان تقویم شمسی جلالی ایران را به کار می‌برد و ماه‌ها را از نشانه‌های زودیاک نام می‌گذارد. پس نام ماه‌های جلالی در `ps` (وری، غویی، ...، کب) نام‌های جایگزین همان ماه‌ها هستند و با نام‌های پارسی `fa` اشتراکی ندارند. داده از locale خود CLDR برای `ps` می‌آید، از طریق ICU، نه از حافظه. CLDR شکل کوتاه پشتو ندارد، پس سراسر `short` همان `long` را دوباره به کار می‌برد. ## افزودن یک زبان یک `LocalePack` داده ساده در برابر یک رابط صادرشده است. افزودن زبان کد دیگر این بسته را عوض نمی‌کند: `format()` هر بسته‌ای را که بدهید می‌خواند. گام‌ها، با `ps` به‌عنوان مثال کارشده: 1. **بسته را بنویسید.** `fa.ts` (RTL) یا `en.ts` (LTR) را در `packages/i18n/src/` کپی کنید و فیلدها را پر کنید: `code`، `direction`، ۱۰ نویسه `digits`، `defaultNumerals`، `weekdaySeparator`، نام ماه برای *هر دو* سامانه تقویم، نام روز هفته (شاخص ۰ یکشنبه است)، دو جایگاه‌نمای انتخابگر، رشته‌های ظاهر `ui` (یک کلید برای هر معنای کنترل، از جمله `closedDay` برای نوک راهنمای تعطیل مسدود)، و عبارت‌های `relative` (`today`، شکل‌های گذشته/آینده `one`/`other` با `{n}`). نام‌ها را از داده واقعی قابل تأیید بگیرید. CLDR از طریق `Intl` در Node خوب کار می‌کند: `new Intl.DateTimeFormat('ps-AF-u-ca-persian', { month: 'long' })` نام ماه جلالی را می‌دهد، `Intl.NumberFormat` رقم‌ها را می‌دهد، و `Intl.RelativeTimeFormat` عبارت‌های نسبی را می‌دهد. 2. **آن را ثبت کنید.** بسته را از `packages/i18n/src/index.ts` صادر کنید، و کد آن را به `LocaleCode` و جدول بسته در `packages/i18n/src/locale-packs.ts` اضافه کنید. همان یک جدول چیزی است که بایندینگ‌های React، Vue و Web Components دوباره صادر می‌کنند، پس prop با نام `locale` کد تازه را بدون تغییر API می‌پذیرد. 3. **آزمون اضافه کنید** که پوشش موجود `fa` در `format.test.ts` و `numerals.test.ts` را آینه کند: یک رشته قالب‌شده برای هر سبک، پیشوند روز هفته، و بازنویسی صریح `numerals: 'latin'`. 4. **اختیاری: عبارت‌های NLP.** یک فهرست واژه در `packages/nlp/src/word-list.ts` خواندن زبان طبیعی برای آن زبان را اضافه می‌کند. این از بسته نمایش جدا است و فقط وقتی مجموعه عبارت خوب شناخته شود ارسال می‌شود. `Intl.RelativeTimeFormat` منبع قابل تأیید برای اصطلاحات نسبی است. --- --- url: https://jalali-js.yanovian.com/fa/guide/nlp.md description: عبارت‌های تاریخ انگلیسی، فارسی و پشتو را به تاریخ تقویم تبدیل کنید. --- # پردازش زبان طبیعی :::tabs key:pm variant:code \== npm ```sh npm install @jalali-js/nlp ``` \== pnpm ```sh pnpm add @jalali-js/nlp ``` \== yarn ```sh yarn add @jalali-js/nlp ``` ::: `parse()` یک عبارت کوتاه زبان طبیعی را می‌خواند و یک `CalendarDate` برمی‌گرداند، یا وقتی عبارت را نشناسد `null`. سه زبان: `en`، `fa` و `ps` (پشتو). ورودی انگلیسی نام ماه‌های جلالی با حرف لاتین را می‌پذیرد (`Mehr`، `Aban`، `Azar`). ورودی فارسی از خط پارسی استفاده می‌کند. این بسته برای عبارت‌های آزاد است. برای ورودی با شکل دقیق و شناخته‌شده مثل `1403/05/15`، به‌جای آن [`parseTemplate()`](/fa/guide/i18n#parsetemplate) از `@jalali-js/i18n` را به کار ببرید. ```ts import { parse } from '@jalali-js/nlp'; parse('today', 'en'); // امروز، در سامانه jalali (پیش‌فرض) parse('tomorrow', 'en'); parse('yesterday', 'en'); parse('next week', 'en'); parse('next Farvardin', 'en'); // نزدیک‌ترین رخداد آینده آن ماه parse('امروز', 'fa'); // 'today' parse('فردا', 'fa'); // 'tomorrow' parse('هفته آینده', 'fa'); // 'next week' parse('فروردین آینده', 'fa'); // 'next Farvardin' parse('نن', 'ps'); // 'today'، به پشتو parse('راتلونکې اونۍ', 'ps'); // 'next week' parse('راتلونکی وری', 'ps'); // 'next Wray' (نام افغانی ماه ۱ جلالی) parse('banana', 'en'); // null: عبارت شناخته‌شده نیست ``` `{ system: 'gregorian' }` را بدهید تا نتیجه در سامانه میلادی باشد، نه پیش‌فرض `'jalali'`: ```ts parse('today', 'en', { system: 'gregorian' }); ``` «ماه آینده» یعنی رخداد پیش رو، نه ماهی که هم‌اکنون جاری است: اگر ماه نام‌برده امسال شروع شده باشد، نتیجه سال بعد است. همان قرارداد «دوشنبه آینده» برای انتخاب روز داخل یک دوره وقتی روزی داده نشده. روز روی ۱ ثابت است. `getWordList(locale)` جدول عبارت زیرین (`WordList`) را که `parse()` با آن تطبیق می‌دهد در دسترس می‌گذارد، برای مصرف‌کننده‌ای که می‌خواهد تطبیق خودش را بسازد و مستقیم `parse()` را به کار نبرد. نوع کامل: [مرجع API](/api/@jalali-js/nlp/). --- --- url: https://jalali-js.yanovian.com/fa/guide/browser-support.md description: مرورگرها و نسخه‌های Node که مجموعه CI امروز بررسی می‌کند. --- # پشتیبانی مرورگر این صفحه می‌گوید CI چه چیزی را بررسی می‌کند. این یک وعده برای هر مرورگر یا هر نسخه Node نیست. ## ماتریس Node `.github/workflows/ci.yml` یک کار سبک `node-matrix` را روی هر LTS پشتیبانی‌شده اجرا می‌کند، به‌صورت موازی با دروازه کامل Node 24: | Node | نقش در CI | | ---- | ----------------------------------------------------- | | 22 | LTS نگهداری. Typecheck، آزمون واحد، ساخت بسته‌ها | | 24 | LTS فعال. دروازه کامل CI، به‌همراه همان بررسی‌های سبک | نسخه‌های اصلی منقضی‌شده Node (۲۰ و قدیمی‌تر) خارج از محدوده هستند. ## ماتریس e2e بصری `.github/workflows/e2e.yml` یک‌بار Playwright را برای هر مرورگر، به‌صورت موازی اجرا می‌کند: | مرورگر | پروژه Playwright | نمای دستگاه | | -------- | ---------------- | -------------- | | Chromium | `chromium` | Chrome رومیزی | | Firefox | `firefox` | Firefox رومیزی | | WebKit | `webkit` | Safari رومیزی | `playwright.config.ts` نمای رومیزی `1280×900` را تنظیم می‌کند. امروز پروژه دستگاه موبایل در آن پیکربندی نیست. ## این چه چیزی را پوشش می‌دهد * نسخه‌های زنده React، Vue و Vanilla: بخش‌های انتخابگر بسته و شبکه‌های تقویم باز. * برنامه‌های نسخه زنده Next.js و Nuxt در همان فهرست webServer در Playwright. * مقایسه پایه تصویر با تحمل کوچک ضد هموارسازی (`maxDiffPixelRatio: 0.02`). ## این چه چیزی را پوشش نمی‌دهد * پروژه‌های اختصاصی گوشی یا تبلت. * هر پشته فونت سیستم‌عامل میزبان. پایه‌ها روی `ubuntu-latest` اجرا می‌شوند. * هر bundler مصرف‌کننده. آزمون واحد و ماتریس typecheck بسته‌ها را پوشش می‌دهند، نه هر پشته برنامه. ## راهنمای عملی برای مرورگرهای evergreen مدرن بسازید. سه پروژه Playwright بالا را مجموعه تأییدشده بدانید. اگر بررسی طرح موبایل خاصی لازم دارید، اول یک پروژه Playwright و یک بخش نسخه زنده اضافه کنید، سپس این صفحه را به‌روز کنید. --- --- url: https://jalali-js.yanovian.com/fa/guide/theming.md description: قالب‌بندی بدون ظاهر، قالب‌های CSS، انتخابگر بازه، و گزینه‌های تقویم درون‌خطی. --- # پیکربندی و قالب ظاهری ## ماتریس پیکربندی بصری هر انتخابگر این محورهای مستقل را ترکیب می‌کند؛ هر کدام یک prop ساده یا یک stylesheet واردشده است، نه یک fork یا مؤلفه جدا: | محور | مقادیر | تنظیم از راه | | ------------------ | --------------------------------------------- | ---------------------------------------- | | سامانه تقویم | `jalali`، `gregorian` | prop با نام `system` | | زبان | `en`، `fa`، `ps` (رقم، نام ماه/روز هفته، جهت) | prop با نام `locale` | | دقت | تاریخ، تاریخ+زمان، تاریخ+زمان+منطقه زمانی | نوعی که وارد می‌کنید | | قالب نمایش | بلند/کوتاه، با/بدون روز هفته، رقم پارسی/لاتین | prop با نام `displayFormat` | | قالب مقدار (ذخیره) | ISO میلادی، شیء جلالی، و دیگرها | prop با نام `valueFormat` | | گونه UI انتخابگر | پاپ‌آپ شبکه (پیش‌فرض)، فیلدهای dropdown | prop با نام `variant` (فقط `DatePicker`) | | قالب ظاهری | پیش‌فرض، `dark`، `compact`، یا هر ترکیب | stylesheetهایی که وارد می‌کنید | ## بدون ظاهر یا با ظاهر `Calendar` (React و Vue) پریمیتیو بدون ظاهر است: نشانه‌گذاری ساده با ویژگی‌های `data-jalali-*` و بدون CSS اجباری، تا بتوانید ظاهر را کامل عوض کنید. `DatePicker` همان پریمیتیو با popover و stylesheet پیش‌فرض دور آن است. برای ظاهر قابل استفاده بدون کار قالب‌بندی، `@jalali-js/react/date-picker.css` (یا معادل Vue) را وارد کنید، یا وارد نکنید و ویژگی‌های data را خودتان قالب دهید؛ هیچ چیز در مؤلفه‌ها برای کار کردن به stylesheet وابسته نیست. ## قرارداد قالب ظاهری `date-picker.css` هر قاعده را از طریق ویژگی‌های سفارشی `--jalali-*` بیان می‌کند، نه مقدار لفظی. یک قالب ظاهری stylesheetی است که زیرمجموعه‌ای از این‌ها را روی همان گزینشگرها بازنویسی می‌کند (`[data-jalali-datepicker-root]`، `[data-jalali-datepicker-dropdown]`، `[data-jalali-timepicker-root]`، `[data-jalali-timerangepicker-root]`، `[data-jalali-calendar-root]`)؛ هرگز یک قاعده را از نو تعریف نمی‌کند. | متغیر | کنترل می‌کند | | ------------------------------- | -------------------------------------------------- | | `--jalali-font` | خانواده فونت | | `--jalali-font-size` | اندازه فونت پایه | | `--jalali-line-height` | ارتفاع خط پایه | | `--jalali-bg` | رنگ پس‌زمینه (ورودی، popover) | | `--jalali-fg` | رنگ متن | | `--jalali-muted-fg` | رنگ متن ثانویه (سرستون روز هفته، روزهای بیرون ماه) | | `--jalali-border` | رنگ حاشیه | | `--jalali-radius` | شعاع گوشه (ورودی، popover، سلول ماه/سال) | | `--jalali-day-radius` | شعاع گوشه سلول روز و کنترل‌های ناوبری | | `--jalali-primary` | رنگ تأکید: حلقه امروز، پر شدن انتخاب/انتهای بازه | | `--jalali-primary-fg` | رنگ متن روی `--jalali-primary` | | `--jalali-shadow` | سایه popover | | `--jalali-gap` | فاصله بین سلول‌های شبکه | | `--jalali-header-gap` | فاصله و حاشیه در سربرگ تقویم | | `--jalali-control-size` | عرض و ارتفاع کنترل‌های ناوبری | | `--jalali-input-padding` | فاصله داخلی ورودی متن و فیلدها | | `--jalali-popover-padding` | فاصله داخلی popover و تقویم رویداد | | `--jalali-cell-padding` | فاصله داخلی سلول‌های انتخابگر ماه و سال | | `--jalali-day-min-size` | حداقل عرض/ارتفاع سلول روز | | `--jalali-weekday-size` | اندازه فونت سرستون روز هفته | | `--jalali-event-bg` | پس‌زمینه تراشه رویداد | | `--jalali-event-fg` | متن تراشه رویداد | | `--jalali-holiday-fg` | متن روز تعطیل | | `--jalali-hover-bg` | پر شدن hover برای روزها و ناوبری | | `--jalali-range-bg` | پر شدن روز داخل بازه برای `RangePicker` | | `--jalali-focus-ring` | رنگ outline برای `:focus-visible` | | `--jalali-timeline-marker-size` | قطر نشانگر timeline | | `--jalali-timeline-accent` | تأکید کارت timeline | | `--jalali-timeline-road-track` | عرض جاده چیدمان roadmap | | `--jalali-timeline-road-color` | خط آسفالت roadmap | | `--jalali-timeline-road-dash` | خط‌چین مرکزی roadmap | | `--jalali-timeline-road-edge` | خط لبه roadmap | متن نوک راهنمای تعطیل از `[data-jalali-calendar-tip]` زیر شبکه ماه استفاده می‌کند. تعطیلی که مسدود هم باشد `--jalali-holiday-fg` و پر شدن نرم تعطیل را نگه می‌دارد. توکن‌های پیش‌فرض و قالب `dark` برای کنتراست متن WCAG 2.2 AA و حدود ۳:۱ برای حاشیه‌ها هدف می‌گیرند. stylesheet همچنین به `prefers-contrast: more` و `forced-colors: active` پاسخ می‌دهد. سلول‌های روز همان شعاع گوشه نرم پوسته تقویم را دارند. چگالی پیش‌فرض روی گوشی و لپ‌تاپ از قبل فشرده است. فقط وقتی مقیاس داشبورد متراکم‌تر لازم دارید `themes/compact.css` را وارد کنید. چون ویژگی‌های سفارشی CSS به ارث می‌رسند، وقتی stylesheet یک قالب وارد شود روی هر انتخابگر صفحه اعمال می‌شود: قالب ظاهری انتخاب کل برنامه است، نه یک prop برای هر نمونه. برای یک بخش قالب‌دار، بازنویسی خود را زیر گزینشگر والد محدود کنید، با همان الگو (متغیرها را بازنویسی کنید، با قواعد نجنگید). ## قالب‌های اضافه `@jalali-js/ui-react` و `@jalali-js/ui-vue` دو قالب آماده می‌فرستند؛ هر کدام مجموعه جدا از متغیرها را بازنویسی می‌کند تا با وارد کردن هر دو ترکیب شوند: ```ts import '@jalali-js/react/date-picker.css'; import '@jalali-js/ui-react/themes/dark.css'; // رنگ‌ها import '@jalali-js/ui-react/themes/compact.css'; // فاصله و اندازه ``` ## انتخابگر بازه، تقویم رویداد، و تقویم درون‌خطی `@jalali-js/ui-react` (و `@jalali-js/ui-vue`) مؤلفه‌های بیشتری روی همان پریمیتیوهای بدون ظاهر اضافه می‌کنند: * **`RangePicker`**: انتخابگر بازه تاریخ شروع/پایان. انتخاب دوکلیکی (کلیک اول شروع را می‌گذارد، کلیک دوم پایان را می‌گذارد و popover را می‌بندد)؛ کلیک قبل از شروع جاری بازه را از نقطه تازه شروع می‌کند، به‌جای خطا. پس از انتخاب شروع، hover بازه‌ای را که انتخاب کامل می‌سازد پیش‌نمایش می‌کند. * **`EventCalendar`**: نماهای ماه، هفته، روز و timeline برای رویدادهای متعلق به مصرف‌کننده، شامل مقدارهای `layout` با نام‌های `single`، `alternating` و `roadmap`. ببینید [تقویم رویداد](/fa/guide/event-calendar). * **`InlineCalendar`**: `Calendar` با نامی قابل‌کشف‌تر دوباره صادر شده، برای شبکه همیشه دیده‌شده بدون popover دور آن. برای فهرست کامل propها راهنماهای [React](/fa/guide/react) و [Vue](/fa/guide/vue) را ببینید، و برای نوع‌های تولیدشده `@jalali-js/ui-react` به [مرجع API](/api/@jalali-js/ui-react/) مراجعه کنید. --- --- url: https://jalali-js.yanovian.com/fa/guide/holidays.md description: تعطیلات رسمی ایران، بسته‌های منطقه، و نشانه‌های انتخابگر. --- # تعطیلات `@jalali-js/holidays` تعطیلات رسمی ایران (`IR`) را به‌صورت آفلاین می‌فرستد. `AF` و `TJ` رزرو شده‌اند و تا زمان ارسال آن بسته‌ها خطا می‌دهند. تاریخ‌ها فیلدهای جلالی `{ year, month, day }` دارند. ## منطقه‌ها ```ts import { isHoliday, SHIPPED_HOLIDAY_REGIONS } from '@jalali-js/holidays'; isHoliday({ year: 1403, month: 1, day: 1 }); // ایران (پیش‌فرض) isHoliday({ year: 1403, month: 1, day: 1 }, { region: 'IR' }); SHIPPED_HOLIDAY_REGIONS; // ['IR'] ``` چیدمان بسته ایران: ``` regions/ir/ ids.ts fixed.ts lunar-table.ts holiday.ts names/{en,fa,ps}.ts index.ts ``` نام‌ها یک فایل برای هر زبان هستند، مثل `@jalali-js/i18n`. زمان اجرا همچنان `names: { en, fa, ps }` برمی‌گرداند. ## ثابت و قمری ایران دو تقویم را در یک بسته ترکیب می‌کند: * `kind: 'fixed'`: روزهای شمسی جلالی (نوروز و مانند آن) در `fixed.ts` * `kind: 'lunar'`: روزهای اسلامی که هر سال جابه‌جا می‌شوند در `data/ir/lunar/` پوشش قمری `HOLIDAY_YEAR_RANGE` است (امروز ۱۴۰۲ تا ۱۴۲۶). بیرون از آن بازه، روزهای ثابت همچنان حل می‌شوند. ## API ```ts import { isHoliday, holidaysOn, holidaysInMonth, holidayName, holidayDayTip, holidayDayChrome, HOLIDAY_YEAR_RANGE, } from '@jalali-js/holidays'; isHoliday({ year: 1403, month: 1, day: 1 }); holidaysOn({ year: 1403, month: 1, day: 13 }); holidayName('ashura', 'fa'); holidaysInMonth(1403, 1); HOLIDAY_YEAR_RANGE; // { min: 1402, max: 1426 } ``` ## انتخابگرها `showHolidays` روزها را با `data-holiday` علامت می‌زند. `blockHolidays` انتخاب را هم مسدود می‌کند. منطقه پیش‌فرض ایران است (`holidayRegion` / `holiday-region`). با `showHolidays`، hover یا focus روی روز تعطیل یک نوک راهنما زیر شبکه نشان می‌دهد (`data-jalali-calendar-tip`). چند تعطیل در یک روز با `·` به هم می‌پیوندند. وقتی روز مسدود هم باشد، نوک راهنما برچسب `LocalePack.ui.closedDay` زبان را اضافه می‌کند (مثل `Closed` / `بسته`). نام دسترس‌پذیر دکمه روز متن نوک راهنما را هم دارد. روزهای تعطیل مسدود از `data-disabled` و `aria-disabled` به‌جای ویژگی بومی `disabled` استفاده می‌کنند، تا hover و focus برای نوک راهنما همچنان کار کنند. ```tsx ``` ```vue ``` ```html ``` ## نوک راهنمای روز (بدون ظاهر) برای شبکه سفارشی، نوک راهنما و برچسب aria را با همان کمک‌تابع‌هایی بسازید که انتخابگرها به کار می‌برند: ```ts import { holidayDayTip, holidayDayChrome } from '@jalali-js/holidays'; holidayDayTip({ year: 1403, month: 1, day: 1 }, { locale: 'en' }); // 'Nowruz' holidayDayTip( { year: 1403, month: 1, day: 1 }, { locale: 'en', closed: true, closedLabel: 'Closed' }, ); // 'Nowruz · Closed' holidayDayChrome('15 Mordad 1403', cell, { locale: 'en', closedLabel: 'Closed', }); // { tip?, ariaLabel, blocked? } ``` ## به‌روزرسانی داده قمری ```sh make update-holidays YEARS=next make update-holidays YEARS=1426 make update-holidays ``` `YEARS=next` سال بعد از بالاترین سال JSON را از emrooz.app می‌گیرد. بدون سال یعنی فقط از JSON روی دیسک بازسازی کند. CI سالانه وقتی فایل‌ها عوض شوند یک PR باز می‌کند. --- --- url: https://jalali-js.yanovian.com/fa/guide/event-calendar.md description: تقویم‌های رویداد ماه، هفته، روز و timeline با رویدادهای متعلق به مصرف‌کننده. --- # تقویم رویداد رویدادهای خودتان را روی تقویم نشان دهید. کتابخانه رویدادها را می‌چیند. ذخیره و ویرایش مال شماست. ## محدوده * `view` برابر `'month'` (پیش‌فرض)، `'week'`، `'day'`، یا `'timeline'` است. * در `@jalali-js/ui-react`، `@jalali-js/ui-vue` و `@jalali-js/ui-web` ارسال می‌شود. * قواعد تکرار داخل کتابخانه باز نمی‌شوند. آن‌ها را باز کنید، سپس ردیف‌های تخت `CalendarEvent` را بدهید. ## مدل رویداد `CalendarEvent` در `jalali-js` (هسته) زندگی می‌کند: | فیلد | معنا | | ----------------------- | -------------------------------------------------- | | `id` | شناسه پایدار برای کلیک و کلیدهای چیدمان. | | `title` | برچسب روی تراشه رویداد یا کارت timeline. | | `start` / `end` | فیلدهای تاریخ شامل در سامانه تقویم نمایش‌داده‌شده. | | `allDay` | اختیاری. وقتی زمان گذاشته نشود پیش‌فرض true است. | | `startTime` / `endTime` | زمان روز اختیاری برای رویدادهای زمان‌دار. | | `description` | متن بدنه اختیاری برای کارت‌های timeline. | | `color` | رنگ CSS اختیاری برای تأکید timeline. | | `icon` | نشانگر کوتاه اختیاری (ایموجی یا متن). | کمک‌تابع‌های چیدمان (`layoutMonthEvents`، `layoutWeekEvents`، `layoutDayTimedEvents`، `eventsForTimeline` و مرتبط) تابع خالص هستند، کنار `buildCalendarGrid()`. ## نماها * **ماه**: تراشه‌های سبک تمام‌روز روی شبکه ماه. * **هفته** / **روز**: یک ردیف تمام‌روز به‌همراه شبکه زمان‌دار ۲۴ ساعته. رویدادهای زمان‌دار از `startTime` / `endTime` استفاده می‌کنند. هم‌پوشانی‌ها خطوط کنارهم می‌گیرند. * **Timeline**: فهرست زمانی با ریل، نشانگر، و کارت تأکید. تاریخ و زمان از `@jalali-js/i18n` استفاده می‌کنند (`format`، `formatNumber`، رقم‌های زبان، و `displayFormat.numerals`). چیدمان کارت را با `timeline.layout` انتخاب کنید (پایین را ببینید). لنگر را با `initialDisplayedMonth` (ماه) یا `initialDate` (هفته و روز) بگذارید. Timeline از ناوبری ماه قبل/بعد استفاده نمی‌کند. ## گزینه‌های Timeline وقتی `view` برابر `'timeline'` است، یک شیء `timeline` بدهید: | فیلد | نوع | پیش‌فرض | معنا | | ------------- | ---------------------------------------- | ------------ | ------------------------------------------------------------------------------------- | | `direction` | `'vertical' \| 'horizontal'` | `'vertical'` | جهت ریل | | `markerShape` | `'circular' \| 'square'` | `'circular'` | شکل نشانگر | | `showIcons` | `boolean` | `true` | نشان دادن `event.icon` در نشانگر | | `layout` | `'single' \| 'alternating' \| 'roadmap'` | `'single'` | جای کارت کنار ریل | | `alternating` | `boolean` | `false` | نام مستعار قدیمی: وقتی `layout` نباشد، `true` به `layout: 'alternating'` نگاشت می‌شود | | `markerSize` | `number` | پیش‌فرض CSS | قطر نشانگر به پیکسل CSS | مقدارهای `layout`: * **`single`**: همه کارت‌ها یک طرف ریل مستقیم (پیش‌فرض). * **`alternating`**: کارت‌ها دو طرف ریل مستقیم مرکزی. * **`roadmap`**: جاده مارپیچ خط‌چین با نشانگر روی قله منحنی‌ها. `direction` افقی از `roadmap` به `alternating` برمی‌گردد. رقم بومی از بسته زبان (`fa` / `ps`) یا از `displayFormat.numerals` (`'native'` یا `'latin'`) می‌آید. روی نماهای باریک، چیدمان‌های دوطرفه به ریل یک‌طرفه جمع می‌شوند. ## React ```tsx import { EventCalendar } from '@jalali-js/ui-react'; import type { CalendarEvent } from 'jalali-js'; const events: CalendarEvent[] = [ { id: 'workshop', title: 'Workshop', start: { year: 1403, month: 5, day: 10 }, end: { year: 1403, month: 5, day: 12 }, }, { id: 'meeting', title: 'Meeting', start: { year: 1403, month: 5, day: 15 }, end: { year: 1403, month: 5, day: 15 }, allDay: false, startTime: { hour: 14, minute: 0 }, endTime: { hour: 15, minute: 0 }, }, ]; console.log(event.id)} onDayClick={(date) => console.log(date)} />; ``` مثال Timeline: ```tsx ``` ## Vue ```vue ``` ## Web Components ```ts import '@jalali-js/ui-web'; const el = document.querySelector('jalali-event-calendar')!; el.view = 'week'; el.initialDate = { year: 1403, month: 5, day: 15 }; el.events = [ { id: 'workshop', title: 'Workshop', start: { year: 1403, month: 5, day: 10 }, end: { year: 1403, month: 5, day: 12 }, }, ]; el.addEventListener('event-click', (event) => { console.log(event.detail.event); }); ``` ```html ``` برای timeline، در صورت نیاز `el.view = 'timeline'`، `el.timeline = { ... }` و `el.displayFormat = { numerals: 'native' }` را بگذارید. ## Propها (React) | Prop | نوع | پیش‌فرض | معنا | | ----------------------- | ------------------------------------------ | ---------- | --------------------- | | `system` | `CalendarSystem` | `'jalali'` | تقویم نمایش | | `locale` | `LocaleCode` | `'en'` | زبان UI | | `view` | `'month' \| 'week' \| 'day' \| 'timeline'` | `'month'` | نمای دیده‌شده | | `events` | `CalendarEvent[]` | `[]` | رویدادها برای چیدمان | | `initialDisplayedMonth` | `{ year, month }` | - | لنگر ماه (روز ۱) | | `initialDate` | `{ year, month, day }` | امروز | لنگر هفته یا روز | | `displayFormat` | `FormatOptions` | - | قالب روز و مهر زمانی | | `timeline` | `TimelineOptions` | - | چیدمان timeline | | `onEventClick` | `(event) => void` | - | کلیک روی تراشه رویداد | | `onDayClick` | `(date) => void` | - | کلیک روی سلول روز | | `className` | `string` | - | کلاس ریشه | Vue: همان propها، با emitهای `eventClick` و `dayClick`. Web: ویژگی‌های `system`، `locale`، `view`؛ propهای `events`، `initialDisplayedMonth`، `initialDate`، `displayFormat`، `timeline`؛ رویدادهای `event-click`، `day-click`. ## قالب ظاهری همان `date-picker.css` دیگر انتخابگرها را وارد کنید. تراشه‌های رویداد از `data-jalali-eventcalendar-*` و متغیرهای `--jalali-event-bg` / `--jalali-event-fg` استفاده می‌کنند. Timeline از `data-jalali-timeline-*`، `data-layout`، و توکن‌هایی مثل `--jalali-timeline-marker-size`، `--jalali-timeline-accent`، و مجموعه `--jalali-timeline-road-*` برای `layout: 'roadmap'` استفاده می‌کند. وقتی `timeline.markerSize` حذف شود، اندازه نشانگر پیش‌فرض stylesheet اعمال می‌شود. فهرست کامل متغیرها را در [پیکربندی و قالب ظاهری](/fa/guide/theming) ببینید. --- --- url: https://jalali-js.yanovian.com/fa/guide/recipes.md description: پاسخ‌های کوتاه آماده‌کپی برای کارهای رایج DatePicker. --- # دستورالعمل‌ها یک مثال کوتاه برای هر کار. مثال‌ها از React استفاده می‌کنند. نکته‌های Vue و Web وقتی بایندینگ فرق دارد زیر هر دستورالعمل آمده است. همچنین ببینید [مثال‌ها](/fa/guide/examples). ## پیش‌فرض امروز مقدار پیش‌فرض همان امروز است. چیزی ندهید، یا امروز را صریح بدهید. ```tsx import '@jalali-js/react/date-picker.css'; import { DatePicker } from '@jalali-js/react'; console.log(value)} />; ``` شروع خالی: `defaultDate={null}` (Vue با `:default-date="null"`، Web با `.defaultDate = null`). ## کران حداقل و حداکثر ```tsx import { DatePicker } from '@jalali-js/react'; ; ``` ## مسدود کردن آخر هفته روزهای هفته جلالی یکشنبه = ۰ … شنبه = ۶. آخر هفته پنجشنبه/جمعه: ```tsx ``` ## Epoch برای یک API ```tsx { // value یک عدد Unix epoch است (میلی‌ثانیه) fetch('/api/appointments', { method: 'POST', body: JSON.stringify({ at: value }) }); }} /> ``` ## ارسال فرم ```tsx function BookingForm() { const [stored, setStored] = useState(null); return (
{ event.preventDefault(); if (stored) submitBooking(stored); }} > setStored(value)} /> ); } ``` Vue: `v-model` را به مقدار ذخیره ببندید و همان ref را ارسال کنید. Web: از رویداد `change` مقدار `event.detail.value` را بخوانید، یا `.value` عنصر را بخوانید. ## تنظیم، خواندن و پاک کردن برنامه‌ای ### React `DatePicker` برای انتخاب بدون کنترل است. با `defaultDate` مقدار اولیه بدهید. برای خواندن وضعیت خودتان را از `onChange` نگه دارید. برای پاک کردن یا بازنشانی با `key` تازه remount کنید. ```tsx function ControlledShell() { const [seed, setSeed] = useState(null); const [stored, setStored] = useState(null); return ( <> setStored(value)} />
{JSON.stringify(stored)}
); } ``` `Calendar` / `InlineCalendar` کنترل‌شده‌اند: `value` و `onSelect` را بدهید. ### Vue `DatePicker` مقدار ذخیره را از طریق `v-model` می‌نویسد. با `defaultDate` مقدار اولیه بدهید. برای پاک کردن با `:key` remount کنید. `Calendar` از `:value` و `@select` استفاده می‌کند. ```vue ``` ### Web Components برای خواندن یا نوشتن انتخاب بدون ارسال رویداد، `.value` را تنظیم کنید. برای مقدار اولیه، قبل از connect مقدار `.defaultDate` را بگذارید. برای انتخاب کاربر به `change` گوش دهید. ```ts const el = document.querySelector('jalali-date-picker')!; el.defaultDate = null; // خالی تا کاربر انتخاب کند el.addEventListener('change', (event) => { console.log(event.detail.value); }); // بعداً el.value = null; // پاک کردن، بدون رویداد change console.log(el.value); ``` ## SSR (Next.js / Nuxt) CSS را در مرز کلاینت وارد کنید. برای propهایی که از سرور عبور می‌کنند، رشته‌های `valueFormat` را بر اشیاء `Date` ترجیح دهید. ```tsx 'use client'; import '@jalali-js/react/date-picker.css'; import { DatePicker } from '@jalali-js/react'; export function ClientPicker() { return ; } ``` برای `'zoned-datetime'` با `timeZone: 'auto'`، از `useResolvedTimeZone('auto')` استفاده کنید تا SSR و اولین رنگ کلاینت روی `'UTC'` بمانند. راهنماهای [React](/fa/guide/react) و [Vue](/fa/guide/vue) را ببینید. --- --- url: https://jalali-js.yanovian.com/fa/guide/getting-started.md description: >- هسته یا یک بایندینگ فریم‌ورک را نصب کنید، سپس تاریخ را تبدیل کنید یا یک انتخابگر بسازید. --- # شروع کار ## نصب :::tabs key:pm variant:code \== npm ```sh npm install jalali-js # React npm install @jalali-js/react # Vue npm install @jalali-js/vue # بدون فریم‌ورک: Web Components ساده npm install @jalali-js/web ``` \== pnpm ```sh pnpm add jalali-js # React pnpm add @jalali-js/react # Vue pnpm add @jalali-js/vue # بدون فریم‌ورک: Web Components ساده pnpm add @jalali-js/web ``` \== yarn ```sh yarn add jalali-js # React yarn add @jalali-js/react # Vue yarn add @jalali-js/vue # بدون فریم‌ورک: Web Components ساده yarn add @jalali-js/web ``` ::: `jalali-js` بسته هسته است: TypeScript خالص، بدون وابستگی به فریم‌ورک، و بدون وابستگی زمان اجرا. `@jalali-js/react`، `@jalali-js/vue` و `@jalali-js/web` همه به آن وابسته‌اند. `@jalali-js/web` به هیچ فریم‌ورکی نیاز ندارد: Web Components ساده است و از HTML/JS معمولی یا داخل هر فریم‌ورک مثل هر عنصر HTML دیگر کار می‌کند (ببینید [Vanilla / Web Components](/fa/guide/web-components)). `@jalali-js/i18n` (داده زبان و قالب‌بندی)، `@jalali-js/nlp` (پردازش زبان طبیعی تاریخ)، و `@jalali-js/holidays` (تعطیلات رسمی ایران) بسته‌های جدا هستند و فقط وقتی مستقیم لازم دارید نصب می‌شوند. هر بایندینگ خودش به `@jalali-js/i18n` وابسته است، و انتخابگرها می‌توانند تعطیلات ایران را با `showHolidays` علامت بزنند (ببینید [تعطیلات](/fa/guide/holidays)). ## تبدیل یک تاریخ ```ts import { createCalendar, toGregorian, fromGregorian } from 'jalali-js'; const jalali = createCalendar({ system: 'jalali' }); jalali.today(); // { year: 1403, month: 5, day: 15 } toGregorian({ year: 1403, month: 5, day: 15 }, 'jalali'); // { year: 2024, month: 8, day: 5 } fromGregorian({ year: 2024, month: 8, day: 5 }, 'jalali'); // { year: 1403, month: 5, day: 15 } ``` `system` برابر `'jalali'` یا `'gregorian'` است. تبدیل میلادی به میلادی تبدیل هویت است، عمداً: تا کد برنامه «سامانه تقویم» را یک تنظیم بداند، نه یک حالت خاص (ببینید [مفاهیم اصلی](/fa/guide/core-concepts)). ## ساخت انتخابگر (React) ```tsx import '@jalali-js/react/date-picker.css'; import { DatePicker } from '@jalali-js/react'; function BirthDateField() { return ( { // value به‌صورت پیش‌فرض یک رشته ISO میلادی است: '2024-08-05'. // برای دلیل و روش خروج از این رفتار، «مقدار نمایشی در برابر مقدار ذخیره‌سازی» را ببینید. }} /> ); } ``` ## ساخت انتخابگر (Vue) ```vue ``` ## ساخت انتخابگر (بدون فریم‌ورک) ```html ``` بعدی: [مفاهیم اصلی](/fa/guide/core-concepts) لایه‌های دقت و شکاف نمایش/ذخیره را پوشش می‌دهد که این مثال‌ها بر آن تکیه دارند. --- --- url: https://jalali-js.yanovian.com/fa/guide/selection-rules.md description: >- محدود کردن انتخاب، کران حداقل/حداکثر، تاریخ‌ها و روزهای هفته مسدود، در هر انتخابگر. --- # قواعد انتخاب هر انتخابگر یک شیء `rules` می‌گیرد (`SelectionRules` از `jalali-js`) که محدود می‌کند شخص چه چیزی را انتخاب کند. روزهای مسدود به‌صورت دکمه‌های غیرفعال با ویژگی `data-disabled` رندر می‌شوند: کلیک کاری نمی‌کند، و ترتیب Tab از آن‌ها می‌گذرد. همان قواعد روی `Calendar`، `DatePicker` و `RangePicker` در React، Vue و Web Components کار می‌کنند، چون همه قواعد را از طریق `buildCalendarGrid()` مشترک می‌خوانند. ```ts interface SelectionRules { minDate?: { year: number; month: number; day: number }; maxDate?: { year: number; month: number; day: number }; enabledDates?: { year: number; month: number; day: number }[]; disabledDates?: { year: number; month: number; day: number }[]; disabledWeekdays?: number[]; // 0 یکشنبه است، 6 شنبه } ``` تاریخ‌های قاعده فیلدهای ساده `{ year, month, day }` هستند و در سامانه تقویم خود انتخابگر خوانده می‌شوند. ترتیب اولویت، که `isDateSelectable(date, rules)` حل می‌کند: 1. وقتی `enabledDates` تنظیم شود، به‌تنهایی تصمیم می‌گیرد. این فهرست بر هر قاعده دیگر می‌برد. 2. `disabledDates` تاریخ فهرست‌شده را مسدود می‌کند. 3. `disabledWeekdays` روز هفته فهرست‌شده را مسدود می‌کند. 4. `minDate` و `maxDate` تاریخ‌های بیرون از کران را مسدود می‌کنند (کران‌ها شامل). ## کران حداقل/حداکثر یک فرم رزرو را به ۳۰ روز آینده محدود کنید: ```tsx import { DatePicker } from '@jalali-js/react'; import { addDays, createCalendar } from 'jalali-js'; const today = createCalendar({ system: 'jalali' }).today(); ; ``` ## مسدود کردن آخر هفته (پنجشنبه و جمعه) آخر هفته ایران پنجشنبه و جمعه است، شاخص‌های روز هفته ۴ و ۵: ```tsx ``` ## فهرست سفید تاریخ‌های باز وقتی فقط مجموعه شناخته‌شده‌ای از تاریخ‌ها معتبر است، آن‌ها را در `enabledDates` فهرست کنید. هر تاریخ دیگر مسدود است، و بقیه قواعد نادیده گرفته می‌شوند: ```tsx ``` ## Vue و Web Components مؤلفه‌های Vue همان prop با نام `rules` را می‌گیرند: ```vue ``` روی Web Components، `rules` یک property است (یک شیء)، نه یک attribute: ```js const picker = document.querySelector('jalali-date-picker'); picker.rules = { disabledWeekdays: [4, 5] }; ``` ## انتخابگر بازه `RangePicker` همان `rules` را به کار می‌برد. بازه نامزدی که از روز مسدود عبور کند کامل نمی‌شود: کلیک دوم بازه تازه را از روز کلیک‌شده شروع می‌کند. آن انتخاب در React، Vue و Web از طریق `isRangeSelectable(start, end, rules)` مشترک است. ```tsx import { RangePicker } from '@jalali-js/ui-react'; ; ``` --- --- url: https://jalali-js.yanovian.com/fa/guide/examples.md description: قطعه‌های آماده‌کپی برای تبدیل، انتخابگر، بازه، NLP و قالب ظاهری. --- # مثال‌ها قطعه‌های کوتاه و مستقل برای کارهای رایج. هر کدام آماده‌کپی است: هر واردکردنی که لازم دارد را نشان می‌دهد. برای پاسخ‌های شکل‌وظیفه (کران، epoch، فرم، SSR)، ببینید [دستورالعمل‌ها](/fa/guide/recipes). برای مفاهیم، ببینید [شروع کار](/fa/guide/getting-started)، [مفاهیم اصلی](/fa/guide/core-concepts)، و [پیکربندی و قالب ظاهری](/fa/guide/theming). ## تبدیل بین تقویم‌ها ```ts import { toGregorian, fromGregorian } from 'jalali-js'; toGregorian({ year: 1403, month: 5, day: 15 }, 'jalali'); // { year: 2024, month: 8, day: 5 } fromGregorian({ year: 2024, month: 8, day: 5 }, 'jalali'); // { year: 1403, month: 5, day: 15 } ``` ## قالب‌بندی تاریخ برای نمایش ```ts import { format, fa } from '@jalali-js/i18n'; const date = { precision: 'date' as const, system: 'jalali' as const, year: 1403, month: 5, day: 15, }; format(date, fa); // '۱۵ مرداد ۱۴۰۳' format(date, fa, { weekday: true }); // 'دوشنبه، ۱۵ مرداد ۱۴۰۳' format(date, fa, { numerals: 'latin' }); // '15 مرداد 1403' ``` ## خواندن یک عبارت زبان طبیعی ```ts import { parse } from '@jalali-js/nlp'; parse('tomorrow', 'en'); parse('فردا', 'fa'); parse('نن', 'ps'); // پشتو برای 'today' parse('next Farvardin', 'en'); ``` ## React: فیلد تاریخی که میلادی ذخیره می‌کند و جلالی نشان می‌دهد ```tsx import '@jalali-js/react/date-picker.css'; import { DatePicker } from '@jalali-js/react'; function BirthDateField() { return ( { // value یک رشته ISO میلادی است، مثل '2024-08-05'. همین را ذخیره کنید. }} /> ); } ``` ## Vue: همان فیلد، با `v-model` ```vue ``` ## Vanilla / Web Components: همان فیلد، بدون فریم‌ورک ```html ``` ## React: فیلد بازه تاریخ ```tsx import '@jalali-js/react/date-picker.css'; import { RangePicker } from '@jalali-js/ui-react'; console.log(value)} />; ``` ## React: تقویم همیشه دیده‌شده، بدون popover ```tsx import '@jalali-js/react/date-picker.css'; import { InlineCalendar } from '@jalali-js/ui-react'; import { useState } from 'react'; import type { CalendarDate } from 'jalali-js'; function EventDatePicker() { const [selected, setSelected] = useState(null); return ; } ``` ## React: تقویم رویداد (ماه، هفته، روز، یا timeline) ```tsx import '@jalali-js/react/date-picker.css'; import { EventCalendar } from '@jalali-js/ui-react'; import type { CalendarEvent } from 'jalali-js'; const events: CalendarEvent[] = [ { id: 'workshop', title: 'Workshop', start: { year: 1403, month: 5, day: 10 }, end: { year: 1403, month: 5, day: 12 }, }, { id: 'meeting', title: 'Meeting', start: { year: 1403, month: 5, day: 15 }, end: { year: 1403, month: 5, day: 15 }, allDay: false, startTime: { hour: 14, minute: 0 }, endTime: { hour: 15, minute: 0 }, }, ]; ; ``` Timeline با چیدمان roadmap: ```tsx ``` ## تعطیلات با نوک راهنمای روز ```tsx ``` برای خواندن نوک راهنما زیر شبکه، روی روز تعطیل hover یا focus کنید. ببینید [تعطیلات](/fa/guide/holidays#انتخابگرها). ## یک قالب ظاهری سفارشی، بدون فایل قالب ویژگی‌های سفارشی `--jalali-*` به ارث می‌رسند، پس بازنویسی خام روی عنصر پوششی می‌تواند به مقداری که مستقیم روی ریشه خود انتخابگر نشسته ببازد، برای مثال اگر `dark.css` در همان صفحه وارد شده باشد (ببینید [پیکربندی و قالب ظاهری](/fa/guide/theming)). به‌جای آن بازنویسی را زیر یک کلاس والد محدود کنید، روی گزینشگری که خود عنصر ریشه را می‌گیرد: ```css /* my-theme.css */ .my-theme [data-jalali-datepicker-root] { --jalali-primary: #c026d3; --jalali-primary-fg: #ffffff; --jalali-bg: #fdf4ff; --jalali-fg: #581c87; --jalali-radius: 20px; } ``` ```tsx import '@jalali-js/react/date-picker.css'; import './my-theme.css'; import { DatePicker } from '@jalali-js/react';
; ``` --- --- url: https://jalali-js.yanovian.com/fa/guide/core-concepts.md description: سامانه تقویم، لایه‌های دقت، موتور تبدیل، و بسته‌های زبان. --- # مفاهیم اصلی ## سامانه تقویم یک تنظیم نمایش است `jalali-js` روی یک سامانه تقویم متمرکز است: جلالی (هجری شمسی). میلادی تنها سامانه دیگر است و یک ویژگی هم‌رده نیست: یک نیاز ساختاری است، سمت ذخیره قرارداد «نمایش جلالی، ذخیره میلادی» که هر مؤلفه به‌صورت پیش‌فرض از آن پیروی می‌کند (ببینید [مقدار نمایشی در برابر مقدار ذخیره‌سازی](/fa/guide/display-vs-storage)). `system: 'gregorian'` روی `createCalendar()` یا هر مؤلفه تبدیل هویت است: تا کد برنامه «کدام تقویم» را یک تنظیم بداند، نه اینکه همه‌جا میلادی را حالت خاص کند. ## لایه‌های دقت، نه فیلدهای اختیاری `jalali-js` همان سه لایه پیشنهاد TC39 `Temporal` را به کار می‌برد، روی هر سامانه تقویم فعالی: | نوع | فیلدها | آگاه از منطقه زمانی؟ | | ----------------------- | -------------------------------------------------- | -------------------- | | `CalendarDate` | `year`، `month`، `day` | خیر | | `CalendarDateTime` | به‌علاوه `hour`، `minute`، `second`، `millisecond` | خیر (ساعت دیواری) | | `ZonedCalendarDateTime` | به‌علاوه نام IANA `timeZone` | بله | هر لایه نوع TypeScript خودش را دارد، نه یک نوع با فیلدهای اختیاری. کدی که روی `CalendarDate` نوشته شده هرگز به‌اشتباه فیلد `hour` خوانده‌نشده را نمی‌خواند. لایه را با گزینه `precision` در `createCalendar()` انتخاب کنید؛ overloadهای TypeScript برای هر دقت، `today()` را با نوع برگشت درست می‌دهند: ```ts createCalendar({ system: 'jalali' }); // precision: 'date' (پیش‌فرض) createCalendar({ system: 'jalali', precision: 'datetime' }); createCalendar({ system: 'jalali', precision: 'zoned-datetime', timeZone: 'auto' }); createCalendar({ system: 'jalali', precision: 'zoned-datetime', timeZone: 'Asia/Tehran' }); ``` `timeZone: 'auto'` مقدار `Intl.DateTimeFormat().resolvedOptions().timeZone` را می‌خواند. زیر SSR (Next.js، Nuxt)، در رندر سرور به `'UTC'` می‌رسد چون هنوز `window` نیست؛ هوک یا composable با نام `useResolvedTimeZone()` پس از mount منطقه زمانی واقعی مرورگر را دوباره حل می‌کند، بدون mismatch هیدراسیون. راهنماهای [React](/fa/guide/react) و [Vue](/fa/guide/vue) را ببینید. ## موتور تبدیل تبدیل جلالی به میلادی از Julian Day Number می‌گذرد (شمارش پیوسته روز بدون تقویم خودش) به‌عنوان تنها مسیر بین دو سامانه، پشت یک رابط کوچک `CalendarEngine`. موتور پیش‌فرض از قاعده حسابی سال کبیسه در چرخه ۳۳ ساله اعتبارسنجی‌شده استفاده می‌کند (Kazimierz M. Borkowski). برای بازه‌ای که برنامه‌های واقعی نیاز دارند با تقویم نجومی هم‌خوان است، در زمان ثابت اجرا می‌شود، و وابستگی زمان اجرا ندارد. در برابر تقویم پارسی ICU در Node و یک جدول کبیسه ۱۲۱ ساله منتشرشده بررسی شده است. یک موتور نجومی اختیاری هم هست. نوروز را از اعتدال مارس در نصف‌النهار تهران (۵۲٫۵° شرقی) با طول خورشیدی کم‌دقت Jean Meeus پیدا می‌کند. وقتی کبیسه‌های مبتنی بر اعتدال خیلی بیرون از بازه هم‌خوانی حسابی لازم دارید از آن استفاده کنید. از پیش‌فرض کندتر است. ```ts createCalendar({ system: 'jalali', engine: 'astronomical' }); toGregorian({ year: 1403, month: 1, day: 1 }, 'jalali', { engine: 'astronomical' }); fromGregorian({ year: 2024, month: 3, day: 20 }, 'jalali', { engine: 'astronomical' }); ``` `engine` را حذف کنید، یا `'arithmetic'` بدهید، برای پیش‌فرض. ## ریاضی تاریخ و پرس‌وجو هسته کنار موتور تبدیل، کمک‌تابع‌های تاریخ می‌فرستد. هر کدام روی سامانه تقویم کار می‌کند، با صفر وابستگی زمان اجرا: ```ts import { addDays, addMonths, addYears, diffDates, startOf, endOf, isBefore, isAfter, isSameDay, isBetween, isToday, } from 'jalali-js'; addDays({ year: 1403, month: 12, day: 30 }, 1, 'jalali'); // 1404-01-01 addMonths({ year: 1403, month: 1, day: 31 }, 6, 'jalali'); // 1403-07-30 (روز محدود شده) addYears({ year: 1403, month: 12, day: 30 }, 1, 'jalali'); // 1404-12-29 (روز محدود شده) diffDates(a, b, 'month', 'jalali'); // ماه‌های کامل علامت‌دار از b تا a startOf({ year: 1403, month: 5, day: 15 }, 'week', 'jalali'); // 1403-05-13، شنبه startOf({ year: 2024, month: 8, day: 5 }, 'week', 'gregorian', 1); // شروع هفته: 1 = دوشنبه endOf({ year: 1403, month: 5, day: 15 }, 'month', 'jalali'); // 1403-05-31 isBefore(a, b); // compareDates(a, b) < 0 isBetween(date, start, end); // کران‌ها شامل isToday(date, 'jalali'); ``` سه قاعده مهم: * `addMonths()` و `addYears()` روز را به طول ماه هدف محدود می‌کنند. ۳۰ اسفند سال کبیسه به‌علاوه یک سال می‌شود ۲۹ اسفند. * `diffDates()` به‌سوی صفر قطع می‌کند: واحد فقط وقتی کامل گذشته باشد شمرده می‌شود. واحدها: `day`، `week`، `month`، `year`. * `startOf()` و `endOf()` روز شروع هفته را به‌عنوان پارامتر می‌گیرند، چون هفته جلالی از شنبه شروع می‌شود و هفته میلادی معمولاً از یکشنبه یا دوشنبه. پیش‌فرض قرارداد خود سامانه است (`WEEK_START_DAY`). ## قواعد انتخاب `SelectionRules` محدود می‌کند انتخابگر تاریخ چه چیزی را بپذیرد. `isDateSelectable(date, rules)` یک ترتیب اولویت را حل می‌کند: 1. وقتی `enabledDates` تنظیم شود، به‌تنهایی تصمیم می‌گیرد. 2. `disabledDates` تاریخ فهرست‌شده را مسدود می‌کند. 3. `disabledWeekdays` روز هفته فهرست‌شده را مسدود می‌کند (۰ یکشنبه، ۶ شنبه). 4. `minDate` و `maxDate` تاریخ‌های بیرون از کران را مسدود می‌کنند (کران‌ها شامل). تاریخ‌های قاعده فیلدهای ساده `{ year, month, day }` هستند و در سامانه تقویم خود تاریخ خوانده می‌شوند. هر انتخابگر prop با نام `rules` می‌گیرد و آن را از طریق `buildCalendarGrid()` می‌خواند. ببینید [قواعد انتخاب](/fa/guide/selection-rules). ## زمان روز `TimeOfDay` برابر `{ hour, minute }` است. `withTime(date, time)` یک `CalendarDateTime` می‌سازد. `TimePicker` انتخابگر ساعت و دقیقه را نشان می‌دهد. `DatePicker` با `precision: 'datetime'` یک پنل زمان زیر شبکه اضافه می‌کند. ببینید [انتخاب زمان](/fa/guide/time-selection). ## بسته‌های زبان `@jalali-js/i18n` مقادیر `en`، `fa` و `ps` (پشتو، با نام‌های زودیاکی افغانستان برای همان ماه‌های جلالی) را صادر می‌کند؛ هر کدام یک `LocalePack`: نام ماه (برای هر دو سامانه تقویم، پس `en` آوانویسی انگلیسی ماه‌های جلالی را دارد و `fa` آوانویسی پارسی ماه‌های میلادی را)، نام روز هفته، سبک رقم، و جهت متن. `format()` یک تاریخ به‌همراه بسته زبان می‌گیرد و آن را رندر می‌کند؛ prop با نام `locale` در بایندینگ‌های React، Vue و Web Components مشخص می‌کند مؤلفه کدام بسته را به کار ببرد. `format()` همچنین گزینه `template` می‌گیرد (`'YYYY/MM/DD'`، `'D MMMM YYYY'`) برای شکل خروجی دقیق، و `parseTemplate()` چنین شکلی را دوباره به `CalendarDate` می‌خواند. ببینید [قالب‌ها](/fa/guide/i18n#templates) در راهنمای i18n. --- --- url: https://jalali-js.yanovian.com/fa/guide/comparison.md description: برای کار تازه jalali-js را ترجیح دهید. مقایسه کنارهم با بسته‌های جلالی دیگر. --- # مقایسه با گزینه‌های دیگر مجموعه موجود ابزارهای تقویم جلالی و پارسی برای JavaScript بین بسته‌های کوچک زیاد تقسیم شده است. هر کدام یک یا دو نیاز را خوب پوشش می‌دهد و درباره بقیه ساکت است. هیچ‌کدام به‌تنهایی همه این‌ها را ندارد: هسته تبدیل نگهداری‌شده و TypeScript-first، مدل صریح دقت تاریخ/زمان/منطقه زمانی، بایندینگ برای بیش از یک فریم‌ورک، پشتیبانی داخلی انگلیسی و فارسی، و لایه مؤلفه بدون ظاهر و قالب‌پذیر با آزمون رگرسیون بصری در CI. 🟢 خوب · 🟡 ناقص · 🔴 غایب یا یک ضعف واقعی | کتابخانه | کاربرد اصلی | TS-native | طراحی چندتقویمی | مدل تاریخ/زمان/منطقه زمانی | انگلیسی و فارسی | بایندینگ فریم‌ورک | UI بدون ظاهر و قالب‌پذیر | | ---------------------------------------------------------------------------------------- | ---------------------------- | --------- | -------------------- | ----------------------------------------------------------------------------- | --------------- | --------------------------------------------- | ----------------------------------------------------- | | [`jalali-js`](https://www.npmjs.com/package/jalali-js) | هسته تبدیل + بایندینگ + UI | 🟢 بله | 🟢 بله (رابط افزونه) | 🟢 لایه‌های صریح: `CalendarDate`، `CalendarDateTime`، `ZonedCalendarDateTime` | 🟢 بله | 🟢 React، Vue، و Web Components بدون فریم‌ورک | 🟢 پریمیتیوهای بدون ظاهر، `DatePicker` با ظاهر روی آن | | [`jalaali-js`](https://www.npmjs.com/package/jalaali-js) | ریاضی جلالی به میلادی | 🟢 بله | 🔴 خیر، یک تقویم | 🔴 خیر، عدد ساده | 🔴 خیر | 🔴 خیر | 🔴 خیر | | [`moment-jalaali`](https://www.npmjs.com/package/moment-jalaali) | افزونه جلالی برای Moment | 🔴 خیر | 🔴 خیر | 🔴 از طریق Moment، که تیم خودش آن را legacy می‌نامد | 🟡 ناقص | 🔴 خیر | 🔴 خیر | | [`jalali-moment`](https://www.npmjs.com/package/jalali-moment) | فورک جلالی Moment | 🔴 خیر | 🔴 خیر | 🔴 از طریق Moment، که تیم خودش آن را legacy می‌نامد | 🟡 ناقص | 🔴 خیر | 🔴 خیر | | [`date-fns-jalali`](https://www.npmjs.com/package/date-fns-jalali) | API کامل date-fns، طعم جلالی | 🟢 بله | 🔴 خیر، یک تقویم | 🟡 از طریق date-fns، بدون نوع دقت صریح | 🔴 خیر | 🔴 خیر | 🔴 خیر | | `dayjs` + `jalaliday` | افزونه جلالی برای Day.js | 🟡 ناقص | 🔴 خیر | 🟡 از طریق Day.js | 🔴 خیر | 🔴 خیر | 🔴 خیر | | [`persian-date`](https://www.npmjs.com/package/persian-date) | شیء تاریخ پارسی | 🔴 خیر | 🔴 خیر | 🔴 خیر | 🟡 ناقص | 🔴 خیر | 🔴 خیر | | [`react-multi-date-picker`](https://github.com/shahabyazdi/react-multi-date-picker) | UI انتخابگر تاریخ React | 🟢 بله | 🟢 بله، چند تقویم | 🔴 بدون مدل صریح | 🟢 بله | 🟡 فقط React | 🔴 وابسته به UI، نه بدون ظاهر | | [`vue-persian-datetime-picker`](https://github.com/talkhabi/vue-persian-datetime-picker) | UI انتخابگر تاریخ Vue | 🔴 خیر | 🔴 خیر | 🔴 از طریق moment-jalaali | 🟡 ناقص | 🟡 فقط Vue | 🔴 وابسته به UI، نه بدون ظاهر | برای کار تازه jalali-js را ترجیح دهید. تنها ردیف سبز در همه ستون‌ها است. * فقط ریاضی: باز هم هسته `jalali-js` را بر `jalaali-js` ترجیح دهید. * UI برای React یا Vue: `@jalali-js/react` یا `@jalali-js/vue`، نه یک انتخابگر تک‌فریم‌ورک. * بدون فریم‌ورک: `@jalali-js/web`. * برای کار تازه از `moment-jalaali` و `jalali-moment` بگذرید. دو الگو در گزینه‌های دیگر تکرار می‌شود. اول، چند مورد به Moment.js وابسته‌اند و تیم Moment.js خودش پروژه را legacy می‌نامد و برای کار تازه توصیه نمی‌کند. دوم، بسته‌هایی با مؤلفه UI قوی منطق تاریخ را به یک فریم‌ورک گره می‌زنند، پس تیم نمی‌تواند موتور تبدیل را بدون درخت مؤلفه بگیرد، یا برعکس. jalali-js عمداً روی آن نقطه دوم شکاف می‌گذارد: یک هسته کوچک، مستقل از فریم‌ورک و بدون وابستگی (`jalali-js`) کار تبدیل را انجام می‌دهد؛ بایندینگ‌های نازک فریم‌ورک (`@jalali-js/react`، `@jalali-js/vue` و `@jalali-js/web`) روی آن می‌نشینند؛ یک لایه مؤلفه بدون ظاهر روی آن. `@jalali-js/web` Web Components ساده است، نه پوشش React یا Vue، پس به هیچ فریم‌ورکی نیاز ندارد و مثل هر عنصر HTML دیگر در همه آن‌ها می‌نشیند. همان هسته می‌تواند یک داشبورد مدیریت React، یک فروشگاه Vue یا Nuxt، یک صفحه HTML ساده، و یک کار backend با TypeScript را تغذیه کند، بدون کد هدررفته در هیچ‌کدام. ## jalali-js صریحاً چه کاری نمی‌کند * **ریاضی عمومی تاریخ.** جایگزین date-fns یا Temporal نیست. `jalali-js` صفر وابستگی زمان اجرا دارد و اشیاء ساده `Date`، رشته‌های ISO و اعداد epoch را می‌خواند و برمی‌گرداند؛ برای ریاضی تاریخی که پوشش نمی‌دهد، مثل افزودن روزهای کاری، date-fns یا Temporal را کنار آن به کار ببرید. * **قالب ذخیره پایگاه داده.** `jalali-js` تصمیم نمی‌گیرد برنامه شما تاریخ را چگونه در طرح‌واره خودش ذخیره کند. فقط تصمیم می‌گیرد مؤلفه به‌صورت پیش‌فرض چه مقداری برگرداند (ببینید [مقدار نمایشی در برابر مقدار ذخیره‌سازی](/fa/guide/display-vs-storage))، و آن مقدار را مستقل از تقویم می‌کند تا مورد رایج نیاز به فکر اضافه نداشته باشد. --- --- url: https://jalali-js.yanovian.com/fa/guide/display-vs-storage.md description: >- چرا مؤلفه‌ها به‌صورت پیش‌فرض جلالی را نشان می‌دهند و یک مقدار ذخیره میلادی می‌فرستند. --- # مقدار نمایشی در برابر مقدار ذخیره‌سازی سامانه تقویم یک تنظیم نمایش است. یک تنظیم ذخیره نیست. یک مؤلفه می‌تواند تقویم جلالی را به کاربر نشان دهد و همچنان مقداری به برنامه بدهد که هیچ وابستگی خاصی به تقویم ندارد. ## رفتار پیش‌فرض هر مؤلفه و هر تابع تبدیل هسته، به‌صورت پیش‌فرض یک مقدار میلادی و مستقل از تقویم برمی‌گرداند. شکل آن از لایه دقت فعال پیروی می‌کند: | لایه دقت | شکل مقدار پیش‌فرض | | ----------------------- | ------------------------------------------------------- | | `CalendarDate` | رشته تاریخ ISO میلادی، `YYYY-MM-DD` | | `CalendarDateTime` | رشته تاریخ‌زمان ISO میلادی، بدون افست | | `ZonedCalendarDateTime` | رشته تاریخ‌زمان ISO میلادی با افست، یا میلی‌ثانیه epoch | این با رفتار `` بومی هم‌خوان است: هر تقویمی که سیستم‌عامل نشان دهد، مقدار همیشه یک رشته ISO میلادی است. `jalali-js` همین شکاف را به‌عمد نگه می‌دارد، به‌جای بستن مقدار ذخیره‌شده به تقویمی که روی صفحه است. یک انتخابگر تقویم پارسی موجود برای React، یعنی `react-multi-date-picker`، این دو را به هم گره می‌زند: اگر آن را برای نمایش تقویم پارسی پیکربندی کنید، مقداری که برمی‌گرداند هم پارسی است و برای گرفتن مقدار میلادی به فراخوانی صریح `.convert()` نیاز دارید. آن پیوند باعث می‌شود خروجی خام انتخابگر آسان وارد فرم یا فیلد پایگاه داده شود، بدون گام تبدیل. `jalali-js` با نگه داشتن خروجی پیش‌فرض میلادی، صرف‌نظر از تقویم نمایش، از آن پرهیز می‌کند. ## انتخاب مقدار بومی جلالی برخی برنامه‌ها باید مقدار جلالی را همان‌طور ذخیره کنند (برای مثال سامانه ثبت دولتی یا حقوقی که تاریخ را به شکل جلالی نگه می‌دارد). گزینه `valueFormat`، هرجا که مؤلفه یا `toStorageValue()` آن را بپذیرد، این را پوشش می‌دهد: ```ts import { toStorageValue } from 'jalali-js'; const date = { year: 1403, month: 5, day: 15 }; toStorageValue(date, 'gregorian-iso'); // '2024-08-05' (پیش‌فرض) toStorageValue(date, 'date'); // Date بومی JS toStorageValue(date, 'epoch'); // میلی‌ثانیه epoch toStorageValue(date, 'jalali-iso'); // '1403-05-15' toStorageValue(date, 'jalali-object'); // { year: 1403, month: 5, day: 15 } ``` `'jalali-iso'` و `'jalali-object'` با وجود نام، واقعاً ویژه جلالی نیستند: همان سامانه تقویم خود تاریخ (`system`) را بدون تبدیل می‌دهند، نه معادل میلادی. برای مورد اصلی (ذخیره تاریخ جلالی به‌همان شکل) نام‌گذاری شده‌اند و برای تاریخ با سامانه میلادی هم همین‌طور کار می‌کنند. این درباره طرح‌واره خود شما تصمیم نمی‌گیرد. فقط مشخص می‌کند مؤلفه چه مقداری برگرداند، و مقدار مستقل از تقویم را پیش‌فرض می‌کند تا انتخاب درست نیاز به فکر اضافه نداشته باشد. ## رفت و برگشت کامل یک برنامه معمول: مقدار ذخیره‌شده را بخوانید (پیش‌فرض میلادی) → فقط برای نمایش به تقویم نمایش تبدیل کنید → بگذارید کاربر تاریخ تازه انتخاب کند → هنگام تغییر دوباره به مقدار ذخیره برگردید. `onChange` در `DatePicker` هر دو شکل را در یک فراخوانی می‌دهد، پس بیشتر برنامه‌ها این تبدیل را دستی نمی‌نویسند: ```tsx { // value: مقدار ذخیره، شکل‌گرفته با valueFormat (آنچه ذخیره می‌کنید) // date: CalendarDate خام (اگر لازم باشد برای وضعیت محلی UI نگه دارید) }} /> ```