@xenosystem/blocks 0.15.0 → 0.15.1

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.
@@ -981,6 +981,12 @@ interface XenoInspectorField {
981
981
  field: string;
982
982
  in: XenoFieldValue[];
983
983
  };
984
+ /**
985
+ * Inside `itemFields`: a sub-field with `token.bindable` carries its binding IN THE ITEM as
986
+ * `${subId}Token` (a token id or empty). The row's token menu reads it, and a pick rewrites the item
987
+ * and emits ONE `set` for the list — the same contract as a value edit, so a host binds a stroke's
988
+ * colour or an effect's shadow from the item it already receives.
989
+ */
984
990
  /** For a structured `list`: the label drawn on each item row (e.g. `Fill`, `Shadow`). */
985
991
  itemLabel?: string;
986
992
  /** Axis labels for `vector` (e.g. `['X','Y']`). */
@@ -2011,7 +2011,9 @@ function findField(schema, fieldId) {
2011
2011
  if (!list || !sub) return void 0;
2012
2012
  const item = (Array.isArray(list.value) ? list.value : []).find((it) => it?.id === v.itemId);
2013
2013
  if (!item) return void 0;
2014
- return { ...sub, id: fieldId, value: item[v.subId], disabled: sub.disabled || list.disabled, readOnly: sub.readOnly || list.readOnly };
2014
+ const tokenId = sub.token?.bindable ? item[`${v.subId}Token`] : void 0;
2015
+ const token = sub.token ? { ...sub.token, ...typeof tokenId === "string" && tokenId ? { tokenId } : { tokenId: null } } : void 0;
2016
+ return { ...sub, id: fieldId, value: item[v.subId], disabled: sub.disabled || list.disabled, readOnly: sub.readOnly || list.readOnly, ...token ? { token } : {} };
2015
2017
  }
