@zendir/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/CHANGELOG.md CHANGED
@@ -1,84 +1,142 @@
1
- # @zendir/ui
2
-
3
- ## 0.2.2
4
-
5
- ### Features
6
-
7
- #### GroundTrackMap — Night Visualization
8
-
9
- - **Seamless night polygon** — completely rewritten terminator geometry: sunset/sunrise curves are now computed as continuous longitude pairs, producing a single closed polygon with no antimeridian artifacts. Eliminates all "jerk" lines and rendering glitches at the poles.
10
- - **`nightTileUrl` prop** — optional second tile layer (e.g. NASA Black Marble, VIIRS city lights) rendered beneath the terminator overlay. The graduated twilight gradient naturally masks the day-to-night tile transition. Leaflet backend only.
11
- - **`lightSources` prop** — array of point light sources (`LightSource` interface) rendered as soft glow dots on the night side of the map. Each light is masked by the terminator: invisible in daylight, fading in through twilight, full brightness at night. Supports custom colors, radii, intensity, and labels.
12
- - **Solar elevation masking** — light source visibility is computed per-point using the exact solar elevation angle (not polygon containment), giving a smooth and physically correct twilight fade for each individual light.
13
-
14
- ### Documentation
15
-
16
- - **City Lights at Night** story — 35+ world cities as `lightSources`, demonstrating realistic nighttime glow.
17
- - **City Lights Time Travel** story interactive UTC hour slider showing lights switching on/off as the terminator sweeps.
18
- - **Custom Light Sources** story mission scenario with colored RF emitters, bases, and relay nodes.
19
- - **Night Tile Layer** story — demonstrates `nightTileUrl` combined with `lightSources`.
20
- - Updated component description with Night Tile Layer and Dynamic Light Sources sections.
21
-
22
- ### Bug Fixes
23
-
24
- - Fixed terminator night polygon antimeridian wrapping — sunset and sunrise curves are now generated as continuous coordinate pairs (no `lon ± 180` mirroring), preventing the polygon from crossing the day side.
25
- - Removed unused `buildBandPolygon` function from Leaflet backend.
26
-
27
- ---
28
-
29
- ## 0.2.0
30
-
31
- ### Features
32
-
33
- #### SDK Category System (New)
34
- - **`CategoryDef`**shared interface for a named, colored data category (`id`, `color`, `label?`), used across Timeline, GroundTrackMap, and any future component.
35
- - **`CategoryPalette`**utility class that maps category IDs to stable colors and labels, with built-in fallback palettes for auto-assignment.
36
- - **`CategoryProvider` / `useCategoryPalette`** — optional React Context for sharing a `CategoryPalette` and a custom display label (e.g. "Squad", "Division") across an entire dashboard. Fully opt-in; components work standalone without it.
37
- - New Storybook documentation page (`SDK Category Concept`) with interactive examples, architecture diagrams, and integration guidance.
38
-
39
- #### UnifiedTimeline
40
- - **Team / category-aware events** — events now carry structured team identity (`id`, `color`, `label?`), enabling category-colored event bars and badges.
41
- - **Multi-select team filter** — replaces the former boolean `teamColoredOnly` toggle; users can filter by specific teams via pill-style checkboxes.
42
- - **`teamLabel` prop** devs can rename "Team" to any domain-specific term (e.g. "Squad", "Division"); also readable from `CategoryProvider` context.
43
- - **Day markers** — `showDayMarkers` draws labeled day boundaries on multi-day timelines.
44
- - **Redesigned filter bar** — collapsible panel with Astro UX filter icon, search field moved to top header row, responsive breakpoints.
45
- - **Performance** — bounding-box culling for `ChartView` events outside the visible viewport.
46
-
47
- #### GroundTrackMap
48
- - **Twilight terminator with gradient zones** — realistic Civil / Nautical / Astronomical / Full Night shading derived from solar depression angle, replacing the former hard-edge day/night line. Uses `depressionDeg` for precise boundaries.
49
- - **Collaborative pins** — new `MapPin` interface and `pins` / `pinsEditable` / `onPinAdd` / `onPinUpdate` / `onPinRemove` props for placing colored points-of-interest synced across terminals.
50
- - **Enhanced satellite visualization** `showFootprint` / `footprintRadius` for sensor coverage circles, `futureTrackIndex` for solid-past / dashed-future track split, `passMarkers` for AOS/LOS diamonds.
51
- - **Ground station antenna icons** — `dish`, `phased-array`, `omni`, and `relay` icon types with coverage circles and Astro status colors.
52
- - **Legend overlay** — auto-generated satellite + ground station legend with status indicators.
53
- - Category-aware pin colors via `CategoryProvider` integration.
54
-
55
- #### SimulationControls
56
- - Increased control-button background opacities for better visibility on dark themes.
57
-
58
- ### Documentation
59
- - Comprehensive Storybook updates for Timeline (`WithCategoryProvider`, `MultiDayWithCategories` stories) and GroundTrackMap (`SDK Category Integration` section).
60
- - New `CategoryConcept` Storybook page with `PaletteBasics`, `ProviderAndHook`, and `DynamicCategories` interactive stories.
61
-
62
- ### Breaking Changes
63
- - `TimelineEvent.color` replaced by `TimelineEvent.team` (`TimelineTeam` / `CategoryDef`). Plain string colors are still accepted for backward compatibility but are treated as legacy entries.
64
- - `TimelineFilter.teamColoredOnly` replaced by `TimelineFilter.teams` (multi-select `string[]`).
65
-
66
- ---
67
-
68
- ## 0.1.0
69
-
70
- Initial public release.
71
-
72
- ### Features
73
-
74
- - 60+ React components for space, air, land, and maritime operations
75
- - Built on Astro UX Design System
76
- - Themeable (Zen, Hybrid, Astro, Glass) with dark/light mode
77
- - ECharts-based charting (line, area, bar, radar, treemap, sankey, and more)
78
- - 3D viewers (Earth, Solar System, ZenSpace3D) via Three.js
79
- - Ground track maps (Leaflet and canvas backends)
80
- - Mission control widgets (MissionClock, SimulationControls, UnifiedTimeline)
81
- - Layout primitives (Box, Flex, Grid, Stack, Container, SideNav, SidePanel)
82
- - Accessibility-first (WCAG 2.2 AA oriented)
83
- - Design tokens as JS objects and CSS custom properties
84
- - Optional @zendir/sdk integration with graceful fallback
1
+ # @zendir/ui
2
+
3
+ ## 0.2.4
4
+
5
+ ### Features
6
+
7
+ #### GroundTrackMap — Layers Panel
8
+
9
+ - **Layers icon + dropdown panel** — the top-right control bar now shows a stacked-diamond icon that opens a clean dropdown panel with two sections: **Base Map** (Dark/Satellite radio) and **Overlays** (toggle switches for Day/Night terminator, Grid Lines, and custom layers).
10
+ - **Custom layers API** — pass `customLayers: MapLayerDef[]` to add your own toggle items to the Overlays section. The map provides the toggle UI; the consumer app renders its own overlay content via `onLayerChange(layerId, enabled)`.
11
+ - **Persistent tile style** — Dark/Satellite choice is saved to `localStorage` and restored across tabs and page reloads.
12
+ - **Unified control bar** — Recenter, Layers, and Zoom (+/−) are now a single horizontal row at top-right, replacing both the old separate controls and Leaflet's native zoom.
13
+ - **Runtime overlay toggling** — built-in overlays (Terminator, Grid) can now be toggled on/off at runtime from the Layers panel without remounting the map.
14
+
15
+ ### Breaking Changes
16
+
17
+ - `showMapStyleToggle` prop is still accepted but now controls whether the "Base Map" section appears in the Layers panel (default `true`).
18
+ - Leaflet's native zoom controls have been replaced by custom-styled buttons matching the Astro UXDS dark ops aesthetic.
19
+
20
+ ### Documentation
21
+
22
+ - **LayersPanel** story — demonstrates the full layers panel with base map toggle and overlay switches.
23
+ - **CustomLayers** story — shows how to add developer-defined overlay toggles with `MapLayerDef[]` and respond via `onLayerChange`.
24
+
25
+ ---
26
+
27
+ ## 0.2.3
28
+
29
+ ### Features
30
+
31
+ #### GroundTrackMap — Map Style Toggle
32
+
33
+ - **Built-in Dark / Satellite tile switcher** — when no explicit `tileUrl` is passed, a compact toggle appears below the Leaflet zoom controls allowing operators to switch between Dark (CartoDB) and Satellite (Esri World Imagery) tile layers.
34
+ - **No-flash tile swap** toggling swaps only the tile layer without recreating the Leaflet map, preserving the current zoom, pan, and overlay state.
35
+ - **`showMapStyleToggle` prop** defaults to `true`. Set to `false` to hide the toggle. Automatically hidden when an explicit `tileUrl` is provided (backward compatible).
36
+ - **`TILE_PRESETS`** — exported preset URLs (`dark`, `satellite`, `light`) for quick tile configuration.
37
+
38
+ #### GroundTrackMap — Terminator Boundary Line
39
+
40
+ - **Geometric terminator line** — a subtle dashed line at the 0° solar depression boundary (geometric sunset/sunrise) is now drawn on both Canvas and Leaflet backends, giving a clear visual reference for the day/night edge while the graduated fade provides the realistic transition.
41
+
42
+ #### UnifiedTimelinePlayhead Auto-Follow
43
+
44
+ - **Auto-scroll to playhead** — when the playhead marker moves near the edge of the visible chart viewport, the view auto-scrolls to keep it centered. Throttled at 300ms to avoid fighting user scrolling.
45
+ - **Smooth playhead animation** — the playhead line now uses a CSS transition (`left 0.4s linear`) for glide-smooth movement between position updates.
46
+
47
+ ### Documentation
48
+
49
+ - **Map Style Toggle** story demonstrates the built-in tile switcher with a satellite track and terminator, including opt-out patterns.
50
+ - Updated component description with Map Style Toggle feature.
51
+
52
+ ### Internal
53
+
54
+ - Refactored tile layer lifecycle in `GroundTrackMapLeaflet` — tile creation is now a separate effect from map initialization, enabling smooth in-place tile swaps.
55
+ - **Fixed duplicate tile layer on mount** — the initial mount effect no longer creates a tile layer; the dedicated tile-swap effect is solely responsible, eliminating z-order conflicts that caused the terminator overlay to render behind tiles.
56
+ - **Attribution management** tile swap effect now properly adds/removes Carto vs OSM attribution when switching tile styles.
57
+ - Map controls repositioned to bottom-left for reliable visibility across container sizes.
58
+
59
+ ---
60
+
61
+ ## 0.2.2
62
+
63
+ ### Features
64
+
65
+ #### GroundTrackMap — Night Visualization
66
+
67
+ - **Seamless night polygon** — completely rewritten terminator geometry: sunset/sunrise curves are now computed as continuous longitude pairs, producing a single closed polygon with no antimeridian artifacts. Eliminates all "jerk" lines and rendering glitches at the poles.
68
+ - **`nightTileUrl` prop** — optional second tile layer (e.g. NASA Black Marble, VIIRS city lights) rendered beneath the terminator overlay. The graduated twilight gradient naturally masks the day-to-night tile transition. Leaflet backend only.
69
+ - **`lightSources` prop** — array of point light sources (`LightSource` interface) rendered as soft glow dots on the night side of the map. Each light is masked by the terminator: invisible in daylight, fading in through twilight, full brightness at night. Supports custom colors, radii, intensity, and labels.
70
+ - **Solar elevation masking** — light source visibility is computed per-point using the exact solar elevation angle (not polygon containment), giving a smooth and physically correct twilight fade for each individual light.
71
+
72
+ ### Documentation
73
+
74
+ - **City Lights at Night** story — 35+ world cities as `lightSources`, demonstrating realistic nighttime glow.
75
+ - **City Lights Time Travel** story — interactive UTC hour slider showing lights switching on/off as the terminator sweeps.
76
+ - **Custom Light Sources** story — mission scenario with colored RF emitters, bases, and relay nodes.
77
+ - **Night Tile Layer** story demonstrates `nightTileUrl` combined with `lightSources`.
78
+ - Updated component description with Night Tile Layer and Dynamic Light Sources sections.
79
+
80
+ ### Bug Fixes
81
+
82
+ - Fixed terminator night polygon antimeridian wrapping — sunset and sunrise curves are now generated as continuous coordinate pairs (no `lon ± 180` mirroring), preventing the polygon from crossing the day side.
83
+ - Removed unused `buildBandPolygon` function from Leaflet backend.
84
+
85
+ ---
86
+
87
+ ## 0.2.0
88
+
89
+ ### Features
90
+
91
+ #### SDK Category System (New)
92
+ - **`CategoryDef`** — shared interface for a named, colored data category (`id`, `color`, `label?`), used across Timeline, GroundTrackMap, and any future component.
93
+ - **`CategoryPalette`** — utility class that maps category IDs to stable colors and labels, with built-in fallback palettes for auto-assignment.
94
+ - **`CategoryProvider` / `useCategoryPalette`** — optional React Context for sharing a `CategoryPalette` and a custom display label (e.g. "Squad", "Division") across an entire dashboard. Fully opt-in; components work standalone without it.
95
+ - New Storybook documentation page (`SDK Category Concept`) with interactive examples, architecture diagrams, and integration guidance.
96
+
97
+ #### UnifiedTimeline
98
+ - **Team / category-aware events** — events now carry structured team identity (`id`, `color`, `label?`), enabling category-colored event bars and badges.
99
+ - **Multi-select team filter** — replaces the former boolean `teamColoredOnly` toggle; users can filter by specific teams via pill-style checkboxes.
100
+ - **`teamLabel` prop** — devs can rename "Team" to any domain-specific term (e.g. "Squad", "Division"); also readable from `CategoryProvider` context.
101
+ - **Day markers** — `showDayMarkers` draws labeled day boundaries on multi-day timelines.
102
+ - **Redesigned filter bar** — collapsible panel with Astro UX filter icon, search field moved to top header row, responsive breakpoints.
103
+ - **Performance** — bounding-box culling for `ChartView` events outside the visible viewport.
104
+
105
+ #### GroundTrackMap
106
+ - **Twilight terminator with gradient zones** — realistic Civil / Nautical / Astronomical / Full Night shading derived from solar depression angle, replacing the former hard-edge day/night line. Uses `depressionDeg` for precise boundaries.
107
+ - **Collaborative pins** — new `MapPin` interface and `pins` / `pinsEditable` / `onPinAdd` / `onPinUpdate` / `onPinRemove` props for placing colored points-of-interest synced across terminals.
108
+ - **Enhanced satellite visualization** — `showFootprint` / `footprintRadius` for sensor coverage circles, `futureTrackIndex` for solid-past / dashed-future track split, `passMarkers` for AOS/LOS diamonds.
109
+ - **Ground station antenna icons** — `dish`, `phased-array`, `omni`, and `relay` icon types with coverage circles and Astro status colors.
110
+ - **Legend overlay** — auto-generated satellite + ground station legend with status indicators.
111
+ - Category-aware pin colors via `CategoryProvider` integration.
112
+
113
+ #### SimulationControls
114
+ - Increased control-button background opacities for better visibility on dark themes.
115
+
116
+ ### Documentation
117
+ - Comprehensive Storybook updates for Timeline (`WithCategoryProvider`, `MultiDayWithCategories` stories) and GroundTrackMap (`SDK Category Integration` section).
118
+ - New `CategoryConcept` Storybook page with `PaletteBasics`, `ProviderAndHook`, and `DynamicCategories` interactive stories.
119
+
120
+ ### Breaking Changes
121
+ - `TimelineEvent.color` replaced by `TimelineEvent.team` (`TimelineTeam` / `CategoryDef`). Plain string colors are still accepted for backward compatibility but are treated as legacy entries.
122
+ - `TimelineFilter.teamColoredOnly` replaced by `TimelineFilter.teams` (multi-select `string[]`).
123
+
124
+ ---
125
+
126
+ ## 0.1.0
127
+
128
+ Initial public release.
129
+
130
+ ### Features
131
+
132
+ - 60+ React components for space, air, land, and maritime operations
133
+ - Built on Astro UX Design System
134
+ - Themeable (Zen, Hybrid, Astro, Glass) with dark/light mode
135
+ - ECharts-based charting (line, area, bar, radar, treemap, sankey, and more)
136
+ - 3D viewers (Earth, Solar System, ZenSpace3D) via Three.js
137
+ - Ground track maps (Leaflet and canvas backends)
138
+ - Mission control widgets (MissionClock, SimulationControls, UnifiedTimeline)
139
+ - Layout primitives (Box, Flex, Grid, Stack, Container, SideNav, SidePanel)
140
+ - Accessibility-first (WCAG 2.2 AA oriented)
141
+ - Design tokens as JS objects and CSS custom properties
142
+ - Optional @zendir/sdk integration with graceful fallback
@@ -1,5 +1,5 @@
1
1
  import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
