@xenosystem/blocks 0.13.30 → 0.13.32

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.
@@ -7696,7 +7696,7 @@ var curveManifest = {
7696
7696
 
7697
7697
  // src/edit/curve/react/CurvePanelView.tsx
7698
7698
  import { useCallback as useCallback6, useEffect as useEffect5, useRef as useRef6, useSyncExternalStore as useSyncExternalStore5 } from "react";
7699
- import { Column as Column5, EmptyState as EmptyState4, StatusBar as StatusBar3, Text as Text5, TextButton as TextButton3, Toolbar as Toolbar3, ToolbarGroup } from "@xenosystem/components/chrome";
7699
+ import { Column as Column5, DrawnSurface, EmptyState as EmptyState4, StatusBar as StatusBar3, Text as Text5, TextButton as TextButton3, Toolbar as Toolbar3, ToolbarGroup } from "@xenosystem/components/chrome";
7700
7700
 
7701
7701
  // src/edit/curve/declaration.ts
7702
7702
  import { formatTick } from "@xenosystem/time-core";
@@ -7895,13 +7895,10 @@ function CurveSurface({ controller }) {
7895
7895
  const selected = new Set(state.selection.keys.map(keyRefId));
7896
7896
  const channels = state.curves?.channels ?? [];
7897
7897
  return /* @__PURE__ */ jsx7(
7898
- "div",
7898
+ DrawnSurface,
7899
7899
  {
7900
7900
  ref: containerRef,
7901
- tabIndex: 0,
7902
- role: "application",
7903
- "aria-label": "Curve editor",
7904
- style: SURFACE,
7901
+ label: "Curve editor",
7905
7902
  onWheel,
7906
7903
  onPointerDown,
7907
7904
  onPointerMove,
@@ -8026,15 +8023,6 @@ function Handles({
8026
8023
  ] }, side);
8027
8024
  }) });
8028
8025
  }
8029
- var SURFACE = {
8030
- position: "relative",
8031
- flex: 1,
8032
- minHeight: 0,
8033
- overflow: "hidden",
8034
- outline: "none",
8035
- userSelect: "none",
8036
- touchAction: "none"
8037
- };
8038
8026
  var CURVE_RUNTIME_UNITS = ["curve/Surface"];