2016
2018
  function findSectionOf(schema, fieldId) {
2017
2019
  return schema.sections.find((s) => s.fields.some((f) => f.id === fieldId));
@@ -2673,6 +2675,13 @@ var InspectorPanelController = class {
2673
2675
  bindToken(fieldId, tokenId) {
2674
2676
  const field = findField(this.schema, fieldId);
2675
2677
  if (!field) return false;
2678
+ const virtual = parseListFieldId(fieldId);
2679
+ if (virtual) {
2680
+ const items = this.getFieldValue(virtual.listId) ?? [];
2681
+ const next = items.map((it) => it.id === virtual.itemId ? { ...it, [`${virtual.subId}Token`]: tokenId ?? "" } : it);
2682
+ this.emit({ type: "set", targetIds: this.targetIds(), fieldId: virtual.listId, value: next });
2683
+ return true;
2684
+ }
2676
2685
  this.emit({ type: "bindToken", targetIds: this.targetIds(), fieldId, tokenId });
2677
2686
  return true;
2678
2687
  }
@@ -3266,15 +3275,16 @@ var INSPECTOR_DECLARATION = {
3266
3275
  };
3267
3276
 
3268
3277
  // src/edit/inspector/react/InspectorPanelView.tsx
3269
- import { Badge as Badge2, Column as Column2, EmptyState as EmptyState2, Field, FieldGroup, IconButton as IconButton3, Menu, ScrollArea as ScrollArea2, SearchField as SearchField2, Section, Select as Select2, Stack as Stack2, Text as Text3 } from "@xenosystem/components/chrome";
3278
+ import { Badge as Badge2, Column as Column2, EmptyState as EmptyState2, Field, FieldGroup, IconButton as IconButton3, Menu as Menu2, ScrollArea as ScrollArea2, SearchField as SearchField2, Section, Select as Select2, Stack as Stack2, Text as Text3 } from "@xenosystem/components/chrome";
3270
3279
 
3271
3280
  // src/edit/inspector/react/widgets.tsx
3272
3281
  import { useCallback as useCallback2, useRef as useRef3 } from "react";
3273
- import { Fragment as Fragment2 } from "react";
3282
+ import "react";
3274
3283
  import {
3275
3284
  AxisLabel,
3276
3285
  IconButton as IconButton2,
3277
3286
  Input as Input2,
3287
+ Menu,
3278
3288
  ProportionBar,
3279
3289
  SegmentedControl,
3280
3290
  Select,
@@ -3561,7 +3571,27 @@ function ListWidget({ field, controller, renderField }) {
3561
3571
  field.itemLabel ? /* @__PURE__ */ jsx3(Text2, { role: "caption", children: `${field.itemLabel} ${i + 1}` }) : null,
3562
3572
  field.itemFields.filter((sub) => itemShowsSubField(sub, item)).map((sub) => {
3563
3573
  const virtual = controller.getField(`${field.id}[${item.id}].${sub.id}`);
3564
- return virtual ? /* @__PURE__ */ jsx3(Fragment2, { children: renderField(virtual) }, sub.id) : null;
3574
+ if (!virtual) return null;
3575
+ const bound = !!virtual.token?.tokenId;
3576
+ const tokens = controller.getTokens();
3577
+ const menu = sub.token?.bindable && controller.areTokensShown() ? /* @__PURE__ */ jsx3(
3578
+ Menu,
3579
+ {
3580
+ size: "sm",
3581
+ trigger: /* @__PURE__ */ jsx3(LinkIcon, {}),
3582
+ items: tokenItemsFor(virtual, tokens, bound),
3583
+ label: bound ? "Unbind token" : "Bind token",
3584
+ align: "end",
3585
+ onSelect: (id) => {
3586
+ if (id === "__unbind") controller.bindToken(virtual.id, null);
3587
+ else if (id.startsWith("token:")) controller.bindToken(virtual.id, id.slice(6));
3588
+ }
3589
+ }
3590
+ ) : null;
3591
+ return /* @__PURE__ */ jsxs2(Stack, { direction: "row", gap: 2, pad: "none", children: [
3592
+ bound ? /* @__PURE__ */ jsx3(Text2, { role: "meta", children: virtual.token?.tokenName ?? tokens.find((t) => t.id === virtual.token?.tokenId)?.name ?? virtual.token?.tokenId }) : renderField(virtual),
3593
+ menu
3594
+ ] }, sub.id);
3565
3595
  })
3566
3596
  ] }) : /* @__PURE__ */ jsx3(Text2, { role: "meta", children: typeof item === "string" ? item : JSON.stringify(item) }),
3567
3597
  editable ? /* @__PURE__ */ jsxs2(Fragment3, { children: [
@@ -3646,7 +3676,7 @@ function SectionView({ section, controller }) {
3646
3676
  badge: section.badge ? /* @__PURE__ */ jsx4(Badge2, { children: section.badge }) : null,
3647
3677
  actions: hasActions ? /* @__PURE__ */ jsxs3(Fragment4, { children: [
3648
3678
  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)),
3649
- 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
3679
+ section.hasAddMenu ? /* @__PURE__ */ jsx4(Menu2, { size: "sm", trigger: "\uFF0B", items: section.addItems, label: section.addLabel, align: "end", onSelect: (id) => ui10({ kind: "addItem", sectionId: section.id, itemId: id }) }) : null
3650
3680
  ] }) : null,
3651
3681
  children: [
3652
3682
  section.showEmptyHint ? /* @__PURE__ */ jsx4(Stack2, { pad: "inset", children: /* @__PURE__ */ jsx4(Text3, { role: "caption", children: section.emptyHint }) }) : null,
@@ -3675,7 +3705,7 @@ function FieldRow({ row: row2, controller }) {
3675
3705
  trailing: /* @__PURE__ */ jsxs3(Fragment4, { children: [
3676
3706
  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,
3677
3707
  row2.showKeyframes ? /* @__PURE__ */ jsx4(Badge2, { size: "sm", children: row2.keyframeChip }) : null,
3678
- row2.showToken ? /* @__PURE__ */ jsx4(Menu, { 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,
3708
+ 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,
3679
3709
  row2.showReset ? /* @__PURE__ */ jsx4(IconButton3, { size: "sm", icon: /* @__PURE__ */ jsx4(ResetIcon, {}), label: "Reset to default", onClick: () => ui10({ kind: "resetField", fieldId: row2.id }) }) : null
3680
3710
  ] }),
3681
3711
  children: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xenosystem/blocks",
3
- "version": "0.15.0",
3
+ "version": "0.15.1",
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",