- import { memo, useState, useCallback, useMemo, useRef } from "react";
2
+ import { memo, useState, useCallback, useMemo, useRef, useEffect } from "react";
3
3
  import { classNames, safeAccentText } from "../utils/index.js";
4
4
  import { useCategoryPalette } from "../context/CategoryContext.js";
5
5
  import { Icon } from "../core/Icon.js";
@@ -578,6 +578,28 @@ const ChartView = memo(function ChartView2({
578
578
  const currentPlayheadTime = playheadTime || /* @__PURE__ */ new Date();
579
579
  const now = currentPlayheadTime.getTime();
580
580
  const playheadPercent = showPlayhead && now >= start.getTime() && now <= end.getTime() ? (now - start.getTime()) / totalDuration * 100 : null;
581
+ const lastAutoScrollRef = useRef(0);
582
+ useEffect(() => {
583
+ if (playheadPercent === null) return;
584
+ const container = scrollContainerRef.current;
585
+ if (!container) return;
586
+ const contentWidth = container.scrollWidth;
587
+ const viewportWidth = container.clientWidth;
588
+ if (contentWidth <= viewportWidth) return;
589
+ const timelineContentWidth = contentWidth - trackLabelWidth;
590
+ const playheadPx = trackLabelWidth + playheadPercent / 100 * timelineContentWidth;
591
+ const scrollLeft = container.scrollLeft;
592
+ const visibleLeft = scrollLeft + trackLabelWidth;
593
+ const visibleRight = scrollLeft + viewportWidth;
594
+ const margin = viewportWidth * 0.15;
595
+ if (playheadPx > visibleRight - margin || playheadPx < visibleLeft + margin) {
596
+ const nowMs = Date.now();
597
+ if (nowMs - lastAutoScrollRef.current < 300) return;
598
+ lastAutoScrollRef.current = nowMs;
599
+ const targetScroll = playheadPx - viewportWidth * 0.5;
600
+ container.scrollTo({ left: Math.max(0, targetScroll), behavior: "smooth" });
601
+ }
602
+ }, [playheadPercent, trackLabelWidth]);
581
603
  const hoveredEventData = hoveredEvent ? events.find((e) => e.id === hoveredEvent) : null;
582
604
  return /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
583
605
  /* @__PURE__ */ jsx(
@@ -946,7 +968,8 @@ const ChartView = memo(function ChartView2({
946
968
  backgroundColor: tokens.colors.accent.primary,
947
969
  boxShadow: `0 0 12px ${tokens.colors.accent.primary}`,
948
970
  zIndex: Z.trackEventHovered,
949
- pointerEvents: "none"
971
+ pointerEvents: "none",
972
+ transition: "left 0.4s linear"
950
973
  },
951
974
  children: [
952
975
  /* @__PURE__ */ jsx(