Skip to content

@doranjs/react

RTL-first, accessible React calendar components.

ts
import '@doranjs/ui/styles.css';
import '@doranjs/react/styles.css';

Components

ComponentDescription
DoranCalendarFull month calendar with header navigation
DoranMonthViewA single accessible month grid (the building block)
DoranDatePickerInput with a pop-over calendar
DoranRangePickerTwo-click date-range selection
DoranTimePickerStandalone hour/minute time picker
DoranNlpInputNatural-language input with autocomplete + hint
DoranAgendaVertical day-by-day agenda with events
tsx
import { DoranCalendar, DoranDatePicker } from '@doranjs/react';

<DoranCalendar defaultValue={DoranDate.now()} onChange={(d) => ...} />
<DoranDatePicker placeholder="انتخاب تاریخ" />

DoranDatePicker props

PropTypeDefaultDescription
valueDoranDate | nullControlled value
defaultValueDoranDate | nullUncontrolled initial value
onChange(date: DoranDate | null, gregorian: Date | null) => voidCalled on selection or Clear; second arg is the native Date for backend use
localeLocale | stringgetDefaultLocale()Formatting locale — falls back to the global default set by setDefaultLocale()
formatstring'YYYY/MM/DD'Display pattern (+ 'HH:mm' when withTime)
placeholderstring'انتخاب تاریخ'Input placeholder
footerActionsreadonly ('today' | 'clear')[]['today']Ordered footer actions; an empty array hides the footer
hideFooterbooleanfalseDeprecated; use footerActions={[]}
iconPosition'left' | 'right''left'Trigger icon position
textAlign'left' | 'right''right'Trigger text alignment
inputWidthCSSProperties['width']Trigger width; numbers are interpreted as pixels
dropdownWidth'auto' | 'trigger' | CSSProperties['width']'auto'Intrinsic, trigger-matched, or custom CSS popover width
minDoranDateEarliest selectable date
maxDoranDateLatest selectable date
disabledbooleanfalseDisables the input
classNamestringAdded to the root element
styleCSSPropertiesInline style forwarded to the root element
idstringid forwarded to the root element
size'sm' | 'md' | 'lg'Preset heights: 32 / 40 / 48 px
withTimebooleanfalseShow a time picker and carry the time on the value
headerMode'dropdown' | 'separate''dropdown'In-place month/year panels, or native <select>s
minuteStepnumber1Minute increment for the time stepper
isHoliday(day: DoranDate) => booleanMark holiday days (dot + holiday color)
weekendsnumber[][6]Weekday indices treated as weekend (0 = Saturday)
arrows{ prev, next }chevronsCustom navigation arrow nodes
showOutsideDaysbooleanShow days from adjacent months in the grid
tsx
// Minimal usage
<DoranDatePicker onChange={(_d, gregorian) => console.log(gregorian?.toISOString())} />;

// Controlled, with backend POST
const [date, setDate] = useState<DoranDate | null>(null);
<DoranDatePicker
  value={date}
  size="md"
  style={{ width: 200 }}
  onChange={(d, greg) => {
    setDate(d);
    if (greg) await api.post('/events', { date: greg.toISOString() });
  }}
/>;

// Locale follows global default — call once at app root:
setDefaultLocale(enUS);
// Every picker now uses Latin digits, English names, and Today/Clear labels.

DoranRangePicker props

PropTypeDefaultDescription
valueDateRangeControlled range ({ start, end })
defaultValueDateRangeUncontrolled initial range
onChange(range: DateRange, gregorian: GregorianDateRange) => voidCalled on each selection step; second arg carries native Date objects
localeLocale | stringgetDefaultLocale()Falls back to the global default
numberOfMonthsnumber1Side-by-side month grids
presetsboolean | RangePreset[]true for built-in presets, or a custom array
footerActionsreadonly 'clear'[]['clear']Footer Clear control; an empty array hides the footer
isHoliday(day: DoranDate) => booleanMark holiday days
weekendsnumber[][6]Weekend indices
tsx
import { DoranRangePicker, type GregorianDateRange } from '@doranjs/react';

<DoranRangePicker
  presets
  onChange={(range, { start, end }) => {
    if (start && end) {
      setFilter({ from: start.toISOString(), to: end.toISOString() });
    }
  }}
/>;

DoranCalendar and DoranDatePicker accept ordered today and clear actions through footerActions, for example ['today', 'clear']. An empty array hides the whole footer. Today selects the current date and calls onChange; Clear removes the value and emits onChange(null) (with a null Gregorian argument from DatePicker).

DoranRangePicker shows a Clear control in its footer by default. footerActions={[]} hides it together with the range summary. hideFooter remains for backward compatibility but is deprecated. Button labels follow the active locale: faIR uses «امروز»/«پاک کردن», while enUS uses Today/Clear.

Month, year & time selection

DoranCalendar (and DoranDatePicker) accept:

PropTypeDefaultDescription
headerMode'dropdown' | 'separate''dropdown'In-place month/year panels, or native <select>s
withTimebooleanfalseShow a time picker and carry the time on the value
minuteStepnumber1Minute increment for the time stepper
isHoliday(day) => booleanMark holiday days (dot + holiday color)
weekendsnumber[][6]Weekday indices treated as weekend (0 = Saturday)
arrows{ prev, next }chevronsCustom navigation arrow nodes
tsx
import { getHolidaysOn } from '@doranjs/holidays';

<DoranCalendar
  withTime
  headerMode="dropdown"
  isHoliday={(d) => getHolidaysOn(d).some((h) => h.official)}
/>;

Natural-language input

tsx
import { DoranNlpInput } from '@doranjs/react';

<DoranNlpInput placeholder="مثلاً: جمعه ساعت ۷ شب" onResolve={(r) => console.log(r?.date)} />;

Shows a live autocomplete dropdown and a resolved-date hint pinned to the opposite (LTR) end of the field. The headless useNlpSuggest(text, options) hook returns { result, suggestions } for building your own UI.

Theming

Every part reads its own CSS variable, so you can restyle a single instance without overriding components — colors, fonts, shadows, borders, radii, and arrows:

tsx
<div style={{ '--doran-day-selected-bg': '#e11d48', '--doran-calendar-radius': '22px' }}>
  <DoranCalendar />
</div>

See @doranjs/ui for the full token list.

Headless primitives

tsx
import { useCalendar, useDateRange, buildMonthGrid } from '@doranjs/react';

const { grid, goToNextMonth, select, isSelected } = useCalendar();
const grid = buildMonthGrid(1405, 3); // pure, no React

All components support keyboard navigation (arrows, Home/End, Enter/Space), ARIA grid semantics, dark mode, and mobile layouts.

Released under the MIT License.