RangeCalendar

A range calendar is an extension of the regular calendar component, but it allows to select a range of dates.

Installyarn add @diallink-corp/convergo-react-calendar
Version4.1.2
Usageimport {RangeCalendar} from '@diallink-corp/convergo-react-calendar'

Uncontrolled Value

By default, the RangeCalendar component handles its value uncontrolled. In the uncontrolled variant you can pass in a defaultValue to set the default date.

<RangeCalendar
  defaultValue={{
    start: new CalendarDate(2022, 5, 1),
    end: new CalendarDate(2022, 5, 10)
  }}
/>
<RangeCalendar
  defaultValue={{
    start: new CalendarDate(2022, 5, 1),
    end: new CalendarDate(2022, 5, 10)
  }}
/>
<RangeCalendar
  defaultValue={{
    start:
      new CalendarDate(
        2022,
        5,
        1
      ),
    end:
      new CalendarDate(
        2022,
        5,
        10
      )
  }}
/>

Controlled Value

You can also handle the value of the component in a controlled manner. To do so, you can pass in a value prop as well as an onChange handler to modify the value when the user changes the date.

function Example() {
  const [date, setDate] = useState({
    start: new CalendarDate(2019, 2, 3),
    end: new CalendarDate(2019, 2, 10)
  });

  return <RangeCalendar value={date} onChange={setDate} />;
}
function Example() {
  const [date, setDate] = useState({
    start: new CalendarDate(2019, 2, 3),
    end: new CalendarDate(2019, 2, 10)
  });

  return <RangeCalendar value={date} onChange={setDate} />;
}
function Example() {
  const [date, setDate] =
    useState({
      start:
        new CalendarDate(
          2019,
          2,
          3
        ),
      end:
        new CalendarDate(
          2019,
          2,
          10
        )
    });

  return (
    <RangeCalendar
      value={date}
      onChange={setDate}
    />
  );
}

Calendar and Locale

The calendar component supports most calendar types across the globe as well as all browser locales for accessibility.

