@zendir/ui 0.1.14 → 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,
@@ -607,11 +684,12 @@ const ChartView = memo(function ChartView2({
607
684
  )),
608
685
  (eventsByTrack[track.id] || []).map((event) => {
609
686
  const { left, width } = getEventPosition(event);
610
- 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);
611
689
  const isHovered = hoveredEvent === event.id;
612
690
  const overlap = eventOverlaps[event.id];
613
691
  const hasOverlap = overlap && overlap.overlapCount > 0;
614
- const cardHeight = hasOverlap ? 28 : 36;
692
+ const cardHeight = hasOverlap ? 30 : 38;
615
693
  const stackOffset = overlap ? overlap.stackIndex * 30 : 0;
616
694
  const baseTop = ((track.height || trackHeight) - cardHeight) / 2;
617
695
  return /* @__PURE__ */ jsxs(
@@ -649,7 +727,7 @@ const ChartView = memo(function ChartView2({
649
727
  transform: isHovered ? "translateY(-3px) scale(1.02)" : "none"
650
728
  },
651
729
  children: [
652
- event.color && /* @__PURE__ */ jsx(
730
+ event.color ? /* @__PURE__ */ jsx(
653
731
  "div",
654
732
  {
655
733
  style: {
@@ -657,57 +735,63 @@ const ChartView = memo(function ChartView2({
657
735
  top: 0,
658
736
  left: 0,
659
737
  right: 0,
660
- height: 3,
738
+ height: 2,
661
739
  backgroundColor: event.color,
662
- borderRadius: "4px 4px 0 0"
663
- }
664
- }
665
- ),
666
- /* @__PURE__ */ jsx(
667
- "div",
668
- {
669
- style: {
670
- width: 4,
671
- height: "100%",
672
- backgroundColor: color,
673
- flexShrink: 0,
674
- borderRadius: "2px 0 0 2px"
675
- }
740
+ borderRadius: "4px 4px 0 0",
741
+ zIndex: 1,
742
+ pointerEvents: "none"
743
+ },
744
+ "aria-hidden": true
676
745
  }
677
- ),
746
+ ) : null,
678
747
  /* @__PURE__ */ jsxs(
679
748
  "div",
680
749
  {
681
750
  style: {
682
751
  flex: 1,
683
- padding: "4px 8px",
752
+ padding: `${event.color ? 6 : 4}px 8px 4px 8px`,
684
753
  overflow: "hidden",
685
- minWidth: 0
754
+ minWidth: 0,
755
+ display: "flex",
756
+ flexDirection: "column",
757
+ justifyContent: "center"
686
758
  },
687
759
  children: [
688
- /* @__PURE__ */ jsx(
760
+ /* @__PURE__ */ jsxs(
689
761
  "div",
690
762
  {
691
763
  style: {
692
764
  display: "flex",
693
765
  alignItems: "center",
694
- gap: 4
766
+ gap: 6,
767
+ minWidth: 0
695
768
  },
696
- children: /* @__PURE__ */ jsx(
697
- "span",
698
- {
699
- style: {
700
- fontSize: "0.6875rem",
701
- fontWeight: 500,
702
- // AstroUXDS medium (was 600)
703
- color: "#fff",
704
- whiteSpace: "nowrap",
705
- overflow: "hidden",
706
- textOverflow: "ellipsis"
707
- },
708
- children: event.title
709
- }
710
- )
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
+ ]
711
795
  }
712
796
  ),
713
797
  event.subtitle && !hasOverlap && /* @__PURE__ */ jsx(
@@ -719,7 +803,8 @@ const ChartView = memo(function ChartView2({
719
803
  whiteSpace: "nowrap",
720
804
  overflow: "hidden",
721
805
  textOverflow: "ellipsis",
722
- marginTop: 1
806
+ marginTop: 1,
807
+ paddingLeft: 16
723
808
  },
724
809
  children: event.subtitle
725
810
  }
@@ -1404,6 +1489,273 @@ const ScatterView = memo(function ScatterView2({
1404
1489
  ` })
1405
1490
  ] });
1406
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
+ });
1407
1759
  const UnifiedTimeline = memo(function UnifiedTimeline2({
1408
1760
  title = "Timeline",
1409
1761
  events,
@@ -1422,6 +1774,8 @@ const UnifiedTimeline = memo(function UnifiedTimeline2({
1422
1774
  zoomable = false,
1423
1775
  initialZoom = 1,
1424
1776
  showFilters: _showFilters = false,
1777
+ filtersDefaultExpanded = false,
1778
+ hideEmptyTracksWhenFiltered = true,
1425
1779
  filter: _filter,
1426
1780
  onFilterChange: _onFilterChange,
1427
1781
  showCount: _showCount = true,
@@ -1437,6 +1791,15 @@ const UnifiedTimeline = memo(function UnifiedTimeline2({
1437
1791
  const [internalViewMode, setInternalViewMode] = useState(defaultView);
1438
1792
  const [zoom, setZoom] = useState(initialZoom);
1439
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
+ );
1440
1803
  const viewMode = controlledViewMode ?? internalViewMode;
1441
1804
  const handleViewModeChange = useCallback((mode) => {
1442
1805
  setInternalViewMode(mode);
@@ -1481,9 +1844,28 @@ const UnifiedTimeline = memo(function UnifiedTimeline2({
1481
1844
  height: trackHeight
1482
1845
  }));
1483
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]);
1484
1865
  const sortedEvents = useMemo(() => {
1485
- return [...events].sort((a, b) => b.start.getTime() - a.start.getTime());
1486
- }, [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}` : ""})`;
1487
1869
  return /* @__PURE__ */ jsxs(
1488
1870
  "div",
1489
1871
  {
@@ -1507,7 +1889,7 @@ const UnifiedTimeline = memo(function UnifiedTimeline2({
1507
1889
  borderBottom: `1px solid ${tokens.colors.border.muted}`
1508
1890
  },
1509
1891
  children: [
1510
- /* @__PURE__ */ jsxs(
1892
+ /* @__PURE__ */ jsx(
1511
1893
  "h3",
1512
1894
  {
1513
1895
  style: {
@@ -1517,12 +1899,7 @@ const UnifiedTimeline = memo(function UnifiedTimeline2({
1517
1899
  // AstroUXDS medium (was 600)
1518
1900
  color: tokens.colors.text.primary
1519
1901
  },
1520
- children: [
1521
- title,
1522
- " (",
1523
- events.length,
1524
- ")"
1525
- ]
1902
+ children: countLabel
1526
1903
  }
1527
1904
  ),
1528
1905
  /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [
@@ -1697,6 +2074,15 @@ const UnifiedTimeline = memo(function UnifiedTimeline2({
1697
2074
  ]
1698
2075
  }
1699
2076
  ),
2077
+ _showFilters ? /* @__PURE__ */ jsx(
2078
+ TimelineFiltersToolbar,
2079
+ {
2080
+ filter,
2081
+ onFilterChange: setFilter,
2082
+ trackOptions: trackOptionsForToolbar,
2083
+ defaultExpanded: filtersDefaultExpanded
2084
+ }
2085
+ ) : null,
1700
2086
  loading && /* @__PURE__ */ jsx(
1701
2087
  "div",
1702
2088
  {
@@ -1751,6 +2137,43 @@ const UnifiedTimeline = memo(function UnifiedTimeline2({
1751
2137
  /* @__PURE__ */ jsx("span", { style: { fontSize: "0.875rem" }, children: "No events to display" })
1752
2138
  ]
1753
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
+ }
1754
2177
  ) : viewMode === "list" ? (
1755
2178
  // List View
1756
2179
  sortedEvents.map((event, index) => /* @__PURE__ */ jsx(
@@ -1767,8 +2190,8 @@ const UnifiedTimeline = memo(function UnifiedTimeline2({
1767
2190
  /* @__PURE__ */ jsx(
1768
2191
  ScatterView,
1769
2192
  {
1770
- events,
1771
- tracks: effectiveTracks,
2193
+ events: filteredEvents,
2194
+ tracks: effectiveTracksForViews,
1772
2195
  start,
1773
2196
  end,
1774
2197
  trackHeight,
@@ -1783,8 +2206,8 @@ const UnifiedTimeline = memo(function UnifiedTimeline2({
1783
2206
  /* @__PURE__ */ jsx(
1784
2207
  ChartView,
1785
2208
  {
1786
- events,
1787
- tracks: effectiveTracks,
2209
+ events: filteredEvents,
2210
+ tracks: effectiveTracksForViews,
1788
2211
  start,
1789
2212
  end,
1790
2213
  trackHeight,
@@ -1810,6 +2233,9 @@ const UnifiedTimeline = memo(function UnifiedTimeline2({
1810
2233
  );
1811
2234
  });
1812
2235
  export {
1813
- UnifiedTimeline
2236
+ UnifiedTimeline,
2237
+ getTimelineEventDisplayStatus,
2238
+ isTimelineFilterActive,
2239
+ matchesTimelineFilter
1814
2240
  };
1815
2241
  //# sourceMappingURL=UnifiedTimeline.js.map