@pos-360/horizon 0.28.0 → 0.29.0

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.
@@ -1,4 +1,4 @@
1
- import { cn, Label, Tooltip, mergeRefs } from './chunk-EZDGMHS7.mjs';
1
+ import { cn, Label, Tooltip, Text, mergeRefs } from './chunk-EZDGMHS7.mjs';
2
2
  import * as React10 from 'react';
3
3
  import { useState, useEffect, useCallback } from 'react';
4
4
  import { Slot } from '@radix-ui/react-slot';
@@ -2122,16 +2122,16 @@ function TimeInput({
2122
2122
  setEditValue(raw);
2123
2123
  return;
2124
2124
  }
2125
+ if (raw.length === 1) {
2126
+ setEditValue(raw);
2127
+ return;
2128
+ }
2125
2129
  const parsed = parseInt(raw, 10);
2126
2130
  const clamped = clamp(parsed, min, max);
2127
- const display = parsed !== clamped ? pad(clamped) : raw;
2128
- setEditValue(display);
2129
- if (raw.length === 2) {
2130
- committedRef.current = true;
2131
- onChange(clamped);
2132
- setEditValue(null);
2133
- onComplete?.();
2134
- }
2131
+ committedRef.current = true;
2132
+ onChange(clamped);
2133
+ setEditValue(null);
2134
+ onComplete?.();
2135
2135
  };