function Example() {
  const calendars = [
    { key: 'gregory', name: 'Gregorian' },
    { key: 'japanese', name: 'Japanese' },
    { key: 'buddhist', name: 'Buddhist' },
    { key: 'roc', name: 'Taiwan' },
    { key: 'persian', name: 'Persian' },
    { key: 'indian', name: 'Indian' },
    { key: 'islamic-umalqura', name: 'Islamic (Umm al-Qura)' },
    { key: 'islamic-civil', name: 'Islamic Civil' },
    { key: 'islamic-tbla', name: 'Islamic Tabular' },
    { key: 'hebrew', name: 'Hebrew' },
    { key: 'coptic', name: 'Coptic' },
    { key: 'ethiopic', name: 'Ethiopic' },
    { key: 'ethioaa', name: 'Ethiopic (Amete Alem)' }
  ];
  const [calendar, setCalendar] = useState(calendars[0].key);

  // https://github.com/unicode-org/cldr/blob/22af90ae3bb04263f651323ce3d9a71747a75ffb/common/supplemental/supplementalData.xml#L4649-L4664
  const locales = [
    { label: 'Default', locale: 'en-US', ordering: 'gregory' },
    {
      label: 'Arabic (Algeria)',
      locale: 'ar-DZ',
      territories: 'DJ DZ EH ER IQ JO KM LB LY MA MR OM PS SD SY TD TN YE',
      ordering: 'gregory islamic islamic-civil islamic-tbla'
    },
    {
      label: 'Arabic (United Arab Emirates)',
      locale: 'ar-AE',
      territories: 'AE BH KW QA',
      ordering: 'gregory islamic-umalqura islamic islamic-civil islamic-tbla'
    },
    {
      label: 'Arabic (Egypt)',
      locale: 'AR-EG',
      territories: 'EG',
      ordering: 'gregory coptic islamic islamic-civil islamic-tbla'
    },
    {
      label: 'Arabic (Saudi Arabia)',
      locale: 'ar-SA',
      territories: 'SA',
      ordering: 'islamic-umalqura gregory islamic islamic-rgsa'
    },
    {
      label: 'Farsi (Afghanistan)',
      locale: 'fa-AF',
      territories: 'AF IR',
      ordering: 'persian gregory islamic islamic-civil islamic-tbla'
    },
    {
      label: 'Amharic (Ethiopia)',
      locale: 'am-ET',
      territories: 'ET',
      ordering: 'gregory ethiopic ethioaa'
    },
    {
      label: 'Hebrew (Israel)',
      locale: 'he-IL',
      territories: 'IL',
      ordering: 'gregory hebrew islamic islamic-civil islamic-tbla'
    },
    {
      label: 'Hindi (India)',
      locale: 'hi-IN',
      territories: 'IN',
      ordering: 'gregory indian'
    },
    {
      label: 'Japanese (Japan)',
      locale: 'ja-JP',
      territories: 'JP',
      ordering: 'gregory japanese'
    },
    {
      label: 'Thai (Thailand)',
      locale: 'th-TH',
      territories: 'TH',
      ordering: 'buddhist gregory'
    },
    {
      label: 'Chinese (Taiwan)',
      locale: 'zh-TW',
      territories: 'TW',
      ordering: 'gregory roc chinese'
    }
  ];
  const { locale: defaultLocale } = useLocale();
  const [locale, setLocale] = useState(defaultLocale);

  const [date, setDate] = useState({
    start: new CalendarDate(2019, 2, 3),
    end: new CalendarDate(2019, 2, 10)
  });

  const handleLocaleChange = (locale) => {
    setLocale(locale);
    const fullLocale = locales.find((p) => p.locale === locale);
    setCalendar(fullLocale.ordering.split(' ')[0]);
  };

  return (
    <div>
      <Select
        label="Locale"
        items={locales}
        selectedKey={locale}
        onSelectionChange={handleLocaleChange}
      >
        {(item) => <Item key={item.locale}>{item.label}</Item>}
      </Select>
      <Select
        label="Calendar"
        items={calendars}
        selectedKey={calendar}
        onSelectionChange={setCalendar}
      >
        {(item) => <Item key={item.key}>{item.name}</Item>}
      </Select>
      <ConvergoProvider locale={`${locale}${calendar && `-u-ca-${calendar}`}`}>
        <RangeCalendar value={date} onChange={setDate} />
      </ConvergoProvider>
    </div>
  );
}
function Example() {
  const calendars = [
    { key: 'gregory', name: 'Gregorian' },
    { key: 'japanese', name: 'Japanese' },
    { key: 'buddhist', name: 'Buddhist' },
    { key: 'roc', name: 'Taiwan' },
    { key: 'persian', name: 'Persian' },
    { key: 'indian', name: 'Indian' },
    {
      key: 'islamic-umalqura',
      name: 'Islamic (Umm al-Qura)'
    },
    { key: 'islamic-civil', name: 'Islamic Civil' },
    { key: 'islamic-tbla', name: 'Islamic Tabular' },
    { key: 'hebrew', name: 'Hebrew' },
    { key: 'coptic', name: 'Coptic' },
    { key: 'ethiopic', name: 'Ethiopic' },
    { key: 'ethioaa', name: 'Ethiopic (Amete Alem)' }
  ];
  const [calendar, setCalendar] = useState(
    calendars[0].key
  );

  // https://github.com/unicode-org/cldr/blob/22af90ae3bb04263f651323ce3d9a71747a75ffb/common/supplemental/supplementalData.xml#L4649-L4664
  const locales = [
    {
      label: 'Default',
      locale: 'en-US',
      ordering: 'gregory'
    },
    {
      label: 'Arabic (Algeria)',
      locale: 'ar-DZ',
      territories:
        'DJ DZ EH ER IQ JO KM LB LY MA MR OM PS SD SY TD TN YE',
      ordering: 'gregory islamic islamic-civil islamic-tbla'
    },
    {
      label: 'Arabic (United Arab Emirates)',
      locale: 'ar-AE',
      territories: 'AE BH KW QA',
      ordering:
        'gregory islamic-umalqura islamic islamic-civil islamic-tbla'
    },
    {
      label: 'Arabic (Egypt)',
      locale: 'AR-EG',
      territories: 'EG',
      ordering:
        'gregory coptic islamic islamic-civil islamic-tbla'
    },
    {
      label: 'Arabic (Saudi Arabia)',
      locale: 'ar-SA',
      territories: 'SA',
      ordering:
        'islamic-umalqura gregory islamic islamic-rgsa'
    },
    {
      label: 'Farsi (Afghanistan)',
      locale: 'fa-AF',
      territories: 'AF IR',
      ordering:
        'persian gregory islamic islamic-civil islamic-tbla'
    },
    {
      label: 'Amharic (Ethiopia)',
      locale: 'am-ET',
      territories: 'ET',
      ordering: 'gregory ethiopic ethioaa'
    },
    {
      label: 'Hebrew (Israel)',
      locale: 'he-IL',
      territories: 'IL',
      ordering:
        'gregory hebrew islamic islamic-civil islamic-tbla'
    },
    {
      label: 'Hindi (India)',
      locale: 'hi-IN',
      territories: 'IN',
      ordering: 'gregory indian'
    },
    {
      label: 'Japanese (Japan)',
      locale: 'ja-JP',
      territories: 'JP',
      ordering: 'gregory japanese'
    },
    {
      label: 'Thai (Thailand)',
      locale: 'th-TH',
      territories: 'TH',
      ordering: 'buddhist gregory'
    },
    {
      label: 'Chinese (Taiwan)',
      locale: 'zh-TW',
      territories: 'TW',
      ordering: 'gregory roc chinese'
    }
  ];
  const { locale: defaultLocale } = useLocale();
  const [locale, setLocale] = useState(defaultLocale);

  const [date, setDate] = useState({
    start: new CalendarDate(2019, 2, 3),
    end: new CalendarDate(2019, 2, 10)
  });

  const handleLocaleChange = (locale) => {
    setLocale(locale);
    const fullLocale = locales.find((p) =>
      p.locale === locale
    );
    setCalendar(fullLocale.ordering.split(' ')[0]);
  };

  return (
    <div>
      <Select
        label="Locale"
        items={locales}
        selectedKey={locale}
        onSelectionChange={handleLocaleChange}
      >
        {(item) => (
          <Item key={item.locale}>{item.label}</Item>
        )}
      </Select>
      <Select
        label="Calendar"
        items={calendars}
        selectedKey={calendar}
        onSelectionChange={setCalendar}
      >
        {(item) => <Item key={item.key}>{item.name}</Item>}
      </Select>
      <ConvergoProvider
        locale={`${locale}${
          calendar && `-u-ca-${calendar}`
        }`}
      >
        <RangeCalendar value={date} onChange={setDate} />
      </ConvergoProvider>
    </div>
  );
}
function Example() {
  const calendars = [
    {
      key: 'gregory',
      name: 'Gregorian'
    },
    {
      key: 'japanese',
      name: 'Japanese'
    },
    {
      key: 'buddhist',
      name: 'Buddhist'
    },
    {
      key: 'roc',
      name: 'Taiwan'
    },
    {
      key: 'persian',
      name: 'Persian'
    },
    {
      key: 'indian',
      name: 'Indian'
    },
    {
      key:
        'islamic-umalqura',
      name:
        'Islamic (Umm al-Qura)'
    },
    {
      key:
        'islamic-civil',
      name:
        'Islamic Civil'
    },
    {
      key:
        'islamic-tbla',
      name:
        'Islamic Tabular'
    },
    {
      key: 'hebrew',
      name: 'Hebrew'
    },
    {
      key: 'coptic',
      name: 'Coptic'
    },
    {
      key: 'ethiopic',
      name: 'Ethiopic'
    },
    {
      key: 'ethioaa',
      name:
        'Ethiopic (Amete Alem)'
    }
  ];
  const [
    calendar,
    setCalendar
  ] = useState(
    calendars[0].key
  );

  // https://github.com/unicode-org/cldr/blob/22af90ae3bb04263f651323ce3d9a71747a75ffb/common/supplemental/supplementalData.xml#L4649-L4664
  const locales = [
    {
      label: 'Default',
      locale: 'en-US',
      ordering: 'gregory'
    },
    {
      label:
        'Arabic (Algeria)',
      locale: 'ar-DZ',
      territories:
        'DJ DZ EH ER IQ JO KM LB LY MA MR OM PS SD SY TD TN YE',
      ordering:
        'gregory islamic islamic-civil islamic-tbla'
    },
    {
      label:
        'Arabic (United Arab Emirates)',
      locale: 'ar-AE',
      territories:
        'AE BH KW QA',
      ordering:
        'gregory islamic-umalqura islamic islamic-civil islamic-tbla'
    },
    {
      label:
        'Arabic (Egypt)',
      locale: 'AR-EG',
      territories: 'EG',
      ordering:
        'gregory coptic islamic islamic-civil islamic-tbla'
    },
    {
      label:
        'Arabic (Saudi Arabia)',
      locale: 'ar-SA',
      territories: 'SA',
      ordering:
        'islamic-umalqura gregory islamic islamic-rgsa'
    },
    {
      label:
        'Farsi (Afghanistan)',
      locale: 'fa-AF',
      territories:
        'AF IR',
      ordering:
        'persian gregory islamic islamic-civil islamic-tbla'
    },
    {
      label:
        'Amharic (Ethiopia)',
      locale: 'am-ET',
      territories: 'ET',
      ordering:
        'gregory ethiopic ethioaa'
    },
    {
      label:
        'Hebrew (Israel)',
      locale: 'he-IL',
      territories: 'IL',
      ordering:
        'gregory hebrew islamic islamic-civil islamic-tbla'
    },
    {
      label:
        'Hindi (India)',
      locale: 'hi-IN',
      territories: 'IN',
      ordering:
        'gregory indian'
    },
    {
      label:
        'Japanese (Japan)',
      locale: 'ja-JP',
      territories: 'JP',
      ordering:
        'gregory japanese'
    },
    {
      label:
        'Thai (Thailand)',
      locale: 'th-TH',
      territories: 'TH',
      ordering:
        'buddhist gregory'
    },
    {
      label:
        'Chinese (Taiwan)',
      locale: 'zh-TW',
      territories: 'TW',
      ordering:
        'gregory roc chinese'
    }
  ];
  const {
    locale: defaultLocale
  } = useLocale();
  const [
    locale,
    setLocale
  ] = useState(
    defaultLocale
  );

  const [date, setDate] =
    useState({
      start:
        new CalendarDate(
          2019,
          2,
          3
        ),
      end:
        new CalendarDate(
          2019,
          2,
          10
        )
    });

  const handleLocaleChange =
    (locale) => {
      setLocale(locale);
      const fullLocale =
        locales.find(
          (p) =>
            p.locale ===
              locale
        );
      setCalendar(
        fullLocale
          .ordering
          .split(' ')[0]
      );
    };

  return (
    <div>
      <Select
        label="Locale"
        items={locales}
        selectedKey={locale}
        onSelectionChange={handleLocaleChange}
      >
        {(item) => (
          <Item
            key={item
              .locale}
          >
            {item.label}
          </Item>
        )}
      </Select>
      <Select
        label="Calendar"
        items={calendars}
        selectedKey={calendar}
        onSelectionChange={setCalendar}
      >
        {(item) => (
          <Item
            key={item
              .key}
          >
            {item.name}
          </Item>
        )}
      </Select>
      <ConvergoProvider
        locale={`${locale}${
          calendar &&
          `-u-ca-${calendar}`
        }`}
      >
        <RangeCalendar
          value={date}
          onChange={setDate}
        />
      </ConvergoProvider>
    </div>
  );
}

