@xenosystem/blocks 0.13.29 → 0.13.31

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.
@@ -1983,7 +1983,7 @@ declare const terminalManifest: PanelManifest;
1983
1983
  /**
1984
1984
  * The Terminal panel AS A DECLARATION — the twenty-fifth block written the §8d way, the fourth
1985
1985
  * DRAWN surface. The CHROME is data: the session strip (a `chrome/TabStrip` of `Tab`s — title, a
1986
- * status chip, a close action), the new-terminal and find actions, the find bar, the empty states,
1986
+ * status chip, a pointer-only close whose keyboard path is Delete on the strip), the new-terminal and find actions, the find bar, the empty states,
1987
1987
  * the cwd and size readouts. The SURFACES are one runtime unit (`terminal/Surfaces`) bound to the
1988
1988
  * controller and the host's emulator factory: one bare `<div>` per session that the emulator owns
1989
1989
  * outright — hidden, never unmounted, when another tab is active, so the on-screen buffer survives.
package/dist/ops/index.js CHANGED
@@ -2775,7 +2775,7 @@ var TERMINAL_DECLARATION = {
2775
2775
  node: {
2776
2776
  component: "chrome/TabStrip",
2777
2777
  props: { label: { value: "Terminals" }, value: { input: "view.activeId" }, ids: { input: "view.tabIds" } },
2778
- on: { onChange: ui3("activate", { id: { arg: "" } }) },
2778
+ on: { onChange: ui3("activate", { id: { arg: "" } }), onClose: ui3("close", { id: { arg: "" } }) },
2779
2779
  children: [
2780
2780
  {
2781
2781
  component: "chrome/Tab",
@@ -2891,7 +2891,7 @@ function TerminalPanelView({ controller, createEmulator, multiInstance = true })
2891
2891
  view.stripShown ? /* @__PURE__ */ jsx3(
2892
2892
  Toolbar3,
2893
2893
  {
2894
- left: /* @__PURE__ */ jsx3(TabStrip, { label: "Terminals", value: view.activeId, ids: view.tabIds, onChange: (id) => ui5({ kind: "activate", id }), children: view.tabs.map((t) => /* @__PURE__ */ jsx3(Tab, { selected: t.selected, closeLabel: t.closeLabel, closeIcon: /* @__PURE__ */ jsx3(XGlyph, {}), chip: t.chip ? /* @__PURE__ */ jsx3(Badge3, { tone: t.chipTone, children: t.chip }) : null, onSelect: () => ui5({ kind: "activate", id: t.id }), onClose: () => ui5({ kind: "close", id: t.id }), children: t.title }, t.key)) }),
2894
+ left: /* @__PURE__ */ jsx3(TabStrip, { label: "Terminals", value: view.activeId, ids: view.tabIds, onChange: (id) => ui5({ kind: "activate", id }), onClose: (id) => ui5({ kind: "close", id }), children: view.tabs.map((t) => /* @__PURE__ */ jsx3(Tab, { selected: t.selected, closeLabel: t.closeLabel, closeIcon: /* @__PURE__ */ jsx3(XGlyph, {}), chip: t.chip ? /* @__PURE__ */ jsx3(Badge3, { tone: t.chipTone, children: t.chip }) : null, onSelect: () => ui5({ kind: "activate", id: t.id }), onClose: () => ui5({ kind: "close", id: t.id }), children: t.title }, t.key)) }),
2895
2895
  right: /* @__PURE__ */ jsxs3(ToolbarGroup3, { end: true, children: [
2896
2896
  /* @__PURE__ */ jsx3(IconButton3, { label: "New terminal", icon: /* @__PURE__ */ jsx3(PlusGlyph, {}), onClick: () => ui5({ kind: "open" }) }),
2897
2897
  /* @__PURE__ */ jsx3(TextButton2, { onClick: () => ui5({ kind: "toggleFind" }), children: "Find" })
@@ -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, 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,77 @@ 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
+ "div",
3073
+ {
3074
+ ref: containerRef,
3075
+ tabIndex: 0,
3076
+ role: "application",
3077
+ "aria-label": "Timeline",
3078
+ style: SURFACE,
3079
+ onWheel,
3080
+ onPointerDown,
3081
+ onPointerMove,
3082
+ onPointerUp,
3083
+ onPointerCancel: onPointerUp,
3084
+ onKeyDown,
3085
+ children: [
3086
+ /* @__PURE__ */ jsx2("div", { style: { ...RULER, height: RULER_PX }, children: ticks.map((tick) => /* @__PURE__ */ jsx2(
3087
+ "div",
2976
3088
  {
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
3089
+ style: {
3090
+ position: "absolute",
3091
+ left: Math.floor(tick.x),
3092
+ bottom: 0,
3093
+ width: 1,
3094
+ height: tick.weight === "major" ? 8 : tick.weight === "medium" ? 5 : 3,
3095
+ background: "var(--xeno-active)"
3096
+ },
3097
+ children: tick.label ? /* @__PURE__ */ jsx2("span", { style: TICK_LABEL, className: "tabular-nums", children: tick.label }) : null
2983
3098
  },
2984
- tool.id
3099
+ tick.tick
2985
3100
  )) }),
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(
3101
+ /* @__PURE__ */ jsxs2("div", { style: { position: "absolute", inset: `${RULER_PX}px 0 0 0`, overflow: "hidden" }, children: [
3102
+ state.visible.map((row) => {
3103
+ const top = row.topPx - scale.scrollTopPx;
3104
+ return /* @__PURE__ */ jsxs2("div", { style: { position: "absolute", left: 0, right: 0, top, height: row.heightPx }, children: [
3105
+ /* @__PURE__ */ jsx2("div", { style: { ...GUTTER, width: scale.gutterPx }, children: /* @__PURE__ */ jsx2("span", { style: TRACK_NAME, children: row.track.name }) }),
3106
+ /* @__PURE__ */ jsx2("div", { "data-canvas": "timeline-lane", style: { ...LANE, left: scale.gutterPx }, children: row.clips.map((clip) => {
3107
+ const shown = preview?.clips[clip.id] ?? clip;
3108
+ const x = scale.tickToX(shown.startTick);
3109
+ const width = Math.max(1, scale.durationToPx(shown.endTick - shown.startTick));
3110
+ return /* @__PURE__ */ jsx2(
3111
+ ClipRect,
3112
+ {
3113
+ clip,
3114
+ left: x - scale.gutterPx,
3115
+ width,
3116
+ selected: selected.has(clip.id)
3117
+ },
3118
+ clip.id
3119
+ );
3120
+ }) })
3121
+ ] }, row.track.id);
3122
+ }),
3123
+ preview?.marquee ? /* @__PURE__ */ jsx2(
3018
3124
  "div",
3019
3125
  {
3020
3126
  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
- }
3127
+ ...MARQUEE,
3128
+ left: Math.min(scale.tickToX(preview.marquee.fromTick), scale.tickToX(preview.marquee.toTick)),
3129
+ width: Math.abs(
3130
+ scale.tickToX(preview.marquee.toTick) - scale.tickToX(preview.marquee.fromTick)
3131
+ ),
3132
+ top: Math.min(preview.marquee.fromY, preview.marquee.toY) - scale.scrollTopPx,
3133
+ height: Math.abs(preview.marquee.toY - preview.marquee.fromY)
3066
3134
  }
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
- ] });
3135
+ }
3136
+ ) : null
3137
+ ] }),
3138
+ /* @__PURE__ */ jsx2("div", { style: { ...PLAYHEAD, left: Math.floor(scale.tickToX(state.playheadTick)) } })
3139
+ ]
3140
+ }
3141
+ );
3081
3142
  }