2136
2136
  const commit = () => {
2137
2137
  if (committedRef.current) {
@@ -2250,7 +2250,7 @@ function TimeField({
2250
2250
  const focusMinute = () => {
2251
2251
  minuteInputRef.current?.focus();
2252
2252
  };
2253
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2253
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 justify-between", children: [
2254
2254
  /* @__PURE__ */ jsx(
2255
2255
  "span",
2256
2256
  {
@@ -2309,6 +2309,80 @@ function TimeField({
2309
2309
  ] })
2310
2310
  ] });
2311
2311
  }
2312
+ function TimePickerColumn({ value, onChange, disabled = false }) {
2313
+ const toHourRef = React10.useRef(null);
2314
+ const fromSet = isTimeSet(value.from);
2315
+ const toSet = isTimeSet(value.to);
2316
+ const bothSet = fromSet && toSet;
2317
+ const fromMinutes = (value.from.hour ?? 0) * 60 + (value.from.minute ?? 0);
2318
+ const toMinutes = (value.to.hour ?? 0) * 60 + (value.to.minute ?? 0);
2319
+ const bothEqual = fromMinutes === toMinutes;
2320
+ const isOvernight = bothSet && toMinutes < fromMinutes;
2321
+ const durationMinutes = bothSet && !bothEqual ? isOvernight ? 24 * 60 - fromMinutes + toMinutes : toMinutes - fromMinutes : 0;
2322
+ const durationHours = Math.floor(durationMinutes / 60);
2323
+ const durationRemaining = durationMinutes % 60;
2324
+ const showDuration = bothSet && !bothEqual;
2325
+ const durationLabel = durationRemaining > 0 ? `${durationHours}h ${durationRemaining}m window${isOvernight ? " (overnight)" : ""}` : `${durationHours}h window${isOvernight ? " (overnight)" : ""}`;
2326
+ return /* @__PURE__ */ jsxs(
2327
+ "div",
2328
+ {
2329
+ className: cn(
2330
+ "flex flex-col px-2 pt-2 pb-2 gap-1",
2331
+ "border-t border-gray-100 dark:border-neutral-700"
2332
+ ),
2333
+ children: [
2334
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2335
+ /* @__PURE__ */ jsx(
2336
+ Clock,
2337
+ {
2338
+ className: cn(
2339
+ "w-4 h-4 shrink-0",
2340
+ disabled ? "text-gray-300 dark:text-gray-600" : "text-gray-400 dark:text-gray-500"
2341
+ )
2342
+ }
2343
+ ),
2344
+ /* @__PURE__ */ jsx(
2345
+ "span",
2346
+ {
2347
+ className: cn(
2348
+ "text-xs font-semibold uppercase tracking-wider",
2349
+ disabled ? "text-gray-300 dark:text-gray-600" : "text-gray-400 dark:text-gray-500"
2350
+ ),
2351
+ children: "Time"
2352
+ }
2353
+ ),
2354
+ /* @__PURE__ */ jsx("span", { className: "text-[9px] font-medium text-gray-400 dark:text-gray-600 tracking-wide", children: "(Optional)" })
2355
+ ] }),
2356
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 pl-6", children: [
2357
+ /* @__PURE__ */ jsx(
2358
+ TimeField,
2359
+ {
2360
+ label: "From",
2361
+ value: value.from,
2362
+ onChange: (from) => onChange({ ...value, from }),
2363
+ onMinuteComplete: () => toHourRef.current?.focus(),
2364
+ disabled
2365
+ }
2366
+ ),
2367
+ /* @__PURE__ */ jsx(
2368
+ TimeField,
2369
+ {
2370
+ label: "To",
2371
+ value: value.to,
2372
+ onChange: (to) => onChange({ ...value, to }),
2373
+ hourRef: toHourRef,
2374
+ disabled
2375
+ }
2376
+ ),
2377
+ showDuration && /* @__PURE__ */ jsx("span", { className: cn(
2378
+ "text-[10px] font-medium",
2379
+ isOvernight ? "text-amber-500 dark:text-amber-400" : "text-gray-400 dark:text-gray-500"
2380
+ ), children: durationLabel })
2381
+ ] })
2382
+ ]
2383
+ }
2384
+ );
2385
+ }
2312
2386
  function TimePickerRow({ value, onChange, disabled = false }) {
2313
2387
  const toHourRef = React10.useRef(null);
2314
2388
  const fromSet = isTimeSet(value.from);
@@ -2627,11 +2701,17 @@ function DateRangePicker({
2627
2701
  };
2628
2702
  const handlePreset = (preset) => {
2629
2703
  const newRange = preset.getRange();
2630
- if (onChange) onChange(newRange);
2631
- else setInternalRange(newRange);
2632
- setActivePreset(preset.label);
2633
- if (newRange.from) setLeftMonth(startOfMonth(newRange.from));
2634
- setOpen(false);
2704
+ if (showTimePicker) {
2705
+ setDraft(newRange);
2706
+ setActivePreset(preset.label);
2707
+ if (newRange.from) setLeftMonth(startOfMonth(newRange.from));
2708
+ } else {
2709
+ if (onChange) onChange(newRange);
2710
+ else setInternalRange(newRange);
2711
+ setActivePreset(preset.label);
2712
+ if (newRange.from) setLeftMonth(startOfMonth(newRange.from));
2713
+ setOpen(false);
2714
+ }
2635
2715
  };
2636
2716
  const handleApply = () => {
2637
2717
  if (draft.from && !draft.to) return;
@@ -2769,6 +2849,399 @@ function DateRangePicker({
2769
2849
  ] }) })
2770
2850
  ] });
2771
2851
  }
