@xenosystem/blocks 0.15.1 → 0.15.2

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.
@@ -242,6 +242,7 @@ function RedoIcon({ size = 11 }) {
242
242
 
243
243
  // src/edit/inspector/react/icons.tsx
244
244
  import Link from "@xenosystem/elements/elements/link";
245
+ import Copy2 from "@xenosystem/elements/elements/copy";
245
246
  import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
246
247
  var base = (size) => ({
247
248
  width: size,
@@ -271,6 +272,7 @@ function NextIcon({ size = 9 }) {
271
272
  return /* @__PURE__ */ jsx6("svg", { ...base(size), children: /* @__PURE__ */ jsx6("path", { d: "m9 18 6-6-6-6" }) });
272
273
  }
273
274
  var LinkIcon = fromElement(Link, 10);
275
+ var CopyIcon = fromElement(Copy2, 10);
274
276
  function ResetIcon({ size = 10 }) {
275
277
  return /* @__PURE__ */ jsxs5("svg", { ...base(size), children: [
276
278
  /* @__PURE__ */ jsx6("path", { d: "M3 12a9 9 0 1 0 3-6.7L3 8" }),
@@ -489,6 +491,7 @@ export {
489
491
  PrevIcon,
490
492
  NextIcon,
491
493
  LinkIcon,
494
+ CopyIcon,
492
495
  ResetIcon,
493
496
  XIcon2,
494
497
  KindGlyph,
@@ -12,7 +12,7 @@ import {
12
12
  RefreshGlyph,
13
13
  SortAscGlyph,
14
14
  SortDescGlyph
15
- } from "../chunk-4IDY5FHM.js";
15
+ } from "../chunk-LKYPCOTE.js";
16
16
  import "../chunk-2KG3PWR4.js";
17
17
 
18
18
  // src/data/table/panel.ts
@@ -989,6 +989,13 @@ interface XenoInspectorField {
989
989
  */
990
990
  /** For a structured `list`: the label drawn on each item row (e.g. `Fill`, `Shadow`). */
991
991
  itemLabel?: string;
992
+ /**
993
+ * Draw a Copy button beside the field. The block writes the field's text to the clipboard itself
994
+ * when it has one; where it does not (a sandboxed frame), it emits `action { actionId: 'copy' }`
995
+ * with the value so the host can. Raised by Canvas's Dev handoff (2026-09-18): a read-only code
996
+ * block whose whole point is being copied.
997
+ */
998
+ copyable?: boolean;
992
999
  /** Axis labels for `vector` (e.g. `['X','Y']`). */
993
1000
  components?: string[];
994
1001
  /** Scalar ⇔ per-element expander (Canvas's corner radius). */
@@ -1430,6 +1437,11 @@ declare class InspectorPanelController {
1430
1437
  * normal field `set`; otherwise it is an `action` with `actionId: 'setEnabled'`.
1431
1438
  */
1432
1439
  toggleSectionEnabled(sectionId: string): boolean;
1440
+ /**
1441
+ * Copy a field's text. The clipboard is used when this runtime has one; otherwise the host gets
1442
+ * `action { sectionId, actionId: 'copy', value }` and copies on the panel's behalf.
1443
+ */
1444
+ copyField(fieldId: string): boolean;
1433
1445
  /** Run a section action button. */
1434
1446
  runAction(sectionId: string, actionId: string): void;
1435
1447
  /** Pick an entry from a section's Add menu. */
@@ -1691,6 +1703,7 @@ interface InspectorViewField {
1691
1703
  showToken: boolean;
1692
1704
  tokenActionLabel: string;
1693
1705
  showReset: boolean;
1706
+ showCopy: boolean;
1694
1707
  showInfoNote: boolean;
1695
1708
  infoNote?: string;
1696
1709
  /** The field record itself — what `inspector/FieldWidget` renders. */
@@ -1780,6 +1793,9 @@ type InspectorUiIntent = {
1780
1793
  } | {
1781
1794
  kind: 'resetField';
1782
1795
  fieldId: string;
1796
+ } | {
1797
+ kind: 'copyField';
1798
+ fieldId: string;
1783
1799
  };
1784
1800
  /** The link menu's items: the field's group of tokens (all, when it names none), then Unbind and Create-from-value. */
1785
1801
  declare function tokenItemsFor(field: XenoInspectorField, tokens: readonly XenoInspectorToken[], bound: boolean): InspectorViewField['tokenItems'];
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  CollapseGlyph,
3
+ CopyIcon,
3
4
  DiamondIcon,
4
5
  EntryIcon,
5
6
  ExpandGlyph,
@@ -21,7 +22,7 @@ import {
21
22
  VisibilityIcon,
22
23
  XIcon,
23
24
  XIcon2
24
- } from "../chunk-4IDY5FHM.js";
25
+ } from "../chunk-LKYPCOTE.js";
25
26
  import "../chunk-2KG3PWR4.js";
26
27
 
27
28
  // src/edit/layers/panel.ts
@@ -2631,6 +2632,23 @@ var InspectorPanelController = class {
2631
2632
  this.emit({ type: "action", sectionId, actionId: "setEnabled", value: next });
2632
2633
  return true;
2633
2634
  }
2635
+ /**
2636
+ * Copy a field's text. The clipboard is used when this runtime has one; otherwise the host gets
2637
+ * `action { sectionId, actionId: 'copy', value }` and copies on the panel's behalf.
2638
+ */
2639
+ copyField(fieldId) {
2640
+ const field = findField(this.schema, fieldId);
2641
+ if (!field) return false;
2642
+ const text11 = String(this.getFieldValue(fieldId) ?? "");
2643
+ const clip = globalThis.navigator?.clipboard;
2644
+ if (clip?.writeText) {
2645
+ void clip.writeText(text11).catch(() => void 0);
2646
+ return true;
2647
+ }
2648
+ const sectionId = findSectionOf(this.schema, fieldId)?.id ?? "";
2649
+ this.emit({ type: "action", sectionId, actionId: "copy", value: text11 });
2650
+ return true;
2651
+ }
2634
2652
  /** Run a section action button. */
2635
2653
  runAction(sectionId, actionId) {
2636
2654
  this.emit({ type: "action", sectionId, actionId });
@@ -3061,6 +3079,7 @@ function inspectorViewState(c) {
3061
3079
  showToken: showTokens && field.token?.bindable !== false,
3062
3080
  tokenActionLabel: bound ? "Unbind token" : "Bind token",
3063
3081
  showReset: field.defaultValue !== void 0 && isFieldEditable(field),
3082
+ showCopy: !!field.copyable,
3064
3083
  showInfoNote: !!field.description && field.type === "info",
3065
3084
  infoNote: field.description,
3066
3085
  field
@@ -3123,6 +3142,9 @@ function applyInspectorUi(c, intent) {
3123
3142
  case "resetField":
3124
3143
  c.resetField(intent.fieldId);
3125
3144
  break;
3145
+ case "copyField":
3146
+ c.copyField(intent.fieldId);
3147
+ break;
3126
3148
  }
3127
3149
  }
3128
3150
  var inspectorViewManifest = {
@@ -3244,7 +3266,8 @@ var INSPECTOR_DECLARATION = {
3244
3266
  props: { size: { value: "sm" }, trigger: { node: { component: "icons/Link" } }, items: { item: "tokenItems" }, label: { item: "tokenActionLabel" }, align: { value: "end" } },
3245
3267
  on: { onSelect: ui2("pickToken", { fieldId: { item: "id" }, itemId: { arg: "" } }) }
3246
3268
  },
3247
- iconButton("Reset", { value: "Reset to default" }, ui2("resetField", { fieldId: { item: "id" } }), { when: { item: "showReset" } })
3269
+ iconButton("Reset", { value: "Reset to default" }, ui2("resetField", { fieldId: { item: "id" } }), { when: { item: "showReset" } }),
3270
+ iconButton("Copy", { value: "Copy" }, ui2("copyField", { fieldId: { item: "id" } }), { when: { item: "showCopy" } })
3248
3271
  ]
3249
3272
  }
3250
3273
  }
@@ -3706,7 +3729,8 @@ function FieldRow({ row: row2, controller }) {
3706
3729
  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,
3707
3730
  row2.showKeyframes ? /* @__PURE__ */ jsx4(Badge2, { size: "sm", children: row2.keyframeChip }) : null,
3708
3731
  row2.showToken ? /* @__PURE__ */ jsx4(Menu2, { size: "sm", trigger: /* @__PURE__ */ jsx4(LinkIcon, {}), items: row2.tokenItems, label: row2.tokenActionLabel, align: "end", onSelect: (id) => ui10({ kind: "pickToken", fieldId: row2.id, itemId: id }) }) : null,
3709
- row2.showReset ? /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(ResetIcon, {}), label: "Reset to default", onClick: () => ui10({ kind: "resetField", fieldId: row2.id }) }) : null
3732
+ row2.showReset ? /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(ResetIcon, {}), label: "Reset to default", onClick: () => ui10({ kind: "resetField", fieldId: row2.id }) }) : null,
3733
+ row2.showCopy ? /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(CopyIcon, {}), label: "Copy", onClick: () => ui10({ kind: "copyField", fieldId: row2.id }) }) : null
3710
3734
  ] }),