3082
3143
  function ClipRect({
3083
3144
  clip,
@@ -3136,7 +3197,6 @@ function hitTest(state, x, y) {
3136
3197
  }
3137
3198
  return { target: { kind: "lane" }, trackIndex: -1 };
3138
3199
  }
3139
- var SHELL = { display: "flex", flexDirection: "column", height: "100%", minHeight: 0 };
3140
3200
  var SURFACE = {
3141
3201
  position: "relative",
3142
3202
  flex: 1,
@@ -3201,18 +3261,9 @@ var PLAYHEAD = {
3201
3261
  background: "var(--xeno-text)",
3202
3262
  pointerEvents: "none"
3203
3263
  };
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
- };
3264
+ var TIMELINE_RUNTIME_UNITS = ["timeline/Surface"];
3265
+ function timelineRuntimeComponents(controller) {
3266
+ return { "timeline/Surface": () => /* @__PURE__ */ jsx2(TimelineSurface, { controller }) };
3216
3267
  }
3217
3268
 
3218
3269
  // src/time/timeline/panel.ts
@@ -3434,10 +3485,10 @@ function gridStart(monthKey, firstDayOfWeek) {
3434
3485
  return addDays(first, -offset);
3435
3486
  }
3436
3487
  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";
3488
+ const text4 = String(value ?? "").toLowerCase();
3489
+ if (/done|complete|published|paid|ok/.test(text4)) return "success";
3490
+ if (/pending|draft|scheduled|review/.test(text4)) return "warning";
3491
+ if (/fail|error|cancel|reject|overdue/.test(text4)) return "error";
3441
3492
  return "neutral";
3442
3493
  }