8039
8027
  function curveRuntimeComponents(controller) {
8040
8028
  return { "curve/Surface": () => /* @__PURE__ */ jsx7(CurveSurface, { controller }) };
@@ -8646,7 +8634,7 @@ var viewportManifest = {
8646
8634
 
8647
8635
  // src/edit/viewport/react/ViewportPanelView.tsx
8648
8636
  import { useEffect as useEffect6, useRef as useRef7, useSyncExternalStore as useSyncExternalStore6 } from "react";
8649
- import { Badge as Badge4, Overlay, StatusBar as StatusBar4 } from "@xenosystem/components/chrome";
8637
+ import { Badge as Badge4, DrawnSurface as DrawnSurface2, Overlay, StatusBar as StatusBar4 } from "@xenosystem/components/chrome";
8650
8638
 
8651
8639
  // src/edit/viewport/declaration.ts
8652
8640
  function viewportViewState(c, options = {}) {
@@ -8730,12 +8718,11 @@ function ViewportSurface({ controller, overlays, background, children }) {
8730
8718
  }, [controller]);
8731
8719
  const hidden = new Set(state.hiddenSlots);
8732
8720
  return /* @__PURE__ */ jsxs7(
8733
- "div",
8721
+ DrawnSurface2,
8734
8722
  {
8735
8723
  ref: containerRef,
8736
- tabIndex: 0,
8737
- role: "application",
8738
- "aria-label": "Viewport",
8724
+ label: "Viewport",
8725
+ focused: state.focused,
8739
8726
  onFocus: () => controller.setFocused(true),
8740
8727
  onBlur: () => controller.setFocused(false),
8741
8728
  onKeyDown: (event) => controller.routeKey("down", event.nativeEvent),
@@ -8756,19 +8743,7 @@ function ViewportSurface({ controller, overlays, background, children }) {
8756
8743
  onPointerLeave: (event) => controller.routePointer("leave", event.nativeEvent),
8757
8744
  onWheel: (event) => controller.routePointer("wheel", event.nativeEvent),
8758
8745
  onContextMenu: (event) => event.preventDefault(),
8759
- style: {
8760
- position: "relative",
8761
- width: "100%",
8762
- height: "100%",
8763
- minHeight: 0,
8764
- overflow: "hidden",
8765
- outline: "none",
8766
- background: background ?? "transparent",
8767
- // A focused viewport must be visibly focused, or the element-scoped keyboard model is
8768
- // invisible to the person using it.
8769
- boxShadow: state.focused ? "inset 0 0 0 1px var(--xeno-control)" : void 0,
8770
- touchAction: "none"
8771
- },
8746
+ style: { width: "100%", height: "100%", background: background ?? "transparent" },
8772
8747
  children: [
8773
8748
  /* @__PURE__ */ jsx8(
8774
8749
  "canvas",
@@ -11893,7 +11868,7 @@ var nodegraphManifest = {
11893
11868
 
11894
11869
  // src/edit/nodegraph/react/NodeGraphPanelView.tsx
11895
11870
  import { useCallback as useCallback7, useEffect as useEffect7, useRef as useRef8, useSyncExternalStore as useSyncExternalStore9 } from "react";
11896
- import { Column as Column8, EmptyState as EmptyState7, StatusBar as StatusBar7, Text as Text8, TextButton as TextButton6, Toolbar as Toolbar6, ToolbarGroup as ToolbarGroup4 } from "@xenosystem/components/chrome";
11871
+ import { Badge as Badge7, Column as Column8, DrawnSurface as DrawnSurface3, EmptyState as EmptyState7, Overlay as Overlay2, StatusBar as StatusBar7, Text as Text8, TextButton as TextButton6, Toolbar as Toolbar6, ToolbarGroup as ToolbarGroup4 } from "@xenosystem/components/chrome";
11897
11872
 
11898
11873
  // src/edit/nodegraph/declaration.ts
11899
11874
  function nodegraphViewState(c, _options = {}) {
@@ -12066,13 +12041,10 @@ function NodeGraphSurface({ controller }) {
12066
12041
  const selectedNodes = new Set(state.selection.nodeIds);
12067
12042
  const selectedEdges = new Set(state.selection.edgeIds);
12068
12043
  return /* @__PURE__ */ jsxs10(
12069
- "div",
12044
+ DrawnSurface3,
12070
12045
  {
12071
12046
  ref: containerRef,
12072
- tabIndex: 0,
12073
- role: "application",
12074
- "aria-label": "Node graph",
12075
- style: SURFACE2,
12047
+ label: "Node graph",
12076
12048
  onWheel,
12077
12049
  onPointerDown,
12078
12050
  onPointerMove,
@@ -12124,7 +12096,7 @@ function NodeGraphSurface({ controller }) {
12124
12096
  ] })
12125
12097
  }
12126
12098
  ),
12127
- preview?.connection && !preview.connection.verdict.ok && preview.connection.target ? /* @__PURE__ */ jsx11("div", { style: REASON, children: preview.connection.verdict.reason }) : null
12099
+ preview?.connection && !preview.connection.verdict.ok && preview.connection.target ? /* @__PURE__ */ jsx11(Overlay2, { anchor: "bottom-left", children: /* @__PURE__ */ jsx11(Badge7, { children: preview.connection.verdict.reason }) }) : null
12128
12100
  ]
12129
12101
  }
12130
12102
  );
@@ -12248,27 +12220,6 @@ function Port({
12248
12220
  )
12249
12221
  ] });
12250
12222
  }
12251
- var SURFACE2 = {
12252
- position: "relative",
12253
- flex: 1,
12254
- minHeight: 0,
12255
- overflow: "hidden",
12256
- outline: "none",
12257
- userSelect: "none",
12258
- touchAction: "none"
12259
- };
12260
- var REASON = {
12261
- position: "absolute",
12262
- left: 8,
12263
- bottom: 8,
12264
- padding: "2px 6px",
12265
- fontSize: 10,
12266
- borderRadius: 2,
12267
- border: "1px solid var(--xeno-control)",
12268
- background: "var(--xeno-elevated)",
12269
- color: "var(--xeno-text)",
12270
- pointerEvents: "none"
12271
- };
12272
12223
  var NODEGRAPH_RUNTIME_UNITS = ["nodegraph/Surface"];
12273
12224
  function nodegraphRuntimeComponents(controller) {
12274
12225
  return { "nodegraph/Surface": () => /* @__PURE__ */ jsx11(NodeGraphSurface, { controller }) };
@@ -13500,7 +13451,7 @@ var treeManifest = {
13500
13451
  // src/edit/tree/react/TreePanelView.tsx
13501
13452
  import { useCallback as useCallback8, useEffect as useEffect8, useRef as useRef9, useSyncExternalStore as useSyncExternalStore10 } from "react";
13502
13453
  import {
13503
- Badge as Badge7,
13454
+ Badge as Badge8,
13504
13455
  Column as Column9,
13505
13456
  EmptyState as EmptyState8,
13506
13457
  ErrorState,
@@ -13850,15 +13801,15 @@ function TreePanelView({ controller, ...options }) {
13850
13801
  ] }),
13851
13802
  meta: /* @__PURE__ */ jsxs11(Fragment8, { children: [
13852
13803
  r.chipLoading ? /* @__PURE__ */ jsx12(Text9, { role: "caption", children: "loading\u2026" }) : null,
13853
- r.chipError ? /* @__PURE__ */ jsx12(Badge7, { tone: "error", children: r.chipErrorText }) : null,
13804
+ r.chipError ? /* @__PURE__ */ jsx12(Badge8, { tone: "error", children: r.chipErrorText }) : null,
13854
13805
  r.chipLoadMore ? /* @__PURE__ */ jsx12(TextButton7, { onClick: () => ui10({ kind: "loadMore", id: r.id }), children: "load more\u2026" }) : null,
13855
- r.chipTruncated ? /* @__PURE__ */ jsx12(Badge7, { tone: "warning", children: r.chipTruncatedText }) : null,
13806
+ r.chipTruncated ? /* @__PURE__ */ jsx12(Badge8, { tone: "warning", children: r.chipTruncatedText }) : null,
13856
13807
  r.chipEmpty ? /* @__PURE__ */ jsx12(Text9, { role: "caption", children: "empty" }) : null
13857
13808
  ] }),
13858
13809
  trailing: /* @__PURE__ */ jsxs11(Fragment8, { children: [
13859
13810
  r.columns.map((c) => /* @__PURE__ */ jsx12(Text9, { role: "number", children: c.text }, c.key)),
13860
13811
  r.glyphs.map((g) => /* @__PURE__ */ jsx12(Text9, { role: "meta", title: g.title, children: icon(g.iconName, g.iconText) }, g.key)),
13861
- r.badges.map((b) => /* @__PURE__ */ jsx12(Badge7, { tone: b.tone, children: b.text }, b.key)),
13812
+ r.badges.map((b) => /* @__PURE__ */ jsx12(Badge8, { tone: b.tone, children: b.text }, b.key)),
13862
13813
  r.actions.map((a) => /* @__PURE__ */ jsx12(IconButton7, { size: "sm", icon: icon(a.iconName, a.iconText), label: a.label, disabled: a.disabled, onClick: () => ui10({ kind: "action", id: a.rowId, actionId: a.actionId }) }, a.key))
13863
13814
  ] }),
13864
13815
  onExpandedChange: () => ui10({ kind: "toggleExpanded", id: r.id }),
@@ -421,7 +421,7 @@ interface TransportPanelViewModel extends TransportViewState {
421
421
  positionLabel: string;
422
422
  }
423
423
  declare function transportPanelView(state: TransportViewState): TransportPanelViewModel;
424
- declare const BEHAVIOURS$1: {
424
+ declare const BEHAVIOURS$2: {
425
425
  'time/transportPanelView': (inputs: Record<string, unknown>) => TransportPanelViewModel;
426
426
  };
427
427
  declare const TRANSPORT_DECLARATION: BlockDeclaration;
@@ -1977,7 +1977,60 @@ declare function rulerTicks(scale: XenoTimeScale, timebase: XenoTimebase, option
1977
1977
  declare function gridTicksFor(scale: XenoTimeScale, timebase: XenoTimebase): number;
1978
1978
 
1979
1979
  /**
1980
- * The Timeline view.
1980
+ * The Timeline panel AS A DECLARATION — the twenty-sixth and LAST block written the §8d way, the
1981
+ * fifth DRAWN surface. The CHROME is data: the tool choice (a `chrome/SegmentedControl` — select,
1982
+ * razor, ripple, hand — where four hand-styled `aria-pressed` buttons lived), the snap toggle (a
1983
+ * `chrome/FilterChip`), the fit action, the empty state, the track count and the playhead readout.
1984
+ * The SURFACE is one runtime unit (`timeline/Surface`) bound to the controller: the ruler, the
1985
+ * lanes with their clips, the marquee, the playhead layer, the pointer and keyboard models.
1986
+ *
1987
+ * Presentation contract: input `view` (a {@link TimelineViewModel}), output `ui` (a
1988
+ * {@link TimelineUiIntent}) applied by the runtime to the controller's own methods.
1989
+ */
1990
+
1991
+ /** The half of a renderer's config the view reads. */
1992
+ interface TimelineViewOptions {
1993
+ trackHeightPx?: number;
1994
+ virtualize?: boolean;
1995
+ }
1996
+ interface TimelineViewModel {
1997
+ tools: {
1998
+ value: XenoTimelineTool;
1999
+ label: string;
2000
+ title: string;
2001
+ }[];
2002
+ tool: XenoTimelineTool;
2003
+ snapOn: boolean;
2004
+ empty: boolean;
2005
+ drawn: boolean;
2006
+ tracksLabel?: string;
2007
+ playheadLabel: string;
2008
+ }
2009
+ type TimelineUiIntent = {
2010
+ kind: 'tool';
2011
+ tool: XenoTimelineTool;
2012
+ } | {
2013
+ kind: 'snap';
2014
+ on: boolean;
2015
+ } | {
2016
+ kind: 'fit';
2017
+ };
2018
+ /** Derive the view model from the live controller — the runtime calls this on every draw. */
2019
+ declare function timelineViewState(c: TimelineController, _options?: TimelineViewOptions): TimelineViewModel;
2020
+ /** Apply a `ui` intent to the controller — the runtime's half of the contract. */
2021
+ declare function applyTimelineUi(c: TimelineController, intent: TimelineUiIntent): void;
2022
+ declare const timelineViewManifest: PanelManifest;
2023
+ declare const BEHAVIOURS$1: {
2024
+ 'time/timelinePanelView': (inputs: Record<string, unknown>) => TimelineViewModel;
2025
+ };
2026
+ declare const TIMELINE_DECLARATION: BlockDeclaration;
2027
+
2028
+ /**
2029
+ * The Timeline view — the CODE VIEW of `TIMELINE_DECLARATION`, drawing the same
2030
+ * {@link TimelineViewModel} byte-identical (the equivalence suite holds the two together). The one
2031
+ * runtime-bound unit is the SURFACE (`timeline/Surface`: the ruler, the lanes and clips, the
2032
+ * marquee, the playhead, the pointer and keyboard models); the chrome intents go through
2033
+ * `applyTimelineUi`.
1981
2034
  *
1982
2035
  * Composes `@xenosystem/components/chrome`. **The host must import
1983
2036
  * `@xenosystem/workbench/primitives.css`** or this renders unstyled with no error — the most common
@@ -1990,13 +2043,23 @@ declare function gridTicksFor(scale: XenoTimeScale, timebase: XenoTimebase): num
1990
2043
  */
1991
2044
 
1992
2045
  /** Props for {@link TimelinePanelView}. */
1993
- interface TimelinePanelViewProps {
2046
+ interface TimelinePanelViewProps extends TimelineViewOptions {
1994
2047
  controller: TimelineController;
1995
- trackHeightPx?: number;
1996
- virtualize?: boolean;
1997
2048
  }
1998
2049
  /** The Timeline panel view. */
1999
- declare function TimelinePanelView({ controller }: TimelinePanelViewProps): ReactNode;
2050
+ declare function TimelinePanelView({ controller, ...options }: TimelinePanelViewProps): ReactNode;
2051
+ /**
2052
+ * The surface — `timeline/Surface` in the declaration, bound to the controller: the ruler (scrubs),
2053
+ * the lanes with their clips, the marquee, the playhead on its own layer, and the pointer and
2054
+ * keyboard models.
2055
+ */
2056
+ declare function TimelineSurface({ controller }: {
2057
+ controller: TimelineController;
2058
+ }): ReactNode;
2059
+ /** The unit names the runtime supplies for this block — what a host's registry check must accept beside the shared families. */
2060
+ declare const TIMELINE_RUNTIME_UNITS: readonly ["timeline/Surface"];
2061
+ /** The units the runtime registers for `TIMELINE_DECLARATION`, bound to ITS controller. */
2062
+ declare function timelineRuntimeComponents(controller: TimelineController): Record<(typeof TIMELINE_RUNTIME_UNITS)[number], React.ComponentType<any>>;
2000
2063
 
2001
2064
  /**
2002
2065
  * The `xeno.core.calendar` contract.
@@ -2540,4 +2603,4 @@ interface CalendarPanelViewProps extends CalendarViewOptions {
2540
2603
  /** The Calendar panel view. */
2541
2604
  declare function CalendarPanelView({ controller, firstDayOfWeek, emptyHint }: CalendarPanelViewProps): ReactNode;
2542
2605
 
2543
- export { ALL_CALENDAR_MODES, type BeginDragOptions, type BuildCellsOptions, BEHAVIOURS as CALENDAR_BEHAVIOURS, CALENDAR_DECLARATION, CALENDAR_PANEL_ID, CALENDAR_RUNTIME_UNITS, CalendarController, type CalendarControllerOptions, type CalendarHostBridge, type CalendarPanelState, CalendarPanelView, type CalendarPanelViewProps, type CalendarRenderContext, type CalendarUiIntent, type CalendarViewAgendaRow, type CalendarViewCell, type CalendarViewChip, type CalendarViewModel, type CalendarViewOptions, type CalendarViewState, type CreateCalendarPanelOptions, type CreateTimelinePanelOptions, type CreateTransportPanelOptions, DEFAULT_SNAP, DEFAULT_ZOOM, DRAG_THRESHOLD_PX, type DeriveOptions, EDGE_ZONE_MIN_CLIP_PX, EDGE_ZONE_PX, MIN_MAJOR_PX, MIN_MINOR_PX, TIMELINE_PANEL_ID, BEHAVIOURS$1 as TRANSPORT_BEHAVIOURS, TRANSPORT_DECLARATION, TRANSPORT_ICONS, TRANSPORT_RUNTIME_UNITS, TRIM_SNAP_PX, TimelineController, type TimelineControllerOptions, type TimelineHostBridge, type TimelinePanelState, TimelinePanelView, type TimelinePanelViewProps, type TimelineRenderConfig, type TimelineRenderContext, type TimelineViewState, type TransportKeyEvent, TransportPanelController, type TransportPanelControllerOptions, type TransportPanelSerialized, TransportPanelView, type TransportPanelViewModel, type TransportPanelViewProps, type TransportUiIntent, type TransportViewState, type XenoArrangement, type XenoCachedTile, type XenoCalendarCell, type XenoCalendarEdit, type XenoCalendarEvent, type XenoCalendarSlotActivate, type XenoCalendarViewMode, type XenoCalendarWindow, type XenoClip, type XenoClipFade, type XenoDragKind, type XenoDragModifiers, type XenoDragPreview, type XenoDragState, type XenoHitTarget, type XenoLaneTile, type XenoLaneTileRequest, type XenoMarker, type XenoOverlaySpan, type XenoRenderTier, type XenoRowLayout, type XenoRulerTick, type XenoSnapCandidate, type XenoSnapConfig, type XenoSnapMode, type XenoSnapResult, type XenoTickWeight, XenoTileCache, type XenoTileCacheOptions, XenoTimeScale, type XenoTimeScaleGeometry, type XenoTimeScaleState, type XenoTimelineOp, type XenoTimelineSelection, type XenoTimelineTool, type XenoTimelineViewport, type XenoTrack, type XenoTrackKind, type XenoTrimMode, type XenoVisibleTrack, type XenoZoomBounds, addDays, addMonths, alignToTileGrid, applyCalendarUi, applyTransportUi, beginDrag, blitTile, buildCells, buildRowLayout, calendarManifest, calendarPanel, calendarViewManifest, calendarViewState, chooseRung, clampScroll, clipDuration, clipsInMarquee, clipsOverlap, collectSnapTargets, commitDrag, computeVisible, createCalendarPanel, createTimelinePanel, createTransportPanel, dayKey, daysInMonth, dedupeByColumn, deriveEvents, edgeZone, formatMinutes, gridStart, gridTicksFor, hasSourceWindow, isZoomGesture, isoWeekday, packOverlaps, parseDayKey, passedThreshold, previewDrag, renderTier, rowAtY, rowInWindow, rulerTicks, scrollToReveal, snapDelta, snapTick, snapWouldFight, sourceRangeFor, statusTone, ticksPerStep, tileKey, tileWidthTicks, timelineManifest, timelinePanel, todayKey, transportManifest, transportPanel, transportPanelView, transportViewManifest, transportViewState, trimModeFor, visibleClips, visibleRows, weekStart, wheelZoomFactor, withSnapModifier, zoomAboutCursor, zoomBucket, zoomToFit };
2606
+ export { ALL_CALENDAR_MODES, type BeginDragOptions, type BuildCellsOptions, BEHAVIOURS as CALENDAR_BEHAVIOURS, CALENDAR_DECLARATION, CALENDAR_PANEL_ID, CALENDAR_RUNTIME_UNITS, CalendarController, type CalendarControllerOptions, type CalendarHostBridge, type CalendarPanelState, CalendarPanelView, type CalendarPanelViewProps, type CalendarRenderContext, type CalendarUiIntent, type CalendarViewAgendaRow, type CalendarViewCell, type CalendarViewChip, type CalendarViewModel, type CalendarViewOptions, type CalendarViewState, type CreateCalendarPanelOptions, type CreateTimelinePanelOptions, type CreateTransportPanelOptions, DEFAULT_SNAP, DEFAULT_ZOOM, DRAG_THRESHOLD_PX, type DeriveOptions, EDGE_ZONE_MIN_CLIP_PX, EDGE_ZONE_PX, MIN_MAJOR_PX, MIN_MINOR_PX, BEHAVIOURS$1 as TIMELINE_BEHAVIOURS, TIMELINE_DECLARATION, TIMELINE_PANEL_ID, TIMELINE_RUNTIME_UNITS, BEHAVIOURS$2 as TRANSPORT_BEHAVIOURS, TRANSPORT_DECLARATION, TRANSPORT_ICONS, TRANSPORT_RUNTIME_UNITS, TRIM_SNAP_PX, TimelineController, type TimelineControllerOptions, type TimelineHostBridge, type TimelinePanelState, TimelinePanelView, type TimelinePanelViewProps, type TimelineRenderConfig, type TimelineRenderContext, TimelineSurface, type TimelineUiIntent, type TimelineViewModel, type TimelineViewOptions, type TimelineViewState, type TransportKeyEvent, TransportPanelController, type TransportPanelControllerOptions, type TransportPanelSerialized, TransportPanelView, type TransportPanelViewModel, type TransportPanelViewProps, type TransportUiIntent, type TransportViewState, type XenoArrangement, type XenoCachedTile, type XenoCalendarCell, type XenoCalendarEdit, type XenoCalendarEvent, type XenoCalendarSlotActivate, type XenoCalendarViewMode, type XenoCalendarWindow, type XenoClip, type XenoClipFade, type XenoDragKind, type XenoDragModifiers, type XenoDragPreview, type XenoDragState, type XenoHitTarget, type XenoLaneTile, type XenoLaneTileRequest, type XenoMarker, type XenoOverlaySpan, type XenoRenderTier, type XenoRowLayout, type XenoRulerTick, type XenoSnapCandidate, type XenoSnapConfig, type XenoSnapMode, type XenoSnapResult, type XenoTickWeight, XenoTileCache, type XenoTileCacheOptions, XenoTimeScale, type XenoTimeScaleGeometry, type XenoTimeScaleState, type XenoTimelineOp, type XenoTimelineSelection, type XenoTimelineTool, type XenoTimelineViewport, type XenoTrack, type XenoTrackKind, type XenoTrimMode, type XenoVisibleTrack, type XenoZoomBounds, addDays, addMonths, alignToTileGrid, applyCalendarUi, applyTimelineUi, applyTransportUi, beginDrag, blitTile, buildCells, buildRowLayout, calendarManifest, calendarPanel, calendarViewManifest, calendarViewState, chooseRung, clampScroll, clipDuration, clipsInMarquee, clipsOverlap, collectSnapTargets, commitDrag, computeVisible, createCalendarPanel, createTimelinePanel, createTransportPanel, dayKey, daysInMonth, dedupeByColumn, deriveEvents, edgeZone, formatMinutes, gridStart, gridTicksFor, hasSourceWindow, isZoomGesture, isoWeekday, packOverlaps, parseDayKey, passedThreshold, previewDrag, renderTier, rowAtY, rowInWindow, rulerTicks, scrollToReveal, snapDelta, snapTick, snapWouldFight, sourceRangeFor, statusTone, ticksPerStep, tileKey, tileWidthTicks, timelineManifest, timelinePanel, timelineRuntimeComponents, timelineViewManifest, timelineViewState, todayKey, transportManifest, transportPanel, transportPanelView, transportViewManifest, transportViewState, trimModeFor, visibleClips, visibleRows, weekStart, wheelZoomFactor, withSnapModifier, zoomAboutCursor, zoomBucket, zoomToFit };
@@ -2857,17 +2857,118 @@ var timelineManifest = {
2857
2857
 
2858
2858
  // src/time/timeline/react/TimelinePanelView.tsx
2859
2859
  import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useSyncExternalStore as useSyncExternalStore2 } from "react";
2860
- import { EmptyState, StatusBar, Toolbar, ToolbarGroup } from "@xenosystem/components/chrome";
2860
+ import { Column as Column2, DrawnSurface, EmptyState, FilterChip, SegmentedControl, StatusBar, Text, TextButton as TextButton2, Toolbar, ToolbarGroup } from "@xenosystem/components/chrome";
2861
+
2862
+ // src/time/timeline/declaration.ts
2861
2863
  import { formatTick as formatTick4 } from "@xenosystem/time-core";
2862
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
2863
- var RULER_PX = 22;
2864
2864
  var TOOLS = [
2865
- { id: "select", label: "Select", key: "V" },
2866
- { id: "razor", label: "Razor", key: "C" },
2867
- { id: "ripple", label: "Ripple", key: "B" },
2868
- { id: "hand", label: "Hand", key: "H" }
2865
+ { value: "select", label: "Select", title: "Select (V)" },
2866
+ { value: "razor", label: "Razor", title: "Razor (C)" },
2867
+ { value: "ripple", label: "Ripple", title: "Ripple (B)" },
2868
+ { value: "hand", label: "Hand", title: "Hand (H)" }
2869
2869
  ];
2870
- function TimelinePanelView({ controller }) {
2870
+ function timelineViewState(c, _options = {}) {
2871
+ const state = c.getState();
2872
+ const tracks = state.arrangement?.tracks.length ?? 0;
2873
+ return {
2874
+ tools: TOOLS,
2875
+ tool: state.tool,
2876
+ snapOn: state.snap.mode !== "off",
2877
+ empty: tracks === 0,
2878
+ drawn: tracks > 0,
2879
+ tracksLabel: state.arrangement ? `${tracks} tracks` : void 0,
2880
+ playheadLabel: formatTick4(state.playheadTick, state.timebase)
2881
+ };
2882
+ }
2883
+ function applyTimelineUi(c, intent) {
2884
+ switch (intent.kind) {
2885
+ case "tool":
2886
+ c.setTool(intent.tool);
2887
+ break;
2888
+ case "snap":
2889
+ c.setSnapMode(intent.on ? "both" : "off");
2890
+ break;
2891
+ case "fit":
2892
+ c.zoomToFitRange();
2893
+ break;
2894
+ }
2895
+ }
2896
+ var timelineViewManifest = {
2897
+ id: timelineManifest.id,
2898
+ version: "1.0.0",
2899
+ title: "Timeline",
2900
+ category: "time",
2901
+ layout: { slot: "bottom" },
2902
+ inputs: [{ id: "view", type: "object", label: "View state", description: "The TimelineViewModel the runtime derives from the controller on every draw." }],
2903
+ outputs: [{ id: "ui", type: "object", label: "UI intent", description: "{ kind, tool?, on? } \u2014 applied by the runtime to the controller." }],
2904
+ commands: []
2905
+ };
2906
+ var EMPTY2 = { tools: TOOLS, tool: "select", snapOn: true, empty: true, drawn: false, playheadLabel: "" };
2907
+ var BEHAVIOURS2 = {
2908
+ "time/timelinePanelView": (inputs) => inputs.view ?? EMPTY2
2909
+ };
2910
+ var text2 = (b) => ({ component: "text", props: { text: b } });
2911
+ var ui2 = (kind, fields = {}) => ({ emit: "ui", value: { object: { kind: { value: kind }, ...fields } } });
2912
+ var TIMELINE_DECLARATION = {
2913
+ format: "xeno.block@1",
2914
+ manifest: timelineViewManifest,
2915
+ behaviour: "time/timelinePanelView",
2916
+ composition: {
2917
+ component: "chrome/Column",
2918
+ children: [
2919
+ {
2920
+ component: "chrome/Toolbar",
2921
+ props: {
2922
+ left: { node: { component: "chrome/SegmentedControl", props: { size: { value: "sm" }, label: { value: "Tool" }, options: { input: "view.tools" }, value: { input: "view.tool" } }, on: { onChange: ui2("tool", { tool: { arg: "" } }) } } },
2923
+ right: {
2924
+ node: {
2925
+ component: "chrome/ToolbarGroup",
2926
+ props: { end: { value: true } },
2927
+ children: [
2928
+ { component: "chrome/FilterChip", props: { on: { input: "view.snapOn" }, title: { value: "Snapping" } }, children: [text2({ value: "Snap" })], on: { onChange: ui2("snap", { on: { arg: "" } }) } },
2929
+ { component: "chrome/TextButton", children: [text2({ value: "Fit" })], on: { onClick: ui2("fit") } }
2930
+ ]
2931
+ }
2932
+ }
2933
+ }
2934
+ },
2935
+ { component: "chrome/EmptyState", when: { input: "view.empty" }, props: { title: { value: "No arrangement" }, hint: { value: "Wire a host arrangement into this panel's input." } } },
2936
+ { component: "timeline/Surface", when: { input: "view.drawn" } },
2937
+ {
2938
+ component: "chrome/StatusBar",
2939
+ props: {
2940
+ left: { node: { component: "chrome/Text", when: { input: "view.tracksLabel" }, props: { role: { value: "number" } }, children: [text2({ input: "view.tracksLabel" })] } },
2941
+ right: { node: { component: "chrome/Text", props: { role: { value: "number" } }, children: [text2({ input: "view.playheadLabel" })] } }
2942
+ }
2943
+ }
2944
+ ]
2945
+ }
2946
+ };
2947
+
2948
+ // src/time/timeline/react/TimelinePanelView.tsx
2949
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
2950
+ var RULER_PX = 22;
2951
+ function TimelinePanelView({ controller, ...options }) {
2952
+ useSyncExternalStore2(controller.subscribe, controller.getState, controller.getState);
2953
+ const view = timelineViewState(controller, options);
2954
+ const ui4 = (intent) => applyTimelineUi(controller, intent);
2955
+ return /* @__PURE__ */ jsxs2(Column2, { children: [
2956
+ /* @__PURE__ */ jsx2(
2957
+ Toolbar,
2958
+ {
2959
+ left: /* @__PURE__ */ jsx2(SegmentedControl, { size: "sm", label: "Tool", options: view.tools, value: view.tool, onChange: (tool) => ui4({ kind: "tool", tool }) }),
2960
+ right: /* @__PURE__ */ jsxs2(ToolbarGroup, { end: true, children: [
2961
+ /* @__PURE__ */ jsx2(FilterChip, { on: view.snapOn, title: "Snapping", onChange: (on) => ui4({ kind: "snap", on }), children: "Snap" }),
2962
+ /* @__PURE__ */ jsx2(TextButton2, { onClick: () => ui4({ kind: "fit" }), children: "Fit" })
2963
+ ] })
2964
+ }
2965
+ ),
2966
+ view.empty ? /* @__PURE__ */ jsx2(EmptyState, { title: "No arrangement", hint: "Wire a host arrangement into this panel's input." }) : null,
2967
+ view.drawn ? /* @__PURE__ */ jsx2(TimelineSurface, { controller }) : null,
2968
+ /* @__PURE__ */ jsx2(StatusBar, { left: view.tracksLabel ? /* @__PURE__ */ jsx2(Text, { role: "number", children: view.tracksLabel }) : null, right: /* @__PURE__ */ jsx2(Text, { role: "number", children: view.playheadLabel }) })
2969
+ ] });
2970
+ }
2971
+ function TimelineSurface({ controller }) {
2871
2972
  const state = useSyncExternalStore2(controller.subscribe, controller.getState, controller.getState);
2872
2973
  const containerRef = useRef2(null);
2873
2974
  useEffect2(() => {
@@ -2875,7 +2976,7 @@ function TimelinePanelView({ controller }) {
2875
2976
  if (!el) return;
2876
2977
  const measure = () => {
2877
2978
  const rect = el.getBoundingClientRect();
2878
- controller.resize(rect.width, rect.height);
2979
+ if (rect.width > 0 && rect.height > 0) controller.resize(rect.width, rect.height);
2879
2980
  };
2880
2981
  measure();
2881
2982
  if (typeof ResizeObserver === "undefined") return;
@@ -2967,117 +3068,74 @@ function TimelinePanelView({ controller }) {
2967
3068
  const ticks = state.arrangement ? rulerTicks(scale, state.timebase) : [];
2968
3069
  const selected = new Set(state.selection.clipIds);
2969
3070
  const preview = state.preview;
2970
- return /* @__PURE__ */ jsxs2("div", { style: SHELL, children: [
2971
- /* @__PURE__ */ jsx2(
2972
- Toolbar,
2973
- {
2974
- left: /* @__PURE__ */ jsx2(ToolbarGroup, { children: TOOLS.map((tool) => /* @__PURE__ */ jsx2(
2975
- "button",
3071
+ return /* @__PURE__ */ jsxs2(
3072
+ DrawnSurface,
3073
+ {
3074
+ ref: containerRef,
3075
+ label: "Timeline",
3076
+ onWheel,
3077
+ onPointerDown,
3078
+ onPointerMove,
3079
+ onPointerUp,
3080
+ onPointerCancel: onPointerUp,
3081
+ onKeyDown,
3082
+ children: [
3083
+ /* @__PURE__ */ jsx2("div", { style: { ...RULER, height: RULER_PX }, children: ticks.map((tick) => /* @__PURE__ */ jsx2(
3084
+ "div",
2976
3085
  {
2977
- type: "button",
2978
- title: `${tool.label} (${tool.key})`,
2979
- "aria-pressed": state.tool === tool.id,
2980
- onClick: () => controller.setTool(tool.id),
2981
- style: toolButton(state.tool === tool.id),
2982
- children: tool.label
3086
+ style: {
3087
+ position: "absolute",
3088
+ left: Math.floor(tick.x),
3089
+ bottom: 0,
3090
+ width: 1,
3091
+ height: tick.weight === "major" ? 8 : tick.weight === "medium" ? 5 : 3,
3092
+ background: "var(--xeno-active)"
3093
+ },
3094
+ children: tick.label ? /* @__PURE__ */ jsx2("span", { style: TICK_LABEL, className: "tabular-nums", children: tick.label }) : null
2983
3095
  },
2984
- tool.id
3096
+ tick.tick
2985
3097
  )) }),
2986
- right: /* @__PURE__ */ jsxs2(ToolbarGroup, { end: true, children: [
2987
- /* @__PURE__ */ jsx2(
2988
- "button",
2989
- {
2990
- type: "button",
2991
- title: "Snapping",
2992
- "aria-pressed": state.snap.mode !== "off",
2993
- onClick: () => controller.setSnapMode(state.snap.mode === "off" ? "both" : "off"),
2994
- style: toolButton(state.snap.mode !== "off"),
2995
- children: "Snap"
2996
- }
2997
- ),
2998
- /* @__PURE__ */ jsx2("button", { type: "button", title: "Zoom to fit", onClick: () => controller.zoomToFitRange(), style: toolButton(false), children: "Fit" })
2999
- ] })
3000
- }
3001
- ),
3002
- !state.arrangement || state.arrangement.tracks.length === 0 ? /* @__PURE__ */ jsx2(EmptyState, { title: "No arrangement", hint: "Wire a host arrangement into this panel's input." }) : /* @__PURE__ */ jsxs2(
3003
- "div",
3004
- {
3005
- ref: containerRef,
3006
- tabIndex: 0,
3007
- role: "application",
3008
- "aria-label": "Timeline",
3009
- style: SURFACE,
3010
- onWheel,
3011
- onPointerDown,
3012
- onPointerMove,
3013
- onPointerUp,
3014
- onPointerCancel: onPointerUp,
3015
- onKeyDown,
3016
- children: [
3017
- /* @__PURE__ */ jsx2("div", { style: { ...RULER, height: RULER_PX }, children: ticks.map((tick) => /* @__PURE__ */ jsx2(
3098
+ /* @__PURE__ */ jsxs2("div", { style: { position: "absolute", inset: `${RULER_PX}px 0 0 0`, overflow: "hidden" }, children: [
3099
+ state.visible.map((row) => {
3100
+ const top = row.topPx - scale.scrollTopPx;
3101
+ return /* @__PURE__ */ jsxs2("div", { style: { position: "absolute", left: 0, right: 0, top, height: row.heightPx }, children: [
3102
+ /* @__PURE__ */ jsx2("div", { style: { ...GUTTER, width: scale.gutterPx }, children: /* @__PURE__ */ jsx2("span", { style: TRACK_NAME, children: row.track.name }) }),
3103
+ /* @__PURE__ */ jsx2("div", { "data-canvas": "timeline-lane", style: { ...LANE, left: scale.gutterPx }, children: row.clips.map((clip) => {
3104
+ const shown = preview?.clips[clip.id] ?? clip;
3105
+ const x = scale.tickToX(shown.startTick);
3106
+ const width = Math.max(1, scale.durationToPx(shown.endTick - shown.startTick));
3107
+ return /* @__PURE__ */ jsx2(
3108
+ ClipRect,
3109
+ {
3110
+ clip,
3111
+ left: x - scale.gutterPx,
3112
+ width,
3113
+ selected: selected.has(clip.id)
3114
+ },
3115
+ clip.id
3116
+ );
3117
+ }) })
3118
+ ] }, row.track.id);
3119
+ }),
3120
+ preview?.marquee ? /* @__PURE__ */ jsx2(
3018
3121
  "div",
3019
3122
  {
3020
3123
  style: {
3021
- position: "absolute",
3022
- left: Math.floor(tick.x),
3023
- bottom: 0,
3024
- width: 1,
3025
- height: tick.weight === "major" ? 8 : tick.weight === "medium" ? 5 : 3,
3026
- background: "var(--xeno-active)"
3027
- },
3028
- children: tick.label ? /* @__PURE__ */ jsx2("span", { style: TICK_LABEL, className: "tabular-nums", children: tick.label }) : null
3029
- },
3030
- tick.tick
3031
- )) }),
3032
- /* @__PURE__ */ jsxs2("div", { style: { position: "absolute", inset: `${RULER_PX}px 0 0 0`, overflow: "hidden" }, children: [
3033
- state.visible.map((row) => {
3034
- const top = row.topPx - scale.scrollTopPx;
3035
- return /* @__PURE__ */ jsxs2("div", { style: { position: "absolute", left: 0, right: 0, top, height: row.heightPx }, children: [
3036
- /* @__PURE__ */ jsx2("div", { style: { ...GUTTER, width: scale.gutterPx }, children: /* @__PURE__ */ jsx2("span", { style: TRACK_NAME, children: row.track.name }) }),
3037
- /* @__PURE__ */ jsx2("div", { "data-canvas": "timeline-lane", style: { ...LANE, left: scale.gutterPx }, children: row.clips.map((clip) => {
3038
- const shown = preview?.clips[clip.id] ?? clip;
3039
- const x = scale.tickToX(shown.startTick);
3040
- const width = Math.max(1, scale.durationToPx(shown.endTick - shown.startTick));
3041
- return /* @__PURE__ */ jsx2(
3042
- ClipRect,
3043
- {
3044
- clip,
3045
- left: x - scale.gutterPx,
3046
- width,
3047
- selected: selected.has(clip.id)
3048
- },
3049
- clip.id
3050
- );
3051
- }) })
3052
- ] }, row.track.id);
3053
- }),
3054
- preview?.marquee ? /* @__PURE__ */ jsx2(
3055
- "div",
3056
- {
3057
- style: {
3058
- ...MARQUEE,
3059
- left: Math.min(scale.tickToX(preview.marquee.fromTick), scale.tickToX(preview.marquee.toTick)),
3060
- width: Math.abs(
3061
- scale.tickToX(preview.marquee.toTick) - scale.tickToX(preview.marquee.fromTick)
3062
- ),
3063
- top: Math.min(preview.marquee.fromY, preview.marquee.toY) - scale.scrollTopPx,
3064
- height: Math.abs(preview.marquee.toY - preview.marquee.fromY)
3065
- }
3124
+ ...MARQUEE,
3125
+ left: Math.min(scale.tickToX(preview.marquee.fromTick), scale.tickToX(preview.marquee.toTick)),
3126
+ width: Math.abs(
3127
+ scale.tickToX(preview.marquee.toTick) - scale.tickToX(preview.marquee.fromTick)
3128
+ ),
3129
+ top: Math.min(preview.marquee.fromY, preview.marquee.toY) - scale.scrollTopPx,
3130
+ height: Math.abs(preview.marquee.toY - preview.marquee.fromY)
3066
3131
  }
3067
- ) : null
3068
- ] }),
3069
- /* @__PURE__ */ jsx2("div", { style: { ...PLAYHEAD, left: Math.floor(scale.tickToX(state.playheadTick)) } })
3070
- ]
3071
- }
3072
- ),
3073
- /* @__PURE__ */ jsx2(
3074
- StatusBar,
3075
- {
3076
- left: state.arrangement ? `${state.arrangement.tracks.length} tracks` : void 0,
3077
- right: /* @__PURE__ */ jsx2("span", { className: "tabular-nums", children: formatTick4(state.playheadTick, state.timebase) })
3078
- }
3079
- )
3080
- ] });
3132
+ }
3133
+ ) : null
3134
+ ] }),
3135
+ /* @__PURE__ */ jsx2("div", { style: { ...PLAYHEAD, left: Math.floor(scale.tickToX(state.playheadTick)) } })
3136
+ ]
3137
+ }
3138
+ );
3081
3139
  }
3082
3140
  function ClipRect({
3083
3141
  clip,
@@ -3136,16 +3194,6 @@ function hitTest(state, x, y) {
3136
3194
  }
3137
3195
  return { target: { kind: "lane" }, trackIndex: -1 };
3138
3196
  }
3139
- var SHELL = { display: "flex", flexDirection: "column", height: "100%", minHeight: 0 };
3140
- var SURFACE = {
3141
- position: "relative",
3142
- flex: 1,
3143
- minHeight: 0,
3144
- overflow: "hidden",
3145
- outline: "none",
3146
- userSelect: "none",
3147
- touchAction: "none"
3148
- };
3149
3197
  var RULER = {
3150
3198
  position: "absolute",
3151
3199
  top: 0,
@@ -3201,18 +3249,9 @@ var PLAYHEAD = {
3201
3249
  background: "var(--xeno-text)",
3202
3250
  pointerEvents: "none"
3203
3251
  };
3204
- function toolButton(active) {
3205
- return {
3206
- height: 18,
3207
- padding: "0 6px",
3208
- fontSize: 10,
3209
- // Rectangles with a corner radius. No colour, no gradient, no shadow.
3210
- borderRadius: 2,
3211
- border: `1px solid ${active ? "var(--xeno-active)" : "var(--xeno-control)"}`,
3212
- background: active ? "var(--xeno-control)" : "transparent",
3213
- color: `${active ? "var(--xeno-text)" : "var(--xeno-muted)"}`,
3214
- cursor: "pointer"
3215
- };
3252
+ var TIMELINE_RUNTIME_UNITS = ["timeline/Surface"];
3253
+ function timelineRuntimeComponents(controller) {
3254
+ return { "timeline/Surface": () => /* @__PURE__ */ jsx2(TimelineSurface, { controller }) };
3216
3255
  }
3217
3256
 
3218
3257
  // src/time/timeline/panel.ts
@@ -3434,10 +3473,10 @@ function gridStart(monthKey, firstDayOfWeek) {
3434
3473
  return addDays(first, -offset);
3435
3474
  }
3436
3475
  function statusTone(value) {
3437
- const text3 = String(value ?? "").toLowerCase();
3438
- if (/done|complete|published|paid|ok/.test(text3)) return "success";
3439
- if (/pending|draft|scheduled|review/.test(text3)) return "warning";
3440
- if (/fail|error|cancel|reject|overdue/.test(text3)) return "error";
3476
+ const text4 = String(value ?? "").toLowerCase();
3477
+ if (/done|complete|published|paid|ok/.test(text4)) return "success";
3478
+ if (/pending|draft|scheduled|review/.test(text4)) return "warning";
3479
+ if (/fail|error|cancel|reject|overdue/.test(text4)) return "error";
3441
3480
  return "neutral";
3442
3481
  }
3443
3482
  function columnMap(result) {
@@ -4110,7 +4149,7 @@ import { useSyncExternalStore as useSyncExternalStore3 } from "react";
4110
4149
  import {
4111
4150
  Badge,
4112
4151
  CalendarGrid,
4113
- Column as Column2,
4152
+ Column as Column3,
4114
4153
  DayCell,
4115
4154
  EmptyState as EmptyState2,
4116
4155
  ErrorState,
@@ -4119,10 +4158,10 @@ import {
4119
4158
  Row,
4120
4159
  RowList,
4121
4160
  ScrollArea,
4122
- SegmentedControl,
4161
+ SegmentedControl as SegmentedControl2,
4123
4162
  StatusBar as StatusBar2,
4124
- Text,
4125
- TextButton as TextButton2,
4163
+ Text as Text2,
4164
+ TextButton as TextButton3,
4126
4165
  Toolbar as Toolbar2,
4127
4166
  ToolbarGroup as ToolbarGroup2,
4128
4167
  WeekdayRow
@@ -4234,7 +4273,7 @@ var calendarViewManifest = {
4234
4273
  outputs: [{ id: "ui", type: "object", label: "UI intent", description: "{ kind, \u2026 } \u2014 applied by the runtime to the controller." }],
4235
4274
  commands: []
4236
4275
  };
4237
- var EMPTY2 = {
4276
+ var EMPTY3 = {
4238
4277
  anchor: "",
4239
4278
  partial: false,
4240
4279
  timeZone: "UTC",
@@ -4254,12 +4293,12 @@ var EMPTY2 = {
4254
4293
  rows: [],
4255
4294
  countLabel: "0 events"
4256
4295
  };
4257
- var BEHAVIOURS2 = {
4258
- "time/calendarPanelView": (inputs) => inputs.view ?? EMPTY2
4296
+ var BEHAVIOURS3 = {
4297
+ "time/calendarPanelView": (inputs) => inputs.view ?? EMPTY3
4259
4298
  };
4260
4299
  var CALENDAR_RUNTIME_UNITS = [];
4261
- var text2 = (b) => ({ component: "text", props: { text: b } });
4262
- var ui2 = (kind, fields = {}) => ({ emit: "ui", value: { object: { kind: { value: kind }, ...fields } } });
4300
+ var text3 = (b) => ({ component: "text", props: { text: b } });
4301
+ var ui3 = (kind, fields = {}) => ({ emit: "ui", value: { object: { kind: { value: kind }, ...fields } } });
4263
4302
  var CALENDAR_DECLARATION = {
4264
4303
  format: "xeno.block@1",
4265
4304
  manifest: calendarViewManifest,
@@ -4274,10 +4313,10 @@ var CALENDAR_DECLARATION = {
4274
4313
  node: {
4275
4314
  component: "fragment",
4276
4315
  children: [
4277
- { component: "chrome/IconButton", props: { icon: { node: { component: "icons/Chevron", props: { direction: { value: "left" } } } }, label: { value: "Previous" } }, on: { onClick: ui2("navigate", { direction: { value: -1 } }) } },
4278
- { component: "chrome/IconButton", props: { icon: { node: { component: "icons/Chevron", props: { direction: { value: "right" } } } }, label: { value: "Next" } }, on: { onClick: ui2("navigate", { direction: { value: 1 } }) } },
4279
- { component: "chrome/TextButton", on: { onClick: ui2("today") }, children: [text2({ value: "Today" })] },
4280
- { component: "chrome/Text", props: { role: { value: "meta" } }, children: [text2({ input: "view.anchor" })] }
4316
+ { component: "chrome/IconButton", props: { icon: { node: { component: "icons/Chevron", props: { direction: { value: "left" } } } }, label: { value: "Previous" } }, on: { onClick: ui3("navigate", { direction: { value: -1 } }) } },
4317
+ { component: "chrome/IconButton", props: { icon: { node: { component: "icons/Chevron", props: { direction: { value: "right" } } } }, label: { value: "Next" } }, on: { onClick: ui3("navigate", { direction: { value: 1 } }) } },
4318
+ { component: "chrome/TextButton", on: { onClick: ui3("today") }, children: [text3({ value: "Today" })] },
4319
+ { component: "chrome/Text", props: { role: { value: "meta" } }, children: [text3({ input: "view.anchor" })] }
4281
4320
  ]
4282
4321
  }
4283
4322
  },
@@ -4286,9 +4325,9 @@ var CALENDAR_DECLARATION = {
4286
4325
  component: "chrome/ToolbarGroup",
4287
4326
  props: { end: { value: true } },
4288
4327
  children: [
4289
- { component: "chrome/Badge", when: { input: "view.partial" }, props: { tone: { value: "warning" }, title: { value: "Some measures have not finished syncing." } }, children: [text2({ value: "partial" })] },
4290
- { component: "chrome/Badge", props: { title: { value: "Every date is bucketed in this zone." } }, children: [text2({ input: "view.timeZone" })] },
4291
- { component: "chrome/SegmentedControl", props: { size: { value: "sm" }, label: { value: "View" }, options: { input: "view.modes" }, value: { input: "view.viewMode" } }, on: { onChange: ui2("mode", { mode: { arg: "" } }) } }
4328
+ { component: "chrome/Badge", when: { input: "view.partial" }, props: { tone: { value: "warning" }, title: { value: "Some measures have not finished syncing." } }, children: [text3({ value: "partial" })] },
4329
+ { component: "chrome/Badge", props: { title: { value: "Every date is bucketed in this zone." } }, children: [text3({ input: "view.timeZone" })] },
4330
+ { component: "chrome/SegmentedControl", props: { size: { value: "sm" }, label: { value: "View" }, options: { input: "view.modes" }, value: { input: "view.viewMode" } }, on: { onChange: ui3("mode", { mode: { arg: "" } }) } }
4292
4331
  ]
4293
4332
  }
4294
4333
  }
@@ -4308,8 +4347,8 @@ var CALENDAR_DECLARATION = {
4308
4347
  {
4309
4348
  component: "chrome/Row",
4310
4349
  each: { input: "view.rows", key: "id" },
4311
- props: { label: { item: "title" }, meta: { item: "meta" }, selected: { item: "selected" }, trailing: { node: { component: "chrome/Badge", when: { item: "status" }, props: { tone: { item: "tone" } }, children: [text2({ item: "status" })] } } },
4312
- on: { onClick: ui2("select", { id: { item: "id" } }), onDoubleClick: ui2("activateRow", { id: { item: "id" } }) }
4350
+ props: { label: { item: "title" }, meta: { item: "meta" }, selected: { item: "selected" }, trailing: { node: { component: "chrome/Badge", when: { item: "status" }, props: { tone: { item: "tone" } }, children: [text3({ item: "status" })] } } },
4351
+ on: { onClick: ui3("select", { id: { item: "id" } }), onDoubleClick: ui3("activateRow", { id: { item: "id" } }) }
4313
4352
  }
4314
4353
  ]
4315
4354
  }
@@ -4328,18 +4367,18 @@ var CALENDAR_DECLARATION = {
4328
4367
  component: "chrome/DayCell",
4329
4368
  each: { input: "view.cells", key: "key" },
4330
4369
  props: { day: { item: "day" }, label: { item: "label" }, today: { item: "today" }, outside: { item: "outside" }, tabStop: { item: "tabStop" }, overflow: { item: "overflow" } },
4331
- on: { onActivate: ui2("activateSlot", { key: { item: "key" } }) },
4370
+ on: { onActivate: ui3("activateSlot", { key: { item: "key" } }) },
4332
4371
  children: [
4333
4372
  {
4334
4373
  component: "chrome/EventChip",
4335
4374
  each: { item: "chips", key: "id" },
4336
4375
  props: { time: { item: "time" }, selected: { item: "selected" }, title: { item: "tooltip" } },
4337
4376
  on: {
4338
- onClick: ui2("select", { id: { item: "id" }, additive: { arg: "ctrlKey", index: 0 }, meta: { arg: "metaKey", index: 0 } }),
4339
- onDoubleClick: ui2("activateRow", { id: { item: "id" } }),
4340
- onContextMenuAt: ui2("contextMenu", { id: { item: "id" }, x: { arg: "", index: 0 }, y: { arg: "", index: 1 } })
4377
+ onClick: ui3("select", { id: { item: "id" }, additive: { arg: "ctrlKey", index: 0 }, meta: { arg: "metaKey", index: 0 } }),
4378
+ onDoubleClick: ui3("activateRow", { id: { item: "id" } }),
4379
+ onContextMenuAt: ui3("contextMenu", { id: { item: "id" }, x: { arg: "", index: 0 }, y: { arg: "", index: 1 } })
4341
4380
  },
4342
- children: [text2({ item: "title" })]
4381
+ children: [text3({ item: "title" })]
4343
4382
  }
4344
4383
  ]
4345
4384
  }
@@ -4358,21 +4397,21 @@ var Chevron = ICONS["icons/Chevron"];
4358
4397
  function CalendarPanelView({ controller, firstDayOfWeek, emptyHint }) {
4359
4398
  useSyncExternalStore3(controller.subscribe, controller.getState, controller.getState);
4360
4399
  const view = calendarViewState(controller, { firstDayOfWeek, emptyHint });
4361
- const ui3 = (intent) => applyCalendarUi(controller, intent);
4362
- return /* @__PURE__ */ jsxs3(Column2, { children: [
4400
+ const ui4 = (intent) => applyCalendarUi(controller, intent);
4401
+ return /* @__PURE__ */ jsxs3(Column3, { children: [
4363
4402
  /* @__PURE__ */ jsx3(
4364
4403
  Toolbar2,
4365
4404
  {
4366
4405
  left: /* @__PURE__ */ jsxs3(Fragment, { children: [
4367
- /* @__PURE__ */ jsx3(IconButton2, { icon: /* @__PURE__ */ jsx3(Chevron, { direction: "left" }), label: "Previous", onClick: () => ui3({ kind: "navigate", direction: -1 }) }),
4368
- /* @__PURE__ */ jsx3(IconButton2, { icon: /* @__PURE__ */ jsx3(Chevron, { direction: "right" }), label: "Next", onClick: () => ui3({ kind: "navigate", direction: 1 }) }),
4369
- /* @__PURE__ */ jsx3(TextButton2, { onClick: () => ui3({ kind: "today" }), children: "Today" }),
4370
- /* @__PURE__ */ jsx3(Text, { role: "meta", children: view.anchor })
4406
+ /* @__PURE__ */ jsx3(IconButton2, { icon: /* @__PURE__ */ jsx3(Chevron, { direction: "left" }), label: "Previous", onClick: () => ui4({ kind: "navigate", direction: -1 }) }),
4407
+ /* @__PURE__ */ jsx3(IconButton2, { icon: /* @__PURE__ */ jsx3(Chevron, { direction: "right" }), label: "Next", onClick: () => ui4({ kind: "navigate", direction: 1 }) }),
4408
+ /* @__PURE__ */ jsx3(TextButton3, { onClick: () => ui4({ kind: "today" }), children: "Today" }),
4409
+ /* @__PURE__ */ jsx3(Text2, { role: "meta", children: view.anchor })
4371
4410
  ] }),
4372
4411
  right: /* @__PURE__ */ jsxs3(ToolbarGroup2, { end: true, children: [
4373
4412
  view.partial ? /* @__PURE__ */ jsx3(Badge, { tone: "warning", title: "Some measures have not finished syncing.", children: "partial" }) : null,
4374
4413
  /* @__PURE__ */ jsx3(Badge, { title: "Every date is bucketed in this zone.", children: view.timeZone }),
4375
- /* @__PURE__ */ jsx3(SegmentedControl, { size: "sm", label: "View", options: view.modes, value: view.viewMode, onChange: (mode) => ui3({ kind: "mode", mode }) })
4414
+ /* @__PURE__ */ jsx3(SegmentedControl2, { size: "sm", label: "View", options: view.modes, value: view.viewMode, onChange: (mode) => ui4({ kind: "mode", mode }) })
4376
4415
  ] })
4377
4416
  }
4378
4417
  ),
@@ -4386,22 +4425,22 @@ function CalendarPanelView({ controller, firstDayOfWeek, emptyHint }) {
4386
4425
  meta: row.meta,
4387
4426
  selected: row.selected,
4388
4427
  trailing: row.status ? /* @__PURE__ */ jsx3(Badge, { tone: row.tone, children: row.status }) : null,
4389
- onClick: () => ui3({ kind: "select", id: row.id }),
4390
- onDoubleClick: () => ui3({ kind: "activateRow", id: row.id })
4428
+ onClick: () => ui4({ kind: "select", id: row.id }),
4429
+ onDoubleClick: () => ui4({ kind: "activateRow", id: row.id })
4391
4430
  },
4392
4431
  row.id
4393
4432
  )) }) }) : null,
4394
4433
  view.grid ? /* @__PURE__ */ jsx3(ScrollArea, { children: /* @__PURE__ */ jsxs3(CalendarGrid, { columns: view.columns, label: view.gridLabel, children: [
4395
4434
  view.weekHeaded ? /* @__PURE__ */ jsx3(WeekdayRow, { days: view.weekdays }) : null,
4396
- view.cells.map((cell) => /* @__PURE__ */ jsx3(DayCell, { day: cell.day, label: cell.label, today: cell.today, outside: cell.outside, tabStop: cell.tabStop, overflow: cell.overflow, onActivate: () => ui3({ kind: "activateSlot", key: cell.key }), children: cell.chips.map((chip) => /* @__PURE__ */ jsx3(
4435
+ view.cells.map((cell) => /* @__PURE__ */ jsx3(DayCell, { day: cell.day, label: cell.label, today: cell.today, outside: cell.outside, tabStop: cell.tabStop, overflow: cell.overflow, onActivate: () => ui4({ kind: "activateSlot", key: cell.key }), children: cell.chips.map((chip) => /* @__PURE__ */ jsx3(
4397
4436
  EventChip,
4398
4437
  {
4399
4438
  time: chip.time,
4400
4439
  selected: chip.selected,
4401
4440
  title: chip.tooltip,
4402
- onClick: (e) => ui3({ kind: "select", id: chip.id, additive: e.ctrlKey, meta: e.metaKey }),
4403
- onDoubleClick: () => ui3({ kind: "activateRow", id: chip.id }),
4404
- onContextMenuAt: (x, y) => ui3({ kind: "contextMenu", id: chip.id, x, y }),
4441
+ onClick: (e) => ui4({ kind: "select", id: chip.id, additive: e.ctrlKey, meta: e.metaKey }),
4442
+ onDoubleClick: () => ui4({ kind: "activateRow", id: chip.id }),
4443
+ onContextMenuAt: (x, y) => ui4({ kind: "contextMenu", id: chip.id, x, y }),
4405
4444
  children: chip.title
4406
4445
  },
4407
4446
  chip.id
@@ -4570,7 +4609,7 @@ var export_wrapIntoLoop = clock_exports.wrapIntoLoop;
4570
4609
  export {
4571
4610
  ALL_CALENDAR_MODES,
4572
4611
  export_BAR_SUBDIVISION as BAR_SUBDIVISION,
4573
- BEHAVIOURS2 as CALENDAR_BEHAVIOURS,
4612
+ BEHAVIOURS3 as CALENDAR_BEHAVIOURS,
4574
4613
  CALENDAR_DECLARATION,
4575
4614
  CALENDAR_PANEL_ID,
4576
4615
  CALENDAR_RUNTIME_UNITS,
@@ -4586,7 +4625,10 @@ export {
4586
4625
  export_IDLE_CLOCK as IDLE_CLOCK,
4587
4626
  MIN_MAJOR_PX,
4588
4627
  MIN_MINOR_PX,
4628
+ BEHAVIOURS2 as TIMELINE_BEHAVIOURS,
4629
+ TIMELINE_DECLARATION,
4589
4630
  TIMELINE_PANEL_ID,
4631
+ TIMELINE_RUNTIME_UNITS,
4590
4632
  BEHAVIOURS as TRANSPORT_BEHAVIOURS,
4591
4633
  TRANSPORT_DECLARATION,
4592
4634
  TRANSPORT_ICONS,
@@ -4594,6 +4636,7 @@ export {
4594
4636
  TRIM_SNAP_PX,
4595
4637
  TimelineController,
4596
4638
  TimelinePanelView,
4639
+ TimelineSurface,
4597
4640
  TransportPanelController,
4598
4641
  TransportPanelView,
4599
4642
  XenoTileCache,
@@ -4602,6 +4645,7 @@ export {
4602
4645
  addMonths,
4603
4646
  alignToTileGrid,
4604
4647
  applyCalendarUi,
4648
+ applyTimelineUi,
4605
4649
  applyTransportUi,
4606
4650
  beginDrag,
4607
4651
  blitTile,
@@ -4672,6 +4716,9 @@ export {
4672
4716
  tileWidthTicks,
4673
4717
  timelineManifest,
4674
4718
  timelinePanel,
4719
+ timelineRuntimeComponents,
4720
+ timelineViewManifest,
4721
+ timelineViewState,
4675
4722
  export_toTick as toTick,
4676
4723
  todayKey,
4677
4724
  transportManifest,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xenosystem/blocks",
3
- "version": "0.13.30",
3
+ "version": "0.13.32",
4
4
  "description": "XENO Blocks — rung 3 of the front ladder: components composed into a contract-bearing unit (manifest: ports, intents, commands, agent surface), rendered by @xenosystem/workbench. ONE package, one subpath per family (/auth, /edit, /data, /time, /ops, /trust, /agent), one named export per block — XENO PACKAGE NAMING - STANDARD.md.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -64,7 +64,7 @@
64
64
  "peerDependencies": {
65
65
  "@duckdb/duckdb-wasm": ">=1.28.0",
66
66
  "@xenosystem/block-sdk": ">=0.3.4 <1",
67
- "@xenosystem/components": ">=0.31.0 <1",
67
+ "@xenosystem/components": ">=0.32.0 <1",
68
68
  "@xenosystem/data-core": "^0.1.0",
69
69
  "@xenosystem/elements": ">=0.0.1",
70
70
  "@xenosystem/elements-react": ">=0.0.1",
@@ -81,7 +81,7 @@
81
81
  "@types/react": "^19.0.0",
82
82
  "@types/react-dom": "^19.0.0",
83
83
  "@xenosystem/block-sdk": "^0.3.4",
84
- "@xenosystem/components": "^0.31.0",
84
+ "@xenosystem/components": "^0.32.0",
85
85
  "@xenosystem/data-core": "^0.1.0",
86
86
  "@xenosystem/elements": "0.0.1",
87
87
  "@xenosystem/elements-react": "0.0.1",