@xenosystem/blocks 0.13.24 → 0.13.26

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.
@@ -1487,9 +1487,9 @@ function LayersPanelView({ controller }) {
1487
1487
  const getSnapshot = useCallback(() => controller.getRevision(), [controller]);
1488
1488
  useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
1489
1489
  const view = layersViewState(controller);
1490
- const ui9 = (intent) => applyLayersUi(controller, intent);
1490
+ const ui10 = (intent) => applyLayersUi(controller, intent);
1491
1491
  return /* @__PURE__ */ jsxs(Column, { className: "xeno-layers-panel", children: [
1492
- view.searchShown ? /* @__PURE__ */ jsx2(Toolbar, { children: /* @__PURE__ */ jsx2(SearchField, { value: view.filter, onChange: (v) => ui9({ kind: "filter", value: v }), placeholder: "Search layers", label: "Search layers" }) }) : null,
1492
+ view.searchShown ? /* @__PURE__ */ jsx2(Toolbar, { children: /* @__PURE__ */ jsx2(SearchField, { value: view.filter, onChange: (v) => ui10({ kind: "filter", value: v }), placeholder: "Search layers", label: "Search layers" }) }) : null,
1493
1493
  /* @__PURE__ */ jsxs(LayersScroller, { controller, children: [
1494
1494
  /* @__PURE__ */ jsx2(RowList, { role: "tree", "aria-label": "Layers", children: /* @__PURE__ */ jsx2(VirtualWindow, { totalHeight: view.totalHeight, offsetTop: view.offsetTop, children: view.rows.map((row2) => /* @__PURE__ */ jsx2(LayerRow, { row: row2, thumbnailSize: view.thumbnailSize, controller }, row2.id)) }) }),
1495
1495
  view.empty ? /* @__PURE__ */ jsx2(EmptyState, { title: "No layers" }) : null
@@ -1602,7 +1602,7 @@ function LayersThumbnail({ thumbnailKey, size, controller }) {
1602
1602
  return /* @__PURE__ */ jsx2(Thumbnail, { size, data: controller.getThumbnail(thumbnailKey) });
1603
1603
  }
1604
1604
  function LayerRow({ row: row2, thumbnailSize, controller }) {
1605
- const ui9 = (intent) => applyLayersUi(controller, intent);
1605
+ const ui10 = (intent) => applyLayersUi(controller, intent);
1606
1606
  return /* @__PURE__ */ jsx2(
1607
1607
  Row,
1608
1608
  {
@@ -1617,11 +1617,11 @@ function LayerRow({ row: row2, thumbnailSize, controller }) {
1617
1617
  title: row2.title,
1618
1618
  icon: row2.hasThumbnail ? /* @__PURE__ */ jsx2(LayersThumbnail, { thumbnailKey: row2.thumbnailKey, size: thumbnailSize, controller }) : /* @__PURE__ */ jsx2(KindGlyph, {}),
1619
1619
  leading: /* @__PURE__ */ jsxs(Fragment, { children: [
1620
- row2.showVisibility ? /* @__PURE__ */ jsx2(IconButton, { size: "sm", icon: /* @__PURE__ */ jsx2(VisibilityIcon, { open: row2.visible }), label: row2.visibilityLabel, active: row2.visible, onClick: () => ui9({ kind: "toggleProp", id: row2.id, prop: "visible" }) }) : null,
1621
- row2.showLock ? /* @__PURE__ */ jsx2(IconButton, { size: "sm", icon: /* @__PURE__ */ jsx2(LockStateIcon, { locked: row2.locked }), label: row2.lockLabel, active: row2.locked, onClick: () => ui9({ kind: "toggleProp", id: row2.id, prop: "locked" }) }) : null,
1622
- row2.showSolo ? /* @__PURE__ */ jsx2(ChipToggle, { glyph: "S", label: "Solo", on: row2.solo, onChange: () => ui9({ kind: "toggleProp", id: row2.id, prop: "solo" }) }) : null,
1623
- row2.showMute ? /* @__PURE__ */ jsx2(ChipToggle, { glyph: "M", label: "Mute", on: row2.muted, onChange: () => ui9({ kind: "toggleProp", id: row2.id, prop: "muted" }) }) : null,
1624
- row2.showArm ? /* @__PURE__ */ jsx2(ChipToggle, { glyph: "R", label: "Arm", on: row2.armed, onChange: () => ui9({ kind: "toggleProp", id: row2.id, prop: "armed" }) }) : null,
1620
+ row2.showVisibility ? /* @__PURE__ */ jsx2(IconButton, { size: "sm", icon: /* @__PURE__ */ jsx2(VisibilityIcon, { open: row2.visible }), label: row2.visibilityLabel, active: row2.visible, onClick: () => ui10({ kind: "toggleProp", id: row2.id, prop: "visible" }) }) : null,
1621
+ row2.showLock ? /* @__PURE__ */ jsx2(IconButton, { size: "sm", icon: /* @__PURE__ */ jsx2(LockStateIcon, { locked: row2.locked }), label: row2.lockLabel, active: row2.locked, onClick: () => ui10({ kind: "toggleProp", id: row2.id, prop: "locked" }) }) : null,
1622
+ row2.showSolo ? /* @__PURE__ */ jsx2(ChipToggle, { glyph: "S", label: "Solo", on: row2.solo, onChange: () => ui10({ kind: "toggleProp", id: row2.id, prop: "solo" }) }) : null,
1623
+ row2.showMute ? /* @__PURE__ */ jsx2(ChipToggle, { glyph: "M", label: "Mute", on: row2.muted, onChange: () => ui10({ kind: "toggleProp", id: row2.id, prop: "muted" }) }) : null,
1624
+ row2.showArm ? /* @__PURE__ */ jsx2(ChipToggle, { glyph: "R", label: "Arm", on: row2.armed, onChange: () => ui10({ kind: "toggleProp", id: row2.id, prop: "armed" }) }) : null,
1625
1625
  row2.showColor ? /* @__PURE__ */ jsx2(ColorTag, { color: row2.colorLabel }) : null
1626
1626
  ] }),
1627
1627
  label: row2.renaming ? /* @__PURE__ */ jsx2(LayersRenameField, { id: row2.id, controller }) : row2.name,
@@ -1629,9 +1629,9 @@ function LayerRow({ row: row2, thumbnailSize, controller }) {
1629
1629
  row2.adornments.map((a) => /* @__PURE__ */ jsx2(Badge, { size: "sm", title: a.title, children: a.text }, a.key)),
1630
1630
  row2.showOpacity ? /* @__PURE__ */ jsx2(Text, { role: "number", children: row2.opacity }) : null
1631
1631
  ] }),
1632
- onExpandedChange: () => ui9({ kind: "toggleExpanded", id: row2.id }),
1633
- onDoubleClick: () => ui9({ kind: "beginRename", id: row2.id }),
1634
- onContextMenuAt: (x, y) => ui9({ kind: "contextMenu", id: row2.id, x, y })
1632
+ onExpandedChange: () => ui10({ kind: "toggleExpanded", id: row2.id }),
1633
+ onDoubleClick: () => ui10({ kind: "beginRename", id: row2.id }),
1634
+ onContextMenuAt: (x, y) => ui10({ kind: "contextMenu", id: row2.id, x, y })
1635
1635
  }
1636
1636
  );
1637
1637
  }
@@ -2023,8 +2023,8 @@ function constraintsOf(field) {
2023
2023
  scale: field.scale
2024
2024
  };
2025
2025
  }
2026
- function parseNumeric(text9) {
2027
- const trimmed = String(text9).trim();
2026
+ function parseNumeric(text10) {
2027
+ const trimmed = String(text10).trim();
2028
2028
  if (trimmed.length === 0) return { ok: false, reason: "empty" };
2029
2029
  const match = /^[+-]?(\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?/.exec(trimmed);
2030
2030
  if (!match) return { ok: false, reason: "nan" };
@@ -2049,8 +2049,8 @@ function normalizeNumeric(value, c) {
2049
2049
  function formatNumeric(value, field) {
2050
2050
  if (!Number.isFinite(value)) return "";
2051
2051
  const precision = field.precision;
2052
- const text9 = typeof precision === "number" && Number.isFinite(precision) ? value.toFixed(Math.max(0, Math.floor(precision))) : String(value);
2053
- return field.unit ? `${text9}${field.unit}` : text9;
2052
+ const text10 = typeof precision === "number" && Number.isFinite(precision) ? value.toFixed(Math.max(0, Math.floor(precision))) : String(value);
2053
+ return field.unit ? `${text10}${field.unit}` : text10;
2054
2054
  }
2055
2055
  function usesLogScale(c) {
2056
2056
  return c.scale === "log" && typeof c.min === "number" && typeof c.max === "number" && c.min > 0 && c.max > c.min;
@@ -2384,44 +2384,44 @@ var InspectorPanelController = class {
2384
2384
  if (!field || !isFieldEditable(field)) return;
2385
2385
  const mixed = isFieldMixed(field);
2386
2386
  const value = this.getFieldValue(fieldId);
2387
- const text9 = mixed ? "" : field.type === "number" && typeof value === "number" ? formatNumeric(value, field) : value === void 0 || value === null ? "" : String(value);
2388
- this.drafts.set(fieldId, { text: text9, original: value });
2387
+ const text10 = mixed ? "" : field.type === "number" && typeof value === "number" ? formatNumeric(value, field) : value === void 0 || value === null ? "" : String(value);
2388
+ this.drafts.set(fieldId, { text: text10, original: value });
2389
2389
  this.focusedFieldId = fieldId;
2390
2390
  this.emitFieldFocus(fieldId);
2391
2391
  this.notify();
2392
2392
  }
2393
2393
  /** Update the draft text (typing). Emits nothing under the `blur` policy. */
2394
- setDraft(fieldId, text9) {
2394
+ setDraft(fieldId, text10) {
2395
2395
  const draft = this.drafts.get(fieldId);
2396
2396
  if (!draft) {
2397
- this.drafts.set(fieldId, { text: text9, original: this.getFieldValue(fieldId) });
2397
+ this.drafts.set(fieldId, { text: text10, original: this.getFieldValue(fieldId) });
2398
2398
  } else {
2399
- draft.text = text9;
2399
+ draft.text = text10;
2400
2400
  }
2401
2401
  const field = this.getField(fieldId);
2402
2402
  if (field && commitPolicyOf(field) === "live") {
2403
- const parsed = this.parseDraft(fieldId, text9);
2403
+ const parsed = this.parseDraft(fieldId, text10);
2404
2404
  if (parsed.ok) this.emitSet(fieldId, parsed.value);
2405
2405
  }
2406
2406
  this.notify();
2407
2407
  }
2408
2408
  /** Parse a draft string into a field-appropriate value. */
2409
- parseDraft(fieldId, text9) {
2409
+ parseDraft(fieldId, text10) {
2410
2410
  const field = this.getField(fieldId);
2411
2411
  if (!field) return { ok: false };
2412
2412
  if (field.type === "number") {
2413
- const parsed = parseNumeric(text9);
2413
+ const parsed = parseNumeric(text10);
2414
2414
  if (!parsed.ok) return { ok: false };
2415
2415
  return { ok: true, value: normalizeNumeric(parsed.value, constraintsOf(field)) };
2416
2416
  }
2417
2417
  if (field.type === "json") {
2418
2418
  try {
2419
- return { ok: true, value: JSON.parse(text9) };
2419
+ return { ok: true, value: JSON.parse(text10) };
2420
2420
  } catch {
2421
2421
  return { ok: false };
2422
2422
  }
2423
2423
  }
2424
- return { ok: true, value: text9 };
2424
+ return { ok: true, value: text10 };
2425
2425
  }
2426
2426
  /**
2427
2427
  * Commit the draft (Enter / blur). Invalid input reverts instead of committing garbage.
@@ -3347,7 +3347,7 @@ function NumberWidget({ field, controller, component }) {
3347
3347
  },
3348
3348
  [controller, editable, field.id, component]
3349
3349
  );
3350
- const text9 = component !== void 0 ? (() => {
3350
+ const text10 = component !== void 0 ? (() => {
3351
3351
  const raw = controller.getFieldValue(field.id);
3352
3352
  const v = Array.isArray(raw) ? raw[component] : void 0;
3353
3353
  return typeof v === "number" ? formatNumeric(v, field) : "";
@@ -3359,7 +3359,7 @@ function NumberWidget({ field, controller, component }) {
3359
3359
  Input2,
3360
3360
  {
3361
3361
  inputMode: "decimal",
3362
- value: text9,
3362
+ value: text10,
3363
3363
  placeholder: mixed ? controller.getMixedPlaceholder() : field.placeholder,
3364
3364
  mixed,
3365
3365
  readOnly: !editable,
@@ -3577,7 +3577,7 @@ function ActionGlyph({ glyph }) {
3577
3577
  return /* @__PURE__ */ jsx4("span", { "aria-hidden": true, children: glyph });
3578
3578
  }
3579
3579
  function SectionView({ section, controller }) {
3580
- const ui9 = (intent) => applyInspectorUi(controller, intent);
3580
+ const ui10 = (intent) => applyInspectorUi(controller, intent);
3581
3581
  const hasActions = section.actions.length > 0 || section.hasAddMenu;
3582
3582
  return /* @__PURE__ */ jsxs3(
3583
3583
  Section,
@@ -3586,13 +3586,13 @@ function SectionView({ section, controller }) {
3586
3586
  flush: true,
3587
3587
  collapsible: section.collapsible,
3588
3588
  collapsed: section.collapsed,
3589
- onCollapsedChange: () => ui9({ kind: "toggleSectionCollapsed", sectionId: section.id }),
3589
+ onCollapsedChange: () => ui10({ kind: "toggleSectionCollapsed", sectionId: section.id }),
3590
3590
  enabled: section.enabled,
3591
- onEnabledChange: () => ui9({ kind: "toggleSectionEnabled", sectionId: section.id }),
3591
+ onEnabledChange: () => ui10({ kind: "toggleSectionEnabled", sectionId: section.id }),
3592
3592
  badge: section.badge ? /* @__PURE__ */ jsx4(Badge2, { children: section.badge }) : null,
3593
3593
  actions: hasActions ? /* @__PURE__ */ jsxs3(Fragment3, { children: [
3594
- section.actions.map((action) => /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(ActionGlyph, { glyph: action.glyph }), label: action.label, disabled: action.disabled, onClick: () => ui9({ kind: "runAction", sectionId: section.id, actionId: action.id }) }, action.id)),
3595
- section.hasAddMenu ? /* @__PURE__ */ jsx4(Menu, { size: "sm", trigger: "\uFF0B", items: section.addItems, label: section.addLabel, align: "end", onSelect: (id) => ui9({ kind: "addItem", sectionId: section.id, itemId: id }) }) : null
3594
+ section.actions.map((action) => /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(ActionGlyph, { glyph: action.glyph }), label: action.label, disabled: action.disabled, onClick: () => ui10({ kind: "runAction", sectionId: section.id, actionId: action.id }) }, action.id)),
3595
+ section.hasAddMenu ? /* @__PURE__ */ jsx4(Menu, { size: "sm", trigger: "\uFF0B", items: section.addItems, label: section.addLabel, align: "end", onSelect: (id) => ui10({ kind: "addItem", sectionId: section.id, itemId: id }) }) : null
3596
3596
  ] }) : null,
3597
3597
  children: [
3598
3598
  section.showEmptyHint ? /* @__PURE__ */ jsx4(Stack2, { pad: "inset", children: /* @__PURE__ */ jsx4(Text3, { role: "caption", children: section.emptyHint }) }) : null,
@@ -3602,7 +3602,7 @@ function SectionView({ section, controller }) {
3602
3602
  );
3603
3603
  }
3604
3604
  function FieldRow({ row: row2, controller }) {
3605
- const ui9 = (intent) => applyInspectorUi(controller, intent);
3605
+ const ui10 = (intent) => applyInspectorUi(controller, intent);
3606
3606
  return /* @__PURE__ */ jsxs3(Fragment3, { children: [
3607
3607
  /* @__PURE__ */ jsxs3(
3608
3608
  Field,
@@ -3610,19 +3610,19 @@ function FieldRow({ row: row2, controller }) {
3610
3610
  label: row2.label,
3611
3611
  title: row2.title,
3612
3612
  focused: row2.focused,
3613
- onLabelClick: () => ui9({ kind: "focusField", fieldId: row2.id }),
3614
- onContextMenu: (x, y) => ui9({ kind: "contextMenu", fieldId: row2.id, x, y }),
3613
+ onLabelClick: () => ui10({ kind: "focusField", fieldId: row2.id }),
3614
+ onContextMenu: (x, y) => ui10({ kind: "contextMenu", fieldId: row2.id, x, y }),
3615
3615
  leading: row2.showKeyframes ? /* @__PURE__ */ jsxs3(Fragment3, { children: [
3616
- /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(StopwatchIcon, {}), label: "Toggle animation", active: row2.animated, onClick: () => ui9({ kind: "keyframe", fieldId: row2.id, op: "toggleAnim" }) }),
3617
- row2.animated ? /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(PrevIcon, {}), label: "Previous keyframe", disabled: row2.prevDisabled, onClick: () => ui9({ kind: "keyframe", fieldId: row2.id, op: "prev" }) }) : null,
3618
- row2.animated ? /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(DiamondIcon, { filled: row2.onKeyframe }), label: row2.keyframeLabel, onClick: () => ui9({ kind: "keyframe", fieldId: row2.id, op: row2.keyframeOp }) }) : null,
3619
- row2.animated ? /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(NextIcon, {}), label: "Next keyframe", disabled: row2.nextDisabled, onClick: () => ui9({ kind: "keyframe", fieldId: row2.id, op: "next" }) }) : null
3616
+ /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(StopwatchIcon, {}), label: "Toggle animation", active: row2.animated, onClick: () => ui10({ kind: "keyframe", fieldId: row2.id, op: "toggleAnim" }) }),
3617
+ row2.animated ? /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(PrevIcon, {}), label: "Previous keyframe", disabled: row2.prevDisabled, onClick: () => ui10({ kind: "keyframe", fieldId: row2.id, op: "prev" }) }) : null,
3618
+ row2.animated ? /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(DiamondIcon, { filled: row2.onKeyframe }), label: row2.keyframeLabel, onClick: () => ui10({ kind: "keyframe", fieldId: row2.id, op: row2.keyframeOp }) }) : null,
3619
+ row2.animated ? /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(NextIcon, {}), label: "Next keyframe", disabled: row2.nextDisabled, onClick: () => ui10({ kind: "keyframe", fieldId: row2.id, op: "next" }) }) : null
3620
3620
  ] }) : null,