3443
3494
  function columnMap(result) {
@@ -4110,7 +4161,7 @@ import { useSyncExternalStore as useSyncExternalStore3 } from "react";
4110
4161
  import {
4111
4162
  Badge,
4112
4163
  CalendarGrid,
4113
- Column as Column2,
4164
+ Column as Column3,
4114
4165
  DayCell,
4115
4166
  EmptyState as EmptyState2,
4116
4167
  ErrorState,
@@ -4119,10 +4170,10 @@ import {
4119
4170
  Row,
4120
4171
  RowList,
4121
4172
  ScrollArea,
4122
- SegmentedControl,
4173
+ SegmentedControl as SegmentedControl2,
4123
4174
  StatusBar as StatusBar2,
4124
- Text,
4125
- TextButton as TextButton2,
4175
+ Text as Text2,
4176
+ TextButton as TextButton3,
4126
4177
  Toolbar as Toolbar2,
4127
4178
  ToolbarGroup as ToolbarGroup2,
4128
4179
  WeekdayRow
@@ -4234,7 +4285,7 @@ var calendarViewManifest = {
4234
4285
  outputs: [{ id: "ui", type: "object", label: "UI intent", description: "{ kind, \u2026 } \u2014 applied by the runtime to the controller." }],
4235
4286
  commands: []
4236
4287
  };
4237
- var EMPTY2 = {
4288
+ var EMPTY3 = {
4238
4289
  anchor: "",
4239
4290
  partial: false,
4240
4291
  timeZone: "UTC",
@@ -4254,12 +4305,12 @@ var EMPTY2 = {
4254
4305
  rows: [],
4255
4306
  countLabel: "0 events"
4256
4307
  };
4257
- var BEHAVIOURS2 = {
4258
- "time/calendarPanelView": (inputs) => inputs.view ?? EMPTY2
4308
+ var BEHAVIOURS3 = {
4309
+ "time/calendarPanelView": (inputs) => inputs.view ?? EMPTY3
4259
4310
  };
4260
4311
  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 } } });
4312
+ var text3 = (b) => ({ component: "text", props: { text: b } });
4313
+ var ui3 = (kind, fields = {}) => ({ emit: "ui", value: { object: { kind: { value: kind }, ...fields } } });
4263
4314
  var CALENDAR_DECLARATION = {
4264
4315
  format: "xeno.block@1",
4265
4316
  manifest: calendarViewManifest,
@@ -4274,10 +4325,10 @@ var CALENDAR_DECLARATION = {
4274
4325
  node: {
4275
4326
  component: "fragment",
4276
4327
  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" })] }
4328
+ { component: "chrome/IconButton", props: { icon: { node: { component: "icons/Chevron", props: { direction: { value: "left" } } } }, label: { value: "Previous" } }, on: { onClick: ui3("navigate", { direction: { value: -1 } }) } },
4329
+ { component: "chrome/IconButton", props: { icon: { node: { component: "icons/Chevron", props: { direction: { value: "right" } } } }, label: { value: "Next" } }, on: { onClick: ui3("navigate", { direction: { value: 1 } }) } },
4330
+ { component: "chrome/TextButton", on: { onClick: ui3("today") }, children: [text3({ value: "Today" })] },
4331
+ { component: "chrome/Text", props: { role: { value: "meta" } }, children: [text3({ input: "view.anchor" })] }
4281
4332
  ]
4282
4333
  }
4283
4334
  },
@@ -4286,9 +4337,9 @@ var CALENDAR_DECLARATION = {
4286
4337
  component: "chrome/ToolbarGroup",
4287
4338
  props: { end: { value: true } },
4288
4339
  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: "" } }) } }
