@zendir/ui 0.1.13 → 0.1.15

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.
@@ -4,7 +4,84 @@ import { classNames, safeAccentText } from "../utils/index.js";
4
4
  import { Icon } from "../core/Icon.js";
5
5
  import { Badge } from "../core/Badge.js";
6
6
  import { Tooltip } from "../core/Tooltip.js";
7
+ import { Checkbox } from "../core/Checkbox.js";
7
8
  import { useTheme } from "../theme/ThemeProvider.js";
9
+ const ALL_TIMELINE_STATUSES = [
10
+ "off",
11
+ "standby",
12
+ "normal",
13
+ "caution",
14
+ "serious",
15
+ "critical"
16
+ ];
17
+ function getTimelineEventDisplayStatus(event) {
18
+ if (event.badgeVariant && event.badgeVariant !== "default" && event.badgeVariant !== "primary") {
19
+ return event.badgeVariant;
20
+ }
21
+ return event.status ?? "normal";
22
+ }
23
+ function isTimelineFilterActive(filter) {
24
+ return Boolean(
25
+ filter.search && filter.search.trim() || filter.tracks && filter.tracks.length > 0 || filter.status && filter.status.length > 0 || filter.eventShape && filter.eventShape !== "all" || filter.teamColoredOnly
26
+ );
27
+ }
28
+ function normalizeTimelineFilter(f) {
29
+ var _a, _b, _c;
30
+ const o = {};
31
+ const s = (_a = f.search) == null ? void 0 : _a.trim();
32
+ if (s) o.search = s;
33
+ if ((_b = f.tracks) == null ? void 0 : _b.length) o.tracks = [...f.tracks];
34
+ if ((_c = f.status) == null ? void 0 : _c.length) o.status = [...f.status];
35
+ if (f.eventShape && f.eventShape !== "all") o.eventShape = f.eventShape;
36
+ if (f.teamColoredOnly) o.teamColoredOnly = true;
37
+ return o;
38
+ }
39
+ function matchesTimelineFilter(event, filter) {
40
+ var _a, _b, _c, _d, _e;
41
+ if (!isTimelineFilterActive(filter)) return true;
42
+ if ((_a = filter.tracks) == null ? void 0 : _a.length) {
43
+ const tid = event.track ?? "default";
44
+ if (!filter.tracks.includes(tid)) return false;
45
+ }
46
+ if ((_b = filter.status) == null ? void 0 : _b.length) {
47
+ const ds = getTimelineEventDisplayStatus(event);
48
+ if (!filter.status.includes(ds)) return false;
49
+ }
50
+ const q = (_c = filter.search) == null ? void 0 : _c.trim().toLowerCase();
51
+ if (q) {
52
+ const argStr = event.arguments ? Object.values(event.arguments).map((v) => String(v)).join(" ") : "";
53
+ const hay = [
54
+ event.title,
55
+ event.subtitle,
56
+ event.badge,
57
+ event.track,
58
+ argStr
59
+ ].filter(Boolean).join(" ").toLowerCase();
60
+ if (!hay.includes(q)) return false;
61
+ }
62
+ if (filter.eventShape === "point") {
63
+ const endT = (_d = event.end) == null ? void 0 : _d.getTime();
64
+ const st = event.start.getTime();
65
+ if (endT != null && endT > st) return false;
66
+ }
67
+ if (filter.eventShape === "range") {
68
+ const endT = (_e = event.end) == null ? void 0 : _e.getTime();
69
+ const st = event.start.getTime();
70
+ if (endT == null || endT <= st) return false;
71
+ }
72
+ if (filter.teamColoredOnly && !event.color) return false;
73
+ return true;
74
+ }
75
+ function countTimelineFilterChips(filter) {
76
+ var _a, _b, _c;
77
+ let n = 0;
78
+ if ((_a = filter.search) == null ? void 0 : _a.trim()) n++;
79
+ if ((_b = filter.tracks) == null ? void 0 : _b.length) n++;
80
+ if ((_c = filter.status) == null ? void 0 : _c.length) n++;
81
+ if (filter.eventShape && filter.eventShape !== "all") n++;
82
+ if (filter.teamColoredOnly) n++;
83
+ return n;
84
+ }
8
85
  function TimelineStatusMarker({
9
86
  status,
10
87
  fillColor,
@@ -78,17 +155,32 @@ const EventListItem = memo(function EventListItem2({
78
155
  onMouseLeave: () => setHovered(false),
79
156
  onClick: () => onEventClick == null ? void 0 : onEventClick(event),
80
157
  style: {
158
+ position: "relative",
81
159
  flex: 1,
82
160
  marginBottom: "16px",
83
- padding: "16px 20px",
161
+ padding: event.color ? "19px 20px 16px 20px" : "16px 20px",
84
162
  backgroundColor: tokens.colors.background.surface,
85
163
  border: `1px solid ${hovered ? tokens.colors.accent.primary : tokens.colors.border.muted}`,
86
164
  borderRadius: tokens.borderRadius.lg,
87
165
  cursor: onEventClick ? "pointer" : "default",
88
166
  transition: "all 200ms cubic-bezier(0.4, 0, 0.2, 1)",
167
+ overflow: "hidden",
89
168
  boxShadow: hovered ? `0 4px 20px ${tokens.colors.accent.primary}15, 0 0 0 1px ${tokens.colors.accent.primary}20` : "none"
90
169
  },
91
170
  children: [
171
+ event.color && /* @__PURE__ */ jsx(
172
+ "div",
173
+ {
174
+ style: {
175
+ position: "absolute",
176
+ top: 0,
177
+ left: 0,
178
+ right: 0,
179
+ height: 3,
180
+ backgroundColor: event.color
181
+ }
182
+ }
183
+ ),
92
184
  /* @__PURE__ */ jsxs(
93
185
  "div",
94
186
  {
@@ -592,11 +684,12 @@ const ChartView = memo(function ChartView2({
592
684
  )),
593
685
  (eventsByTrack[track.id] || []).map((event) => {
594
686
  const { left, width } = getEventPosition(event);
595
- const color = getStatusColor(event.status);
687
+ const displayStatus = event.badgeVariant && event.badgeVariant !== "default" && event.badgeVariant !== "primary" ? event.badgeVariant : event.status ?? "normal";
688
+ const color = getStatusColor(displayStatus);
596
689
  const isHovered = hoveredEvent === event.id;
597
690
  const overlap = eventOverlaps[event.id];
598
691
  const hasOverlap = overlap && overlap.overlapCount > 0;
599
- const cardHeight = hasOverlap ? 28 : 36;
692
+ const cardHeight = hasOverlap ? 30 : 38;
600
693
  const stackOffset = overlap ? overlap.stackIndex * 30 : 0;
601
694
  const baseTop = ((track.height || trackHeight) - cardHeight) / 2;
602
695
  return /* @__PURE__ */ jsxs(
@@ -634,51 +727,71 @@ const ChartView = memo(function ChartView2({
634
727
  transform: isHovered ? "translateY(-3px) scale(1.02)" : "none"
635
728
  },
636
729
  children: [
637
- /* @__PURE__ */ jsx(
730
+ event.color ? /* @__PURE__ */ jsx(
638
731
  "div",
639
732
  {
640
733
  style: {
641
- width: 4,
642
- height: "100%",
643
- backgroundColor: color,
644
- flexShrink: 0,
645
- borderRadius: "2px 0 0 2px"
646
- }
734
+ position: "absolute",
735
+ top: 0,
736
+ left: 0,
737
+ right: 0,
738
+ height: 2,
739
+ backgroundColor: event.color,
740
+ borderRadius: "4px 4px 0 0",
741
+ zIndex: 1,
742
+ pointerEvents: "none"
743
+ },
744
+ "aria-hidden": true
647
745
  }
648
- ),
746
+ ) : null,
649
747
  /* @__PURE__ */ jsxs(
650
748
  "div",
651
749
  {
652
750
  style: {
653
751
  flex: 1,
654
- padding: "4px 8px",
752
+ padding: `${event.color ? 6 : 4}px 8px 4px 8px`,
655
753
  overflow: "hidden",
656
- minWidth: 0
754
+ minWidth: 0,
755
+ display: "flex",
756
+ flexDirection: "column",
757
+ justifyContent: "center"
657
758
  },
658
759
  children: [
659
- /* @__PURE__ */ jsx(
760
+ /* @__PURE__ */ jsxs(
660
761
  "div",
661
762
  {
662
763
  style: {
663
764
  display: "flex",
664
765
  alignItems: "center",
665
- gap: 4
766
+ gap: 6,
767
+ minWidth: 0
666
768
  },
667
- children: /* @__PURE__ */ jsx(
668
- "span",
669
- {
670
- style: {
671
- fontSize: "0.6875rem",
672
- fontWeight: 500,
673
- // AstroUXDS medium (was 600)
674
- color: "#fff",
675
- whiteSpace: "nowrap",
676
- overflow: "hidden",
677
- textOverflow: "ellipsis"
678
- },
679
- children: event.title
680
- }
681
- )
769
+ children: [
770
+ /* @__PURE__ */ jsx(
771
+ TimelineStatusMarker,
772
+ {
773
+ status: displayStatus,
774
+ fillColor: color,
775
+ size: hasOverlap ? 8 : 10
776
+ }
777
+ ),
778
+ /* @__PURE__ */ jsx(
779
+ "span",
780
+ {
781
+ style: {
782
+ fontSize: "0.6875rem",
783
+ fontWeight: 500,
784
+ // AstroUXDS medium (was 600)
785
+ color: "#fff",
786
+ whiteSpace: "nowrap",
787
+ overflow: "hidden",
788
+ textOverflow: "ellipsis",
789
+ minWidth: 0
790
+ },
791
+ children: event.title
792
+ }
793
+ )
794
+ ]
682
795
  }
683
796
  ),
684
797
  event.subtitle && !hasOverlap && /* @__PURE__ */ jsx(
@@ -690,7 +803,8 @@ const ChartView = memo(function ChartView2({
690
803
  whiteSpace: "nowrap",
691
804
  overflow: "hidden",
692
805
  textOverflow: "ellipsis",
693
- marginTop: 1
806
+ marginTop: 1,
807
+ paddingLeft: 16
694
808
  },
695
809
  children: event.subtitle
696
810
  }
@@ -798,158 +912,166 @@ const ChartView = memo(function ChartView2({
798
912
  )
799
913
  }
800
914
  ),
801
- hoveredEventData && tooltipPos && /* @__PURE__ */ jsxs(
802
- "div",
803
- {
804
- style: {
805
- position: "fixed",
806
- left: tooltipPos.x,
807
- top: tooltipPos.y,
808
- transform: "translate(-50%, -100%)",
809
- zIndex: 1e3,
810
- pointerEvents: "none",
811
- animation: "zendir-tooltip-appear 150ms ease"
812
- },
813
- children: [
814
- /* @__PURE__ */ jsxs(
815
- "div",
816
- {
817
- style: {
818
- backgroundColor: "rgba(15, 23, 42, 0.98)",
819
- border: `1px solid ${getStatusColor(hoveredEventData.status)}50`,
820
- borderRadius: tokens.borderRadius.md,
821
- padding: "12px 16px",
822
- minWidth: 220,
823
- maxWidth: 320,
824
- boxShadow: `0 12px 40px rgba(0, 0, 0, 0.5), 0 0 0 1px ${getStatusColor(hoveredEventData.status)}30`,
825
- backdropFilter: "blur(12px)"
826
- },
827
- children: [
828
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 8 }, children: [
915
+ hoveredEventData && tooltipPos && (() => {
916
+ var _a;
917
+ const tooltipColor = getStatusColor(hoveredEventData.status);
918
+ return /* @__PURE__ */ jsxs(
919
+ "div",
920
+ {
921
+ style: {
922
+ position: "fixed",
923
+ left: tooltipPos.x,
924
+ top: tooltipPos.y,
925
+ transform: "translate(-50%, -100%)",
926
+ zIndex: 1e3,
927
+ pointerEvents: "none",
928
+ animation: "zendir-tooltip-appear 150ms ease"
929
+ },
930
+ children: [
931
+ /* @__PURE__ */ jsxs(
932
+ "div",
933
+ {
934
+ style: {
935
+ backgroundColor: "rgba(15, 23, 42, 0.98)",
936
+ border: `1px solid ${tooltipColor}50`,
937
+ borderRadius: tokens.borderRadius.md,
938
+ padding: "12px 16px",
939
+ minWidth: 220,
940
+ maxWidth: 320,
941
+ boxShadow: `0 12px 40px rgba(0, 0, 0, 0.5), 0 0 0 1px ${tooltipColor}30`,
942
+ backdropFilter: "blur(12px)"
943
+ },
944
+ children: [
945
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 8 }, children: [
946
+ /* @__PURE__ */ jsx(
947
+ TimelineStatusMarker,
948
+ {
949
+ status: hoveredEventData.status,
950
+ fillColor: tooltipColor,
951
+ size: 10
952
+ }
953
+ ),
954
+ /* @__PURE__ */ jsx(
955
+ "span",
956
+ {
957
+ style: {
958
+ fontSize: "0.75rem",
959
+ fontWeight: 500,
960
+ // AstroUXDS medium (was 600)
961
+ color: tooltipColor,
962
+ textTransform: "uppercase",
963
+ letterSpacing: "0.05em"
964
+ },
965
+ children: getStatusLabel(hoveredEventData.status)
966
+ }
967
+ ),
968
+ hoveredEventData.badge && /* @__PURE__ */ jsx(
969
+ "span",
970
+ {
971
+ style: {
972
+ marginLeft: "auto",
973
+ fontSize: "0.625rem",
974
+ fontWeight: 500,
975
+ // AstroUXDS medium (was 600)
976
+ padding: "2px 6px",
977
+ borderRadius: tokens.borderRadius.sm,
978
+ backgroundColor: `${tooltipColor}20`,
979
+ color: tooltipColor
980
+ },
981
+ children: hoveredEventData.badge
982
+ }
983
+ )
984
+ ] }),
985
+ hoveredEventData.color && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6, marginBottom: 6 }, children: [
986
+ /* @__PURE__ */ jsx("div", { style: { width: 8, height: 8, borderRadius: 2, backgroundColor: hoveredEventData.color, flexShrink: 0 } }),
987
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "0.6875rem", color: hoveredEventData.color, fontWeight: 500 }, children: ((_a = hoveredEventData.arguments) == null ? void 0 : _a.Team) || hoveredEventData.badge || "Team" })
988
+ ] }),
829
989
  /* @__PURE__ */ jsx(
830
- TimelineStatusMarker,
990
+ "div",
831
991
  {
832
- status: hoveredEventData.status,
833
- fillColor: getStatusColor(hoveredEventData.status),
834
- size: 10
992
+ style: {
993
+ fontSize: "0.875rem",
994
+ fontWeight: 500,
995
+ // AstroUXDS medium (was 600)
996
+ color: "#fff",
997
+ marginBottom: 4
998
+ },
999
+ children: hoveredEventData.title
835
1000
  }
836
1001
  ),
837
- /* @__PURE__ */ jsx(
838
- "span",
1002
+ hoveredEventData.subtitle && /* @__PURE__ */ jsx(
1003
+ "div",
839
1004
  {
840
1005
  style: {
841
1006
  fontSize: "0.75rem",
842
- fontWeight: 500,
843
- // AstroUXDS medium (was 600)
844
- color: getStatusColor(hoveredEventData.status),
845
- textTransform: "uppercase",
846
- letterSpacing: "0.05em"
1007
+ color: "rgba(255, 255, 255, 0.6)",
1008
+ marginBottom: 12
1009
+ },
1010
+ children: hoveredEventData.subtitle
1011
+ }
1012
+ ),
1013
+ /* @__PURE__ */ jsxs(
1014
+ "div",
1015
+ {
1016
+ style: {
1017
+ display: "grid",
1018
+ gridTemplateColumns: "auto 1fr",
1019
+ gap: "6px 12px",
1020
+ fontSize: "0.6875rem",
1021
+ borderTop: `1px solid ${tokens.colors.border.muted}30`,
1022
+ paddingTop: 10
847
1023
  },
848
- children: getStatusLabel(hoveredEventData.status)
1024
+ children: [
1025
+ /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.tertiary }, children: "Start:" }),
1026
+ /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.primary, fontFamily: tokens.typography.fontFamily.mono }, children: formatTime(hoveredEventData.start, true) }),
1027
+ hoveredEventData.end && /* @__PURE__ */ jsxs(Fragment, { children: [
1028
+ /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.tertiary }, children: "End:" }),
1029
+ /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.primary, fontFamily: tokens.typography.fontFamily.mono }, children: formatTime(hoveredEventData.end, true) }),
1030
+ /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.tertiary }, children: "Duration:" }),
1031
+ /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.accent.secondary, fontWeight: 500 }, children: formatDuration(hoveredEventData.end.getTime() - hoveredEventData.start.getTime()) })
1032
+ ] }),
1033
+ /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.tertiary }, children: "UTC:" }),
1034
+ /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.secondary, fontFamily: tokens.typography.fontFamily.mono, fontSize: "0.625rem" }, children: formatUTC(hoveredEventData.start) })
1035
+ ]
849
1036
  }
850
1037
  ),
851
- hoveredEventData.badge && /* @__PURE__ */ jsx(
852
- "span",
1038
+ onEventClick && /* @__PURE__ */ jsx(
1039
+ "div",
853
1040
  {
854
1041
  style: {
855
- marginLeft: "auto",
1042
+ marginTop: 10,
1043
+ paddingTop: 8,
1044
+ borderTop: `1px solid ${tokens.colors.border.muted}20`,
856
1045
  fontSize: "0.625rem",
857
- fontWeight: 500,
858
- // AstroUXDS medium (was 600)
859
- padding: "2px 6px",
860
- borderRadius: tokens.borderRadius.sm,
861
- backgroundColor: `${getStatusColor(hoveredEventData.status)}20`,
862
- color: getStatusColor(hoveredEventData.status)
1046
+ color: tokens.colors.text.tertiary,
1047
+ textAlign: "center"
863
1048
  },
864
- children: hoveredEventData.badge
1049
+ children: "Click for details"
865
1050
  }
866
1051
  )
867
- ] }),
868
- /* @__PURE__ */ jsx(
869
- "div",
870
- {
871
- style: {
872
- fontSize: "0.875rem",
873
- fontWeight: 500,
874
- // AstroUXDS medium (was 600)
875
- color: "#fff",
876
- marginBottom: 4
877
- },
878
- children: hoveredEventData.title
879
- }
880
- ),
881
- hoveredEventData.subtitle && /* @__PURE__ */ jsx(
882
- "div",
883
- {
884
- style: {
885
- fontSize: "0.75rem",
886
- color: "rgba(255, 255, 255, 0.6)",
887
- marginBottom: 12
888
- },
889
- children: hoveredEventData.subtitle
890
- }
891
- ),
892
- /* @__PURE__ */ jsxs(
893
- "div",
894
- {
895
- style: {
896
- display: "grid",
897
- gridTemplateColumns: "auto 1fr",
898
- gap: "6px 12px",
899
- fontSize: "0.6875rem",
900
- borderTop: `1px solid ${tokens.colors.border.muted}30`,
901
- paddingTop: 10
902
- },
903
- children: [
904
- /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.tertiary }, children: "Start:" }),
905
- /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.primary, fontFamily: tokens.typography.fontFamily.mono }, children: formatTime(hoveredEventData.start, true) }),
906
- hoveredEventData.end && /* @__PURE__ */ jsxs(Fragment, { children: [
907
- /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.tertiary }, children: "End:" }),
908
- /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.primary, fontFamily: tokens.typography.fontFamily.mono }, children: formatTime(hoveredEventData.end, true) }),
909
- /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.tertiary }, children: "Duration:" }),
910
- /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.accent.secondary, fontWeight: 500 }, children: formatDuration(hoveredEventData.end.getTime() - hoveredEventData.start.getTime()) })
911
- ] }),
912
- /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.tertiary }, children: "UTC:" }),
913
- /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.secondary, fontFamily: tokens.typography.fontFamily.mono, fontSize: "0.625rem" }, children: formatUTC(hoveredEventData.start) })
914
- ]
915
- }
916
- ),
917
- onEventClick && /* @__PURE__ */ jsx(
918
- "div",
919
- {
920
- style: {
921
- marginTop: 10,
922
- paddingTop: 8,
923
- borderTop: `1px solid ${tokens.colors.border.muted}20`,
924
- fontSize: "0.625rem",
925
- color: tokens.colors.text.tertiary,
926
- textAlign: "center"
927
- },
928
- children: "Click for details"
929
- }
930
- )
931
- ]
932
- }
933
- ),
934
- /* @__PURE__ */ jsx(
935
- "div",
936
- {
937
- style: {
938
- position: "absolute",
939
- bottom: -6,
940
- left: "50%",
941
- transform: "translateX(-50%) rotate(45deg)",
942
- width: 12,
943
- height: 12,
944
- backgroundColor: "rgba(15, 23, 42, 0.98)",
945
- borderRight: `1px solid ${getStatusColor(hoveredEventData.status)}50`,
946
- borderBottom: `1px solid ${getStatusColor(hoveredEventData.status)}50`
1052
+ ]
947
1053
  }
948
- }
949
- )
950
- ]
951
- }
952
- ),
1054
+ ),
1055
+ /* @__PURE__ */ jsx(
1056
+ "div",
1057
+ {
1058
+ style: {
1059
+ position: "absolute",
1060
+ bottom: -6,
1061
+ left: "50%",
1062
+ transform: "translateX(-50%) rotate(45deg)",
1063
+ width: 12,
1064
+ height: 12,
1065
+ backgroundColor: "rgba(15, 23, 42, 0.98)",
1066
+ borderRight: `1px solid ${tooltipColor}50`,
1067
+ borderBottom: `1px solid ${tooltipColor}50`
1068
+ }
1069
+ }
1070
+ )
1071
+ ]
1072
+ }
1073
+ );
1074
+ })(),
953
1075
  /* @__PURE__ */ jsx("style", { children: `
954
1076
  .zendir-timeline-region:hover {
955
1077
  z-index: 100 !important;
@@ -1170,7 +1292,9 @@ const ScatterView = memo(function ScatterView2({
1170
1292
  cursor: "pointer",
1171
1293
  transition: "all 200ms cubic-bezier(0.34, 1.56, 0.64, 1)",
1172
1294
  zIndex: isHovered ? 20 : 1,
1173
- lineHeight: 0
1295
+ lineHeight: 0,
1296
+ borderRadius: "50%",
1297
+ boxShadow: event.color ? `0 0 0 2px ${event.color}` : void 0
1174
1298
  },
1175
1299
  "aria-label": event.title,
1176
1300
  children: /* @__PURE__ */ jsx(TimelineStatusMarker, { status: effectiveStatus, fillColor: color, size: dotSize })
@@ -1188,153 +1312,161 @@ const ScatterView = memo(function ScatterView2({
1188
1312
  ]
1189
1313
  }
1190
1314
  ),
1191
- hoveredEventData && tooltipPosition && /* @__PURE__ */ jsxs(
1192
- "div",
1193
- {
1194
- className: "zendir-scatter-tooltip",
1195
- style: {
1196
- position: "fixed",
1197
- left: tooltipPosition.x,
1198
- top: tooltipPosition.y - 12,
1199
- transform: "translate(-50%, -100%)",
1200
- backgroundColor: "rgba(11, 26, 40, 0.98)",
1201
- border: `1px solid ${tokens.colors.accent.primary}40`,
1202
- borderRadius: tokens.borderRadius.lg,
1203
- padding: "12px 16px",
1204
- minWidth: 200,
1205
- maxWidth: 320,
1206
- zIndex: 1e3,
1207
- boxShadow: `0 12px 40px rgba(0, 0, 0, 0.5), 0 0 0 1px ${tokens.colors.accent.primary}20`,
1208
- backdropFilter: "blur(12px)",
1209
- animation: "zendir-tooltip-in 150ms cubic-bezier(0.34, 1.56, 0.64, 1)"
1210
- },
1211
- children: [
1212
- /* @__PURE__ */ jsx(
1213
- "div",
1214
- {
1215
- style: {
1216
- position: "absolute",
1217
- bottom: -6,
1218
- left: "50%",
1219
- transform: "translateX(-50%) rotate(45deg)",
1220
- width: 12,
1221
- height: 12,
1222
- backgroundColor: "rgba(11, 26, 40, 0.98)",
1223
- borderRight: `1px solid ${tokens.colors.accent.primary}40`,
1224
- borderBottom: `1px solid ${tokens.colors.accent.primary}40`
1225
- }
1226
- }
1227
- ),
1228
- hoveredEventData.status && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 8 }, children: [
1315
+ hoveredEventData && tooltipPosition && (() => {
1316
+ var _a;
1317
+ const scatterTipColor = getStatusColor(hoveredEventData.status);
1318
+ return /* @__PURE__ */ jsxs(
1319
+ "div",
1320
+ {
1321
+ className: "zendir-scatter-tooltip",
1322
+ style: {
1323
+ position: "fixed",
1324
+ left: tooltipPosition.x,
1325
+ top: tooltipPosition.y - 12,
1326
+ transform: "translate(-50%, -100%)",
1327
+ backgroundColor: "rgba(11, 26, 40, 0.98)",
1328
+ border: `1px solid ${scatterTipColor}40`,
1329
+ borderRadius: tokens.borderRadius.lg,
1330
+ padding: "12px 16px",
1331
+ minWidth: 200,
1332
+ maxWidth: 320,
1333
+ zIndex: 1e3,
1334
+ boxShadow: `0 12px 40px rgba(0, 0, 0, 0.5), 0 0 0 1px ${scatterTipColor}20`,
1335
+ backdropFilter: "blur(12px)",
1336
+ animation: "zendir-tooltip-in 150ms cubic-bezier(0.34, 1.56, 0.64, 1)"
1337
+ },
1338
+ children: [
1229
1339
  /* @__PURE__ */ jsx(
1230
- TimelineStatusMarker,
1231
- {
1232
- status: hoveredEventData.status,
1233
- fillColor: getStatusColor(hoveredEventData.status),
1234
- size: 10
1235
- }
1236
- ),
1237
- /* @__PURE__ */ jsx(
1238
- "span",
1239
- {
1240
- style: {
1241
- fontSize: "0.75rem",
1242
- fontWeight: 500,
1243
- color: getStatusColor(hoveredEventData.status),
1244
- textTransform: "uppercase",
1245
- letterSpacing: "0.05em"
1246
- },
1247
- children: hoveredEventData.status
1248
- }
1249
- ),
1250
- hoveredEventData.badge && /* @__PURE__ */ jsx(
1251
- "span",
1252
- {
1253
- style: {
1254
- marginLeft: "auto",
1255
- fontSize: "0.625rem",
1256
- fontWeight: 500,
1257
- padding: "2px 6px",
1258
- borderRadius: tokens.borderRadius.sm,
1259
- backgroundColor: `${getStatusColor(hoveredEventData.status)}20`,
1260
- color: getStatusColor(hoveredEventData.status)
1261
- },
1262
- children: hoveredEventData.badge
1263
- }
1264
- )
1265
- ] }),
1266
- /* @__PURE__ */ jsx(
1267
- "div",
1268
- {
1269
- style: {
1270
- fontSize: "0.875rem",
1271
- fontWeight: 500,
1272
- color: "#fff",
1273
- marginBottom: 8
1274
- },
1275
- children: hoveredEventData.title
1276
- }
1277
- ),
1278
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 4 }, children: [
1279
- /* @__PURE__ */ jsxs(
1280
- "div",
1281
- {
1282
- style: {
1283
- display: "flex",
1284
- justifyContent: "space-between",
1285
- fontSize: "0.75rem"
1286
- },
1287
- children: [
1288
- /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.tertiary }, children: "Time:" }),
1289
- /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.secondary, fontFamily: tokens.typography.fontFamily.mono }, children: formatTimeLabel(hoveredEventData.start) })
1290
- ]
1291
- }
1292
- ),
1293
- hoveredEventData.badge && /* @__PURE__ */ jsxs(
1294
1340
  "div",
1295
1341
  {
1296
1342
  style: {
1297
- display: "flex",
1298
- justifyContent: "space-between",
1299
- fontSize: "0.75rem"
1300
- },
1301
- children: [
1302
- /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.tertiary }, children: "Trigger:" }),
1303
- /* @__PURE__ */ jsx("span", { style: { color: safeAccentText(tokens.colors.accent.primary), fontWeight: 500 }, children: hoveredEventData.badge })
1304
- ]
1343
+ position: "absolute",
1344
+ bottom: -6,
1345
+ left: "50%",
1346
+ transform: "translateX(-50%) rotate(45deg)",
1347
+ width: 12,
1348
+ height: 12,
1349
+ backgroundColor: "rgba(11, 26, 40, 0.98)",
1350
+ borderRight: `1px solid ${scatterTipColor}40`,
1351
+ borderBottom: `1px solid ${scatterTipColor}40`
1352
+ }
1305
1353
  }
1306
1354
  ),
1307
- /* @__PURE__ */ jsxs(
1355
+ hoveredEventData.status && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 8 }, children: [
1356
+ /* @__PURE__ */ jsx(
1357
+ TimelineStatusMarker,
1358
+ {
1359
+ status: hoveredEventData.status,
1360
+ fillColor: scatterTipColor,
1361
+ size: 10
1362
+ }
1363
+ ),
1364
+ /* @__PURE__ */ jsx(
1365
+ "span",
1366
+ {
1367
+ style: {
1368
+ fontSize: "0.75rem",
1369
+ fontWeight: 500,
1370
+ color: scatterTipColor,
1371
+ textTransform: "uppercase",
1372
+ letterSpacing: "0.05em"
1373
+ },
1374
+ children: hoveredEventData.status
1375
+ }
1376
+ ),
1377
+ hoveredEventData.badge && /* @__PURE__ */ jsx(
1378
+ "span",
1379
+ {
1380
+ style: {
1381
+ marginLeft: "auto",
1382
+ fontSize: "0.625rem",
1383
+ fontWeight: 500,
1384
+ padding: "2px 6px",
1385
+ borderRadius: tokens.borderRadius.sm,
1386
+ backgroundColor: `${scatterTipColor}20`,
1387
+ color: scatterTipColor
1388
+ },
1389
+ children: hoveredEventData.badge
1390
+ }
1391
+ )
1392
+ ] }),
1393
+ hoveredEventData.color && /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6, marginBottom: 6 }, children: [
1394
+ /* @__PURE__ */ jsx("div", { style: { width: 8, height: 8, borderRadius: 2, backgroundColor: hoveredEventData.color, flexShrink: 0 } }),
1395
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "0.6875rem", color: hoveredEventData.color, fontWeight: 500 }, children: ((_a = hoveredEventData.arguments) == null ? void 0 : _a.Team) || hoveredEventData.badge || "Team" })
1396
+ ] }),
1397
+ /* @__PURE__ */ jsx(
1308
1398
  "div",
1309
1399
  {
1310
1400
  style: {
1311
- display: "flex",
1312
- justifyContent: "space-between",
1313
- fontSize: "0.75rem"
1401
+ fontSize: "0.875rem",
1402
+ fontWeight: 500,
1403
+ color: "#fff",
1404
+ marginBottom: 8
1314
1405
  },
1315
- children: [
1316
- /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.tertiary }, children: "UTC:" }),
1317
- /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.secondary, fontFamily: tokens.typography.fontFamily.mono }, children: hoveredEventData.start.toISOString().replace("T", " ").slice(0, 19) })
1318
- ]
1406
+ children: hoveredEventData.title
1319
1407
  }
1320
1408
  ),
1321
- hoveredEventData.subtitle && /* @__PURE__ */ jsx(
1322
- "div",
1323
- {
1324
- style: {
1325
- marginTop: 4,
1326
- paddingTop: 8,
1327
- borderTop: `1px solid ${tokens.colors.border.muted}`,
1328
- fontSize: "0.75rem",
1329
- color: tokens.colors.text.secondary
1330
- },
1331
- children: hoveredEventData.subtitle
1332
- }
1333
- )
1334
- ] })
1335
- ]
1336
- }
1337
- ),
1409
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 4 }, children: [
1410
+ /* @__PURE__ */ jsxs(
1411
+ "div",
1412
+ {
1413
+ style: {
1414
+ display: "flex",
1415
+ justifyContent: "space-between",
1416
+ fontSize: "0.75rem"
1417
+ },
1418
+ children: [
1419
+ /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.tertiary }, children: "Time:" }),
1420
+ /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.secondary, fontFamily: tokens.typography.fontFamily.mono }, children: formatTimeLabel(hoveredEventData.start) })
1421
+ ]
1422
+ }
1423
+ ),
1424
+ hoveredEventData.badge && /* @__PURE__ */ jsxs(
1425
+ "div",
1426
+ {
1427
+ style: {
1428
+ display: "flex",
1429
+ justifyContent: "space-between",
1430
+ fontSize: "0.75rem"
1431
+ },
1432
+ children: [
1433
+ /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.tertiary }, children: "Trigger:" }),
1434
+ /* @__PURE__ */ jsx("span", { style: { color: safeAccentText(tokens.colors.accent.primary), fontWeight: 500 }, children: hoveredEventData.badge })
1435
+ ]
1436
+ }
1437
+ ),
1438
+ /* @__PURE__ */ jsxs(
1439
+ "div",
1440
+ {
1441
+ style: {
1442
+ display: "flex",
1443
+ justifyContent: "space-between",
1444
+ fontSize: "0.75rem"
1445
+ },
1446
+ children: [
1447
+ /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.tertiary }, children: "UTC:" }),
1448
+ /* @__PURE__ */ jsx("span", { style: { color: tokens.colors.text.secondary, fontFamily: tokens.typography.fontFamily.mono }, children: hoveredEventData.start.toISOString().replace("T", " ").slice(0, 19) })
1449
+ ]
1450
+ }
1451
+ ),
1452
+ hoveredEventData.subtitle && /* @__PURE__ */ jsx(
1453
+ "div",
1454
+ {
1455
+ style: {
1456
+ marginTop: 4,
1457
+ paddingTop: 8,
1458
+ borderTop: `1px solid ${tokens.colors.border.muted}`,
1459
+ fontSize: "0.75rem",
1460
+ color: tokens.colors.text.secondary
1461
+ },
1462
+ children: hoveredEventData.subtitle
1463
+ }
1464
+ )
1465
+ ] })
1466
+ ]
1467
+ }
1468
+ );
1469
+ })(),
1338
1470
  /* @__PURE__ */ jsx("style", { children: `
1339
1471
  @keyframes zendir-tooltip-in {
1340
1472
  from {
@@ -1357,6 +1489,273 @@ const ScatterView = memo(function ScatterView2({
1357
1489
  ` })
1358
1490
  ] });
1359
1491
  });
1492
+ const TimelineFiltersToolbar = memo(function TimelineFiltersToolbar2({
1493
+ filter,
1494
+ onFilterChange,
1495
+ trackOptions,
1496
+ defaultExpanded
1497
+ }) {
1498
+ const { tokens, theme } = useTheme();
1499
+ const isTransparentTheme = theme === "transparent" || theme === "transparent-bold" || theme === "transparent-minimal";
1500
+ const [expanded, setExpanded] = useState(defaultExpanded);
1501
+ const chipCount = countTimelineFilterChips(filter);
1502
+ const patch = useCallback(
1503
+ (partial) => {
1504
+ onFilterChange(normalizeTimelineFilter({ ...filter, ...partial }));
1505
+ },
1506
+ [filter, onFilterChange]
1507
+ );
1508
+ const clearAll = useCallback(() => {
1509
+ onFilterChange({});
1510
+ }, [onFilterChange]);
1511
+ const toggleTrack = useCallback(
1512
+ (id) => {
1513
+ const cur = filter.tracks ?? [];
1514
+ const next = cur.includes(id) ? cur.filter((t) => t !== id) : [...cur, id];
1515
+ patch({ tracks: next.length ? next : void 0 });
1516
+ },
1517
+ [filter.tracks, patch]
1518
+ );
1519
+ const toggleStatus = useCallback(
1520
+ (st) => {
1521
+ const cur = filter.status ?? [];
1522
+ const next = cur.includes(st) ? cur.filter((s) => s !== st) : [...cur, st];
1523
+ patch({ status: next.length ? next : void 0 });
1524
+ },
1525
+ [filter.status, patch]
1526
+ );
1527
+ const pillBase = (active) => ({
1528
+ padding: "4px 10px",
1529
+ borderRadius: tokens.borderRadius.full ?? 999,
1530
+ fontSize: "0.6875rem",
1531
+ fontWeight: 500,
1532
+ border: `1px solid ${active ? tokens.colors.accent.primary : tokens.colors.border.muted}`,
1533
+ backgroundColor: active ? `${tokens.colors.accent.primary}22` : tokens.colors.background.elevated,
1534
+ color: active ? tokens.colors.accent.primary : tokens.colors.text.secondary,
1535
+ cursor: "pointer",
1536
+ transition: "background-color 150ms ease, border-color 150ms ease, color 150ms ease"
1537
+ });
1538
+ return /* @__PURE__ */ jsxs(
1539
+ "div",
1540
+ {
1541
+ style: {
1542
+ padding: "12px 20px",
1543
+ borderBottom: `1px solid ${tokens.colors.border.muted}`,
1544
+ backgroundColor: isTransparentTheme ? "transparent" : tokens.colors.background.elevated,
1545
+ ...isTransparentTheme && { backdropFilter: "blur(8px)", WebkitBackdropFilter: "blur(8px)" }
1546
+ },
1547
+ children: [
1548
+ /* @__PURE__ */ jsxs(
1549
+ "div",
1550
+ {
1551
+ style: {
1552
+ display: "flex",
1553
+ flexWrap: "wrap",
1554
+ alignItems: "center",
1555
+ gap: 10
1556
+ },
1557
+ children: [
1558
+ /* @__PURE__ */ jsxs("div", { style: { flex: "1 1 220px", minWidth: 0, position: "relative" }, children: [
1559
+ /* @__PURE__ */ jsx(
1560
+ Icon,
1561
+ {
1562
+ name: "search",
1563
+ size: 16,
1564
+ style: {
1565
+ position: "absolute",
1566
+ left: 12,
1567
+ top: "50%",
1568
+ transform: "translateY(-50%)",
1569
+ color: tokens.colors.text.tertiary,
1570
+ pointerEvents: "none"
1571
+ }
1572
+ }
1573
+ ),
1574
+ /* @__PURE__ */ jsx(
1575
+ "input",
1576
+ {
1577
+ type: "search",
1578
+ value: filter.search ?? "",
1579
+ onChange: (e) => patch({ search: e.target.value || void 0 }),
1580
+ placeholder: "Search title, badge, track, fields…",
1581
+ "aria-label": "Search timeline events",
1582
+ style: {
1583
+ width: "100%",
1584
+ boxSizing: "border-box",
1585
+ height: 36,
1586
+ paddingLeft: 40,
1587
+ paddingRight: 12,
1588
+ borderRadius: tokens.borderRadius.md,
1589
+ border: `1px solid ${tokens.colors.border.muted}`,
1590
+ backgroundColor: tokens.colors.background.surface,
1591
+ color: tokens.colors.text.primary,
1592
+ fontSize: "0.8125rem",
1593
+ outline: "none"
1594
+ }
1595
+ }
1596
+ )
1597
+ ] }),
1598
+ /* @__PURE__ */ jsxs(
1599
+ "button",
1600
+ {
1601
+ type: "button",
1602
+ onClick: () => setExpanded((v) => !v),
1603
+ "aria-expanded": expanded,
1604
+ "aria-controls": "zendir-timeline-filters-panel",
1605
+ style: {
1606
+ display: "inline-flex",
1607
+ alignItems: "center",
1608
+ gap: 6,
1609
+ height: 36,
1610
+ padding: "0 14px",
1611
+ borderRadius: tokens.borderRadius.md,
1612
+ border: `1px solid ${tokens.colors.border.muted}`,
1613
+ backgroundColor: tokens.colors.background.surface,
1614
+ color: tokens.colors.text.primary,
1615
+ cursor: "pointer",
1616
+ fontSize: "0.8125rem",
1617
+ fontWeight: 500
1618
+ },
1619
+ children: [
1620
+ "Filters",
1621
+ chipCount > 0 ? /* @__PURE__ */ jsx(Badge, { variant: "filled", size: "small", status: "normal", children: chipCount }) : null,
1622
+ /* @__PURE__ */ jsx(Icon, { name: expanded ? "chevron-up" : "chevron-down", size: 18 })
1623
+ ]
1624
+ }
1625
+ ),
1626
+ isTimelineFilterActive(filter) ? /* @__PURE__ */ jsx(
1627
+ "button",
1628
+ {
1629
+ type: "button",
1630
+ onClick: clearAll,
1631
+ style: {
1632
+ height: 36,
1633
+ padding: "0 12px",
1634
+ borderRadius: tokens.borderRadius.md,
1635
+ border: `1px solid ${tokens.colors.border.muted}`,
1636
+ backgroundColor: "transparent",
1637
+ color: tokens.colors.text.secondary,
1638
+ cursor: "pointer",
1639
+ fontSize: "0.75rem",
1640
+ fontWeight: 500
1641
+ },
1642
+ children: "Clear all"
1643
+ }
1644
+ ) : null
1645
+ ]
1646
+ }
1647
+ ),
1648
+ expanded ? /* @__PURE__ */ jsxs(
1649
+ "div",
1650
+ {
1651
+ id: "zendir-timeline-filters-panel",
1652
+ style: {
1653
+ marginTop: 14,
1654
+ display: "flex",
1655
+ flexDirection: "column",
1656
+ gap: 14
1657
+ },
1658
+ children: [
1659
+ trackOptions.length > 0 ? /* @__PURE__ */ jsxs("div", { children: [
1660
+ /* @__PURE__ */ jsx(
1661
+ "div",
1662
+ {
1663
+ style: {
1664
+ fontSize: "0.625rem",
1665
+ fontWeight: 600,
1666
+ letterSpacing: "0.06em",
1667
+ textTransform: "uppercase",
1668
+ color: tokens.colors.text.tertiary,
1669
+ marginBottom: 8
1670
+ },
1671
+ children: "Tracks"
1672
+ }
1673
+ ),
1674
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 6 }, children: trackOptions.map((t) => {
1675
+ var _a;
1676
+ const active = ((_a = filter.tracks) == null ? void 0 : _a.includes(t.id)) ?? false;
1677
+ return /* @__PURE__ */ jsx(
1678
+ "button",
1679
+ {
1680
+ type: "button",
1681
+ onClick: () => toggleTrack(t.id),
1682
+ style: pillBase(active),
1683
+ children: t.label
1684
+ },
1685
+ t.id
1686
+ );
1687
+ }) })
1688
+ ] }) : null,
1689
+ /* @__PURE__ */ jsxs("div", { children: [
1690
+ /* @__PURE__ */ jsx(
1691
+ "div",
1692
+ {
1693
+ style: {
1694
+ fontSize: "0.625rem",
1695
+ fontWeight: 600,
1696
+ letterSpacing: "0.06em",
1697
+ textTransform: "uppercase",
1698
+ color: tokens.colors.text.tertiary,
1699
+ marginBottom: 8
1700
+ },
1701
+ children: "Status"
1702
+ }
1703
+ ),
1704
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 6 }, children: ALL_TIMELINE_STATUSES.map((st) => {
1705
+ var _a;
1706
+ const active = ((_a = filter.status) == null ? void 0 : _a.includes(st)) ?? false;
1707
+ return /* @__PURE__ */ jsx("button", { type: "button", onClick: () => toggleStatus(st), style: pillBase(active), children: st }, st);
1708
+ }) })
1709
+ ] }),
1710
+ /* @__PURE__ */ jsxs(
1711
+ "div",
1712
+ {
1713
+ style: {
1714
+ display: "flex",
1715
+ flexWrap: "wrap",
1716
+ alignItems: "center",
1717
+ gap: 16
1718
+ },
1719
+ children: [
1720
+ /* @__PURE__ */ jsxs("div", { children: [
1721
+ /* @__PURE__ */ jsx(
1722
+ "div",
1723
+ {
1724
+ style: {
1725
+ fontSize: "0.625rem",
1726
+ fontWeight: 600,
1727
+ letterSpacing: "0.06em",
1728
+ textTransform: "uppercase",
1729
+ color: tokens.colors.text.tertiary,
1730
+ marginBottom: 8
1731
+ },
1732
+ children: "Duration"
1733
+ }
1734
+ ),
1735
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", gap: 8 }, children: ["all", "point", "range"].map((key) => {
1736
+ const active = (filter.eventShape ?? "all") === key;
1737
+ return /* @__PURE__ */ jsx("button", { type: "button", onClick: () => patch({ eventShape: key }), style: pillBase(active), children: key === "all" ? "All" : key === "point" ? "Instant" : "Range" }, key);
1738
+ }) })
1739
+ ] }),
1740
+ /* @__PURE__ */ jsx(
1741
+ Checkbox,
1742
+ {
1743
+ label: "Team color only",
1744
+ checked: Boolean(filter.teamColoredOnly),
1745
+ onChange: (checked) => patch({ teamColoredOnly: checked || void 0 }),
1746
+ size: "small"
1747
+ }
1748
+ )
1749
+ ]
1750
+ }
1751
+ )
1752
+ ]
1753
+ }
1754
+ ) : null
1755
+ ]
1756
+ }
1757
+ );
1758
+ });
1360
1759
  const UnifiedTimeline = memo(function UnifiedTimeline2({
1361
1760
  title = "Timeline",
1362
1761
  events,
@@ -1375,6 +1774,8 @@ const UnifiedTimeline = memo(function UnifiedTimeline2({
1375
1774
  zoomable = false,
1376
1775
  initialZoom = 1,
1377
1776
  showFilters: _showFilters = false,
1777
+ filtersDefaultExpanded = false,
1778
+ hideEmptyTracksWhenFiltered = true,
1378
1779
  filter: _filter,
1379
1780
  onFilterChange: _onFilterChange,
1380
1781
  showCount: _showCount = true,
@@ -1390,6 +1791,15 @@ const UnifiedTimeline = memo(function UnifiedTimeline2({
1390
1791
  const [internalViewMode, setInternalViewMode] = useState(defaultView);
1391
1792
  const [zoom, setZoom] = useState(initialZoom);
1392
1793
  const [_internalFilter, _setInternalFilter] = useState({});
1794
+ const filter = _filter !== void 0 ? _filter : _internalFilter;
1795
+ const setFilter = useCallback(
1796
+ (next) => {
1797
+ const n = normalizeTimelineFilter(next);
1798
+ if (_filter === void 0) _setInternalFilter(n);
1799
+ _onFilterChange == null ? void 0 : _onFilterChange(n);
1800
+ },
1801
+ [_filter, _onFilterChange]
1802
+ );
1393
1803
  const viewMode = controlledViewMode ?? internalViewMode;
1394
1804
  const handleViewModeChange = useCallback((mode) => {
1395
1805
  setInternalViewMode(mode);
@@ -1434,9 +1844,28 @@ const UnifiedTimeline = memo(function UnifiedTimeline2({
1434
1844
  height: trackHeight
1435
1845
  }));
1436
1846
  }, [events, tracks, trackHeight]);
1847
+ const filteredEvents = useMemo(
1848
+ () => events.filter((e) => matchesTimelineFilter(e, filter)),
1849
+ [events, filter]
1850
+ );
1851
+ const effectiveTracksForViews = useMemo(() => {
1852
+ if (!hideEmptyTracksWhenFiltered || !isTimelineFilterActive(filter)) return effectiveTracks;
1853
+ const ids = new Set(filteredEvents.map((e) => e.track || "default"));
1854
+ return effectiveTracks.filter((t) => ids.has(t.id));
1855
+ }, [effectiveTracks, filteredEvents, filter, hideEmptyTracksWhenFiltered]);
1856
+ const trackOptionsForToolbar = useMemo(() => {
1857
+ if (tracks.length > 0) return tracks.map((t) => ({ id: t.id, label: t.label }));
1858
+ const u = /* @__PURE__ */ new Set();
1859
+ events.forEach((e) => {
1860
+ if (e.track) u.add(e.track);
1861
+ });
1862
+ if (u.size === 0) return [{ id: "default", label: "Events" }];
1863
+ return [...u].sort().map((id) => ({ id, label: id }));
1864
+ }, [events, tracks]);
1437
1865
  const sortedEvents = useMemo(() => {
1438
- return [...events].sort((a, b) => b.start.getTime() - a.start.getTime());
1439
- }, [events]);
1866
+ return [...filteredEvents].sort((a, b) => b.start.getTime() - a.start.getTime());
1867
+ }, [filteredEvents]);
1868
+ const countLabel = !_showCount ? title : `${title} (${filteredEvents.length}${filteredEvents.length !== events.length ? ` / ${events.length}` : ""})`;
1440
1869
  return /* @__PURE__ */ jsxs(
1441
1870
  "div",
1442
1871
  {
@@ -1460,7 +1889,7 @@ const UnifiedTimeline = memo(function UnifiedTimeline2({
1460
1889
  borderBottom: `1px solid ${tokens.colors.border.muted}`
1461
1890
  },
1462
1891
  children: [
1463
- /* @__PURE__ */ jsxs(
1892
+ /* @__PURE__ */ jsx(
1464
1893
  "h3",
1465
1894
  {
1466
1895
  style: {
@@ -1470,12 +1899,7 @@ const UnifiedTimeline = memo(function UnifiedTimeline2({
1470
1899
  // AstroUXDS medium (was 600)
1471
1900
  color: tokens.colors.text.primary
1472
1901
  },
1473
- children: [
1474
- title,
1475
- " (",
1476
- events.length,
1477
- ")"
1478
- ]
1902
+ children: countLabel
1479
1903
  }
1480
1904
  ),
1481
1905
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [
@@ -1650,6 +2074,15 @@ const UnifiedTimeline = memo(function UnifiedTimeline2({
1650
2074
  ]
1651
2075
  }
1652
2076
  ),
2077
+ _showFilters ? /* @__PURE__ */ jsx(
2078
+ TimelineFiltersToolbar,
2079
+ {
2080
+ filter,
2081
+ onFilterChange: setFilter,
2082
+ trackOptions: trackOptionsForToolbar,
2083
+ defaultExpanded: filtersDefaultExpanded
2084
+ }
2085
+ ) : null,
1653
2086
  loading && /* @__PURE__ */ jsx(
1654
2087
  "div",
1655
2088
  {
@@ -1704,6 +2137,43 @@ const UnifiedTimeline = memo(function UnifiedTimeline2({
1704
2137
  /* @__PURE__ */ jsx("span", { style: { fontSize: "0.875rem" }, children: "No events to display" })
1705
2138
  ]
1706
2139
  }
2140
+ ) : filteredEvents.length === 0 ? /* @__PURE__ */ jsxs(
2141
+ "div",
2142
+ {
2143
+ style: {
2144
+ display: "flex",
2145
+ flexDirection: "column",
2146
+ alignItems: "center",
2147
+ justifyContent: "center",
2148
+ padding: "48px 24px",
2149
+ color: tokens.colors.text.tertiary,
2150
+ gap: 12,
2151
+ textAlign: "center"
2152
+ },
2153
+ children: [
2154
+ /* @__PURE__ */ jsx(Icon, { name: "search", size: 32 }),
2155
+ /* @__PURE__ */ jsx("span", { style: { fontSize: "0.875rem", color: tokens.colors.text.secondary }, children: "No events match the current filters." }),
2156
+ _showFilters && isTimelineFilterActive(filter) ? /* @__PURE__ */ jsx(
2157
+ "button",
2158
+ {
2159
+ type: "button",
2160
+ onClick: () => setFilter({}),
2161
+ style: {
2162
+ marginTop: 4,
2163
+ padding: "8px 16px",
2164
+ borderRadius: tokens.borderRadius.md,
2165
+ border: `1px solid ${tokens.colors.accent.primary}`,
2166
+ backgroundColor: `${tokens.colors.accent.primary}18`,
2167
+ color: tokens.colors.accent.primary,
2168
+ cursor: "pointer",
2169
+ fontSize: "0.8125rem",
2170
+ fontWeight: 500
2171
+ },
2172
+ children: "Clear filters"
2173
+ }
2174
+ ) : null
2175
+ ]
2176
+ }
1707
2177
  ) : viewMode === "list" ? (
1708
2178
  // List View
1709
2179
  sortedEvents.map((event, index) => /* @__PURE__ */ jsx(
@@ -1720,8 +2190,8 @@ const UnifiedTimeline = memo(function UnifiedTimeline2({
1720
2190
  /* @__PURE__ */ jsx(
1721
2191
  ScatterView,
1722
2192
  {
1723
- events,
1724
- tracks: effectiveTracks,
2193
+ events: filteredEvents,
2194
+ tracks: effectiveTracksForViews,
1725
2195
  start,
1726
2196
  end,
1727
2197
  trackHeight,
@@ -1736,8 +2206,8 @@ const UnifiedTimeline = memo(function UnifiedTimeline2({
1736
2206
  /* @__PURE__ */ jsx(
1737
2207
  ChartView,
1738
2208
  {
1739
- events,
1740
- tracks: effectiveTracks,
2209
+ events: filteredEvents,
2210
+ tracks: effectiveTracksForViews,
1741
2211
  start,
1742
2212
  end,
1743
2213
  trackHeight,
@@ -1763,6 +2233,9 @@ const UnifiedTimeline = memo(function UnifiedTimeline2({
1763
2233
  );
1764
2234
  });
1765
2235
  export {
1766
- UnifiedTimeline
2236
+ UnifiedTimeline,
2237
+ getTimelineEventDisplayStatus,
2238
+ isTimelineFilterActive,
2239
+ matchesTimelineFilter
1767
2240
  };
1768
2241
  //# sourceMappingURL=UnifiedTimeline.js.map