3711
3735
  children: [
3712
3736
  row2.bound ? /* @__PURE__ */ jsx4(Badge2, { title: row2.tokenTitle, children: row2.tokenLabel }) : null,
@@ -2,7 +2,7 @@ import {
2
2
  ICONS,
3
3
  ICON_UNITS,
4
4
  Svg
5
- } from "../chunk-4IDY5FHM.js";
5
+ } from "../chunk-LKYPCOTE.js";
6
6
  import "../chunk-2KG3PWR4.js";
7
7
  export {
8
8
  ICONS,
package/dist/ops/index.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  ICONS,
11
11
  PlusGlyph,
12
12
  XGlyph
13
- } from "../chunk-4IDY5FHM.js";
13
+ } from "../chunk-LKYPCOTE.js";
14
14
  import "../chunk-2KG3PWR4.js";
15
15
 
16
16
  // src/ops/console/panel.ts
@@ -13,7 +13,7 @@ import {
13
13
  StopIcon,
14
14
  TRANSPORT_ICONS,
15
15
  TRANSPORT_RUNTIME_UNITS
16
- } from "../chunk-4IDY5FHM.js";
16
+ } from "../chunk-LKYPCOTE.js";
17
17
  import {
18
18
  __reExport
19
19
  } from "../chunk-2KG3PWR4.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xenosystem/blocks",
3
- "version": "0.15.1",
3
+ "version": "0.15.2",
4
4
  "description": "XENO Blocks — rung 3 of the front ladder: components composed into a contract-bearing unit (manifest: ports, intents, commands, agent surface), rendered by @xenosystem/workbench. ONE package, one subpath per family (/auth, /edit, /data, /time, /ops, /trust, /agent), one named export per block — XENO PACKAGE NAMING - STANDARD.md.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",