@xenosystem/blocks 0.12.5 → 0.12.6

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.
@@ -882,15 +882,15 @@ var LayersPanelController = class {
882
882
  requestVisibleThumbnails() {
883
883
  if (!this.thumbnailsEnabled) return;
884
884
  if (!this.getColumns().includes("thumbnail")) return;
885
- for (const row of this.getWindowRows()) {
886
- const key = row.node.thumbnailKey;
885
+ for (const row2 of this.getWindowRows()) {
886
+ const key = row2.node.thumbnailKey;
887
887
  if (!key || this.thumbnails.has(key) || this.requestedThumbs.has(key)) continue;
888
888
  this.requestedThumbs.add(key);
889
889
  const request = {
890
890
  key,
891
891
  width: this.thumbnailSize,
892
892
  height: this.thumbnailSize,
893
- nodeId: row.id
893
+ nodeId: row2.id
894
894
  };
895
895
  this.host.emit("thumbnailRequest", request);
896
896
  }
@@ -1216,22 +1216,22 @@ function layersViewState(c) {
1216
1216
  filter: c.getFilter(),
1217
1217
  totalHeight: window_.totalHeight,
1218
1218
  offsetTop: window_.offsetTop,
1219
- rows: c.getWindowRows().map((row) => {
1220
- const node = row.node;
1219
+ rows: c.getWindowRows().map((row2) => {
1220
+ const node = row2.node;
1221
1221
  const container = isContainer(node);
1222
1222
  return {
1223
- id: row.id,
1223
+ id: row2.id,
1224
1224
  name: node.name,
1225
1225
  title: node.name,
1226
- depth: row.depth,
1226
+ depth: row2.depth,
1227
1227
  height: rowHeight,
1228
- selected: c.isSelected(row.id),
1229
- active: activeId === row.id,
1230
- dimmed: !row.matched,
1231
- dropHint: drag?.target && drag.target.targetId === row.id ? drag.target.position : null,
1232
- expanded: container ? row.expanded : void 0,
1233
- renaming: renamingId === row.id,
1234
- notRenaming: renamingId !== row.id,
1228
+ selected: c.isSelected(row2.id),
1229
+ active: activeId === row2.id,
1230
+ dimmed: !row2.matched,
1231
+ dropHint: drag?.target && drag.target.targetId === row2.id ? drag.target.position : null,
1232
+ expanded: container ? row2.expanded : void 0,
1233
+ renaming: renamingId === row2.id,
1234
+ notRenaming: renamingId !== row2.id,
1235
1235
  hasThumbnail: columns.includes("thumbnail") && !!node.thumbnailKey,
1236
1236
  noThumbnail: !(columns.includes("thumbnail") && !!node.thumbnailKey),
1237
1237
  thumbnailKey: node.thumbnailKey,
@@ -1513,11 +1513,11 @@ function LayersPanelView({ controller }) {
1513
1513
  const getSnapshot = useCallback(() => controller.getRevision(), [controller]);
1514
1514
  useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
1515
1515
  const view = layersViewState(controller);
1516
- const ui4 = (intent) => applyLayersUi(controller, intent);
1516
+ const ui5 = (intent) => applyLayersUi(controller, intent);
1517
1517
  return /* @__PURE__ */ jsxs2(Column, { className: "xeno-layers-panel", children: [
1518
- view.searchShown ? /* @__PURE__ */ jsx3(Toolbar, { children: /* @__PURE__ */ jsx3(SearchField, { value: view.filter, onChange: (v) => ui4({ kind: "filter", value: v }), placeholder: "Search layers", label: "Search layers" }) }) : null,
1518
+ view.searchShown ? /* @__PURE__ */ jsx3(Toolbar, { children: /* @__PURE__ */ jsx3(SearchField, { value: view.filter, onChange: (v) => ui5({ kind: "filter", value: v }), placeholder: "Search layers", label: "Search layers" }) }) : null,
1519
1519
  /* @__PURE__ */ jsxs2(LayersScroller, { controller, children: [
1520
- /* @__PURE__ */ jsx3(RowList, { role: "tree", "aria-label": "Layers", children: /* @__PURE__ */ jsx3(VirtualWindow, { totalHeight: view.totalHeight, offsetTop: view.offsetTop, children: view.rows.map((row) => /* @__PURE__ */ jsx3(LayerRow, { row, thumbnailSize: view.thumbnailSize, controller }, row.id)) }) }),
1520
+ /* @__PURE__ */ jsx3(RowList, { role: "tree", "aria-label": "Layers", children: /* @__PURE__ */ jsx3(VirtualWindow, { totalHeight: view.totalHeight, offsetTop: view.offsetTop, children: view.rows.map((row2) => /* @__PURE__ */ jsx3(LayerRow, { row: row2, thumbnailSize: view.thumbnailSize, controller }, row2.id)) }) }),
1521
1521
  view.empty ? /* @__PURE__ */ jsx3(EmptyState, { title: "No layers" }) : null
1522
1522
  ] }),
1523
1523
  /* @__PURE__ */ jsx3(StatusBar, { left: /* @__PURE__ */ jsx3(Text, { role: "number", children: view.count }), right: view.orderLabel ? /* @__PURE__ */ jsx3(Text, { role: "meta", children: view.orderLabel }) : null })
@@ -1627,37 +1627,37 @@ function LayersRenameField({ id, controller }) {
1627
1627
  function LayersThumbnail({ thumbnailKey, size, controller }) {
1628
1628
  return /* @__PURE__ */ jsx3(Thumbnail, { size, data: controller.getThumbnail(thumbnailKey) });
1629
1629
  }
1630
- function LayerRow({ row, thumbnailSize, controller }) {
1631
- const ui4 = (intent) => applyLayersUi(controller, intent);
1630
+ function LayerRow({ row: row2, thumbnailSize, controller }) {
1631
+ const ui5 = (intent) => applyLayersUi(controller, intent);
1632
1632
  return /* @__PURE__ */ jsx3(
1633
1633
  Row,
1634
1634
  {
1635
- "data-layer-row": row.id,
1636
- height: row.height,
1637
- depth: row.depth,
1638
- selected: row.selected,
1639
- active: row.active,
1640
- dimmed: row.dimmed,
1641
- dropHint: row.dropHint,
1642
- expanded: row.expanded,
1643
- title: row.title,
1644
- icon: row.hasThumbnail ? /* @__PURE__ */ jsx3(LayersThumbnail, { thumbnailKey: row.thumbnailKey, size: thumbnailSize, controller }) : /* @__PURE__ */ jsx3(KindGlyph, {}),
1635
+ "data-layer-row": row2.id,
1636
+ height: row2.height,
1637
+ depth: row2.depth,
1638
+ selected: row2.selected,
1639
+ active: row2.active,
1640
+ dimmed: row2.dimmed,
1641
+ dropHint: row2.dropHint,
1642
+ expanded: row2.expanded,
1643
+ title: row2.title,
1644
+ icon: row2.hasThumbnail ? /* @__PURE__ */ jsx3(LayersThumbnail, { thumbnailKey: row2.thumbnailKey, size: thumbnailSize, controller }) : /* @__PURE__ */ jsx3(KindGlyph, {}),
1645
1645
  leading: /* @__PURE__ */ jsxs2(Fragment, { children: [
1646
- row.showVisibility ? /* @__PURE__ */ jsx3(IconButton, { size: "sm", icon: /* @__PURE__ */ jsx3(VisibilityIcon, { open: row.visible }), label: row.visibilityLabel, active: row.visible, onClick: () => ui4({ kind: "toggleProp", id: row.id, prop: "visible" }) }) : null,
1647
- row.showLock ? /* @__PURE__ */ jsx3(IconButton, { size: "sm", icon: /* @__PURE__ */ jsx3(LockStateIcon, { locked: row.locked }), label: row.lockLabel, active: row.locked, onClick: () => ui4({ kind: "toggleProp", id: row.id, prop: "locked" }) }) : null,
1648
- row.showSolo ? /* @__PURE__ */ jsx3(ChipToggle, { glyph: "S", label: "Solo", on: row.solo, onChange: () => ui4({ kind: "toggleProp", id: row.id, prop: "solo" }) }) : null,
1649
- row.showMute ? /* @__PURE__ */ jsx3(ChipToggle, { glyph: "M", label: "Mute", on: row.muted, onChange: () => ui4({ kind: "toggleProp", id: row.id, prop: "muted" }) }) : null,
1650
- row.showArm ? /* @__PURE__ */ jsx3(ChipToggle, { glyph: "R", label: "Arm", on: row.armed, onChange: () => ui4({ kind: "toggleProp", id: row.id, prop: "armed" }) }) : null,
1651
- row.showColor ? /* @__PURE__ */ jsx3(ColorTag, { color: row.colorLabel }) : null
1646
+ row2.showVisibility ? /* @__PURE__ */ jsx3(IconButton, { size: "sm", icon: /* @__PURE__ */ jsx3(VisibilityIcon, { open: row2.visible }), label: row2.visibilityLabel, active: row2.visible, onClick: () => ui5({ kind: "toggleProp", id: row2.id, prop: "visible" }) }) : null,
1647
+ row2.showLock ? /* @__PURE__ */ jsx3(IconButton, { size: "sm", icon: /* @__PURE__ */ jsx3(LockStateIcon, { locked: row2.locked }), label: row2.lockLabel, active: row2.locked, onClick: () => ui5({ kind: "toggleProp", id: row2.id, prop: "locked" }) }) : null,
1648
+ row2.showSolo ? /* @__PURE__ */ jsx3(ChipToggle, { glyph: "S", label: "Solo", on: row2.solo, onChange: () => ui5({ kind: "toggleProp", id: row2.id, prop: "solo" }) }) : null,
1649
+ row2.showMute ? /* @__PURE__ */ jsx3(ChipToggle, { glyph: "M", label: "Mute", on: row2.muted, onChange: () => ui5({ kind: "toggleProp", id: row2.id, prop: "muted" }) }) : null,
1650
+ row2.showArm ? /* @__PURE__ */ jsx3(ChipToggle, { glyph: "R", label: "Arm", on: row2.armed, onChange: () => ui5({ kind: "toggleProp", id: row2.id, prop: "armed" }) }) : null,
1651
+ row2.showColor ? /* @__PURE__ */ jsx3(ColorTag, { color: row2.colorLabel }) : null
1652
1652
  ] }),
1653
- label: row.renaming ? /* @__PURE__ */ jsx3(LayersRenameField, { id: row.id, controller }) : row.name,
1653
+ label: row2.renaming ? /* @__PURE__ */ jsx3(LayersRenameField, { id: row2.id, controller }) : row2.name,
1654
1654
  trailing: /* @__PURE__ */ jsxs2(Fragment, { children: [
1655
- row.adornments.map((a) => /* @__PURE__ */ jsx3(Badge, { size: "sm", title: a.title, children: a.text }, a.key)),
1656
- row.showOpacity ? /* @__PURE__ */ jsx3(Text, { role: "number", children: row.opacity }) : null
1655
+ row2.adornments.map((a) => /* @__PURE__ */ jsx3(Badge, { size: "sm", title: a.title, children: a.text }, a.key)),
1656
+ row2.showOpacity ? /* @__PURE__ */ jsx3(Text, { role: "number", children: row2.opacity }) : null
1657
1657
  ] }),
1658
- onExpandedChange: () => ui4({ kind: "toggleExpanded", id: row.id }),
1659
- onDoubleClick: () => ui4({ kind: "beginRename", id: row.id }),
1660
- onContextMenuAt: (x, y) => ui4({ kind: "contextMenu", id: row.id, x, y })
1658
+ onExpandedChange: () => ui5({ kind: "toggleExpanded", id: row2.id }),
1659
+ onDoubleClick: () => ui5({ kind: "beginRename", id: row2.id }),
1660
+ onContextMenuAt: (x, y) => ui5({ kind: "contextMenu", id: row2.id, x, y })
1661
1661
  }
1662
1662
  );
1663
1663
  }
@@ -2051,8 +2051,8 @@ function constraintsOf(field) {
2051
2051
  scale: field.scale
2052
2052
  };
2053
2053
  }
2054
- function parseNumeric(text4) {
2055
- const trimmed = String(text4).trim();
2054
+ function parseNumeric(text5) {
2055
+ const trimmed = String(text5).trim();
2056
2056
  if (trimmed.length === 0) return { ok: false, reason: "empty" };
2057
2057
  const match = /^[+-]?(\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?/.exec(trimmed);
2058
2058
  if (!match) return { ok: false, reason: "nan" };
@@ -2077,8 +2077,8 @@ function normalizeNumeric(value, c) {
2077
2077
  function formatNumeric(value, field) {
2078
2078
  if (!Number.isFinite(value)) return "";
2079
2079
  const precision = field.precision;
2080
- const text4 = typeof precision === "number" && Number.isFinite(precision) ? value.toFixed(Math.max(0, Math.floor(precision))) : String(value);
2081
- return field.unit ? `${text4}${field.unit}` : text4;
2080
+ const text5 = typeof precision === "number" && Number.isFinite(precision) ? value.toFixed(Math.max(0, Math.floor(precision))) : String(value);
2081
+ return field.unit ? `${text5}${field.unit}` : text5;
2082
2082
  }
2083
2083
  function usesLogScale(c) {
2084
2084
  return c.scale === "log" && typeof c.min === "number" && typeof c.max === "number" && c.min > 0 && c.max > c.min;
@@ -2412,44 +2412,44 @@ var InspectorPanelController = class {
2412
2412
  if (!field || !isFieldEditable(field)) return;
2413
2413
  const mixed = isFieldMixed(field);
2414
2414
  const value = this.getFieldValue(fieldId);
2415
- const text4 = mixed ? "" : field.type === "number" && typeof value === "number" ? formatNumeric(value, field) : value === void 0 || value === null ? "" : String(value);
2416
- this.drafts.set(fieldId, { text: text4, original: value });
2415
+ const text5 = mixed ? "" : field.type === "number" && typeof value === "number" ? formatNumeric(value, field) : value === void 0 || value === null ? "" : String(value);
2416
+ this.drafts.set(fieldId, { text: text5, original: value });
2417
2417
  this.focusedFieldId = fieldId;
2418
2418
  this.emitFieldFocus(fieldId);
2419
2419
  this.notify();
2420
2420
  }
2421
2421
  /** Update the draft text (typing). Emits nothing under the `blur` policy. */
2422
- setDraft(fieldId, text4) {
2422
+ setDraft(fieldId, text5) {
2423
2423
  const draft = this.drafts.get(fieldId);
2424
2424
  if (!draft) {
2425
- this.drafts.set(fieldId, { text: text4, original: this.getFieldValue(fieldId) });
2425
+ this.drafts.set(fieldId, { text: text5, original: this.getFieldValue(fieldId) });
2426
2426
  } else {
2427
- draft.text = text4;
2427
+ draft.text = text5;
2428
2428
  }
2429
2429
  const field = this.getField(fieldId);
2430
2430
  if (field && commitPolicyOf(field) === "live") {
2431
- const parsed = this.parseDraft(fieldId, text4);
2431
+ const parsed = this.parseDraft(fieldId, text5);
2432
2432
  if (parsed.ok) this.emitSet(fieldId, parsed.value);
2433
2433
  }
2434
2434
  this.notify();
2435
2435
  }
2436
2436
  /** Parse a draft string into a field-appropriate value. */
2437
- parseDraft(fieldId, text4) {
2437
+ parseDraft(fieldId, text5) {
2438
2438
  const field = this.getField(fieldId);
2439
2439
  if (!field) return { ok: false };
2440
2440
  if (field.type === "number") {
2441
- const parsed = parseNumeric(text4);
2441
+ const parsed = parseNumeric(text5);
2442
2442
  if (!parsed.ok) return { ok: false };
2443
2443
  return { ok: true, value: normalizeNumeric(parsed.value, constraintsOf(field)) };
2444
2444
  }
2445
2445
  if (field.type === "json") {
2446
2446
  try {
2447
- return { ok: true, value: JSON.parse(text4) };
2447
+ return { ok: true, value: JSON.parse(text5) };
2448
2448
  } catch {
2449
2449
  return { ok: false };
2450
2450
  }
2451
2451
  }
2452
- return { ok: true, value: text4 };
2452
+ return { ok: true, value: text5 };
2453
2453
  }
2454
2454
  /**
2455
2455
  * Commit the draft (Enter / blur). Invalid input reverts instead of committing garbage.
@@ -3424,7 +3424,7 @@ function NumberWidget({ field, controller, component }) {
3424
3424
  },
3425
3425
  [controller, editable, field.id, component]
3426
3426
  );
3427
- const text4 = component !== void 0 ? (() => {
3427
+ const text5 = component !== void 0 ? (() => {
3428
3428
  const raw = controller.getFieldValue(field.id);
3429
3429
  const v = Array.isArray(raw) ? raw[component] : void 0;
3430
3430
  return typeof v === "number" ? formatNumeric(v, field) : "";
@@ -3436,7 +3436,7 @@ function NumberWidget({ field, controller, component }) {
3436
3436
  Input2,
3437
3437
  {
3438
3438
  inputMode: "decimal",
3439
- value: text4,
3439
+ value: text5,
3440
3440
  placeholder: mixed ? controller.getMixedPlaceholder() : field.placeholder,
3441
3441
  mixed,
3442
3442
  readOnly: !editable,
@@ -3654,7 +3654,7 @@ function ActionGlyph({ glyph }) {
3654
3654
  return /* @__PURE__ */ jsx6("span", { "aria-hidden": true, children: glyph });
3655
3655
  }
3656
3656
  function SectionView({ section, controller }) {
3657
- const ui4 = (intent) => applyInspectorUi(controller, intent);
3657
+ const ui5 = (intent) => applyInspectorUi(controller, intent);
3658
3658
  const hasActions = section.actions.length > 0 || section.hasAddMenu;
3659
3659
  return /* @__PURE__ */ jsxs5(
3660
3660
  Section,
@@ -3663,51 +3663,51 @@ function SectionView({ section, controller }) {
3663
3663
  flush: true,
3664
3664
  collapsible: section.collapsible,
3665
3665
  collapsed: section.collapsed,
3666
- onCollapsedChange: () => ui4({ kind: "toggleSectionCollapsed", sectionId: section.id }),
3666
+ onCollapsedChange: () => ui5({ kind: "toggleSectionCollapsed", sectionId: section.id }),
3667
3667
  enabled: section.enabled,
3668
- onEnabledChange: () => ui4({ kind: "toggleSectionEnabled", sectionId: section.id }),
3668
+ onEnabledChange: () => ui5({ kind: "toggleSectionEnabled", sectionId: section.id }),
3669
3669
  badge: section.badge ? /* @__PURE__ */ jsx6(Badge2, { children: section.badge }) : null,
3670
3670
  actions: hasActions ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
3671
- section.actions.map((action) => /* @__PURE__ */ jsx6(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx6(ActionGlyph, { glyph: action.glyph }), label: action.label, disabled: action.disabled, onClick: () => ui4({ kind: "runAction", sectionId: section.id, actionId: action.id }) }, action.id)),
3672
- section.hasAddMenu ? /* @__PURE__ */ jsx6(Select2, { size: "sm", placeholder: "\uFF0B", options: section.addOptions, value: "", label: section.addLabel, onChange: (id) => ui4({ kind: "addItem", sectionId: section.id, itemId: id }) }) : null
3671
+ section.actions.map((action) => /* @__PURE__ */ jsx6(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx6(ActionGlyph, { glyph: action.glyph }), label: action.label, disabled: action.disabled, onClick: () => ui5({ kind: "runAction", sectionId: section.id, actionId: action.id }) }, action.id)),
3672
+ section.hasAddMenu ? /* @__PURE__ */ jsx6(Select2, { size: "sm", placeholder: "\uFF0B", options: section.addOptions, value: "", label: section.addLabel, onChange: (id) => ui5({ kind: "addItem", sectionId: section.id, itemId: id }) }) : null
3673
3673
  ] }) : null,
3674
3674
  children: [
3675
3675
  section.showEmptyHint ? /* @__PURE__ */ jsx6(Stack2, { pad: "inset", children: /* @__PURE__ */ jsx6(Text3, { role: "caption", children: section.emptyHint }) }) : null,
3676
- /* @__PURE__ */ jsx6(FieldGroup, { labelWidth: section.labelWidth, children: section.fields.map((row) => /* @__PURE__ */ jsx6(FieldRow, { row, controller }, row.id)) })
3676
+ /* @__PURE__ */ jsx6(FieldGroup, { labelWidth: section.labelWidth, children: section.fields.map((row2) => /* @__PURE__ */ jsx6(FieldRow, { row: row2, controller }, row2.id)) })
3677
3677
  ]
3678
3678
  }
3679
3679
  );
3680
3680
  }
3681
- function FieldRow({ row, controller }) {
3682
- const ui4 = (intent) => applyInspectorUi(controller, intent);
3681
+ function FieldRow({ row: row2, controller }) {
3682
+ const ui5 = (intent) => applyInspectorUi(controller, intent);
3683
3683
  return /* @__PURE__ */ jsxs5(Fragment3, { children: [
3684
3684
  /* @__PURE__ */ jsxs5(
3685
3685
  Field,
3686
3686
  {
3687
- label: row.label,
3688
- title: row.title,
3689
- focused: row.focused,
3690
- onLabelClick: () => ui4({ kind: "focusField", fieldId: row.id }),
3691
- onContextMenu: (x, y) => ui4({ kind: "contextMenu", fieldId: row.id, x, y }),
3692
- leading: row.showKeyframes ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
3693
- /* @__PURE__ */ jsx6(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx6(StopwatchIcon, {}), label: "Toggle animation", active: row.animated, onClick: () => ui4({ kind: "keyframe", fieldId: row.id, op: "toggleAnim" }) }),
3694
- row.animated ? /* @__PURE__ */ jsx6(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx6(PrevIcon, {}), label: "Previous keyframe", disabled: row.prevDisabled, onClick: () => ui4({ kind: "keyframe", fieldId: row.id, op: "prev" }) }) : null,
3695
- row.animated ? /* @__PURE__ */ jsx6(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx6(DiamondIcon, { filled: row.onKeyframe }), label: row.keyframeLabel, onClick: () => ui4({ kind: "keyframe", fieldId: row.id, op: row.keyframeOp }) }) : null,
3696
- row.animated ? /* @__PURE__ */ jsx6(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx6(NextIcon, {}), label: "Next keyframe", disabled: row.nextDisabled, onClick: () => ui4({ kind: "keyframe", fieldId: row.id, op: "next" }) }) : null
3687
+ label: row2.label,
3688
+ title: row2.title,
3689
+ focused: row2.focused,
3690
+ onLabelClick: () => ui5({ kind: "focusField", fieldId: row2.id }),
3691
+ onContextMenu: (x, y) => ui5({ kind: "contextMenu", fieldId: row2.id, x, y }),
3692
+ leading: row2.showKeyframes ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
3693
+ /* @__PURE__ */ jsx6(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx6(StopwatchIcon, {}), label: "Toggle animation", active: row2.animated, onClick: () => ui5({ kind: "keyframe", fieldId: row2.id, op: "toggleAnim" }) }),
3694
+ row2.animated ? /* @__PURE__ */ jsx6(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx6(PrevIcon, {}), label: "Previous keyframe", disabled: row2.prevDisabled, onClick: () => ui5({ kind: "keyframe", fieldId: row2.id, op: "prev" }) }) : null,
3695
+ row2.animated ? /* @__PURE__ */ jsx6(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx6(DiamondIcon, { filled: row2.onKeyframe }), label: row2.keyframeLabel, onClick: () => ui5({ kind: "keyframe", fieldId: row2.id, op: row2.keyframeOp }) }) : null,
3696
+ row2.animated ? /* @__PURE__ */ jsx6(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx6(NextIcon, {}), label: "Next keyframe", disabled: row2.nextDisabled, onClick: () => ui5({ kind: "keyframe", fieldId: row2.id, op: "next" }) }) : null
3697
3697
  ] }) : null,
3698
3698
  trailing: /* @__PURE__ */ jsxs5(Fragment3, { children: [
3699
- row.showEasing ? /* @__PURE__ */ jsx6(Select2, { size: "sm", options: row.easingOptions, value: row.easing, label: "Easing", onChange: (v) => ui4({ kind: "setEasing", fieldId: row.id, easing: v }) }) : null,
3700
- row.showKeyframes ? /* @__PURE__ */ jsx6(Badge2, { size: "sm", children: row.keyframeChip }) : null,
3701
- row.showToken ? /* @__PURE__ */ jsx6(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx6(LinkIcon, {}), label: row.tokenActionLabel, active: row.bound, onClick: () => ui4({ kind: "bindToken", fieldId: row.id }) }) : null,
3702
- row.showReset ? /* @__PURE__ */ jsx6(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx6(ResetIcon, {}), label: "Reset to default", onClick: () => ui4({ kind: "resetField", fieldId: row.id }) }) : null
3699
+ row2.showEasing ? /* @__PURE__ */ jsx6(Select2, { size: "sm", options: row2.easingOptions, value: row2.easing, label: "Easing", onChange: (v) => ui5({ kind: "setEasing", fieldId: row2.id, easing: v }) }) : null,
3700
+ row2.showKeyframes ? /* @__PURE__ */ jsx6(Badge2, { size: "sm", children: row2.keyframeChip }) : null,
3701
+ row2.showToken ? /* @__PURE__ */ jsx6(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx6(LinkIcon, {}), label: row2.tokenActionLabel, active: row2.bound, onClick: () => ui5({ kind: "bindToken", fieldId: row2.id }) }) : null,
3702
+ row2.showReset ? /* @__PURE__ */ jsx6(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx6(ResetIcon, {}), label: "Reset to default", onClick: () => ui5({ kind: "resetField", fieldId: row2.id }) }) : null
3703
3703
  ] }),
3704
3704
  children: [
3705
- row.bound ? /* @__PURE__ */ jsx6(Badge2, { title: row.tokenTitle, children: row.tokenLabel }) : null,
3706
- row.unbound ? /* @__PURE__ */ jsx6(FieldWidget, { field: row.field, controller }) : null
3705
+ row2.bound ? /* @__PURE__ */ jsx6(Badge2, { title: row2.tokenTitle, children: row2.tokenLabel }) : null,
3706
+ row2.unbound ? /* @__PURE__ */ jsx6(FieldWidget, { field: row2.field, controller }) : null
3707
3707
  ]
3708
3708
  }
3709
3709
  ),
3710
- row.showInfoNote ? /* @__PURE__ */ jsx6(Stack2, { pad: "inset", children: /* @__PURE__ */ jsx6(Text3, { role: "caption", children: row.infoNote }) }) : null
3710
+ row2.showInfoNote ? /* @__PURE__ */ jsx6(Stack2, { pad: "inset", children: /* @__PURE__ */ jsx6(Text3, { role: "caption", children: row2.infoNote }) }) : null
3711
3711
  ] });
3712
3712
  }
3713
3713
  function FieldWidget({
@@ -4498,9 +4498,9 @@ var HistoryPanelController = class {
4498
4498
  case "ArrowUp": {
4499
4499
  const delta = event.key === "ArrowDown" ? 1 : -1;
4500
4500
  const next = focusIndex < 0 ? 0 : Math.min(rows.length - 1, Math.max(0, focusIndex + delta));
4501
- const row = rows[next];
4502
- if (row) {
4503
- this.focusedEntryId = row.entryId;
4501
+ const row2 = rows[next];
4502
+ if (row2) {
4503
+ this.focusedEntryId = row2.entryId;
4504
4504
  this.scrollIndexIntoView(next, rows.length);
4505
4505
  }
4506
4506
  this.notify();
@@ -4509,9 +4509,9 @@ var HistoryPanelController = class {
4509
4509
  case "Home":
4510
4510
  case "End": {
4511
4511
  const index = event.key === "Home" ? 0 : rows.length - 1;
4512
- const row = rows[index];
4513
- if (row) {
4514
- this.focusedEntryId = row.entryId;
4512
+ const row2 = rows[index];
4513
+ if (row2) {
4514
+ this.focusedEntryId = row2.entryId;
4515
4515
  this.scrollIndexIntoView(index, rows.length);
4516
4516
  }
4517
4517
  this.notify();
@@ -4751,22 +4751,22 @@ function historyViewState(c) {
4751
4751
  pruned: c.isPruned(),
4752
4752
  totalHeight: window_.totalHeight,
4753
4753
  offsetTop: window_.offsetTop,
4754
- rows: c.getWindowRows().map((row) => {
4755
- const entry = row.entry;
4754
+ rows: c.getWindowRows().map((row2) => {
4755
+ const entry = row2.entry;
4756
4756
  const pending = entry?.status === "pending";
4757
4757
  const source = entry?.source;
4758
4758
  return {
4759
- key: row.entryId ?? "__original__",
4760
- entryId: row.entryId,
4761
- label: row.label,
4762
- meta: row.kind === "entry" ? row.ordinal : void 0,
4763
- current: row.current,
4764
- future: row.future,
4765
- focused: focused === row.entryId,
4759
+ key: row2.entryId ?? "__original__",
4760
+ entryId: row2.entryId,
4761
+ label: row2.label,
4762
+ meta: row2.kind === "entry" ? row2.ordinal : void 0,
4763
+ current: row2.current,
4764
+ future: row2.future,
4765
+ focused: focused === row2.entryId,
4766
4766
  jumpable: jumpAllowed && entry?.caps?.jumpable !== false,
4767
4767
  showIcon: showIcons,
4768
4768
  hideIcon: !showIcons,
4769
- iconName: row.kind === "original" ? "original" : c.getIconName(entry?.kind),
4769
+ iconName: row2.kind === "original" ? "original" : c.getIconName(entry?.kind),
4770
4770
  pending,
4771
4771
  failed: entry?.status === "failed",
4772
4772
  showSource: showSource && !!source && source !== "user",
@@ -5046,26 +5046,26 @@ function HistoryPanelView({ controller }) {
5046
5046
  const getSnapshot = useCallback4(() => controller.getRevision(), [controller]);
5047
5047
  useSyncExternalStore3(subscribe, getSnapshot, getSnapshot);
5048
5048
  const view = historyViewState(controller);
5049
- const ui4 = (intent) => applyHistoryUi(controller, intent);
5049
+ const ui5 = (intent) => applyHistoryUi(controller, intent);
5050
5050
  return /* @__PURE__ */ jsxs7(Column3, { className: "xeno-history-panel", children: [
5051
5051
  /* @__PURE__ */ jsx8(
5052
5052
  Toolbar2,
5053
5053
  {
5054
5054
  left: /* @__PURE__ */ jsxs7(Fragment4, { children: [
5055
- /* @__PURE__ */ jsx8(IconButton4, { size: "sm", icon: /* @__PURE__ */ jsx8(UndoIcon, {}), label: "Undo", disabled: view.cannotUndo, onClick: () => ui4({ kind: "undo" }) }),
5056
- /* @__PURE__ */ jsx8(IconButton4, { size: "sm", icon: /* @__PURE__ */ jsx8(RedoIcon, {}), label: "Redo", disabled: view.cannotRedo, onClick: () => ui4({ kind: "redo" }) })
5055
+ /* @__PURE__ */ jsx8(IconButton4, { size: "sm", icon: /* @__PURE__ */ jsx8(UndoIcon, {}), label: "Undo", disabled: view.cannotUndo, onClick: () => ui5({ kind: "undo" }) }),
5056
+ /* @__PURE__ */ jsx8(IconButton4, { size: "sm", icon: /* @__PURE__ */ jsx8(RedoIcon, {}), label: "Redo", disabled: view.cannotRedo, onClick: () => ui5({ kind: "redo" }) })
5057
5057
  ] }),
5058
5058
  right: /* @__PURE__ */ jsxs7(Fragment4, { children: [
5059
5059
  /* @__PURE__ */ jsx8(Text4, { role: "number", children: view.counter }),
5060
- view.clearAllowed ? /* @__PURE__ */ jsx8(IconButton4, { size: "sm", icon: /* @__PURE__ */ jsx8(TrashIcon, {}), label: "Clear history", onClick: () => ui4({ kind: "requestClear" }) }) : null
5060
+ view.clearAllowed ? /* @__PURE__ */ jsx8(IconButton4, { size: "sm", icon: /* @__PURE__ */ jsx8(TrashIcon, {}), label: "Clear history", onClick: () => ui5({ kind: "requestClear" }) }) : null
5061
5061
  ] }),
5062
- children: view.searchShown ? /* @__PURE__ */ jsx8(SearchField3, { value: view.filter, onChange: (v) => ui4({ kind: "filter", value: v }), placeholder: "Search history", label: "Search history" }) : null
5062
+ children: view.searchShown ? /* @__PURE__ */ jsx8(SearchField3, { value: view.filter, onChange: (v) => ui5({ kind: "filter", value: v }), placeholder: "Search history", label: "Search history" }) : null
5063
5063
  }
5064
5064
  ),
5065
- view.confirmingClear ? /* @__PURE__ */ jsx8(InlineConfirm, { message: "Clear all history?", label: "Confirm clear history", confirmLabel: "Clear", onConfirm: () => ui4({ kind: "confirmClear" }), onCancel: () => ui4({ kind: "cancelClear" }) }) : null,
5065
+ view.confirmingClear ? /* @__PURE__ */ jsx8(InlineConfirm, { message: "Clear all history?", label: "Confirm clear history", confirmLabel: "Clear", onConfirm: () => ui5({ kind: "confirmClear" }), onCancel: () => ui5({ kind: "cancelClear" }) }) : null,
5066
5066
  view.pruned ? /* @__PURE__ */ jsx8(Text4, { role: "caption", children: "Earlier history discarded (limit reached)" }) : null,
5067
5067
  /* @__PURE__ */ jsxs7(HistoryScroller, { controller, children: [
5068
- /* @__PURE__ */ jsx8(RowList2, { role: "listbox", "aria-label": "History", children: /* @__PURE__ */ jsx8(VirtualWindow2, { totalHeight: view.totalHeight, offsetTop: view.offsetTop, children: view.rows.map((row) => /* @__PURE__ */ jsx8(HistoryRowView, { row, controller }, row.key)) }) }),
5068
+ /* @__PURE__ */ jsx8(RowList2, { role: "listbox", "aria-label": "History", children: /* @__PURE__ */ jsx8(VirtualWindow2, { totalHeight: view.totalHeight, offsetTop: view.offsetTop, children: view.rows.map((row2) => /* @__PURE__ */ jsx8(HistoryRowView, { row: row2, controller }, row2.key)) }) }),
5069
5069
  view.empty ? /* @__PURE__ */ jsx8(EmptyState3, { title: "No history" }) : null
5070
5070
  ] }),
5071
5071
  view.hasMemory ? /* @__PURE__ */ jsx8(StatusBar2, { left: /* @__PURE__ */ jsx8(Text4, { role: "number", children: view.memoryText }), right: view.memoryDisk ? /* @__PURE__ */ jsx8(Text4, { role: "meta", children: view.memoryDisk }) : null }) : null
@@ -5119,33 +5119,33 @@ function HistoryCancelButton({ entryId, controller }) {
5119
5119
  }
5120
5120
  );
5121
5121
  }
5122
- function HistoryRowView({ row, controller }) {
5123
- const ui4 = (intent) => applyHistoryUi(controller, intent);
5122
+ function HistoryRowView({ row: row2, controller }) {
5123
+ const ui5 = (intent) => applyHistoryUi(controller, intent);
5124
5124
  return /* @__PURE__ */ jsx8(
5125
5125
  Row2,
5126
5126
  {
5127
- height: row.height,
5128
- selected: row.current,
5129
- focused: row.focused,
5130
- struck: row.future,
5131
- noIcon: row.hideIcon,
5132
- interactive: row.jumpable,
5133
- icon: /* @__PURE__ */ jsx8(EntryIcon, { name: row.iconName }),
5134
- label: row.label,
5135
- meta: row.meta,
5136
- "data-history-row": row.key,
5137
- title: row.label,
5127
+ height: row2.height,
5128
+ selected: row2.current,
5129
+ focused: row2.focused,
5130
+ struck: row2.future,
5131
+ noIcon: row2.hideIcon,
5132
+ interactive: row2.jumpable,
5133
+ icon: /* @__PURE__ */ jsx8(EntryIcon, { name: row2.iconName }),
5134
+ label: row2.label,
5135
+ meta: row2.meta,
5136
+ "data-history-row": row2.key,
5137
+ title: row2.label,
5138
5138
  trailing: /* @__PURE__ */ jsxs7(Fragment4, { children: [
5139
- row.pending ? /* @__PURE__ */ jsx8(PendingGlyph, {}) : null,
5140
- row.failed ? /* @__PURE__ */ jsx8(Badge3, { size: "sm", tone: "error", children: "failed" }) : null,
5141
- row.showSource ? /* @__PURE__ */ jsx8(Badge3, { size: "sm", title: row.sourceTitle, children: row.sourceGlyph }) : null,
5142
- row.showCoalesced ? /* @__PURE__ */ jsx8(Badge3, { size: "sm", title: row.coalescedTitle, children: row.coalescedText }) : null,
5143
- row.showTime ? /* @__PURE__ */ jsx8(Text4, { role: "meta", children: row.time }) : null,
5144
- row.pending ? /* @__PURE__ */ jsx8(HistoryCancelButton, { entryId: row.cancelId, controller }) : null
5139
+ row2.pending ? /* @__PURE__ */ jsx8(PendingGlyph, {}) : null,
5140
+ row2.failed ? /* @__PURE__ */ jsx8(Badge3, { size: "sm", tone: "error", children: "failed" }) : null,
5141
+ row2.showSource ? /* @__PURE__ */ jsx8(Badge3, { size: "sm", title: row2.sourceTitle, children: row2.sourceGlyph }) : null,
5142
+ row2.showCoalesced ? /* @__PURE__ */ jsx8(Badge3, { size: "sm", title: row2.coalescedTitle, children: row2.coalescedText }) : null,
5143
+ row2.showTime ? /* @__PURE__ */ jsx8(Text4, { role: "meta", children: row2.time }) : null,
5144
+ row2.pending ? /* @__PURE__ */ jsx8(HistoryCancelButton, { entryId: row2.cancelId, controller }) : null
5145
5145
  ] }),
5146
- onClick: () => ui4({ kind: "jump", entryId: row.entryId }),
5147
- onMouseEnter: () => ui4({ kind: "hover", entryId: row.entryId }),
5148
- onContextMenuAt: (x, y) => ui4({ kind: "contextMenu", entryId: row.entryId, x, y })
5146
+ onClick: () => ui5({ kind: "jump", entryId: row2.entryId }),
5147
+ onMouseEnter: () => ui5({ kind: "hover", entryId: row2.entryId }),
5148
+ onContextMenuAt: (x, y) => ui5({ kind: "contextMenu", entryId: row2.entryId, x, y })
5149
5149
  }
5150
5150
  );
5151
5151
  }
@@ -6183,6 +6183,181 @@ var ColorPanelController = class {
6183
6183
  import { useCallback as useCallback5, useEffect as useEffect4, useRef as useRef5 } from "react";
6184
6184
  import { useSyncExternalStore as useSyncExternalStore4 } from "react";
6185
6185
 
6186
+ // src/edit/color/declaration.ts
6187
+ var SPACE_LABEL = { hex: "HEX", rgb: "RGB", hsl: "HSL", hsv: "HSV", oklch: "OKLCH" };
6188
+ var COMPONENT_LABELS = { rgb: ["R", "G", "B"], hsl: ["H", "S", "L"], oklch: ["L", "C", "H"] };
6189
+ function roundForSpace(space, v) {
6190
+ if (space === "oklch") return Math.round(v * 10) / 10;
6191
+ return Math.round(v);
6192
+ }
6193
+ function colorViewState(c) {
6194
+ const value = c.getColorValue();
6195
+ const space = c.getSpace();
6196
+ const comps = value.components ?? [];
6197
+ const labels = COMPONENT_LABELS[space] ?? [];
6198
+ const active = c.getActiveChannel();
6199
+ return {
6200
+ hex: value.hex,
6201
+ bound: c.isBound(),
6202
+ fgBg: c.getChannelsMode() === "fg-bg",
6203
+ fgActive: active === "fg",
6204
+ bgActive: active === "bg",
6205
+ space,
6206
+ spaceOptions: EDIT_SPACES.map((sp) => ({ value: sp, label: SPACE_LABEL[sp] })),
6207
+ isHex: space === "hex",
6208
+ isComponents: space !== "hex",
6209
+ components: labels.map((label, index) => ({ key: label, label, index, value: roundForSpace(space, comps[index] ?? 0) })),
6210
+ alphaShown: c.isAlphaShown(),
6211
+ alphaPercent: Math.round(value.alpha * 100),
6212
+ hasTokens: c.hasTokens(),
6213
+ boundTokenId: c.getBoundTokenId() ?? "",
6214
+ tokenOptions: c.getTokens().map((t) => ({ value: t.id, label: t.name })),
6215
+ swatches: c.getSwatches().map((hex) => ({ key: hex, hex })),
6216
+ hasRecent: c.getRecent().length > 0,
6217
+ recent: c.getRecent().map((hex, i) => ({ key: `${hex}-${i}`, hex }))
6218
+ };
6219
+ }
6220
+ function applyColorUi(c, intent) {
6221
+ switch (intent.kind) {
6222
+ case "setChannel":
6223
+ c.setChannel(intent.channel);
6224
+ break;
6225
+ case "swapChannels":
6226
+ c.swapChannels();
6227
+ break;
6228
+ case "setSpace":
6229
+ c.setSpace(intent.space);
6230
+ break;
6231
+ case "setHex":
6232
+ c.setFromColor(intent.value, void 0, { commit: true });
6233
+ break;
6234
+ case "setComponent": {
6235
+ const comps = [...c.getColorValue().components ?? [0, 0, 0]];
6236
+ comps[intent.index] = intent.value;
6237
+ c.setFromComponents(c.getSpace(), comps, { commit: true });
6238
+ break;
6239
+ }
6240
+ case "setAlpha":
6241
+ c.setAlpha(intent.percent / 100, { commit: true });
6242
+ break;
6243
+ case "eyedropper":
6244
+ c.requestEyedropper();
6245
+ break;
6246
+ case "bindToken":
6247
+ if (intent.tokenId) c.bindToken(intent.tokenId);
6248
+ else c.unbindToken();
6249
+ break;
6250
+ case "unbindToken":
6251
+ c.unbindToken();
6252
+ break;
6253
+ case "addSwatch":
6254
+ void c.addSwatch();
6255
+ break;
6256
+ case "selectColor":
6257
+ c.selectColor(intent.hex);
6258
+ break;
6259
+ case "removeSwatch":
6260
+ void c.removeSwatch(intent.hex);
6261
+ break;
6262
+ }
6263
+ }
6264
+ var colorViewManifest = {
6265
+ id: colorManifest.id,
6266
+ version: "1.0.0",
6267
+ title: "Color",
6268
+ category: "edit",
6269
+ layout: { slot: "side" },
6270
+ inputs: [{ id: "view", type: "object", label: "View state", description: "The ColorViewState the runtime derives from the controller on every draw." }],
6271
+ outputs: [{ id: "ui", type: "object", label: "UI intent", description: "{ kind, \u2026 } \u2014 applied by the runtime to the controller." }],
6272
+ commands: []
6273
+ };
6274
+ var EMPTY4 = { hex: "#000000", bound: false, fgBg: false, fgActive: true, bgActive: false, space: "hex", spaceOptions: EDIT_SPACES.map((sp) => ({ value: sp, label: SPACE_LABEL[sp] })), isHex: true, isComponents: false, components: [], alphaShown: false, alphaPercent: 100, hasTokens: false, boundTokenId: "", tokenOptions: [], swatches: [], hasRecent: false, recent: [] };
6275
+ var BEHAVIOURS4 = {
6276
+ "edit/colorPanelView": (inputs) => inputs.view ?? EMPTY4
6277
+ };
6278
+ var text4 = (b) => ({ component: "text", props: { text: b } });
6279
+ var ui4 = (kind, fields = {}) => ({ emit: "ui", value: { object: { kind: { value: kind }, ...fields } } });
6280
+ var row = (children, extra = {}, when) => ({
6281
+ component: "chrome/Stack",
6282
+ ...when ? { when } : {},
6283
+ props: { direction: { value: "row" }, pad: { value: "none" }, ...extra },
6284
+ children
6285
+ });
6286
+ var COLOR_DECLARATION = {
6287
+ format: "xeno.block@1",
6288
+ manifest: colorViewManifest,
6289
+ behaviour: "edit/colorPanelView",
6290
+ composition: {
6291
+ component: "chrome/Column",
6292
+ props: { className: { value: "xeno-color-panel" } },
6293
+ children: [
6294
+ {
6295
+ component: "chrome/Stack",
6296
+ props: { gap: { value: 8 } },
6297
+ children: [
6298
+ row(
6299
+ [
6300
+ { component: "chrome/ColorChip", props: { color: { input: "view.hex" }, label: { value: "Foreground" }, pressed: { input: "view.fgActive" } }, on: { onClick: ui4("setChannel", { channel: { value: "fg" } }) } },
6301
+ { component: "chrome/IconButton", props: { size: { value: "sm" }, icon: { node: { component: "color/SwapIcon" } }, label: { value: "Swap FG/BG (X)" } }, on: { onClick: ui4("swapChannels") } },
6302
+ { component: "chrome/ColorChip", props: { color: { value: null }, label: { value: "Background" }, pressed: { input: "view.bgActive" } }, on: { onClick: ui4("setChannel", { channel: { value: "bg" } }) } }
6303
+ ],
6304
+ {},
6305
+ { input: "view.fgBg" }
6306
+ ),
6307
+ { component: "color/Picker" },
6308
+ row(
6309
+ [
6310
+ { component: "chrome/Select", props: { size: { value: "sm" }, label: { value: "Color model" }, value: { input: "view.space" }, options: { input: "view.spaceOptions" } }, on: { onChange: ui4("setSpace", { space: { arg: "" } }) } },
6311
+ { component: "chrome/Input", when: { input: "view.isHex" }, props: { variant: { value: "mono" }, label: { value: "Hex" }, value: { input: "view.hex" }, disabled: { input: "view.bound" } }, on: { onChange: ui4("setHex", { value: { arg: "" } }) } },
6312
+ { component: "chrome/NumberInput", each: { input: "view.components", key: "key" }, props: { caption: { item: "label" }, value: { item: "value" }, disabled: { input: "view.bound" } }, on: { onChange: ui4("setComponent", { index: { item: "index" }, value: { arg: "" } }) } },
6313
+ { component: "chrome/NumberInput", when: { input: "view.alphaShown" }, props: { caption: { value: "A" }, label: { value: "Alpha" }, min: { value: 0 }, max: { value: 100 }, value: { input: "view.alphaPercent" }, disabled: { input: "view.bound" } }, on: { onChange: ui4("setAlpha", { percent: { arg: "" } }) } },
6314
+ { component: "chrome/IconButton", props: { size: { value: "sm" }, icon: { node: { component: "color/EyedropperIcon" } }, label: { value: "Pick from screen" } }, on: { onClick: ui4("eyedropper") } }
6315
+ ],
6316
+ { gap: { value: 4 } }
6317
+ ),
6318
+ {
6319
+ component: "chrome/Field",
6320
+ when: { input: "view.hasTokens" },
6321
+ props: { label: { value: "Token" }, htmlFor: { value: "xeno-color-token" } },
6322
+ children: [
6323
+ row(
6324
+ [
6325
+ { component: "chrome/Select", props: { size: { value: "sm" }, label: { value: "Bind token" }, value: { input: "view.boundTokenId" }, placeholder: { value: "\u2014 raw \u2014" }, options: { input: "view.tokenOptions" } }, on: { onChange: ui4("bindToken", { tokenId: { arg: "" } }) } },
6326
+ { component: "chrome/TextButton", when: { input: "view.bound" }, on: { onClick: ui4("unbindToken") }, children: [text4({ value: "Unbind" })] }
6327
+ ],
6328
+ { gap: { value: 4 } }
6329
+ )
6330
+ ]
6331
+ },
6332
+ {
6333
+ component: "chrome/Section",
6334
+ props: { title: { value: "Swatches" }, flush: { value: true }, actions: { node: { component: "chrome/TextButton", on: { onClick: ui4("addSwatch") }, children: [text4({ value: "+ Save" })] } } },
6335
+ children: [
6336
+ {
6337
+ component: "chrome/SwatchGrid",
6338
+ props: { label: { value: "Swatches" } },
6339
+ children: [{ component: "chrome/ColorChip", each: { input: "view.swatches", key: "key" }, props: { size: { value: "grid" }, color: { item: "hex" }, label: { item: "hex" } }, on: { onClick: ui4("selectColor", { hex: { item: "hex" } }), onContextMenu: ui4("removeSwatch", { hex: { item: "hex" } }) } }]
6340
+ }
6341
+ ]
6342
+ },
6343
+ {
6344
+ component: "chrome/Section",
6345
+ when: { input: "view.hasRecent" },
6346
+ props: { title: { value: "Recent" }, flush: { value: true } },
6347
+ children: [
6348
+ {
6349
+ component: "chrome/SwatchGrid",
6350
+ props: { label: { value: "Recent" } },
6351
+ children: [{ component: "chrome/ColorChip", each: { input: "view.recent", key: "key" }, props: { size: { value: "grid" }, color: { item: "hex" }, label: { item: "hex" } }, on: { onClick: ui4("selectColor", { hex: { item: "hex" } }) } }]
6352
+ }
6353
+ ]
6354
+ }
6355
+ ]
6356
+ }
6357
+ ]
6358
+ }
6359
+ };
6360
+
6186
6361
  // src/edit/color/react/viewHelpers.ts
6187
6362
  function hsvFromHexOrBlack(hex) {
6188
6363
  const rgba = parseHexColor(hex);
@@ -6276,24 +6451,39 @@ function SwapIcon() {
6276
6451
 
6277
6452
  // src/edit/color/react/ColorPanelView.tsx
6278
6453
  import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
6279
- var SPACE_LABEL = {
6280
- hex: "HEX",
6281
- rgb: "RGB",
6282
- hsl: "HSL",
6283
- hsv: "HSV",
6284
- oklch: "OKLCH"
6285
- };
6286
- var COMPONENT_LABELS = {
6287
- rgb: ["R", "G", "B"],
6288
- hsl: ["H", "S", "L"],
6289
- oklch: ["L", "C", "H"]
6290
- };
6291
6454
  function ColorPanelView({ controller }) {
6455
+ const subscribe = useCallback5((cb) => controller.subscribe(cb), [controller]);
6456
+ const getSnapshot = useCallback5(() => controller.getRevision(), [controller]);
6457
+ useSyncExternalStore4(subscribe, getSnapshot, getSnapshot);
6458
+ const view = colorViewState(controller);
6459
+ const ui5 = (intent) => applyColorUi(controller, intent);
6460
+ return /* @__PURE__ */ jsx10(Column4, { className: "xeno-color-panel", children: /* @__PURE__ */ jsxs9(Stack3, { gap: 8, children: [
6461
+ view.fgBg ? /* @__PURE__ */ jsxs9(Stack3, { direction: "row", pad: "none", children: [
6462
+ /* @__PURE__ */ jsx10(ColorChip, { color: view.hex, label: "Foreground", pressed: view.fgActive, onClick: () => ui5({ kind: "setChannel", channel: "fg" }) }),
6463
+ /* @__PURE__ */ jsx10(IconButton5, { size: "sm", icon: /* @__PURE__ */ jsx10(SwapIcon, {}), label: "Swap FG/BG (X)", onClick: () => ui5({ kind: "swapChannels" }) }),
6464
+ /* @__PURE__ */ jsx10(ColorChip, { color: null, label: "Background", pressed: view.bgActive, onClick: () => ui5({ kind: "setChannel", channel: "bg" }) })
6465
+ ] }) : null,
6466
+ /* @__PURE__ */ jsx10(ColorPicker, { controller }),
6467
+ /* @__PURE__ */ jsxs9(Stack3, { direction: "row", pad: "none", gap: 4, children: [
6468
+ /* @__PURE__ */ jsx10(Select3, { size: "sm", label: "Color model", value: view.space, options: view.spaceOptions, onChange: (v) => ui5({ kind: "setSpace", space: v }) }),
6469
+ view.isHex ? /* @__PURE__ */ jsx10(Input3, { variant: "mono", label: "Hex", value: view.hex, onChange: (v) => ui5({ kind: "setHex", value: v }), disabled: view.bound }) : null,
6470
+ view.components.map((comp) => /* @__PURE__ */ jsx10(NumberInput, { caption: comp.label, value: comp.value, onChange: (n) => ui5({ kind: "setComponent", index: comp.index, value: n }), disabled: view.bound }, comp.key)),
6471
+ view.alphaShown ? /* @__PURE__ */ jsx10(NumberInput, { caption: "A", label: "Alpha", min: 0, max: 100, value: view.alphaPercent, onChange: (n) => ui5({ kind: "setAlpha", percent: n }), disabled: view.bound }) : null,
6472
+ /* @__PURE__ */ jsx10(IconButton5, { size: "sm", icon: /* @__PURE__ */ jsx10(EyedropperIcon, {}), label: "Pick from screen", onClick: () => ui5({ kind: "eyedropper" }) })
6473
+ ] }),
6474
+ view.hasTokens ? /* @__PURE__ */ jsx10(Field2, { label: "Token", htmlFor: "xeno-color-token", children: /* @__PURE__ */ jsxs9(Stack3, { direction: "row", pad: "none", gap: 4, children: [
6475
+ /* @__PURE__ */ jsx10(Select3, { size: "sm", label: "Bind token", value: view.boundTokenId, placeholder: "\u2014 raw \u2014", options: view.tokenOptions, onChange: (id) => ui5({ kind: "bindToken", tokenId: id }) }),
6476
+ view.bound ? /* @__PURE__ */ jsx10(TextButton2, { onClick: () => ui5({ kind: "unbindToken" }), children: "Unbind" }) : null
6477
+ ] }) }) : null,
6478
+ /* @__PURE__ */ jsx10(Section2, { title: "Swatches", flush: true, actions: /* @__PURE__ */ jsx10(TextButton2, { onClick: () => ui5({ kind: "addSwatch" }), children: "+ Save" }), children: /* @__PURE__ */ jsx10(SwatchGrid, { label: "Swatches", children: view.swatches.map((sw) => /* @__PURE__ */ jsx10(ColorChip, { size: "grid", color: sw.hex, label: sw.hex, onClick: () => ui5({ kind: "selectColor", hex: sw.hex }), onContextMenu: () => ui5({ kind: "removeSwatch", hex: sw.hex }) }, sw.key)) }) }),
6479
+ view.hasRecent ? /* @__PURE__ */ jsx10(Section2, { title: "Recent", flush: true, children: /* @__PURE__ */ jsx10(SwatchGrid, { label: "Recent", children: view.recent.map((r) => /* @__PURE__ */ jsx10(ColorChip, { size: "grid", color: r.hex, label: r.hex, onClick: () => ui5({ kind: "selectColor", hex: r.hex }) }, r.key)) }) }) : null
6480
+ ] }) });
6481
+ }
6482
+ function ColorPicker({ controller }) {
6292
6483
  const subscribe = useCallback5((cb) => controller.subscribe(cb), [controller]);
6293
6484
  const getSnapshot = useCallback5(() => controller.getRevision(), [controller]);
6294
6485
  useSyncExternalStore4(subscribe, getSnapshot, getSnapshot);
6295
6486
  const value = controller.getColorValue();
6296
- const space = controller.getSpace();
6297
6487
  const bound = controller.isBound();
6298
6488
  const hsv = hsvFromHexOrBlack(value.hex);
6299
6489
  const spectrumRef = useRef5(null);
@@ -6364,116 +6554,82 @@ function ColorPanelView({ controller }) {
6364
6554
  controller.endDrag();
6365
6555
  }
6366
6556
  }, [controller]);
6367
- const onHexInput = useCallback5(
6368
- (raw) => {
6369
- controller.setFromColor(raw, void 0, { commit: true });
6370
- },
6371
- [controller]
6372
- );
6373
- const onComponentInput = useCallback5(
6374
- (index, n) => {
6375
- const comps2 = [...value.components ?? [0, 0, 0]];
6376
- comps2[index] = n;
6377
- controller.setFromComponents(space, comps2, { commit: true });
6378
- },
6379
- [controller, space, value.components]
6380
- );
6381
- const componentLabels = COMPONENT_LABELS[space];
6382
- const comps = value.components ?? [];
6383
- const activeChannel = controller.getActiveChannel();
6384
- return /* @__PURE__ */ jsx10(Column4, { className: "xeno-color-panel", children: /* @__PURE__ */ jsxs9(Stack3, { gap: 8, children: [
6385
- controller.getChannelsMode() === "fg-bg" ? /* @__PURE__ */ jsxs9(Stack3, { direction: "row", pad: "none", children: [
6386
- /* @__PURE__ */ jsx10(ColorChip, { color: value.hex, label: "Foreground", pressed: activeChannel === "fg", onClick: () => controller.setChannel("fg") }),
6387
- /* @__PURE__ */ jsx10(IconButton5, { size: "sm", icon: /* @__PURE__ */ jsx10(SwapIcon, {}), label: "Swap FG/BG (X)", onClick: () => controller.swapChannels() }),
6388
- /* @__PURE__ */ jsx10(ColorChip, { color: null, label: "Background", pressed: activeChannel === "bg", onClick: () => controller.setChannel("bg") })
6389
- ] }) : null,
6390
- /* @__PURE__ */ jsxs9(Stack3, { direction: "row", pad: "none", children: [
6391
- /* @__PURE__ */ jsx10(
6392
- CanvasSurface,
6393
- {
6394
- ref: spectrumRef,
6395
- width: 200,
6396
- height: 140,
6397
- grow: true,
6398
- cursor: "crosshair",
6399
- disabled: bound,
6400
- "aria-label": "Saturation and value",
6401
- onPointerDown: (e) => onSpectrumPointer(e, true),
6402
- onPointerMove: (e) => onSpectrumPointer(e, false),
6403
- onPointerUp: endDrag
6404
- }
6405
- ),
6406
- /* @__PURE__ */ jsx10(
6407
- CanvasSurface,
6408
- {
6409
- ref: hueRef,
6410
- width: 14,
6411
- height: 140,
6412
- cursor: "ns-resize",
6413
- disabled: bound,
6414
- "aria-label": "Hue",
6415
- onPointerDown: (e) => onHuePointer(e, true),
6416
- onPointerMove: (e) => onHuePointer(e, false),
6417
- onPointerUp: endDrag
6418
- }
6419
- ),
6420
- controller.isAlphaShown() ? /* @__PURE__ */ jsx10(
6421
- CanvasSurface,
6422
- {
6423
- ref: alphaRef,
6424
- width: 14,
6425
- height: 140,
6426
- cursor: "ns-resize",
6427
- disabled: bound,
6428
- "aria-label": "Alpha",
6429
- onPointerDown: (e) => onAlphaPointer(e, true),
6430
- onPointerMove: (e) => onAlphaPointer(e, false),
6431
- onPointerUp: endDrag
6432
- }
6433
- ) : null
6434
- ] }),
6435
- /* @__PURE__ */ jsxs9(Stack3, { direction: "row", pad: "none", gap: 4, children: [
6436
- /* @__PURE__ */ jsx10(Select3, { size: "sm", label: "Color model", value: space, options: EDIT_SPACES.map((sp) => ({ value: sp, label: SPACE_LABEL[sp] })), onChange: (v) => controller.setSpace(v) }),
6437
- space === "hex" ? /* @__PURE__ */ jsx10(Input3, { variant: "mono", label: "Hex", value: value.hex, onChange: onHexInput, disabled: bound }) : (componentLabels ?? []).map((label, i) => /* @__PURE__ */ jsx10(NumberInput, { caption: label, value: roundForSpace(space, i, comps[i] ?? 0), onChange: (n) => onComponentInput(i, n), disabled: bound }, label)),
6438
- controller.isAlphaShown() ? /* @__PURE__ */ jsx10(NumberInput, { caption: "A", label: "Alpha", min: 0, max: 100, value: Math.round(value.alpha * 100), onChange: (n) => controller.setAlpha(n / 100, { commit: true }), disabled: bound }) : null,
6439
- /* @__PURE__ */ jsx10(IconButton5, { size: "sm", icon: /* @__PURE__ */ jsx10(EyedropperIcon, {}), label: "Pick from screen", onClick: () => controller.requestEyedropper() })
6440
- ] }),
6441
- controller.hasTokens() ? /* @__PURE__ */ jsx10(Field2, { label: "Token", htmlFor: "xeno-color-token", children: /* @__PURE__ */ jsxs9(Stack3, { direction: "row", pad: "none", gap: 4, children: [
6442
- /* @__PURE__ */ jsx10(
6443
- Select3,
6444
- {
6445
- size: "sm",
6446
- label: "Bind token",
6447
- value: controller.getBoundTokenId() ?? "",
6448
- placeholder: "\u2014 raw \u2014",
6449
- options: controller.getTokens().map((t) => ({ value: t.id, label: t.name })),
6450
- onChange: (id) => id ? controller.bindToken(id) : controller.unbindToken()
6451
- }
6452
- ),
6453
- bound ? /* @__PURE__ */ jsx10(TextButton2, { onClick: () => controller.unbindToken(), children: "Unbind" }) : null
6454
- ] }) }) : null,
6455
- /* @__PURE__ */ jsx10(Section2, { title: "Swatches", flush: true, actions: /* @__PURE__ */ jsx10(TextButton2, { onClick: () => void controller.addSwatch(), children: "+ Save" }), children: /* @__PURE__ */ jsx10(SwatchGrid, { label: "Swatches", children: controller.getSwatches().map((hex) => /* @__PURE__ */ jsx10(ColorChip, { size: "grid", color: hex, label: hex, onClick: () => controller.selectColor(hex), onContextMenu: () => void controller.removeSwatch(hex) }, hex)) }) }),
6456
- controller.getRecent().length > 0 ? /* @__PURE__ */ jsx10(Section2, { title: "Recent", flush: true, children: /* @__PURE__ */ jsx10(SwatchGrid, { label: "Recent", children: controller.getRecent().map((hex, i) => /* @__PURE__ */ jsx10(ColorChip, { size: "grid", color: hex, label: hex, onClick: () => controller.selectColor(hex) }, `${hex}-${i}`)) }) }) : null
6457
- ] }) });
6557
+ return /* @__PURE__ */ jsxs9(Stack3, { direction: "row", pad: "none", children: [
6558
+ /* @__PURE__ */ jsx10(
6559
+ CanvasSurface,
6560
+ {
6561
+ ref: spectrumRef,
6562
+ width: 200,
6563
+ height: 140,
6564
+ grow: true,
6565
+ cursor: "crosshair",
6566
+ disabled: bound,
6567
+ "aria-label": "Saturation and value",
6568
+ onPointerDown: (e) => onSpectrumPointer(e, true),
6569
+ onPointerMove: (e) => onSpectrumPointer(e, false),
6570
+ onPointerUp: endDrag
6571
+ }
6572
+ ),
6573
+ /* @__PURE__ */ jsx10(
6574
+ CanvasSurface,
6575
+ {
6576
+ ref: hueRef,
6577
+ width: 14,
6578
+ height: 140,
6579
+ cursor: "ns-resize",
6580
+ disabled: bound,
6581
+ "aria-label": "Hue",
6582
+ onPointerDown: (e) => onHuePointer(e, true),
6583
+ onPointerMove: (e) => onHuePointer(e, false),
6584
+ onPointerUp: endDrag
6585
+ }
6586
+ ),
6587
+ controller.isAlphaShown() ? /* @__PURE__ */ jsx10(
6588
+ CanvasSurface,
6589
+ {
6590
+ ref: alphaRef,
6591
+ width: 14,
6592
+ height: 140,
6593
+ cursor: "ns-resize",
6594
+ disabled: bound,
6595
+ "aria-label": "Alpha",
6596
+ onPointerDown: (e) => onAlphaPointer(e, true),
6597
+ onPointerMove: (e) => onAlphaPointer(e, false),
6598
+ onPointerUp: endDrag
6599
+ }
6600
+ ) : null
6601
+ ] });
6602
+ }
6603
+ function colorRuntimeComponents(controller) {
6604
+ return {
6605
+ "color/Picker": () => /* @__PURE__ */ jsx10(ColorPicker, { controller }),
6606
+ "color/SwapIcon": SwapIcon,
6607
+ "color/EyedropperIcon": EyedropperIcon
6608
+ };
6458
6609
  }
6459
6610
  function clamp01(n) {
6460
6611
  return Math.max(0, Math.min(1, Number.isFinite(n) ? n : 0));
6461
6612
  }
6462
- function roundForSpace(space, index, v) {
6463
- if (space === "oklch") return Math.round(v * 10) / 10;
6464
- return Math.round(v);
6465
- }
6466
6613
 
6467
6614
  // src/edit/color/panel.ts
6468
6615
  function createColorPanel(options = {}) {
6469
6616
  return {
6470
6617
  manifest: colorManifest,
6471
6618
  activate(host) {
6472
- const controller = new ColorPanelController(host, options);
6619
+ const { render: customRender, ...controllerOptions } = options;
6620
+ const controller = new ColorPanelController(host, controllerOptions);
6473
6621
  void controller.load();
6474
6622
  let root = null;
6623
+ let unrender = null;
6475
6624
  return {
6476
6625
  render(el) {
6626
+ if (customRender) {
6627
+ unrender = customRender(el, controller);
6628
+ return () => {
6629
+ unrender?.();
6630
+ unrender = null;
6631
+ };
6632
+ }
6477
6633
  root = createRoot4(el);
6478
6634
  root.render(createElement4(ColorPanelView, { controller }));
6479
6635
  return () => {
@@ -6496,6 +6652,8 @@ function createColorPanel(options = {}) {
6496
6652
  dispose() {
6497
6653
  root?.unmount();
6498
6654
  root = null;
6655
+ unrender?.();
6656
+ unrender = null;
6499
6657
  controller.dispose();
6500
6658
  }
6501
6659
  };
@@ -8981,11 +9139,11 @@ var FindController = class {
8981
9139
  * @param text - The new query text.
8982
9140
  * @param immediate - Skip the debounce (a paste, or pressing Enter).
8983
9141
  */
8984
- setText(text4, immediate = false) {
8985
- if (text4 === this.text) return;
8986
- this.text = text4;
9142
+ setText(text5, immediate = false) {
9143
+ if (text5 === this.text) return;
9144
+ this.text = text5;
8987
9145
  this.index = -1;
8988
- if (text4 === "") {
9146
+ if (text5 === "") {
8989
9147
  this.clearResults("idle");
8990
9148
  this.emitQuery(true);
8991
9149
  return;
@@ -9013,8 +9171,8 @@ var FindController = class {
9013
9171
  this.notify();
9014
9172
  }
9015
9173
  /** The replacement text. Never emitted on its own — a replacement is not a search. */
9016
- setReplaceText(text4) {
9017
- this.replaceText = text4;
9174
+ setReplaceText(text5) {
9175
+ this.replaceText = text5;
9018
9176
  this.notify();
9019
9177
  }
9020
9178
  /** Show or hide the replace row. */
@@ -12304,14 +12462,14 @@ var TreeController = class {
12304
12462
  filter: this.filter,
12305
12463
  labelOf: (node) => node.label,
12306
12464
  isContainer: isTreeContainer
12307
- }).map((row) => ({
12308
- id: row.id,
12309
- node: row.node,
12310
- depth: row.depth,
12311
- container: row.container,
12312
- expanded: row.expanded,
12313
- matched: row.matched,
12314
- childState: childStateOf(row.node)
12465
+ }).map((row2) => ({
12466
+ id: row2.id,
12467
+ node: row2.node,
12468
+ depth: row2.depth,
12469
+ container: row2.container,
12470
+ expanded: row2.expanded,
12471
+ matched: row2.matched,
12472
+ childState: childStateOf(row2.node)
12315
12473
  }));
12316
12474
  return this.rowCache;
12317
12475
  }
@@ -12596,7 +12754,7 @@ var TreeController = class {
12596
12754
  if (rows.length === 0) return false;
12597
12755
  const index = rows.findIndex((r) => r.id === this.focusedId);
12598
12756
  const current = index >= 0 ? index : 0;
12599
- const row = rows[current];
12757
+ const row2 = rows[current];
12600
12758
  switch (event.key) {
12601
12759
  case "ArrowDown":
12602
12760
  this.moveFocus(rows, Math.min(rows.length - 1, current + 1), event);
@@ -12611,15 +12769,15 @@ var TreeController = class {
12611
12769
  this.moveFocus(rows, rows.length - 1, event);
12612
12770
  return true;
12613
12771
  case "ArrowRight":
12614
- if (row?.container && !row.expanded) this.setExpanded(row.id, true);
12615
- else if (row && current + 1 < rows.length) this.moveFocus(rows, current + 1, event);
12772
+ if (row2?.container && !row2.expanded) this.setExpanded(row2.id, true);
12773
+ else if (row2 && current + 1 < rows.length) this.moveFocus(rows, current + 1, event);
12616
12774
  return true;
12617
12775
  case "ArrowLeft": {
12618
- if (row?.container && row.expanded) {
12619
- this.setExpanded(row.id, false);
12776
+ if (row2?.container && row2.expanded) {
12777
+ this.setExpanded(row2.id, false);
12620
12778
  return true;
12621
12779
  }
12622
- const parentId = row?.node.parentId;
12780
+ const parentId = row2?.node.parentId;
12623
12781
  if (parentId) {
12624
12782
  this.focusedId = parentId;
12625
12783
  this.select([parentId]);
@@ -12627,10 +12785,10 @@ var TreeController = class {
12627
12785
  return true;
12628
12786
  }
12629
12787
  case "Enter":
12630
- if (row) this.open(row.id, { alt: event.altKey });
12788
+ if (row2) this.open(row2.id, { alt: event.altKey });
12631
12789
  return true;
12632
12790
  case "F2":
12633
- if (row) this.beginRename(row.id);
12791
+ if (row2) this.beginRename(row2.id);
12634
12792
  return true;
12635
12793
  case "Delete":
12636
12794
  case "Backspace":
@@ -12650,12 +12808,12 @@ var TreeController = class {
12650
12808
  }
12651
12809
  if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
12652
12810
  const fresh = now - this.typeAhead.at > this.typeAheadMs;
12653
- const text4 = (fresh ? "" : this.typeAhead.text) + event.key.toLowerCase();
12654
- this.typeAhead = { text: text4, at: now };
12811
+ const text5 = (fresh ? "" : this.typeAhead.text) + event.key.toLowerCase();
12812
+ this.typeAhead = { text: text5, at: now };
12655
12813
  const from = fresh ? current : current + 1;
12656
12814
  for (let i = 0; i < rows.length; i += 1) {
12657
12815
  const candidate = rows[(from + i) % rows.length];
12658
- if (candidate.node.label.toLowerCase().startsWith(text4)) {
12816
+ if (candidate.node.label.toLowerCase().startsWith(text5)) {
12659
12817
  this.focusedId = candidate.id;
12660
12818
  this.select([candidate.id]);
12661
12819
  return true;
@@ -12681,9 +12839,9 @@ var TreeController = class {
12681
12839
  return true;
12682
12840
  }
12683
12841
  /** Update the rename draft. */
12684
- updateRenameDraft(text4) {
12842
+ updateRenameDraft(text5) {
12685
12843
  if (!this.renaming) return;
12686
- this.renaming = { ...this.renaming, draft: text4 };
12844
+ this.renaming = { ...this.renaming, draft: text5 };
12687
12845
  this.notify();
12688
12846
  }
12689
12847
  /**
@@ -13412,10 +13570,10 @@ function TreePanelView({
13412
13570
  e.preventDefault();
13413
13571
  }
13414
13572
  },
13415
- children: /* @__PURE__ */ jsx17("div", { style: { height: window2.totalHeight, position: "relative" }, children: /* @__PURE__ */ jsx17("div", { style: { transform: `translateY(${window2.offsetTop}px)` }, children: slice.map((row) => /* @__PURE__ */ jsx17(
13573
+ children: /* @__PURE__ */ jsx17("div", { style: { height: window2.totalHeight, position: "relative" }, children: /* @__PURE__ */ jsx17("div", { style: { transform: `translateY(${window2.offsetTop}px)` }, children: slice.map((row2) => /* @__PURE__ */ jsx17(
13416
13574
  TreeRowView,
13417
13575
  {
13418
- row,
13576
+ row: row2,
13419
13577
  controller,
13420
13578
  state,
13421
13579
  rowHeight,
@@ -13423,7 +13581,7 @@ function TreePanelView({
13423
13581
  openOn,
13424
13582
  columns
13425
13583
  },
13426
- row.id
13584
+ row2.id
13427
13585
  )) }) })
13428
13586
  }
13429
13587
  ) });
@@ -13465,7 +13623,7 @@ function TreePanelView({
13465
13623
  ] });
13466
13624
  }
13467
13625
  function TreeRowView({
13468
- row,
13626
+ row: row2,
13469
13627
  controller,
13470
13628
  state,
13471
13629
  rowHeight,
@@ -13473,18 +13631,18 @@ function TreeRowView({
13473
13631
  openOn,
13474
13632
  columns
13475
13633
  }) {
13476
- const node = row.node;
13477
- const selected = state.selection.includes(row.id);
13478
- const renaming = state.renaming?.id === row.id ? state.renaming : null;
13479
- const drop = state.drag?.targetId === row.id ? state.drag : null;
13480
- const twisty = row.container ? /* @__PURE__ */ jsx17(
13634
+ const node = row2.node;
13635
+ const selected = state.selection.includes(row2.id);
13636
+ const renaming = state.renaming?.id === row2.id ? state.renaming : null;
13637
+ const drop = state.drag?.targetId === row2.id ? state.drag : null;
13638
+ const twisty = row2.container ? /* @__PURE__ */ jsx17(
13481
13639
  "span",
13482
13640
  {
13483
13641
  role: "button",
13484
- "aria-label": row.expanded ? "Collapse" : "Expand",
13642
+ "aria-label": row2.expanded ? "Collapse" : "Expand",
13485
13643
  onClick: (e) => {
13486
13644
  e.stopPropagation();
13487
- controller.setExpanded(row.id, !row.expanded);
13645
+ controller.setExpanded(row2.id, !row2.expanded);
13488
13646
  },
13489
13647
  style: {
13490
13648
  display: "flex",
@@ -13493,7 +13651,7 @@ function TreeRowView({
13493
13651
  width: 12,
13494
13652
  flex: "0 0 auto",
13495
13653
  cursor: "pointer",
13496
- transform: row.expanded ? "rotate(90deg)" : void 0,
13654
+ transform: row2.expanded ? "rotate(90deg)" : void 0,
13497
13655
  transition: "transform 80ms ease",
13498
13656
  opacity: 0.7
13499
13657
  },
@@ -13518,34 +13676,34 @@ function TreeRowView({
13518
13676
  Row4,
13519
13677
  {
13520
13678
  role: "treeitem",
13521
- "aria-expanded": row.container ? row.expanded : void 0,
13522
- "aria-level": row.depth + 1,
13679
+ "aria-expanded": row2.container ? row2.expanded : void 0,
13680
+ "aria-level": row2.depth + 1,
13523
13681
  selected,
13524
13682
  disabled: node.caps?.select === false,
13525
13683
  depth: 0,
13526
- style: { height: rowHeight, paddingLeft: 6 + row.depth * indentPx },
13684
+ style: { height: rowHeight, paddingLeft: 6 + row2.depth * indentPx },
13527
13685
  onClick: (e) => {
13528
- controller.select([row.id], {
13686
+ controller.select([row2.id], {
13529
13687
  toggle: e.ctrlKey || e.metaKey,
13530
13688
  range: e.shiftKey
13531
13689
  });
13532
- if (openOn === "single") controller.open(row.id, { alt: e.altKey });
13690
+ if (openOn === "single") controller.open(row2.id, { alt: e.altKey });
13533
13691
  },
13534
13692
  onDoubleClick: () => {
13535
- if (openOn === "double") controller.open(row.id);
13693
+ if (openOn === "double") controller.open(row2.id);
13536
13694
  },
13537
13695
  onContextMenu: (e) => {
13538
13696
  e.preventDefault();
13539
- controller.requestContextMenu(selected ? state.selection : [row.id], e.clientX, e.clientY);
13697
+ controller.requestContextMenu(selected ? state.selection : [row2.id], e.clientX, e.clientY);
13540
13698
  },
13541
13699
  onPointerDown: (e) => {
13542
13700
  if (e.button !== 0) return;
13543
- controller.beginDrag(selected ? state.selection : [row.id]);
13701
+ controller.beginDrag(selected ? state.selection : [row2.id]);
13544
13702
  },
13545
13703
  onPointerMove: (e) => {
13546
13704
  if (!state.drag) return;
13547
13705
  const rect = e.currentTarget.getBoundingClientRect();
13548
- controller.dragOver(row.id, e.clientY - rect.top);
13706
+ controller.dragOver(row2.id, e.clientY - rect.top);
13549
13707
  },
13550
13708
  onPointerUp: () => {
13551
13709
  if (state.drag) controller.endDrag();
@@ -13579,7 +13737,7 @@ function TreeRowView({
13579
13737
  }
13580
13738
  }
13581
13739
  ) : node.label,
13582
- meta: /* @__PURE__ */ jsx17(ChildStateChip, { row, controller }),
13740
+ meta: /* @__PURE__ */ jsx17(ChildStateChip, { row: row2, controller }),
13583
13741
  trailing: /* @__PURE__ */ jsxs16(Fragment9, { children: [
13584
13742
  columns?.map((columnId) => /* @__PURE__ */ jsx17("span", { style: { opacity: 0.7, fontVariantNumeric: "tabular-nums" }, children: node.columns?.[columnId] ?? "" }, columnId)),
13585
13743
  node.glyphs?.map((glyph) => /* @__PURE__ */ jsx17("span", { title: glyph.title, style: { display: "flex", opacity: 0.7 }, children: /* @__PURE__ */ jsx17(NodeIcon, { icon: glyph.icon }) }, glyph.id)),
@@ -13594,7 +13752,7 @@ function TreeRowView({
13594
13752
  icon: /* @__PURE__ */ jsx17(NodeIcon, { icon: action.icon }),
13595
13753
  label: action.label,
13596
13754
  disabled: action.disabled,
13597
- onClick: () => controller.runAction(row.id, action.id)
13755
+ onClick: () => controller.runAction(row2.id, action.id)
13598
13756
  },
13599
13757
  action.id
13600
13758
  ))
@@ -13605,35 +13763,35 @@ function TreeRowView({
13605
13763
  );
13606
13764
  }
13607
13765
  function ChildStateChip({
13608
- row,
13766
+ row: row2,
13609
13767
  controller
13610
13768
  }) {
13611
- if (!row.container) return null;
13612
- if (row.childState === "loading") {
13769
+ if (!row2.container) return null;
13770
+ if (row2.childState === "loading") {
13613
13771
  return /* @__PURE__ */ jsx17("span", { style: { opacity: 0.5, fontSize: 9 }, children: "loading\u2026" });
13614
13772
  }
13615
- if (row.childState === "error") {
13616
- const error = row.node.error;
13773
+ if (row2.childState === "error") {
13774
+ const error = row2.node.error;
13617
13775
  return /* @__PURE__ */ jsx17(Badge7, { tone: "error", children: error?.code === "denied" ? "no access" : error?.code ?? "failed" });
13618
13776
  }
13619
- if (row.node.hasMore && row.expanded) {
13777
+ if (row2.node.hasMore && row2.expanded) {
13620
13778
  return /* @__PURE__ */ jsx17(
13621
13779
  "span",
13622
13780
  {
13623
13781
  role: "button",
13624
13782
  onClick: (e) => {
13625
13783
  e.stopPropagation();
13626
- controller.loadMore(row.id);
13784
+ controller.loadMore(row2.id);
13627
13785
  },
13628
13786
  style: { cursor: "pointer", opacity: 0.7, fontSize: 9 },
13629
13787
  children: "load more\u2026"
13630
13788
  }
13631
13789
  );
13632
13790
  }
13633
- if (row.node.truncatedAt !== void 0) {
13634
- return /* @__PURE__ */ jsx17(Badge7, { tone: "warning", children: `first ${row.node.truncatedAt}` });
13791
+ if (row2.node.truncatedAt !== void 0) {
13792
+ return /* @__PURE__ */ jsx17(Badge7, { tone: "warning", children: `first ${row2.node.truncatedAt}` });
13635
13793
  }
13636
- if (row.expanded && isEmptyContainer(row.node)) {
13794
+ if (row2.expanded && isEmptyContainer(row2.node)) {
13637
13795
  return /* @__PURE__ */ jsx17("span", { style: { opacity: 0.4, fontSize: 9 }, children: "empty" });
13638
13796
  }
13639
13797
  return null;
@@ -13847,6 +14005,8 @@ function numberConfig(value, fallback) {
13847
14005
  }
13848
14006
  var treePanel = createTreePanel();
13849
14007
  export {
14008
+ BEHAVIOURS4 as COLOR_BEHAVIOURS,
14009
+ COLOR_DECLARATION,
13850
14010
  COLOR_SPACES,
13851
14011
  COMMENTS_PANEL_ID,
13852
14012
  CURVE_PANEL_ID,
@@ -13889,6 +14049,7 @@ export {
13889
14049
  MIXED,
13890
14050
  NODEGRAPH_PANEL_ID,
13891
14051
  NodeGraphPanelView,
14052
+ SPACE_LABEL,
13892
14053
  TREE_PANEL_ID,
13893
14054
  Thumbnail,
13894
14055
  TreeController,
@@ -13906,6 +14067,7 @@ export {
13906
14067
  allIds,
13907
14068
  anchorStateOf,
13908
14069
  appliedCount,
14070
+ applyColorUi,
13909
14071
  applyHistoryUi,
13910
14072
  applyInspectorUi,
13911
14073
  applyLayersUi,
@@ -13923,6 +14085,9 @@ export {
13923
14085
  collectDescendants,
13924
14086
  colorManifest,
13925
14087
  colorPanel,
14088
+ colorRuntimeComponents,
14089
+ colorViewManifest,
14090
+ colorViewState,
13926
14091
  commentsManifest,
13927
14092
  commentsPanel,
13928
14093
  commitPolicyOf,