3621
3621
  trailing: /* @__PURE__ */ jsxs3(Fragment3, { children: [
3622
- row2.showEasing ? /* @__PURE__ */ jsx4(Select2, { size: "sm", options: row2.easingOptions, value: row2.easing, label: "Easing", onChange: (v) => ui9({ kind: "setEasing", fieldId: row2.id, easing: v }) }) : null,
3622
+ row2.showEasing ? /* @__PURE__ */ jsx4(Select2, { size: "sm", options: row2.easingOptions, value: row2.easing, label: "Easing", onChange: (v) => ui10({ kind: "setEasing", fieldId: row2.id, easing: v }) }) : null,
3623
3623
  row2.showKeyframes ? /* @__PURE__ */ jsx4(Badge2, { size: "sm", children: row2.keyframeChip }) : null,
3624
- row2.showToken ? /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(LinkIcon, {}), label: row2.tokenActionLabel, active: row2.bound, onClick: () => ui9({ kind: "bindToken", fieldId: row2.id }) }) : null,
3625
- row2.showReset ? /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(ResetIcon, {}), label: "Reset to default", onClick: () => ui9({ kind: "resetField", fieldId: row2.id }) }) : null
3624
+ row2.showToken ? /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(LinkIcon, {}), label: row2.tokenActionLabel, active: row2.bound, onClick: () => ui10({ kind: "bindToken", fieldId: row2.id }) }) : null,
3625
+ row2.showReset ? /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(ResetIcon, {}), label: "Reset to default", onClick: () => ui10({ kind: "resetField", fieldId: row2.id }) }) : null
3626
3626
  ] }),