Min and Max Value

You can specify a minimum and maximum date that the user can select.

<RangeCalendar
  defaultValue={{
    start: new CalendarDate(2019, 2, 3),
    end: new CalendarDate(2019, 2, 10)
  }}
  minValue={new CalendarDate(2019, 2, 1)}
  maxValue={new CalendarDate(2019, 2, 15)}
/>
<RangeCalendar
  defaultValue={{
    start: new CalendarDate(2019, 2, 3),
    end: new CalendarDate(2019, 2, 10)
  }}
  minValue={new CalendarDate(2019, 2, 1)}
  maxValue={new CalendarDate(2019, 2, 15)}
/>
<RangeCalendar
  defaultValue={{
    start:
      new CalendarDate(
        2019,
        2,
        3
      ),
    end:
      new CalendarDate(
        2019,
        2,
        10
      )
  }}
  minValue={new CalendarDate(
    2019,
    2,
    1
  )}
  maxValue={new CalendarDate(
    2019,
    2,
    15
  )}
/>

Visible Months

You can define how many months should be visible through the visibleMonths prop.

<RangeCalendar
  defaultValue={{
    start: new CalendarDate(2019, 2, 3),
    end: new CalendarDate(2019, 2, 10)
  }}
  visibleMonths={3}
/>
<RangeCalendar
  defaultValue={{
    start: new CalendarDate(2019, 2, 3),
    end: new CalendarDate(2019, 2, 10)
  }}
  visibleMonths={3}
