@fvc/picker
v1.1.4
Published
`@fvc/picker` provides date and time picker components for FE-VIS applications — `DatePicker`, `RangeDatePicker`, and `TimePicker` — built on Ant Design and dayjs. It adds controlled date-enabling/disabling, a compact display mode, and range shortcut chip
Downloads
2,307
Readme
@fvc/picker
@fvc/picker provides date and time picker components for FE-VIS applications — DatePicker, RangeDatePicker, and TimePicker — built on Ant Design and dayjs. It adds controlled date-enabling/disabling, a compact display mode, and range shortcut chips on top of the standard antd API.
Installation
bun add @fvc/pickerPeer Dependencies
bun add react antd@fvc/icons is a direct dependency and is included automatically.
Import
import { DatePicker, RangeDatePicker, TimePicker, Shortcut } from '@fvc/picker';Quick Start
import { DatePicker } from '@fvc/picker';
export function BirthDateField() {
return (
<DatePicker
format="DD.MM.YYYY"
onChange={(_, dateString) => console.log(dateString)}
/>
);
}DatePicker
Additional props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| disabledDates | IDateActivationConf | — | Dates outside this config are disabled. |
| enabledDates | IDateActivationConf | — | Only dates matching this config are enabled. |
| error | boolean | false | Applies error border and background styling. |
| short | boolean | false | Compact width mode (max-width: 140px). |
| hideYear | boolean | false | Hides the year row in the dropdown panel. |
| format | string | antd default | Display and parse format string (dayjs tokens). |
| testId | string | 'datepicker' | Maps to data-testid on the wrapper element. |
All antd DatePickerProps are forwarded.
IDateActivationConf
Controls which dates are selectable. disabledDates and enabledDates can be
used independently or together — enabledDates takes precedence when both are provided.
interface IDateActivationConf {
dates?: string[]; // exact dates: ['2024-12-25', '2024-12-31']
ranges?: [string, string][]; // date ranges: [['2024-01-01', '2024-01-07']]
fromDate?: string; // disable everything before this date
tillDate?: string; // disable everything after this date
}Common Usage
Error state
<DatePicker format="DD.MM.YYYY" error={hasValidationError} />Compact mode
<DatePicker format="DD.MM.YYYY" short />Restrict selectable dates
// Only allow future dates
<DatePicker
format="DD.MM.YYYY"
disabledDates={{ tillDate: dayjs().format('YYYY-MM-DD') }}
/>
// Enable only specific dates
<DatePicker
format="DD.MM.YYYY"
enabledDates={{
dates: ['2024-06-15', '2024-06-16'],
ranges: [['2024-07-01', '2024-07-07']],
}}
/>RangeDatePicker
Additional props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| format | string | 'DD.MM.YYYY' | Display format shown in the input. |
| outputFormat | string | 'YYYY-MM-DD' | Format of the strings passed to onChange. |
| shortcuts | ShortcutDef[] | — | Shortcut chips rendered below the picker. |
| updateValueBeforeChange | BeforeChangeFunction | — | Intercepts and transforms the value before onChange fires. |
| disabledDates | IDateActivationConf | — | Same as DatePicker. |
| enabledDates | IDateActivationConf | — | Same as DatePicker. |
| testId | string | 'rangepicker' | Maps to data-testid on the wrapper. |
formatcontrols what the user sees in the input.outputFormatcontrols whatonChangereceives. Set these independently when your API expects a format different from the display format.
Shortcuts
Shortcut chips render below the picker. Selecting a chip sets the range value and highlights it. Picking dates manually clears the active shortcut.
type ShortcutDef = {
label: string;
value?: [Dayjs | null, Dayjs | null];
renderType?: 'DEFAULT' | 'MONTHLY' | 'YEARLY' | 'QUARTERLY';
};Common Usage
Basic range
<RangeDatePicker
format="DD.MM.YYYY"
outputFormat="YYYY-MM-DD"
onChange={(_, [start, end]) => console.log(start, end)}
/>With shortcuts
import dayjs from 'dayjs';
<RangeDatePicker
shortcuts={[
{
label: 'This week',
value: [dayjs().startOf('week'), dayjs().endOf('week')],
},
{
label: 'This month',
value: [dayjs().startOf('month'), dayjs().endOf('month')],
},
{
label: 'Last 30 days',
value: [dayjs().subtract(30, 'day'), dayjs()],
},
]}
/>TimePicker
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| format | string | 'HH:mm' | Time display and parse format. |
| testId | string | 'timepicker' | Maps to data-testid on the wrapper. |
All antd TimePickerProps are forwarded.
<TimePicker
format="HH:mm"
onChange={(_, timeString) => setTime(timeString)}
/>Shortcut
A standalone clickable chip. Used internally by RangeDatePicker but available for building custom range layouts.
<Shortcut
label="Last 30 days"
isSelected={isActive}
onClick={handleShortcut}
testId="shortcut-30d"
/>| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| label | string | — | Chip text. |
| isSelected | boolean | false | Highlighted/active state. |
| onClick | () => void | — | Click handler. |
| testId | string | — | Maps to data-testid. |
Ref Forwarding
All three picker components forward refs typed as PickerRef.
interface PickerRef {
nativeElement: HTMLDivElement;
focus: (options?: FocusOptions) => void;
blur: VoidFunction;
}const ref = useRef<PickerRef>(null);
<DatePicker ref={ref} />
ref.current?.focus();Consumer Example
import { DatePicker, RangeDatePicker } from '@fvc/picker';
import dayjs from 'dayjs';
interface ReportFilterProps {
onDateChange: (date: string) => void;
onRangeChange: (start: string, end: string) => void;
}
export function ReportFilter({ onDateChange, onRangeChange }: ReportFilterProps) {
return (
<div className="report-filter">
<DatePicker
format="DD.MM.YYYY"
disabledDates={{ tillDate: dayjs().subtract(1, 'year').format('YYYY-MM-DD') }}
onChange={(_, dateString) => onDateChange(dateString as string)}
testId="report-date"
/>
<RangeDatePicker
format="DD.MM.YYYY"
outputFormat="YYYY-MM-DD"
shortcuts={[
{ label: 'Last 7 days', value: [dayjs().subtract(7, 'd'), dayjs()] },
{ label: 'Last 30 days', value: [dayjs().subtract(30, 'd'), dayjs()] },
]}
onChange={(_, [start, end]) => onRangeChange(start, end)}
testId="report-range"
/>
</div>
);
}Testing
testId maps to data-testid on the wrapper <div>. Shortcut chips use
{testId}-shortcut-{index} automatically.
<DatePicker testId="birth-date" />
<RangeDatePicker testId="contract-range" />screen.getByTestId('birth-date');
screen.getByTestId('contract-range');
screen.getByTestId('contract-range-shortcut-0');CSS Customisation
The component exposes CSS custom properties for theming. Override them in your global styles:
:root {
/* Layout */
--picker-width: 100%;
--picker-max-width-short: 140px;
--picker-main-padding: 0px;
--picker-main-outlined-input-padding: 5px 13px;
/* Colours */
--picker-main-color: var(--blue-600);
--picker-main-border: 1px solid var(--gray-400);
--picker-main-outlined-input-background: var(--neutral-0);
/* Border radius */
--picker-main-border-radius: 20px;
--picker-cell-in-view-border-radius: 20px;
--picker-today-default-radius: 2px;
--picker-ok-border-radius: 30px;
/* Typography */
--picker-input-font-weight: 500;
/* Error state */
--picker-error-background-color: var(--red-100);
--picker-error-border-color: var(--red-800);
--picker-error-suffix-color: var(--red-800);
/* OK button */
--picker-ok-background-color: var(--green-600);
--picker-ok-box-shadow: none;
}For the full variable list see src/styles/variables.scss.
The Shortcut chip has its own custom properties:
:root {
--shortcut-background-color: var(--gray-250);
--shortcut-selected-background-color: var(--blue-150);
--shortcut-text-color: var(--black-1000);
--shortcut-border-radius: 16px;
--shortcut-padding: 4px 10px;
--shortcut-font-size: 14px;
--shortcut-font-weight: 400;
--shortcut-line-height: 16px;
--shortcut-hover-opacity: 0.85;
}For the full variable list see src/styles/ShortcutVariables.scss.
CSS Classes
| Class | Component | Applied when |
| --- | --- | --- |
| .fvc-datepicker | DatePicker | Always — root wrapper |
| .fvc-datepicker-short | DatePicker | short is true |
| .fvc-datepicker-dropdown | DatePicker | Dropdown panel |
| .fvc-datepicker-dropdown-hide-year | DatePicker | hideYear is true |
| .fvc-rangepicker | RangeDatePicker | Always — root wrapper |
| .fvc-rangepicker-input | RangeDatePicker | Each date input within the range picker |
| .fvc-timepicker | TimePicker | Always — root wrapper |
| .fvc-shortcut | Shortcut | Always — chip element |
| .fvc-shortcut-selected | Shortcut | isSelected is true |
Development
bun run lint
bun run type-check
bun run test