3627
3627
  children: [
3628
3628
  row2.bound ? /* @__PURE__ */ jsx4(Badge2, { title: row2.tokenTitle, children: row2.tokenLabel }) : null,
@@ -4875,23 +4875,23 @@ function HistoryPanelView({ controller }) {
4875
4875
  const getSnapshot = useCallback4(() => controller.getRevision(), [controller]);
4876
4876
  useSyncExternalStore3(subscribe, getSnapshot, getSnapshot);
4877
4877
  const view = historyViewState(controller);
4878
- const ui9 = (intent) => applyHistoryUi(controller, intent);
4878
+ const ui10 = (intent) => applyHistoryUi(controller, intent);
4879
4879
  return /* @__PURE__ */ jsxs4(Column3, { className: "xeno-history-panel", children: [
4880
4880
  /* @__PURE__ */ jsx5(
4881
4881
  Toolbar2,
4882
4882
  {
4883
4883
  left: /* @__PURE__ */ jsxs4(Fragment4, { children: [
4884
- /* @__PURE__ */ jsx5(IconButton4, { size: "sm", icon: /* @__PURE__ */ jsx5(UndoIcon, {}), label: "Undo", disabled: !view.canUndo, onClick: () => ui9({ kind: "undo" }) }),
4885
- /* @__PURE__ */ jsx5(IconButton4, { size: "sm", icon: /* @__PURE__ */ jsx5(RedoIcon, {}), label: "Redo", disabled: !view.canRedo, onClick: () => ui9({ kind: "redo" }) })
4884
+ /* @__PURE__ */ jsx5(IconButton4, { size: "sm", icon: /* @__PURE__ */ jsx5(UndoIcon, {}), label: "Undo", disabled: !view.canUndo, onClick: () => ui10({ kind: "undo" }) }),
4885
+ /* @__PURE__ */ jsx5(IconButton4, { size: "sm", icon: /* @__PURE__ */ jsx5(RedoIcon, {}), label: "Redo", disabled: !view.canRedo, onClick: () => ui10({ kind: "redo" }) })
4886
4886
  ] }),
4887
4887
  right: /* @__PURE__ */ jsxs4(Fragment4, { children: [
4888
4888
  /* @__PURE__ */ jsx5(Text4, { role: "number", children: view.counter }),
4889
- view.clearAllowed ? /* @__PURE__ */ jsx5(IconButton4, { size: "sm", icon: /* @__PURE__ */ jsx5(TrashIcon, {}), label: "Clear history", onClick: () => ui9({ kind: "requestClear" }) }) : null
4889
+ view.clearAllowed ? /* @__PURE__ */ jsx5(IconButton4, { size: "sm", icon: /* @__PURE__ */ jsx5(TrashIcon, {}), label: "Clear history", onClick: () => ui10({ kind: "requestClear" }) }) : null
4890
4890
  ] }),
4891
- children: view.searchShown ? /* @__PURE__ */ jsx5(SearchField3, { value: view.filter, onChange: (v) => ui9({ kind: "filter", value: v }), placeholder: "Search history", label: "Search history" }) : null
4891
+ children: view.searchShown ? /* @__PURE__ */ jsx5(SearchField3, { value: view.filter, onChange: (v) => ui10({ kind: "filter", value: v }), placeholder: "Search history", label: "Search history" }) : null
4892
4892
  }
4893
4893
  ),
4894
- view.confirmingClear ? /* @__PURE__ */ jsx5(InlineConfirm, { message: "Clear all history?", label: "Confirm clear history", confirmLabel: "Clear", onConfirm: () => ui9({ kind: "confirmClear" }), onCancel: () => ui9({ kind: "cancelClear" }) }) : null,
4894
+ view.confirmingClear ? /* @__PURE__ */ jsx5(InlineConfirm, { message: "Clear all history?", label: "Confirm clear history", confirmLabel: "Clear", onConfirm: () => ui10({ kind: "confirmClear" }), onCancel: () => ui10({ kind: "cancelClear" }) }) : null,
4895
4895
  view.pruned ? /* @__PURE__ */ jsx5(Text4, { role: "caption", children: "Earlier history discarded (limit reached)" }) : null,
4896
4896
  /* @__PURE__ */ jsxs4(HistoryScroller, { controller, children: [
4897
4897
  /* @__PURE__ */ jsx5(RowList2, { role: "listbox", "aria-label": "History", children: /* @__PURE__ */ jsx5(VirtualWindow2, { totalHeight: view.totalHeight, offsetTop: view.offsetTop, children: view.rows.map((row2) => /* @__PURE__ */ jsx5(HistoryRowView, { row: row2, controller }, row2.key)) }) }),
@@ -4950,7 +4950,7 @@ function HistoryCancelButton({ entryId, controller }) {
4950
4950
  );
4951
4951
  }
4952
4952
  function HistoryRowView({ row: row2, controller }) {
4953
- const ui9 = (intent) => applyHistoryUi(controller, intent);
4953
+ const ui10 = (intent) => applyHistoryUi(controller, intent);
4954
4954
  return /* @__PURE__ */ jsx5(
4955
4955
  Row2,
4956
4956
  {
@@ -4973,9 +4973,9 @@ function HistoryRowView({ row: row2, controller }) {
4973
4973
  row2.showTime ? /* @__PURE__ */ jsx5(Text4, { role: "meta", children: row2.time }) : null,
4974
4974
  row2.pending ? /* @__PURE__ */ jsx5(HistoryCancelButton, { entryId: row2.cancelId, controller }) : null
4975
4975
  ] }),
4976
- onClick: () => ui9({ kind: "jump", entryId: row2.entryId }),
4977
- onMouseEnter: () => ui9({ kind: "hover", entryId: row2.entryId }),
4978
- onContextMenuAt: (x, y) => ui9({ kind: "contextMenu", entryId: row2.entryId, x, y })
4976
+ onClick: () => ui10({ kind: "jump", entryId: row2.entryId }),
4977
+ onMouseEnter: () => ui10({ kind: "hover", entryId: row2.entryId }),
4978
+ onContextMenuAt: (x, y) => ui10({ kind: "contextMenu", entryId: row2.entryId, x, y })
4979
4979
  }
4980
4980
  );
4981
4981
  }
@@ -6261,27 +6261,27 @@ function ColorPanelView({ controller }) {
6261
6261
  const getSnapshot = useCallback5(() => controller.getRevision(), [controller]);
6262
6262
  useSyncExternalStore4(subscribe, getSnapshot, getSnapshot);
6263
6263
  const view = colorViewState(controller);
6264
- const ui9 = (intent) => applyColorUi(controller, intent);
6264
+ const ui10 = (intent) => applyColorUi(controller, intent);
6265
6265
  return /* @__PURE__ */ jsx6(Column4, { className: "xeno-color-panel", children: /* @__PURE__ */ jsxs5(Stack3, { gap: 8, children: [
6266
6266
  view.fgBg ? /* @__PURE__ */ jsxs5(Stack3, { direction: "row", pad: "none", children: [
6267
- /* @__PURE__ */ jsx6(ColorChip, { color: view.hex, label: "Foreground", pressed: view.fgActive, onClick: () => ui9({ kind: "setChannel", channel: "fg" }) }),
6268
- /* @__PURE__ */ jsx6(IconButton5, { size: "sm", icon: /* @__PURE__ */ jsx6(SwapIcon, {}), label: "Swap FG/BG (X)", onClick: () => ui9({ kind: "swapChannels" }) }),
6269
- /* @__PURE__ */ jsx6(ColorChip, { color: null, label: "Background", pressed: view.bgActive, onClick: () => ui9({ kind: "setChannel", channel: "bg" }) })
6267
+ /* @__PURE__ */ jsx6(ColorChip, { color: view.hex, label: "Foreground", pressed: view.fgActive, onClick: () => ui10({ kind: "setChannel", channel: "fg" }) }),
6268
+ /* @__PURE__ */ jsx6(IconButton5, { size: "sm", icon: /* @__PURE__ */ jsx6(SwapIcon, {}), label: "Swap FG/BG (X)", onClick: () => ui10({ kind: "swapChannels" }) }),
6269
+ /* @__PURE__ */ jsx6(ColorChip, { color: null, label: "Background", pressed: view.bgActive, onClick: () => ui10({ kind: "setChannel", channel: "bg" }) })
6270
6270
  ] }) : null,
6271
6271
  /* @__PURE__ */ jsx6(ColorPicker, { controller }),
6272
6272
  /* @__PURE__ */ jsxs5(Stack3, { direction: "row", pad: "none", gap: 4, children: [
6273
- /* @__PURE__ */ jsx6(Select3, { size: "sm", label: "Color model", value: view.space, options: view.spaceOptions, onChange: (v) => ui9({ kind: "setSpace", space: v }) }),
6274
- view.isHex ? /* @__PURE__ */ jsx6(Input3, { variant: "mono", label: "Hex", value: view.hex, onChange: (v) => ui9({ kind: "setHex", value: v }), disabled: view.bound }) : null,
6275
- view.components.map((comp) => /* @__PURE__ */ jsx6(NumberInput, { caption: comp.label, value: comp.value, onChange: (n) => ui9({ kind: "setComponent", index: comp.index, value: n }), disabled: view.bound }, comp.key)),
6276
- view.alphaShown ? /* @__PURE__ */ jsx6(NumberInput, { caption: "A", label: "Alpha", min: 0, max: 100, value: view.alphaPercent, onChange: (n) => ui9({ kind: "setAlpha", percent: n }), disabled: view.bound }) : null,
6277
- /* @__PURE__ */ jsx6(IconButton5, { size: "sm", icon: /* @__PURE__ */ jsx6(EyedropperIcon, {}), label: "Pick from screen", onClick: () => ui9({ kind: "eyedropper" }) })
6273
+ /* @__PURE__ */ jsx6(Select3, { size: "sm", label: "Color model", value: view.space, options: view.spaceOptions, onChange: (v) => ui10({ kind: "setSpace", space: v }) }),
6274
+ view.isHex ? /* @__PURE__ */ jsx6(Input3, { variant: "mono", label: "Hex", value: view.hex, onChange: (v) => ui10({ kind: "setHex", value: v }), disabled: view.bound }) : null,
6275
+ view.components.map((comp) => /* @__PURE__ */ jsx6(NumberInput, { caption: comp.label, value: comp.value, onChange: (n) => ui10({ kind: "setComponent", index: comp.index, value: n }), disabled: view.bound }, comp.key)),
6276
+ view.alphaShown ? /* @__PURE__ */ jsx6(NumberInput, { caption: "A", label: "Alpha", min: 0, max: 100, value: view.alphaPercent, onChange: (n) => ui10({ kind: "setAlpha", percent: n }), disabled: view.bound }) : null,
6277
+ /* @__PURE__ */ jsx6(IconButton5, { size: "sm", icon: /* @__PURE__ */ jsx6(EyedropperIcon, {}), label: "Pick from screen", onClick: () => ui10({ kind: "eyedropper" }) })
6278
6278
  ] }),
6279
6279
  view.hasTokens ? /* @__PURE__ */ jsx6(Field2, { label: "Token", htmlFor: "xeno-color-token", children: /* @__PURE__ */ jsxs5(Stack3, { direction: "row", pad: "none", gap: 4, children: [
6280
- /* @__PURE__ */ jsx6(Select3, { size: "sm", label: "Bind token", value: view.boundTokenId, placeholder: "\u2014 raw \u2014", options: view.tokenOptions, onChange: (id) => ui9({ kind: "bindToken", tokenId: id }) }),
6281
- view.bound ? /* @__PURE__ */ jsx6(TextButton2, { onClick: () => ui9({ kind: "unbindToken" }), children: "Unbind" }) : null
6280
+ /* @__PURE__ */ jsx6(Select3, { size: "sm", label: "Bind token", value: view.boundTokenId, placeholder: "\u2014 raw \u2014", options: view.tokenOptions, onChange: (id) => ui10({ kind: "bindToken", tokenId: id }) }),
6281
+ view.bound ? /* @__PURE__ */ jsx6(TextButton2, { onClick: () => ui10({ kind: "unbindToken" }), children: "Unbind" }) : null
6282
6282
  ] }) }) : null,
6283
- /* @__PURE__ */ jsx6(Section2, { title: "Swatches", flush: true, actions: /* @__PURE__ */ jsx6(TextButton2, { onClick: () => ui9({ kind: "addSwatch" }), children: "+ Save" }), children: /* @__PURE__ */ jsx6(SwatchGrid, { label: "Swatches", children: view.swatches.map((sw) => /* @__PURE__ */ jsx6(ColorChip, { size: "grid", color: sw.hex, label: sw.hex, onClick: () => ui9({ kind: "selectColor", hex: sw.hex }), onContextMenu: () => ui9({ kind: "removeSwatch", hex: sw.hex }) }, sw.key)) }) }),
6284
- view.hasRecent ? /* @__PURE__ */ jsx6(Section2, { title: "Recent", flush: true, children: /* @__PURE__ */ jsx6(SwatchGrid, { label: "Recent", children: view.recent.map((r) => /* @__PURE__ */ jsx6(ColorChip, { size: "grid", color: r.hex, label: r.hex, onClick: () => ui9({ kind: "selectColor", hex: r.hex }) }, r.key)) }) }) : null
6283
+ /* @__PURE__ */ jsx6(Section2, { title: "Swatches", flush: true, actions: /* @__PURE__ */ jsx6(TextButton2, { onClick: () => ui10({ kind: "addSwatch" }), children: "+ Save" }), children: /* @__PURE__ */ jsx6(SwatchGrid, { label: "Swatches", children: view.swatches.map((sw) => /* @__PURE__ */ jsx6(ColorChip, { size: "grid", color: sw.hex, label: sw.hex, onClick: () => ui10({ kind: "selectColor", hex: sw.hex }), onContextMenu: () => ui10({ kind: "removeSwatch", hex: sw.hex }) }, sw.key)) }) }),
6284
+ view.hasRecent ? /* @__PURE__ */ jsx6(Section2, { title: "Recent", flush: true, children: /* @__PURE__ */ jsx6(SwatchGrid, { label: "Recent", children: view.recent.map((r) => /* @__PURE__ */ jsx6(ColorChip, { size: "grid", color: r.hex, label: r.hex, onClick: () => ui10({ kind: "selectColor", hex: r.hex }) }, r.key)) }) }) : null
6285
6285
  ] }) });
6286
6286
  }
6287
6287
  function ColorPicker({ controller }) {
@@ -7799,19 +7799,19 @@ var DASHES = ["none", "4 2", "1 2", "6 2 1 2"];
7799
7799
  function CurvePanelView({ controller, ...options }) {
7800
7800
  useSyncExternalStore5(controller.subscribe, controller.getState, controller.getState);
7801
7801
  const view = curveViewState(controller, options);
7802
- const ui9 = (intent) => applyCurveUi(controller, intent);
7802
+ const ui10 = (intent) => applyCurveUi(controller, intent);
7803
7803
  return /* @__PURE__ */ jsxs6(Column5, { children: [
7804
7804
  /* @__PURE__ */ jsx7(
7805
7805
  Toolbar3,
7806
7806
  {
7807
- left: /* @__PURE__ */ jsx7(ToolbarGroup, { children: view.interpolations.map((m) => /* @__PURE__ */ jsx7(TextButton3, { onClick: () => ui9({ kind: "interpolation", mode: m.mode }), children: m.label }, m.key)) }),
7807
+ left: /* @__PURE__ */ jsx7(ToolbarGroup, { children: view.interpolations.map((m) => /* @__PURE__ */ jsx7(TextButton3, { onClick: () => ui10({ kind: "interpolation", mode: m.mode }), children: m.label }, m.key)) }),
7808
7808
  right: /* @__PURE__ */ jsxs6(ToolbarGroup, { end: true, children: [
7809
- view.tangentModes.map((m) => /* @__PURE__ */ jsx7(TextButton3, { onClick: () => ui9({ kind: "tangentMode", mode: m.mode }), children: m.label }, m.key)),
7810
- /* @__PURE__ */ jsx7(TextButton3, { onClick: () => ui9({ kind: "fit" }), children: "Fit" })
7809
+ view.tangentModes.map((m) => /* @__PURE__ */ jsx7(TextButton3, { onClick: () => ui10({ kind: "tangentMode", mode: m.mode }), children: m.label }, m.key)),
7810
+ /* @__PURE__ */ jsx7(TextButton3, { onClick: () => ui10({ kind: "fit" }), children: "Fit" })
7811
7811
  ] })
7812
7812
  }
7813
7813
  ),
7814
- view.presetsShown ? /* @__PURE__ */ jsx7(Toolbar3, { left: /* @__PURE__ */ jsx7(ToolbarGroup, { children: view.presets.map((p) => /* @__PURE__ */ jsx7(TextButton3, { onClick: () => ui9({ kind: "preset", id: p.id }), children: p.label }, p.key)) }) }) : null,
7814
+ view.presetsShown ? /* @__PURE__ */ jsx7(Toolbar3, { left: /* @__PURE__ */ jsx7(ToolbarGroup, { children: view.presets.map((p) => /* @__PURE__ */ jsx7(TextButton3, { onClick: () => ui10({ kind: "preset", id: p.id }), children: p.label }, p.key)) }) }) : null,
7815
7815
  view.empty ? /* @__PURE__ */ jsx7(EmptyState4, { title: "No curves", hint: "Wire an animated property into this panel's input." }) : null,
7816
7816
  view.drawn ? /* @__PURE__ */ jsx7(CurveSurface, { controller }) : null,
7817
7817
  /* @__PURE__ */ jsx7(StatusBar3, { left: /* @__PURE__ */ jsx7(Text5, { role: "number", children: view.channelsLabel }), right: /* @__PURE__ */ jsx7(Text5, { role: "number", children: view.playheadLabel }) })
@@ -7825,7 +7825,7 @@ function CurveSurface({ controller }) {
7825
7825
  if (!el) return;
7826
7826
  const measure = () => {
7827
7827
  const rect = el.getBoundingClientRect();
7828
- controller.resize(rect.width, rect.height);
7828
+ if (rect.width > 0 && rect.height > 0) controller.resize(rect.width, rect.height);
7829
7829
  };
7830
7830
  measure();
7831
7831
  if (typeof ResizeObserver === "undefined") return;
@@ -9016,11 +9016,11 @@ var FindController = class {
9016
9016
  * @param text - The new query text.
9017
9017
  * @param immediate - Skip the debounce (a paste, or pressing Enter).
9018
9018
  */
9019
- setText(text9, immediate = false) {
9020
- if (text9 === this.text) return;
9021
- this.text = text9;
9019
+ setText(text10, immediate = false) {
9020
+ if (text10 === this.text) return;
9021
+ this.text = text10;
9022
9022
  this.index = -1;
9023
- if (text9 === "") {
9023
+ if (text10 === "") {
9024
9024
  this.clearResults("idle");
9025
9025
  this.emitQuery(true);
9026
9026
  return;
@@ -9048,8 +9048,8 @@ var FindController = class {
9048
9048
  this.notify();
9049
9049
  }
9050
9050
  /** The replacement text. Never emitted on its own — a replacement is not a search. */
9051
- setReplaceText(text9) {
9052
- this.replaceText = text9;
9051
+ setReplaceText(text10) {
9052
+ this.replaceText = text10;
9053
9053
  this.notify();
9054
9054
  }
9055
9055
  /** Show or hide the replace row. */
@@ -9698,7 +9698,7 @@ function findRuntimeComponents(controller) {
9698
9698
  function FindPanelView({ controller, showResults, placeholder }) {
9699
9699
  useSyncExternalStore7(controller.subscribe, controller.getState, controller.getState);
9700
9700
  const view = findViewState(controller, { showResults, placeholder });
9701
- const ui9 = (intent) => applyFindUi(controller, intent);
9701
+ const ui10 = (intent) => applyFindUi(controller, intent);
9702
9702
  const renderRow = (row2) => /* @__PURE__ */ jsx9(
9703
9703
  Row3,
9704
9704
  {
@@ -9706,8 +9706,8 @@ function FindPanelView({ controller, showResults, placeholder }) {
9706
9706
  selected: row2.current,
9707
9707
  meta: row2.location,
9708
9708
  label: /* @__PURE__ */ jsx9(Highlight, { segments: row2.segments }),
9709
- onClick: () => ui9({ kind: "select", matchId: row2.id }),
9710
- onContextMenuAt: (x, y) => ui9({ kind: "contextMenu", matchId: row2.id, x, y })
9709
+ onClick: () => ui10({ kind: "select", matchId: row2.id }),
9710
+ onContextMenuAt: (x, y) => ui10({ kind: "contextMenu", matchId: row2.id, x, y })
9711
9711
  },
9712
9712
  row2.id
9713
9713
  );
@@ -9715,11 +9715,11 @@ function FindPanelView({ controller, showResults, placeholder }) {
9715
9715
  /* @__PURE__ */ jsx9(
9716
9716
  Toolbar4,
9717
9717
  {
9718
- left: /* @__PURE__ */ jsx9(SearchField4, { value: view.text, placeholder: view.placeholder, onChange: (value) => ui9({ kind: "text", value }) }),
9718
+ left: /* @__PURE__ */ jsx9(SearchField4, { value: view.text, placeholder: view.placeholder, onChange: (value) => ui10({ kind: "text", value }) }),
9719
9719
  right: /* @__PURE__ */ jsxs8(ToolbarGroup2, { end: true, children: [
9720
- /* @__PURE__ */ jsx9(IconButton6, { label: "Match case", active: view.caseSensitive, icon: /* @__PURE__ */ jsx9(CaseIcon, { size: 12 }), onClick: () => ui9({ kind: "option", option: "caseSensitive" }) }),
9721
- /* @__PURE__ */ jsx9(IconButton6, { label: "Whole word", active: view.wholeWord, icon: /* @__PURE__ */ jsx9(WordIcon, { size: 12 }), onClick: () => ui9({ kind: "option", option: "wholeWord" }) }),
9722
- /* @__PURE__ */ jsx9(IconButton6, { label: "Regular expression", active: view.regex, icon: /* @__PURE__ */ jsx9(RegexIcon, { size: 12 }), onClick: () => ui9({ kind: "option", option: "regex" }) })
9720
+ /* @__PURE__ */ jsx9(IconButton6, { label: "Match case", active: view.caseSensitive, icon: /* @__PURE__ */ jsx9(CaseIcon, { size: 12 }), onClick: () => ui10({ kind: "option", option: "caseSensitive" }) }),
9721
+ /* @__PURE__ */ jsx9(IconButton6, { label: "Whole word", active: view.wholeWord, icon: /* @__PURE__ */ jsx9(WordIcon, { size: 12 }), onClick: () => ui10({ kind: "option", option: "wholeWord" }) }),
9722
+ /* @__PURE__ */ jsx9(IconButton6, { label: "Regular expression", active: view.regex, icon: /* @__PURE__ */ jsx9(RegexIcon, { size: 12 }), onClick: () => ui10({ kind: "option", option: "regex" }) })
9723
9723
  ] })
9724
9724
  }
9725
9725
  ),
@@ -9734,9 +9734,9 @@ function FindPanelView({ controller, showResults, placeholder }) {
9734
9734
  view.countShown ? /* @__PURE__ */ jsx9(Text6, { role: "number", children: view.counter }) : null
9735
9735
  ] }),
9736
9736
  right: /* @__PURE__ */ jsxs8(ToolbarGroup2, { end: true, children: [
9737
- /* @__PURE__ */ jsx9(IconButton6, { label: "Previous match", disabled: !view.hasMatches, icon: /* @__PURE__ */ jsx9(Chevron, { direction: "up", size: 12 }), onClick: () => ui9({ kind: "previous" }) }),
9738
- /* @__PURE__ */ jsx9(IconButton6, { label: "Next match", disabled: !view.hasMatches, icon: /* @__PURE__ */ jsx9(Chevron, { direction: "down", size: 12 }), onClick: () => ui9({ kind: "next" }) }),
9739
- /* @__PURE__ */ jsx9(TextButton4, { onClick: () => ui9({ kind: "toggleReplace" }), children: view.replaceLabel })
9737
+ /* @__PURE__ */ jsx9(IconButton6, { label: "Previous match", disabled: !view.hasMatches, icon: /* @__PURE__ */ jsx9(Chevron, { direction: "up", size: 12 }), onClick: () => ui10({ kind: "previous" }) }),
9738
+ /* @__PURE__ */ jsx9(IconButton6, { label: "Next match", disabled: !view.hasMatches, icon: /* @__PURE__ */ jsx9(Chevron, { direction: "down", size: 12 }), onClick: () => ui10({ kind: "next" }) }),
9739
+ /* @__PURE__ */ jsx9(TextButton4, { onClick: () => ui10({ kind: "toggleReplace" }), children: view.replaceLabel })
9740
9740
  ] })
9741
9741
  }
9742
9742
  ),
@@ -9744,10 +9744,10 @@ function FindPanelView({ controller, showResults, placeholder }) {
9744
9744
  view.replaceVisible ? /* @__PURE__ */ jsx9(
9745
9745
  Toolbar4,
9746
9746
  {
9747
- left: /* @__PURE__ */ jsx9(SearchField4, { value: view.replaceText, placeholder: "Replace with", onChange: (value) => ui9({ kind: "replaceText", value }) }),
9747
+ left: /* @__PURE__ */ jsx9(SearchField4, { value: view.replaceText, placeholder: "Replace with", onChange: (value) => ui10({ kind: "replaceText", value }) }),
9748
9748
  right: /* @__PURE__ */ jsxs8(ToolbarGroup2, { end: true, children: [
9749
- /* @__PURE__ */ jsx9(TextButton4, { disabled: !view.canReplace, onClick: () => ui9({ kind: "replaceCurrent" }), children: "Replace" }),
9750
- /* @__PURE__ */ jsx9(TextButton4, { disabled: !view.canReplace, onClick: () => ui9({ kind: "replaceAll" }), children: view.allLabel })
9749
+ /* @__PURE__ */ jsx9(TextButton4, { disabled: !view.canReplace, onClick: () => ui10({ kind: "replaceCurrent" }), children: "Replace" }),
9750
+ /* @__PURE__ */ jsx9(TextButton4, { disabled: !view.canReplace, onClick: () => ui10({ kind: "replaceAll" }), children: view.allLabel })
9751
9751
  ] })
9752
9752
  }
9753
9753
  ) : null,
@@ -10646,37 +10646,37 @@ import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
10646
10646
  function CommentsPanelView({ controller, ...options }) {
10647
10647
  useSyncExternalStore8(controller.subscribe, controller.getState, controller.getState);
10648
10648
  const view = commentsViewState(controller, options);
10649
- const ui9 = (intent) => applyCommentsUi(controller, intent);
10650
- const card = (t) => /* @__PURE__ */ jsxs9(ThreadCard, { active: t.active, resolved: t.resolved, onContextMenuAt: (x, y) => ui9({ kind: "contextMenu", id: t.id, x, y }), children: [
10649
+ const ui10 = (intent) => applyCommentsUi(controller, intent);
10650
+ const card = (t) => /* @__PURE__ */ jsxs9(ThreadCard, { active: t.active, resolved: t.resolved, onContextMenuAt: (x, y) => ui10({ kind: "contextMenu", id: t.id, x, y }), children: [
10651
10651
  /* @__PURE__ */ jsxs9(Stack4, { direction: "row", gap: 4, pad: "none", children: [
10652
10652
  t.hasAnchorBadge ? /* @__PURE__ */ jsx10(Badge6, { tone: t.anchorTone, title: t.anchorTitle, children: t.anchorLabel }) : null,
10653
10653
  t.resolved ? /* @__PURE__ */ jsx10(Badge6, { children: "resolved" }) : null,
10654
10654
  /* @__PURE__ */ jsx10(Text7, { role: "caption", children: t.age })
10655
10655
  ] }),
10656
- t.hasQuote ? /* @__PURE__ */ jsx10(Quote, { orphaned: t.orphaned, onActivate: () => ui9({ kind: "activate", id: t.id }), children: t.quote }) : null,
10656
+ t.hasQuote ? /* @__PURE__ */ jsx10(Quote, { orphaned: t.orphaned, onActivate: () => ui10({ kind: "activate", id: t.id }), children: t.quote }) : null,
10657
10657
  t.messages.map((m) => /* @__PURE__ */ jsx10(Message, { author: m.author, age: m.age, edited: m.edited, children: m.body }, m.id)),
10658
- t.hasReactions ? /* @__PURE__ */ jsx10(Stack4, { direction: "row", gap: 4, pad: "none", children: t.reactions.map((r) => /* @__PURE__ */ jsx10(TextButton5, { onClick: () => ui9({ kind: "react", id: r.threadId, emoji: r.emoji, on: r.reactTo }), children: r.label }, r.emoji)) }) : null,
10658
+ t.hasReactions ? /* @__PURE__ */ jsx10(Stack4, { direction: "row", gap: 4, pad: "none", children: t.reactions.map((r) => /* @__PURE__ */ jsx10(TextButton5, { onClick: () => ui10({ kind: "react", id: r.threadId, emoji: r.emoji, on: r.reactTo }), children: r.label }, r.emoji)) }) : null,
10659
10659
  t.replying ? /* @__PURE__ */ jsxs9(Stack4, { direction: "row", gap: 4, pad: "none", children: [
10660
- /* @__PURE__ */ jsx10(Input4, { value: t.replyDraft, placeholder: "Reply", autoFocus: true, label: "Reply", onChange: (value) => ui9({ kind: "replyDraft", value }), onKeyDown: (e) => ui9({ kind: "replyKey", id: t.id, key: e.key, shift: e.shiftKey }) }),
10661
- /* @__PURE__ */ jsx10(TextButton5, { onClick: () => ui9({ kind: "reply", id: t.id }), children: "Send" })
10660
+ /* @__PURE__ */ jsx10(Input4, { value: t.replyDraft, placeholder: "Reply", autoFocus: true, label: "Reply", onChange: (value) => ui10({ kind: "replyDraft", value }), onKeyDown: (e) => ui10({ kind: "replyKey", id: t.id, key: e.key, shift: e.shiftKey }) }),
10661
+ /* @__PURE__ */ jsx10(TextButton5, { onClick: () => ui10({ kind: "reply", id: t.id }), children: "Send" })
10662
10662
  ] }) : null,
10663
10663
  t.idle ? /* @__PURE__ */ jsxs9(Stack4, { direction: "row", gap: 6, pad: "none", children: [
10664
- /* @__PURE__ */ jsx10(TextButton5, { onClick: () => ui9({ kind: "startReply", id: t.id }), children: "Reply" }),
10665
- /* @__PURE__ */ jsx10(TextButton5, { onClick: () => ui9({ kind: "resolve", id: t.id, resolved: t.resolveTo }), children: t.resolveLabel }),
10666
- /* @__PURE__ */ jsx10(TextButton5, { onClick: () => ui9({ kind: "remove", id: t.id }), children: "Delete" })
10664
+ /* @__PURE__ */ jsx10(TextButton5, { onClick: () => ui10({ kind: "startReply", id: t.id }), children: "Reply" }),
10665
+ /* @__PURE__ */ jsx10(TextButton5, { onClick: () => ui10({ kind: "resolve", id: t.id, resolved: t.resolveTo }), children: t.resolveLabel }),
10666
+ /* @__PURE__ */ jsx10(TextButton5, { onClick: () => ui10({ kind: "remove", id: t.id }), children: "Delete" })
10667
10667
  ] }) : null
10668
10668
  ] }, t.id);
10669
10669
  return /* @__PURE__ */ jsxs9(Column7, { children: [
10670
10670
  /* @__PURE__ */ jsx10(
10671
10671
  Toolbar5,
10672
10672
  {
10673
- left: /* @__PURE__ */ jsx10(SegmentedControl2, { label: "Show", options: view.shows, value: view.show, onChange: (show) => ui9({ kind: "show", show }) }),
10674
- right: /* @__PURE__ */ jsx10(ToolbarGroup3, { end: true, children: /* @__PURE__ */ jsx10(SegmentedControl2, { label: "Sort", options: view.sorts, value: view.sort, onChange: (sort) => ui9({ kind: "sort", sort }) }) })
10673
+ left: /* @__PURE__ */ jsx10(SegmentedControl2, { label: "Show", options: view.shows, value: view.show, onChange: (show) => ui10({ kind: "show", show }) }),
10674
+ right: /* @__PURE__ */ jsx10(ToolbarGroup3, { end: true, children: /* @__PURE__ */ jsx10(SegmentedControl2, { label: "Sort", options: view.sorts, value: view.sort, onChange: (sort) => ui10({ kind: "sort", sort }) }) })
10675
10675
  }
10676
10676
  ),
10677
10677
  view.orphanedNotice ? /* @__PURE__ */ jsxs9(Note, { children: [
10678
10678
  view.orphanedNotice,
10679
- view.orphanedHidden ? /* @__PURE__ */ jsx10(TextButton5, { onClick: () => ui9({ kind: "showOrphaned" }), children: "Show" }) : null
10679
+ view.orphanedHidden ? /* @__PURE__ */ jsx10(TextButton5, { onClick: () => ui10({ kind: "showOrphaned" }), children: "Show" }) : null
10680
10680
  ] }) : null,
10681
10681
  /* @__PURE__ */ jsxs9(ScrollArea5, { children: [
10682
10682
  view.filteredEmpty ? /* @__PURE__ */ jsx10(EmptyState6, { title: "Nothing matches this filter", hint: view.filteredHint }) : null,
@@ -10685,8 +10685,8 @@ function CommentsPanelView({ controller, ...options }) {
10685
10685
  view.hasResolved ? /* @__PURE__ */ jsx10(Section4, { title: view.resolvedTitle, flush: true, children: view.resolved.map(card) }) : null
10686
10686
  ] }),
10687
10687
  /* @__PURE__ */ jsxs9(Stack4, { gap: 2, pad: "gutter", className: "xeno-comments-composer", children: [
10688
- /* @__PURE__ */ jsx10(TextArea2, { value: view.draft, placeholder: view.placeholder, disabled: view.composerDisabled, rows: 2, label: "New comment", onChange: (value) => ui9({ kind: "draft", value }), onKeyDown: (e) => ui9({ kind: "draftKey", key: e.key, ctrl: e.ctrlKey, meta: e.metaKey }) }),
10689
- /* @__PURE__ */ jsx10(Toolbar5, { divided: false, right: /* @__PURE__ */ jsx10(ToolbarGroup3, { end: true, children: /* @__PURE__ */ jsx10(TextButton5, { strong: true, disabled: view.commentDisabled, onClick: () => ui9({ kind: "create" }), children: "Comment" }) }) })
10688
+ /* @__PURE__ */ jsx10(TextArea2, { value: view.draft, placeholder: view.placeholder, disabled: view.composerDisabled, rows: 2, label: "New comment", onChange: (value) => ui10({ kind: "draft", value }), onKeyDown: (e) => ui10({ kind: "draftKey", key: e.key, ctrl: e.ctrlKey, meta: e.metaKey }) }),
10689
+ /* @__PURE__ */ jsx10(Toolbar5, { divided: false, right: /* @__PURE__ */ jsx10(ToolbarGroup3, { end: true, children: /* @__PURE__ */ jsx10(TextButton5, { strong: true, disabled: view.commentDisabled, onClick: () => ui10({ kind: "create" }), children: "Comment" }) }) })
10690
10690
  ] }),
10691
10691
  /* @__PURE__ */ jsx10(StatusBar6, { left: view.countLabel, right: view.staleLabel })
10692
10692
  ] });
@@ -11855,11 +11855,104 @@ var nodegraphManifest = {
11855
11855
 
11856
11856
  // src/edit/nodegraph/react/NodeGraphPanelView.tsx
11857
11857
  import { useCallback as useCallback7, useEffect as useEffect7, useRef as useRef8, useSyncExternalStore as useSyncExternalStore9 } from "react";
11858
- import { EmptyState as EmptyState7, StatusBar as StatusBar7, Toolbar as Toolbar6, ToolbarGroup as ToolbarGroup4 } from "@xenosystem/components/chrome";
11858
+ 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";
11859
+
11860
+ // src/edit/nodegraph/declaration.ts
11861
+ function nodegraphViewState(c, _options = {}) {
11862
+ const state = c.getState();
11863
+ const total = state.graph?.nodes.length ?? 0;
11864
+ return {
11865
+ empty: total === 0,
11866
+ drawn: total > 0,
11867
+ nodesLabel: `${total} node${total === 1 ? "" : "s"}`,
11868
+ zoomLabel: `${Math.round(state.scale.zoom * 100)}%`
11869
+ };
11870
+ }
11871
+ function applyNodeGraphUi(c, intent) {
11872
+ switch (intent.kind) {
11873
+ case "fit":
11874
+ c.fit(false);
11875
+ break;
11876
+ case "fitSelection":
11877
+ c.fit(true);
11878
+ break;
11879
+ }
11880
+ }
11881
+ var nodegraphViewManifest = {
11882
+ id: nodegraphManifest.id,
11883
+ version: "1.0.0",
11884
+ title: "Node Graph",
11885
+ category: "edit",
11886
+ layout: { slot: "center" },
11887
+ inputs: [{ id: "view", type: "object", label: "View state", description: "The NodeGraphViewModel the runtime derives from the controller on every draw." }],
11888
+ outputs: [{ id: "ui", type: "object", label: "UI intent", description: "{ kind } \u2014 applied by the runtime to the controller." }],
11889
+ commands: []
11890
+ };
11891
+ var EMPTY8 = { empty: true, drawn: false, nodesLabel: "0 nodes", zoomLabel: "100%" };
11892
+ var BEHAVIOURS8 = {
11893
+ "edit/nodegraphPanelView": (inputs) => inputs.view ?? EMPTY8
11894
+ };
11895
+ var text8 = (b) => ({ component: "text", props: { text: b } });
11896
+ var ui8 = (kind) => ({ emit: "ui", value: { object: { kind: { value: kind } } } });
11897
+ var NODEGRAPH_DECLARATION = {
11898
+ format: "xeno.block@1",
11899
+ manifest: nodegraphViewManifest,
11900
+ behaviour: "edit/nodegraphPanelView",
11901
+ composition: {
11902
+ component: "chrome/Column",
11903
+ children: [
11904
+ {
11905
+ component: "chrome/Toolbar",
11906
+ props: {
11907
+ right: {
11908
+ node: {
11909
+ component: "chrome/ToolbarGroup",
11910
+ props: { end: { value: true } },
11911
+ children: [
11912
+ { component: "chrome/TextButton", children: [text8({ value: "Fit" })], on: { onClick: ui8("fit") } },
11913
+ { component: "chrome/TextButton", children: [text8({ value: "Fit selection" })], on: { onClick: ui8("fitSelection") } }
11914
+ ]
11915
+ }
11916
+ }
11917
+ }
11918
+ },
11919
+ { component: "chrome/EmptyState", when: { input: "view.empty" }, props: { title: { value: "Empty graph" }, hint: { value: "Wire a host graph into this panel's input." } } },
11920
+ { component: "nodegraph/Surface", when: { input: "view.drawn" } },
11921
+ {
11922
+ component: "chrome/StatusBar",
11923
+ props: {
11924
+ left: { node: { component: "chrome/Text", props: { role: { value: "number" } }, children: [text8({ input: "view.nodesLabel" })] } },
11925
+ right: { node: { component: "chrome/Text", props: { role: { value: "number" } }, children: [text8({ input: "view.zoomLabel" })] } }
11926
+ }
11927
+ }
11928
+ ]
11929
+ }
11930
+ };
11931
+
11932
+ // src/edit/nodegraph/react/NodeGraphPanelView.tsx
11859
11933
  import { Fragment as Fragment7, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
11860
11934
  var HEADER_H2 = 24;
11861
11935
  var PORT_ROW_H2 = 18;
11862
- function NodeGraphPanelView({ controller }) {
11936
+ function NodeGraphPanelView({ controller, ...options }) {
11937
+ useSyncExternalStore9(controller.subscribe, controller.getState, controller.getState);
11938
+ const view = nodegraphViewState(controller, options);
11939
+ const ui10 = (intent) => applyNodeGraphUi(controller, intent);
11940
+ return /* @__PURE__ */ jsxs10(Column8, { children: [
11941
+ /* @__PURE__ */ jsx11(
11942
+ Toolbar6,
11943
+ {
11944
+ right: /* @__PURE__ */ jsxs10(ToolbarGroup4, { end: true, children: [
11945
+ /* @__PURE__ */ jsx11(TextButton6, { onClick: () => ui10({ kind: "fit" }), children: "Fit" }),
11946
+ /* @__PURE__ */ jsx11(TextButton6, { onClick: () => ui10({ kind: "fitSelection" }), children: "Fit selection" })
11947
+ ] })
11948
+ }
11949
+ ),
11950
+ view.empty ? /* @__PURE__ */ jsx11(EmptyState7, { title: "Empty graph", hint: "Wire a host graph into this panel's input." }) : null,
11951
+ view.drawn ? /* @__PURE__ */ jsx11(NodeGraphSurface, { controller }) : null,
11952
+ /* @__PURE__ */ jsx11(StatusBar7, { left: /* @__PURE__ */ jsx11(Text8, { role: "number", children: view.nodesLabel }), right: /* @__PURE__ */ jsx11(Text8, { role: "number", children: view.zoomLabel }) })
11953
+ ] });
11954
+ }
11955
+ function NodeGraphSurface({ controller }) {
11863
11956
  const state = useSyncExternalStore9(controller.subscribe, controller.getState, controller.getState);
11864
11957
  const containerRef = useRef8(null);
11865
11958
  useEffect7(() => {
@@ -11867,7 +11960,7 @@ function NodeGraphPanelView({ controller }) {
11867
11960
  if (!el) return;
11868
11961
  const measure = () => {
11869
11962
  const rect = el.getBoundingClientRect();
11870
- controller.resize(rect.width, rect.height);
11963
+ if (rect.width > 0 && rect.height > 0) controller.resize(rect.width, rect.height);
11871
11964
  };
11872
11965
  measure();
11873
11966
  if (typeof ResizeObserver === "undefined") return;
@@ -11934,91 +12027,69 @@ function NodeGraphPanelView({ controller }) {
11934
12027
  const preview = state.preview;
11935
12028
  const selectedNodes = new Set(state.selection.nodeIds);
11936
12029
  const selectedEdges = new Set(state.selection.edgeIds);
11937
- const total = state.graph?.nodes.length ?? 0;
11938
- return /* @__PURE__ */ jsxs10("div", { style: SHELL, children: [
11939
- /* @__PURE__ */ jsx11(
11940
- Toolbar6,
11941
- {
11942
- right: /* @__PURE__ */ jsxs10(ToolbarGroup4, { end: true, children: [
11943
- /* @__PURE__ */ jsx11("button", { type: "button", style: button(), onClick: () => controller.fit(false), children: "Fit" }),
11944
- /* @__PURE__ */ jsx11("button", { type: "button", style: button(), onClick: () => controller.fit(true), children: "Fit selection" })
11945
- ] })
11946
- }
11947
- ),
11948
- total === 0 ? /* @__PURE__ */ jsx11(EmptyState7, { title: "Empty graph", hint: "Wire a host graph into this panel's input." }) : /* @__PURE__ */ jsxs10(
11949
- "div",
11950
- {
11951
- ref: containerRef,
11952
- tabIndex: 0,
11953
- role: "application",
11954
- "aria-label": "Node graph",
11955
- style: SURFACE2,
11956
- onWheel,
11957
- onPointerDown,
11958
- onPointerMove,
11959
- onPointerUp,
11960
- onPointerCancel: onPointerUp,
11961
- onKeyDown,
11962
- children: [
11963
- /* @__PURE__ */ jsx11(
11964
- "svg",
11965
- {
11966
- "data-canvas": "nodegraph-surface",
11967
- width: "100%",
11968
- height: "100%",
11969
- style: { position: "absolute", inset: 0, display: "block" },
11970
- children: /* @__PURE__ */ jsxs10("g", { transform: `translate(${-scale.x * scale.zoom} ${-scale.y * scale.zoom}) scale(${scale.zoom})`, children: [
11971
- state.edges.map(({ edge, from, to }) => /* @__PURE__ */ jsx11(
11972
- "path",
11973
- {
11974
- d: edgePath(from, to),
11975
- fill: "none",
11976
- stroke: selectedEdges.has(edge.id) ? "var(--xeno-text)" : "var(--xeno-active)",
11977
- strokeWidth: selectedEdges.has(edge.id) ? 2 / scale.zoom : 1.5 / scale.zoom,
11978
- opacity: edge.disabled ? 0.35 : 1
11979
- },
11980
- edge.id
11981
- )),
11982
- preview?.connection ? /* @__PURE__ */ jsx11(PendingWire, { controller, preview, zoom: scale.zoom }) : null,
11983
- state.nodes.map((node) => /* @__PURE__ */ jsx11(
11984
- NodeRect,
11985
- {
11986
- node,
11987
- selected: selectedNodes.has(node.id),
11988
- zoom: scale.zoom
11989
- },
11990
- node.id
11991
- )),
11992
- preview?.marquee ? /* @__PURE__ */ jsx11(
11993
- "rect",
11994
- {
11995
- x: preview.marquee.x,
11996
- y: preview.marquee.y,
11997
- width: preview.marquee.width,
11998
- height: preview.marquee.height,
11999
- fill: "var(--xeno-border-subtle)",
12000
- stroke: "var(--xeno-active)",
12001
- strokeWidth: 1 / scale.zoom
12002
- }
12003
- ) : null
12004
- ] })
12005
- }
12006
- ),
12007
- preview?.connection && !preview.connection.verdict.ok && preview.connection.target ? /* @__PURE__ */ jsx11("div", { style: REASON, children: preview.connection.verdict.reason }) : null
12008
- ]
12009
- }
12010
- ),
12011
- /* @__PURE__ */ jsx11(
12012
- StatusBar7,
12013
- {
12014
- left: `${total} node${total === 1 ? "" : "s"}`,
12015
- right: /* @__PURE__ */ jsxs10("span", { className: "tabular-nums", children: [
12016
- Math.round(scale.zoom * 100),
12017
- "%"
12018
- ] })
12019
- }
12020
- )
12021
- ] });
12030
+ return /* @__PURE__ */ jsxs10(
12031
+ "div",
12032
+ {
12033
+ ref: containerRef,
12034
+ tabIndex: 0,
12035
+ role: "application",
12036
+ "aria-label": "Node graph",
12037
+ style: SURFACE2,
12038
+ onWheel,
12039
+ onPointerDown,
12040
+ onPointerMove,
12041
+ onPointerUp,
12042
+ onPointerCancel: onPointerUp,
12043
+ onKeyDown,
12044
+ children: [
12045
+ /* @__PURE__ */ jsx11(
12046
+ "svg",
12047
+ {
12048
+ "data-canvas": "nodegraph-surface",
12049
+ width: "100%",
12050
+ height: "100%",
12051
+ style: { position: "absolute", inset: 0, display: "block" },
12052
+ children: /* @__PURE__ */ jsxs10("g", { transform: `translate(${-scale.x * scale.zoom} ${-scale.y * scale.zoom}) scale(${scale.zoom})`, children: [
12053
+ state.edges.map(({ edge, from, to }) => /* @__PURE__ */ jsx11(
12054
+ "path",
12055
+ {
12056
+ d: edgePath(from, to),
12057
+ fill: "none",
12058
+ stroke: selectedEdges.has(edge.id) ? "var(--xeno-text)" : "var(--xeno-active)",
12059
+ strokeWidth: selectedEdges.has(edge.id) ? 2 / scale.zoom : 1.5 / scale.zoom,
12060
+ opacity: edge.disabled ? 0.35 : 1
12061
+ },
12062
+ edge.id
12063
+ )),
12064
+ preview?.connection ? /* @__PURE__ */ jsx11(PendingWire, { controller, preview, zoom: scale.zoom }) : null,
12065
+ state.nodes.map((node) => /* @__PURE__ */ jsx11(
12066
+ NodeRect,
12067
+ {
12068
+ node,
12069
+ selected: selectedNodes.has(node.id),
12070
+ zoom: scale.zoom
12071
+ },
12072
+ node.id
12073
+ )),
12074
+ preview?.marquee ? /* @__PURE__ */ jsx11(
12075
+ "rect",
12076
+ {
12077
+ x: preview.marquee.x,
12078
+ y: preview.marquee.y,
12079
+ width: preview.marquee.width,
12080
+ height: preview.marquee.height,
12081
+ fill: "var(--xeno-border-subtle)",
12082
+ stroke: "var(--xeno-active)",
12083
+ strokeWidth: 1 / scale.zoom
12084
+ }
12085
+ ) : null
12086
+ ] })
12087
+ }
12088
+ ),
12089
+ preview?.connection && !preview.connection.verdict.ok && preview.connection.target ? /* @__PURE__ */ jsx11("div", { style: REASON, children: preview.connection.verdict.reason }) : null
12090
+ ]
12091
+ }
12092
+ );
12022
12093
  }
12023
12094
  function PendingWire({
12024
12095
  controller,
@@ -12139,7 +12210,6 @@ function Port({
12139
12210
  )
12140
12211
  ] });
12141
12212
  }
12142
- var SHELL = { display: "flex", flexDirection: "column", height: "100%", minHeight: 0 };
12143
12213
  var SURFACE2 = {
12144
12214
  position: "relative",
12145
12215
  flex: 1,
@@ -12161,17 +12231,9 @@ var REASON = {
12161
12231
  color: "var(--xeno-text)",
12162
12232
  pointerEvents: "none"
12163
12233
  };
12164
- function button() {
12165
- return {
12166
- height: 18,
12167
- padding: "0 6px",
12168
- fontSize: 10,
12169
- borderRadius: 2,
12170
- border: "1px solid var(--xeno-control)",
12171
- background: "transparent",
12172
- color: "var(--xeno-muted)",
12173
- cursor: "pointer"
12174
- };
12234
+ var NODEGRAPH_RUNTIME_UNITS = ["nodegraph/Surface"];
12235
+ function nodegraphRuntimeComponents(controller) {
12236
+ return { "nodegraph/Surface": () => /* @__PURE__ */ jsx11(NodeGraphSurface, { controller }) };
12175
12237
  }
12176
12238
 
12177
12239
  // src/edit/nodegraph/panel.ts
@@ -12828,12 +12890,12 @@ var TreeController = class {
12828
12890
  }
12829
12891
  if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
12830
12892
  const fresh = now - this.typeAhead.at > this.typeAheadMs;
12831
- const text9 = (fresh ? "" : this.typeAhead.text) + event.key.toLowerCase();
12832
- this.typeAhead = { text: text9, at: now };
12893
+ const text10 = (fresh ? "" : this.typeAhead.text) + event.key.toLowerCase();
12894
+ this.typeAhead = { text: text10, at: now };
12833
12895
  const from = fresh ? current : current + 1;
12834
12896
  for (let i = 0; i < rows.length; i += 1) {
12835
12897
  const candidate = rows[(from + i) % rows.length];
12836
- if (candidate.node.label.toLowerCase().startsWith(text9)) {
12898
+ if (candidate.node.label.toLowerCase().startsWith(text10)) {
12837
12899
  this.focusedId = candidate.id;
12838
12900
  this.select([candidate.id]);
12839
12901
  return true;
@@ -12859,9 +12921,9 @@ var TreeController = class {
12859
12921
  return true;
12860
12922
  }
12861
12923
  /** Update the rename draft. */
12862
- updateRenameDraft(text9) {
12924
+ updateRenameDraft(text10) {
12863
12925
  if (!this.renaming) return;
12864
- this.renaming = { ...this.renaming, draft: text9 };
12926
+ this.renaming = { ...this.renaming, draft: text10 };
12865
12927
  this.notify();
12866
12928
  }
12867
12929
  /**
@@ -13401,7 +13463,7 @@ var treeManifest = {
13401
13463
  import { useCallback as useCallback8, useEffect as useEffect8, useRef as useRef9, useSyncExternalStore as useSyncExternalStore10 } from "react";
13402
13464
  import {
13403
13465
  Badge as Badge7,
13404
- Column as Column8,
13466
+ Column as Column9,
13405
13467
  EmptyState as EmptyState8,
13406
13468
  ErrorState,
13407
13469
  IconButton as IconButton7,
@@ -13412,8 +13474,8 @@ import {
13412
13474
  ScrollArea as ScrollArea6,
13413
13475
  SearchField as SearchField5,
13414
13476
  StatusBar as StatusBar8,
13415
- Text as Text8,
13416
- TextButton as TextButton6,
13477
+ Text as Text9,
13478
+ TextButton as TextButton7,
13417
13479
  Toolbar as Toolbar7,
13418
13480
  ToolbarGroup as ToolbarGroup5,
13419
13481
  VirtualWindow as VirtualWindow3
@@ -13575,7 +13637,7 @@ var treeViewManifest = {
13575
13637
  outputs: [{ id: "ui", type: "object", label: "UI intent", description: "{ kind, id?, value?, key?, actionId?, x?, y?, ctrlKey?, metaKey?, shiftKey?, altKey? } \u2014 applied by the runtime to the controller." }],
13576
13638
  commands: []
13577
13639
  };
13578
- var EMPTY8 = {
13640
+ var EMPTY9 = {
13579
13641
  searchShown: true,
13580
13642
  filter: "",
13581
13643
  noSource: true,
@@ -13596,16 +13658,16 @@ var EMPTY8 = {
13596
13658
  rows: [],
13597
13659
  countLabel: "0 items"
13598
13660
  };
13599
- var BEHAVIOURS8 = {
13600
- "edit/treePanelView": (inputs) => inputs.view ?? EMPTY8
13661
+ var BEHAVIOURS9 = {
13662
+ "edit/treePanelView": (inputs) => inputs.view ?? EMPTY9
13601
13663
  };
13602
- var text8 = (b) => ({ component: "text", props: { text: b } });
13603
- var ui8 = (kind, fields = {}) => ({ emit: "ui", value: { object: { kind: { value: kind }, ...fields } } });
13664
+ var text9 = (b) => ({ component: "text", props: { text: b } });
13665
+ var ui9 = (kind, fields = {}) => ({ emit: "ui", value: { object: { kind: { value: kind }, ...fields } } });
13604
13666
  var nodeIcon = () => ({
13605
13667
  component: "fragment",
13606
13668
  children: [
13607
13669
  { component: "icons/TreeKind", when: { item: "iconName" }, props: { name: { item: "iconName" } } },
13608
- { component: "chrome/Text", when: { item: "iconText" }, props: { role: { value: "caption" } }, children: [text8({ item: "iconText" })] }
13670
+ { component: "chrome/Text", when: { item: "iconText" }, props: { role: { value: "caption" } }, children: [text9({ item: "iconText" })] }
13609
13671
  ]
13610
13672
  });
13611
13673
  var TREE_DECLARATION = {
@@ -13618,15 +13680,15 @@ var TREE_DECLARATION = {
13618
13680
  {
13619
13681
  component: "chrome/Toolbar",
13620
13682
  props: {
13621
- left: { node: { component: "chrome/SearchField", when: { input: "view.searchShown" }, props: { value: { input: "view.filter" }, placeholder: { value: "Filter\u2026" } }, on: { onChange: ui8("filter", { value: { arg: "" } }) } } },
13683
+ left: { node: { component: "chrome/SearchField", when: { input: "view.searchShown" }, props: { value: { input: "view.filter" }, placeholder: { value: "Filter\u2026" } }, on: { onChange: ui9("filter", { value: { arg: "" } }) } } },
13622
13684
  right: {
13623
13685
  node: {
13624
13686
  component: "chrome/ToolbarGroup",
13625
13687
  props: { end: { value: true } },
13626
13688
  children: [
13627
- { component: "chrome/IconButton", props: { icon: { node: { component: "icons/Expand" } }, label: { value: "Expand all" } }, on: { onClick: ui8("expandAll") } },
13628
- { component: "chrome/IconButton", props: { icon: { node: { component: "icons/Collapse" } }, label: { value: "Collapse all" } }, on: { onClick: ui8("collapseAll") } },
13629
- { component: "chrome/IconButton", props: { icon: { node: { component: "icons/Refresh" } }, label: { value: "Refresh" } }, on: { onClick: ui8("refresh") } }
13689
+ { component: "chrome/IconButton", props: { icon: { node: { component: "icons/Expand" } }, label: { value: "Expand all" } }, on: { onClick: ui9("expandAll") } },
13690
+ { component: "chrome/IconButton", props: { icon: { node: { component: "icons/Collapse" } }, label: { value: "Collapse all" } }, on: { onClick: ui9("collapseAll") } },
13691
+ { component: "chrome/IconButton", props: { icon: { node: { component: "icons/Refresh" } }, label: { value: "Refresh" } }, on: { onClick: ui9("refresh") } }
13630
13692
  ]
13631
13693
  }
13632
13694
  }
@@ -13634,7 +13696,7 @@ var TREE_DECLARATION = {
13634
13696
  },
13635
13697
  { component: "chrome/EmptyState", when: { input: "view.noSource" }, props: { title: { value: "No source" }, hint: { input: "view.noSourceHint" } } },
13636
13698
  { component: "chrome/LoadingState", when: { input: "view.loading" }, props: { label: { input: "view.loadingLabel" } } },
13637
- { component: "chrome/ErrorState", when: { input: "view.failed" }, props: { title: { input: "view.failedTitle" }, message: { input: "view.failedMessage" }, retryLabel: { input: "view.retryLabel" } }, on: { onRetry: ui8("retry") } },
13699
+ { component: "chrome/ErrorState", when: { input: "view.failed" }, props: { title: { input: "view.failedTitle" }, message: { input: "view.failedMessage" }, retryLabel: { input: "view.retryLabel" } }, on: { onRetry: ui9("retry") } },
13638
13700
  { component: "chrome/EmptyState", when: { input: "view.noMatches" }, props: { title: { value: "No matches" }, hint: { input: "view.noMatchesHint" } } },
13639
13701
  { component: "chrome/EmptyState", when: { input: "view.emptyTree" }, props: { title: { value: "Nothing here" }, hint: { input: "view.emptyHint" } } },
13640
13702
  {
@@ -13667,7 +13729,7 @@ var TREE_DECLARATION = {
13667
13729
  node: {
13668
13730
  component: "fragment",
13669
13731
  children: [
13670
- { component: "chrome/Input", when: { item: "renaming" }, props: { autoFocus: { value: true }, value: { item: "draft" }, label: { value: "Name" } }, on: { onChange: ui8("renameDraft", { value: { arg: "" } }), onBlur: ui8("commitRename"), onKeyDown: ui8("renameKey", { key: { arg: "key" } }) } },
13732
+ { component: "chrome/Input", when: { item: "renaming" }, props: { autoFocus: { value: true }, value: { item: "draft" }, label: { value: "Name" } }, on: { onChange: ui9("renameDraft", { value: { arg: "" } }), onBlur: ui9("commitRename"), onKeyDown: ui9("renameKey", { key: { arg: "key" } }) } },
13671
13733
  { component: "text", when: { not: { item: "renaming" } }, props: { text: { item: "label" } } }
13672
13734
  ]
13673
13735
  }
@@ -13676,11 +13738,11 @@ var TREE_DECLARATION = {
13676
13738
  node: {
13677
13739
  component: "fragment",
13678
13740
  children: [
13679
- { component: "chrome/Text", when: { item: "chipLoading" }, props: { role: { value: "caption" } }, children: [text8({ value: "loading\u2026" })] },
13680
- { component: "chrome/Badge", when: { item: "chipError" }, props: { tone: { value: "error" } }, children: [text8({ item: "chipErrorText" })] },
13681
- { component: "chrome/TextButton", when: { item: "chipLoadMore" }, children: [text8({ value: "load more\u2026" })], on: { onClick: ui8("loadMore", { id: { item: "id" } }) } },
13682
- { component: "chrome/Badge", when: { item: "chipTruncated" }, props: { tone: { value: "warning" } }, children: [text8({ item: "chipTruncatedText" })] },
13683
- { component: "chrome/Text", when: { item: "chipEmpty" }, props: { role: { value: "caption" } }, children: [text8({ value: "empty" })] }
13741
+ { component: "chrome/Text", when: { item: "chipLoading" }, props: { role: { value: "caption" } }, children: [text9({ value: "loading\u2026" })] },
13742
+ { component: "chrome/Badge", when: { item: "chipError" }, props: { tone: { value: "error" } }, children: [text9({ item: "chipErrorText" })] },
13743
+ { component: "chrome/TextButton", when: { item: "chipLoadMore" }, children: [text9({ value: "load more\u2026" })], on: { onClick: ui9("loadMore", { id: { item: "id" } }) } },
13744
+ { component: "chrome/Badge", when: { item: "chipTruncated" }, props: { tone: { value: "warning" } }, children: [text9({ item: "chipTruncatedText" })] },
13745
+ { component: "chrome/Text", when: { item: "chipEmpty" }, props: { role: { value: "caption" } }, children: [text9({ value: "empty" })] }
13684
13746
  ]
13685
13747
  }
13686
13748
  },
@@ -13688,19 +13750,19 @@ var TREE_DECLARATION = {
13688
13750
  node: {
13689
13751
  component: "fragment",
13690
13752
  children: [
13691
- { component: "chrome/Text", each: { item: "columns", key: "key" }, props: { role: { value: "number" } }, children: [text8({ item: "text" })] },
13753
+ { component: "chrome/Text", each: { item: "columns", key: "key" }, props: { role: { value: "number" } }, children: [text9({ item: "text" })] },
13692
13754
  { component: "chrome/Text", each: { item: "glyphs", key: "key" }, props: { role: { value: "meta" }, title: { item: "title" } }, children: [nodeIcon()] },
13693
- { component: "chrome/Badge", each: { item: "badges", key: "key" }, props: { tone: { item: "tone" } }, children: [text8({ item: "text" })] },
13694
- { component: "chrome/IconButton", each: { item: "actions", key: "key" }, props: { size: { value: "sm" }, icon: { node: nodeIcon() }, label: { item: "label" }, disabled: { item: "disabled" } }, on: { onClick: ui8("action", { id: { item: "rowId" }, actionId: { item: "actionId" } }) } }
13755
+ { component: "chrome/Badge", each: { item: "badges", key: "key" }, props: { tone: { item: "tone" } }, children: [text9({ item: "text" })] },
13756
+ { component: "chrome/IconButton", each: { item: "actions", key: "key" }, props: { size: { value: "sm" }, icon: { node: nodeIcon() }, label: { item: "label" }, disabled: { item: "disabled" } }, on: { onClick: ui9("action", { id: { item: "rowId" }, actionId: { item: "actionId" } }) } }
13695
13757
  ]
13696
13758
  }
13697
13759
  }
13698
13760
  },
13699
13761
  on: {
13700
- onExpandedChange: ui8("toggleExpanded", { id: { item: "id" } }),
13701
- onClick: ui8("click", { id: { item: "id" }, ctrlKey: { arg: "ctrlKey" }, metaKey: { arg: "metaKey" }, shiftKey: { arg: "shiftKey" }, altKey: { arg: "altKey" } }),
13702
- onDoubleClick: ui8("doubleClick", { id: { item: "id" } }),
13703
- onContextMenuAt: ui8("contextMenu", { id: { item: "id" }, x: { arg: "" }, y: { arg: "", index: 1 } })
13762
+ onExpandedChange: ui9("toggleExpanded", { id: { item: "id" } }),
13763
+ onClick: ui9("click", { id: { item: "id" }, ctrlKey: { arg: "ctrlKey" }, metaKey: { arg: "metaKey" }, shiftKey: { arg: "shiftKey" }, altKey: { arg: "altKey" } }),
13764
+ onDoubleClick: ui9("doubleClick", { id: { item: "id" } }),
13765
+ onContextMenuAt: ui9("contextMenu", { id: { item: "id" }, x: { arg: "" }, y: { arg: "", index: 1 } })
13704
13766
  }
13705
13767
  }
13706
13768
  ]
@@ -13712,8 +13774,8 @@ var TREE_DECLARATION = {
13712
13774
  {
13713
13775
  component: "chrome/StatusBar",
13714
13776
  props: {
13715
- left: { node: { component: "chrome/Text", props: { role: { value: "number" } }, children: [text8({ input: "view.countLabel" })] } },
13716
- right: { node: { component: "chrome/Text", when: { input: "view.selectedLabel" }, props: { role: { value: "meta" } }, children: [text8({ input: "view.selectedLabel" })] } }
13777
+ left: { node: { component: "chrome/Text", props: { role: { value: "number" } }, children: [text9({ input: "view.countLabel" })] } },
13778
+ right: { node: { component: "chrome/Text", when: { input: "view.selectedLabel" }, props: { role: { value: "meta" } }, children: [text9({ input: "view.selectedLabel" })] } }
13717
13779
  }
13718
13780
  }
13719
13781
  ]
@@ -13726,10 +13788,10 @@ var DRAG_THRESHOLD2 = 4;
13726
13788
  function TreePanelView({ controller, ...options }) {
13727
13789
  useSyncExternalStore10(controller.subscribe, controller.getState, controller.getState);
13728
13790
  const view = treeViewState(controller, options);
13729
- const ui9 = (intent) => applyTreeUi(controller, intent, options);
13791
+ const ui10 = (intent) => applyTreeUi(controller, intent, options);
13730
13792
  const icon = (name, textValue) => /* @__PURE__ */ jsxs11(Fragment8, { children: [
13731
13793
  name ? /* @__PURE__ */ jsx12(TreeIcon, { name }) : null,
13732
- textValue ? /* @__PURE__ */ jsx12(Text8, { role: "caption", children: textValue }) : null
13794
+ textValue ? /* @__PURE__ */ jsx12(Text9, { role: "caption", children: textValue }) : null
13733
13795
  ] });
13734
13796
  const row2 = (r) => /* @__PURE__ */ jsx12(
13735
13797
  Row4,
@@ -13745,48 +13807,48 @@ function TreePanelView({ controller, ...options }) {
13745
13807
  title: r.dropTitle,
13746
13808
  icon: icon(r.iconName, r.iconText),
13747
13809
  label: /* @__PURE__ */ jsxs11(Fragment8, { children: [
13748
- r.renaming ? /* @__PURE__ */ jsx12(Input5, { autoFocus: true, value: r.draft, label: "Name", onChange: (value) => ui9({ kind: "renameDraft", value }), onBlur: () => ui9({ kind: "commitRename" }), onKeyDown: (e) => ui9({ kind: "renameKey", key: e.key }) }) : null,
13810
+ r.renaming ? /* @__PURE__ */ jsx12(Input5, { autoFocus: true, value: r.draft, label: "Name", onChange: (value) => ui10({ kind: "renameDraft", value }), onBlur: () => ui10({ kind: "commitRename" }), onKeyDown: (e) => ui10({ kind: "renameKey", key: e.key }) }) : null,
13749
13811
  !r.renaming ? r.label : null
13750
13812
  ] }),
13751
13813
  meta: /* @__PURE__ */ jsxs11(Fragment8, { children: [
13752
- r.chipLoading ? /* @__PURE__ */ jsx12(Text8, { role: "caption", children: "loading\u2026" }) : null,
13814
+ r.chipLoading ? /* @__PURE__ */ jsx12(Text9, { role: "caption", children: "loading\u2026" }) : null,
13753
13815
  r.chipError ? /* @__PURE__ */ jsx12(Badge7, { tone: "error", children: r.chipErrorText }) : null,
13754
- r.chipLoadMore ? /* @__PURE__ */ jsx12(TextButton6, { onClick: () => ui9({ kind: "loadMore", id: r.id }), children: "load more\u2026" }) : null,
13816
+ r.chipLoadMore ? /* @__PURE__ */ jsx12(TextButton7, { onClick: () => ui10({ kind: "loadMore", id: r.id }), children: "load more\u2026" }) : null,
13755
13817
  r.chipTruncated ? /* @__PURE__ */ jsx12(Badge7, { tone: "warning", children: r.chipTruncatedText }) : null,
13756
- r.chipEmpty ? /* @__PURE__ */ jsx12(Text8, { role: "caption", children: "empty" }) : null
13818
+ r.chipEmpty ? /* @__PURE__ */ jsx12(Text9, { role: "caption", children: "empty" }) : null
13757
13819
  ] }),
13758
13820
  trailing: /* @__PURE__ */ jsxs11(Fragment8, { children: [
13759
- r.columns.map((c) => /* @__PURE__ */ jsx12(Text8, { role: "number", children: c.text }, c.key)),
13760
- r.glyphs.map((g) => /* @__PURE__ */ jsx12(Text8, { role: "meta", title: g.title, children: icon(g.iconName, g.iconText) }, g.key)),
13821
+ r.columns.map((c) => /* @__PURE__ */ jsx12(Text9, { role: "number", children: c.text }, c.key)),
13822
+ r.glyphs.map((g) => /* @__PURE__ */ jsx12(Text9, { role: "meta", title: g.title, children: icon(g.iconName, g.iconText) }, g.key)),
13761
13823
  r.badges.map((b) => /* @__PURE__ */ jsx12(Badge7, { tone: b.tone, children: b.text }, b.key)),
13762
- r.actions.map((a) => /* @__PURE__ */ jsx12(IconButton7, { size: "sm", icon: icon(a.iconName, a.iconText), label: a.label, disabled: a.disabled, onClick: () => ui9({ kind: "action", id: a.rowId, actionId: a.actionId }) }, a.key))
13824
+ 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))
13763
13825
  ] }),
13764
- onExpandedChange: () => ui9({ kind: "toggleExpanded", id: r.id }),
13765
- onClick: (e) => ui9({ kind: "click", id: r.id, ctrlKey: e.ctrlKey, metaKey: e.metaKey, shiftKey: e.shiftKey, altKey: e.altKey }),
13766
- onDoubleClick: () => ui9({ kind: "doubleClick", id: r.id }),
13767
- onContextMenuAt: (x, y) => ui9({ kind: "contextMenu", id: r.id, x, y })
13826
+ onExpandedChange: () => ui10({ kind: "toggleExpanded", id: r.id }),
13827
+ onClick: (e) => ui10({ kind: "click", id: r.id, ctrlKey: e.ctrlKey, metaKey: e.metaKey, shiftKey: e.shiftKey, altKey: e.altKey }),
13828
+ onDoubleClick: () => ui10({ kind: "doubleClick", id: r.id }),
13829
+ onContextMenuAt: (x, y) => ui10({ kind: "contextMenu", id: r.id, x, y })
13768
13830
  },
13769
13831
  r.id
13770
13832
  );
13771
- return /* @__PURE__ */ jsxs11(Column8, { children: [
13833
+ return /* @__PURE__ */ jsxs11(Column9, { children: [
13772
13834
  /* @__PURE__ */ jsx12(
13773
13835
  Toolbar7,
13774
13836
  {
13775
- left: view.searchShown ? /* @__PURE__ */ jsx12(SearchField5, { value: view.filter, placeholder: "Filter\u2026", onChange: (value) => ui9({ kind: "filter", value }) }) : null,
13837
+ left: view.searchShown ? /* @__PURE__ */ jsx12(SearchField5, { value: view.filter, placeholder: "Filter\u2026", onChange: (value) => ui10({ kind: "filter", value }) }) : null,
13776
13838
  right: /* @__PURE__ */ jsxs11(ToolbarGroup5, { end: true, children: [
13777
- /* @__PURE__ */ jsx12(IconButton7, { icon: /* @__PURE__ */ jsx12(ExpandGlyph, {}), label: "Expand all", onClick: () => ui9({ kind: "expandAll" }) }),
13778
- /* @__PURE__ */ jsx12(IconButton7, { icon: /* @__PURE__ */ jsx12(CollapseGlyph, {}), label: "Collapse all", onClick: () => ui9({ kind: "collapseAll" }) }),
13779
- /* @__PURE__ */ jsx12(IconButton7, { icon: /* @__PURE__ */ jsx12(RefreshGlyph, {}), label: "Refresh", onClick: () => ui9({ kind: "refresh" }) })
13839
+ /* @__PURE__ */ jsx12(IconButton7, { icon: /* @__PURE__ */ jsx12(ExpandGlyph, {}), label: "Expand all", onClick: () => ui10({ kind: "expandAll" }) }),
13840
+ /* @__PURE__ */ jsx12(IconButton7, { icon: /* @__PURE__ */ jsx12(CollapseGlyph, {}), label: "Collapse all", onClick: () => ui10({ kind: "collapseAll" }) }),
13841
+ /* @__PURE__ */ jsx12(IconButton7, { icon: /* @__PURE__ */ jsx12(RefreshGlyph, {}), label: "Refresh", onClick: () => ui10({ kind: "refresh" }) })
13780
13842
  ] })
13781
13843
  }
13782
13844
  ),
13783
13845
  view.noSource ? /* @__PURE__ */ jsx12(EmptyState8, { title: "No source", hint: view.noSourceHint }) : null,
13784
13846
  view.loading ? /* @__PURE__ */ jsx12(LoadingState, { label: view.loadingLabel }) : null,
13785
- view.failed ? /* @__PURE__ */ jsx12(ErrorState, { title: view.failedTitle, message: view.failedMessage, retryLabel: view.retryLabel, onRetry: () => ui9({ kind: "retry" }) }) : null,
13847
+ view.failed ? /* @__PURE__ */ jsx12(ErrorState, { title: view.failedTitle, message: view.failedMessage, retryLabel: view.retryLabel, onRetry: () => ui10({ kind: "retry" }) }) : null,
13786
13848
  view.noMatches ? /* @__PURE__ */ jsx12(EmptyState8, { title: "No matches", hint: view.noMatchesHint }) : null,
13787
13849
  view.emptyTree ? /* @__PURE__ */ jsx12(EmptyState8, { title: "Nothing here", hint: view.emptyHint }) : null,
13788
13850
  view.listShown ? /* @__PURE__ */ jsx12(TreeScroller, { controller, children: /* @__PURE__ */ jsx12(RowList4, { role: "tree", "aria-label": "Tree", "aria-multiselectable": true, children: /* @__PURE__ */ jsx12(VirtualWindow3, { totalHeight: view.totalHeight, offsetTop: view.offsetTop, children: view.rows.map(row2) }) }) }) : null,
13789
- /* @__PURE__ */ jsx12(StatusBar8, { left: /* @__PURE__ */ jsx12(Text8, { role: "number", children: view.countLabel }), right: view.selectedLabel ? /* @__PURE__ */ jsx12(Text8, { role: "meta", children: view.selectedLabel }) : null })
13851
+ /* @__PURE__ */ jsx12(StatusBar8, { left: /* @__PURE__ */ jsx12(Text9, { role: "number", children: view.countLabel }), right: view.selectedLabel ? /* @__PURE__ */ jsx12(Text9, { role: "meta", children: view.selectedLabel }) : null })
13790
13852
  ] });
13791
13853
  }
13792
13854
  function TreeScroller({ controller, children }) {
@@ -14127,10 +14189,14 @@ export {
14127
14189
  LayersPanelController,
14128
14190
  LayersPanelView,
14129
14191
  MIXED,
14192
+ BEHAVIOURS8 as NODEGRAPH_BEHAVIOURS,
14193
+ NODEGRAPH_DECLARATION,
14130
14194
  NODEGRAPH_PANEL_ID,
14195
+ NODEGRAPH_RUNTIME_UNITS,
14131
14196
  NodeGraphPanelView,
14197
+ NodeGraphSurface,
14132
14198
  SPACE_LABEL,
14133
- BEHAVIOURS8 as TREE_BEHAVIOURS,
14199
+ BEHAVIOURS9 as TREE_BEHAVIOURS,
14134
14200
  TREE_DECLARATION,
14135
14201
  TREE_PANEL_ID,
14136
14202
  TREE_RUNTIME_UNITS,
@@ -14158,6 +14224,7 @@ export {
14158
14224
  applyHistoryUi,
14159
14225
  applyInspectorUi,
14160
14226
  applyLayersUi,
14227
+ applyNodeGraphUi,
14161
14228
  applyPrecision,
14162
14229
  applyTangentDrag,
14163
14230
  applyTreeUi,
@@ -14280,6 +14347,9 @@ export {
14280
14347
  nodeBounds,
14281
14348
  nodegraphManifest,
14282
14349
  nodegraphPanel,
14350
+ nodegraphRuntimeComponents,
14351
+ nodegraphViewManifest,
14352
+ nodegraphViewState,
14283
14353
  normalizeColorInput,
14284
14354
  normalizeHistoryState,
14285
14355
  normalizeKindKey,