4340
+ { component: "chrome/Badge", when: { input: "view.partial" }, props: { tone: { value: "warning" }, title: { value: "Some measures have not finished syncing." } }, children: [text3({ value: "partial" })] },
4341
+ { component: "chrome/Badge", props: { title: { value: "Every date is bucketed in this zone." } }, children: [text3({ input: "view.timeZone" })] },
4342
+ { 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
4343
  ]
4293
4344
  }
4294
4345
  }
@@ -4308,8 +4359,8 @@ var CALENDAR_DECLARATION = {
4308
4359
  {
4309
4360
  component: "chrome/Row",
4310
4361
  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" } }) }
4362
+ 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" })] } } },
4363
+ on: { onClick: ui3("select", { id: { item: "id" } }), onDoubleClick: ui3("activateRow", { id: { item: "id" } }) }
4313
4364
  }
4314
4365
  ]
4315
4366
  }
@@ -4328,18 +4379,18 @@ var CALENDAR_DECLARATION = {
4328
4379
  component: "chrome/DayCell",
4329
4380
  each: { input: "view.cells", key: "key" },
4330
4381
  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" } }) },
4382
+ on: { onActivate: ui3("activateSlot", { key: { item: "key" } }) },
4332
4383
  children: [
4333
4384
  {
4334
4385
  component: "chrome/EventChip",
4335
4386
  each: { item: "chips", key: "id" },
4336
4387
  props: { time: { item: "time" }, selected: { item: "selected" }, title: { item: "tooltip" } },
4337
4388
  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 } })
4389
+ onClick: ui3("select", { id: { item: "id" }, additive: { arg: "ctrlKey", index: 0 }, meta: { arg: "metaKey", index: 0 } }),
4390
+ onDoubleClick: ui3("activateRow", { id: { item: "id" } }),
4391
+ onContextMenuAt: ui3("contextMenu", { id: { item: "id" }, x: { arg: "", index: 0 }, y: { arg: "", index: 1 } })
4341
4392
  },
4342
- children: [text2({ item: "title" })]
4393
+ children: [text3({ item: "title" })]
4343
4394
  }
4344
4395
  ]
4345
4396
  }
@@ -4358,21 +4409,21 @@ var Chevron = ICONS["icons/Chevron"];
4358
4409
  function CalendarPanelView({ controller, firstDayOfWeek, emptyHint }) {
4359
4410
  useSyncExternalStore3(controller.subscribe, controller.getState, controller.getState);
4360
4411
  const view = calendarViewState(controller, { firstDayOfWeek, emptyHint });
4361
- const ui3 = (intent) => applyCalendarUi(controller, intent);
4362
- return /* @__PURE__ */ jsxs3(Column2, { children: [
4412
+ const ui4 = (intent) => applyCalendarUi(controller, intent);
4413
+ return /* @__PURE__ */ jsxs3(Column3, { children: [
4363
4414
  /* @__PURE__ */ jsx3(
4364
4415
  Toolbar2,
4365
4416
  {
4366
4417
  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 })
4418
+ /* @__PURE__ */ jsx3(IconButton2, { icon: /* @__PURE__ */ jsx3(Chevron, { direction: "left" }), label: "Previous", onClick: () => ui4({ kind: "navigate", direction: -1 }) }),
4419
+ /* @__PURE__ */ jsx3(IconButton2, { icon: /* @__PURE__ */ jsx3(Chevron, { direction: "right" }), label: "Next", onClick: () => ui4({ kind: "navigate", direction: 1 }) }),
4420
+ /* @__PURE__ */ jsx3(TextButton3, { onClick: () => ui4({ kind: "today" }), children: "Today" }),
4421
+ /* @__PURE__ */ jsx3(Text2, { role: "meta", children: view.anchor })
4371
4422
  ] }),
4372
4423
  right: /* @__PURE__ */ jsxs3(ToolbarGroup2, { end: true, children: [
4373
4424
  view.partial ? /* @__PURE__ */ jsx3(Badge, { tone: "warning", title: "Some measures have not finished syncing.", children: "partial" }) : null,
4374
4425
  /* @__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 }) })
4426
+ /* @__PURE__ */ jsx3(SegmentedControl2, { size: "sm", label: "View", options: view.modes, value: view.viewMode, onChange: (mode) => ui4({ kind: "mode", mode }) })
4376
4427
  ] })
4377
4428
  }
4378
4429
  ),
@@ -4386,22 +4437,22 @@ function CalendarPanelView({ controller, firstDayOfWeek, emptyHint }) {
4386
4437
  meta: row.meta,
4387
4438
  selected: row.selected,
4388
4439
  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 })
4440
+ onClick: () => ui4({ kind: "select", id: row.id }),
4441
+ onDoubleClick: () => ui4({ kind: "activateRow", id: row.id })
4391
4442
  },
