@xenosystem/blocks 0.15.1 → 0.15.3
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.
- package/dist/{chunk-4IDY5FHM.js → chunk-LKYPCOTE.js} +3 -0
- package/dist/data/index.js +1 -1
- package/dist/edit/index.d.ts +16 -0
- package/dist/edit/index.js +27 -3
- package/dist/icons/index.js +1 -1
- package/dist/ops/index.d.ts +7 -0
- package/dist/ops/index.js +28 -3
- package/dist/time/index.js +1 -1
- package/package.json +1 -1
|
@@ -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,
|
package/dist/data/index.js
CHANGED
package/dist/edit/index.d.ts
CHANGED
|
@@ -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'];
|
package/dist/edit/index.js
CHANGED
|
@@ -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-
|
|
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,
|
package/dist/icons/index.js
CHANGED
package/dist/ops/index.d.ts
CHANGED
|
@@ -449,6 +449,8 @@ declare class ConsoleController {
|
|
|
449
449
|
/** Collapse adjacent duplicates. */
|
|
450
450
|
setCollapse(collapse: boolean): void;
|
|
451
451
|
/** Drop every record. Emits nothing — clearing a view is not an event a host acts on. */
|
|
452
|
+
/** Ask the host to recompute the records (a lint, an audit) — nothing changes here until it pushes. */
|
|
453
|
+
requestRefresh(): void;
|
|
452
454
|
clear(): void;
|
|
453
455
|
/**
|
|
454
456
|
* A record was opened.
|
|
@@ -486,6 +488,7 @@ interface ConsoleRenderContext {
|
|
|
486
488
|
rowHeight: number;
|
|
487
489
|
showTimestamps: boolean;
|
|
488
490
|
emptyHint?: string;
|
|
491
|
+
showRefresh?: boolean;
|
|
489
492
|
};
|
|
490
493
|
}
|
|
491
494
|
/** Options for {@link createConsolePanel}. */
|
|
@@ -563,6 +566,7 @@ interface ConsoleViewModel {
|
|
|
563
566
|
errors?: string;
|
|
564
567
|
warns?: string;
|
|
565
568
|
multiSource: boolean;
|
|
569
|
+
showRefresh: boolean;
|
|
566
570
|
sources: ConsoleViewSource[];
|
|
567
571
|
empty: boolean;
|
|
568
572
|
emptyTitle: string;
|
|
@@ -585,6 +589,8 @@ type ConsoleUiIntent = {
|
|
|
585
589
|
kind: 'copyVisible';
|
|
586
590
|
} | {
|
|
587
591
|
kind: 'clear';
|
|
592
|
+
} | {
|
|
593
|
+
kind: 'refresh';
|
|
588
594
|
} | {
|
|
589
595
|
kind: 'source';
|
|
590
596
|
id: string;
|
|
@@ -602,6 +608,7 @@ interface ConsoleViewOptions {
|
|
|
602
608
|
rowHeight?: number;
|
|
603
609
|
showTimestamps?: boolean;
|
|
604
610
|
emptyHint?: string;
|
|
611
|
+
showRefresh?: boolean;
|
|
605
612
|
}
|
|
606
613
|
/** Derive the view from the live controller — the runtime calls this on every draw. */
|
|
607
614
|
declare function consoleViewState(c: ConsoleController, options?: ConsoleViewOptions): ConsoleViewModel;
|
package/dist/ops/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
ICONS,
|
|
11
11
|
PlusGlyph,
|
|
12
12
|
XGlyph
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-LKYPCOTE.js";
|
|
14
14
|
import "../chunk-2KG3PWR4.js";
|
|
15
15
|
|
|
16
16
|
// src/ops/console/panel.ts
|
|
@@ -422,6 +422,10 @@ var ConsoleController = class {
|
|
|
422
422
|
this.notify();
|
|
423
423
|
}
|
|
424
424
|
/** Drop every record. Emits nothing — clearing a view is not an event a host acts on. */
|
|
425
|
+
/** Ask the host to recompute the records (a lint, an audit) — nothing changes here until it pushes. */
|
|
426
|
+
requestRefresh() {
|
|
427
|
+
this.host.emit("refreshRequest", {});
|
|
428
|
+
}
|
|
425
429
|
clear() {
|
|
426
430
|
this.records = [];
|
|
427
431
|
this.dropped = 0;
|
|
@@ -522,6 +526,12 @@ var consoleManifest = {
|
|
|
522
526
|
name: "Context Menu Request",
|
|
523
527
|
type: "object",
|
|
524
528
|
description: "The host opens its own menu."
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
id: "refreshRequest",
|
|
532
|
+
name: "Refresh Requested",
|
|
533
|
+
type: "object",
|
|
534
|
+
description: "{} \u2014 the person pressed Refresh (config `showRefresh`), so a host whose records are a COMPUTATION (a lint, an audit, a query) re-runs it and pushes a `replace`. A live stream never shows the button."
|
|
525
535
|
}
|
|
526
536
|
],
|
|
527
537
|
commands: [
|
|
@@ -558,6 +568,13 @@ var consoleManifest = {
|
|
|
558
568
|
}
|
|
559
569
|
],
|
|
560
570
|
config: [
|
|
571
|
+
{
|
|
572
|
+
key: "showRefresh",
|
|
573
|
+
label: "Refresh button",
|
|
574
|
+
type: "boolean",
|
|
575
|
+
defaultValue: false,
|
|
576
|
+
description: "For records that are computed on demand rather than streamed: a Refresh button that emits `refreshRequest`."
|
|
577
|
+
},
|
|
561
578
|
{
|
|
562
579
|
key: "maxRecords",
|
|
563
580
|
label: "Buffer size",
|
|
@@ -667,6 +684,7 @@ function consoleViewState(c, options = {}) {
|
|
|
667
684
|
errors: s.counts.error > 0 ? String(s.counts.error) : void 0,
|
|
668
685
|
warns: s.counts.warn > 0 ? String(s.counts.warn) : void 0,
|
|
669
686
|
multiSource: s.sources.length > 1,
|
|
687
|
+
showRefresh: options.showRefresh === true,
|
|
670
688
|
sources: s.sources.map((src) => ({ id: src.id, label: src.label ?? src.id, on: src.enabled, title: `${src.count} records` })),
|
|
671
689
|
empty: s.rows.length === 0,
|
|
672
690
|
emptyTitle: s.total > 0 ? "No matches" : "No output",
|
|
@@ -705,6 +723,9 @@ function applyConsoleUi(c, intent) {
|
|
|
705
723
|
case "clear":
|
|
706
724
|
c.clear();
|
|
707
725
|
break;
|
|
726
|
+
case "refresh":
|
|
727
|
+
c.requestRefresh();
|
|
728
|
+
break;
|
|
708
729
|
case "source":
|
|
709
730
|
c.toggleSource(intent.id, intent.on);
|
|
710
731
|
break;
|
|
@@ -725,7 +746,7 @@ var consoleViewManifest = {
|
|
|
725
746
|
outputs: [{ id: "ui", name: "UI intent", type: "object", description: "{ kind, \u2026 } \u2014 applied by the runtime to the controller." }],
|
|
726
747
|
commands: []
|
|
727
748
|
};
|
|
728
|
-
var EMPTY = { search: "", levels: [], level: "trace", multiSource: false, sources: [], empty: true, emptyTitle: "No output", emptyHint: "Run something to see its output here.", listed: false, rowHeight: 20, totalHeight: 0, offsetTop: 0, rows: [], countLabel: "0 of 0" };
|
|
749
|
+
var EMPTY = { search: "", levels: [], level: "trace", multiSource: false, showRefresh: false, sources: [], empty: true, emptyTitle: "No output", emptyHint: "Run something to see its output here.", listed: false, rowHeight: 20, totalHeight: 0, offsetTop: 0, rows: [], countLabel: "0 of 0" };
|
|
729
750
|
var BEHAVIOURS = {
|
|
730
751
|
"ops/consolePanelView": (inputs) => inputs.view ?? EMPTY
|
|
731
752
|
};
|
|
@@ -758,6 +779,7 @@ var CONSOLE_DECLARATION = {
|
|
|
758
779
|
children: [
|
|
759
780
|
{ component: "chrome/Badge", when: { input: "view.errors" }, props: { tone: { value: "error" } }, children: [text({ input: "view.errors" })] },
|
|
760
781
|
{ component: "chrome/Badge", when: { input: "view.warns" }, props: { tone: { value: "warning" } }, children: [text({ input: "view.warns" })] },
|
|
782
|
+
{ component: "chrome/IconButton", when: { input: "view.showRefresh" }, props: { icon: { node: { component: "icons/Refresh" } }, label: { value: "Refresh" } }, on: { onClick: ui("refresh") } },
|
|
761
783
|
{ component: "chrome/IconButton", props: { icon: { node: { component: "icons/Copy" } }, label: { value: "Copy visible" } }, on: { onClick: ui("copyVisible") } },
|
|
762
784
|
{ component: "chrome/IconButton", props: { icon: { node: { component: "icons/Clear" } }, label: { value: "Clear" } }, on: { onClick: ui("clear") } }
|
|
763
785
|
]
|
|
@@ -828,6 +850,7 @@ var CONSOLE_DECLARATION = {
|
|
|
828
850
|
// src/ops/console/react/ConsolePanelView.tsx
|
|
829
851
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
830
852
|
var CopyGlyph = ICONS["icons/Copy"];
|
|
853
|
+
var RefreshGlyph = ICONS["icons/Refresh"];
|
|
831
854
|
var ClearGlyph = ICONS["icons/Clear"];
|
|
832
855
|
function ConsoleScroller({ controller, rowHeight = 20, children }) {
|
|
833
856
|
const state = useSyncExternalStore(controller.subscribe, controller.getState, controller.getState);
|
|
@@ -882,6 +905,7 @@ function ConsolePanelView({ controller, ...options }) {
|
|
|
882
905
|
right: /* @__PURE__ */ jsxs(ToolbarGroup, { end: true, children: [
|
|
883
906
|
view.errors ? /* @__PURE__ */ jsx(Badge, { tone: "error", children: view.errors }) : null,
|
|
884
907
|
view.warns ? /* @__PURE__ */ jsx(Badge, { tone: "warning", children: view.warns }) : null,
|
|
908
|
+
view.showRefresh ? /* @__PURE__ */ jsx(IconButton, { icon: /* @__PURE__ */ jsx(RefreshGlyph, {}), label: "Refresh", onClick: () => ui5({ kind: "refresh" }) }) : null,
|
|
885
909
|
/* @__PURE__ */ jsx(IconButton, { icon: /* @__PURE__ */ jsx(CopyGlyph, {}), label: "Copy visible", onClick: () => ui5({ kind: "copyVisible" }) }),
|
|
886
910
|
/* @__PURE__ */ jsx(IconButton, { icon: /* @__PURE__ */ jsx(ClearGlyph, {}), label: "Clear", onClick: () => ui5({ kind: "clear" }) })
|
|
887
911
|
] })
|
|
@@ -935,7 +959,8 @@ function createConsolePanel(options = {}) {
|
|
|
935
959
|
const resolve = (config2) => ({
|
|
936
960
|
rowHeight: numberConfig(config2.rowHeight, 20),
|
|
937
961
|
showTimestamps: config2.showTimestamps !== false,
|
|
938
|
-
emptyHint: typeof config2.emptyHint === "string" ? config2.emptyHint : void 0
|
|
962
|
+
emptyHint: typeof config2.emptyHint === "string" ? config2.emptyHint : void 0,
|
|
963
|
+
showRefresh: config2.showRefresh === true
|
|
939
964
|
});
|
|
940
965
|
let renderConfig = resolve(host.config ?? {});
|
|
941
966
|
let unrender = null;
|
package/dist/time/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xenosystem/blocks",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.3",
|
|
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",
|