/>
<RangeCalendar
  defaultValue={{
    start:
      new CalendarDate(
        2019,
        2,
        3
      ),
    end:
      new CalendarDate(
        2019,
        2,
        10
      )
  }}
  visibleMonths={3}
/>

Disabled

The RangeCalendar component can be disabled via the isDisabled prop.

<RangeCalendar
  defaultValue={{
    start: new CalendarDate(2019, 2, 3),
    end: new CalendarDate(2019, 2, 10)
  }}
  isDisabled
/>
<RangeCalendar
  defaultValue={{
    start: new CalendarDate(2019, 2, 3),
    end: new CalendarDate(2019, 2, 10)
  }}
  isDisabled
/>
<RangeCalendar
  defaultValue={{
    start:
      new CalendarDate(
        2019,
        2,
        3
      ),
    end:
      new CalendarDate(
        2019,
        2,
        10
      )
  }}
  isDisabled
/>

Read Only

The RangeCalendar component can be marked as read only via the isReadOnly prop.

<RangeCalendar
  defaultValue={{
    start: new CalendarDate(2019, 2, 3),
    end: new CalendarDate(2019, 2, 10)
  }}
  isReadOnly
/>
<RangeCalendar
  defaultValue={{
    start: new CalendarDate(2019, 2, 3),
    end: new CalendarDate(2019, 2, 10)
  }}
  isReadOnly
/>
<RangeCalendar
  defaultValue={{
    start:
      new CalendarDate(
        2019,
        2,
        3
      ),
    end:
      new CalendarDate(
        2019,
        2,
        10
      )
  }}
  isReadOnly
/>

API