4392
4443
  row.id
4393
4444
  )) }) }) : null,
4394
4445
  view.grid ? /* @__PURE__ */ jsx3(ScrollArea, { children: /* @__PURE__ */ jsxs3(CalendarGrid, { columns: view.columns, label: view.gridLabel, children: [
4395
4446
  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(
4447
+ 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
4448
  EventChip,
4398
4449
  {
4399
4450
  time: chip.time,
4400
4451
  selected: chip.selected,
4401
4452
  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 }),
4453
+ onClick: (e) => ui4({ kind: "select", id: chip.id, additive: e.ctrlKey, meta: e.metaKey }),
4454
+ onDoubleClick: () => ui4({ kind: "activateRow", id: chip.id }),
4455
+ onContextMenuAt: (x, y) => ui4({ kind: "contextMenu", id: chip.id, x, y }),
4405
4456
  children: chip.title
4406
4457
  },
4407
4458
  chip.id
@@ -4570,7 +4621,7 @@ var export_wrapIntoLoop = clock_exports.wrapIntoLoop;
4570
4621
  export {
4571
4622
  ALL_CALENDAR_MODES,
4572
4623
  export_BAR_SUBDIVISION as BAR_SUBDIVISION,
4573
- BEHAVIOURS2 as CALENDAR_BEHAVIOURS,
4624
+ BEHAVIOURS3 as CALENDAR_BEHAVIOURS,
4574
4625
  CALENDAR_DECLARATION,
4575
4626
  CALENDAR_PANEL_ID,
4576
4627
  CALENDAR_RUNTIME_UNITS,
@@ -4586,7 +4637,10 @@ export {
4586
4637
  export_IDLE_CLOCK as IDLE_CLOCK,
4587
4638
  MIN_MAJOR_PX,
4588
4639
  MIN_MINOR_PX,
4640
+ BEHAVIOURS2 as TIMELINE_BEHAVIOURS,
4641
+ TIMELINE_DECLARATION,
4589
4642
  TIMELINE_PANEL_ID,
4643
+ TIMELINE_RUNTIME_UNITS,
4590
4644
  BEHAVIOURS as TRANSPORT_BEHAVIOURS,
4591
4645
  TRANSPORT_DECLARATION,
4592
4646
  TRANSPORT_ICONS,
@@ -4594,6 +4648,7 @@ export {
4594
4648
  TRIM_SNAP_PX,
4595
4649
  TimelineController,
4596
4650
  TimelinePanelView,
4651
+ TimelineSurface,
4597
4652
  TransportPanelController,
4598
4653
  TransportPanelView,
4599
4654
  XenoTileCache,
@@ -4602,6 +4657,7 @@ export {
4602
4657
  addMonths,
4603
4658
  alignToTileGrid,
4604
4659
  applyCalendarUi,
4660
+ applyTimelineUi,
4605
4661
  applyTransportUi,
4606
4662
  beginDrag,
4607
4663
  blitTile,
@@ -4672,6 +4728,9 @@ export {
4672
4728
  tileWidthTicks,
4673
4729
  timelineManifest,
4674
4730
  timelinePanel,
4731
+ timelineRuntimeComponents,
4732
+ timelineViewManifest,
4733
+ timelineViewState,
4675
4734
  export_toTick as toTick,
4676
4735
  todayKey,
4677
4736
  transportManifest,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xenosystem/blocks",
3
- "version": "0.13.29",
3
+ "version": "0.13.31",
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.30.0 <1",
67
+ "@xenosystem/components": ">=0.31.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.30.0",
84
+ "@xenosystem/components": "^0.31.0",
85
85
  "@xenosystem/data-core": "^0.1.0",
86
86
  "@xenosystem/elements": "0.0.1",
87
87
  "@xenosystem/elements-react": "0.0.1",