@wheelhouse/ui 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/accordion/accordion.js +2 -2
- package/dist/components/alert/alert.stories.js +4 -4
- package/dist/components/alert-dialog/alert-dialog.stories.js +2 -2
- package/dist/components/breadcrumb/breadcrumb.d.ts.map +1 -1
- package/dist/components/breadcrumb/breadcrumb.js +3 -4
- package/dist/components/calendar/calendar.d.ts +34 -0
- package/dist/components/calendar/calendar.d.ts.map +1 -0
- package/dist/components/calendar/calendar.js +82 -0
- package/dist/components/calendar/calendar.stories.d.ts +16 -0
- package/dist/components/calendar/calendar.stories.d.ts.map +1 -0
- package/dist/components/calendar/calendar.stories.js +33 -0
- package/dist/components/calendar/index.d.ts +3 -0
- package/dist/components/calendar/index.d.ts.map +1 -0
- package/dist/components/calendar/index.js +1 -0
- package/dist/components/checkbox/checkbox.js +2 -2
- package/dist/components/collapsible/collapsible.stories.js +4 -4
- package/dist/components/combobox/combobox.d.ts.map +1 -1
- package/dist/components/combobox/combobox.js +5 -7
- package/dist/components/command/command.d.ts.map +1 -1
- package/dist/components/command/command.js +3 -4
- package/dist/components/context-menu/context-menu.d.ts.map +1 -1
- package/dist/components/context-menu/context-menu.js +4 -5
- package/dist/components/date-selector/date-selector-context.d.ts +6 -0
- package/dist/components/date-selector/date-selector-context.d.ts.map +1 -0
- package/dist/components/date-selector/date-selector-context.js +11 -0
- package/dist/components/date-selector/date-selector-parts.d.ts +68 -0
- package/dist/components/date-selector/date-selector-parts.d.ts.map +1 -0
- package/dist/components/date-selector/date-selector-parts.js +131 -0
- package/dist/components/date-selector/date-selector-types.d.ts +118 -0
- package/dist/components/date-selector/date-selector-types.d.ts.map +1 -0
- package/dist/components/date-selector/date-selector-types.js +32 -0
- package/dist/components/date-selector/date-selector-value.d.ts +47 -0
- package/dist/components/date-selector/date-selector-value.d.ts.map +1 -0
- package/dist/components/date-selector/date-selector-value.js +183 -0
- package/dist/components/date-selector/date-selector.d.ts +6 -0
- package/dist/components/date-selector/date-selector.d.ts.map +1 -0
- package/dist/components/date-selector/date-selector.js +144 -0
- package/dist/components/date-selector/date-selector.stories.d.ts +135 -0
- package/dist/components/date-selector/date-selector.stories.d.ts.map +1 -0
- package/dist/components/date-selector/date-selector.stories.js +144 -0
- package/dist/components/date-selector/index.d.ts +7 -0
- package/dist/components/date-selector/index.d.ts.map +1 -0
- package/dist/components/date-selector/index.js +5 -0
- package/dist/components/date-selector/use-date-selector.d.ts +50 -0
- package/dist/components/date-selector/use-date-selector.d.ts.map +1 -0
- package/dist/components/date-selector/use-date-selector.js +305 -0
- package/dist/components/dialog/dialog.js +2 -2
- package/dist/components/dropdown-menu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/dropdown-menu/dropdown-menu.js +5 -6
- package/dist/components/empty/empty.stories.js +2 -2
- package/dist/components/filters/filters.js +4 -4
- package/dist/components/filters/filters.stories.js +3 -3
- package/dist/components/index.d.ts +5 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +5 -0
- package/dist/components/input-group/input-group.stories.js +3 -3
- package/dist/components/item/item.stories.d.ts.map +1 -1
- package/dist/components/item/item.stories.js +5 -6
- package/dist/components/kbd/kbd.stories.js +2 -2
- package/dist/components/menubar/menubar.js +3 -3
- package/dist/components/native-select/native-select.js +2 -2
- package/dist/components/navigation-menu/navigation-menu.js +2 -2
- package/dist/components/navigation-pattern-1/index.d.ts +3 -0
- package/dist/components/navigation-pattern-1/index.d.ts.map +1 -0
- package/dist/components/navigation-pattern-1/index.js +1 -0
- package/dist/components/navigation-pattern-1/pattern-1.config.d.ts +47 -0
- package/dist/components/navigation-pattern-1/pattern-1.config.d.ts.map +1 -0
- package/dist/components/navigation-pattern-1/pattern-1.config.js +55 -0
- package/dist/components/navigation-pattern-1/pattern-1.d.ts +7 -0
- package/dist/components/navigation-pattern-1/pattern-1.d.ts.map +1 -0
- package/dist/components/navigation-pattern-1/pattern-1.js +83 -0
- package/dist/components/navigation-pattern-1/pattern-1.stories.d.ts +16 -0
- package/dist/components/navigation-pattern-1/pattern-1.stories.d.ts.map +1 -0
- package/dist/components/navigation-pattern-1/pattern-1.stories.js +20 -0
- package/dist/components/pagination/pagination.js +4 -4
- package/dist/components/select/select.js +5 -5
- package/dist/components/sheet/sheet.js +2 -2
- package/dist/components/sonner/sonner.d.ts +1 -1
- package/dist/components/sonner/sonner.js +7 -7
- package/dist/components/sortable/index.d.ts +3 -0
- package/dist/components/sortable/index.d.ts.map +1 -0
- package/dist/components/sortable/index.js +1 -0
- package/dist/components/sortable/sortable.d.ts +94 -0
- package/dist/components/sortable/sortable.d.ts.map +1 -0
- package/dist/components/sortable/sortable.js +210 -0
- package/dist/components/sortable/sortable.stories.d.ts +14 -0
- package/dist/components/sortable/sortable.stories.d.ts.map +1 -0
- package/dist/components/sortable/sortable.stories.js +38 -0
- package/dist/components/spinner/spinner.d.ts +3 -3
- package/dist/components/spinner/spinner.d.ts.map +1 -1
- package/dist/components/spinner/spinner.js +2 -2
- package/dist/components/status-indicator/index.d.ts +3 -0
- package/dist/components/status-indicator/index.d.ts.map +1 -0
- package/dist/components/status-indicator/index.js +1 -0
- package/dist/components/status-indicator/status-indicator.d.ts +51 -0
- package/dist/components/status-indicator/status-indicator.d.ts.map +1 -0
- package/dist/components/status-indicator/status-indicator.js +48 -0
- package/dist/components/status-indicator/status-indicator.stories.d.ts +20 -0
- package/dist/components/status-indicator/status-indicator.stories.d.ts.map +1 -0
- package/dist/components/status-indicator/status-indicator.stories.js +97 -0
- package/dist/components/text/text.js +1 -1
- package/dist/hooks/use-mobile.d.ts +2 -0
- package/dist/hooks/use-mobile.d.ts.map +1 -0
- package/dist/hooks/use-mobile.js +15 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/llms.txt +4 -4
- package/package.json +7 -4
- package/src/styles/globals.css +4 -12
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { DateSelectorFilterType, DateSelectorPeriodType } from './date-selector-types';
|
|
2
|
+
interface DateSelectorFilterToggleProps {
|
|
3
|
+
value: DateSelectorFilterType;
|
|
4
|
+
onChange: (value: DateSelectorFilterType) => void;
|
|
5
|
+
showBetween?: boolean;
|
|
6
|
+
showIs?: boolean;
|
|
7
|
+
presetMode?: DateSelectorFilterType;
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function DateSelectorFilterToggle({ value, onChange, showBetween, showIs, presetMode, className }: DateSelectorFilterToggleProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
interface DateSelectorPeriodTabsProps {
|
|
12
|
+
value: DateSelectorPeriodType;
|
|
13
|
+
onChange: (value: DateSelectorPeriodType) => void;
|
|
14
|
+
periodTypes?: DateSelectorPeriodType[];
|
|
15
|
+
className?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function DateSelectorPeriodTabs({ value, onChange, periodTypes, className }: DateSelectorPeriodTabsProps): import("react/jsx-runtime").JSX.Element;
|
|
18
|
+
interface DateSelectorDayPickerProps {
|
|
19
|
+
currentMonth: Date;
|
|
20
|
+
selectedDate?: Date;
|
|
21
|
+
selectedEndDate?: Date;
|
|
22
|
+
onDayClick: (day: Date) => void;
|
|
23
|
+
isRange: boolean;
|
|
24
|
+
onDayHover?: (day: Date | undefined) => void;
|
|
25
|
+
hoverDate?: Date;
|
|
26
|
+
showTwoMonths?: boolean;
|
|
27
|
+
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
28
|
+
onMonthChange?: (month: Date) => void;
|
|
29
|
+
className?: string;
|
|
30
|
+
}
|
|
31
|
+
export declare function DateSelectorDayPicker({ currentMonth, selectedDate, selectedEndDate, onDayClick, isRange, onDayHover, hoverDate, showTwoMonths, weekStartsOn, onMonthChange, className, }: DateSelectorDayPickerProps): import("react/jsx-runtime").JSX.Element;
|
|
32
|
+
interface DateSelectorPeriodGridProps {
|
|
33
|
+
years: number[];
|
|
34
|
+
items: string[];
|
|
35
|
+
selectedYear?: number;
|
|
36
|
+
selectedValue?: number;
|
|
37
|
+
rangeStart?: {
|
|
38
|
+
year: number;
|
|
39
|
+
value: number;
|
|
40
|
+
};
|
|
41
|
+
rangeEnd?: {
|
|
42
|
+
year: number;
|
|
43
|
+
value: number;
|
|
44
|
+
};
|
|
45
|
+
isInRange: (year: number, value: number) => boolean;
|
|
46
|
+
onSelect: (year: number, value: number) => void;
|
|
47
|
+
columns: number;
|
|
48
|
+
className?: string;
|
|
49
|
+
}
|
|
50
|
+
export declare function DateSelectorPeriodGrid({ years, items, selectedYear, selectedValue, rangeStart, rangeEnd, isInRange, onSelect, columns, className, }: DateSelectorPeriodGridProps): import("react/jsx-runtime").JSX.Element;
|
|
51
|
+
interface DateSelectorYearListProps {
|
|
52
|
+
years: number[];
|
|
53
|
+
selectedYear?: number;
|
|
54
|
+
rangeStart?: {
|
|
55
|
+
year: number;
|
|
56
|
+
value: number;
|
|
57
|
+
};
|
|
58
|
+
rangeEnd?: {
|
|
59
|
+
year: number;
|
|
60
|
+
value: number;
|
|
61
|
+
};
|
|
62
|
+
isYearInRange: (year: number) => boolean;
|
|
63
|
+
onSelect: (year: number) => void;
|
|
64
|
+
className?: string;
|
|
65
|
+
}
|
|
66
|
+
export declare function DateSelectorYearList({ years, selectedYear, rangeStart, rangeEnd, isYearInRange, onSelect, className }: DateSelectorYearListProps): import("react/jsx-runtime").JSX.Element;
|
|
67
|
+
export {};
|
|
68
|
+
//# sourceMappingURL=date-selector-parts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"date-selector-parts.d.ts","sourceRoot":"","sources":["../../../src/components/date-selector/date-selector-parts.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAE5F,UAAU,6BAA6B;IACnC,KAAK,EAAE,sBAAsB,CAAC;IAC9B,QAAQ,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;IAClD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,sBAAsB,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,wBAAwB,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAkB,EAAE,MAAa,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,6BAA6B,2CAkCpJ;AAED,UAAU,2BAA2B;IACjC,KAAK,EAAE,sBAAsB,CAAC;IAC9B,QAAQ,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;IAClD,WAAW,CAAC,EAAE,sBAAsB,EAAE,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,sBAAsB,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE,2BAA2B,2CAwC9G;AAED,UAAU,0BAA0B;IAChC,YAAY,EAAE,IAAI,CAAC;IACnB,YAAY,CAAC,EAAE,IAAI,CAAC;IACpB,eAAe,CAAC,EAAE,IAAI,CAAC;IACvB,UAAU,EAAE,CAAC,GAAG,EAAE,IAAI,KAAK,IAAI,CAAC;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,IAAI,GAAG,SAAS,KAAK,IAAI,CAAC;IAC7C,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,KAAK,IAAI,CAAC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,qBAAqB,CAAC,EAClC,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,UAAU,EACV,OAAO,EACP,UAAU,EACV,SAAS,EACT,aAAqB,EACrB,YAAY,EACZ,aAAa,EACb,SAAS,GACZ,EAAE,0BAA0B,2CA2J5B;AAED,UAAU,2BAA2B;IACjC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IACpD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,sBAAsB,CAAC,EACnC,KAAK,EACL,KAAK,EACL,YAAY,EACZ,aAAa,EACb,UAAU,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,OAAO,EACP,SAAS,GACZ,EAAE,2BAA2B,2CAmC7B;AAED,UAAU,yBAAyB;IAC/B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACzC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,oBAAoB,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,yBAAyB,2CAuBhJ"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback } from 'react';
|
|
4
|
+
import { addMonths, isSameMonth, subMonths } from 'date-fns';
|
|
5
|
+
import { DayButton, getDefaultClassNames } from 'react-day-picker';
|
|
6
|
+
import { useIsMobile } from '../../hooks/use-mobile';
|
|
7
|
+
import { cn } from '../../lib/utils';
|
|
8
|
+
import { Button } from '../button';
|
|
9
|
+
import { Calendar, CalendarDayButton } from '../calendar';
|
|
10
|
+
import { Tabs, TabsList, TabsTrigger } from '../tabs';
|
|
11
|
+
import { ChevronLeft, ChevronRight, CornerUpLeft, CornerUpRight } from 'lucide-react';
|
|
12
|
+
import { useDateSelectorContext } from './date-selector-context';
|
|
13
|
+
export function DateSelectorFilterToggle({ value, onChange, showBetween = true, showIs = true, presetMode, className }) {
|
|
14
|
+
const { i18n } = useDateSelectorContext();
|
|
15
|
+
const isDisabled = presetMode !== undefined;
|
|
16
|
+
return (_jsx(Tabs, { className: cn('w-full', className), value: value, onValueChange: (newValue) => {
|
|
17
|
+
if (!isDisabled && newValue) {
|
|
18
|
+
onChange(newValue);
|
|
19
|
+
}
|
|
20
|
+
}, children: _jsxs(TabsList, { className: cn('flex h-9 w-full min-w-0 gap-1 bg-muted/80 p-[3px]', isDisabled && 'pointer-events-none opacity-50'), children: [showIs && (_jsx(TabsTrigger, { value: "is", "aria-label": i18n.filterTypes.is, className: "min-w-0 flex-1 px-1 py-1 text-center font-normal sm:px-2.5", children: i18n.filterTypes.is })), _jsx(TabsTrigger, { value: "before", "aria-label": i18n.filterTypes.before, className: "min-w-0 flex-1 px-1 py-1 text-center font-normal sm:px-2.5", children: i18n.filterTypes.before }), _jsx(TabsTrigger, { value: "after", "aria-label": i18n.filterTypes.after, className: "min-w-0 flex-1 px-1 py-1 text-center font-normal sm:px-2.5", children: i18n.filterTypes.after }), showBetween && (_jsx(TabsTrigger, { value: "between", "aria-label": i18n.filterTypes.between, className: "min-w-0 flex-1 px-1 py-1 text-center font-normal sm:px-2.5", children: i18n.filterTypes.between }))] }) }));
|
|
21
|
+
}
|
|
22
|
+
export function DateSelectorPeriodTabs({ value, onChange, periodTypes, className }) {
|
|
23
|
+
const { i18n } = useDateSelectorContext();
|
|
24
|
+
const tabs = [
|
|
25
|
+
{ value: 'day', label: i18n.periodTypes.day },
|
|
26
|
+
{ value: 'month', label: i18n.periodTypes.month },
|
|
27
|
+
{ value: 'quarter', label: i18n.periodTypes.quarter },
|
|
28
|
+
{ value: 'year', label: i18n.periodTypes.year },
|
|
29
|
+
];
|
|
30
|
+
return (_jsx("div", { className: cn('w-full', className), children: _jsx(Tabs, { className: "w-full", value: value, onValueChange: (newValue) => {
|
|
31
|
+
if (newValue) {
|
|
32
|
+
onChange(newValue);
|
|
33
|
+
}
|
|
34
|
+
}, children: _jsx(TabsList, { className: "flex h-9 w-full min-w-0 gap-1 bg-muted/80 p-[3px]", children: tabs.map((tab) => {
|
|
35
|
+
const disabled = Boolean(periodTypes?.length && !periodTypes.includes(tab.value));
|
|
36
|
+
return (_jsx(TabsTrigger, { value: tab.value, disabled: disabled, "aria-label": tab.label, className: "min-w-0 flex-1 px-1 py-1 text-center font-normal sm:px-2.5", children: tab.label }, tab.value));
|
|
37
|
+
}) }) }) }));
|
|
38
|
+
}
|
|
39
|
+
export function DateSelectorDayPicker({ currentMonth, selectedDate, selectedEndDate, onDayClick, isRange, onDayHover, hoverDate, showTwoMonths = false, weekStartsOn, onMonthChange, className, }) {
|
|
40
|
+
const { i18n } = useDateSelectorContext();
|
|
41
|
+
const isMobile = useIsMobile();
|
|
42
|
+
const selected = isRange
|
|
43
|
+
? selectedDate && selectedEndDate
|
|
44
|
+
? { from: selectedDate, to: selectedEndDate }
|
|
45
|
+
: selectedDate
|
|
46
|
+
? { from: selectedDate, to: hoverDate || selectedDate }
|
|
47
|
+
: undefined
|
|
48
|
+
: selectedDate;
|
|
49
|
+
const handleSelect = (date) => {
|
|
50
|
+
if (!date) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (isRange && 'from' in date) {
|
|
54
|
+
if (date.from && !date.to) {
|
|
55
|
+
onDayClick(date.from);
|
|
56
|
+
}
|
|
57
|
+
else if (date.from && date.to) {
|
|
58
|
+
onDayClick(date.to);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else if (!isRange && date instanceof Date) {
|
|
62
|
+
onDayClick(date);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
const CustomDayButton = useCallback((props) => {
|
|
66
|
+
return (_jsx(CalendarDayButton, { ...props, onMouseEnter: () => {
|
|
67
|
+
if (isRange && onDayHover && props.day) {
|
|
68
|
+
onDayHover(props.day.date);
|
|
69
|
+
}
|
|
70
|
+
}, onMouseLeave: () => {
|
|
71
|
+
if (isRange && onDayHover) {
|
|
72
|
+
onDayHover(undefined);
|
|
73
|
+
}
|
|
74
|
+
} }));
|
|
75
|
+
}, [isRange, onDayHover]);
|
|
76
|
+
const formatters = {
|
|
77
|
+
formatWeekdayName: (date) => {
|
|
78
|
+
const dayIndex = date.getDay();
|
|
79
|
+
return i18n.weekdaysShort[dayIndex] || i18n.weekdays[dayIndex];
|
|
80
|
+
},
|
|
81
|
+
formatMonthCaption: (date) => {
|
|
82
|
+
const monthIndex = date.getMonth();
|
|
83
|
+
const year = date.getFullYear();
|
|
84
|
+
return `${i18n.months[monthIndex]} ${year}`;
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
const monthCount = isMobile ? 1 : showTwoMonths ? 2 : 1;
|
|
88
|
+
const secondMonth = addMonths(currentMonth, 1);
|
|
89
|
+
const captionClass = 'truncate text-center text-sm font-medium';
|
|
90
|
+
const monthNavRow = onMonthChange && (_jsxs("div", { className: "flex w-full min-w-0 items-center gap-2 pb-2", children: [_jsx(Button, { type: "button", variant: "ghost", className: "size-8.5 shrink-0", onClick: () => onMonthChange(subMonths(currentMonth, 1)), "aria-label": "Previous month", children: _jsx(ChevronLeft, { className: "size-4" }) }), monthCount === 2 ? (_jsxs(_Fragment, { children: [_jsx("div", { className: cn(captionClass, 'min-w-0 flex-1'), children: formatters.formatMonthCaption(currentMonth) }), _jsx("div", { className: cn(captionClass, 'min-w-0 flex-1'), children: formatters.formatMonthCaption(secondMonth) })] })) : (_jsx("div", { className: cn(captionClass, 'min-w-0 flex-1'), children: formatters.formatMonthCaption(currentMonth) })), _jsx(Button, { type: "button", variant: "ghost", className: "size-8.5 shrink-0", onClick: () => onMonthChange(addMonths(currentMonth, 1)), "aria-label": "Next month", children: _jsx(ChevronRight, { className: "size-4" }) }), (() => {
|
|
91
|
+
const today = new Date();
|
|
92
|
+
if (isSameMonth(currentMonth, today))
|
|
93
|
+
return null;
|
|
94
|
+
const isFuture = currentMonth > today;
|
|
95
|
+
return (_jsx(Button, { type: "button", variant: "ghost", className: "size-8.5 shrink-0", onClick: () => onMonthChange(new Date()), title: i18n.today, children: isFuture ? _jsx(CornerUpLeft, { className: "size-4" }) : _jsx(CornerUpRight, { className: "size-4" }) }));
|
|
96
|
+
})()] }));
|
|
97
|
+
const rdpClassNames = getDefaultClassNames();
|
|
98
|
+
const calendarClassNames = {
|
|
99
|
+
root: cn('w-full min-w-0', rdpClassNames.root),
|
|
100
|
+
months: 'flex flex-wrap items-start justify-between gap-5 w-full',
|
|
101
|
+
month: cn('flex w-full min-w-0 flex-1 flex-col items-center', rdpClassNames.month),
|
|
102
|
+
month_grid: cn('w-full min-w-0 border-collapse', rdpClassNames.month_grid),
|
|
103
|
+
nav: 'hidden',
|
|
104
|
+
month_caption: 'hidden',
|
|
105
|
+
};
|
|
106
|
+
return (_jsxs("div", { className: cn('flex w-full flex-col', className), children: [monthNavRow, isRange ? (_jsx(Calendar, { month: currentMonth, mode: "range", selected: selected, onSelect: handleSelect, numberOfMonths: monthCount, showOutsideDays: true, weekStartsOn: weekStartsOn, formatters: formatters, className: "w-full shrink-0 p-0", classNames: calendarClassNames, components: {
|
|
107
|
+
DayButton: CustomDayButton,
|
|
108
|
+
} })) : (_jsx(Calendar, { month: currentMonth, mode: "single", selected: selected, onSelect: handleSelect, numberOfMonths: monthCount, showOutsideDays: true, weekStartsOn: weekStartsOn, formatters: formatters, className: "w-full shrink-0 p-0", classNames: calendarClassNames, components: {
|
|
109
|
+
DayButton: CustomDayButton,
|
|
110
|
+
} }))] }));
|
|
111
|
+
}
|
|
112
|
+
export function DateSelectorPeriodGrid({ years, items, selectedYear, selectedValue, rangeStart, rangeEnd, isInRange, onSelect, columns, className, }) {
|
|
113
|
+
return (_jsx("div", { className: cn('w-full space-y-6', className), children: years.map((year) => (_jsxs("div", { children: [_jsx("div", { className: "sticky top-0 z-10 w-full bg-background py-1 text-center text-sm font-medium text-muted-foreground", children: year }), _jsx("div", { className: "grid gap-2", style: {
|
|
114
|
+
gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,
|
|
115
|
+
}, children: items.map((item, index) => {
|
|
116
|
+
const isSelected = selectedYear === year && selectedValue === index;
|
|
117
|
+
const isRangeStart = rangeStart?.year === year && rangeStart?.value === index;
|
|
118
|
+
const isRangeEnd = rangeEnd?.year === year && rangeEnd?.value === index;
|
|
119
|
+
const inRange = isInRange(year, index);
|
|
120
|
+
return (_jsx(Button, { size: "sm", variant: isSelected || isRangeStart || isRangeEnd ? 'default' : 'outline', className: cn(inRange && !isSelected && !isRangeStart && !isRangeEnd && 'bg-accent dark:bg-accent/60'), onClick: () => onSelect(year, index), children: item }, item));
|
|
121
|
+
}) })] }, year))) }));
|
|
122
|
+
}
|
|
123
|
+
export function DateSelectorYearList({ years, selectedYear, rangeStart, rangeEnd, isYearInRange, onSelect, className }) {
|
|
124
|
+
return (_jsx("div", { className: cn('grid grid-cols-2 gap-2', className), children: years.map((year) => {
|
|
125
|
+
const isSelected = selectedYear === year && !rangeStart && !rangeEnd;
|
|
126
|
+
const isRangeStart = rangeStart?.year === year;
|
|
127
|
+
const isRangeEnd = rangeEnd?.year === year;
|
|
128
|
+
const inRange = isYearInRange(year);
|
|
129
|
+
return (_jsx(Button, { size: "sm", variant: isSelected || isRangeStart || isRangeEnd ? 'default' : 'outline', className: cn(inRange && !isSelected && !isRangeStart && !isRangeEnd && 'bg-accent dark:bg-accent/60'), onClick: () => onSelect(year), children: year }, year));
|
|
130
|
+
}) }));
|
|
131
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/** Strings and labels for all UI copy in {@link DateSelector}; override partially via {@link DateSelectorProps.i18n}. */
|
|
2
|
+
export interface DateSelectorI18nConfig {
|
|
3
|
+
selectDate: string;
|
|
4
|
+
apply: string;
|
|
5
|
+
cancel: string;
|
|
6
|
+
clear: string;
|
|
7
|
+
today: string;
|
|
8
|
+
filterTypes: {
|
|
9
|
+
is: string;
|
|
10
|
+
before: string;
|
|
11
|
+
after: string;
|
|
12
|
+
between: string;
|
|
13
|
+
};
|
|
14
|
+
periodTypes: {
|
|
15
|
+
day: string;
|
|
16
|
+
month: string;
|
|
17
|
+
quarter: string;
|
|
18
|
+
year: string;
|
|
19
|
+
};
|
|
20
|
+
months: string[];
|
|
21
|
+
monthsShort: string[];
|
|
22
|
+
quarters: string[];
|
|
23
|
+
weekdays: string[];
|
|
24
|
+
weekdaysShort: string[];
|
|
25
|
+
placeholder: string;
|
|
26
|
+
rangePlaceholder: string;
|
|
27
|
+
rollingWindowTabs: {
|
|
28
|
+
next: string;
|
|
29
|
+
last: string;
|
|
30
|
+
custom: string;
|
|
31
|
+
};
|
|
32
|
+
rollingSummaryNext: string;
|
|
33
|
+
rollingSummaryLast: string;
|
|
34
|
+
rollingDaysChip: string;
|
|
35
|
+
}
|
|
36
|
+
/** Default English copy for {@link DateSelector}. */
|
|
37
|
+
export declare const DEFAULT_DATE_SELECTOR_I18N: DateSelectorI18nConfig;
|
|
38
|
+
export type DateSelectorPeriodType = 'day' | 'month' | 'quarter' | 'year';
|
|
39
|
+
export type DateSelectorFilterType = 'is' | 'before' | 'after' | 'between';
|
|
40
|
+
export declare const DATE_SELECTOR_ROLLING_DAY_OPTIONS: readonly [3, 7, 14, 30, 60, 90, 180, 365];
|
|
41
|
+
export type DateSelectorRollingDays = (typeof DATE_SELECTOR_ROLLING_DAY_OPTIONS)[number];
|
|
42
|
+
export type DateSelectorSelectionMode = 'custom' | 'rolling-next' | 'rolling-last';
|
|
43
|
+
/** Canonical value emitted by {@link DateSelector} and {@link useDateSelector}; shape depends on `period` and `operator`. */
|
|
44
|
+
export interface DateSelectorValue {
|
|
45
|
+
period: DateSelectorPeriodType;
|
|
46
|
+
operator: DateSelectorFilterType;
|
|
47
|
+
selectionMode?: DateSelectorSelectionMode;
|
|
48
|
+
rollingDays?: DateSelectorRollingDays;
|
|
49
|
+
startDate?: Date;
|
|
50
|
+
endDate?: Date;
|
|
51
|
+
year?: number;
|
|
52
|
+
month?: number;
|
|
53
|
+
quarter?: number;
|
|
54
|
+
rangeStart?: {
|
|
55
|
+
year: number;
|
|
56
|
+
value: number;
|
|
57
|
+
};
|
|
58
|
+
rangeEnd?: {
|
|
59
|
+
year: number;
|
|
60
|
+
value: number;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** Context passed to subcomponents (variant/size/i18n) from {@link DateSelector}. */
|
|
64
|
+
export interface DateSelectorContextValue {
|
|
65
|
+
i18n: DateSelectorI18nConfig;
|
|
66
|
+
variant: 'outline' | 'default';
|
|
67
|
+
size: 'sm' | 'default' | 'lg';
|
|
68
|
+
}
|
|
69
|
+
/** Options for {@link useDateSelector} (headless state); mirrors the core props of {@link DateSelector} without UI. */
|
|
70
|
+
export interface UseDateSelectorOptions {
|
|
71
|
+
value?: DateSelectorValue;
|
|
72
|
+
onChange?: (value: DateSelectorValue) => void;
|
|
73
|
+
defaultPeriodType?: DateSelectorPeriodType;
|
|
74
|
+
defaultFilterType?: DateSelectorFilterType;
|
|
75
|
+
presetMode?: DateSelectorFilterType;
|
|
76
|
+
allowRange?: boolean;
|
|
77
|
+
yearRange?: number;
|
|
78
|
+
baseYear?: number;
|
|
79
|
+
minYear?: number;
|
|
80
|
+
maxYear?: number;
|
|
81
|
+
yearOptions?: readonly number[];
|
|
82
|
+
periodTypes?: DateSelectorPeriodType[];
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Props for the full {@link DateSelector} UI (filter toggles, optional text input, period tabs, and picker surface).
|
|
86
|
+
*
|
|
87
|
+
* **Data model:** `DateSelectorValue` is the emitted filter (period × operator × selection). When `value` is passed,
|
|
88
|
+
* the hook stays in sync via a derived sync key (controlled). When `value` is omitted, state is internal
|
|
89
|
+
* (uncontrolled); typed input still calls `onChange` and, for uncontrolled usage, updates the hook via
|
|
90
|
+
* `syncInternalFromParsedValue`.
|
|
91
|
+
*/
|
|
92
|
+
export interface DateSelectorProps {
|
|
93
|
+
value?: DateSelectorValue;
|
|
94
|
+
onChange?: (value: DateSelectorValue) => void;
|
|
95
|
+
allowRange?: boolean;
|
|
96
|
+
periodTypes?: DateSelectorPeriodType[];
|
|
97
|
+
defaultPeriodType?: DateSelectorPeriodType;
|
|
98
|
+
defaultFilterType?: DateSelectorFilterType;
|
|
99
|
+
presetMode?: DateSelectorFilterType;
|
|
100
|
+
showInput?: boolean;
|
|
101
|
+
showOperators?: boolean;
|
|
102
|
+
showTwoMonths?: boolean;
|
|
103
|
+
label?: string;
|
|
104
|
+
className?: string;
|
|
105
|
+
yearRange?: number;
|
|
106
|
+
baseYear?: number;
|
|
107
|
+
minYear?: number;
|
|
108
|
+
maxYear?: number;
|
|
109
|
+
yearOptions?: readonly number[];
|
|
110
|
+
i18n?: Partial<DateSelectorI18nConfig>;
|
|
111
|
+
inputHint?: string;
|
|
112
|
+
dayDateFormat?: string;
|
|
113
|
+
dayDateFormats?: string[];
|
|
114
|
+
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
115
|
+
showRollingPresets?: boolean;
|
|
116
|
+
rollingDayOptions?: readonly DateSelectorRollingDays[];
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=date-selector-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"date-selector-types.d.ts","sourceRoot":"","sources":["../../../src/components/date-selector/date-selector-types.ts"],"names":[],"mappings":"AAAA,yHAAyH;AACzH,MAAM,WAAW,sBAAsB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE;QACT,EAAE,EAAE,MAAM,CAAC;QACX,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,WAAW,EAAE;QACT,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAClE,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;CAC3B;AAED,qDAAqD;AACrD,eAAO,MAAM,0BAA0B,EAAE,sBA6BxC,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,KAAK,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAC1E,MAAM,MAAM,sBAAsB,GAAG,IAAI,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AAE3E,eAAO,MAAM,iCAAiC,2CAA4C,CAAC;AAC3F,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,iCAAiC,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzF,MAAM,MAAM,yBAAyB,GAAG,QAAQ,GAAG,cAAc,GAAG,cAAc,CAAC;AAEnF,6HAA6H;AAC7H,MAAM,WAAW,iBAAiB;IAC9B,MAAM,EAAE,sBAAsB,CAAC;IAC/B,QAAQ,EAAE,sBAAsB,CAAC;IACjC,aAAa,CAAC,EAAE,yBAAyB,CAAC;IAC1C,WAAW,CAAC,EAAE,uBAAuB,CAAC;IACtC,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,OAAO,CAAC,EAAE,IAAI,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9C;AAED,qFAAqF;AACrF,MAAM,WAAW,wBAAwB;IACrC,IAAI,EAAE,sBAAsB,CAAC;IAC7B,OAAO,EAAE,SAAS,GAAG,SAAS,CAAC;IAC/B,IAAI,EAAE,IAAI,GAAG,SAAS,GAAG,IAAI,CAAC;CACjC;AAED,uHAAuH;AACvH,MAAM,WAAW,sBAAsB;IACnC,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC9C,iBAAiB,CAAC,EAAE,sBAAsB,CAAC;IAC3C,iBAAiB,CAAC,EAAE,sBAAsB,CAAC;IAC3C,UAAU,CAAC,EAAE,sBAAsB,CAAC;IACpC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,WAAW,CAAC,EAAE,sBAAsB,EAAE,CAAC;CAC1C;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAC9B,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC9C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,sBAAsB,EAAE,CAAC;IACvC,iBAAiB,CAAC,EAAE,sBAAsB,CAAC;IAC3C,iBAAiB,CAAC,EAAE,sBAAsB,CAAC;IAC3C,UAAU,CAAC,EAAE,sBAAsB,CAAC;IACpC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,IAAI,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,iBAAiB,CAAC,EAAE,SAAS,uBAAuB,EAAE,CAAC;CAC1D"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Default English copy for {@link DateSelector}. */
|
|
2
|
+
export const DEFAULT_DATE_SELECTOR_I18N = {
|
|
3
|
+
selectDate: 'Select date',
|
|
4
|
+
apply: 'Apply',
|
|
5
|
+
cancel: 'Cancel',
|
|
6
|
+
clear: 'Clear',
|
|
7
|
+
today: 'Today',
|
|
8
|
+
filterTypes: {
|
|
9
|
+
is: 'is',
|
|
10
|
+
before: 'before',
|
|
11
|
+
after: 'after',
|
|
12
|
+
between: 'between',
|
|
13
|
+
},
|
|
14
|
+
periodTypes: {
|
|
15
|
+
day: 'Day',
|
|
16
|
+
month: 'Month',
|
|
17
|
+
quarter: 'Quarter',
|
|
18
|
+
year: 'Year',
|
|
19
|
+
},
|
|
20
|
+
months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
|
|
21
|
+
monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
|
|
22
|
+
quarters: ['Q1', 'Q2', 'Q3', 'Q4'],
|
|
23
|
+
weekdays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
|
|
24
|
+
weekdaysShort: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
|
|
25
|
+
placeholder: 'Select date...',
|
|
26
|
+
rangePlaceholder: 'Select date range...',
|
|
27
|
+
rollingWindowTabs: { next: 'Next', last: 'Last', custom: 'Custom' },
|
|
28
|
+
rollingSummaryNext: 'Next {{count}} days',
|
|
29
|
+
rollingSummaryLast: 'Last {{count}} days',
|
|
30
|
+
rollingDaysChip: '{{count}} days',
|
|
31
|
+
};
|
|
32
|
+
export const DATE_SELECTOR_ROLLING_DAY_OPTIONS = [3, 7, 14, 30, 60, 90, 180, 365];
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type DateSelectorFilterType, type DateSelectorI18nConfig, type DateSelectorPeriodType, type DateSelectorRollingDays, type DateSelectorSelectionMode, type DateSelectorValue } from './date-selector-types';
|
|
2
|
+
/**
|
|
3
|
+
* Computes inclusive calendar date bounds for rolling windows. “Next N” includes today and spans N calendar days.
|
|
4
|
+
* “Last N” includes today and goes back N − 1 days before today (N days total).
|
|
5
|
+
*/
|
|
6
|
+
export declare function computeRollingDateRange(mode: 'rolling-next' | 'rolling-last', days: number, now?: Date): {
|
|
7
|
+
startDate: Date;
|
|
8
|
+
endDate: Date;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Formats a {@link DateSelectorValue} for display using the same rules as the selector’s summary text.
|
|
12
|
+
*/
|
|
13
|
+
export declare function formatDateValue(value: DateSelectorValue, i18n?: DateSelectorI18nConfig, dayDateFormat?: string): string;
|
|
14
|
+
/** Stable fingerprint for a {@link DateSelectorValue} (for sync keys and onChange deduplication). */
|
|
15
|
+
export declare function dateSelectorDataKey(value: DateSelectorValue | undefined): string;
|
|
16
|
+
export declare function computeStateSyncKey(value: DateSelectorValue | undefined, presetMode: DateSelectorFilterType | undefined, defaultFilterType: DateSelectorFilterType, validDefaultPeriodType: DateSelectorPeriodType): string;
|
|
17
|
+
/** Full local UI state for {@link useDateSelector} (calendar month / hover are not part of {@link DateSelectorValue}). */
|
|
18
|
+
export interface DateSelectorInternalState {
|
|
19
|
+
periodType: DateSelectorPeriodType;
|
|
20
|
+
filterType: DateSelectorFilterType;
|
|
21
|
+
selectedDate: Date | undefined;
|
|
22
|
+
selectedEndDate: Date | undefined;
|
|
23
|
+
calendarMonth: Date;
|
|
24
|
+
selectedYear: number | undefined;
|
|
25
|
+
selectedMonth: number | undefined;
|
|
26
|
+
selectedQuarter: number | undefined;
|
|
27
|
+
rangeStart: {
|
|
28
|
+
year: number;
|
|
29
|
+
value: number;
|
|
30
|
+
} | undefined;
|
|
31
|
+
rangeEnd: {
|
|
32
|
+
year: number;
|
|
33
|
+
value: number;
|
|
34
|
+
} | undefined;
|
|
35
|
+
hoverDate: Date | undefined;
|
|
36
|
+
selectionMode: DateSelectorSelectionMode;
|
|
37
|
+
rollingDays: DateSelectorRollingDays | undefined;
|
|
38
|
+
}
|
|
39
|
+
export declare function createInitialInternalState(value: DateSelectorValue | undefined, validDefaultPeriodType: DateSelectorPeriodType, defaultFilterType: DateSelectorFilterType, presetMode: DateSelectorFilterType | undefined): DateSelectorInternalState;
|
|
40
|
+
export declare function buildRollingValueFromState(selectionMode: DateSelectorSelectionMode, rollingDays: DateSelectorRollingDays | undefined): DateSelectorValue | undefined;
|
|
41
|
+
export declare function buildCurrentValueFromInternal(s: DateSelectorInternalState, presetMode: DateSelectorFilterType | undefined): DateSelectorValue;
|
|
42
|
+
/** Combined UI state + last emitted value fingerprint for `onChange` deduplication. */
|
|
43
|
+
export interface DateSelectorHookState {
|
|
44
|
+
internal: DateSelectorInternalState;
|
|
45
|
+
lastEmittedDataKey: string;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=date-selector-value.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"date-selector-value.d.ts","sourceRoot":"","sources":["../../../src/components/date-selector/date-selector-value.ts"],"names":[],"mappings":"AAEA,OAAO,EACH,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,iBAAiB,EAEzB,MAAM,uBAAuB,CAAC;AAE/B;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,cAAc,GAAG,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,GAAE,IAAiB,GAAG;IAAE,SAAS,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,IAAI,CAAA;CAAE,CAYvJ;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC3B,KAAK,EAAE,iBAAiB,EACxB,IAAI,GAAE,sBAAmD,EACzD,aAAa,GAAE,MAAqB,GACrC,MAAM,CAuDR;AAED,qGAAqG;AACrG,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,iBAAiB,GAAG,SAAS,GAAG,MAAM,CAgBhF;AAED,wBAAgB,mBAAmB,CAC/B,KAAK,EAAE,iBAAiB,GAAG,SAAS,EACpC,UAAU,EAAE,sBAAsB,GAAG,SAAS,EAC9C,iBAAiB,EAAE,sBAAsB,EACzC,sBAAsB,EAAE,sBAAsB,GAC/C,MAAM,CAER;AAED,0HAA0H;AAC1H,MAAM,WAAW,yBAAyB;IACtC,UAAU,EAAE,sBAAsB,CAAC;IACnC,UAAU,EAAE,sBAAsB,CAAC;IACnC,YAAY,EAAE,IAAI,GAAG,SAAS,CAAC;IAC/B,eAAe,EAAE,IAAI,GAAG,SAAS,CAAC;IAClC,aAAa,EAAE,IAAI,CAAC;IACpB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,UAAU,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IACxD,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IACtD,SAAS,EAAE,IAAI,GAAG,SAAS,CAAC;IAC5B,aAAa,EAAE,yBAAyB,CAAC;IACzC,WAAW,EAAE,uBAAuB,GAAG,SAAS,CAAC;CACpD;AAED,wBAAgB,0BAA0B,CACtC,KAAK,EAAE,iBAAiB,GAAG,SAAS,EACpC,sBAAsB,EAAE,sBAAsB,EAC9C,iBAAiB,EAAE,sBAAsB,EACzC,UAAU,EAAE,sBAAsB,GAAG,SAAS,GAC/C,yBAAyB,CAoD3B;AAED,wBAAgB,0BAA0B,CACtC,aAAa,EAAE,yBAAyB,EACxC,WAAW,EAAE,uBAAuB,GAAG,SAAS,GACjD,iBAAiB,GAAG,SAAS,CAoB/B;AAED,wBAAgB,6BAA6B,CAAC,CAAC,EAAE,yBAAyB,EAAE,UAAU,EAAE,sBAAsB,GAAG,SAAS,GAAG,iBAAiB,CAc7I;AAED,uFAAuF;AACvF,MAAM,WAAW,qBAAqB;IAClC,QAAQ,EAAE,yBAAyB,CAAC;IACpC,kBAAkB,EAAE,MAAM,CAAC;CAC9B"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { addDays, format, startOfDay, subDays } from 'date-fns';
|
|
2
|
+
import { DEFAULT_DATE_SELECTOR_I18N, } from './date-selector-types';
|
|
3
|
+
/**
|
|
4
|
+
* Computes inclusive calendar date bounds for rolling windows. “Next N” includes today and spans N calendar days.
|
|
5
|
+
* “Last N” includes today and goes back N − 1 days before today (N days total).
|
|
6
|
+
*/
|
|
7
|
+
export function computeRollingDateRange(mode, days, now = new Date()) {
|
|
8
|
+
const today = startOfDay(now);
|
|
9
|
+
if (mode === 'rolling-next') {
|
|
10
|
+
return {
|
|
11
|
+
startDate: today,
|
|
12
|
+
endDate: startOfDay(addDays(today, days - 1)),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
startDate: startOfDay(subDays(today, days - 1)),
|
|
17
|
+
endDate: today,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Formats a {@link DateSelectorValue} for display using the same rules as the selector’s summary text.
|
|
22
|
+
*/
|
|
23
|
+
export function formatDateValue(value, i18n = DEFAULT_DATE_SELECTOR_I18N, dayDateFormat = 'MM/dd/yyyy') {
|
|
24
|
+
const { period, selectionMode, rollingDays, startDate, endDate, year, month, quarter, rangeStart, rangeEnd } = value;
|
|
25
|
+
if ((selectionMode === 'rolling-next' || selectionMode === 'rolling-last') && rollingDays !== undefined) {
|
|
26
|
+
const label = selectionMode === 'rolling-next'
|
|
27
|
+
? i18n.rollingSummaryNext.replace('{{count}}', String(rollingDays))
|
|
28
|
+
: i18n.rollingSummaryLast.replace('{{count}}', String(rollingDays));
|
|
29
|
+
if (startDate && endDate) {
|
|
30
|
+
return `${label} (${format(startDate, dayDateFormat)} – ${format(endDate, dayDateFormat)})`;
|
|
31
|
+
}
|
|
32
|
+
return label;
|
|
33
|
+
}
|
|
34
|
+
if (period === 'day') {
|
|
35
|
+
if (startDate && endDate) {
|
|
36
|
+
return `${format(startDate, dayDateFormat)} - ${format(endDate, dayDateFormat)}`;
|
|
37
|
+
}
|
|
38
|
+
if (startDate) {
|
|
39
|
+
return format(startDate, dayDateFormat);
|
|
40
|
+
}
|
|
41
|
+
return '';
|
|
42
|
+
}
|
|
43
|
+
if (period === 'month') {
|
|
44
|
+
if (rangeStart && rangeEnd) {
|
|
45
|
+
return `${i18n.monthsShort[rangeStart.value]} ${rangeStart.year} - ${i18n.monthsShort[rangeEnd.value]} ${rangeEnd.year}`;
|
|
46
|
+
}
|
|
47
|
+
if (year !== undefined && month !== undefined) {
|
|
48
|
+
return `${i18n.monthsShort[month]} ${year}`;
|
|
49
|
+
}
|
|
50
|
+
return '';
|
|
51
|
+
}
|
|
52
|
+
if (period === 'quarter') {
|
|
53
|
+
if (rangeStart && rangeEnd) {
|
|
54
|
+
return `${i18n.quarters[rangeStart.value]} ${rangeStart.year} - ${i18n.quarters[rangeEnd.value]} ${rangeEnd.year}`;
|
|
55
|
+
}
|
|
56
|
+
if (year !== undefined && quarter !== undefined) {
|
|
57
|
+
return `${i18n.quarters[quarter]} ${year}`;
|
|
58
|
+
}
|
|
59
|
+
return '';
|
|
60
|
+
}
|
|
61
|
+
if (period === 'year') {
|
|
62
|
+
if (rangeStart && rangeEnd) {
|
|
63
|
+
return `${rangeStart.year} - ${rangeEnd.year}`;
|
|
64
|
+
}
|
|
65
|
+
if (year !== undefined) {
|
|
66
|
+
return `${year}`;
|
|
67
|
+
}
|
|
68
|
+
return '';
|
|
69
|
+
}
|
|
70
|
+
return '';
|
|
71
|
+
}
|
|
72
|
+
/** Stable fingerprint for a {@link DateSelectorValue} (for sync keys and onChange deduplication). */
|
|
73
|
+
export function dateSelectorDataKey(value) {
|
|
74
|
+
if (value === undefined)
|
|
75
|
+
return '__uc__';
|
|
76
|
+
const v = value;
|
|
77
|
+
return [
|
|
78
|
+
v.period,
|
|
79
|
+
v.operator,
|
|
80
|
+
v.selectionMode ?? '',
|
|
81
|
+
v.rollingDays ?? '',
|
|
82
|
+
v.year ?? '',
|
|
83
|
+
v.month ?? '',
|
|
84
|
+
v.quarter ?? '',
|
|
85
|
+
v.startDate?.getTime() ?? '',
|
|
86
|
+
v.endDate?.getTime() ?? '',
|
|
87
|
+
v.rangeStart ? `${v.rangeStart.year}-${v.rangeStart.value}` : '',
|
|
88
|
+
v.rangeEnd ? `${v.rangeEnd.year}-${v.rangeEnd.value}` : '',
|
|
89
|
+
].join('|');
|
|
90
|
+
}
|
|
91
|
+
export function computeStateSyncKey(value, presetMode, defaultFilterType, validDefaultPeriodType) {
|
|
92
|
+
return `${dateSelectorDataKey(value)}|${presetMode ?? ''}|${defaultFilterType}|${validDefaultPeriodType}`;
|
|
93
|
+
}
|
|
94
|
+
export function createInitialInternalState(value, validDefaultPeriodType, defaultFilterType, presetMode) {
|
|
95
|
+
const calendarMonth = value?.startDate ?? new Date();
|
|
96
|
+
if (!value) {
|
|
97
|
+
return {
|
|
98
|
+
periodType: validDefaultPeriodType,
|
|
99
|
+
filterType: presetMode ?? defaultFilterType,
|
|
100
|
+
selectedDate: undefined,
|
|
101
|
+
selectedEndDate: undefined,
|
|
102
|
+
calendarMonth,
|
|
103
|
+
selectedYear: undefined,
|
|
104
|
+
selectedMonth: undefined,
|
|
105
|
+
selectedQuarter: undefined,
|
|
106
|
+
rangeStart: undefined,
|
|
107
|
+
rangeEnd: undefined,
|
|
108
|
+
hoverDate: undefined,
|
|
109
|
+
selectionMode: 'custom',
|
|
110
|
+
rollingDays: undefined,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
const filterType = presetMode ?? value.operator ?? defaultFilterType;
|
|
114
|
+
if (value.selectionMode === 'rolling-next' || value.selectionMode === 'rolling-last') {
|
|
115
|
+
return {
|
|
116
|
+
periodType: value.period || validDefaultPeriodType,
|
|
117
|
+
filterType,
|
|
118
|
+
selectedDate: undefined,
|
|
119
|
+
selectedEndDate: undefined,
|
|
120
|
+
calendarMonth,
|
|
121
|
+
selectedYear: value.year,
|
|
122
|
+
selectedMonth: value.month,
|
|
123
|
+
selectedQuarter: value.quarter,
|
|
124
|
+
rangeStart: value.rangeStart,
|
|
125
|
+
rangeEnd: value.rangeEnd,
|
|
126
|
+
hoverDate: undefined,
|
|
127
|
+
selectionMode: value.selectionMode,
|
|
128
|
+
rollingDays: value.rollingDays,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
periodType: value.period || validDefaultPeriodType,
|
|
133
|
+
filterType,
|
|
134
|
+
selectedYear: value.year,
|
|
135
|
+
selectedMonth: value.month,
|
|
136
|
+
selectedQuarter: value.quarter,
|
|
137
|
+
rangeStart: value.rangeStart,
|
|
138
|
+
rangeEnd: value.rangeEnd,
|
|
139
|
+
hoverDate: undefined,
|
|
140
|
+
selectionMode: 'custom',
|
|
141
|
+
rollingDays: undefined,
|
|
142
|
+
selectedDate: value.startDate,
|
|
143
|
+
selectedEndDate: value.endDate,
|
|
144
|
+
calendarMonth,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
export function buildRollingValueFromState(selectionMode, rollingDays) {
|
|
148
|
+
if (selectionMode !== 'rolling-next' && selectionMode !== 'rolling-last') {
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
if (rollingDays === undefined) {
|
|
152
|
+
return {
|
|
153
|
+
period: 'day',
|
|
154
|
+
operator: 'between',
|
|
155
|
+
selectionMode,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
const { startDate: rs, endDate: re } = computeRollingDateRange(selectionMode === 'rolling-next' ? 'rolling-next' : 'rolling-last', rollingDays, new Date());
|
|
159
|
+
return {
|
|
160
|
+
period: 'day',
|
|
161
|
+
operator: 'between',
|
|
162
|
+
selectionMode,
|
|
163
|
+
rollingDays,
|
|
164
|
+
startDate: rs,
|
|
165
|
+
endDate: re,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
export function buildCurrentValueFromInternal(s, presetMode) {
|
|
169
|
+
const rolling = buildRollingValueFromState(s.selectionMode, s.rollingDays);
|
|
170
|
+
if (rolling)
|
|
171
|
+
return rolling;
|
|
172
|
+
return {
|
|
173
|
+
period: s.periodType,
|
|
174
|
+
operator: presetMode ?? s.filterType,
|
|
175
|
+
startDate: s.selectedDate,
|
|
176
|
+
endDate: s.selectedEndDate,
|
|
177
|
+
year: s.selectedYear,
|
|
178
|
+
month: s.selectedMonth,
|
|
179
|
+
quarter: s.selectedQuarter,
|
|
180
|
+
rangeStart: s.rangeStart,
|
|
181
|
+
rangeEnd: s.rangeEnd,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type DateSelectorProps } from './date-selector-types';
|
|
2
|
+
/**
|
|
3
|
+
* Composite filter control for dates and calendar periods. Root element sets `data-slot="date-selector"`.
|
|
4
|
+
*/
|
|
5
|
+
export declare function DateSelector({ value, onChange, allowRange, periodTypes, defaultPeriodType, defaultFilterType, presetMode, showInput, showOperators, showTwoMonths, label, className, yearRange, baseYear, minYear, maxYear, yearOptions, i18n: i18nOverride, inputHint, dayDateFormat, dayDateFormats, weekStartsOn, showRollingPresets, rollingDayOptions, }: DateSelectorProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
//# sourceMappingURL=date-selector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"date-selector.d.ts","sourceRoot":"","sources":["../../../src/components/date-selector/date-selector.tsx"],"names":[],"mappings":"AAsBA,OAAO,EAAqC,KAAK,iBAAiB,EAAsD,MAAM,uBAAuB,CAAC;AAItJ;;GAEG;AACH,wBAAgB,YAAY,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,UAAiB,EACjB,WAAW,EACX,iBAAyB,EACzB,iBAAwB,EACxB,UAAU,EACV,SAAgB,EAChB,aAAoB,EACpB,aAAqB,EACrB,KAAK,EACL,SAAS,EACT,SAAa,EACb,QAAQ,EACR,OAAc,EACd,OAAc,EACd,WAAW,EACX,IAAI,EAAE,YAAY,EAClB,SAAS,EACT,aAA4B,EAC5B,cAAc,EACd,YAAY,EACZ,kBAA0B,EAC1B,iBAAqD,GACxD,EAAE,iBAAiB,2CA6TnB"}
|