2852
+ function formatTime2(tv) {
2853
+ if (tv.hour === null || tv.minute === null) return "";
2854
+ const period = tv.hour >= 12 ? "PM" : "AM";
2855
+ const h = tv.hour % 12 || 12;
2856
+ const m = tv.minute.toString().padStart(2, "0");
2857
+ return `${h}:${m} ${period}`;
2858
+ }
2859
+ function formatDateWithTime(date, dateFmt, time) {
2860
+ const dateStr = format(date, dateFmt);
2861
+ const timeStr = time ? formatTime2(time) : "";
2862
+ return timeStr ? `${dateStr}, ${timeStr}` : dateStr;
2863
+ }
2864
+ function formatDateRange2(range, placeholder, time) {
2865
+ if (!range?.from) return placeholder;
2866
+ const hasTime = time && time.from.hour !== null && time.to.hour !== null;
2867
+ if (!range.to || isSameDay(range.from, range.to)) {
2868
+ return formatDateWithTime(range.from, "MMMM d, yyyy", hasTime ? time.from : void 0);
2869
+ }
2870
+ const sameYear = range.from.getFullYear() === range.to.getFullYear();
2871
+ const fromFmt = sameYear ? "MMMM d" : "MMMM d, yyyy";
2872
+ const fromStr = formatDateWithTime(range.from, fromFmt, hasTime ? time.from : void 0);
2873
+ const toStr = formatDateWithTime(range.to, "MMMM d, yyyy", hasTime ? time.to : void 0);
2874
+ return `${fromStr} \u2013 ${toStr}`;
2875
+ }
2876
+ function DateRangePickerMobile({
2877
+ label,
2878
+ value,
2879
+ onChange,
2880
+ presets = DEFAULT_PRESETS,
2881
+ presetSections,
2882
+ placeholder = "Select date range",
2883
+ disabled = false,
2884
+ className,
2885
+ showTimePicker = false,
2886
+ timeValue,
2887
+ onTimeChange
2888
+ }) {
2889
+ const [open, setOpen] = React10.useState(false);
2890
+ const [internalRange, setInternalRange] = React10.useState({
2891
+ from: void 0,
2892
+ to: void 0
2893
+ });
2894
+ const [draft, setDraft] = React10.useState({
2895
+ from: void 0,
2896
+ to: void 0
2897
+ });
2898
+ const [hoverDate, setHoverDate] = React10.useState();
2899
+ const [viewMonth, setViewMonth] = React10.useState(
2900
+ () => startOfMonth(value?.from ?? /* @__PURE__ */ new Date())
2901
+ );
2902
+ const [activePreset, setActivePreset] = React10.useState();
2903
+ const [internalTime, setInternalTime] = React10.useState(DEFAULT_TIME_RANGE);
2904
+ const committedRange = value ?? internalRange;
2905
+ const currentTime = timeValue ?? internalTime;
2906
+ const handleTimeChange = (newTime) => {
2907
+ if (onTimeChange) onTimeChange(newTime);
2908
+ else setInternalTime(newTime);
2909
+ };
2910
+ const timeVisible = !!(draft.from && draft.to);
2911
+ const handleOpenChange = (newOpen) => {
2912
+ if (newOpen) {
2913
+ setDraft(committedRange);
2914
+ if (committedRange.from) setViewMonth(startOfMonth(committedRange.from));
2915
+ if (!onTimeChange) setInternalTime(currentTime);
2916
+ }
2917
+ setOpen(newOpen);
2918
+ };
2919
+ const handleDayClick = (date) => {
2920
+ const { from, to } = draft;
2921
+ if (!from || from && to) {
2922
+ setDraft({ from: date, to: void 0 });
2923
+ setActivePreset(void 0);
2924
+ return;
2925
+ }
2926
+ const [start, end] = isBefore(from, date) ? [from, date] : [date, from];
2927
+ setDraft({ from: start, to: end });
2928
+ setHoverDate(void 0);
2929
+ };
2930
+ const handlePreset = (preset) => {
2931
+ const newRange = preset.getRange();
2932
+ if (showTimePicker) {
2933
+ setDraft(newRange);
2934
+ setActivePreset(preset.label);
2935
+ if (newRange.from) setViewMonth(startOfMonth(newRange.from));
2936
+ } else {
2937
+ if (onChange) onChange(newRange);
2938
+ else setInternalRange(newRange);
2939
+ setActivePreset(preset.label);
2940
+ if (newRange.from) setViewMonth(startOfMonth(newRange.from));
2941
+ setOpen(false);
2942
+ }
2943
+ };
2944
+ const handleApply = () => {
2945
+ if (draft.from && !draft.to) return;
2946
+ const newRange = draft.from && draft.to ? draft : void 0;
2947
+ if (onChange) onChange(newRange);
2948
+ else setInternalRange(newRange ?? { from: void 0, to: void 0 });
2949
+ setOpen(false);
2950
+ };
2951
+ const handleClear = () => {
2952
+ setDraft({ from: void 0, to: void 0 });
2953
+ setActivePreset(void 0);
2954
+ if (showTimePicker) handleTimeChange(DEFAULT_TIME_RANGE);
2955
+ };
2956
+ const canClear = !!(draft.from || committedRange.from);
2957
+ const canApply = !(draft.from && !draft.to) && !!(draft.from || committedRange.from);
2958
+ return /* @__PURE__ */ jsxs("div", { className: cn("space-y-1.5", className), children: [
2959
+ label && /* @__PURE__ */ jsx(Label, { className: "text-sm font-medium text-gray-900 dark:text-gray-100", children: label }),
2960
+ /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: handleOpenChange, children: [
2961
+ /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
2962
+ "button",
2963
+ {
2964
+ disabled,
2965
+ className: cn(
2966
+ "inline-flex w-full items-center gap-2 rounded-md border border-gray-300 bg-white px-3 py-2 text-sm shadow-sm transition-colors",
2967
+ "hover:bg-gray-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2",
2968
+ "dark:border-neutral-600 dark:bg-neutral-800 dark:hover:bg-neutral-700",
2969
+ "disabled:pointer-events-none disabled:opacity-50",
2970
+ committedRange.from ? "text-gray-900 dark:text-gray-100" : "text-gray-400 dark:text-gray-500"
2971
+ ),
2972
+ children: [
2973
+ /* @__PURE__ */ jsx(CalendarIcon, { className: "w-4 h-4 shrink-0 text-gray-400 dark:text-gray-500" }),
2974
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: formatDateRange2(
2975
+ committedRange,
2976
+ placeholder,
2977
+ showTimePicker ? currentTime : void 0
2978
+ ) })
2979
+ ]
2980
+ }
2981
+ ) }),
2982
+ /* @__PURE__ */ jsx(PopoverContent, { align: "center", className: "w-auto p-0 overflow-hidden", children: /* @__PURE__ */ jsxs("div", { className: "flex divide-x divide-gray-100 dark:divide-neutral-700", children: [
2983
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col p-2 gap-0.5 min-w-[110px] max-h-[360px] overflow-y-auto", children: (presetSections ?? [{ title: "Presets", options: presets }]).map(
2984
+ (section, si) => /* @__PURE__ */ jsxs(React10.Fragment, { children: [
2985
+ si > 0 && /* @__PURE__ */ jsx("div", { className: "my-2 border-t border-gray-100 dark:border-neutral-700" }),
2986
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-semibold text-gray-400 dark:text-gray-500 uppercase tracking-wider mb-1 px-2", children: section.title }),
2987
+ section.options.map((preset) => /* @__PURE__ */ jsx(
2988
+ "button",
2989
+ {
2990
+ onClick: () => handlePreset(preset),
2991
+ className: cn(
2992
+ "w-full text-left px-2 py-1.5 rounded-md text-sm transition-colors",
2993
+ activePreset === preset.label ? "bg-blue-50 text-blue-600 font-medium dark:bg-blue-950/50 dark:text-blue-400" : "text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-neutral-700"
2994
+ ),
2995
+ children: preset.label
2996
+ },
2997
+ preset.label
2998
+ ))
2999
+ ] }, section.title)
3000
+ ) }),
3001
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
3002
+ /* @__PURE__ */ jsx("div", { className: "p-2", children: /* @__PURE__ */ jsx(
3003
+ CalendarMonth,
3004
+ {
3005
+ month: viewMonth,
3006
+ range: draft,
3007
+ hoverDate,
3008
+ onDayClick: handleDayClick,
3009
+ onDayHover: setHoverDate,
3010
+ onPrevMonth: () => setViewMonth(subMonths(viewMonth, 1)),
3011
+ onNextMonth: () => setViewMonth(addMonths(viewMonth, 1)),
3012
+ showPrevNav: true,
3013
+ showNextNav: true
3014
+ }
3015
+ ) }),
3016
+ showTimePicker && /* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: timeVisible && /* @__PURE__ */ jsx(
3017
+ motion.div,
3018
+ {
3019
+ initial: { height: 0, opacity: 0 },
3020
+ animate: { height: "auto", opacity: 1 },
3021
+ exit: { height: 0, opacity: 0 },
3022
+ transition: {
3023
+ height: {
3024
+ type: "spring",
3025
+ stiffness: 400,
3026
+ damping: 30,
3027
+ mass: 0.8
3028
+ },
3029
+ opacity: { duration: 0.2 }
3030
+ },
3031
+ className: "overflow-hidden",
3032
+ children: /* @__PURE__ */ jsx(
3033
+ TimePickerColumn,
3034
+ {
3035
+ value: currentTime,
3036
+ onChange: handleTimeChange
3037
+ }
3038
+ )
3039
+ },
3040
+ "time-picker"
3041
+ ) }),
3042
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-2 px-2 py-3 border-t border-gray-100 dark:border-neutral-700", children: [
3043
+ /* @__PURE__ */ jsx(
3044
+ "button",
3045
+ {
3046
+ onClick: handleClear,
3047
+ disabled: !canClear,
3048
+ className: cn(
3049
+ "px-3 py-1.5 rounded-md text-sm transition-colors",
3050
+ canClear ? "text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-neutral-700" : "text-gray-300 dark:text-gray-600 cursor-not-allowed"
3051
+ ),
3052
+ children: "Clear"
3053
+ }
3054
+ ),
3055
+ /* @__PURE__ */ jsx(
3056
+ "button",
3057
+ {
3058
+ onClick: handleApply,
3059
+ disabled: !canApply,
3060
+ className: cn(
3061
+ "px-3 py-1.5 rounded-md text-sm font-medium transition-colors",
3062
+ canApply ? "bg-blue-600 text-white hover:bg-blue-700 dark:hover:bg-blue-500" : "bg-blue-100 text-blue-300 cursor-not-allowed dark:bg-blue-950/30 dark:text-blue-800"
3063
+ ),
3064
+ children: "Apply"
3065
+ }
3066
+ )
3067
+ ] })
3068
+ ] })
3069
+ ] }) })
3070
+ ] })
3071
+ ] });
3072
+ }
3073
+ var colsClass = {
3074
+ 2: "grid-cols-2",
3075
+ 3: "grid-cols-3",
3076
+ 4: "grid-cols-4",
3077
+ 5: "grid-cols-5"
3078
+ };
3079
+ function MobileDataCard({
3080
+ title,
3081
+ subtitle,
3082
+ image,
3083
+ contentRows,
3084
+ onPress,
3085
+ showChevron,
3086
+ selectBar,
3087
+ stats,
3088
+ statColumns,
3089
+ statsRenderer,
3090
+ details,
3091
+ extraContent,
3092
+ className
3093
+ }) {
3094
+ const isSelected = selectBar?.isSelected ?? false;
3095
+ const chevronVisible = showChevron ?? !!onPress;
3096
+ const contentBody = /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3 px-3 py-3", children: [
3097
+ image && /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: image }),
3098
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-2", children: [
3099
+ /* @__PURE__ */ jsx(
3100
+ Text,
3101
+ {
3102
+ size: "sm",
3103
+ weight: "semibold",
3104
+ className: "truncate leading-tight text-neutral-900 dark:text-neutral-100",
3105
+ children: title
3106
+ }
3107
+ ),
3108
+ subtitle && /* @__PURE__ */ jsx(Text, { size: "xs", className: "text-neutral-400 dark:text-neutral-500", children: subtitle }),
3109
+ contentRows && contentRows.length > 0 && /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-x-4 gap-y-1 text-xs", children: contentRows.map((row) => /* @__PURE__ */ jsxs("div", { className: "truncate", children: [
3110
+ /* @__PURE__ */ jsxs("span", { className: "text-neutral-400 dark:text-neutral-500", children: [
3111
+ row.label,
3112
+ " "
3113
+ ] }),
3114
+ /* @__PURE__ */ jsx("span", { className: "text-neutral-700 dark:text-neutral-300", children: row.value })
3115
+ ] }, row.label)) })
3116
+ ] }),
3117
+ chevronVisible && /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4 flex-shrink-0 self-center text-neutral-300 dark:text-neutral-600" })
3118
+ ] });
3119
+ const hasStats = stats && stats.length > 0 || !!statsRenderer;
3120
+ const hasDetails = details && details.length > 0;
3121
+ const cols = statColumns ?? stats?.length ?? 2;
3122
+ return /* @__PURE__ */ jsxs(
3123
+ "div",
3124
+ {
3125
+ className: cn(
3126
+ "overflow-hidden rounded-lg border transition-colors",
3127
+ isSelected ? "border-blue-500 bg-blue-50/50 dark:border-blue-400 dark:bg-blue-900/10" : "border-neutral-200 bg-white dark:border-neutral-700 dark:bg-neutral-800/30",
3128
+ className
3129
+ ),
3130
+ children: [
3131
+ selectBar && /* @__PURE__ */ jsxs(
3132
+ "div",
3133
+ {
3134
+ role: "button",
3135
+ tabIndex: 0,
3136
+ "aria-label": isSelected ? "Deselect item" : "Select item",
3137
+ onClick: selectBar.onToggle,
3138
+ onKeyDown: (e) => {
3139
+ if (e.key === "Enter" || e.key === " ") {
3140
+ e.preventDefault();
3141
+ selectBar.onToggle(e);
3142
+ }
3143
+ },
3144
+ className: "flex w-full cursor-pointer items-center gap-2.5 border-b border-neutral-100 px-3 py-1.5 focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-blue-500 dark:border-neutral-700/50",
3145
+ children: [
3146
+ /* @__PURE__ */ jsx(
3147
+ Checkbox,
3148
+ {
3149
+ checked: isSelected,
3150
+ className: "pointer-events-none",
3151
+ tabIndex: -1
3152
+ }
3153
+ ),
3154
+ /* @__PURE__ */ jsx(
3155
+ Text,
3156
+ {
3157
+ size: "xs",
3158
+ as: "span",
3159
+ className: cn(
3160
+ isSelected ? "font-medium text-blue-600 dark:text-blue-400" : "text-neutral-400 dark:text-neutral-500"
3161
+ ),
3162
+ children: isSelected ? "Selected" : "Select"
3163
+ }
3164
+ ),
3165
+ selectBar.badge && /* @__PURE__ */ jsx("span", { className: "ml-auto", children: selectBar.badge })
3166
+ ]
3167
+ }
3168
+ ),
3169
+ onPress ? /* @__PURE__ */ jsx(
3170
+ "button",
3171
+ {
3172
+ type: "button",
3173
+ onClick: onPress,
3174
+ className: "w-full text-left transition-colors active:bg-neutral-50 dark:active:bg-neutral-800",
3175
+ children: contentBody
3176
+ }
3177
+ ) : contentBody,
3178
+ statsRenderer ?? (stats && stats.length > 0 && /* @__PURE__ */ jsx("div", { className: cn("grid gap-1.5 px-3 pb-3", colsClass[cols]), children: stats.map((stat) => /* @__PURE__ */ jsxs(
3179
+ "div",
3180
+ {
3181
+ className: "flex flex-col items-center rounded-md bg-neutral-100 py-1.5 dark:bg-neutral-800",
3182
+ children: [
3183
+ /* @__PURE__ */ jsx(
3184
+ Text,
3185
+ {
3186
+ size: "xs",
3187
+ as: "span",
3188
+ className: "leading-none text-neutral-400 dark:text-neutral-500",
3189
+ children: stat.label
3190
+ }
3191
+ ),
3192
+ /* @__PURE__ */ jsx(
3193
+ Text,
3194
+ {
3195
+ size: "sm",
3196
+ weight: "semibold",
3197
+ as: "span",
3198
+ className: cn(
3199
+ "mt-0.5 tabular-nums",
3200
+ stat.className ?? "text-neutral-800 dark:text-neutral-200"
3201
+ ),
3202
+ children: stat.value
3203
+ }
3204
+ )
3205
+ ]
3206
+ },
3207
+ stat.label
3208
+ )) })),
3209
+ hasDetails && /* @__PURE__ */ jsxs(Fragment, { children: [
3210
+ hasStats && /* @__PURE__ */ jsx(Separator3, {}),
3211
+ /* @__PURE__ */ jsx("div", { className: "space-y-1 px-3 py-2", children: details.map((detail) => /* @__PURE__ */ jsxs(
3212
+ "div",
3213
+ {
3214
+ className: "flex items-center justify-between",
3215
+ children: [
3216
+ /* @__PURE__ */ jsx(
3217
+ Text,
3218
+ {
3219
+ size: "xs",
3220
+ as: "span",
3221
+ className: "text-neutral-400 dark:text-neutral-500",
3222
+ children: detail.label
3223
+ }
3224
+ ),
3225
+ detail.pill ? /* @__PURE__ */ jsx("span", { className: "inline-flex items-center rounded-full bg-blue-50 px-2 py-0.5 dark:bg-blue-900/30", children: /* @__PURE__ */ jsx(
3226
+ Text,
3227
+ {
3228
+ size: "xs",
3229
+ weight: "medium",
3230
+ as: "span",
3231
+ className: "text-blue-600 dark:text-blue-400",
3232
+ children: detail.value
3233
+ }
3234
+ ) }) : detail.value
3235
+ ]
3236
+ },
3237
+ detail.label
3238
+ )) })
3239
+ ] }),
3240
+ extraContent
3241
+ ]
3242
+ }
3243
+ );
3244
+ }
2772
3245
  var DEFAULT_COMPARISON_PERIODS = [
2773
3246
  {
2774
3247
  key: "yesterday",
@@ -2845,6 +3318,6 @@ function PeriodComparisonSelector({
2845
3318
  ] });
2846
3319
  }
