@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,406 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import { computeRollingPresetRange, DATE_SELECTOR_COMPACT_DAY_FORMAT, DateSelector, formatDateValue, formatRollingRangeTooltipDetail, getRollingSummaryLabel, resolveRollingCount, resolveRollingUnit, } from '../../blocks/date-selector';
|
|
5
|
+
import { 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 '../../blocks/date-selector/date-selector-types';
|
|
6
|
+
import { Button } from '../button';
|
|
7
|
+
import { ButtonGroupText } from '../button-group';
|
|
8
|
+
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '../dialog';
|
|
9
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, } from '../dropdown-menu';
|
|
10
|
+
import { Input } from '../input';
|
|
11
|
+
import { Popover, PopoverContent, PopoverTrigger } from '../popover';
|
|
12
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from '../tooltip';
|
|
13
|
+
import { Check } from 'lucide-react';
|
|
14
|
+
import { cn } from '../../lib/utils';
|
|
15
|
+
import { dateMetricValueForCustomEditor, getDateMetricPayloadFromValues, getOperatorsForField } from './filters-utils';
|
|
16
|
+
/** Matches `Button` `variant="outline"` surface: bordered tile in the preset grid. */
|
|
17
|
+
const ROLLING_PRESET_OUTLINE = 'rounded-md border border-input bg-popover shadow-xs/5 dark:bg-input/32';
|
|
18
|
+
const ROLLING_PRESET_CELL_BASE = cn(ROLLING_PRESET_OUTLINE, 'relative min-h-7 shrink-0 justify-center !px-1.5 !py-1 text-center text-[0.7rem] leading-tight [text-wrap:pretty] tabular-nums', '[&_[data-slot=dropdown-menu-radio-item-indicator]]:hidden');
|
|
19
|
+
/** Selected tile: filled “active” look instead of the menu radio checkmark. */
|
|
20
|
+
const rollingPresetCellSelected = 'border-primary bg-accent font-medium text-foreground shadow-xs/10 dark:bg-accent/90';
|
|
21
|
+
function RollingWindowPresetGrid({ mode, i18n, idPrefix, rollingDayOpts, rollingMonthOpts, rollingQuarterOpts, rollingYearOpts, radioValue, rollingRadioKey, labelForRolling, onApply, }) {
|
|
22
|
+
const rollingPrefix = mode === 'rolling-next' ? i18n.rollingWindowTabs.next : i18n.rollingWindowTabs.last;
|
|
23
|
+
const sectionLabel = (unitTab) => `${rollingPrefix} ${unitTab}`;
|
|
24
|
+
return (_jsx(DropdownMenuRadioGroup, { value: radioValue ?? '', onValueChange: (v) => {
|
|
25
|
+
if (!v)
|
|
26
|
+
return;
|
|
27
|
+
const [u, c] = v.split(':');
|
|
28
|
+
const count = Number(c);
|
|
29
|
+
if (!u || !Number.isFinite(count))
|
|
30
|
+
return;
|
|
31
|
+
onApply(u, count);
|
|
32
|
+
}, children: _jsx("div", { className: "flex flex-col", children: _jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(DropdownMenuLabel, { className: "px-0 pt-0 pb-0", children: sectionLabel(i18n.rollingUnitTabs.days) }), _jsx("div", { className: "grid grid-cols-4 gap-1.5", children: rollingDayOpts.map((days) => {
|
|
33
|
+
const value = rollingRadioKey('day', days);
|
|
34
|
+
const selected = radioValue === value;
|
|
35
|
+
return (_jsx(DropdownMenuRadioItem, { className: cn(ROLLING_PRESET_CELL_BASE, selected && rollingPresetCellSelected), value: value, "aria-label": labelForRolling(mode, 'day', days), children: days }, `${idPrefix}-day-${days}`));
|
|
36
|
+
}) })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(DropdownMenuLabel, { className: "px-0 pt-0 pb-0", children: sectionLabel(i18n.rollingUnitTabs.months) }), _jsx("div", { className: "grid grid-cols-5 gap-1.5", children: rollingMonthOpts.map((m) => {
|
|
37
|
+
const value = rollingRadioKey('month', m);
|
|
38
|
+
const selected = radioValue === value;
|
|
39
|
+
return (_jsx(DropdownMenuRadioItem, { className: cn(ROLLING_PRESET_CELL_BASE, selected && rollingPresetCellSelected), value: value, "aria-label": labelForRolling(mode, 'month', m), children: m }, `${idPrefix}-month-${m}`));
|
|
40
|
+
}) })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(DropdownMenuLabel, { className: "px-0 pt-0 pb-0", children: sectionLabel(i18n.rollingUnitTabs.quarters) }), _jsx("div", { className: "grid grid-cols-4 gap-1.5", children: rollingQuarterOpts.map((q) => {
|
|
41
|
+
const value = rollingRadioKey('quarter', q);
|
|
42
|
+
const selected = radioValue === value;
|
|
43
|
+
return (_jsx(DropdownMenuRadioItem, { className: cn(ROLLING_PRESET_CELL_BASE, selected && rollingPresetCellSelected), value: value, "aria-label": labelForRolling(mode, 'quarter', q), children: q }, `${idPrefix}-quarter-${q}`));
|
|
44
|
+
}) })] }), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(DropdownMenuLabel, { className: "px-0 pt-0 pb-0", children: sectionLabel(i18n.rollingUnitTabs.years) }), _jsx("div", { className: "grid grid-cols-4 gap-1.5", children: rollingYearOpts.map((y) => {
|
|
45
|
+
const value = rollingRadioKey('year', y);
|
|
46
|
+
const selected = radioValue === value;
|
|
47
|
+
return (_jsx(DropdownMenuRadioItem, { className: cn(ROLLING_PRESET_CELL_BASE, selected && rollingPresetCellSelected), value: value, "aria-label": labelForRolling(mode, 'year', y), children: y }, `${idPrefix}-year-${y}`));
|
|
48
|
+
}) })] })] }) }) }));
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Compact date summary for the bar (e.g. "Last 60 days"); uses rolling templates when applicable.
|
|
52
|
+
* Day pickers use {@link DATE_SELECTOR_COMPACT_DAY_FORMAT} here so the bar stays short; the dialog still uses `dateMetricProps.dayDateFormat` for parsing.
|
|
53
|
+
* Pass {@link FormatDateValueOptions} to match {@link DateSelectorProps.rollingRangeDisplay} on the filter field.
|
|
54
|
+
*/
|
|
55
|
+
export function dateSegmentLabelForBar(date, dateI18n, dayDateFormat, options) {
|
|
56
|
+
return formatDateValue(date, dateI18n, dayDateFormat, options);
|
|
57
|
+
}
|
|
58
|
+
/** Static "in" connector + rolling Next/Last presets (submenus) + full {@link DateSelector} in a dialog for Custom. */
|
|
59
|
+
export function FilterDateMetricBarPeriodSegments({ field, values, onChange, i18n, size, autoFocus }) {
|
|
60
|
+
const [menuOpen, setMenuOpen] = useState(false);
|
|
61
|
+
const [customOpen, setCustomOpen] = useState(false);
|
|
62
|
+
/** Draft while Custom dialog is open; committed on Done, discarded on dismiss. */
|
|
63
|
+
const [customDraft, setCustomDraft] = useState(null);
|
|
64
|
+
const menuAutoOpenedRef = useRef(false);
|
|
65
|
+
const payload = useMemo(() => getDateMetricPayloadFromValues(values), [values]);
|
|
66
|
+
const setPayload = (next) => {
|
|
67
|
+
onChange([next]);
|
|
68
|
+
};
|
|
69
|
+
const dayFormat = field.dateMetricProps?.dayDateFormat ?? 'MM/dd/yyyy';
|
|
70
|
+
const mergedDateI18n = { ...DEFAULT_DATE_SELECTOR_I18N, ...field.dateMetricProps?.i18n };
|
|
71
|
+
const rollingDayOpts = (field.dateMetricProps?.rollingDayOptions ?? DATE_SELECTOR_ROLLING_DAY_OPTIONS);
|
|
72
|
+
const rollingMonthOpts = field.dateMetricProps?.rollingMonthOptions ?? DATE_SELECTOR_ROLLING_MONTH_OPTIONS;
|
|
73
|
+
const rollingQuarterOpts = field.dateMetricProps?.rollingQuarterOptions ?? DATE_SELECTOR_ROLLING_QUARTER_OPTIONS;
|
|
74
|
+
const rollingYearOpts = field.dateMetricProps?.rollingYearOptions ?? DATE_SELECTOR_ROLLING_YEAR_OPTIONS;
|
|
75
|
+
const rollingRangeDisplay = field.dateMetricProps?.rollingRangeDisplay ?? 'inline';
|
|
76
|
+
const barFormatOptions = rollingRangeDisplay === 'tooltip' ? { includeRollingRangeDetailInLabel: false } : undefined;
|
|
77
|
+
const dateSummary = dateSegmentLabelForBar(payload.date, mergedDateI18n, DATE_SELECTOR_COMPACT_DAY_FORMAT, barFormatOptions);
|
|
78
|
+
const rollingRangeTooltip = rollingRangeDisplay === 'tooltip' ? formatRollingRangeTooltipDetail(payload.date, mergedDateI18n, dayFormat) : null;
|
|
79
|
+
const buttonSize = size === 'lg' ? 'lg' : size === 'sm' ? 'sm' : 'default';
|
|
80
|
+
const dateRangeTriggerButtonClassName = 'max-w-[min(100%,18rem)] justify-start text-start [text-wrap:pretty] whitespace-normal';
|
|
81
|
+
const dateRangeTriggerButton = _jsx(Button, { variant: "outline", size: buttonSize, className: dateRangeTriggerButtonClassName });
|
|
82
|
+
const applyRolling = useCallback((mode, unit, count) => {
|
|
83
|
+
const base = getDateMetricPayloadFromValues(values);
|
|
84
|
+
const { startDate, endDate } = computeRollingPresetRange(mode, unit, count);
|
|
85
|
+
const nextDate = {
|
|
86
|
+
period: 'day',
|
|
87
|
+
operator: 'between',
|
|
88
|
+
selectionMode: mode,
|
|
89
|
+
rollingUnit: unit,
|
|
90
|
+
rollingCount: count,
|
|
91
|
+
startDate,
|
|
92
|
+
endDate,
|
|
93
|
+
};
|
|
94
|
+
if (unit === 'day' && DATE_SELECTOR_ROLLING_DAY_OPTIONS.includes(count)) {
|
|
95
|
+
nextDate.rollingDays = count;
|
|
96
|
+
}
|
|
97
|
+
onChange([
|
|
98
|
+
{
|
|
99
|
+
...base,
|
|
100
|
+
date: nextDate,
|
|
101
|
+
},
|
|
102
|
+
]);
|
|
103
|
+
setMenuOpen(false);
|
|
104
|
+
}, [values, onChange]);
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
if (!autoFocus)
|
|
107
|
+
return;
|
|
108
|
+
if (menuAutoOpenedRef.current)
|
|
109
|
+
return;
|
|
110
|
+
let cancelled = false;
|
|
111
|
+
const timer = window.setTimeout(() => {
|
|
112
|
+
if (cancelled)
|
|
113
|
+
return;
|
|
114
|
+
menuAutoOpenedRef.current = true;
|
|
115
|
+
setMenuOpen(true);
|
|
116
|
+
}, 100);
|
|
117
|
+
return () => {
|
|
118
|
+
cancelled = true;
|
|
119
|
+
window.clearTimeout(timer);
|
|
120
|
+
};
|
|
121
|
+
}, [autoFocus]);
|
|
122
|
+
const labelForRolling = (mode, unit, count) => {
|
|
123
|
+
if (unit === 'year' && count === 1) {
|
|
124
|
+
return mode === 'rolling-next' ? mergedDateI18n.rollingSummaryNextYear : mergedDateI18n.rollingSummaryLastYear;
|
|
125
|
+
}
|
|
126
|
+
if (unit === 'month' && count === 1) {
|
|
127
|
+
return mode === 'rolling-next' ? mergedDateI18n.rollingSummaryNextSingleMonth : mergedDateI18n.rollingSummaryLastSingleMonth;
|
|
128
|
+
}
|
|
129
|
+
if (unit === 'month' && count > 1) {
|
|
130
|
+
return mode === 'rolling-next'
|
|
131
|
+
? mergedDateI18n.rollingSummaryNextMonths.replace('{{count}}', String(count))
|
|
132
|
+
: mergedDateI18n.rollingSummaryLastMonths.replace('{{count}}', String(count));
|
|
133
|
+
}
|
|
134
|
+
if (unit === 'quarter' && count === 1) {
|
|
135
|
+
return mode === 'rolling-next' ? mergedDateI18n.rollingSummaryNextQuarter : mergedDateI18n.rollingSummaryLastQuarter;
|
|
136
|
+
}
|
|
137
|
+
if (unit === 'quarter' && count > 1) {
|
|
138
|
+
return mode === 'rolling-next'
|
|
139
|
+
? mergedDateI18n.rollingSummaryNextQuarters.replace('{{count}}', String(count))
|
|
140
|
+
: mergedDateI18n.rollingSummaryLastQuarters.replace('{{count}}', String(count));
|
|
141
|
+
}
|
|
142
|
+
return (getRollingSummaryLabel({ period: 'day', operator: 'between', selectionMode: mode, rollingUnit: unit, rollingCount: count }, mergedDateI18n) ?? '');
|
|
143
|
+
};
|
|
144
|
+
const rollingRadioKey = (unit, count) => `${unit}:${count}`;
|
|
145
|
+
const { selectionMode } = payload.date;
|
|
146
|
+
const selectedCount = resolveRollingCount(payload.date);
|
|
147
|
+
const selectedUnit = resolveRollingUnit(payload.date);
|
|
148
|
+
const isAllowedRolling = (unit, count) => {
|
|
149
|
+
const list = unit === 'day' ? rollingDayOpts : unit === 'month' ? rollingMonthOpts : unit === 'quarter' ? rollingQuarterOpts : rollingYearOpts;
|
|
150
|
+
return list.includes(count);
|
|
151
|
+
};
|
|
152
|
+
const nextRadioValue = selectionMode === 'rolling-next' && selectedCount != null && isAllowedRolling(selectedUnit, selectedCount)
|
|
153
|
+
? rollingRadioKey(selectedUnit, selectedCount)
|
|
154
|
+
: undefined;
|
|
155
|
+
const lastRadioValue = selectionMode === 'rolling-last' && selectedCount != null && isAllowedRolling(selectedUnit, selectedCount)
|
|
156
|
+
? rollingRadioKey(selectedUnit, selectedCount)
|
|
157
|
+
: undefined;
|
|
158
|
+
const isNextBranchActive = selectionMode === 'rolling-next';
|
|
159
|
+
const isLastBranchActive = selectionMode === 'rolling-last';
|
|
160
|
+
const isCustomRangeActive = selectionMode === 'custom';
|
|
161
|
+
const mainMenuActiveIcon = (show) => (show ? _jsx(Check, { className: "ml-auto size-4 shrink-0 text-foreground", "aria-hidden": true }) : null);
|
|
162
|
+
const openCustomDialog = () => {
|
|
163
|
+
setMenuOpen(false);
|
|
164
|
+
setCustomDraft(dateMetricValueForCustomEditor(payload.date));
|
|
165
|
+
setCustomOpen(true);
|
|
166
|
+
};
|
|
167
|
+
const commitCustomDialog = () => {
|
|
168
|
+
if (customDraft != null) {
|
|
169
|
+
setPayload({ ...payload, date: customDraft });
|
|
170
|
+
}
|
|
171
|
+
setCustomDraft(null);
|
|
172
|
+
setCustomOpen(false);
|
|
173
|
+
};
|
|
174
|
+
return (_jsxs(_Fragment, { children: [_jsx(ButtonGroupText, { size: size, className: "bg-background font-normal text-muted-foreground dark:bg-input/30", children: i18n.helpers.dateMetricDateConnector(payload.date, mergedDateI18n) }), _jsxs(DropdownMenu, { open: menuOpen, onOpenChange: setMenuOpen, children: [rollingRangeTooltip ? (_jsxs(Tooltip, { children: [_jsx(DropdownMenuTrigger, { render: _jsx(TooltipTrigger, { render: dateRangeTriggerButton }), children: _jsx("span", { children: dateSummary || i18n.select }) }), _jsx(TooltipContent, { side: "top", sideOffset: 6, className: "max-w-xs [text-wrap:pretty] tabular-nums", children: rollingRangeTooltip })] })) : (_jsx(DropdownMenuTrigger, { render: dateRangeTriggerButton, children: _jsx("span", { children: dateSummary || i18n.select }) })), _jsxs(DropdownMenuContent, { align: "center", className: "min-w-48", side: "bottom", children: [_jsxs(DropdownMenuSub, { children: [_jsx(DropdownMenuSubTrigger, { children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "min-w-0 shrink", children: mergedDateI18n.rollingWindowTabs.next }), mainMenuActiveIcon(isNextBranchActive)] }) }), _jsx(DropdownMenuSubContent, { align: "start", className: "max-h-none min-w-[13rem] overflow-visible p-2", children: _jsx(RollingWindowPresetGrid, { mode: "rolling-next", idPrefix: "next", i18n: mergedDateI18n, rollingDayOpts: rollingDayOpts, rollingMonthOpts: rollingMonthOpts, rollingQuarterOpts: rollingQuarterOpts, rollingYearOpts: rollingYearOpts, radioValue: nextRadioValue, rollingRadioKey: rollingRadioKey, labelForRolling: labelForRolling, onApply: (unit, count) => applyRolling('rolling-next', unit, count) }) })] }), _jsxs(DropdownMenuSub, { children: [_jsx(DropdownMenuSubTrigger, { children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "min-w-0 shrink", children: mergedDateI18n.rollingWindowTabs.last }), mainMenuActiveIcon(isLastBranchActive)] }) }), _jsx(DropdownMenuSubContent, { align: "start", className: "max-h-none min-w-[13rem] overflow-visible p-2", children: _jsx(RollingWindowPresetGrid, { mode: "rolling-last", idPrefix: "last", i18n: mergedDateI18n, rollingDayOpts: rollingDayOpts, rollingMonthOpts: rollingMonthOpts, rollingQuarterOpts: rollingQuarterOpts, rollingYearOpts: rollingYearOpts, radioValue: lastRadioValue, rollingRadioKey: rollingRadioKey, labelForRolling: labelForRolling, onApply: (unit, count) => applyRolling('rolling-last', unit, count) }) })] }), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { className: "gap-2", onClick: openCustomDialog, children: [_jsx("span", { className: "min-w-0 shrink", children: mergedDateI18n.rollingWindowTabs.custom }), mainMenuActiveIcon(isCustomRangeActive)] })] })] }), _jsx(Dialog, { open: customOpen, onOpenChange: (open) => {
|
|
175
|
+
setCustomOpen(open);
|
|
176
|
+
if (!open) {
|
|
177
|
+
setCustomDraft(null);
|
|
178
|
+
}
|
|
179
|
+
}, children: _jsxs(DialogContent, { className: "max-h-[min(90vh,32rem)] w-[min(calc(100vw-2rem),28rem)] gap-0 overflow-y-auto p-4 sm:max-w-none", children: [_jsx(DialogHeader, { className: "pb-2", children: _jsx(DialogTitle, { children: mergedDateI18n.selectDate }) }), _jsx("div", { className: "flex flex-col gap-6 py-2", children: _jsx("section", { className: "flex flex-col gap-2", children: _jsx(DateSelector, { ...field.dateMetricProps, className: cn('max-w-none space-y-3', field.dateMetricProps?.className), value: customDraft ?? dateMetricValueForCustomEditor(payload.date), onChange: setCustomDraft, showOperators: field.dateMetricProps?.showOperators !== false, showInput: field.dateMetricProps?.showInput ?? false, dayDateFormat: dayFormat, showRollingPresets: false }) }) }), _jsx(DialogFooter, { className: "mt-2 border-t pt-4 sm:justify-end", children: _jsx(Button, { type: "button", size: "sm", variant: "default", onClick: commitCustomDialog, children: i18n.dateMetricDialogDone }) })] }) })] }));
|
|
180
|
+
}
|
|
181
|
+
/** Typographic en dash (–) for “no amount” on the bar trigger. */
|
|
182
|
+
const METRIC_EMPTY_AMOUNT = '\u2013';
|
|
183
|
+
/** Spaces around the en dash so empty segments don’t feel cramped (e.g. `$ – `). */
|
|
184
|
+
const METRIC_EMPTY_DISPLAY = ` ${METRIC_EMPTY_AMOUNT} `;
|
|
185
|
+
const metricAmountFormatters = new Map();
|
|
186
|
+
const metricIntegerFormatters = new Map();
|
|
187
|
+
const metricPercentFormatters = new Map();
|
|
188
|
+
const metricPercentSuffixLiteralByLocale = new Map();
|
|
189
|
+
function formatMetricAmountDigits(value, locale) {
|
|
190
|
+
let nf = metricAmountFormatters.get(locale);
|
|
191
|
+
if (!nf) {
|
|
192
|
+
try {
|
|
193
|
+
nf = new Intl.NumberFormat(locale, {
|
|
194
|
+
minimumFractionDigits: 0,
|
|
195
|
+
maximumFractionDigits: 20,
|
|
196
|
+
useGrouping: true,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
nf = new Intl.NumberFormat('en-US', {
|
|
201
|
+
minimumFractionDigits: 0,
|
|
202
|
+
maximumFractionDigits: 20,
|
|
203
|
+
useGrouping: true,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
metricAmountFormatters.set(locale, nf);
|
|
207
|
+
}
|
|
208
|
+
return nf.format(value);
|
|
209
|
+
}
|
|
210
|
+
function formatMetricIntegerDigits(value, locale) {
|
|
211
|
+
let nf = metricIntegerFormatters.get(locale);
|
|
212
|
+
if (!nf) {
|
|
213
|
+
try {
|
|
214
|
+
nf = new Intl.NumberFormat(locale, { maximumFractionDigits: 0, useGrouping: true });
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
nf = new Intl.NumberFormat('en-US', { maximumFractionDigits: 0, useGrouping: true });
|
|
218
|
+
}
|
|
219
|
+
metricIntegerFormatters.set(locale, nf);
|
|
220
|
+
}
|
|
221
|
+
return nf.format(value);
|
|
222
|
+
}
|
|
223
|
+
function dateMetricBarValueFormat(field) {
|
|
224
|
+
return field.dateMetricValueFormat ?? 'currency';
|
|
225
|
+
}
|
|
226
|
+
/** Suffix literals from `Intl` for an empty percent segment (locale-specific spacing, RTL, etc.). */
|
|
227
|
+
function percentBarSuffixLiteral(locale) {
|
|
228
|
+
let s = metricPercentSuffixLiteralByLocale.get(locale);
|
|
229
|
+
if (s !== undefined)
|
|
230
|
+
return s;
|
|
231
|
+
try {
|
|
232
|
+
const nf = new Intl.NumberFormat(locale, { style: 'percent', maximumFractionDigits: 0 });
|
|
233
|
+
s = nf
|
|
234
|
+
.formatToParts(1)
|
|
235
|
+
.filter((p) => p.type === 'literal')
|
|
236
|
+
.map((p) => p.value)
|
|
237
|
+
.join('');
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
s = '%';
|
|
241
|
+
}
|
|
242
|
+
if (!s)
|
|
243
|
+
s = '%';
|
|
244
|
+
metricPercentSuffixLiteralByLocale.set(locale, s);
|
|
245
|
+
return s;
|
|
246
|
+
}
|
|
247
|
+
/** `value` is percentage points (e.g. 85 → 85%); `Intl` expects a ratio, so divide by 100. */
|
|
248
|
+
function formatMetricPercentFromPercentagePoints(value, locale) {
|
|
249
|
+
let nf = metricPercentFormatters.get(locale);
|
|
250
|
+
if (!nf) {
|
|
251
|
+
try {
|
|
252
|
+
nf = new Intl.NumberFormat(locale, {
|
|
253
|
+
style: 'percent',
|
|
254
|
+
minimumFractionDigits: 0,
|
|
255
|
+
maximumFractionDigits: 20,
|
|
256
|
+
useGrouping: true,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
nf = new Intl.NumberFormat('en-US', {
|
|
261
|
+
style: 'percent',
|
|
262
|
+
minimumFractionDigits: 0,
|
|
263
|
+
maximumFractionDigits: 20,
|
|
264
|
+
useGrouping: true,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
metricPercentFormatters.set(locale, nf);
|
|
268
|
+
}
|
|
269
|
+
return nf.format(value / 100);
|
|
270
|
+
}
|
|
271
|
+
/** Bar label for a single threshold: currency, percent, or integer locale formatting. */
|
|
272
|
+
function formatDateMetricBarAmount(value, format, locale, currencySym) {
|
|
273
|
+
if (format === 'currency') {
|
|
274
|
+
if (value == null || Number.isNaN(value))
|
|
275
|
+
return `${currencySym}${METRIC_EMPTY_DISPLAY}`;
|
|
276
|
+
return `${currencySym}${formatMetricAmountDigits(value, locale)}`;
|
|
277
|
+
}
|
|
278
|
+
if (format === 'integer') {
|
|
279
|
+
if (value == null || Number.isNaN(value))
|
|
280
|
+
return METRIC_EMPTY_DISPLAY;
|
|
281
|
+
return formatMetricIntegerDigits(value, locale);
|
|
282
|
+
}
|
|
283
|
+
if (value == null || Number.isNaN(value))
|
|
284
|
+
return `${METRIC_EMPTY_DISPLAY}${percentBarSuffixLiteral(locale)}`;
|
|
285
|
+
return formatMetricPercentFromPercentagePoints(value, locale);
|
|
286
|
+
}
|
|
287
|
+
function parseDraftNumber(raw, previous) {
|
|
288
|
+
if (raw.trim() === '')
|
|
289
|
+
return null;
|
|
290
|
+
const n = Number(raw);
|
|
291
|
+
if (!Number.isFinite(n))
|
|
292
|
+
return previous ?? null;
|
|
293
|
+
return n;
|
|
294
|
+
}
|
|
295
|
+
const METRIC_POPOVER_TRIGGER_NARROW = 'max-w-[min(100%,14rem)] shrink-0 justify-start font-medium tabular-nums';
|
|
296
|
+
const METRIC_POPOVER_TRIGGER_WIDE = 'max-w-[min(100%,18rem)] shrink-0 justify-start text-start font-medium [text-wrap:pretty] whitespace-normal tabular-nums';
|
|
297
|
+
function MetricValueThresholdPopoverShell({ open, onOpenChange, buttonSize, triggerLabel, summary, triggerClassName, children, }) {
|
|
298
|
+
return (_jsxs(Popover, { open: open, onOpenChange: onOpenChange, children: [_jsx(PopoverTrigger, { render: _jsx(Button, { type: "button", variant: "outline", size: buttonSize, className: triggerClassName, "aria-label": triggerLabel, "aria-expanded": open }), children: summary }), _jsx(PopoverContent, { align: "start", side: "bottom", className: "w-(--anchor-width) max-w-none min-w-[8rem] gap-0 p-1.5", children: children })] }));
|
|
299
|
+
}
|
|
300
|
+
/** Value inputs / “any value” control for a date metric filter bar (after field, “in”, range, and operator). */
|
|
301
|
+
export function FilterDateMetricBarValueSegment({ field, values, onChange, operator, i18n, size, onOperatorChange, }) {
|
|
302
|
+
const [metricPopoverOpen, setMetricPopoverOpen] = useState(false);
|
|
303
|
+
const [draftMin, setDraftMin] = useState('');
|
|
304
|
+
const [draftMax, setDraftMax] = useState('');
|
|
305
|
+
const draftMinRef = useRef('');
|
|
306
|
+
const draftMaxRef = useRef('');
|
|
307
|
+
const payload = useMemo(() => getDateMetricPayloadFromValues(values), [values]);
|
|
308
|
+
const commitMetricFromDraft = useCallback(() => {
|
|
309
|
+
const base = getDateMetricPayloadFromValues(values);
|
|
310
|
+
const min = parseDraftNumber(draftMinRef.current, base.min ?? null);
|
|
311
|
+
const max = parseDraftNumber(draftMaxRef.current, base.max ?? null);
|
|
312
|
+
if (operator === 'value_greater_than') {
|
|
313
|
+
onChange([{ ...base, min }]);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
if (operator === 'value_less_than') {
|
|
317
|
+
onChange([{ ...base, max }]);
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
if (operator === 'value_between') {
|
|
321
|
+
onChange([{ ...base, min, max }]);
|
|
322
|
+
}
|
|
323
|
+
}, [operator, values, onChange]);
|
|
324
|
+
const handleMetricPopoverOpenChange = useCallback((open) => {
|
|
325
|
+
if (open) {
|
|
326
|
+
const base = getDateMetricPayloadFromValues(values);
|
|
327
|
+
const dm = base.min != null ? String(base.min) : '';
|
|
328
|
+
const dx = base.max != null ? String(base.max) : '';
|
|
329
|
+
draftMinRef.current = dm;
|
|
330
|
+
draftMaxRef.current = dx;
|
|
331
|
+
setDraftMin(dm);
|
|
332
|
+
setDraftMax(dx);
|
|
333
|
+
setMetricPopoverOpen(true);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
setMetricPopoverOpen((wasOpen) => {
|
|
337
|
+
if (wasOpen) {
|
|
338
|
+
commitMetricFromDraft();
|
|
339
|
+
}
|
|
340
|
+
return false;
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
}, [values, commitMetricFromDraft]);
|
|
344
|
+
const handleMetricValueInputKeyDown = useCallback((e) => {
|
|
345
|
+
if (e.key !== 'Enter')
|
|
346
|
+
return;
|
|
347
|
+
e.preventDefault();
|
|
348
|
+
handleMetricPopoverOpenChange(false);
|
|
349
|
+
}, [handleMetricPopoverOpenChange]);
|
|
350
|
+
const operators = useMemo(() => getOperatorsForField(field, values, i18n), [field, values, i18n]);
|
|
351
|
+
const valueAnyOperator = operators.find((o) => o.value === 'value_any');
|
|
352
|
+
const sym = i18n.defaultCurrency;
|
|
353
|
+
const numberLocale = i18n.numberFormatLocale;
|
|
354
|
+
const barValueFormat = dateMetricBarValueFormat(field);
|
|
355
|
+
const inputSizeProp = size === 'lg' ? 'default' : 'sm';
|
|
356
|
+
const buttonSize = size === 'lg' ? 'lg' : size === 'sm' ? 'sm' : 'default';
|
|
357
|
+
const valueSegment = (() => {
|
|
358
|
+
if (operator === 'value_any') {
|
|
359
|
+
const anyLabel = i18n.operators.valueAny;
|
|
360
|
+
const anyIcon = valueAnyOperator?.icon;
|
|
361
|
+
if (anyIcon) {
|
|
362
|
+
return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { render: _jsx(Button, { type: "button", variant: "outline", size: buttonSize, className: "min-w-8 shrink-0 px-2 font-normal text-muted-foreground hover:text-foreground [&_svg]:size-3.5", "aria-label": anyLabel, onClick: () => onOperatorChange?.('value_greater_than') }), children: anyIcon }), _jsx(TooltipContent, { side: "top", sideOffset: 6, children: anyLabel })] }));
|
|
363
|
+
}
|
|
364
|
+
return (_jsx(Button, { type: "button", variant: "outline", size: buttonSize, className: "max-w-[min(100%,14rem)] justify-start font-normal text-muted-foreground hover:text-foreground", "aria-label": anyLabel, onClick: () => onOperatorChange?.('value_greater_than'), children: anyLabel }));
|
|
365
|
+
}
|
|
366
|
+
if (operator === 'value_greater_than') {
|
|
367
|
+
const hasMinValue = payload.min != null && !Number.isNaN(payload.min);
|
|
368
|
+
const summary = formatDateMetricBarAmount(payload.min ?? undefined, barValueFormat, numberLocale, sym);
|
|
369
|
+
const triggerLabel = `${i18n.operators.greaterThan}: ${summary}`;
|
|
370
|
+
return (_jsx(MetricValueThresholdPopoverShell, { open: metricPopoverOpen, onOpenChange: handleMetricPopoverOpenChange, buttonSize: buttonSize, triggerLabel: triggerLabel, summary: summary, triggerClassName: cn(METRIC_POPOVER_TRIGGER_NARROW, !hasMinValue ? 'text-muted-foreground' : 'text-foreground'), children: _jsx(Input, { type: "number", size: inputSizeProp, className: "w-full min-w-0 tabular-nums", value: draftMin, onChange: (e) => {
|
|
371
|
+
const v = e.target.value;
|
|
372
|
+
draftMinRef.current = v;
|
|
373
|
+
setDraftMin(v);
|
|
374
|
+
}, onKeyDown: handleMetricValueInputKeyDown }) }));
|
|
375
|
+
}
|
|
376
|
+
if (operator === 'value_less_than') {
|
|
377
|
+
const hasMaxValue = payload.max != null && !Number.isNaN(payload.max);
|
|
378
|
+
const summary = formatDateMetricBarAmount(payload.max ?? undefined, barValueFormat, numberLocale, sym);
|
|
379
|
+
const triggerLabel = `${i18n.operators.lessThan}: ${summary}`;
|
|
380
|
+
return (_jsx(MetricValueThresholdPopoverShell, { open: metricPopoverOpen, onOpenChange: handleMetricPopoverOpenChange, buttonSize: buttonSize, triggerLabel: triggerLabel, summary: summary, triggerClassName: cn(METRIC_POPOVER_TRIGGER_NARROW, !hasMaxValue ? 'text-muted-foreground' : 'text-foreground'), children: _jsx(Input, { type: "number", size: inputSizeProp, className: "w-full min-w-0 tabular-nums", value: draftMax, onChange: (e) => {
|
|
381
|
+
const v = e.target.value;
|
|
382
|
+
draftMaxRef.current = v;
|
|
383
|
+
setDraftMax(v);
|
|
384
|
+
}, onKeyDown: handleMetricValueInputKeyDown }) }));
|
|
385
|
+
}
|
|
386
|
+
if (operator === 'value_between') {
|
|
387
|
+
const hasMinValue = payload.min != null && !Number.isNaN(payload.min);
|
|
388
|
+
const hasMaxValue = payload.max != null && !Number.isNaN(payload.max);
|
|
389
|
+
const minPart = formatDateMetricBarAmount(payload.min ?? undefined, barValueFormat, numberLocale, sym);
|
|
390
|
+
const maxPart = formatDateMetricBarAmount(payload.max ?? undefined, barValueFormat, numberLocale, sym);
|
|
391
|
+
const summary = `${minPart} - ${maxPart}`;
|
|
392
|
+
const triggerLabel = `${i18n.operators.between}: ${summary}`;
|
|
393
|
+
return (_jsx(MetricValueThresholdPopoverShell, { open: metricPopoverOpen, onOpenChange: handleMetricPopoverOpenChange, buttonSize: buttonSize, triggerLabel: triggerLabel, summary: summary, triggerClassName: cn(METRIC_POPOVER_TRIGGER_WIDE, !hasMinValue && !hasMaxValue ? 'text-muted-foreground' : 'text-foreground'), children: _jsxs("div", { className: "flex w-full flex-col gap-1.5", children: [_jsx(Input, { type: "number", size: inputSizeProp, className: "w-full min-w-0 tabular-nums", value: draftMin, onChange: (e) => {
|
|
394
|
+
const v = e.target.value;
|
|
395
|
+
draftMinRef.current = v;
|
|
396
|
+
setDraftMin(v);
|
|
397
|
+
}, onKeyDown: handleMetricValueInputKeyDown }), _jsx("div", { className: "pointer-events-none text-center text-xs text-muted-foreground select-none", "aria-hidden": true, children: "-" }), _jsx(Input, { type: "number", size: inputSizeProp, className: "w-full min-w-0 tabular-nums", value: draftMax, onChange: (e) => {
|
|
398
|
+
const v = e.target.value;
|
|
399
|
+
draftMaxRef.current = v;
|
|
400
|
+
setDraftMax(v);
|
|
401
|
+
}, onKeyDown: handleMetricValueInputKeyDown })] }) }));
|
|
402
|
+
}
|
|
403
|
+
return null;
|
|
404
|
+
})();
|
|
405
|
+
return valueSegment;
|
|
406
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { i18n as I18nInstance, TFunction } from 'i18next';
|
|
2
|
+
import type { DateSelectorI18nConfig } from '../../blocks/date-selector/date-selector-types';
|
|
3
|
+
import type { FilterFieldConfig, FilterFieldsConfig } from './filters-types';
|
|
4
|
+
/** Flat fields for minimal `Default` / `WithOneFilter` stories (real listing keys). */
|
|
5
|
+
export declare function buildListingDemoFields(t: TFunction): FilterFieldConfig[];
|
|
6
|
+
/** Grouped listing catalog for `GroupedFieldsAndSearch` (keys and shapes mirror app listing filters). */
|
|
7
|
+
export declare function buildListingGroupedFields(t: TFunction, dateSelectorI18n: DateSelectorI18nConfig, i18n: I18nInstance): FilterFieldsConfig;
|
|
8
|
+
/** Flat listing fields for docs previews (no filter i18n bundle required). */
|
|
9
|
+
export declare function buildListingDemoFieldsForDocs(): FilterFieldConfig[];
|
|
10
|
+
/** Grouped listing catalog for docs previews; pass docs `I18nextProvider` instance and date-selector copy. */
|
|
11
|
+
export declare function buildListingGroupedFieldsForDocs(dateSelectorI18n: DateSelectorI18nConfig, i18n: I18nInstance): FilterFieldsConfig;
|
|
12
|
+
//# sourceMappingURL=filter-fields-listing-demo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-fields-listing-demo.d.ts","sourceRoot":"","sources":["../../../src/components/filters/filter-fields-listing-demo.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,IAAI,YAAY,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAyB/D,OAAO,KAAK,EAAE,sBAAsB,EAA8C,MAAM,gDAAgD,CAAC;AACzI,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAkB,MAAM,iBAAiB,CAAC;AA0D7F,uFAAuF;AACvF,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,SAAS,GAAG,iBAAiB,EAAE,CA+BxE;AAED,yGAAyG;AACzG,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,SAAS,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,IAAI,EAAE,YAAY,GAAG,kBAAkB,CA0dxI;AAED,8EAA8E;AAC9E,wBAAgB,6BAA6B,IAAI,iBAAiB,EAAE,CAEnE;AAED,8GAA8G;AAC9G,wBAAgB,gCAAgC,CAAC,gBAAgB,EAAE,sBAAsB,EAAE,IAAI,EAAE,YAAY,GAAG,kBAAkB,CAEjI"}
|