@wheelhouse/ui 0.2.2 → 0.2.4
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/blocks/columns/columns-types.d.ts +40 -0
- package/dist/blocks/columns/columns-types.d.ts.map +1 -0
- package/dist/blocks/columns/columns-types.js +10 -0
- package/dist/blocks/columns/columns-utils.d.ts +13 -0
- package/dist/blocks/columns/columns-utils.d.ts.map +1 -0
- package/dist/blocks/columns/columns-utils.js +85 -0
- package/dist/blocks/columns/columns.d.ts +3 -0
- package/dist/blocks/columns/columns.d.ts.map +1 -0
- package/dist/blocks/columns/columns.js +79 -0
- package/dist/blocks/columns/columns.stories.d.ts +12 -0
- package/dist/blocks/columns/columns.stories.d.ts.map +1 -0
- package/dist/blocks/columns/columns.stories.js +67 -0
- package/dist/blocks/columns/index.d.ts +6 -0
- package/dist/blocks/columns/index.d.ts.map +1 -0
- package/dist/blocks/columns/index.js +3 -0
- package/dist/blocks/date-selector/date-selector-context.d.ts.map +1 -0
- package/dist/blocks/date-selector/date-selector-default-i18n.d.ts +10 -0
- package/dist/blocks/date-selector/date-selector-default-i18n.d.ts.map +1 -0
- package/dist/blocks/date-selector/date-selector-default-i18n.js +29 -0
- package/dist/blocks/date-selector/date-selector-i18n-resources.d.ts +11 -0
- package/dist/blocks/date-selector/date-selector-i18n-resources.d.ts.map +1 -0
- package/dist/blocks/date-selector/date-selector-i18n-resources.js +248 -0
- package/dist/blocks/date-selector/date-selector-i18n.shared.d.ts +12 -0
- package/dist/blocks/date-selector/date-selector-i18n.shared.d.ts.map +1 -0
- package/dist/blocks/date-selector/date-selector-i18n.shared.js +84 -0
- package/dist/{components → blocks}/date-selector/date-selector-parts.d.ts +9 -0
- package/dist/blocks/date-selector/date-selector-parts.d.ts.map +1 -0
- package/dist/{components → blocks}/date-selector/date-selector-parts.js +21 -6
- package/dist/{components → blocks}/date-selector/date-selector-types.d.ts +70 -0
- package/dist/blocks/date-selector/date-selector-types.d.ts.map +1 -0
- package/dist/{components → blocks}/date-selector/date-selector-types.js +22 -0
- package/dist/blocks/date-selector/date-selector-value.d.ts +81 -0
- package/dist/blocks/date-selector/date-selector-value.d.ts.map +1 -0
- package/dist/blocks/date-selector/date-selector-value.js +423 -0
- package/dist/{components → blocks}/date-selector/date-selector.d.ts +1 -1
- package/dist/blocks/date-selector/date-selector.d.ts.map +1 -0
- package/dist/blocks/date-selector/date-selector.js +191 -0
- package/dist/{components → blocks}/date-selector/date-selector.stories.d.ts +14 -0
- package/dist/blocks/date-selector/date-selector.stories.d.ts.map +1 -0
- package/dist/blocks/date-selector/date-selector.stories.js +299 -0
- package/dist/blocks/date-selector/index.d.ts +11 -0
- package/dist/blocks/date-selector/index.d.ts.map +1 -0
- package/dist/blocks/date-selector/index.js +8 -0
- package/dist/{components → blocks}/date-selector/use-date-selector.d.ts +4 -3
- package/dist/blocks/date-selector/use-date-selector.d.ts.map +1 -0
- package/dist/{components → blocks}/date-selector/use-date-selector.js +14 -8
- package/dist/blocks/floating-menu-widget/floating-menu-widget.d.ts +26 -0
- package/dist/blocks/floating-menu-widget/floating-menu-widget.d.ts.map +1 -0
- package/dist/blocks/floating-menu-widget/floating-menu-widget.js +200 -0
- package/dist/blocks/floating-menu-widget/floating-menu-widget.stories.d.ts +15 -0
- package/dist/blocks/floating-menu-widget/floating-menu-widget.stories.d.ts.map +1 -0
- package/dist/blocks/floating-menu-widget/floating-menu-widget.stories.js +22 -0
- package/dist/blocks/floating-menu-widget/index.d.ts +3 -0
- package/dist/blocks/floating-menu-widget/index.d.ts.map +1 -0
- package/dist/blocks/floating-menu-widget/index.js +1 -0
- package/dist/blocks/index.d.ts +5 -0
- package/dist/blocks/index.d.ts.map +1 -0
- package/dist/blocks/index.js +4 -0
- package/dist/blocks/navigation/index.d.ts +5 -0
- package/dist/blocks/navigation/index.d.ts.map +1 -0
- package/dist/blocks/navigation/index.js +2 -0
- package/dist/blocks/navigation/navigation-types.d.ts +60 -0
- package/dist/blocks/navigation/navigation-types.d.ts.map +1 -0
- package/dist/blocks/navigation/navigation-types.js +1 -0
- package/dist/blocks/navigation/navigation.d.ts +9 -0
- package/dist/blocks/navigation/navigation.d.ts.map +1 -0
- package/dist/blocks/navigation/navigation.demo.d.ts +4 -0
- package/dist/blocks/navigation/navigation.demo.d.ts.map +1 -0
- package/dist/blocks/navigation/navigation.demo.js +46 -0
- package/dist/blocks/navigation/navigation.js +98 -0
- package/dist/blocks/navigation/navigation.stories.d.ts +14 -0
- package/dist/blocks/navigation/navigation.stories.d.ts.map +1 -0
- package/dist/blocks/navigation/navigation.stories.js +16 -0
- package/dist/components/accordion/accordion.stories.js +1 -1
- package/dist/components/alert/alert.stories.js +1 -1
- package/dist/components/alert-dialog/alert-dialog.stories.js +1 -1
- package/dist/components/aspect-ratio/aspect-ratio.stories.js +1 -1
- package/dist/components/avatar/avatar.stories.js +1 -1
- package/dist/components/badge/badge.stories.js +1 -1
- package/dist/components/breadcrumb/breadcrumb.stories.js +1 -1
- package/dist/components/button/button.d.ts +18 -11
- package/dist/components/button/button.d.ts.map +1 -1
- package/dist/components/button/button.js +27 -14
- package/dist/components/button/button.stories.d.ts +11 -0
- package/dist/components/button/button.stories.d.ts.map +1 -1
- package/dist/components/button/button.stories.js +85 -1
- package/dist/components/button-group/button-group.d.ts +10 -4
- package/dist/components/button-group/button-group.d.ts.map +1 -1
- package/dist/components/button-group/button-group.js +15 -3
- package/dist/components/button-group/button-group.stories.js +1 -1
- package/dist/components/button-group/index.d.ts +2 -2
- package/dist/components/button-group/index.d.ts.map +1 -1
- package/dist/components/button-group/index.js +1 -1
- package/dist/components/calendar/calendar.stories.js +1 -1
- package/dist/components/card/card.stories.js +1 -1
- package/dist/components/checkbox/checkbox.stories.js +1 -1
- package/dist/components/collapsible/collapsible.stories.js +1 -1
- package/dist/components/combobox/combobox.stories.js +1 -1
- package/dist/components/command/command.stories.js +1 -1
- package/dist/components/context-menu/context-menu.stories.js +1 -1
- package/dist/components/dialog/dialog.stories.js +1 -1
- package/dist/components/direction/direction.stories.js +1 -1
- package/dist/components/drawer/drawer.stories.js +1 -1
- package/dist/components/dropdown-menu/dropdown-menu.d.ts +9 -2
- package/dist/components/dropdown-menu/dropdown-menu.d.ts.map +1 -1
- package/dist/components/dropdown-menu/dropdown-menu.js +4 -1
- package/dist/components/dropdown-menu/dropdown-menu.stories.js +1 -1
- package/dist/components/dropdown-menu/index.d.ts +2 -2
- package/dist/components/dropdown-menu/index.d.ts.map +1 -1
- package/dist/components/dropdown-menu/index.js +1 -1
- package/dist/components/empty/empty.stories.js +1 -1
- package/dist/components/field/field.stories.js +1 -1
- package/dist/components/filters/filter-date-metric-value.d.ts +32 -0
- package/dist/components/filters/filter-date-metric-value.d.ts.map +1 -0
- package/dist/components/filters/filter-date-metric-value.js +406 -0
- package/dist/components/filters/filter-fields-listing-demo.d.ts +12 -0
- package/dist/components/filters/filter-fields-listing-demo.d.ts.map +1 -0
- package/dist/components/filters/filter-fields-listing-demo.js +565 -0
- package/dist/components/filters/filters-defaults.d.ts +4 -0
- package/dist/components/filters/filters-defaults.d.ts.map +1 -1
- package/dist/components/filters/filters-defaults.js +59 -1
- package/dist/components/filters/filters-i18n-resources.d.ts +277 -0
- package/dist/components/filters/filters-i18n-resources.d.ts.map +1 -0
- package/dist/components/filters/filters-i18n-resources.js +276 -0
- package/dist/components/filters/filters-i18n.shared.d.ts +16 -0
- package/dist/components/filters/filters-i18n.shared.d.ts.map +1 -0
- package/dist/components/filters/filters-i18n.shared.js +111 -0
- package/dist/components/filters/filters-types.d.ts +40 -1
- package/dist/components/filters/filters-types.d.ts.map +1 -1
- package/dist/components/filters/filters-utils.d.ts +28 -1
- package/dist/components/filters/filters-utils.d.ts.map +1 -1
- package/dist/components/filters/filters-utils.js +102 -0
- package/dist/components/filters/filters.d.ts +21 -3
- package/dist/components/filters/filters.d.ts.map +1 -1
- package/dist/components/filters/filters.js +493 -290
- package/dist/components/filters/filters.stories.d.ts +107 -2
- package/dist/components/filters/filters.stories.d.ts.map +1 -1
- package/dist/components/filters/filters.stories.js +224 -30
- package/dist/components/filters/index.d.ts +4 -1
- package/dist/components/filters/index.d.ts.map +1 -1
- package/dist/components/filters/index.js +4 -1
- package/dist/components/frame/frame.stories.js +1 -1
- package/dist/components/hover-card/hover-card.stories.js +1 -1
- package/dist/components/index.d.ts +2 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +2 -2
- package/dist/components/input/input.stories.js +1 -1
- package/dist/components/input-group/input-group.stories.js +1 -1
- package/dist/components/item/item.stories.js +1 -1
- package/dist/components/kbd/kbd.stories.js +1 -1
- package/dist/components/label/label.stories.js +1 -1
- package/dist/components/menubar/menubar.stories.js +1 -1
- package/dist/components/native-select/native-select.stories.js +1 -1
- package/dist/components/navigation-menu/navigation-menu.stories.js +1 -1
- package/dist/components/pagination/pagination.stories.js +1 -1
- package/dist/components/popover/index.d.ts +1 -0
- package/dist/components/popover/index.d.ts.map +1 -1
- package/dist/components/popover/index.js +1 -0
- package/dist/components/popover/popover-handle.d.ts +6 -0
- package/dist/components/popover/popover-handle.d.ts.map +1 -0
- package/dist/components/popover/popover-handle.js +6 -0
- package/dist/components/popover/popover.d.ts +41 -7
- package/dist/components/popover/popover.d.ts.map +1 -1
- package/dist/components/popover/popover.js +50 -3
- package/dist/components/popover/popover.stories.js +1 -1
- package/dist/components/progress/progress.js +1 -1
- package/dist/components/progress/progress.stories.d.ts +11 -2
- package/dist/components/progress/progress.stories.d.ts.map +1 -1
- package/dist/components/progress/progress.stories.js +78 -5
- package/dist/components/radio-group/radio-group.stories.js +1 -1
- package/dist/components/resizable/resizable.stories.js +1 -1
- package/dist/components/scroll-area/scroll-area.stories.js +1 -1
- package/dist/components/select/select.stories.js +1 -1
- package/dist/components/separator/separator.stories.js +1 -1
- package/dist/components/sheet/sheet.stories.js +1 -1
- package/dist/components/sidebar/index.d.ts +2 -0
- package/dist/components/sidebar/index.d.ts.map +1 -0
- package/dist/components/sidebar/index.js +1 -0
- package/dist/components/sidebar/sidebar.d.ts +64 -0
- package/dist/components/sidebar/sidebar.d.ts.map +1 -0
- package/dist/components/sidebar/sidebar.js +255 -0
- package/dist/components/sidebar/sidebar.stories.d.ts +20 -0
- package/dist/components/sidebar/sidebar.stories.d.ts.map +1 -0
- package/dist/components/sidebar/sidebar.stories.js +184 -0
- package/dist/components/skeleton/index.d.ts +3 -0
- package/dist/components/skeleton/index.d.ts.map +1 -0
- package/dist/components/skeleton/index.js +1 -0
- package/dist/components/skeleton/skeleton.d.ts +7 -0
- package/dist/components/skeleton/skeleton.d.ts.map +1 -0
- package/dist/components/skeleton/skeleton.js +8 -0
- package/dist/components/slider/slider.stories.js +1 -1
- package/dist/components/sonner/sonner.stories.js +1 -1
- package/dist/components/sortable/sortable.stories.js +1 -1
- package/dist/components/spinner/spinner.stories.js +1 -1
- package/dist/components/status-indicator/status-indicator.stories.js +1 -1
- package/dist/components/switch/switch.stories.js +1 -1
- package/dist/components/tabs/tabs.stories.js +1 -1
- package/dist/components/text/text.stories.js +1 -1
- package/dist/components/textarea/textarea.stories.js +1 -1
- package/dist/components/toggle/toggle.stories.js +1 -1
- package/dist/components/toggle-group/toggle-group.stories.js +1 -1
- package/dist/components/tooltip/tooltip.stories.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/llms.txt +10 -5
- package/package.json +8 -4
- package/dist/components/date-selector/date-selector-context.d.ts.map +0 -1
- package/dist/components/date-selector/date-selector-parts.d.ts.map +0 -1
- package/dist/components/date-selector/date-selector-types.d.ts.map +0 -1
- package/dist/components/date-selector/date-selector-value.d.ts +0 -47
- package/dist/components/date-selector/date-selector-value.d.ts.map +0 -1
- package/dist/components/date-selector/date-selector-value.js +0 -183
- package/dist/components/date-selector/date-selector.d.ts.map +0 -1
- package/dist/components/date-selector/date-selector.js +0 -144
- package/dist/components/date-selector/date-selector.stories.d.ts.map +0 -1
- package/dist/components/date-selector/date-selector.stories.js +0 -144
- package/dist/components/date-selector/index.d.ts +0 -7
- package/dist/components/date-selector/index.d.ts.map +0 -1
- package/dist/components/date-selector/index.js +0 -5
- package/dist/components/date-selector/use-date-selector.d.ts.map +0 -1
- package/dist/components/navigation-pattern-1/index.d.ts +0 -3
- package/dist/components/navigation-pattern-1/index.d.ts.map +0 -1
- package/dist/components/navigation-pattern-1/index.js +0 -1
- package/dist/components/navigation-pattern-1/pattern-1.config.d.ts +0 -47
- package/dist/components/navigation-pattern-1/pattern-1.config.d.ts.map +0 -1
- package/dist/components/navigation-pattern-1/pattern-1.config.js +0 -55
- package/dist/components/navigation-pattern-1/pattern-1.d.ts +0 -7
- package/dist/components/navigation-pattern-1/pattern-1.d.ts.map +0 -1
- package/dist/components/navigation-pattern-1/pattern-1.js +0 -83
- package/dist/components/navigation-pattern-1/pattern-1.stories.d.ts +0 -16
- package/dist/components/navigation-pattern-1/pattern-1.stories.d.ts.map +0 -1
- package/dist/components/navigation-pattern-1/pattern-1.stories.js +0 -20
- /package/dist/{components → blocks}/date-selector/date-selector-context.d.ts +0 -0
- /package/dist/{components → blocks}/date-selector/date-selector-context.js +0 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* Rich date / period filter: day through year granularity, filter operators (is / before / after / between), optional free-text input,
|
|
5
|
+
* and shared state via {@link useDateSelector}. Built on `Calendar`, tabs, and `ScrollArea`.
|
|
6
|
+
*
|
|
7
|
+
* Implementation is split across `date-selector-types`, `date-selector-value`, `use-date-selector`, `date-selector-context`,
|
|
8
|
+
* and `date-selector-parts` for maintainability.
|
|
9
|
+
*/
|
|
10
|
+
import { useCallback, useContext, useLayoutEffect, useMemo, useState } from 'react';
|
|
11
|
+
import { parse } from 'date-fns';
|
|
12
|
+
import { I18nContext, useTranslation } from 'react-i18next';
|
|
13
|
+
import { cn } from '../../lib/utils';
|
|
14
|
+
import { Button } from '../../components/button';
|
|
15
|
+
import { Input } from '../../components/input';
|
|
16
|
+
import { ScrollArea } from '../../components/scroll-area';
|
|
17
|
+
import { Tabs, TabsList, TabsTrigger } from '../../components/tabs';
|
|
18
|
+
import { X } from 'lucide-react';
|
|
19
|
+
import { DateSelectorContext } from './date-selector-context';
|
|
20
|
+
import { DateSelectorDayPicker, DateSelectorFilterToggle, DateSelectorGranularityTabs, DateSelectorPeriodGrid, DateSelectorPeriodTabs, DateSelectorYearList, } from './date-selector-parts';
|
|
21
|
+
import { getDateSelectorDefaultI18n } from './date-selector-default-i18n';
|
|
22
|
+
import { buildDateSelectorI18nFromT, registerDateSelectorI18n } from './date-selector-i18n.shared';
|
|
23
|
+
import { DATE_SELECTOR_NAMESPACE } from './date-selector-i18n-resources';
|
|
24
|
+
import { DATE_SELECTOR_ROLLING_DAY_OPTIONS, DATE_SELECTOR_ROLLING_MONTH_OPTIONS, DATE_SELECTOR_ROLLING_QUARTER_OPTIONS, DATE_SELECTOR_ROLLING_YEAR_OPTIONS, } from './date-selector-types';
|
|
25
|
+
import { formatDateValue } from './date-selector-value';
|
|
26
|
+
import { useDateSelector } from './use-date-selector';
|
|
27
|
+
/**
|
|
28
|
+
* Composite filter control for dates and calendar periods. Root element sets `data-slot="date-selector"`.
|
|
29
|
+
*/
|
|
30
|
+
export function DateSelector({ value, onChange, allowRange = true, periodTypes, defaultPeriodType = 'day', defaultFilterType = 'is', presetMode, showInput = true, showOperators = true, showTwoMonths = false, label, className, yearRange = 5, baseYear, minYear = 2024, maxYear = 2028, yearOptions, i18n: i18nOverride, i18nInstance: i18nInstanceProp, inputHint, dayDateFormat = 'MM/dd/yyyy', dayDateFormats, weekStartsOn, showRollingPresets = false, rollingDayOptions = DATE_SELECTOR_ROLLING_DAY_OPTIONS, rollingMonthOptions = DATE_SELECTOR_ROLLING_MONTH_OPTIONS, rollingQuarterOptions = DATE_SELECTOR_ROLLING_QUARTER_OPTIONS, rollingYearOptions = DATE_SELECTOR_ROLLING_YEAR_OPTIONS, fillHeight = false, separateDayPeriod = false, }) {
|
|
31
|
+
// Resolve the i18next instance: explicit prop wins, then nearest I18nextProvider, else a package default
|
|
32
|
+
// (bundled `dateSelector` resources) so the block works without a provider in tests / minimal apps.
|
|
33
|
+
const i18nFromCtx = useContext(I18nContext)?.i18n;
|
|
34
|
+
const i18nResolved = i18nInstanceProp ?? i18nFromCtx ?? getDateSelectorDefaultI18n();
|
|
35
|
+
// Merge built-in locale JSON into this instance once per instance; layout effect so bundles exist before paint.
|
|
36
|
+
useLayoutEffect(() => {
|
|
37
|
+
registerDateSelectorI18n(i18nResolved);
|
|
38
|
+
}, [i18nResolved]);
|
|
39
|
+
// Namespace `dateSelector`; pass `i18n` explicitly so it matches `i18nResolved`. Suspense off for predictable SSR/story usage.
|
|
40
|
+
const { t } = useTranslation(DATE_SELECTOR_NAMESPACE, {
|
|
41
|
+
i18n: i18nResolved,
|
|
42
|
+
useSuspense: false,
|
|
43
|
+
});
|
|
44
|
+
const translatedI18n = useMemo(() => buildDateSelectorI18nFromT(t), [t]);
|
|
45
|
+
// Optional `i18n` prop still overrides individual strings without replacing i18next setup.
|
|
46
|
+
const mergedI18n = useMemo(() => ({ ...translatedI18n, ...i18nOverride }), [translatedI18n, i18nOverride]);
|
|
47
|
+
const selector = useDateSelector({
|
|
48
|
+
value,
|
|
49
|
+
onChange,
|
|
50
|
+
defaultPeriodType,
|
|
51
|
+
defaultFilterType,
|
|
52
|
+
presetMode,
|
|
53
|
+
allowRange,
|
|
54
|
+
yearRange,
|
|
55
|
+
baseYear,
|
|
56
|
+
minYear,
|
|
57
|
+
maxYear,
|
|
58
|
+
yearOptions,
|
|
59
|
+
periodTypes,
|
|
60
|
+
});
|
|
61
|
+
const { periodType, filterType, selectedDate, selectedEndDate, calendarMonth, selectedYear, selectedMonth, selectedQuarter, rangeStart, rangeEnd, hoverDate, years, currentValue, setPeriodType, setFilterType, setCalendarMonth, setHoverDate, clearSelection, handleDayClick, handlePeriodSelect, handleYearSelect, isInRange, isYearInRange, selectionMode, rollingUnit, rollingCount, applyRollingPreset, enterCustomRange, syncInternalFromParsedValue, } = selector;
|
|
62
|
+
const optionsForRollingUnit = useCallback((unit) => {
|
|
63
|
+
if (unit === 'day')
|
|
64
|
+
return rollingDayOptions;
|
|
65
|
+
if (unit === 'month')
|
|
66
|
+
return rollingMonthOptions;
|
|
67
|
+
if (unit === 'quarter')
|
|
68
|
+
return rollingQuarterOptions;
|
|
69
|
+
return rollingYearOptions;
|
|
70
|
+
}, [rollingDayOptions, rollingMonthOptions, rollingQuarterOptions, rollingYearOptions]);
|
|
71
|
+
const rollingChipOptions = useMemo(() => [...optionsForRollingUnit(rollingUnit)], [rollingUnit, optionsForRollingUnit]);
|
|
72
|
+
const rollingChipLabel = useCallback((count) => {
|
|
73
|
+
if (rollingUnit === 'month') {
|
|
74
|
+
return count === 1 ? mergedI18n.rollingMonthChipSingle : mergedI18n.rollingMonthsChip.replace('{{count}}', String(count));
|
|
75
|
+
}
|
|
76
|
+
if (rollingUnit === 'quarter') {
|
|
77
|
+
return count === 1 ? mergedI18n.rollingQuarterChip : mergedI18n.rollingQuartersChip.replace('{{count}}', String(count));
|
|
78
|
+
}
|
|
79
|
+
if (rollingUnit === 'year') {
|
|
80
|
+
return count === 1 ? mergedI18n.rollingYearChip : mergedI18n.rollingYearsChip.replace('{{count}}', String(count));
|
|
81
|
+
}
|
|
82
|
+
return mergedI18n.rollingDaysChip.replace('{{count}}', String(count));
|
|
83
|
+
}, [mergedI18n, rollingUnit]);
|
|
84
|
+
const hideOperatorsForRolling = showRollingPresets && periodType === 'day' && (selectionMode === 'rolling-next' || selectionMode === 'rolling-last');
|
|
85
|
+
const showDayCalendar = periodType === 'day' && selectionMode === 'custom';
|
|
86
|
+
const displayValue = formatDateValue(currentValue, mergedI18n, dayDateFormat);
|
|
87
|
+
const [draftInput, setDraftInput] = useState('');
|
|
88
|
+
const [isInputFocused, setIsInputFocused] = useState(false);
|
|
89
|
+
const summaryInputValue = inputHint ? (isInputFocused ? draftInput : displayValue) : displayValue;
|
|
90
|
+
const dateFormats = useMemo(() => {
|
|
91
|
+
if (dayDateFormats && dayDateFormats.length > 0) {
|
|
92
|
+
const formats = [...dayDateFormats];
|
|
93
|
+
if (!formats.includes(dayDateFormat)) {
|
|
94
|
+
formats.unshift(dayDateFormat);
|
|
95
|
+
}
|
|
96
|
+
return formats;
|
|
97
|
+
}
|
|
98
|
+
const defaultFormats = [dayDateFormat, 'dd/MM/yyyy', 'yyyy-MM-dd', 'MM-dd-yyyy', 'dd-MM-yyyy'];
|
|
99
|
+
return Array.from(new Set(defaultFormats));
|
|
100
|
+
}, [dayDateFormat, dayDateFormats]);
|
|
101
|
+
const parseInputValue = useCallback((text) => {
|
|
102
|
+
if (!text.trim())
|
|
103
|
+
return null;
|
|
104
|
+
const trimmed = text.trim();
|
|
105
|
+
const yearMatch = trimmed.match(/^\d{4}$/);
|
|
106
|
+
if (yearMatch) {
|
|
107
|
+
const year = parseInt(yearMatch[0]);
|
|
108
|
+
if (year >= 1900 && year <= 2100) {
|
|
109
|
+
return {
|
|
110
|
+
period: 'year',
|
|
111
|
+
operator: presetMode ?? filterType,
|
|
112
|
+
year,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const quarterMatch = trimmed.match(/^Q([1-4])(?:\s+(\d{4}))?$/i);
|
|
117
|
+
if (quarterMatch) {
|
|
118
|
+
const quarter = parseInt(quarterMatch[1]) - 1;
|
|
119
|
+
const year = quarterMatch[2] ? parseInt(quarterMatch[2]) : new Date().getFullYear();
|
|
120
|
+
if (year >= 1900 && year <= 2100) {
|
|
121
|
+
return {
|
|
122
|
+
period: 'quarter',
|
|
123
|
+
operator: presetMode ?? filterType,
|
|
124
|
+
year,
|
|
125
|
+
quarter,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
for (const dateFormat of dateFormats) {
|
|
130
|
+
try {
|
|
131
|
+
const parsed = parse(trimmed, dateFormat, new Date());
|
|
132
|
+
if (!isNaN(parsed.getTime())) {
|
|
133
|
+
return {
|
|
134
|
+
period: 'day',
|
|
135
|
+
operator: presetMode ?? filterType,
|
|
136
|
+
startDate: parsed,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
// Continue to next format
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}, [filterType, presetMode, dateFormats]);
|
|
146
|
+
const handleInputChange = useCallback((e) => {
|
|
147
|
+
const newValue = e.target.value;
|
|
148
|
+
setDraftInput(newValue);
|
|
149
|
+
const parsed = parseInputValue(newValue);
|
|
150
|
+
if (parsed) {
|
|
151
|
+
onChange?.(parsed);
|
|
152
|
+
if (value === undefined) {
|
|
153
|
+
syncInternalFromParsedValue(parsed);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}, [onChange, parseInputValue, syncInternalFromParsedValue, value]);
|
|
157
|
+
const handleInputBlur = useCallback(() => {
|
|
158
|
+
setIsInputFocused(false);
|
|
159
|
+
if (!parseInputValue(draftInput)) {
|
|
160
|
+
setDraftInput(displayValue);
|
|
161
|
+
}
|
|
162
|
+
}, [draftInput, displayValue, parseInputValue]);
|
|
163
|
+
const summaryInput = showInput ? (_jsxs("div", { className: "relative", "data-slot": "date-selector-summary-input", children: [_jsx(Input, { type: "text", value: summaryInputValue, readOnly: !inputHint, placeholder: isInputFocused && inputHint ? inputHint : mergedI18n.placeholder, onFocus: () => {
|
|
164
|
+
setIsInputFocused(true);
|
|
165
|
+
setDraftInput(displayValue);
|
|
166
|
+
}, onBlur: handleInputBlur, onChange: handleInputChange }), summaryInputValue && (_jsx("button", { type: "button", onClick: clearSelection, className: cn('absolute end-2.5 top-1/2 size-4 -translate-y-1/2 cursor-pointer rounded-xs', 'opacity-70 transition-opacity hover:opacity-100', 'ring-offset-background focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-none'), children: _jsx(X, { className: "size-4" }) }))] })) : null;
|
|
167
|
+
return (_jsx(DateSelectorContext.Provider, { value: { i18n: mergedI18n, variant: 'outline', size: 'default' }, children: _jsxs("div", { "data-slot": "date-selector", className: cn('w-full max-w-[20rem]', fillHeight ? 'flex h-full min-h-0 flex-col gap-4' : 'space-y-2', className), children: [label && (_jsx("h3", { className: "shrink-0 text-sm font-medium", "data-slot": "data-selector-label", children: label })), showRollingPresets && (_jsxs("div", { className: cn('shrink-0', fillHeight ? 'space-y-4' : 'space-y-2'), "data-slot": "date-selector-rolling", children: [_jsx(Tabs, { className: "w-full", value: selectionMode === 'rolling-next' ? 'rolling-next' : selectionMode === 'rolling-last' ? 'rolling-last' : 'custom', onValueChange: (newValue) => {
|
|
168
|
+
if (!newValue)
|
|
169
|
+
return;
|
|
170
|
+
if (newValue === 'rolling-next') {
|
|
171
|
+
const opts = optionsForRollingUnit(rollingUnit);
|
|
172
|
+
const count = rollingCount !== undefined && opts.includes(rollingCount) ? rollingCount : opts[0];
|
|
173
|
+
applyRollingPreset('rolling-next', rollingUnit, count);
|
|
174
|
+
}
|
|
175
|
+
else if (newValue === 'rolling-last') {
|
|
176
|
+
const opts = optionsForRollingUnit(rollingUnit);
|
|
177
|
+
const count = rollingCount !== undefined && opts.includes(rollingCount) ? rollingCount : opts[0];
|
|
178
|
+
applyRollingPreset('rolling-last', rollingUnit, count);
|
|
179
|
+
}
|
|
180
|
+
else if (newValue === 'custom')
|
|
181
|
+
enterCustomRange();
|
|
182
|
+
}, children: _jsxs(TabsList, { className: "flex h-9 w-full min-w-0 gap-1 bg-muted/80 p-[3px]", children: [_jsx(TabsTrigger, { value: "rolling-next", "aria-label": mergedI18n.rollingWindowTabs.next, className: "min-w-0 flex-1 px-2 py-1 text-center font-normal", children: mergedI18n.rollingWindowTabs.next }), _jsx(TabsTrigger, { value: "rolling-last", "aria-label": mergedI18n.rollingWindowTabs.last, className: "min-w-0 flex-1 px-2 py-1 text-center font-normal", children: mergedI18n.rollingWindowTabs.last }), _jsx(TabsTrigger, { value: "custom", "aria-label": mergedI18n.rollingWindowTabs.custom, className: "min-w-0 flex-1 px-2 py-1 text-center font-normal", children: mergedI18n.rollingWindowTabs.custom })] }) }), showInput && summaryInput, (selectionMode === 'rolling-next' || selectionMode === 'rolling-last') && (_jsxs("div", { className: "space-y-2", "data-slot": "date-selector-rolling-value", children: [_jsx(Tabs, { className: "w-full", value: rollingUnit, onValueChange: (v) => {
|
|
183
|
+
if (!v)
|
|
184
|
+
return;
|
|
185
|
+
const unit = v;
|
|
186
|
+
const opts = optionsForRollingUnit(unit);
|
|
187
|
+
const count = rollingCount !== undefined && opts.includes(rollingCount) ? rollingCount : opts[0];
|
|
188
|
+
applyRollingPreset(selectionMode === 'rolling-last' ? 'rolling-last' : 'rolling-next', unit, count);
|
|
189
|
+
}, children: _jsxs(TabsList, { className: "grid h-auto min-h-9 w-full min-w-0 grid-cols-2 gap-1 bg-muted/60 p-[3px] sm:grid-cols-4", children: [_jsx(TabsTrigger, { value: "day", className: "min-w-0 px-2 py-1 text-center font-normal", children: mergedI18n.rollingUnitTabs.days }), _jsx(TabsTrigger, { value: "month", className: "min-w-0 px-2 py-1 text-center font-normal", children: mergedI18n.rollingUnitTabs.months }), _jsx(TabsTrigger, { value: "quarter", className: "min-w-0 px-2 py-1 text-center font-normal", children: mergedI18n.rollingUnitTabs.quarters }), _jsx(TabsTrigger, { value: "year", className: "min-w-0 px-2 py-1 text-center font-normal", children: mergedI18n.rollingUnitTabs.years })] }) }), _jsx("div", { className: cn('grid gap-2', rollingChipOptions.length <= 4 ? 'grid-cols-2 sm:grid-cols-4' : 'grid-cols-3 sm:grid-cols-4'), children: rollingChipOptions.map((c) => (_jsx(Button, { type: "button", size: "sm", className: "w-full min-w-0", variant: rollingCount === c ? 'default' : 'outline', onClick: () => applyRollingPreset(selectionMode === 'rolling-last' ? 'rolling-last' : 'rolling-next', rollingUnit, c), children: rollingChipLabel(c) }, c))) })] }))] })), showOperators && !hideOperatorsForRolling && (_jsx(DateSelectorFilterToggle, { className: "shrink-0", value: filterType, onChange: setFilterType, showBetween: allowRange, presetMode: presetMode })), showInput && !showRollingPresets && summaryInput, (!showRollingPresets || selectionMode === 'custom') &&
|
|
190
|
+
(separateDayPeriod ? (_jsxs("div", { className: "flex w-full shrink-0 flex-wrap items-stretch gap-2", children: [(!periodTypes?.length || periodTypes.includes('day')) && (_jsx(Button, { type: "button", variant: periodType === 'day' ? 'default' : 'outline', size: "sm", className: "h-9 shrink-0 px-4", onClick: () => setPeriodType('day'), children: mergedI18n.periodTypes.day })), _jsx("div", { className: "min-w-0 flex-1", children: _jsx(DateSelectorGranularityTabs, { periodType: periodType, onChange: setPeriodType, periodTypes: periodTypes?.filter((p) => p !== 'day') }) })] })) : (_jsx(DateSelectorPeriodTabs, { className: "shrink-0", value: periodType, onChange: setPeriodType, periodTypes: periodTypes }))), periodType === 'day' && showDayCalendar && (_jsx("div", { className: cn('w-full pb-1', fillHeight && 'flex min-h-0 flex-1 flex-col'), children: _jsx(DateSelectorDayPicker, { currentMonth: calendarMonth, selectedDate: selectedDate, selectedEndDate: selectedEndDate, onDayClick: handleDayClick, isRange: filterType === 'between' && allowRange, onDayHover: setHoverDate, hoverDate: hoverDate, showTwoMonths: showTwoMonths, weekStartsOn: weekStartsOn, onMonthChange: setCalendarMonth }) })), periodType !== 'day' && (_jsx("div", { className: cn('-mr-3 flex w-full flex-col', fillHeight ? 'min-h-0 flex-1' : ''), children: _jsxs(ScrollArea, { className: cn('min-h-0 w-full pe-3', fillHeight ? 'flex-1 basis-0' : 'h-[200px]'), children: [periodType === 'month' && (_jsx(DateSelectorPeriodGrid, { years: years, items: mergedI18n.monthsShort, selectedYear: selectedYear, selectedValue: selectedMonth, rangeStart: rangeStart, rangeEnd: rangeEnd, isInRange: isInRange, onSelect: handlePeriodSelect, columns: 3 })), periodType === 'quarter' && (_jsx(DateSelectorPeriodGrid, { className: "space-y-3", years: years, items: mergedI18n.quarters, selectedYear: selectedYear, selectedValue: selectedQuarter, rangeStart: rangeStart, rangeEnd: rangeEnd, isInRange: isInRange, onSelect: handlePeriodSelect, columns: 4 })), periodType === 'year' && (_jsx(DateSelectorYearList, { years: years, selectedYear: selectedYear, rangeStart: rangeStart, rangeEnd: rangeEnd, isYearInRange: isYearInRange, onSelect: handleYearSelect }))] }, periodType) }))] }) }));
|
|
191
|
+
}
|
|
@@ -14,6 +14,8 @@ type DateSelectorStoryArgs = Omit<Partial<DateSelectorProps>, 'value' | 'onChang
|
|
|
14
14
|
periodTypesPreset?: PeriodTypesPreset;
|
|
15
15
|
presetMode?: DateSelectorFilterType | 'unset';
|
|
16
16
|
weekStartsOn?: 'unset' | NonNullable<DateSelectorProps['weekStartsOn']>;
|
|
17
|
+
/** Pattern 2 only: when true, `i18nInstance` is omitted so the Storybook toolbar locale applies. */
|
|
18
|
+
useSharedToolbarI18n?: boolean;
|
|
17
19
|
};
|
|
18
20
|
/** Storybook-only shell: maps story args to {@link DateSelector} and wires controlled state. */
|
|
19
21
|
declare function DateSelectorStorybook(args: DateSelectorStoryArgs): import("react/jsx-runtime").JSX.Element;
|
|
@@ -113,6 +115,15 @@ declare const meta: {
|
|
|
113
115
|
i18n: {
|
|
114
116
|
control: false;
|
|
115
117
|
};
|
|
118
|
+
i18nInstance: {
|
|
119
|
+
control: false;
|
|
120
|
+
};
|
|
121
|
+
useSharedToolbarI18n: {
|
|
122
|
+
control: false;
|
|
123
|
+
table: {
|
|
124
|
+
disable: true;
|
|
125
|
+
};
|
|
126
|
+
};
|
|
116
127
|
yearOptions: {
|
|
117
128
|
control: false;
|
|
118
129
|
};
|
|
@@ -132,4 +143,7 @@ export declare const PresetBetween: Story;
|
|
|
132
143
|
export declare const NoInput: Story;
|
|
133
144
|
export declare const NoOperators: Story;
|
|
134
145
|
export declare const RollingPresets: Story;
|
|
146
|
+
export declare const PatternPartialI18nProp: Story;
|
|
147
|
+
export declare const PatternDedicatedI18nInstance: Story;
|
|
148
|
+
export declare const PatternGlobalLocaleToolbar: Story;
|
|
135
149
|
//# sourceMappingURL=date-selector.stories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"date-selector.stories.d.ts","sourceRoot":"","sources":["../../../src/blocks/date-selector/date-selector.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAQ,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAOvD,OAAO,KAAK,EAAE,sBAAsB,EAAkD,iBAAiB,EAAqB,MAAM,GAAG,CAAC;AAEtI,QAAA,MAAM,mBAAmB;;;;;;;CAOgD,CAAC;AAE1E,KAAK,iBAAiB,GAAG,MAAM,OAAO,mBAAmB,CAAC;AAE1D,4FAA4F;AAC5F,KAAK,qBAAqB,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,aAAa,GAAG,YAAY,GAAG,cAAc,CAAC,GAAG;IAClI,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,UAAU,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC;IAC9C,YAAY,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC,CAAC;IACxE,oGAAoG;IACpG,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAClC,CAAC;AAgGF,gGAAgG;AAChG,iBAAS,qBAAqB,CAAC,IAAI,EAAE,qBAAqB,2CAIzD;AAED,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAoD+C,iBAAiB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsB9B,CAAC;AAE/C,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAEnC,eAAO,MAAM,OAAO,EAAE,KAAU,CAAC;AAEjC,eAAO,MAAM,OAAO,EAAE,KAerB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAM3B,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,KAKrB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAMzB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,KAM5B,CAAC;AAkBF,eAAO,MAAM,sBAAsB,EAAE,KA2CpC,CAAC;AAEF,eAAO,MAAM,4BAA4B,EAAE,KAqD1C,CAAC;AAEF,eAAO,MAAM,0BAA0B,EAAE,KA0CxC,CAAC"}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { createInstance } from 'i18next';
|
|
3
|
+
import { initReactI18next } from 'react-i18next';
|
|
4
|
+
import { useState } from 'react';
|
|
5
|
+
import { DATE_SELECTOR_NAMESPACE, DATE_SELECTOR_RESOURCE_BUNDLES, DateSelector, DEFAULT_DATE_SELECTOR_I18N } from '.';
|
|
6
|
+
const PERIOD_TYPE_PRESETS = {
|
|
7
|
+
all: undefined,
|
|
8
|
+
day: ['day'],
|
|
9
|
+
'day-month': ['day', 'month'],
|
|
10
|
+
month: ['month'],
|
|
11
|
+
quarter: ['quarter'],
|
|
12
|
+
year: ['year'],
|
|
13
|
+
};
|
|
14
|
+
function JsonBlock({ label, value }) {
|
|
15
|
+
return (_jsxs("div", { className: "mt-3 space-y-1.5", children: [_jsx("div", { className: "text-xs font-medium text-foreground", children: label }), _jsx("pre", { className: "max-h-64 overflow-auto rounded-md border border-border bg-background p-3 font-mono text-[11px] leading-relaxed whitespace-pre-wrap text-foreground", children: JSON.stringify(value, null, 2) })] }));
|
|
16
|
+
}
|
|
17
|
+
/** Canvas + Docs intro for the three i18n pattern examples (share with teammates). */
|
|
18
|
+
function StoryIntro({ title, description, children }) {
|
|
19
|
+
return (_jsxs("div", { className: "flex w-full max-w-lg flex-col gap-4", children: [_jsxs("div", { className: "rounded-md border border-border bg-muted/40 p-4 text-sm leading-relaxed text-foreground", children: [_jsx("h2", { className: "mb-2 font-semibold tracking-tight", children: title }), _jsx("div", { className: "space-y-2 text-muted-foreground [&_code]:rounded [&_code]:bg-background [&_code]:px-1 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-xs", children: description })] }), children] }));
|
|
20
|
+
}
|
|
21
|
+
const demoJapaneseBundle = {
|
|
22
|
+
...DEFAULT_DATE_SELECTOR_I18N,
|
|
23
|
+
selectDate: '日付を選択',
|
|
24
|
+
apply: '適用',
|
|
25
|
+
cancel: 'キャンセル',
|
|
26
|
+
clear: 'クリア',
|
|
27
|
+
today: '今日',
|
|
28
|
+
filterTypes: {
|
|
29
|
+
is: '次と一致',
|
|
30
|
+
before: 'より前',
|
|
31
|
+
after: 'より後',
|
|
32
|
+
between: '範囲',
|
|
33
|
+
},
|
|
34
|
+
periodTypes: {
|
|
35
|
+
day: '日',
|
|
36
|
+
month: '月',
|
|
37
|
+
quarter: '四半期',
|
|
38
|
+
year: '年',
|
|
39
|
+
},
|
|
40
|
+
months: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
|
|
41
|
+
monthsShort: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
|
|
42
|
+
quarters: ['Q1', 'Q2', 'Q3', 'Q4'],
|
|
43
|
+
weekdays: ['日曜日', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日'],
|
|
44
|
+
weekdaysShort: ['日', '月', '火', '水', '木', '金', '土'],
|
|
45
|
+
placeholder: '日付を選択…',
|
|
46
|
+
rangePlaceholder: '期間を選択…',
|
|
47
|
+
rollingWindowTabs: { next: '次へ', last: '前へ', custom: 'カスタム' },
|
|
48
|
+
rollingSummaryNext: '次の{{count}}日間',
|
|
49
|
+
rollingSummaryLast: '過去{{count}}日間',
|
|
50
|
+
rollingDaysChip: '{{count}}日',
|
|
51
|
+
};
|
|
52
|
+
/** Isolated i18next instance for “own language pack” demos (not the Storybook toolbar instance). */
|
|
53
|
+
const jaDemoI18n = createInstance();
|
|
54
|
+
jaDemoI18n.use(initReactI18next).init({
|
|
55
|
+
lng: 'ja',
|
|
56
|
+
fallbackLng: 'ja',
|
|
57
|
+
supportedLngs: ['ja'],
|
|
58
|
+
interpolation: { escapeValue: false },
|
|
59
|
+
react: { useSuspense: false },
|
|
60
|
+
ns: [DATE_SELECTOR_NAMESPACE],
|
|
61
|
+
defaultNS: DATE_SELECTOR_NAMESPACE,
|
|
62
|
+
resources: {
|
|
63
|
+
ja: { [DATE_SELECTOR_NAMESPACE]: demoJapaneseBundle },
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
const pattern1DefaultI18n = {
|
|
67
|
+
filterTypes: {
|
|
68
|
+
is: 'equals',
|
|
69
|
+
before: 'before',
|
|
70
|
+
after: 'after',
|
|
71
|
+
between: 'between',
|
|
72
|
+
},
|
|
73
|
+
placeholder: 'Pick a date…',
|
|
74
|
+
rangePlaceholder: 'Pick a start and end…',
|
|
75
|
+
};
|
|
76
|
+
function storyArgsToProps(args) {
|
|
77
|
+
const { periodTypesPreset = 'all', presetMode, weekStartsOn, useSharedToolbarI18n: _strip, ...rest } = args;
|
|
78
|
+
return {
|
|
79
|
+
...rest,
|
|
80
|
+
periodTypes: PERIOD_TYPE_PRESETS[periodTypesPreset],
|
|
81
|
+
presetMode: presetMode === 'unset' ? undefined : presetMode,
|
|
82
|
+
weekStartsOn: weekStartsOn === 'unset' ? undefined : weekStartsOn,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/** Storybook-only shell: maps story args to {@link DateSelector} and wires controlled state. */
|
|
86
|
+
function DateSelectorStorybook(args) {
|
|
87
|
+
const [value, setValue] = useState();
|
|
88
|
+
const props = storyArgsToProps(args);
|
|
89
|
+
return _jsx(DateSelector, { ...props, value: value, onChange: setValue });
|
|
90
|
+
}
|
|
91
|
+
const meta = {
|
|
92
|
+
title: 'Blocks/DateSelector',
|
|
93
|
+
component: DateSelectorStorybook,
|
|
94
|
+
tags: ['autodocs'],
|
|
95
|
+
parameters: {
|
|
96
|
+
layout: 'padded',
|
|
97
|
+
docs: {
|
|
98
|
+
story: {
|
|
99
|
+
height: '720px',
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
args: {
|
|
104
|
+
label: '',
|
|
105
|
+
showInput: true,
|
|
106
|
+
showOperators: true,
|
|
107
|
+
showTwoMonths: false,
|
|
108
|
+
allowRange: true,
|
|
109
|
+
showRollingPresets: false,
|
|
110
|
+
defaultPeriodType: 'day',
|
|
111
|
+
defaultFilterType: 'is',
|
|
112
|
+
presetMode: 'unset',
|
|
113
|
+
periodTypesPreset: 'all',
|
|
114
|
+
minYear: 2024,
|
|
115
|
+
maxYear: 2028,
|
|
116
|
+
yearRange: 10,
|
|
117
|
+
weekStartsOn: 'unset',
|
|
118
|
+
inputHint: '',
|
|
119
|
+
dayDateFormat: 'MM/dd/yyyy',
|
|
120
|
+
},
|
|
121
|
+
argTypes: {
|
|
122
|
+
label: { control: 'text' },
|
|
123
|
+
showInput: { control: 'boolean' },
|
|
124
|
+
showOperators: { control: 'boolean' },
|
|
125
|
+
showTwoMonths: { control: 'boolean' },
|
|
126
|
+
allowRange: { control: 'boolean' },
|
|
127
|
+
showRollingPresets: { control: 'boolean' },
|
|
128
|
+
defaultPeriodType: {
|
|
129
|
+
control: 'select',
|
|
130
|
+
options: ['day', 'month', 'quarter', 'year'],
|
|
131
|
+
},
|
|
132
|
+
defaultFilterType: {
|
|
133
|
+
control: 'select',
|
|
134
|
+
options: ['is', 'before', 'after', 'between'],
|
|
135
|
+
},
|
|
136
|
+
presetMode: {
|
|
137
|
+
control: 'select',
|
|
138
|
+
options: ['unset', 'is', 'before', 'after', 'between'],
|
|
139
|
+
description: 'Use “unset” to clear (same as leaving `presetMode` undefined).',
|
|
140
|
+
},
|
|
141
|
+
periodTypesPreset: {
|
|
142
|
+
control: 'select',
|
|
143
|
+
options: Object.keys(PERIOD_TYPE_PRESETS),
|
|
144
|
+
description: 'Maps to the `periodTypes` prop (which tabs are enabled).',
|
|
145
|
+
},
|
|
146
|
+
minYear: { control: 'number' },
|
|
147
|
+
maxYear: { control: 'number' },
|
|
148
|
+
yearRange: { control: 'number' },
|
|
149
|
+
baseYear: { control: 'number' },
|
|
150
|
+
weekStartsOn: {
|
|
151
|
+
control: 'select',
|
|
152
|
+
options: ['unset', 0, 1, 2, 3, 4, 5, 6],
|
|
153
|
+
description: 'Use “unset” for the default (Sunday in most locales).',
|
|
154
|
+
},
|
|
155
|
+
inputHint: { control: 'text' },
|
|
156
|
+
dayDateFormat: { control: 'text' },
|
|
157
|
+
className: { control: false },
|
|
158
|
+
i18n: { control: false },
|
|
159
|
+
i18nInstance: { control: false },
|
|
160
|
+
useSharedToolbarI18n: { control: false, table: { disable: true } },
|
|
161
|
+
yearOptions: { control: false },
|
|
162
|
+
dayDateFormats: { control: false },
|
|
163
|
+
rollingDayOptions: { control: false },
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
export default meta;
|
|
167
|
+
export const Default = {};
|
|
168
|
+
export const DayOnly = {
|
|
169
|
+
args: {
|
|
170
|
+
label: 'Date',
|
|
171
|
+
periodTypesPreset: 'day',
|
|
172
|
+
defaultPeriodType: 'day',
|
|
173
|
+
},
|
|
174
|
+
render: function DayOnlyStory(args) {
|
|
175
|
+
const [value, setValue] = useState({
|
|
176
|
+
period: 'day',
|
|
177
|
+
operator: 'is',
|
|
178
|
+
startDate: new Date(2026, 3, 13),
|
|
179
|
+
});
|
|
180
|
+
const props = storyArgsToProps(args);
|
|
181
|
+
return _jsx(DateSelector, { ...props, value: value, onChange: setValue });
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
export const PresetBetween = {
|
|
185
|
+
args: {
|
|
186
|
+
label: 'In range',
|
|
187
|
+
presetMode: 'between',
|
|
188
|
+
defaultFilterType: 'between',
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
export const NoInput = {
|
|
192
|
+
args: {
|
|
193
|
+
label: 'Pick in calendar',
|
|
194
|
+
showInput: false,
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
export const NoOperators = {
|
|
198
|
+
args: {
|
|
199
|
+
label: 'Period only (operator fixed to is)',
|
|
200
|
+
showOperators: false,
|
|
201
|
+
defaultFilterType: 'is',
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
export const RollingPresets = {
|
|
205
|
+
args: {
|
|
206
|
+
label: 'Rolling window',
|
|
207
|
+
showRollingPresets: true,
|
|
208
|
+
defaultFilterType: 'between',
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
const docPartialProp = `
|
|
212
|
+
Use the **\`i18n\`** prop to override specific strings (a \`Partial<DateSelectorI18nConfig>\`). Values merge on top of whatever
|
|
213
|
+
the active i18next locale resolves. Good for product wording, A/B copy, or apps that do not want to register JSON bundles.
|
|
214
|
+
`;
|
|
215
|
+
const docDedicatedInstance = `
|
|
216
|
+
Create an **\`i18next\` instance** (e.g. \`createInstance()\`), load your \`dateSelector\` namespace resources, and pass
|
|
217
|
+
**\`i18nInstance={…}\`** so this block uses that instance—useful for embeds, tests, or a locale that only exists in one subtree.
|
|
218
|
+
`;
|
|
219
|
+
const docGlobalToolbar = `
|
|
220
|
+
**Production-style path:** one app-wide \`i18n\`, call \`registerDateSelectorI18n(appI18n)\` at startup, then
|
|
221
|
+
**\`changeLanguage\`** (or your locale switcher). In Storybook, use the **Locale** toolbar: choose **Português** to see the
|
|
222
|
+
built-in \`pt\` bundle—no extra props on \`DateSelector\`.
|
|
223
|
+
`;
|
|
224
|
+
export const PatternPartialI18nProp = {
|
|
225
|
+
name: 'i18n · Partial prop overrides',
|
|
226
|
+
parameters: {
|
|
227
|
+
docs: {
|
|
228
|
+
description: {
|
|
229
|
+
story: docPartialProp,
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
args: {
|
|
234
|
+
label: 'Due date',
|
|
235
|
+
i18n: pattern1DefaultI18n,
|
|
236
|
+
},
|
|
237
|
+
argTypes: {
|
|
238
|
+
i18n: {
|
|
239
|
+
control: 'object',
|
|
240
|
+
description: 'Partial `DateSelectorI18nConfig`. Edits apply live (same data as the JSON panel above).',
|
|
241
|
+
},
|
|
242
|
+
i18nInstance: { table: { disable: true } },
|
|
243
|
+
},
|
|
244
|
+
render: function PatternPartialI18nPropRender(args) {
|
|
245
|
+
const [value, setValue] = useState();
|
|
246
|
+
const props = storyArgsToProps(args);
|
|
247
|
+
return (_jsx(StoryIntro, { title: "Pattern 1 \u2014 Partial `i18n` prop", description: _jsxs(_Fragment, { children: [_jsxs("p", { children: ["Override individual labels without touching i18next resources. Merges on top of the current locale from ", _jsx("code", { children: "t()" }), "."] }), _jsxs("p", { children: [_jsx("strong", { children: "Controls \u2192 `i18n`" }), " is a JSON object editor for this prop. ", _jsx("code", { children: "i18nInstance" }), " cannot appear in Controls\u2014it is a runtime i18next instance, not serializable JSON (see Pattern 2)."] }), _jsx(JsonBlock, { label: "Live JSON: `i18n` prop (synced with Controls)", value: args.i18n ?? {} })] }), children: _jsx(DateSelector, { ...props, value: value, onChange: setValue }) }));
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
export const PatternDedicatedI18nInstance = {
|
|
251
|
+
name: 'i18n · Dedicated instance (Japanese)',
|
|
252
|
+
parameters: {
|
|
253
|
+
docs: {
|
|
254
|
+
description: {
|
|
255
|
+
story: docDedicatedInstance,
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
args: {
|
|
260
|
+
label: '期間',
|
|
261
|
+
useSharedToolbarI18n: false,
|
|
262
|
+
},
|
|
263
|
+
argTypes: {
|
|
264
|
+
useSharedToolbarI18n: {
|
|
265
|
+
control: 'boolean',
|
|
266
|
+
table: { disable: false },
|
|
267
|
+
description: 'Off: pass `i18nInstance={jaDemoI18n}` (Japanese bundle below). On: omit `i18nInstance` and use the Storybook Locale toolbar instead.',
|
|
268
|
+
},
|
|
269
|
+
i18n: { table: { disable: true } },
|
|
270
|
+
i18nInstance: { table: { disable: true } },
|
|
271
|
+
},
|
|
272
|
+
render: function PatternDedicatedI18nInstanceRender(args) {
|
|
273
|
+
const [value, setValue] = useState();
|
|
274
|
+
const props = storyArgsToProps(args);
|
|
275
|
+
const useShared = args.useSharedToolbarI18n === true;
|
|
276
|
+
return (_jsx(StoryIntro, { title: "Pattern 2 \u2014 Dedicated `i18n` instance", description: _jsxs(_Fragment, { children: [_jsxs("p", { children: ["This story uses a ", _jsx("strong", { children: "separate" }), " ", _jsx("code", { children: "i18next" }), " instance (", _jsx("code", { children: "jaDemoI18n" }), ") with a full", ' ', _jsx("code", { children: "dateSelector" }), " resource for Japanese. You cannot edit ", _jsx("code", { children: "i18nInstance" }), " in Controls\u2014it is not JSON."] }), _jsxs("p", { children: ["Toggle ", _jsx("strong", { children: "Use shared toolbar i18n" }), " to compare: same component without ", _jsx("code", { children: "i18nInstance" }), ", so language comes from the toolbar (Locale)."] }), _jsx(JsonBlock, { label: "JSON shape: resources.ja.dateSelector (loaded into jaDemoI18n)", value: { ja: { [DATE_SELECTOR_NAMESPACE]: demoJapaneseBundle } } }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Code: ", _jsxs("code", { children: ["i18nInstance=", '{jaDemoI18n}'] }), " \u2014 holds the instance returned by ", _jsx("code", { children: "createInstance()" }), ", not a plain object."] })] }), children: _jsx(DateSelector, { ...props, i18nInstance: useShared ? undefined : jaDemoI18n, value: value, onChange: setValue }) }));
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
export const PatternGlobalLocaleToolbar = {
|
|
280
|
+
name: 'i18n · Shared locale (toolbar)',
|
|
281
|
+
parameters: {
|
|
282
|
+
docs: {
|
|
283
|
+
description: {
|
|
284
|
+
story: docGlobalToolbar,
|
|
285
|
+
},
|
|
286
|
+
},
|
|
287
|
+
},
|
|
288
|
+
args: {
|
|
289
|
+
label: 'Data',
|
|
290
|
+
},
|
|
291
|
+
argTypes: {
|
|
292
|
+
i18n: { table: { disable: true } },
|
|
293
|
+
},
|
|
294
|
+
render: function PatternGlobalLocaleToolbarRender(args) {
|
|
295
|
+
const [value, setValue] = useState();
|
|
296
|
+
const props = storyArgsToProps(args);
|
|
297
|
+
return (_jsx(StoryIntro, { title: "Pattern 3 \u2014 Global locale (Storybook toolbar)", description: _jsxs(_Fragment, { children: [_jsxs("p", { children: [_jsx("strong", { children: "No" }), " ", _jsx("code", { children: "i18n" }), " or ", _jsx("code", { children: "i18nInstance" }), " props: the component uses the nearest", ' ', _jsx("code", { children: "I18nextProvider" }), " from Storybook preview (shared ", _jsx("code", { children: "storybookI18n" }), ")."] }), _jsxs("p", { children: ["Use the Storybook ", _jsx("strong", { children: "Locale" }), " toolbar and select ", _jsx("strong", { children: "Portugu\u00EAs" }), " \u2014 the built-in ", _jsx("code", { children: "pt" }), " bundle ships with ", _jsx("code", { children: "@wheelhouse/ui" }), " and is registered on mount."] }), _jsx(JsonBlock, { label: "Reference JSON: built-in `pt` bundle (namespace dateSelector)", value: { pt: { [DATE_SELECTOR_NAMESPACE]: DATE_SELECTOR_RESOURCE_BUNDLES.pt } } })] }), children: _jsx(DateSelector, { ...props, value: value, onChange: setValue }) }));
|
|
298
|
+
},
|
|
299
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { computeRollingDateRange, computeRollingPresetRange, DATE_SELECTOR_COMPACT_DAY_FORMAT, formatDateValue, formatRollingRangeTooltipDetail, getRollingBarShortLabel, getRollingSummaryLabel, resolveRollingCount, resolveRollingUnit, } from './date-selector-value';
|
|
2
|
+
export { getDateSelectorDefaultI18n } from './date-selector-default-i18n';
|
|
3
|
+
export { buildDateSelectorI18nFromT, registerDateSelectorI18n } from './date-selector-i18n.shared';
|
|
4
|
+
export { DATE_SELECTOR_NAMESPACE, DATE_SELECTOR_RESOURCE_BUNDLES } from './date-selector-i18n-resources';
|
|
5
|
+
export type { DateSelectorResourceBundle } from './date-selector-i18n-resources';
|
|
6
|
+
export { DATE_SELECTOR_ROLLING_DAY_OPTIONS, DATE_SELECTOR_ROLLING_MONTH_OPTIONS, DATE_SELECTOR_ROLLING_QUARTER_OPTIONS, DATE_SELECTOR_ROLLING_YEAR_OPTIONS, DEFAULT_DATE_SELECTOR_I18N, } from './date-selector-types';
|
|
7
|
+
export { DateSelector } from './date-selector';
|
|
8
|
+
export { useDateSelector } from './use-date-selector';
|
|
9
|
+
export { useDateSelectorContext } from './date-selector-context';
|
|
10
|
+
export type { DateSelectorContextValue, DateSelectorFilterType, DateSelectorI18nConfig, FormatDateValueOptions, DateSelectorPeriodType, DateSelectorProps, DateSelectorRollingDays, DateSelectorRollingMonths, DateSelectorRollingQuarters, DateSelectorRollingUnit, DateSelectorRollingYears, DateSelectorSelectionMode, DateSelectorValue, UseDateSelectorOptions, } from './date-selector-types';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/blocks/date-selector/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,uBAAuB,EACvB,yBAAyB,EACzB,gCAAgC,EAChC,eAAe,EACf,+BAA+B,EAC/B,uBAAuB,EACvB,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,GACrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AACnG,OAAO,EAAE,uBAAuB,EAAE,8BAA8B,EAAE,MAAM,gCAAgC,CAAC;AACzG,YAAY,EAAE,0BAA0B,EAAE,MAAM,gCAAgC,CAAC;AACjF,OAAO,EACH,iCAAiC,EACjC,mCAAmC,EACnC,qCAAqC,EACrC,kCAAkC,EAClC,0BAA0B,GAC7B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,YAAY,EACR,wBAAwB,EACxB,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACtB,iBAAiB,EACjB,uBAAuB,EACvB,yBAAyB,EACzB,2BAA2B,EAC3B,uBAAuB,EACvB,wBAAwB,EACxB,yBAAyB,EACzB,iBAAiB,EACjB,sBAAsB,GACzB,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { computeRollingDateRange, computeRollingPresetRange, DATE_SELECTOR_COMPACT_DAY_FORMAT, formatDateValue, formatRollingRangeTooltipDetail, getRollingBarShortLabel, getRollingSummaryLabel, resolveRollingCount, resolveRollingUnit, } from './date-selector-value';
|
|
2
|
+
export { getDateSelectorDefaultI18n } from './date-selector-default-i18n';
|
|
3
|
+
export { buildDateSelectorI18nFromT, registerDateSelectorI18n } from './date-selector-i18n.shared';
|
|
4
|
+
export { DATE_SELECTOR_NAMESPACE, DATE_SELECTOR_RESOURCE_BUNDLES } from './date-selector-i18n-resources';
|
|
5
|
+
export { DATE_SELECTOR_ROLLING_DAY_OPTIONS, DATE_SELECTOR_ROLLING_MONTH_OPTIONS, DATE_SELECTOR_ROLLING_QUARTER_OPTIONS, DATE_SELECTOR_ROLLING_YEAR_OPTIONS, DEFAULT_DATE_SELECTOR_I18N, } from './date-selector-types';
|
|
6
|
+
export { DateSelector } from './date-selector';
|
|
7
|
+
export { useDateSelector } from './use-date-selector';
|
|
8
|
+
export { useDateSelectorContext } from './date-selector-context';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type SetStateAction } from 'react';
|
|
2
|
-
import type { DateSelectorFilterType, DateSelectorPeriodType,
|
|
2
|
+
import type { DateSelectorFilterType, DateSelectorPeriodType, DateSelectorRollingUnit, DateSelectorValue, UseDateSelectorOptions } from './date-selector-types';
|
|
3
3
|
/**
|
|
4
4
|
* Headless state and handlers for the date selector: period, filter operator, selected dates/ranges, and year lists.
|
|
5
5
|
* Use when building a custom layout; otherwise prefer {@link DateSelector}.
|
|
@@ -30,7 +30,8 @@ export declare function useDateSelector({ value, onChange, defaultPeriodType, de
|
|
|
30
30
|
currentValue: DateSelectorValue;
|
|
31
31
|
allowRange: boolean;
|
|
32
32
|
selectionMode: import("./date-selector-types").DateSelectorSelectionMode;
|
|
33
|
-
|
|
33
|
+
rollingUnit: DateSelectorRollingUnit;
|
|
34
|
+
rollingCount: number | undefined;
|
|
34
35
|
setPeriodType: (type: DateSelectorPeriodType) => void;
|
|
35
36
|
setFilterType: (type: DateSelectorFilterType) => void;
|
|
36
37
|
setSelectedDate: (action: SetStateAction<Date | undefined>) => void;
|
|
@@ -43,7 +44,7 @@ export declare function useDateSelector({ value, onChange, defaultPeriodType, de
|
|
|
43
44
|
handleYearSelect: (year: number) => void;
|
|
44
45
|
isInRange: (year: number, periodValue: number) => boolean;
|
|
45
46
|
isYearInRange: (year: number) => boolean;
|
|
46
|
-
applyRollingPreset: (mode: "rolling-next" | "rolling-last",
|
|
47
|
+
applyRollingPreset: (mode: "rolling-next" | "rolling-last", unit: DateSelectorRollingUnit, count: number) => void;
|
|
47
48
|
enterCustomRange: () => void;
|
|
48
49
|
syncInternalFromParsedValue: (parsed: DateSelectorValue) => void;
|
|
49
50
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-date-selector.d.ts","sourceRoot":"","sources":["../../../src/blocks/date-selector/use-date-selector.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,cAAc,EAAkC,MAAM,OAAO,CAAC;AAG5E,OAAO,KAAK,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAUhK;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,EAC5B,KAAK,EACL,QAAQ,EACR,iBAAyB,EACzB,iBAAwB,EACxB,UAAU,EACV,UAAiB,EACjB,SAAc,EACd,QAAQ,EACR,OAAO,EACP,OAAO,EACP,WAAW,EACX,WAAW,GACd,EAAE,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;0BA+PV,sBAAsB;0BAoBtB,sBAAsB;8BArMpB,cAAc,CAAC,IAAI,GAAG,SAAS,CAAC;iCAUhC,cAAc,CAAC,IAAI,GAAG,SAAS,CAAC;+BA/BC,cAAc,CAAC,IAAI,CAAC;2BAUxB,cAAc,CAAC,IAAI,GAAG,SAAS,CAAC;;0BA8EhE,IAAI;+BAgCH,MAAM,eAAe,MAAM;6BA0C3B,MAAM;sBA6EN,MAAM,eAAe,MAAM;0BAW3B,MAAM;+BArLN,cAAc,GAAG,cAAc,QAAQ,uBAAuB,SAAS,MAAM;;0CA/E3E,iBAAiB;EAiTjC"}
|