2847
3320
 
2848
- export { Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, ColumnSelection, DEFAULT_COMPARISON_PERIODS, DEFAULT_PRESETS, DEFAULT_TIME_RANGE, DateRangePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Form, FormControl, FormDescription, FormField, FormLabel, FormMessage, PeriodComparisonSelector, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, SegmentedControl, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator3 as Separator, Skeleton, SkeletonAvatar, SkeletonBadge, SkeletonButton, SkeletonCard, SkeletonIcon, SkeletonInput, SkeletonSubtitle, SkeletonTableRow, SkeletonTableRows, SkeletonText, SkeletonTitle, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, TableRowCheckbox, TableSelectAll, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toggle, buttonVariants, segmentedControlItemVariants, segmentedControlVariants, separatorVariants, switchLabelVariants, switchThumbVariants, switchTrackVariants, toggleGroupVariants, toggleItemVariants, useColumnVisibility, useFormContext, useFormFieldContext, useTableSelection };
2849
- //# sourceMappingURL=chunk-SJJ6KXCU.mjs.map
2850
- //# sourceMappingURL=chunk-SJJ6KXCU.mjs.map
3321
+ export { Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, ColumnSelection, DEFAULT_COMPARISON_PERIODS, DEFAULT_PRESETS, DEFAULT_TIME_RANGE, DateRangePicker, DateRangePickerMobile, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Form, FormControl, FormDescription, FormField, FormLabel, FormMessage, MobileDataCard, PeriodComparisonSelector, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, SegmentedControl, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator3 as Separator, Skeleton, SkeletonAvatar, SkeletonBadge, SkeletonButton, SkeletonCard, SkeletonIcon, SkeletonInput, SkeletonSubtitle, SkeletonTableRow, SkeletonTableRows, SkeletonText, SkeletonTitle, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, TableRowCheckbox, TableSelectAll, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Toggle, buttonVariants, segmentedControlItemVariants, segmentedControlVariants, separatorVariants, switchLabelVariants, switchThumbVariants, switchTrackVariants, toggleGroupVariants, toggleItemVariants, useColumnVisibility, useFormContext, useFormFieldContext, useTableSelection };
3322
+ //# sourceMappingURL=chunk-PXBJSQUY.mjs.map
3323
+ //# sourceMappingURL=chunk-PXBJSQUY.mjs.map