dsh-motion-ui 0.5.3 → 0.5.4
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/CHANGELOG.md +9 -0
- package/README.md +6 -0
- package/VERIFICATION.md +18 -0
- package/client.js +386 -249
- package/index.js +16 -3
- package/lib/author-expression.js +3 -2
- package/lib/authoring-guide.js +9 -0
- package/lib/build-info.js +1 -1
- package/lib/canvas-preview.js +1 -1
- package/lib/canvas-system.js +3 -2
- package/lib/catalog.js +5 -4
- package/lib/components.js +2 -2
- package/lib/export-runtime-bundle.js +1 -1
- package/lib/freeform.js +3 -2
- package/lib/identifiers.js +4 -0
- package/lib/protocol.js +20 -11
- package/lib/stream.js +2 -1
- package/lib/tool-json.js +21 -2
- package/lib/tool-schema.js +29 -0
- package/package.json +1 -1
package/client.js
CHANGED
|
@@ -16,9 +16,9 @@ var __export = (target, all) => {
|
|
|
16
16
|
};
|
|
17
17
|
var __copyProps = (to, from, except, desc) => {
|
|
18
18
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
19
|
-
for (let
|
|
20
|
-
if (!__hasOwnProp.call(to,
|
|
21
|
-
__defProp(to,
|
|
19
|
+
for (let key2 of __getOwnPropNames(from))
|
|
20
|
+
if (!__hasOwnProp.call(to, key2) && key2 !== except)
|
|
21
|
+
__defProp(to, key2, { get: () => from[key2], enumerable: !(desc = __getOwnPropDesc(from, key2)) || desc.enumerable });
|
|
22
22
|
}
|
|
23
23
|
return to;
|
|
24
24
|
};
|
|
@@ -504,9 +504,9 @@ var require_react_dom_development = __commonJS({
|
|
|
504
504
|
if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined" && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart === "function") {
|
|
505
505
|
__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error());
|
|
506
506
|
}
|
|
507
|
-
var
|
|
507
|
+
var React10 = require("react");
|
|
508
508
|
var Scheduler = require_scheduler();
|
|
509
|
-
var ReactSharedInternals =
|
|
509
|
+
var ReactSharedInternals = React10.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
|
|
510
510
|
var suppressWarning = false;
|
|
511
511
|
function setSuppressWarning(newSuppressWarning) {
|
|
512
512
|
{
|
|
@@ -2113,7 +2113,7 @@ var require_react_dom_development = __commonJS({
|
|
|
2113
2113
|
{
|
|
2114
2114
|
if (props.value == null) {
|
|
2115
2115
|
if (typeof props.children === "object" && props.children !== null) {
|
|
2116
|
-
|
|
2116
|
+
React10.Children.forEach(props.children, function(child) {
|
|
2117
2117
|
if (child == null) {
|
|
2118
2118
|
return;
|
|
2119
2119
|
}
|
|
@@ -2506,8 +2506,8 @@ var require_react_dom_development = __commonJS({
|
|
|
2506
2506
|
strokeOpacity: true,
|
|
2507
2507
|
strokeWidth: true
|
|
2508
2508
|
};
|
|
2509
|
-
function prefixKey(prefix2,
|
|
2510
|
-
return prefix2 +
|
|
2509
|
+
function prefixKey(prefix2, key2) {
|
|
2510
|
+
return prefix2 + key2.charAt(0).toUpperCase() + key2.substring(1);
|
|
2511
2511
|
}
|
|
2512
2512
|
var prefixes = ["Webkit", "ms", "Moz", "O"];
|
|
2513
2513
|
Object.keys(isUnitlessNumber).forEach(function(prop) {
|
|
@@ -2656,10 +2656,10 @@ var require_react_dom_development = __commonJS({
|
|
|
2656
2656
|
}
|
|
2657
2657
|
function expandShorthandMap(styles) {
|
|
2658
2658
|
var expanded = {};
|
|
2659
|
-
for (var
|
|
2660
|
-
var longhands = shorthandToLonghand[
|
|
2659
|
+
for (var key2 in styles) {
|
|
2660
|
+
var longhands = shorthandToLonghand[key2] || [key2];
|
|
2661
2661
|
for (var i = 0; i < longhands.length; i++) {
|
|
2662
|
-
expanded[longhands[i]] =
|
|
2662
|
+
expanded[longhands[i]] = key2;
|
|
2663
2663
|
}
|
|
2664
2664
|
}
|
|
2665
2665
|
return expanded;
|
|
@@ -2672,9 +2672,9 @@ var require_react_dom_development = __commonJS({
|
|
|
2672
2672
|
var expandedUpdates = expandShorthandMap(styleUpdates);
|
|
2673
2673
|
var expandedStyles = expandShorthandMap(nextStyles);
|
|
2674
2674
|
var warnedAbout = {};
|
|
2675
|
-
for (var
|
|
2676
|
-
var originalKey = expandedUpdates[
|
|
2677
|
-
var correctOriginalKey = expandedStyles[
|
|
2675
|
+
for (var key2 in expandedUpdates) {
|
|
2676
|
+
var originalKey = expandedUpdates[key2];
|
|
2677
|
+
var correctOriginalKey = expandedStyles[key2];
|
|
2678
2678
|
if (correctOriginalKey && originalKey !== correctOriginalKey) {
|
|
2679
2679
|
var warningKey = originalKey + "," + correctOriginalKey;
|
|
2680
2680
|
if (warnedAbout[warningKey]) {
|
|
@@ -3345,10 +3345,10 @@ var require_react_dom_development = __commonJS({
|
|
|
3345
3345
|
function warnInvalidARIAProps(type, props) {
|
|
3346
3346
|
{
|
|
3347
3347
|
var invalidProps = [];
|
|
3348
|
-
for (var
|
|
3349
|
-
var isValid = validateProperty(type,
|
|
3348
|
+
for (var key2 in props) {
|
|
3349
|
+
var isValid = validateProperty(type, key2);
|
|
3350
3350
|
if (!isValid) {
|
|
3351
|
-
invalidProps.push(
|
|
3351
|
+
invalidProps.push(key2);
|
|
3352
3352
|
}
|
|
3353
3353
|
}
|
|
3354
3354
|
var unknownPropString = invalidProps.map(function(prop) {
|
|
@@ -3488,10 +3488,10 @@ var require_react_dom_development = __commonJS({
|
|
|
3488
3488
|
var warnUnknownProperties = function(type, props, eventRegistry) {
|
|
3489
3489
|
{
|
|
3490
3490
|
var unknownProps = [];
|
|
3491
|
-
for (var
|
|
3492
|
-
var isValid = validateProperty$1(type,
|
|
3491
|
+
for (var key2 in props) {
|
|
3492
|
+
var isValid = validateProperty$1(type, key2, props[key2], eventRegistry);
|
|
3493
3493
|
if (!isValid) {
|
|
3494
|
-
unknownProps.push(
|
|
3494
|
+
unknownProps.push(key2);
|
|
3495
3495
|
}
|
|
3496
3496
|
}
|
|
3497
3497
|
var unknownPropString = unknownProps.map(function(prop) {
|
|
@@ -3796,14 +3796,14 @@ var require_react_dom_development = __commonJS({
|
|
|
3796
3796
|
throw new Error("clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue.");
|
|
3797
3797
|
}
|
|
3798
3798
|
}
|
|
3799
|
-
function get(
|
|
3800
|
-
return
|
|
3799
|
+
function get(key2) {
|
|
3800
|
+
return key2._reactInternals;
|
|
3801
3801
|
}
|
|
3802
|
-
function has(
|
|
3803
|
-
return
|
|
3802
|
+
function has(key2) {
|
|
3803
|
+
return key2._reactInternals !== void 0;
|
|
3804
3804
|
}
|
|
3805
|
-
function set(
|
|
3806
|
-
|
|
3805
|
+
function set(key2, value) {
|
|
3806
|
+
key2._reactInternals = value;
|
|
3807
3807
|
}
|
|
3808
3808
|
var NoFlags = (
|
|
3809
3809
|
/* */
|
|
@@ -5378,9 +5378,9 @@ var require_react_dom_development = __commonJS({
|
|
|
5378
5378
|
}
|
|
5379
5379
|
return true;
|
|
5380
5380
|
}
|
|
5381
|
-
function attemptReplayContinuousQueuedEventInMap(queuedEvent,
|
|
5381
|
+
function attemptReplayContinuousQueuedEventInMap(queuedEvent, key2, map) {
|
|
5382
5382
|
if (attemptReplayContinuousQueuedEvent(queuedEvent)) {
|
|
5383
|
-
map.delete(
|
|
5383
|
+
map.delete(key2);
|
|
5384
5384
|
}
|
|
5385
5385
|
}
|
|
5386
5386
|
function replayUnblockedEvents() {
|
|
@@ -5976,9 +5976,9 @@ var require_react_dom_development = __commonJS({
|
|
|
5976
5976
|
};
|
|
5977
5977
|
function getEventKey(nativeEvent) {
|
|
5978
5978
|
if (nativeEvent.key) {
|
|
5979
|
-
var
|
|
5980
|
-
if (
|
|
5981
|
-
return
|
|
5979
|
+
var key2 = normalizeKey[nativeEvent.key] || nativeEvent.key;
|
|
5980
|
+
if (key2 !== "Unidentified") {
|
|
5981
|
+
return key2;
|
|
5982
5982
|
}
|
|
5983
5983
|
}
|
|
5984
5984
|
if (nativeEvent.type === "keypress") {
|
|
@@ -9033,8 +9033,8 @@ var require_react_dom_development = __commonJS({
|
|
|
9033
9033
|
return instance.__reactInternalMemoizedMaskedChildContext;
|
|
9034
9034
|
}
|
|
9035
9035
|
var context = {};
|
|
9036
|
-
for (var
|
|
9037
|
-
context[
|
|
9036
|
+
for (var key2 in contextTypes) {
|
|
9037
|
+
context[key2] = unmaskedContext[key2];
|
|
9038
9038
|
}
|
|
9039
9039
|
{
|
|
9040
9040
|
var name = getComponentNameFromFiber(workInProgress2) || "Unknown";
|
|
@@ -10140,9 +10140,9 @@ var require_react_dom_development = __commonJS({
|
|
|
10140
10140
|
return existing;
|
|
10141
10141
|
}
|
|
10142
10142
|
}
|
|
10143
|
-
function updateFragment2(returnFiber, current3, fragment, lanes,
|
|
10143
|
+
function updateFragment2(returnFiber, current3, fragment, lanes, key2) {
|
|
10144
10144
|
if (current3 === null || current3.tag !== Fragment) {
|
|
10145
|
-
var created = createFiberFromFragment(fragment, returnFiber.mode, lanes,
|
|
10145
|
+
var created = createFiberFromFragment(fragment, returnFiber.mode, lanes, key2);
|
|
10146
10146
|
created.return = returnFiber;
|
|
10147
10147
|
return created;
|
|
10148
10148
|
} else {
|
|
@@ -10191,9 +10191,9 @@ var require_react_dom_development = __commonJS({
|
|
|
10191
10191
|
return null;
|
|
10192
10192
|
}
|
|
10193
10193
|
function updateSlot(returnFiber, oldFiber, newChild, lanes) {
|
|
10194
|
-
var
|
|
10194
|
+
var key2 = oldFiber !== null ? oldFiber.key : null;
|
|
10195
10195
|
if (typeof newChild === "string" && newChild !== "" || typeof newChild === "number") {
|
|
10196
|
-
if (
|
|
10196
|
+
if (key2 !== null) {
|
|
10197
10197
|
return null;
|
|
10198
10198
|
}
|
|
10199
10199
|
return updateTextNode(returnFiber, oldFiber, "" + newChild, lanes);
|
|
@@ -10201,14 +10201,14 @@ var require_react_dom_development = __commonJS({
|
|
|
10201
10201
|
if (typeof newChild === "object" && newChild !== null) {
|
|
10202
10202
|
switch (newChild.$$typeof) {
|
|
10203
10203
|
case REACT_ELEMENT_TYPE: {
|
|
10204
|
-
if (newChild.key ===
|
|
10204
|
+
if (newChild.key === key2) {
|
|
10205
10205
|
return updateElement(returnFiber, oldFiber, newChild, lanes);
|
|
10206
10206
|
} else {
|
|
10207
10207
|
return null;
|
|
10208
10208
|
}
|
|
10209
10209
|
}
|
|
10210
10210
|
case REACT_PORTAL_TYPE: {
|
|
10211
|
-
if (newChild.key ===
|
|
10211
|
+
if (newChild.key === key2) {
|
|
10212
10212
|
return updatePortal(returnFiber, oldFiber, newChild, lanes);
|
|
10213
10213
|
} else {
|
|
10214
10214
|
return null;
|
|
@@ -10221,7 +10221,7 @@ var require_react_dom_development = __commonJS({
|
|
|
10221
10221
|
}
|
|
10222
10222
|
}
|
|
10223
10223
|
if (isArray(newChild) || getIteratorFn(newChild)) {
|
|
10224
|
-
if (
|
|
10224
|
+
if (key2 !== null) {
|
|
10225
10225
|
return null;
|
|
10226
10226
|
}
|
|
10227
10227
|
return updateFragment2(returnFiber, oldFiber, newChild, lanes, null);
|
|
@@ -10277,20 +10277,20 @@ var require_react_dom_development = __commonJS({
|
|
|
10277
10277
|
case REACT_ELEMENT_TYPE:
|
|
10278
10278
|
case REACT_PORTAL_TYPE:
|
|
10279
10279
|
warnForMissingKey(child, returnFiber);
|
|
10280
|
-
var
|
|
10281
|
-
if (typeof
|
|
10280
|
+
var key2 = child.key;
|
|
10281
|
+
if (typeof key2 !== "string") {
|
|
10282
10282
|
break;
|
|
10283
10283
|
}
|
|
10284
10284
|
if (knownKeys === null) {
|
|
10285
10285
|
knownKeys = /* @__PURE__ */ new Set();
|
|
10286
|
-
knownKeys.add(
|
|
10286
|
+
knownKeys.add(key2);
|
|
10287
10287
|
break;
|
|
10288
10288
|
}
|
|
10289
|
-
if (!knownKeys.has(
|
|
10290
|
-
knownKeys.add(
|
|
10289
|
+
if (!knownKeys.has(key2)) {
|
|
10290
|
+
knownKeys.add(key2);
|
|
10291
10291
|
break;
|
|
10292
10292
|
}
|
|
10293
|
-
error("Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted \u2014 the behavior is unsupported and could change in a future version.",
|
|
10293
|
+
error("Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted \u2014 the behavior is unsupported and could change in a future version.", key2);
|
|
10294
10294
|
break;
|
|
10295
10295
|
case REACT_LAZY_TYPE:
|
|
10296
10296
|
var payload = child._payload;
|
|
@@ -10538,10 +10538,10 @@ var require_react_dom_development = __commonJS({
|
|
|
10538
10538
|
return created;
|
|
10539
10539
|
}
|
|
10540
10540
|
function reconcileSingleElement(returnFiber, currentFirstChild, element, lanes) {
|
|
10541
|
-
var
|
|
10541
|
+
var key2 = element.key;
|
|
10542
10542
|
var child = currentFirstChild;
|
|
10543
10543
|
while (child !== null) {
|
|
10544
|
-
if (child.key ===
|
|
10544
|
+
if (child.key === key2) {
|
|
10545
10545
|
var elementType = element.type;
|
|
10546
10546
|
if (elementType === REACT_FRAGMENT_TYPE) {
|
|
10547
10547
|
if (child.tag === Fragment) {
|
|
@@ -10591,10 +10591,10 @@ var require_react_dom_development = __commonJS({
|
|
|
10591
10591
|
}
|
|
10592
10592
|
}
|
|
10593
10593
|
function reconcileSinglePortal(returnFiber, currentFirstChild, portal, lanes) {
|
|
10594
|
-
var
|
|
10594
|
+
var key2 = portal.key;
|
|
10595
10595
|
var child = currentFirstChild;
|
|
10596
10596
|
while (child !== null) {
|
|
10597
|
-
if (child.key ===
|
|
10597
|
+
if (child.key === key2) {
|
|
10598
10598
|
if (child.tag === HostPortal && child.stateNode.containerInfo === portal.containerInfo && child.stateNode.implementation === portal.implementation) {
|
|
10599
10599
|
deleteRemainingChildren(returnFiber, child.sibling);
|
|
10600
10600
|
var existing = useFiber(child, portal.children || []);
|
|
@@ -11929,17 +11929,17 @@ var require_react_dom_development = __commonJS({
|
|
|
11929
11929
|
}
|
|
11930
11930
|
return [newState, dispatch];
|
|
11931
11931
|
}
|
|
11932
|
-
function mountMutableSource(source, getSnapshot,
|
|
11932
|
+
function mountMutableSource(source, getSnapshot, subscribe2) {
|
|
11933
11933
|
{
|
|
11934
11934
|
return void 0;
|
|
11935
11935
|
}
|
|
11936
11936
|
}
|
|
11937
|
-
function updateMutableSource(source, getSnapshot,
|
|
11937
|
+
function updateMutableSource(source, getSnapshot, subscribe2) {
|
|
11938
11938
|
{
|
|
11939
11939
|
return void 0;
|
|
11940
11940
|
}
|
|
11941
11941
|
}
|
|
11942
|
-
function mountSyncExternalStore(
|
|
11942
|
+
function mountSyncExternalStore(subscribe2, getSnapshot, getServerSnapshot) {
|
|
11943
11943
|
var fiber = currentlyRenderingFiber$1;
|
|
11944
11944
|
var hook = mountWorkInProgressHook();
|
|
11945
11945
|
var nextSnapshot;
|
|
@@ -11982,12 +11982,12 @@ var require_react_dom_development = __commonJS({
|
|
|
11982
11982
|
getSnapshot
|
|
11983
11983
|
};
|
|
11984
11984
|
hook.queue = inst;
|
|
11985
|
-
mountEffect(subscribeToStore.bind(null, fiber, inst,
|
|
11985
|
+
mountEffect(subscribeToStore.bind(null, fiber, inst, subscribe2), [subscribe2]);
|
|
11986
11986
|
fiber.flags |= Passive;
|
|
11987
11987
|
pushEffect(HasEffect | Passive$1, updateStoreInstance.bind(null, fiber, inst, nextSnapshot, getSnapshot), void 0, null);
|
|
11988
11988
|
return nextSnapshot;
|
|
11989
11989
|
}
|
|
11990
|
-
function updateSyncExternalStore(
|
|
11990
|
+
function updateSyncExternalStore(subscribe2, getSnapshot, getServerSnapshot) {
|
|
11991
11991
|
var fiber = currentlyRenderingFiber$1;
|
|
11992
11992
|
var hook = updateWorkInProgressHook();
|
|
11993
11993
|
var nextSnapshot = getSnapshot();
|
|
@@ -12007,7 +12007,7 @@ var require_react_dom_development = __commonJS({
|
|
|
12007
12007
|
markWorkInProgressReceivedUpdate();
|
|
12008
12008
|
}
|
|
12009
12009
|
var inst = hook.queue;
|
|
12010
|
-
updateEffect(subscribeToStore.bind(null, fiber, inst,
|
|
12010
|
+
updateEffect(subscribeToStore.bind(null, fiber, inst, subscribe2), [subscribe2]);
|
|
12011
12011
|
if (inst.getSnapshot !== getSnapshot || snapshotChanged || // Check if the susbcribe function changed. We can save some memory by
|
|
12012
12012
|
// checking whether we scheduled a subscription effect above.
|
|
12013
12013
|
workInProgressHook !== null && workInProgressHook.memoizedState.tag & HasEffect) {
|
|
@@ -12050,13 +12050,13 @@ var require_react_dom_development = __commonJS({
|
|
|
12050
12050
|
forceStoreRerender(fiber);
|
|
12051
12051
|
}
|
|
12052
12052
|
}
|
|
12053
|
-
function subscribeToStore(fiber, inst,
|
|
12053
|
+
function subscribeToStore(fiber, inst, subscribe2) {
|
|
12054
12054
|
var handleStoreChange = function() {
|
|
12055
12055
|
if (checkIfSnapshotChanged(inst)) {
|
|
12056
12056
|
forceStoreRerender(fiber);
|
|
12057
12057
|
}
|
|
12058
12058
|
};
|
|
12059
|
-
return
|
|
12059
|
+
return subscribe2(handleStoreChange);
|
|
12060
12060
|
}
|
|
12061
12061
|
function checkIfSnapshotChanged(inst) {
|
|
12062
12062
|
var latestGetSnapshot = inst.getSnapshot;
|
|
@@ -12637,15 +12637,15 @@ var require_react_dom_development = __commonJS({
|
|
|
12637
12637
|
mountHookTypesDev();
|
|
12638
12638
|
return mountTransition();
|
|
12639
12639
|
},
|
|
12640
|
-
useMutableSource: function(source, getSnapshot,
|
|
12640
|
+
useMutableSource: function(source, getSnapshot, subscribe2) {
|
|
12641
12641
|
currentHookNameInDev = "useMutableSource";
|
|
12642
12642
|
mountHookTypesDev();
|
|
12643
12643
|
return mountMutableSource();
|
|
12644
12644
|
},
|
|
12645
|
-
useSyncExternalStore: function(
|
|
12645
|
+
useSyncExternalStore: function(subscribe2, getSnapshot, getServerSnapshot) {
|
|
12646
12646
|
currentHookNameInDev = "useSyncExternalStore";
|
|
12647
12647
|
mountHookTypesDev();
|
|
12648
|
-
return mountSyncExternalStore(
|
|
12648
|
+
return mountSyncExternalStore(subscribe2, getSnapshot, getServerSnapshot);
|
|
12649
12649
|
},
|
|
12650
12650
|
useId: function() {
|
|
12651
12651
|
currentHookNameInDev = "useId";
|
|
@@ -12741,15 +12741,15 @@ var require_react_dom_development = __commonJS({
|
|
|
12741
12741
|
updateHookTypesDev();
|
|
12742
12742
|
return mountTransition();
|
|
12743
12743
|
},
|
|
12744
|
-
useMutableSource: function(source, getSnapshot,
|
|
12744
|
+
useMutableSource: function(source, getSnapshot, subscribe2) {
|
|
12745
12745
|
currentHookNameInDev = "useMutableSource";
|
|
12746
12746
|
updateHookTypesDev();
|
|
12747
12747
|
return mountMutableSource();
|
|
12748
12748
|
},
|
|
12749
|
-
useSyncExternalStore: function(
|
|
12749
|
+
useSyncExternalStore: function(subscribe2, getSnapshot, getServerSnapshot) {
|
|
12750
12750
|
currentHookNameInDev = "useSyncExternalStore";
|
|
12751
12751
|
updateHookTypesDev();
|
|
12752
|
-
return mountSyncExternalStore(
|
|
12752
|
+
return mountSyncExternalStore(subscribe2, getSnapshot, getServerSnapshot);
|
|
12753
12753
|
},
|
|
12754
12754
|
useId: function() {
|
|
12755
12755
|
currentHookNameInDev = "useId";
|
|
@@ -12845,15 +12845,15 @@ var require_react_dom_development = __commonJS({
|
|
|
12845
12845
|
updateHookTypesDev();
|
|
12846
12846
|
return updateTransition();
|
|
12847
12847
|
},
|
|
12848
|
-
useMutableSource: function(source, getSnapshot,
|
|
12848
|
+
useMutableSource: function(source, getSnapshot, subscribe2) {
|
|
12849
12849
|
currentHookNameInDev = "useMutableSource";
|
|
12850
12850
|
updateHookTypesDev();
|
|
12851
12851
|
return updateMutableSource();
|
|
12852
12852
|
},
|
|
12853
|
-
useSyncExternalStore: function(
|
|
12853
|
+
useSyncExternalStore: function(subscribe2, getSnapshot, getServerSnapshot) {
|
|
12854
12854
|
currentHookNameInDev = "useSyncExternalStore";
|
|
12855
12855
|
updateHookTypesDev();
|
|
12856
|
-
return updateSyncExternalStore(
|
|
12856
|
+
return updateSyncExternalStore(subscribe2, getSnapshot);
|
|
12857
12857
|
},
|
|
12858
12858
|
useId: function() {
|
|
12859
12859
|
currentHookNameInDev = "useId";
|
|
@@ -12949,15 +12949,15 @@ var require_react_dom_development = __commonJS({
|
|
|
12949
12949
|
updateHookTypesDev();
|
|
12950
12950
|
return rerenderTransition();
|
|
12951
12951
|
},
|
|
12952
|
-
useMutableSource: function(source, getSnapshot,
|
|
12952
|
+
useMutableSource: function(source, getSnapshot, subscribe2) {
|
|
12953
12953
|
currentHookNameInDev = "useMutableSource";
|
|
12954
12954
|
updateHookTypesDev();
|
|
12955
12955
|
return updateMutableSource();
|
|
12956
12956
|
},
|
|
12957
|
-
useSyncExternalStore: function(
|
|
12957
|
+
useSyncExternalStore: function(subscribe2, getSnapshot, getServerSnapshot) {
|
|
12958
12958
|
currentHookNameInDev = "useSyncExternalStore";
|
|
12959
12959
|
updateHookTypesDev();
|
|
12960
|
-
return updateSyncExternalStore(
|
|
12960
|
+
return updateSyncExternalStore(subscribe2, getSnapshot);
|
|
12961
12961
|
},
|
|
12962
12962
|
useId: function() {
|
|
12963
12963
|
currentHookNameInDev = "useId";
|
|
@@ -13067,17 +13067,17 @@ var require_react_dom_development = __commonJS({
|
|
|
13067
13067
|
mountHookTypesDev();
|
|
13068
13068
|
return mountTransition();
|
|
13069
13069
|
},
|
|
13070
|
-
useMutableSource: function(source, getSnapshot,
|
|
13070
|
+
useMutableSource: function(source, getSnapshot, subscribe2) {
|
|
13071
13071
|
currentHookNameInDev = "useMutableSource";
|
|
13072
13072
|
warnInvalidHookAccess();
|
|
13073
13073
|
mountHookTypesDev();
|
|
13074
13074
|
return mountMutableSource();
|
|
13075
13075
|
},
|
|
13076
|
-
useSyncExternalStore: function(
|
|
13076
|
+
useSyncExternalStore: function(subscribe2, getSnapshot, getServerSnapshot) {
|
|
13077
13077
|
currentHookNameInDev = "useSyncExternalStore";
|
|
13078
13078
|
warnInvalidHookAccess();
|
|
13079
13079
|
mountHookTypesDev();
|
|
13080
|
-
return mountSyncExternalStore(
|
|
13080
|
+
return mountSyncExternalStore(subscribe2, getSnapshot, getServerSnapshot);
|
|
13081
13081
|
},
|
|
13082
13082
|
useId: function() {
|
|
13083
13083
|
currentHookNameInDev = "useId";
|
|
@@ -13188,17 +13188,17 @@ var require_react_dom_development = __commonJS({
|
|
|
13188
13188
|
updateHookTypesDev();
|
|
13189
13189
|
return updateTransition();
|
|
13190
13190
|
},
|
|
13191
|
-
useMutableSource: function(source, getSnapshot,
|
|
13191
|
+
useMutableSource: function(source, getSnapshot, subscribe2) {
|
|
13192
13192
|
currentHookNameInDev = "useMutableSource";
|
|
13193
13193
|
warnInvalidHookAccess();
|
|
13194
13194
|
updateHookTypesDev();
|
|
13195
13195
|
return updateMutableSource();
|
|
13196
13196
|
},
|
|
13197
|
-
useSyncExternalStore: function(
|
|
13197
|
+
useSyncExternalStore: function(subscribe2, getSnapshot, getServerSnapshot) {
|
|
13198
13198
|
currentHookNameInDev = "useSyncExternalStore";
|
|
13199
13199
|
warnInvalidHookAccess();
|
|
13200
13200
|
updateHookTypesDev();
|
|
13201
|
-
return updateSyncExternalStore(
|
|
13201
|
+
return updateSyncExternalStore(subscribe2, getSnapshot);
|
|
13202
13202
|
},
|
|
13203
13203
|
useId: function() {
|
|
13204
13204
|
currentHookNameInDev = "useId";
|
|
@@ -13309,17 +13309,17 @@ var require_react_dom_development = __commonJS({
|
|
|
13309
13309
|
updateHookTypesDev();
|
|
13310
13310
|
return rerenderTransition();
|
|
13311
13311
|
},
|
|
13312
|
-
useMutableSource: function(source, getSnapshot,
|
|
13312
|
+
useMutableSource: function(source, getSnapshot, subscribe2) {
|
|
13313
13313
|
currentHookNameInDev = "useMutableSource";
|
|
13314
13314
|
warnInvalidHookAccess();
|
|
13315
13315
|
updateHookTypesDev();
|
|
13316
13316
|
return updateMutableSource();
|
|
13317
13317
|
},
|
|
13318
|
-
useSyncExternalStore: function(
|
|
13318
|
+
useSyncExternalStore: function(subscribe2, getSnapshot, getServerSnapshot) {
|
|
13319
13319
|
currentHookNameInDev = "useSyncExternalStore";
|
|
13320
13320
|
warnInvalidHookAccess();
|
|
13321
13321
|
updateHookTypesDev();
|
|
13322
|
-
return updateSyncExternalStore(
|
|
13322
|
+
return updateSyncExternalStore(subscribe2, getSnapshot);
|
|
13323
13323
|
},
|
|
13324
13324
|
useId: function() {
|
|
13325
13325
|
currentHookNameInDev = "useId";
|
|
@@ -13479,9 +13479,9 @@ var require_react_dom_development = __commonJS({
|
|
|
13479
13479
|
if (callback === null || typeof callback === "function") {
|
|
13480
13480
|
return;
|
|
13481
13481
|
}
|
|
13482
|
-
var
|
|
13483
|
-
if (!didWarnOnInvalidCallback.has(
|
|
13484
|
-
didWarnOnInvalidCallback.add(
|
|
13482
|
+
var key2 = callerName + "_" + callback;
|
|
13483
|
+
if (!didWarnOnInvalidCallback.has(key2)) {
|
|
13484
|
+
didWarnOnInvalidCallback.add(key2);
|
|
13485
13485
|
error("%s(...): Expected the last optional `callback` argument to be a function. Instead received: %s.", callerName, callback);
|
|
13486
13486
|
}
|
|
13487
13487
|
};
|
|
@@ -16893,15 +16893,15 @@ var require_react_dom_development = __commonJS({
|
|
|
16893
16893
|
}
|
|
16894
16894
|
}
|
|
16895
16895
|
}
|
|
16896
|
-
var
|
|
16896
|
+
var snapshot2 = instance.getSnapshotBeforeUpdate(finishedWork.elementType === finishedWork.type ? prevProps : resolveDefaultProps(finishedWork.type, prevProps), prevState);
|
|
16897
16897
|
{
|
|
16898
16898
|
var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate;
|
|
16899
|
-
if (
|
|
16899
|
+
if (snapshot2 === void 0 && !didWarnSet.has(finishedWork.type)) {
|
|
16900
16900
|
didWarnSet.add(finishedWork.type);
|
|
16901
16901
|
error("%s.getSnapshotBeforeUpdate(): A snapshot value (or null) must be returned. You have returned undefined.", getComponentNameFromFiber(finishedWork));
|
|
16902
16902
|
}
|
|
16903
16903
|
}
|
|
16904
|
-
instance.__reactInternalSnapshotBeforeUpdate =
|
|
16904
|
+
instance.__reactInternalSnapshotBeforeUpdate = snapshot2;
|
|
16905
16905
|
}
|
|
16906
16906
|
break;
|
|
16907
16907
|
}
|
|
@@ -20259,9 +20259,9 @@ var require_react_dom_development = __commonJS({
|
|
|
20259
20259
|
hasBadMapPolyfill = true;
|
|
20260
20260
|
}
|
|
20261
20261
|
}
|
|
20262
|
-
function FiberNode(tag, pendingProps,
|
|
20262
|
+
function FiberNode(tag, pendingProps, key2, mode) {
|
|
20263
20263
|
this.tag = tag;
|
|
20264
|
-
this.key =
|
|
20264
|
+
this.key = key2;
|
|
20265
20265
|
this.elementType = null;
|
|
20266
20266
|
this.type = null;
|
|
20267
20267
|
this.stateNode = null;
|
|
@@ -20302,8 +20302,8 @@ var require_react_dom_development = __commonJS({
|
|
|
20302
20302
|
}
|
|
20303
20303
|
}
|
|
20304
20304
|
}
|
|
20305
|
-
var createFiber = function(tag, pendingProps,
|
|
20306
|
-
return new FiberNode(tag, pendingProps,
|
|
20305
|
+
var createFiber = function(tag, pendingProps, key2, mode) {
|
|
20306
|
+
return new FiberNode(tag, pendingProps, key2, mode);
|
|
20307
20307
|
};
|
|
20308
20308
|
function shouldConstruct$1(Component) {
|
|
20309
20309
|
var prototype = Component.prototype;
|
|
@@ -20445,7 +20445,7 @@ var require_react_dom_development = __commonJS({
|
|
|
20445
20445
|
}
|
|
20446
20446
|
return createFiber(HostRoot, null, null, mode);
|
|
20447
20447
|
}
|
|
20448
|
-
function createFiberFromTypeAndProps(type,
|
|
20448
|
+
function createFiberFromTypeAndProps(type, key2, pendingProps, owner, mode, lanes) {
|
|
20449
20449
|
var fiberTag = IndeterminateComponent;
|
|
20450
20450
|
var resolvedType = type;
|
|
20451
20451
|
if (typeof type === "function") {
|
|
@@ -20464,7 +20464,7 @@ var require_react_dom_development = __commonJS({
|
|
|
20464
20464
|
} else {
|
|
20465
20465
|
getTag: switch (type) {
|
|
20466
20466
|
case REACT_FRAGMENT_TYPE:
|
|
20467
|
-
return createFiberFromFragment(pendingProps.children, mode, lanes,
|
|
20467
|
+
return createFiberFromFragment(pendingProps.children, mode, lanes, key2);
|
|
20468
20468
|
case REACT_STRICT_MODE_TYPE:
|
|
20469
20469
|
fiberTag = Mode;
|
|
20470
20470
|
mode |= StrictLegacyMode;
|
|
@@ -20473,13 +20473,13 @@ var require_react_dom_development = __commonJS({
|
|
|
20473
20473
|
}
|
|
20474
20474
|
break;
|
|
20475
20475
|
case REACT_PROFILER_TYPE:
|
|
20476
|
-
return createFiberFromProfiler(pendingProps, mode, lanes,
|
|
20476
|
+
return createFiberFromProfiler(pendingProps, mode, lanes, key2);
|
|
20477
20477
|
case REACT_SUSPENSE_TYPE:
|
|
20478
|
-
return createFiberFromSuspense(pendingProps, mode, lanes,
|
|
20478
|
+
return createFiberFromSuspense(pendingProps, mode, lanes, key2);
|
|
20479
20479
|
case REACT_SUSPENSE_LIST_TYPE:
|
|
20480
|
-
return createFiberFromSuspenseList(pendingProps, mode, lanes,
|
|
20480
|
+
return createFiberFromSuspenseList(pendingProps, mode, lanes, key2);
|
|
20481
20481
|
case REACT_OFFSCREEN_TYPE:
|
|
20482
|
-
return createFiberFromOffscreen(pendingProps, mode, lanes,
|
|
20482
|
+
return createFiberFromOffscreen(pendingProps, mode, lanes, key2);
|
|
20483
20483
|
case REACT_LEGACY_HIDDEN_TYPE:
|
|
20484
20484
|
// eslint-disable-next-line no-fallthrough
|
|
20485
20485
|
case REACT_SCOPE_TYPE:
|
|
@@ -20528,7 +20528,7 @@ var require_react_dom_development = __commonJS({
|
|
|
20528
20528
|
}
|
|
20529
20529
|
}
|
|
20530
20530
|
}
|
|
20531
|
-
var fiber = createFiber(fiberTag, pendingProps,
|
|
20531
|
+
var fiber = createFiber(fiberTag, pendingProps, key2, mode);
|
|
20532
20532
|
fiber.elementType = type;
|
|
20533
20533
|
fiber.type = resolvedType;
|
|
20534
20534
|
fiber.lanes = lanes;
|
|
@@ -20543,27 +20543,27 @@ var require_react_dom_development = __commonJS({
|
|
|
20543
20543
|
owner = element._owner;
|
|
20544
20544
|
}
|
|
20545
20545
|
var type = element.type;
|
|
20546
|
-
var
|
|
20546
|
+
var key2 = element.key;
|
|
20547
20547
|
var pendingProps = element.props;
|
|
20548
|
-
var fiber = createFiberFromTypeAndProps(type,
|
|
20548
|
+
var fiber = createFiberFromTypeAndProps(type, key2, pendingProps, owner, mode, lanes);
|
|
20549
20549
|
{
|
|
20550
20550
|
fiber._debugSource = element._source;
|
|
20551
20551
|
fiber._debugOwner = element._owner;
|
|
20552
20552
|
}
|
|
20553
20553
|
return fiber;
|
|
20554
20554
|
}
|
|
20555
|
-
function createFiberFromFragment(elements, mode, lanes,
|
|
20556
|
-
var fiber = createFiber(Fragment, elements,
|
|
20555
|
+
function createFiberFromFragment(elements, mode, lanes, key2) {
|
|
20556
|
+
var fiber = createFiber(Fragment, elements, key2, mode);
|
|
20557
20557
|
fiber.lanes = lanes;
|
|
20558
20558
|
return fiber;
|
|
20559
20559
|
}
|
|
20560
|
-
function createFiberFromProfiler(pendingProps, mode, lanes,
|
|
20560
|
+
function createFiberFromProfiler(pendingProps, mode, lanes, key2) {
|
|
20561
20561
|
{
|
|
20562
20562
|
if (typeof pendingProps.id !== "string") {
|
|
20563
20563
|
error('Profiler must specify an "id" of type `string` as a prop. Received the type `%s` instead.', typeof pendingProps.id);
|
|
20564
20564
|
}
|
|
20565
20565
|
}
|
|
20566
|
-
var fiber = createFiber(Profiler, pendingProps,
|
|
20566
|
+
var fiber = createFiber(Profiler, pendingProps, key2, mode | ProfileMode);
|
|
20567
20567
|
fiber.elementType = REACT_PROFILER_TYPE;
|
|
20568
20568
|
fiber.lanes = lanes;
|
|
20569
20569
|
{
|
|
@@ -20574,20 +20574,20 @@ var require_react_dom_development = __commonJS({
|
|
|
20574
20574
|
}
|
|
20575
20575
|
return fiber;
|
|
20576
20576
|
}
|
|
20577
|
-
function createFiberFromSuspense(pendingProps, mode, lanes,
|
|
20578
|
-
var fiber = createFiber(SuspenseComponent, pendingProps,
|
|
20577
|
+
function createFiberFromSuspense(pendingProps, mode, lanes, key2) {
|
|
20578
|
+
var fiber = createFiber(SuspenseComponent, pendingProps, key2, mode);
|
|
20579
20579
|
fiber.elementType = REACT_SUSPENSE_TYPE;
|
|
20580
20580
|
fiber.lanes = lanes;
|
|
20581
20581
|
return fiber;
|
|
20582
20582
|
}
|
|
20583
|
-
function createFiberFromSuspenseList(pendingProps, mode, lanes,
|
|
20584
|
-
var fiber = createFiber(SuspenseListComponent, pendingProps,
|
|
20583
|
+
function createFiberFromSuspenseList(pendingProps, mode, lanes, key2) {
|
|
20584
|
+
var fiber = createFiber(SuspenseListComponent, pendingProps, key2, mode);
|
|
20585
20585
|
fiber.elementType = REACT_SUSPENSE_LIST_TYPE;
|
|
20586
20586
|
fiber.lanes = lanes;
|
|
20587
20587
|
return fiber;
|
|
20588
20588
|
}
|
|
20589
|
-
function createFiberFromOffscreen(pendingProps, mode, lanes,
|
|
20590
|
-
var fiber = createFiber(OffscreenComponent, pendingProps,
|
|
20589
|
+
function createFiberFromOffscreen(pendingProps, mode, lanes, key2) {
|
|
20590
|
+
var fiber = createFiber(OffscreenComponent, pendingProps, key2, mode);
|
|
20591
20591
|
fiber.elementType = REACT_OFFSCREEN_TYPE;
|
|
20592
20592
|
fiber.lanes = lanes;
|
|
20593
20593
|
var primaryChildInstance = {
|
|
@@ -20731,14 +20731,14 @@ var require_react_dom_development = __commonJS({
|
|
|
20731
20731
|
}
|
|
20732
20732
|
var ReactVersion = "18.3.1";
|
|
20733
20733
|
function createPortal2(children, containerInfo, implementation) {
|
|
20734
|
-
var
|
|
20734
|
+
var key2 = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : null;
|
|
20735
20735
|
{
|
|
20736
|
-
checkKeyStringCoercion(
|
|
20736
|
+
checkKeyStringCoercion(key2);
|
|
20737
20737
|
}
|
|
20738
20738
|
return {
|
|
20739
20739
|
// This tag allow us to uniquely identify this as a React Portal
|
|
20740
20740
|
$$typeof: REACT_PORTAL_TYPE,
|
|
20741
|
-
key:
|
|
20741
|
+
key: key2 == null ? null : "" + key2,
|
|
20742
20742
|
children,
|
|
20743
20743
|
containerInfo,
|
|
20744
20744
|
implementation
|
|
@@ -20966,17 +20966,17 @@ var require_react_dom_development = __commonJS({
|
|
|
20966
20966
|
var setSuspenseHandler = null;
|
|
20967
20967
|
{
|
|
20968
20968
|
var copyWithDeleteImpl = function(obj, path, index2) {
|
|
20969
|
-
var
|
|
20969
|
+
var key2 = path[index2];
|
|
20970
20970
|
var updated = isArray(obj) ? obj.slice() : assign({}, obj);
|
|
20971
20971
|
if (index2 + 1 === path.length) {
|
|
20972
20972
|
if (isArray(updated)) {
|
|
20973
|
-
updated.splice(
|
|
20973
|
+
updated.splice(key2, 1);
|
|
20974
20974
|
} else {
|
|
20975
|
-
delete updated[
|
|
20975
|
+
delete updated[key2];
|
|
20976
20976
|
}
|
|
20977
20977
|
return updated;
|
|
20978
20978
|
}
|
|
20979
|
-
updated[
|
|
20979
|
+
updated[key2] = copyWithDeleteImpl(obj[key2], path, index2 + 1);
|
|
20980
20980
|
return updated;
|
|
20981
20981
|
};
|
|
20982
20982
|
var copyWithDelete = function(obj, path) {
|
|
@@ -21022,9 +21022,9 @@ var require_react_dom_development = __commonJS({
|
|
|
21022
21022
|
if (index2 >= path.length) {
|
|
21023
21023
|
return value;
|
|
21024
21024
|
}
|
|
21025
|
-
var
|
|
21025
|
+
var key2 = path[index2];
|
|
21026
21026
|
var updated = isArray(obj) ? obj.slice() : assign({}, obj);
|
|
21027
|
-
updated[
|
|
21027
|
+
updated[key2] = copyWithSetImpl(obj[key2], path, index2 + 1, value);
|
|
21028
21028
|
return updated;
|
|
21029
21029
|
};
|
|
21030
21030
|
var copyWithSet = function(obj, path, value) {
|
|
@@ -21583,11 +21583,11 @@ var require_react_dom_development = __commonJS({
|
|
|
21583
21583
|
setRestoreImplementation(restoreControlledState$3);
|
|
21584
21584
|
setBatchingImplementation(batchedUpdates$1, discreteUpdates, flushSync);
|
|
21585
21585
|
function createPortal$1(children, container) {
|
|
21586
|
-
var
|
|
21586
|
+
var key2 = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : null;
|
|
21587
21587
|
if (!isValidContainer(container)) {
|
|
21588
21588
|
throw new Error("Target container is not a DOM element.");
|
|
21589
21589
|
}
|
|
21590
|
-
return createPortal2(children, container, null,
|
|
21590
|
+
return createPortal2(children, container, null, key2);
|
|
21591
21591
|
}
|
|
21592
21592
|
function renderSubtreeIntoContainer(parentComponent, element, containerNode, callback) {
|
|
21593
21593
|
return unstable_renderSubtreeIntoContainer(parentComponent, element, containerNode, callback);
|
|
@@ -21678,10 +21678,10 @@ __export(client_exports, {
|
|
|
21678
21678
|
inject: () => inject
|
|
21679
21679
|
});
|
|
21680
21680
|
module.exports = __toCommonJS(client_exports);
|
|
21681
|
-
var
|
|
21681
|
+
var import_react14 = __toESM(require("react"), 1);
|
|
21682
21682
|
|
|
21683
21683
|
// src/view.js
|
|
21684
|
-
var
|
|
21684
|
+
var import_react12 = __toESM(require("react"), 1);
|
|
21685
21685
|
|
|
21686
21686
|
// lib/presentation.js
|
|
21687
21687
|
var UI_ICONS = Object.freeze(["sparkles", "sliders", "layers", "chart", "gauge", "cpu", "database", "info", "check", "warning", "arrow", "target"]);
|
|
@@ -21770,12 +21770,13 @@ function formatNumber(value, decimals = 2) {
|
|
|
21770
21770
|
|
|
21771
21771
|
// lib/canvas-system.js
|
|
21772
21772
|
var CANVAS_SYSTEM_CSS = `
|
|
21773
|
-
:root{--canvas-radius:
|
|
21773
|
+
:root{--canvas-radius:20px;--canvas-gap:16px;--canvas-positive:#167456;--canvas-negative:#b13b3b;--canvas-warning:#875b15}
|
|
21774
21774
|
:root[data-canvas-scheme=dark]{--canvas-positive:#78d9b4;--canvas-negative:#ffaaaa;--canvas-warning:#edc87e}
|
|
21775
|
-
html,body{margin:0;min-width:0;background:var(--canvas-bg,#fff);color:var(--canvas-ink,#182537);font:14px/1.6 system-ui,"Microsoft YaHei",sans-serif}*{box-sizing:border-box}svg{max-width:100%;height:auto}button,input,select,textarea{font:inherit;color:inherit}button,input,select,textarea{border:1px solid var(--canvas-line,#ced4df);border-radius:8px;background:var(--canvas-bg,#fff);padding:8px 12px;max-width:100%}button{cursor:pointer}button:disabled{cursor:default;opacity:.55}input[type=range]{padding:0;accent-color:var(--canvas-accent,#3e60d3)}input[type=checkbox],input[type=radio]{accent-color:var(--canvas-accent,#3e60d3)}button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[tabindex]:focus-visible{outline:2px solid var(--canvas-accent,#3e60d3);outline-offset:3px}
|
|
21775
|
+
#canvas{display:flow-root}html,body{margin:0;min-width:0;background:var(--canvas-bg,#fff);color:var(--canvas-ink,#182537);font:14px/1.6 system-ui,"Microsoft YaHei",sans-serif}*{box-sizing:border-box}svg{max-width:100%;height:auto}button,input,select,textarea{font:inherit;color:inherit}button,input,select,textarea{border:1px solid var(--canvas-line,#ced4df);border-radius:8px;background:var(--canvas-bg,#fff);padding:8px 12px;max-width:100%}button{cursor:pointer}button:disabled{cursor:default;opacity:.55}input[type=range]{padding:0;accent-color:var(--canvas-accent,#3e60d3)}input[type=checkbox],input[type=radio]{accent-color:var(--canvas-accent,#3e60d3)}button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[tabindex]:focus-visible{outline:2px solid var(--canvas-accent,#3e60d3);outline-offset:3px}
|
|
21776
21776
|
.ui-stack{display:grid;gap:var(--canvas-gap)}.ui-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:var(--canvas-gap)}.ui-surface{padding:20px;border:1px solid var(--canvas-line,#ced4df);border-radius:var(--canvas-radius);background:var(--canvas-soft,#f3f5f8)}.ui-title{margin:0;font-size:clamp(20px,3vw,28px);line-height:1.3;letter-spacing:-.02em}.ui-caption{color:var(--canvas-muted,#526176);margin:8px 0;font-size:14px}.ui-value{font-size:clamp(24px,4vw,36px);font-variant-numeric:tabular-nums;line-height:1.2}.ui-controls{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.ui-field{display:grid;gap:6px;min-width:0}.ui-legend{display:flex;gap:16px;flex-wrap:wrap;font-size:13px}.ui-status{min-height:1.6em}.ui-error{color:var(--canvas-negative)}.ui-primary{background:var(--canvas-accent,#3e60d3);color:var(--canvas-accent-ink,#fff);border-color:transparent}
|
|
21777
21777
|
svg .ui-node{fill:var(--canvas-soft,#f3f5f8);stroke:var(--canvas-line,#ced4df);stroke-width:1}svg .ui-edge{fill:none;stroke:var(--canvas-muted,#526176);stroke-width:1.5}svg .ui-label{fill:var(--canvas-ink,#182537);font:500 14px system-ui,sans-serif}svg .ui-note{fill:var(--canvas-muted,#526176);font:400 13px system-ui,sans-serif}svg .ui-leader{fill:none;stroke:var(--canvas-muted,#526176);stroke-dasharray:3 4}svg .ui-accent{fill:color-mix(in srgb,var(--canvas-accent,#3e60d3) 12%,var(--canvas-bg,#fff));stroke:var(--canvas-accent,#3e60d3)}
|
|
21778
21778
|
.ui-flow{display:flex;align-items:center;justify-content:center;gap:16px;padding:24px 8px;flex-wrap:wrap}.ui-step{display:grid;gap:6px;min-width:130px;max-width:240px;padding:16px 20px;border:1px solid var(--canvas-line);border-radius:6px;background:var(--canvas-bg)}.ui-step strong{font-size:16px;font-weight:600}.ui-step span{font-size:14px;color:var(--canvas-muted)}.ui-arrow{color:var(--canvas-muted);font-size:22px}.ui-callout{border-inline-start:3px solid var(--canvas-accent);padding:8px 16px;color:var(--canvas-ink)}
|
|
21779
|
+
.ui-surface,.ui-step{border-radius:var(--canvas-radius);background:linear-gradient(135deg,color-mix(in srgb,var(--canvas-accent,#3e60d3) 9%,var(--canvas-bg,#fff)),var(--canvas-soft,#f3f5f8))}button,input:not([type=checkbox]):not([type=radio]):not([type=range]),select,textarea{border-radius:14px}.ui-primary{background:linear-gradient(120deg,var(--canvas-accent,#3e60d3),color-mix(in srgb,var(--canvas-accent,#3e60d3) 85%,#152647))}.ui-callout{border-radius:14px;background:linear-gradient(120deg,color-mix(in srgb,var(--canvas-accent,#3e60d3) 7%,var(--canvas-bg,#fff)),var(--canvas-bg,#fff))}
|
|
21779
21780
|
@media(max-width:480px){.ui-flow{flex-direction:column;padding:16px 8px;gap:12px}.ui-step{width:100%;max-width:none}.ui-arrow{transform:rotate(90deg)}}
|
|
21780
21781
|
@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}}`;
|
|
21781
21782
|
|
|
@@ -21840,13 +21841,13 @@ var COMPONENTS = Object.freeze({
|
|
|
21840
21841
|
badge: define(["text"], "Short explicit status label", "tone"),
|
|
21841
21842
|
progress: define(["label", "value", "max", "unit"], "Declared numeric progress snapshot", "tone"),
|
|
21842
21843
|
steps: define(["items"], "Ordered declared steps"),
|
|
21843
|
-
metric: define(["label", "value", "unit", "decimals"], "
|
|
21844
|
+
metric: define(["label", "value", "unit", "decimals"], "Number with units, or a literal/bound status string", "tone"),
|
|
21844
21845
|
input: define(["label", "bind"], "String or numeric state input"),
|
|
21845
21846
|
slider: define(["label", "bind"], "Numeric state control"),
|
|
21846
21847
|
select: define(["label", "bind"], "Selection from declared state options"),
|
|
21847
21848
|
toggle: define(["label", "bind"], "Boolean state control"),
|
|
21848
21849
|
button: define(["text", "action"], "Declared Agent follow-up", "icon"),
|
|
21849
|
-
table: define(["rows", "columns"], "
|
|
21850
|
+
table: define(["label", "rows", "columns"], "Supplied or derived values; inline rows or data/derived reference"),
|
|
21850
21851
|
chart: define(["kind", "rows", "labelKey", "valueKey", "label", "unit", "xScale"], "Bar/line comparison with accessible data"),
|
|
21851
21852
|
sandbox: define(["title", "html", "css", "script", "fallback", "height", "stateKeys", "dataKeys", "derivedKeys"], "Freeform isolated HTML/SVG/CSS/JavaScript visualization")
|
|
21852
21853
|
});
|
|
@@ -21855,6 +21856,11 @@ function componentFields(type) {
|
|
|
21855
21856
|
return c && ["id", "type", ...c.fields, ...c.presentation ? ["icon"] : [], ...c.presentation === "tone" ? ["tone"] : []];
|
|
21856
21857
|
}
|
|
21857
21858
|
|
|
21859
|
+
// lib/identifiers.js
|
|
21860
|
+
var IDENTIFIER_SOURCE = "[\\p{L}_][\\p{L}\\p{M}\\p{N}_]{0,63}";
|
|
21861
|
+
var pattern = new RegExp(`^${IDENTIFIER_SOURCE}$`, "u");
|
|
21862
|
+
var validIdentifier = (value) => typeof value === "string" && pattern.test(value) && !["constructor", "prototype", "__proto__"].includes(value);
|
|
21863
|
+
|
|
21858
21864
|
// lib/author-expression.js
|
|
21859
21865
|
function compileExpression(source) {
|
|
21860
21866
|
const fail2 = () => {
|
|
@@ -21863,7 +21869,7 @@ function compileExpression(source) {
|
|
|
21863
21869
|
if (typeof source !== "string" || !source.trim() || source.length > 2048) fail2();
|
|
21864
21870
|
const tokens = [];
|
|
21865
21871
|
let offset = 0;
|
|
21866
|
-
const token =
|
|
21872
|
+
const token = new RegExp(String.raw`\s*(?:(\d+(?:\.\d*)?|\.\d+)([eE][+-]?\d+)?|("(?:[^"\\]|\\.)*")|(${IDENTIFIER_SOURCE}(?:\.${IDENTIFIER_SOURCE})?)|(===|!==|<=|>=|==|!=|[+*/()?,:<>-]))`, "uy");
|
|
21867
21873
|
while (offset < source.length) {
|
|
21868
21874
|
if (!source.slice(offset).trim()) break;
|
|
21869
21875
|
token.lastIndex = offset;
|
|
@@ -21890,7 +21896,7 @@ function compileExpression(source) {
|
|
|
21890
21896
|
} else if (t === "-" || t === "+") {
|
|
21891
21897
|
const arg = parse(5, depth + 1);
|
|
21892
21898
|
out = t === "-" ? { op: "sub", args: [{ const: 0 }, arg] } : arg;
|
|
21893
|
-
} else if (typeof t === "string" &&
|
|
21899
|
+
} else if (typeof t === "string" && t.split(".").length === 2 && ["state", "data", "derived", "item"].includes(t.split(".")[0]) && validIdentifier(t.split(".")[1])) out = { ref: t };
|
|
21894
21900
|
else if (["min", "max", "round", "abs"].includes(t)) {
|
|
21895
21901
|
take("(");
|
|
21896
21902
|
const args = [parse(0, depth + 1)];
|
|
@@ -21949,7 +21955,6 @@ var fail = (message) => {
|
|
|
21949
21955
|
throw new Error(`DSH UI: ${message}`);
|
|
21950
21956
|
};
|
|
21951
21957
|
var object = (x) => x !== null && typeof x === "object" && !Array.isArray(x);
|
|
21952
|
-
var key = (x) => typeof x === "string" && /^[a-zA-Z][a-zA-Z0-9_]{0,63}$/.test(x) && !["constructor", "prototype", "__proto__"].includes(x);
|
|
21953
21958
|
var finite = (x) => typeof x === "number" && Number.isFinite(x);
|
|
21954
21959
|
var scalar = (x) => typeof x === "string" || typeof x === "boolean" || finite(x);
|
|
21955
21960
|
var text = (x, at) => {
|
|
@@ -21996,6 +22001,10 @@ function validateState(doc, state) {
|
|
|
21996
22001
|
if (!finite(v) || v < s.min || v > s.max) fail(`state.${k} is outside its numeric range`);
|
|
21997
22002
|
const offset = (v - s.min) / s.step;
|
|
21998
22003
|
if (Math.abs(offset - Math.round(offset)) > 1e-6) fail(`state.${k} does not match its step`);
|
|
22004
|
+
} else if (s.type === "json") {
|
|
22005
|
+
if (!object(v) && !Array.isArray(v)) fail(`state.${k} must be an array or object for type json`);
|
|
22006
|
+
safeJson(v);
|
|
22007
|
+
if (new TextEncoder().encode(JSON.stringify(v)).length > 16384) fail(`state.${k} JSON exceeds 16 KiB`);
|
|
21999
22008
|
} else if (s.type === "string") text(v, `state.${k}`);
|
|
22000
22009
|
else if (typeof v !== "boolean") fail(`state.${k} must be boolean`);
|
|
22001
22010
|
if (s.options && !s.options.includes(v)) fail(`invalid option for state.${k}`);
|
|
@@ -22005,7 +22014,7 @@ function validateState(doc, state) {
|
|
|
22005
22014
|
}
|
|
22006
22015
|
var ARITY = { add: [1, 8], sub: [2, 2], mul: [1, 8], div: [2, 2], min: [1, 8], max: [1, 8], round: [1, 1], abs: [1, 1], eq: [2, 2], neq: [2, 2], lt: [2, 2], lte: [2, 2], gt: [2, 2], gte: [2, 2], if: [3, 3] };
|
|
22007
22016
|
function reference(doc, ref) {
|
|
22008
|
-
if (typeof ref !== "string" ||
|
|
22017
|
+
if (typeof ref !== "string" || !["state", "data", "derived"].includes(ref.split(".")[0]) || ref.split(".").length !== 2 || !validIdentifier(ref.split(".")[1])) fail(`invalid reference ${JSON.stringify(ref)}; use state.key, data.key or derived.key with a letter/underscore identifier`);
|
|
22009
22018
|
const [group, k] = ref.split(".");
|
|
22010
22019
|
if (!own(doc[group], k)) fail(`unknown reference ${ref}`);
|
|
22011
22020
|
return [group, k];
|
|
@@ -22116,7 +22125,7 @@ function checkViewValues(doc, evaluated) {
|
|
|
22116
22125
|
if (n.type === "chart" && rows.some((r) => !own(r, n.labelKey) || !scalar(r[n.labelKey]) || !own(r, n.valueKey) || !finite(r[n.valueKey]))) fail("chart requires labels and finite numeric values");
|
|
22117
22126
|
if (n.type === "chart" && n.xScale === "linear" && rows.some((r) => !finite(r[n.labelKey]))) fail("linear chart requires numeric x values");
|
|
22118
22127
|
}
|
|
22119
|
-
if (n.type === "metric" && !
|
|
22128
|
+
if (n.type === "metric" && !scalar(evaluated.resolveValue(n.value))) fail(`node.${n.id}.value must resolve to a number, string or boolean; use table for rows or a canvas for structured data`);
|
|
22120
22129
|
if (n.type === "progress") {
|
|
22121
22130
|
const v = evaluated.resolveValue(n.value), max = evaluated.resolveValue(n.max);
|
|
22122
22131
|
if (!finite(v) || !finite(max) || max <= 0 || v < 0 || v > max) fail("progress requires 0 <= value <= positive max");
|
|
@@ -22144,11 +22153,13 @@ function validateDocument(input) {
|
|
|
22144
22153
|
for (const group of ["state", "data", "derived", "actions"]) {
|
|
22145
22154
|
doc[group] ??= {};
|
|
22146
22155
|
if (!object(doc[group]) || Object.keys(doc[group]).length > 64) fail(`invalid ${group}`);
|
|
22147
|
-
for (const k of Object.keys(doc[group])) if (!
|
|
22156
|
+
for (const k of Object.keys(doc[group])) if (!validIdentifier(k)) fail(`invalid key in ${group}: ${JSON.stringify(k)}; use 1..64 letters, numbers or underscores, starting with a letter/underscore (Chinese letters supported); no spaces, dots or hyphens. Put display labels in label/text`);
|
|
22148
22157
|
}
|
|
22149
22158
|
for (const [k, s] of Object.entries(doc.state)) {
|
|
22150
22159
|
fields(s, ["type", "default", "min", "max", "step", "options"], `state.${k}`);
|
|
22151
|
-
if (
|
|
22160
|
+
if (s.type === "string" && (Array.isArray(s.default) || object(s.default)) && !own(s, "options")) s.type = "json";
|
|
22161
|
+
if (!["number", "string", "boolean", "json"].includes(s.type)) fail(`unsupported state type ${k}; use number, string, boolean or json (arrays/objects)`);
|
|
22162
|
+
if (s.type === "json" && own(s, "options")) fail(`state.${k}: json state does not support select options; use scalar options or a canvas`);
|
|
22152
22163
|
if (s.type === "number") {
|
|
22153
22164
|
if (![s.min, s.max, s.step].every(finite) || s.min >= s.max || s.step <= 0) fail(`invalid numeric limits for ${k}`);
|
|
22154
22165
|
if ((s.max - s.min) / s.step > 1e9) fail(`numeric step too small for ${k}`);
|
|
@@ -22171,7 +22182,7 @@ function validateDocument(input) {
|
|
|
22171
22182
|
if (!Array.isArray(rows) || rows.length > LIMITS.rows || !rows.every(object)) fail("map source must be object rows");
|
|
22172
22183
|
if (!object(e.map.fields) || !Object.keys(e.map.fields).length || Object.keys(e.map.fields).length > 16) fail("map requires 1..16 fields");
|
|
22173
22184
|
for (const [k2, value2] of Object.entries(e.map.fields)) {
|
|
22174
|
-
if (!
|
|
22185
|
+
if (!validIdentifier(k2)) fail(`invalid map field ${JSON.stringify(k2).slice(0, 100)}; use a letter/underscore identifier such as powerW or \u529F\u7387, without spaces, dots or hyphens`);
|
|
22175
22186
|
validateExpression(value2, depth + 1, rows);
|
|
22176
22187
|
}
|
|
22177
22188
|
return;
|
|
@@ -22185,7 +22196,7 @@ function validateDocument(input) {
|
|
|
22185
22196
|
fields(e, ["ref"], "expression");
|
|
22186
22197
|
if (typeof e.ref === "string" && e.ref.startsWith("item.")) {
|
|
22187
22198
|
const k = e.ref.slice(5);
|
|
22188
|
-
if (!itemRows || !
|
|
22199
|
+
if (!itemRows || !validIdentifier(k) || itemRows.some((row) => !own(row, k) || !scalar(row[k]))) fail("invalid or unscoped item reference");
|
|
22189
22200
|
} else reference(doc, e.ref);
|
|
22190
22201
|
return;
|
|
22191
22202
|
}
|
|
@@ -22228,9 +22239,10 @@ function validateDocument(input) {
|
|
|
22228
22239
|
if (!Array.isArray(list) || depth > LIMITS.depth) fail("invalid node children or depth");
|
|
22229
22240
|
for (const n of list) {
|
|
22230
22241
|
if (++count > LIMITS.nodes) fail("too many nodes");
|
|
22231
|
-
if (!object(n) || !
|
|
22242
|
+
if (!object(n) || !validIdentifier(n.id) || ids.has(n.id)) fail("node ids must be unique identifiers");
|
|
22232
22243
|
ids.add(n.id);
|
|
22233
22244
|
if (!Object.hasOwn(COMPONENTS, n.type)) fail("unsupported component " + n.type);
|
|
22245
|
+
if (["table", "chart"].includes(n.type) && typeof n.rows === "string" && /^(data|derived)\./.test(n.rows)) n.rows = { ref: n.rows };
|
|
22234
22246
|
switch (n.type) {
|
|
22235
22247
|
case "sandbox": {
|
|
22236
22248
|
text(n.title, "canvas title");
|
|
@@ -22290,6 +22302,7 @@ function validateDocument(input) {
|
|
|
22290
22302
|
const [, k] = reference(doc, n.bind), spec = doc.state[k];
|
|
22291
22303
|
if (n.type === "slider" && spec.type !== "number") fail("slider requires numeric state");
|
|
22292
22304
|
if (n.type === "toggle" && spec.type !== "boolean") fail("toggle requires boolean state");
|
|
22305
|
+
if (["input", "select"].includes(n.type) && spec.type === "json") fail(`node.${n.id}: structured state requires a sandbox with DSHUI.setState; use separate boolean states and toggle nodes for a native checklist`);
|
|
22293
22306
|
if (n.type === "input" && spec.type === "boolean") fail("use toggle for boolean state");
|
|
22294
22307
|
if (n.type === "select" && !spec.options) fail("select requires options");
|
|
22295
22308
|
break;
|
|
@@ -22299,13 +22312,13 @@ function validateDocument(input) {
|
|
|
22299
22312
|
if (!own(doc.actions, n.action)) fail("unknown action");
|
|
22300
22313
|
break;
|
|
22301
22314
|
case "table": {
|
|
22302
|
-
if (
|
|
22303
|
-
value(n.rows, "table rows");
|
|
22315
|
+
if (n.label !== void 0) text(n.label, "table label");
|
|
22316
|
+
if (!Array.isArray(n.rows)) value(n.rows, "table rows");
|
|
22304
22317
|
if (!Array.isArray(n.columns) || !n.columns.length || n.columns.length > 16) fail("invalid table columns");
|
|
22305
22318
|
const cols = /* @__PURE__ */ new Set();
|
|
22306
22319
|
for (const c of n.columns) {
|
|
22307
22320
|
fields(c, ["key", "label", "unit"], "column");
|
|
22308
|
-
if (!
|
|
22321
|
+
if (!validIdentifier(c.key) || cols.has(c.key)) fail("invalid or duplicate column key");
|
|
22309
22322
|
cols.add(c.key);
|
|
22310
22323
|
text(c.label, "column label");
|
|
22311
22324
|
if (c.unit !== void 0) text(c.unit, "column unit");
|
|
@@ -22313,8 +22326,8 @@ function validateDocument(input) {
|
|
|
22313
22326
|
break;
|
|
22314
22327
|
}
|
|
22315
22328
|
case "chart":
|
|
22316
|
-
value(n.rows, "chart rows");
|
|
22317
|
-
if (!["bar", "line"].includes(n.kind) || !
|
|
22329
|
+
if (!Array.isArray(n.rows)) value(n.rows, "chart rows");
|
|
22330
|
+
if (!["bar", "line"].includes(n.kind) || !validIdentifier(n.labelKey) || !validIdentifier(n.valueKey)) fail("invalid chart");
|
|
22318
22331
|
text(n.label, "chart label");
|
|
22319
22332
|
if (n.unit !== void 0) text(n.unit, "chart unit");
|
|
22320
22333
|
if (n.xScale !== void 0 && (!["category", "linear"].includes(n.xScale) || n.xScale === "linear" && n.kind !== "line")) fail("invalid xScale");
|
|
@@ -22378,9 +22391,9 @@ var import_react2 = require("react");
|
|
|
22378
22391
|
|
|
22379
22392
|
// src/state-channel.js
|
|
22380
22393
|
var listeners = /* @__PURE__ */ new Map();
|
|
22381
|
-
var
|
|
22394
|
+
var key = (id, sessionId) => id + "\0" + sessionId;
|
|
22382
22395
|
function subscribeState(id, sessionId, fn) {
|
|
22383
|
-
const k =
|
|
22396
|
+
const k = key(id, sessionId), set = listeners.get(k) ?? /* @__PURE__ */ new Set();
|
|
22384
22397
|
listeners.set(k, set);
|
|
22385
22398
|
set.add(fn);
|
|
22386
22399
|
return () => {
|
|
@@ -22389,7 +22402,7 @@ function subscribeState(id, sessionId, fn) {
|
|
|
22389
22402
|
};
|
|
22390
22403
|
}
|
|
22391
22404
|
function broadcastState(id, sessionId, saved, origin) {
|
|
22392
|
-
for (const fn of listeners.get(
|
|
22405
|
+
for (const fn of listeners.get(key(id, sessionId)) ?? []) if (fn !== origin) fn(saved);
|
|
22393
22406
|
}
|
|
22394
22407
|
|
|
22395
22408
|
// src/saved-state.js
|
|
@@ -22538,6 +22551,40 @@ function useSavedState(record, sessionId, preview = false) {
|
|
|
22538
22551
|
return { state: preview ? initialState(doc) : state, setState, ready: !preview && ready, status: preview ? "\u751F\u6210\u9884\u89C8 \xB7 \u5B8C\u6210\u6821\u9A8C\u540E\u53EF\u64CD\u4F5C" : status, issue, epoch, retry, useRemote: () => load(), keepLocal: () => load(true) };
|
|
22539
22552
|
}
|
|
22540
22553
|
|
|
22554
|
+
// lib/tool-json.js
|
|
22555
|
+
function clean(source) {
|
|
22556
|
+
let input = source.trim().replace(/^\uFEFF/, "");
|
|
22557
|
+
const fence = input.match(/^```(?:json)?\s*\n([\s\S]*?)\n```$/i);
|
|
22558
|
+
if (fence) input = fence[1];
|
|
22559
|
+
let output = "", quoted = false, escaped = false;
|
|
22560
|
+
for (let i = 0; i < input.length; i++) {
|
|
22561
|
+
const c = input[i];
|
|
22562
|
+
if (quoted) {
|
|
22563
|
+
output += c;
|
|
22564
|
+
if (escaped) escaped = false;
|
|
22565
|
+
else if (c === "\\") escaped = true;
|
|
22566
|
+
else if (c === '"') quoted = false;
|
|
22567
|
+
continue;
|
|
22568
|
+
}
|
|
22569
|
+
if (c === '"') quoted = true;
|
|
22570
|
+
if (c === "," && /^\s*[}\]]/.test(input.slice(i + 1))) continue;
|
|
22571
|
+
output += c;
|
|
22572
|
+
}
|
|
22573
|
+
return output;
|
|
22574
|
+
}
|
|
22575
|
+
function toolJson(value, field, maxBytes = 131072) {
|
|
22576
|
+
if (typeof value !== "string") return value;
|
|
22577
|
+
if (new TextEncoder().encode(value).length > maxBytes) throw new Error(`DSH UI: ${field} JSON exceeds size limit`);
|
|
22578
|
+
const source = clean(value);
|
|
22579
|
+
try {
|
|
22580
|
+
return JSON.parse(source);
|
|
22581
|
+
} catch (error) {
|
|
22582
|
+
const position = error.message.match(/position (\d+)/)?.[1];
|
|
22583
|
+
const location = position === void 0 ? "" : ` at line ${source.slice(0, Number(position)).split("\n").length}, column ${Number(position) - source.lastIndexOf("\n", Number(position) - 1)}`;
|
|
22584
|
+
throw new Error(`DSH UI: ${field} must contain valid JSON${location}. Pass an object directly, not a manually escaped JSON string. Do not use single-quoted keys or raw newlines inside strings. For HTML/SVG use render_canvas with separate html/css/script fields. No partial document was saved.`);
|
|
22585
|
+
}
|
|
22586
|
+
}
|
|
22587
|
+
|
|
22541
22588
|
// lib/stream.js
|
|
22542
22589
|
function parseToolArguments(raw) {
|
|
22543
22590
|
if (typeof raw !== "string" || raw.length > LIMITS.bytes || new TextEncoder().encode(raw).length > LIMITS.bytes) return null;
|
|
@@ -22629,7 +22676,7 @@ function previewDocument(raw) {
|
|
|
22629
22676
|
const root = parseToolArguments(raw);
|
|
22630
22677
|
if (!root) return null;
|
|
22631
22678
|
const document2 = root.members?.get("document");
|
|
22632
|
-
if (document2?.complete && typeof document2.value === "string" && root.members.size === 1) return validateDocument(
|
|
22679
|
+
if (document2?.complete && typeof document2.value === "string" && root.members.size === 1) return validateDocument(toolJson(document2.value, "document"));
|
|
22633
22680
|
if (!document2?.members) return null;
|
|
22634
22681
|
if ([...root.members.keys()].some((k) => k !== "document")) return null;
|
|
22635
22682
|
const doc = { ...document2.value }, nodes = document2.members.get("nodes");
|
|
@@ -22698,12 +22745,13 @@ function updatePreview(html) {
|
|
|
22698
22745
|
morph(document.getElementById("canvas"), template.content);
|
|
22699
22746
|
}
|
|
22700
22747
|
function previewFrameDocument(channel, nonce) {
|
|
22701
|
-
return `<!doctype html><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none';script-src 'nonce-${nonce}';style-src 'unsafe-inline';img-src data:;base-uri 'none';form-action 'none';frame-src 'none'"><style>${CANVAS_SYSTEM_CSS}</style><style id="custom"></style><style>#canvas,#canvas *,#canvas *::before,#canvas *::after{animation:none!important;transition:none!important}html,body{overflow:hidden}</style><main id="canvas" inert></main><script nonce="${nonce}">const update=${updatePreview.toString()};addEventListener('message',e=>{if(e.source!==parent||e.data?.channel!==${JSON.stringify(channel)})return;document.getElementById('custom').textContent=e.data.css;for(const [k,v] of Object.entries(e.data.theme||{}))document.documentElement.style.setProperty('--canvas-'+k,v);document.documentElement.dataset.canvasScheme=e.data.theme?.scheme||'light';update(e.data.html)});<\/script>`;
|
|
22748
|
+
return `<!doctype html><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none';script-src 'nonce-${nonce}';style-src 'unsafe-inline';img-src data:;base-uri 'none';form-action 'none';frame-src 'none'"><style>${CANVAS_SYSTEM_CSS}</style><style id="custom"></style><style>#canvas,#canvas *,#canvas *::before,#canvas *::after{animation:none!important;transition:none!important}html,body{overflow:hidden}</style><main id="canvas" inert></main><script nonce="${nonce}">const update=${updatePreview.toString()};addEventListener('message',e=>{if(e.source!==parent||e.data?.channel!==${JSON.stringify(channel)})return;document.getElementById('custom').textContent=e.data.css;for(const [k,v] of Object.entries(e.data.theme||{}))document.documentElement.style.setProperty('--canvas-'+k,v);document.documentElement.dataset.canvasScheme=e.data.theme?.scheme||'light';update(e.data.html)});new ResizeObserver(()=>parent.postMessage({channel:${JSON.stringify(channel)},previewHeight:Math.ceil(document.getElementById('canvas').getBoundingClientRect().height)},'*')).observe(document.getElementById('canvas'));<\/script>`;
|
|
22702
22749
|
}
|
|
22703
22750
|
|
|
22704
22751
|
// src/canvas-preview.js
|
|
22705
22752
|
var h2 = import_react3.default.createElement;
|
|
22706
22753
|
function CanvasPreview({ node }) {
|
|
22754
|
+
const [height, setHeight] = (0, import_react3.useState)(node.height ?? 420);
|
|
22707
22755
|
const frame = (0, import_react3.useRef)(null), latest = (0, import_react3.useRef)(node);
|
|
22708
22756
|
latest.current = node;
|
|
22709
22757
|
const config = (0, import_react3.useMemo)(() => {
|
|
@@ -22728,14 +22776,22 @@ function CanvasPreview({ node }) {
|
|
|
22728
22776
|
observer.observe(document.body, { attributes: true });
|
|
22729
22777
|
return () => observer.disconnect();
|
|
22730
22778
|
}, []);
|
|
22731
|
-
|
|
22779
|
+
(0, import_react3.useEffect)(() => {
|
|
22780
|
+
const receive = (event) => {
|
|
22781
|
+
const m = event.data;
|
|
22782
|
+
if (event.source === frame.current?.contentWindow && m?.channel === config.channel && Number.isFinite(m.previewHeight) && m.previewHeight >= 0) setHeight(Math.max(32, Math.min(1e3, Math.ceil(m.previewHeight))));
|
|
22783
|
+
};
|
|
22784
|
+
window.addEventListener("message", receive);
|
|
22785
|
+
return () => window.removeEventListener("message", receive);
|
|
22786
|
+
}, [config]);
|
|
22787
|
+
return h2("section", { className: "dgui-canvas", "data-canvas-phase": "preview", "aria-label": node.title }, h2("p", { className: "dgui-copy", role: "status" }, "\u9759\u6001\u9884\u89C8 \xB7 \u63D0\u4EA4\u6210\u529F\u540E\u542F\u7528\u4EA4\u4E92"), h2("iframe", { ref: frame, title: node.title + "\uFF08\u9759\u6001\u9884\u89C8\uFF09", sandbox: "allow-scripts", referrerPolicy: "no-referrer", srcDoc, onLoad: publish, style: { display: "block", width: "100%", height, border: 0, pointerEvents: "none" } }));
|
|
22732
22788
|
}
|
|
22733
22789
|
|
|
22734
22790
|
// src/sandbox.js
|
|
22735
|
-
var
|
|
22791
|
+
var import_react6 = __toESM(require("react"), 1);
|
|
22736
22792
|
|
|
22737
22793
|
// lib/export-runtime-bundle.js
|
|
22738
|
-
var EXPORT_RUNTIME = '(() => {\n // lib/presentation.js\n var UI_ICONS = Object.freeze(["sparkles", "sliders", "layers", "chart", "gauge", "cpu", "database", "info", "check", "warning", "arrow", "target"]);\n var UI_TONES = Object.freeze(["neutral", "accent", "success", "warning", "danger"]);\n var UI_LAYOUTS = Object.freeze(["dashboard", "workbench", "comparison", "guide", "status", "report"]);\n var UI_ACCENTS = Object.freeze(["blue", "teal", "violet", "amber", "rose"]);\n var UI_SURFACES = Object.freeze(["outline", "soft", "featured"]);\n\n // lib/visual-audit.js\n function measureVisual(root, nodeId = "") {\n const issues = [], seen = /* @__PURE__ */ new Set(), coverage = { nodeId, elements: 0, truncated: false, contrastChecked: 0, contrastUncovered: 0 };\n const add = (code, value, el2) => {\n const id = el2?.closest("[data-ui-node]")?.getAttribute("data-ui-node") ?? nodeId;\n const k = id + ":" + code + ":" + Math.round(value ?? 0);\n if (!seen.has(k) && issues.length < 40) {\n seen.add(k);\n issues.push({ code, nodeId: id, ...value === void 0 ? {} : { value: Number(value.toFixed(2)) } });\n }\n };\n const color = (s) => {\n let m = s.match(/^rgba?\\(([^)]+)\\)/);\n if (m) {\n const a = m[1].split(/[\\s,\\/]+/).map(Number);\n return [a[0] / 255, a[1] / 255, a[2] / 255, a[3] ?? 1];\n }\n m = s.match(/^color\\(srgb ([^)]+)\\)/);\n if (m) {\n const a = m[1].split(/[\\s\\/]+/).map(Number);\n return [a[0], a[1], a[2], a[3] ?? 1];\n }\n return null;\n };\n const luminance = (c) => c.slice(0, 3).map((v) => v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4).reduce((s, v, i) => s + v * [0.2126, 0.7152, 0.0722][i], 0);\n const widthRoot = root.id === "canvas" ? document.documentElement : root;\n if (widthRoot.scrollWidth > widthRoot.clientWidth + 2) add("overflow", widthRoot.scrollWidth - widthRoot.clientWidth);\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n let el;\n while (el = walker.nextNode()) {\n if (coverage.elements >= 2e3) {\n coverage.truncated = true;\n break;\n }\n coverage.elements++;\n if (el.matches("[data-canvas-phase=error]")) add("runtimeError", void 0, el);\n const css = getComputedStyle(el), box = el.getBoundingClientRect();\n if (!box.width || !box.height || css.visibility === "hidden" || css.display === "none") continue;\n const text2 = [...el.childNodes].some((n) => n.nodeType === 3 && n.textContent.trim());\n if (text2) {\n let size = parseFloat(css.fontSize);\n if (el instanceof SVGElement && el.getScreenCTM) {\n const m = el.getScreenCTM();\n if (m) size *= Math.hypot(m.c, m.d);\n }\n if (size < 11.9) add("smallText", size, el);\n const fg = color(css.color);\n let ancestor = el, bg = null, depth = 0;\n while (ancestor && depth++ < 64) {\n const style = getComputedStyle(ancestor);\n if (style.backgroundImage !== "none") break;\n const c = color(style.backgroundColor);\n if (c?.[3] === 1) {\n bg = c;\n break;\n }\n if (c?.[3] > 0) break;\n ancestor = ancestor.parentElement;\n }\n if (!(el instanceof SVGElement) && fg?.[3] === 1 && bg) {\n coverage.contrastChecked++;\n const a = luminance(fg), b = luminance(bg), ratio = (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);\n if (ratio < (size >= 24 || size >= 18.66 && parseFloat(css.fontWeight) >= 700 ? 3 : 4.5)) add("contrast", ratio, el);\n } else coverage.contrastUncovered++;\n }\n if (el.matches("input:not([type=hidden]),select,textarea,button,[role=button]") && !el.getAttribute("aria-label") && !el.getAttribute("aria-labelledby") && !el.labels?.length && !el.textContent.trim() && !el.getAttribute("title")) add("missingLabel", void 0, el);\n }\n Object.defineProperty(issues, "coverage", { value: coverage });\n return issues;\n }\n\n // lib/format-number.js\n function formatNumber(value, decimals = 2) {\n if (typeof value !== "number" || !Number.isFinite(value)) throw new Error("DSH UI: formatNumber requires a finite number");\n if (!Number.isInteger(decimals) || decimals < 0 || decimals > 6) throw new Error("DSH UI: formatNumber decimals must be an integer from 0 to 6");\n return value.toLocaleString("en-US", { minimumFractionDigits: decimals, maximumFractionDigits: decimals });\n }\n\n // lib/canvas-system.js\n var CANVAS_SYSTEM_CSS = `\n:root{--canvas-radius:12px;--canvas-gap:16px;--canvas-positive:#167456;--canvas-negative:#b13b3b;--canvas-warning:#875b15}\n:root[data-canvas-scheme=dark]{--canvas-positive:#78d9b4;--canvas-negative:#ffaaaa;--canvas-warning:#edc87e}\nhtml,body{margin:0;min-width:0;background:var(--canvas-bg,#fff);color:var(--canvas-ink,#182537);font:14px/1.6 system-ui,"Microsoft YaHei",sans-serif}*{box-sizing:border-box}svg{max-width:100%;height:auto}button,input,select,textarea{font:inherit;color:inherit}button,input,select,textarea{border:1px solid var(--canvas-line,#ced4df);border-radius:8px;background:var(--canvas-bg,#fff);padding:8px 12px;max-width:100%}button{cursor:pointer}button:disabled{cursor:default;opacity:.55}input[type=range]{padding:0;accent-color:var(--canvas-accent,#3e60d3)}input[type=checkbox],input[type=radio]{accent-color:var(--canvas-accent,#3e60d3)}button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[tabindex]:focus-visible{outline:2px solid var(--canvas-accent,#3e60d3);outline-offset:3px}\n.ui-stack{display:grid;gap:var(--canvas-gap)}.ui-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:var(--canvas-gap)}.ui-surface{padding:20px;border:1px solid var(--canvas-line,#ced4df);border-radius:var(--canvas-radius);background:var(--canvas-soft,#f3f5f8)}.ui-title{margin:0;font-size:clamp(20px,3vw,28px);line-height:1.3;letter-spacing:-.02em}.ui-caption{color:var(--canvas-muted,#526176);margin:8px 0;font-size:14px}.ui-value{font-size:clamp(24px,4vw,36px);font-variant-numeric:tabular-nums;line-height:1.2}.ui-controls{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.ui-field{display:grid;gap:6px;min-width:0}.ui-legend{display:flex;gap:16px;flex-wrap:wrap;font-size:13px}.ui-status{min-height:1.6em}.ui-error{color:var(--canvas-negative)}.ui-primary{background:var(--canvas-accent,#3e60d3);color:var(--canvas-accent-ink,#fff);border-color:transparent}\nsvg .ui-node{fill:var(--canvas-soft,#f3f5f8);stroke:var(--canvas-line,#ced4df);stroke-width:1}svg .ui-edge{fill:none;stroke:var(--canvas-muted,#526176);stroke-width:1.5}svg .ui-label{fill:var(--canvas-ink,#182537);font:500 14px system-ui,sans-serif}svg .ui-note{fill:var(--canvas-muted,#526176);font:400 13px system-ui,sans-serif}svg .ui-leader{fill:none;stroke:var(--canvas-muted,#526176);stroke-dasharray:3 4}svg .ui-accent{fill:color-mix(in srgb,var(--canvas-accent,#3e60d3) 12%,var(--canvas-bg,#fff));stroke:var(--canvas-accent,#3e60d3)}\n.ui-flow{display:flex;align-items:center;justify-content:center;gap:16px;padding:24px 8px;flex-wrap:wrap}.ui-step{display:grid;gap:6px;min-width:130px;max-width:240px;padding:16px 20px;border:1px solid var(--canvas-line);border-radius:6px;background:var(--canvas-bg)}.ui-step strong{font-size:16px;font-weight:600}.ui-step span{font-size:14px;color:var(--canvas-muted)}.ui-arrow{color:var(--canvas-muted);font-size:22px}.ui-callout{border-inline-start:3px solid var(--canvas-accent);padding:8px 16px;color:var(--canvas-ink)}\n@media(max-width:480px){.ui-flow{flex-direction:column;padding:16px 8px;gap:12px}.ui-step{width:100%;max-width:none}.ui-arrow{transform:rotate(90deg)}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}}`;\n\n // lib/sandbox.js\n var SANDBOX_LIMITS = Object.freeze({ source: 49152, height: 1e3, message: 16384, rate: 30 });\n function canvasSnapshot(node2, state2, data, derived, disabled, theme) {\n const pick = (keys, values) => Object.fromEntries((keys ?? []).map((k) => [k, values[k]]));\n return { state: pick(node2.stateKeys, state2), data: pick(node2.dataKeys, data), derived: pick(node2.derivedKeys, derived), disabled, theme };\n }\n function canvasPatch(message, node2) {\n if (!message || typeof message !== "object" || Array.isArray(message)) throw new Error("Invalid canvas patch");\n const keys = Object.keys(message);\n if (!keys.length || keys.length > 64 || keys.some((k) => !(node2.stateKeys ?? []).includes(k))) throw new Error("Canvas state key is not declared");\n if (JSON.stringify(message).length > SANDBOX_LIMITS.message) throw new Error("Canvas patch is too large");\n return message;\n }\n function sandboxDocument(node2, channel2, nonce2) {\n const json = (value) => JSON.stringify(value).replace(/</g, "\\\\u003c").replace(/\\u2028/g, "\\\\u2028").replace(/\\u2029/g, "\\\\u2029");\n return `<!doctype html><html><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src \'none\'; script-src \'nonce-${nonce2}\'; style-src \'unsafe-inline\'; img-src data:; font-src \'none\'; connect-src \'none\'; media-src \'none\'; object-src \'none\'; frame-src \'none\'; worker-src \'none\'; base-uri \'none\'; form-action \'none\'"><meta name="viewport" content="width=device-width,initial-scale=1"><style>${CANVAS_SYSTEM_CSS}</style></head><body><main id="canvas"></main><script nonce="${nonce2}">(()=>{\n const channel=${json(channel2)}, source=${json({ html: node2.html, css: node2.css ?? "", script: node2.script ?? "" })};\n let snapshot={state:{},data:{},derived:{},disabled:true,theme:{}}, started=false;\n const listeners=new Set(), send=(type,payload)=>parent.postMessage({dshCanvas:1,channel,type,payload},\'*\');\n const report=e=>send(\'error\',String(e?.message??e).slice(0,1000));\n const audit=${measureVisual.toString()};let auditTimer;const scheduleAudit=()=>{clearTimeout(auditTimer);auditTimer=setTimeout(()=>{const issues=audit(document.getElementById(\'canvas\'),${json(node2.id ?? "")});send(\'audit\',{issues,coverage:issues.coverage})},400)};\n addEventListener(\'resize\',scheduleAudit);\n addEventListener(\'error\',e=>report(e.error??e.message));addEventListener(\'unhandledrejection\',e=>report(e.reason));\n const animations=new Set(), motion=matchMedia(\'(prefers-reduced-motion: reduce)\');\n let raf=0,last=0,time=0;\n const visible=()=>snapshot.visible!==false&&!document.hidden;\n const canAnimate=()=>visible()&&!snapshot.disabled&&!motion.matches;\n const draw=delta=>{for(const fn of animations)try{fn({time,delta,reducedMotion:motion.matches,visible:visible()})}catch(e){animations.delete(fn);report(e)}};\n const tick=t=>{raf=0;if(!canAnimate()||!animations.size){last=0;draw(0);return}const delta=last?Math.min(.05,(t-last)/1000):0;last=t;time+=delta;draw(delta);if(animations.size)raf=requestAnimationFrame(tick)};\n const refresh=()=>{draw(0);if(canAnimate()&&animations.size){if(!raf){last=0;raf=requestAnimationFrame(tick)}}else{cancelAnimationFrame(raf);raf=0;last=0}};\n motion.addEventListener(\'change\',refresh);document.addEventListener(\'visibilitychange\',refresh);\n const formatNumber=${formatNumber.toString()};\n const api={formatNumber,get snapshot(){return structuredClone(snapshot)},subscribe(fn){if(typeof fn!==\'function\')throw Error(\'Listener required\');listeners.add(fn);fn(api.snapshot);return()=>listeners.delete(fn)},setState(patch){if(!snapshot.disabled)send(\'patch\',patch)},animate(fn){if(typeof fn!==\'function\')throw Error(\'Animation callback required\');animations.add(fn);refresh();return()=>{animations.delete(fn);if(!animations.size){cancelAnimationFrame(raf);raf=0;last=0}}}};\n Object.defineProperty(window,\'DSHUI\',{value:Object.freeze(api),writable:false});\n for(const type of [\'click\',\'input\',\'change\',\'keydown\',\'pointerdown\'])document.addEventListener(type,e=>{if(snapshot.disabled){e.preventDefault();e.stopImmediatePropagation()}},true);\n addEventListener(\'message\',event=>{\n const m=event.data;if(event.source!==parent||m?.dshCanvas!==1||m.channel!==channel||m.type!==\'snapshot\')return;\n snapshot=m.payload;for(const [k,v] of Object.entries(snapshot.theme??{}))document.documentElement.style.setProperty(\'--canvas-\'+k,v);\n document.documentElement.style.colorScheme=snapshot.theme?.scheme??\'light\';document.documentElement.dataset.canvasScheme=snapshot.theme?.scheme??\'light\';\n const wasStarted=started;\n if(!started){started=true;document.getElementById(\'canvas\').innerHTML=source.html;const style=document.createElement(\'style\');style.textContent=source.css;document.head.append(style);const script=document.createElement(\'script\');script.nonce=${json(nonce2)};script.textContent=source.script;document.body.append(script)}\n if(wasStarted)for(const fn of listeners)try{fn(api.snapshot)}catch(e){report(e)}\n refresh();if(!wasStarted)send(\'mounted\');scheduleAudit();\n });\n let resizePending=false;new ResizeObserver(()=>{if(!started||resizePending)return;resizePending=true;requestAnimationFrame(()=>{resizePending=false;send(\'height\',Math.ceil(document.getElementById(\'canvas\').getBoundingClientRect().height))})}).observe(document.getElementById(\'canvas\'));\n send(\'ready\');\n})();<\\/script></body></html>`;\n }\n\n // lib/components.js\n var define = (fields2, purpose, presentation = "") => Object.freeze({ fields: Object.freeze(fields2), purpose, presentation });\n var COMPONENTS = Object.freeze({\n heading: define(["text"], "Section heading", "tone"),\n text: define(["text"], "Readable explanation or bound text", "tone"),\n row: define(["children"], "Wrapping parallel content"),\n column: define(["children"], "Ordered vertical content"),\n card: define(["title", "children", "surface"], "Meaningful grouped section", "tone"),\n details: define(["title", "children", "open"], "Collapsible supporting content", "tone"),\n badge: define(["text"], "Short explicit status label", "tone"),\n progress: define(["label", "value", "max", "unit"], "Declared numeric progress snapshot", "tone"),\n steps: define(["items"], "Ordered declared steps"),\n metric: define(["label", "value", "unit", "decimals"], "Numeric result with units", "tone"),\n input: define(["label", "bind"], "String or numeric state input"),\n slider: define(["label", "bind"], "Numeric state control"),\n select: define(["label", "bind"], "Selection from declared state options"),\n toggle: define(["label", "bind"], "Boolean state control"),\n button: define(["text", "action"], "Declared Agent follow-up", "icon"),\n table: define(["rows", "columns"], "Exact supplied or derived values"),\n chart: define(["kind", "rows", "labelKey", "valueKey", "label", "unit", "xScale"], "Bar/line comparison with accessible data"),\n sandbox: define(["title", "html", "css", "script", "fallback", "height", "stateKeys", "dataKeys", "derivedKeys"], "Freeform isolated HTML/SVG/CSS/JavaScript visualization")\n });\n function componentFields(type) {\n const c = Object.hasOwn(COMPONENTS, type) ? COMPONENTS[type] : void 0;\n return c && ["id", "type", ...c.fields, ...c.presentation ? ["icon"] : [], ...c.presentation === "tone" ? ["tone"] : []];\n }\n\n // lib/author-expression.js\n function compileExpression(source) {\n const fail2 = () => {\n throw new Error("DSH UI: invalid formula; use state.x, data.x, derived.x, item.x, numbers, strings, + - * /, comparisons, ?: and min/max/round/abs");\n };\n if (typeof source !== "string" || !source.trim() || source.length > 2048) fail2();\n const tokens = [];\n let offset = 0;\n const token2 = /\\s*(?:(\\d+(?:\\.\\d*)?|\\.\\d+)([eE][+-]?\\d+)?|("(?:[^"\\\\]|\\\\.)*")|([a-zA-Z][a-zA-Z0-9_]*(?:\\.[a-zA-Z][a-zA-Z0-9_]*)?)|(===|!==|<=|>=|==|!=|[+*/()?,:<>-]))/y;\n while (offset < source.length) {\n if (!source.slice(offset).trim()) break;\n token2.lastIndex = offset;\n const m = token2.exec(source);\n if (!m) fail2();\n offset = token2.lastIndex;\n tokens.push(m[1] ? { number: Number(m[1] + (m[2] ?? "")) } : m[3] ? { string: JSON.parse(m[3]) } : m[4] ?? m[5]);\n if (tokens.length > 256) fail2();\n }\n let pos = 0;\n const operators = { "==": ["eq", 1], "===": ["eq", 1], "!=": ["neq", 1], "!==": ["neq", 1], "<": ["lt", 2], "<=": ["lte", 2], ">": ["gt", 2], ">=": ["gte", 2], "+": ["add", 3], "-": ["sub", 3], "*": ["mul", 4], "/": ["div", 4] };\n const take = (t) => {\n if (tokens[pos++] !== t) fail2();\n };\n function parse(min = 0, depth = 0) {\n if (depth > 12) fail2();\n const t = tokens[pos++];\n let out;\n if (t && typeof t === "object") out = { const: Object.hasOwn(t, "number") ? t.number : t.string };\n else if (t === "true" || t === "false") out = { const: t === "true" };\n else if (t === "(") {\n out = parse(0, depth + 1);\n take(")");\n } else if (t === "-" || t === "+") {\n const arg = parse(5, depth + 1);\n out = t === "-" ? { op: "sub", args: [{ const: 0 }, arg] } : arg;\n } else if (typeof t === "string" && /^(state|data|derived|item)\\.[a-zA-Z][a-zA-Z0-9_]*$/.test(t)) out = { ref: t };\n else if (["min", "max", "round", "abs"].includes(t)) {\n take("(");\n const args = [parse(0, depth + 1)];\n while (tokens[pos] === ",") {\n pos++;\n args.push(parse(0, depth + 1));\n if (args.length > 8) fail2();\n }\n take(")");\n out = { op: t, args };\n } else fail2();\n while (typeof tokens[pos] === "string" && Object.hasOwn(operators, tokens[pos]) && operators[tokens[pos]][1] >= min) {\n const [op, precedence] = operators[tokens[pos++]];\n out = { op, args: [out, parse(precedence + 1, depth + 1)] };\n }\n if (min === 0 && tokens[pos] === "?") {\n pos++;\n const yes = parse(0, depth + 1);\n take(":");\n out = { op: "if", args: [out, yes, parse(0, depth + 1)] };\n }\n return out;\n }\n const result = parse();\n if (pos !== tokens.length) fail2();\n return result;\n }\n function expandExpressions(doc2) {\n const expression = (e) => {\n if (!e || typeof e !== "object" || Array.isArray(e)) return e;\n if (Object.hasOwn(e, "expr")) {\n if (Object.keys(e).length !== 1) throw new Error("DSH UI: expr must be the only formula field");\n return compileExpression(e.expr);\n }\n if (Array.isArray(e.args)) e.args = e.args.map(expression);\n if (e.map?.fields) for (const k of Object.keys(e.map.fields)) e.map.fields[k] = expression(e.map.fields[k]);\n return e;\n };\n if (doc2.derived && typeof doc2.derived === "object") for (const k of Object.keys(doc2.derived)) doc2.derived[k] = expression(doc2.derived[k]);\n const walk = (nodes) => {\n if (!Array.isArray(nodes)) return;\n for (const node2 of nodes) {\n if (!node2 || typeof node2 !== "object") continue;\n for (const field of ["text", "value", "max", "rows"]) if (Object.hasOwn(node2, field)) node2[field] = expression(node2[field]);\n walk(node2.children);\n }\n };\n walk(doc2.nodes);\n return doc2;\n }\n\n // lib/protocol.js\n var LIMITS = Object.freeze({ bytes: 131072, nodes: 160, depth: 12, rows: 500, expressions: 128, steps: 4096 });\n var own = (o, k) => Object.hasOwn(o, k);\n var fail = (message) => {\n throw new Error(`DSH UI: ${message}`);\n };\n var object = (x) => x !== null && typeof x === "object" && !Array.isArray(x);\n var key = (x) => typeof x === "string" && /^[a-zA-Z][a-zA-Z0-9_]{0,63}$/.test(x) && !["constructor", "prototype", "__proto__"].includes(x);\n var finite = (x) => typeof x === "number" && Number.isFinite(x);\n var scalar = (x) => typeof x === "string" || typeof x === "boolean" || finite(x);\n var text = (x, at) => {\n if (typeof x !== "string" || x.length > 8192) fail(`${at} must be a string of at most 8192 characters`);\n };\n function fields(value, allowed, at) {\n if (!object(value)) fail(`${at} must be an object`);\n for (const k of Object.keys(value)) if (!allowed.includes(k)) {\n const hint = at === "document" ? " Controls and visual components belong in nodes as registered typed nodes, not extra document fields." : "";\n fail(`unknown field ${at}.${k}; allowed fields at ${at}: ${allowed.join(", ")}.${hint}`);\n }\n }\n function safeJson(value, depth = 0, source = false) {\n if (depth > 48) fail("JSON nesting is too deep");\n if (value === null || typeof value === "boolean") return;\n if (typeof value === "string") {\n if (source) {\n if (value.length > SANDBOX_LIMITS.source) fail("canvas source exceeds 48 Ki characters");\n return;\n }\n return text(value, "value");\n }\n if (typeof value === "number") {\n if (!finite(value)) fail("numbers must be finite");\n return;\n }\n if (typeof value !== "object") fail("only JSON values are accepted");\n if (Array.isArray(value) && value.length > LIMITS.rows) fail("too many array items");\n for (const k of Object.keys(value)) {\n if (["__proto__", "prototype", "constructor"].includes(k)) fail("unsafe property name");\n safeJson(value[k], depth + 1, value.type === "sandbox" && ["html", "css", "script"].includes(k));\n }\n }\n function initialState(doc2) {\n return Object.fromEntries(Object.entries(doc2.state).map(([k, spec]) => [k, spec.default]));\n }\n function validateState(doc2, state2) {\n if (!object(state2) || Object.keys(state2).length !== Object.keys(doc2.state).length) fail("state keys do not match the document");\n const result = {};\n for (const [k, s] of Object.entries(doc2.state)) {\n if (!own(state2, k)) fail(`missing state.${k}`);\n const v = state2[k];\n if (s.type === "number") {\n if (!finite(v) || v < s.min || v > s.max) fail(`state.${k} is outside its numeric range`);\n const offset = (v - s.min) / s.step;\n if (Math.abs(offset - Math.round(offset)) > 1e-6) fail(`state.${k} does not match its step`);\n } else if (s.type === "string") text(v, `state.${k}`);\n else if (typeof v !== "boolean") fail(`state.${k} must be boolean`);\n if (s.options && !s.options.includes(v)) fail(`invalid option for state.${k}`);\n result[k] = v;\n }\n return result;\n }\n var ARITY = { add: [1, 8], sub: [2, 2], mul: [1, 8], div: [2, 2], min: [1, 8], max: [1, 8], round: [1, 1], abs: [1, 1], eq: [2, 2], neq: [2, 2], lt: [2, 2], lte: [2, 2], gt: [2, 2], gte: [2, 2], if: [3, 3] };\n function reference(doc2, ref) {\n if (typeof ref !== "string" || !/^(state|data|derived)\\.[a-zA-Z][a-zA-Z0-9_]{0,63}$/.test(ref)) fail("invalid reference");\n const [group, k] = ref.split(".");\n if (!own(doc2[group], k)) fail(`unknown reference ${ref}`);\n return [group, k];\n }\n function evaluate(doc2, state2) {\n const derived = {}, active = /* @__PURE__ */ new Set();\n let steps = 0, generatedRows = 0;\n const budget = () => {\n if (++steps > LIMITS.steps) fail("calculation budget exceeded");\n };\n const resolve = (ref) => {\n budget();\n const [group, k] = reference(doc2, ref);\n if (group !== "derived") return (group === "state" ? state2 : doc2.data)[k];\n if (own(derived, k)) return derived[k];\n if (active.has(k)) fail(`cyclic calculation ${k}`);\n active.add(k);\n const result2 = expression(doc2.derived[k]);\n active.delete(k);\n derived[k] = result2;\n return result2;\n };\n const expression = (e, item) => {\n budget();\n if (own(e, "map")) {\n const rows = resolve(e.map.source);\n if ((generatedRows += rows.length) > LIMITS.rows) fail("generated row limit exceeded");\n return rows.map((row) => Object.fromEntries(Object.entries(e.map.fields).map(([k, value]) => {\n const out2 = expression(value, row);\n if (!scalar(out2)) fail("generated cells must be scalar");\n return [k, out2];\n })));\n }\n if (own(e, "const")) return e.const;\n if (own(e, "ref")) {\n if (e.ref.startsWith("item.")) {\n const k = e.ref.slice(5);\n if (!item || !own(item, k) || !scalar(item[k])) fail("invalid item reference");\n return item[k];\n }\n return resolve(e.ref);\n }\n if (e.op === "if") {\n const condition = expression(e.args[0], item);\n if (typeof condition !== "boolean") fail("if condition must be boolean");\n return expression(e.args[condition ? 1 : 2], item);\n }\n const a = e.args.map((arg) => expression(arg, item));\n if (e.op === "eq") return a[0] === a[1];\n if (e.op === "neq") return a[0] !== a[1];\n if (!a.every(finite)) fail(`operator ${e.op} requires finite numbers`);\n let out;\n switch (e.op) {\n case "add":\n out = a.reduce((x, y) => x + y, 0);\n break;\n case "sub":\n out = a[0] - a[1];\n break;\n case "mul":\n out = a.reduce((x, y) => x * y, 1);\n break;\n case "div":\n if (a[1] === 0) fail("division by zero");\n out = a[0] / a[1];\n break;\n case "min":\n out = Math.min(...a);\n break;\n case "max":\n out = Math.max(...a);\n break;\n case "round":\n out = Math.round(a[0]);\n break;\n case "abs":\n out = Math.abs(a[0]);\n break;\n case "lt":\n return a[0] < a[1];\n case "lte":\n return a[0] <= a[1];\n case "gt":\n return a[0] > a[1];\n case "gte":\n return a[0] >= a[1];\n default:\n fail(`unsupported operator ${e.op}`);\n }\n if (!finite(out)) fail("non-finite calculation result");\n return out;\n };\n for (const k of Object.keys(doc2.derived)) resolve(`derived.${k}`);\n if (new TextEncoder().encode(JSON.stringify(derived)).length > LIMITS.bytes) fail("derived output exceeds 128 KiB");\n const result = { derived, resolveValue: (value) => {\n if (!object(value)) return value;\n return expression(value);\n } };\n checkViewValues(doc2, result);\n return result;\n }\n function checkViewValues(doc2, evaluated) {\n function walk(list) {\n for (const n of list) {\n if (n.type === "table" || n.type === "chart") {\n const rows = evaluated.resolveValue(n.rows);\n if (!Array.isArray(rows) || rows.length > LIMITS.rows || !rows.every(object)) fail("table/chart rows must reference an array of objects");\n if (n.type === "chart" && rows.some((r) => !own(r, n.labelKey) || !scalar(r[n.labelKey]) || !own(r, n.valueKey) || !finite(r[n.valueKey]))) fail("chart requires labels and finite numeric values");\n if (n.type === "chart" && n.xScale === "linear" && rows.some((r) => !finite(r[n.labelKey]))) fail("linear chart requires numeric x values");\n }\n if (n.type === "metric" && !finite(evaluated.resolveValue(n.value))) fail("metric requires a numeric value");\n if (n.type === "progress") {\n const v = evaluated.resolveValue(n.value), max = evaluated.resolveValue(n.max);\n if (!finite(v) || !finite(max) || max <= 0 || v < 0 || v > max) fail("progress requires 0 <= value <= positive max");\n }\n if (n.children) walk(n.children);\n }\n }\n walk(doc2.nodes);\n }\n function validateDocument(input) {\n safeJson(input);\n const json = JSON.stringify(input);\n if (new TextEncoder().encode(json).length > LIMITS.bytes) fail("document exceeds 128 KiB");\n const doc2 = expandExpressions(JSON.parse(json));\n fields(doc2, ["version", "title", "fallback", "state", "data", "derived", "nodes", "actions", "presentation"], "document");\n if (doc2.presentation !== void 0) {\n fields(doc2.presentation, ["layout", "accent", "density"], "presentation");\n for (const [k, allowed] of Object.entries({ layout: UI_LAYOUTS, accent: UI_ACCENTS, density: ["comfortable", "compact"] }))\n if (doc2.presentation[k] !== void 0 && !allowed.includes(doc2.presentation[k])) fail(`unknown presentation ${k}`);\n }\n if (doc2.version !== 1) fail("unsupported protocol version");\n text(doc2.title, "title");\n text(doc2.fallback, "fallback");\n if (!doc2.title.trim() || !doc2.fallback.trim()) fail("title and fallback cannot be empty");\n for (const group of ["state", "data", "derived", "actions"]) {\n doc2[group] ??= {};\n if (!object(doc2[group]) || Object.keys(doc2[group]).length > 64) fail(`invalid ${group}`);\n for (const k of Object.keys(doc2[group])) if (!key(k)) fail(`invalid key in ${group}`);\n }\n for (const [k, s] of Object.entries(doc2.state)) {\n fields(s, ["type", "default", "min", "max", "step", "options"], `state.${k}`);\n if (!["number", "string", "boolean"].includes(s.type)) fail(`unsupported state type ${k}`);\n if (s.type === "number") {\n if (![s.min, s.max, s.step].every(finite) || s.min >= s.max || s.step <= 0) fail(`invalid numeric limits for ${k}`);\n if ((s.max - s.min) / s.step > 1e9) fail(`numeric step too small for ${k}`);\n } else if (["min", "max", "step"].some((p) => own(s, p))) fail(`numeric limits on non-number ${k}`);\n if (s.options && (!Array.isArray(s.options) || !s.options.length || s.options.length > 64 || !s.options.every(scalar))) fail(`invalid options for ${k}`);\n }\n const defaults = validateState(doc2, initialState(doc2));\n let expressions = 0;\n for (const [k, spec] of Object.entries(doc2.state))\n for (const option of spec.options ?? []) validateState(doc2, { ...defaults, [k]: option });\n function validateExpression(e, depth = 0, itemRows) {\n if (++expressions > LIMITS.expressions || depth > LIMITS.depth) fail("expression limit exceeded");\n if (!object(e)) fail("expression must be an object");\n if (own(e, "map")) {\n if (depth !== 0) fail("map is only allowed at the root of a derived value");\n fields(e, ["map"], "expression");\n fields(e.map, ["source", "fields"], "map");\n if (typeof e.map.source !== "string" || !e.map.source.startsWith("data.")) fail(\'map source must reference static data using a string such as "data.samples"; put object rows in document.data.samples, not inline in map.source\');\n const [, k] = reference(doc2, e.map.source), rows = doc2.data[k];\n if (!Array.isArray(rows) || rows.length > LIMITS.rows || !rows.every(object)) fail("map source must be object rows");\n if (!object(e.map.fields) || !Object.keys(e.map.fields).length || Object.keys(e.map.fields).length > 16) fail("map requires 1..16 fields");\n for (const [k2, value2] of Object.entries(e.map.fields)) {\n if (!key(k2)) fail(`invalid map field ${JSON.stringify(k2).slice(0, 100)}; use an ASCII identifier matching [a-zA-Z][a-zA-Z0-9_]{0,63}, such as powerW. Put Chinese display text in column/chart labels, not internal field keys`);\n validateExpression(value2, depth + 1, rows);\n }\n return;\n }\n if (own(e, "const")) {\n fields(e, ["const"], "expression");\n if (!scalar(e.const)) fail("constant must be scalar");\n return;\n }\n if (own(e, "ref")) {\n fields(e, ["ref"], "expression");\n if (typeof e.ref === "string" && e.ref.startsWith("item.")) {\n const k = e.ref.slice(5);\n if (!itemRows || !key(k) || itemRows.some((row) => !own(row, k) || !scalar(row[k]))) fail("invalid or unscoped item reference");\n } else reference(doc2, e.ref);\n return;\n }\n fields(e, ["op", "args"], "expression");\n const arity = ARITY[e.op];\n if (!arity || !Array.isArray(e.args) || e.args.length < arity[0] || e.args.length > arity[1]) fail("invalid operator or argument count");\n e.args.forEach((a) => validateExpression(a, depth + 1, itemRows));\n }\n Object.values(doc2.derived).forEach((e) => validateExpression(e));\n const visited = /* @__PURE__ */ new Set(), active = /* @__PURE__ */ new Set();\n function visit(k) {\n if (active.has(k)) fail(`cyclic calculation ${k}`);\n if (visited.has(k)) return;\n active.add(k);\n function walk(e) {\n if (e.ref?.startsWith("derived.")) visit(e.ref.split(".")[1]);\n for (const a of e.args ?? []) walk(a);\n for (const value2 of Object.values(e.map?.fields ?? {})) walk(value2);\n }\n walk(doc2.derived[k]);\n active.delete(k);\n visited.add(k);\n }\n Object.keys(doc2.derived).forEach(visit);\n for (const [k, a] of Object.entries(doc2.actions)) {\n fields(a, ["type", "intent", "stateKeys"], `actions.${k}`);\n if (a.type !== "agent.followup") fail("only agent.followup actions are supported");\n text(a.intent, "action intent");\n if (!a.intent.trim() || !Array.isArray(a.stateKeys) || a.stateKeys.length > 64 || new Set(a.stateKeys).size !== a.stateKeys.length || a.stateKeys.some((s) => !own(doc2.state, s))) fail("invalid action stateKeys");\n }\n const ids = /* @__PURE__ */ new Set();\n let count2 = 0;\n const value = (v, at) => {\n if (object(v)) {\n if (own(v, "map")) fail("map belongs in derived");\n validateExpression(v);\n } else if (!scalar(v)) fail(`invalid value at ${at}`);\n };\n function nodes(list, depth = 0) {\n if (!Array.isArray(list) || depth > LIMITS.depth) fail("invalid node children or depth");\n for (const n of list) {\n if (++count2 > LIMITS.nodes) fail("too many nodes");\n if (!object(n) || !key(n.id) || ids.has(n.id)) fail("node ids must be unique identifiers");\n ids.add(n.id);\n if (!Object.hasOwn(COMPONENTS, n.type)) fail("unsupported component " + n.type);\n switch (n.type) {\n case "sandbox": {\n text(n.title, "canvas title");\n text(n.fallback, "canvas fallback");\n if (!n.title.trim() || !n.fallback.trim() || typeof n.html !== "string" || !n.html.trim()) fail("canvas requires title, HTML and fallback");\n for (const field of ["html", "css", "script"]) if (n[field] !== void 0 && (typeof n[field] !== "string" || n[field].length > SANDBOX_LIMITS.source)) fail("canvas source exceeds 48 Ki characters");\n if (n.height !== void 0 && (!Number.isInteger(n.height) || n.height < 160 || n.height > SANDBOX_LIMITS.height)) fail("canvas height must be 160..1000");\n for (const [field, group] of [["stateKeys", "state"], ["dataKeys", "data"], ["derivedKeys", "derived"]]) if (n[field] !== void 0 && (!Array.isArray(n[field]) || n[field].length > 64 || new Set(n[field]).size !== n[field].length || n[field].some((k) => !own(doc2[group], k)))) fail("invalid canvas " + field);\n break;\n }\n case "row":\n case "column":\n break;\n case "card":\n if (n.title !== void 0) text(n.title, "card title");\n if (n.surface !== void 0 && !UI_SURFACES.includes(n.surface)) fail("unknown card surface");\n break;\n case "details":\n text(n.title, "details title");\n if (n.open !== void 0 && typeof n.open !== "boolean") fail("details open must be boolean");\n break;\n case "badge":\n value(n.text, "badge text");\n break;\n case "progress":\n text(n.label, "progress label");\n value(n.value, "progress value");\n value(n.max, "progress max");\n if (n.unit !== void 0) text(n.unit, "progress unit");\n break;\n case "steps": {\n if (!Array.isArray(n.items) || !n.items.length || n.items.length > 12) fail("steps require 1..12 items");\n for (const item of n.items) {\n fields(item, ["title", "description", "status"], "step");\n text(item.title, "step title");\n if (item.description !== void 0) text(item.description, "step description");\n if (!["pending", "active", "done", "error"].includes(item.status)) fail("unknown step status");\n }\n break;\n }\n case "heading":\n case "text":\n value(n.text, "text");\n break;\n case "metric":\n text(n.label, "metric label");\n value(n.value, "metric value");\n if (n.unit !== void 0) text(n.unit, "unit");\n if (n.decimals !== void 0 && (!Number.isInteger(n.decimals) || n.decimals < 0 || n.decimals > 6)) fail("invalid decimals");\n break;\n case "input":\n case "slider":\n case "select":\n case "toggle": {\n text(n.label, "control label");\n if (typeof n.bind !== "string" || !n.bind.startsWith("state.")) fail("controls must bind state");\n const [, k] = reference(doc2, n.bind), spec = doc2.state[k];\n if (n.type === "slider" && spec.type !== "number") fail("slider requires numeric state");\n if (n.type === "toggle" && spec.type !== "boolean") fail("toggle requires boolean state");\n if (n.type === "input" && spec.type === "boolean") fail("use toggle for boolean state");\n if (n.type === "select" && !spec.options) fail("select requires options");\n break;\n }\n case "button":\n text(n.text, "button text");\n if (!own(doc2.actions, n.action)) fail("unknown action");\n break;\n case "table": {\n if (Array.isArray(n.rows)) fail(\'table.rows must use {ref:"data.rows"}; move the array into document.data.rows, not inline in the table\');\n value(n.rows, "table rows");\n if (!Array.isArray(n.columns) || !n.columns.length || n.columns.length > 16) fail("invalid table columns");\n const cols = /* @__PURE__ */ new Set();\n for (const c of n.columns) {\n fields(c, ["key", "label", "unit"], "column");\n if (!key(c.key) || cols.has(c.key)) fail("invalid or duplicate column key");\n cols.add(c.key);\n text(c.label, "column label");\n if (c.unit !== void 0) text(c.unit, "column unit");\n }\n break;\n }\n case "chart":\n value(n.rows, "chart rows");\n if (!["bar", "line"].includes(n.kind) || !key(n.labelKey) || !key(n.valueKey)) fail("invalid chart");\n text(n.label, "chart label");\n if (n.unit !== void 0) text(n.unit, "chart unit");\n if (n.xScale !== void 0 && (!["category", "linear"].includes(n.xScale) || n.xScale === "linear" && n.kind !== "line")) fail("invalid xScale");\n break;\n default:\n fail(`unsupported component ${n.type}`);\n }\n if (["heading", "text", "card", "metric", "button", "badge", "progress", "details"].includes(n.type)) {\n if (n.icon !== void 0 && !UI_ICONS.includes(n.icon)) fail("unknown UI icon");\n if (n.type !== "button") {\n if (n.tone !== void 0 && !UI_TONES.includes(n.tone)) fail("unknown UI tone");\n }\n }\n fields(n, componentFields(n.type), `node.${n.id}`);\n if (["row", "column", "card", "details"].includes(n.type)) nodes(n.children, depth + 1);\n }\n }\n nodes(doc2.nodes);\n if (!count2) fail("at least one node is required");\n evaluate(doc2, defaults);\n return doc2;\n }\n\n // src/export-runtime.js\n var payload = JSON.parse(document.getElementById("dsh-ui-export").textContent);\n var doc = validateDocument(payload.document);\n var node = doc.nodes.flatMap(function flatten(n) {\n return [n, ...(n.children ?? []).flatMap(flatten)];\n }).find((n) => n.id === payload.nodeId && n.type === "sandbox");\n if (!node) throw Error("\\u5BFC\\u51FA\\u7684\\u753B\\u5E03\\u4E0D\\u5B58\\u5728");\n var state = validateState(doc, payload.state);\n var connected = false;\n var start = Date.now();\n var count = 0;\n var token = () => Array.from(crypto.getRandomValues(new Uint8Array(16)), (b) => b.toString(16).padStart(2, "0")).join("");\n var channel = token();\n var nonce = payload.nonce;\n var frame = document.createElement("iframe");\n frame.title = node.title;\n frame.sandbox = "allow-scripts";\n frame.referrerPolicy = "no-referrer";\n frame.style.cssText = "display:block;width:100%;height:" + (node.height ?? 420) + "px;border:0";\n var status = document.getElementById("status");\n var publish = () => {\n try {\n frame.contentWindow.postMessage({ dshCanvas: 1, channel, type: "snapshot", payload: { ...canvasSnapshot(node, state, doc.data, evaluate(doc, state).derived, false, payload.theme), visible: !document.hidden } }, "*");\n } catch (e) {\n status.textContent = "\\u8BA1\\u7B97\\u5931\\u8D25\\uFF1A" + e.message;\n }\n };\n addEventListener("message", (event) => {\n const m = event.data;\n if (event.source !== frame.contentWindow || m?.channel !== channel || m.dshCanvas !== 1) return;\n if (Date.now() - start > 1e3) {\n start = Date.now();\n count = 0;\n }\n if (++count > SANDBOX_LIMITS.rate) return;\n if (m.type === "ready") {\n connected = true;\n publish();\n } else if (m.type === "patch" && connected) {\n try {\n const next = validateState(doc, { ...state, ...canvasPatch(m.payload, node) });\n evaluate(doc, next);\n state = next;\n status.textContent = "\\u672C\\u5730\\u53C2\\u6570\\u5DF2\\u66F4\\u65B0\\uFF1B\\u5237\\u65B0\\u6587\\u4EF6\\u4F1A\\u56DE\\u5230\\u5BFC\\u51FA\\u65F6\\u7684\\u53C2\\u6570\\u3002";\n } catch (e) {\n status.textContent = "\\u53C2\\u6570\\u65E0\\u6548\\uFF1A" + e.message;\n }\n publish();\n } else if (m.type === "height" && Number.isFinite(m.payload)) frame.style.height = Math.max(160, Math.min(1e3, Math.ceil(m.payload))) + "px";\n else if (m.type === "error") status.textContent = "\\u753B\\u5E03\\u8FD0\\u884C\\u5F02\\u5E38\\uFF1A" + String(m.payload).slice(0, 1e3);\n });\n document.addEventListener("visibilitychange", () => {\n if (connected) publish();\n });\n document.getElementById("surface").append(frame);\n frame.srcdoc = sandboxDocument(node, channel, nonce);\n})();\n';
|
|
22794
|
+
var EXPORT_RUNTIME = '(() => {\n // lib/presentation.js\n var UI_ICONS = Object.freeze(["sparkles", "sliders", "layers", "chart", "gauge", "cpu", "database", "info", "check", "warning", "arrow", "target"]);\n var UI_TONES = Object.freeze(["neutral", "accent", "success", "warning", "danger"]);\n var UI_LAYOUTS = Object.freeze(["dashboard", "workbench", "comparison", "guide", "status", "report"]);\n var UI_ACCENTS = Object.freeze(["blue", "teal", "violet", "amber", "rose"]);\n var UI_SURFACES = Object.freeze(["outline", "soft", "featured"]);\n\n // lib/visual-audit.js\n function measureVisual(root, nodeId = "") {\n const issues = [], seen = /* @__PURE__ */ new Set(), coverage = { nodeId, elements: 0, truncated: false, contrastChecked: 0, contrastUncovered: 0 };\n const add = (code, value, el2) => {\n const id = el2?.closest("[data-ui-node]")?.getAttribute("data-ui-node") ?? nodeId;\n const k = id + ":" + code + ":" + Math.round(value ?? 0);\n if (!seen.has(k) && issues.length < 40) {\n seen.add(k);\n issues.push({ code, nodeId: id, ...value === void 0 ? {} : { value: Number(value.toFixed(2)) } });\n }\n };\n const color = (s) => {\n let m = s.match(/^rgba?\\(([^)]+)\\)/);\n if (m) {\n const a = m[1].split(/[\\s,\\/]+/).map(Number);\n return [a[0] / 255, a[1] / 255, a[2] / 255, a[3] ?? 1];\n }\n m = s.match(/^color\\(srgb ([^)]+)\\)/);\n if (m) {\n const a = m[1].split(/[\\s\\/]+/).map(Number);\n return [a[0], a[1], a[2], a[3] ?? 1];\n }\n return null;\n };\n const luminance = (c) => c.slice(0, 3).map((v) => v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4).reduce((s, v, i) => s + v * [0.2126, 0.7152, 0.0722][i], 0);\n const widthRoot = root.id === "canvas" ? document.documentElement : root;\n if (widthRoot.scrollWidth > widthRoot.clientWidth + 2) add("overflow", widthRoot.scrollWidth - widthRoot.clientWidth);\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n let el;\n while (el = walker.nextNode()) {\n if (coverage.elements >= 2e3) {\n coverage.truncated = true;\n break;\n }\n coverage.elements++;\n if (el.matches("[data-canvas-phase=error]")) add("runtimeError", void 0, el);\n const css = getComputedStyle(el), box = el.getBoundingClientRect();\n if (!box.width || !box.height || css.visibility === "hidden" || css.display === "none") continue;\n const text2 = [...el.childNodes].some((n) => n.nodeType === 3 && n.textContent.trim());\n if (text2) {\n let size = parseFloat(css.fontSize);\n if (el instanceof SVGElement && el.getScreenCTM) {\n const m = el.getScreenCTM();\n if (m) size *= Math.hypot(m.c, m.d);\n }\n if (size < 11.9) add("smallText", size, el);\n const fg = color(css.color);\n let ancestor = el, bg = null, depth = 0;\n while (ancestor && depth++ < 64) {\n const style = getComputedStyle(ancestor);\n if (style.backgroundImage !== "none") break;\n const c = color(style.backgroundColor);\n if (c?.[3] === 1) {\n bg = c;\n break;\n }\n if (c?.[3] > 0) break;\n ancestor = ancestor.parentElement;\n }\n if (!(el instanceof SVGElement) && fg?.[3] === 1 && bg) {\n coverage.contrastChecked++;\n const a = luminance(fg), b = luminance(bg), ratio = (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);\n if (ratio < (size >= 24 || size >= 18.66 && parseFloat(css.fontWeight) >= 700 ? 3 : 4.5)) add("contrast", ratio, el);\n } else coverage.contrastUncovered++;\n }\n if (el.matches("input:not([type=hidden]),select,textarea,button,[role=button]") && !el.getAttribute("aria-label") && !el.getAttribute("aria-labelledby") && !el.labels?.length && !el.textContent.trim() && !el.getAttribute("title")) add("missingLabel", void 0, el);\n }\n Object.defineProperty(issues, "coverage", { value: coverage });\n return issues;\n }\n\n // lib/format-number.js\n function formatNumber(value, decimals = 2) {\n if (typeof value !== "number" || !Number.isFinite(value)) throw new Error("DSH UI: formatNumber requires a finite number");\n if (!Number.isInteger(decimals) || decimals < 0 || decimals > 6) throw new Error("DSH UI: formatNumber decimals must be an integer from 0 to 6");\n return value.toLocaleString("en-US", { minimumFractionDigits: decimals, maximumFractionDigits: decimals });\n }\n\n // lib/canvas-system.js\n var CANVAS_SYSTEM_CSS = `\n:root{--canvas-radius:20px;--canvas-gap:16px;--canvas-positive:#167456;--canvas-negative:#b13b3b;--canvas-warning:#875b15}\n:root[data-canvas-scheme=dark]{--canvas-positive:#78d9b4;--canvas-negative:#ffaaaa;--canvas-warning:#edc87e}\n#canvas{display:flow-root}html,body{margin:0;min-width:0;background:var(--canvas-bg,#fff);color:var(--canvas-ink,#182537);font:14px/1.6 system-ui,"Microsoft YaHei",sans-serif}*{box-sizing:border-box}svg{max-width:100%;height:auto}button,input,select,textarea{font:inherit;color:inherit}button,input,select,textarea{border:1px solid var(--canvas-line,#ced4df);border-radius:8px;background:var(--canvas-bg,#fff);padding:8px 12px;max-width:100%}button{cursor:pointer}button:disabled{cursor:default;opacity:.55}input[type=range]{padding:0;accent-color:var(--canvas-accent,#3e60d3)}input[type=checkbox],input[type=radio]{accent-color:var(--canvas-accent,#3e60d3)}button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[tabindex]:focus-visible{outline:2px solid var(--canvas-accent,#3e60d3);outline-offset:3px}\n.ui-stack{display:grid;gap:var(--canvas-gap)}.ui-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:var(--canvas-gap)}.ui-surface{padding:20px;border:1px solid var(--canvas-line,#ced4df);border-radius:var(--canvas-radius);background:var(--canvas-soft,#f3f5f8)}.ui-title{margin:0;font-size:clamp(20px,3vw,28px);line-height:1.3;letter-spacing:-.02em}.ui-caption{color:var(--canvas-muted,#526176);margin:8px 0;font-size:14px}.ui-value{font-size:clamp(24px,4vw,36px);font-variant-numeric:tabular-nums;line-height:1.2}.ui-controls{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.ui-field{display:grid;gap:6px;min-width:0}.ui-legend{display:flex;gap:16px;flex-wrap:wrap;font-size:13px}.ui-status{min-height:1.6em}.ui-error{color:var(--canvas-negative)}.ui-primary{background:var(--canvas-accent,#3e60d3);color:var(--canvas-accent-ink,#fff);border-color:transparent}\nsvg .ui-node{fill:var(--canvas-soft,#f3f5f8);stroke:var(--canvas-line,#ced4df);stroke-width:1}svg .ui-edge{fill:none;stroke:var(--canvas-muted,#526176);stroke-width:1.5}svg .ui-label{fill:var(--canvas-ink,#182537);font:500 14px system-ui,sans-serif}svg .ui-note{fill:var(--canvas-muted,#526176);font:400 13px system-ui,sans-serif}svg .ui-leader{fill:none;stroke:var(--canvas-muted,#526176);stroke-dasharray:3 4}svg .ui-accent{fill:color-mix(in srgb,var(--canvas-accent,#3e60d3) 12%,var(--canvas-bg,#fff));stroke:var(--canvas-accent,#3e60d3)}\n.ui-flow{display:flex;align-items:center;justify-content:center;gap:16px;padding:24px 8px;flex-wrap:wrap}.ui-step{display:grid;gap:6px;min-width:130px;max-width:240px;padding:16px 20px;border:1px solid var(--canvas-line);border-radius:6px;background:var(--canvas-bg)}.ui-step strong{font-size:16px;font-weight:600}.ui-step span{font-size:14px;color:var(--canvas-muted)}.ui-arrow{color:var(--canvas-muted);font-size:22px}.ui-callout{border-inline-start:3px solid var(--canvas-accent);padding:8px 16px;color:var(--canvas-ink)}\n.ui-surface,.ui-step{border-radius:var(--canvas-radius);background:linear-gradient(135deg,color-mix(in srgb,var(--canvas-accent,#3e60d3) 9%,var(--canvas-bg,#fff)),var(--canvas-soft,#f3f5f8))}button,input:not([type=checkbox]):not([type=radio]):not([type=range]),select,textarea{border-radius:14px}.ui-primary{background:linear-gradient(120deg,var(--canvas-accent,#3e60d3),color-mix(in srgb,var(--canvas-accent,#3e60d3) 85%,#152647))}.ui-callout{border-radius:14px;background:linear-gradient(120deg,color-mix(in srgb,var(--canvas-accent,#3e60d3) 7%,var(--canvas-bg,#fff)),var(--canvas-bg,#fff))}\n@media(max-width:480px){.ui-flow{flex-direction:column;padding:16px 8px;gap:12px}.ui-step{width:100%;max-width:none}.ui-arrow{transform:rotate(90deg)}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}}`;\n\n // lib/sandbox.js\n var SANDBOX_LIMITS = Object.freeze({ source: 49152, height: 1e3, message: 16384, rate: 30 });\n function canvasSnapshot(node2, state2, data, derived, disabled, theme) {\n const pick = (keys, values) => Object.fromEntries((keys ?? []).map((k) => [k, values[k]]));\n return { state: pick(node2.stateKeys, state2), data: pick(node2.dataKeys, data), derived: pick(node2.derivedKeys, derived), disabled, theme };\n }\n function canvasPatch(message, node2) {\n if (!message || typeof message !== "object" || Array.isArray(message)) throw new Error("Invalid canvas patch");\n const keys = Object.keys(message);\n if (!keys.length || keys.length > 64 || keys.some((k) => !(node2.stateKeys ?? []).includes(k))) throw new Error("Canvas state key is not declared");\n if (JSON.stringify(message).length > SANDBOX_LIMITS.message) throw new Error("Canvas patch is too large");\n return message;\n }\n function sandboxDocument(node2, channel2, nonce2) {\n const json = (value) => JSON.stringify(value).replace(/</g, "\\\\u003c").replace(/\\u2028/g, "\\\\u2028").replace(/\\u2029/g, "\\\\u2029");\n return `<!doctype html><html><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src \'none\'; script-src \'nonce-${nonce2}\'; style-src \'unsafe-inline\'; img-src data:; font-src \'none\'; connect-src \'none\'; media-src \'none\'; object-src \'none\'; frame-src \'none\'; worker-src \'none\'; base-uri \'none\'; form-action \'none\'"><meta name="viewport" content="width=device-width,initial-scale=1"><style>${CANVAS_SYSTEM_CSS}</style></head><body><main id="canvas"></main><script nonce="${nonce2}">(()=>{\n const channel=${json(channel2)}, source=${json({ html: node2.html, css: node2.css ?? "", script: node2.script ?? "" })};\n let snapshot={state:{},data:{},derived:{},disabled:true,theme:{}}, started=false;\n const listeners=new Set(), send=(type,payload)=>parent.postMessage({dshCanvas:1,channel,type,payload},\'*\');\n const report=e=>send(\'error\',String(e?.message??e).slice(0,1000));\n const audit=${measureVisual.toString()};let auditTimer;const scheduleAudit=()=>{clearTimeout(auditTimer);auditTimer=setTimeout(()=>{const issues=audit(document.getElementById(\'canvas\'),${json(node2.id ?? "")});send(\'audit\',{issues,coverage:issues.coverage})},400)};\n addEventListener(\'resize\',scheduleAudit);\n addEventListener(\'error\',e=>report(e.error??e.message));addEventListener(\'unhandledrejection\',e=>report(e.reason));\n const animations=new Set(), motion=matchMedia(\'(prefers-reduced-motion: reduce)\');\n let raf=0,last=0,time=0;\n const visible=()=>snapshot.visible!==false&&!document.hidden;\n const canAnimate=()=>visible()&&!snapshot.disabled&&!motion.matches;\n const draw=delta=>{for(const fn of animations)try{fn({time,delta,reducedMotion:motion.matches,visible:visible()})}catch(e){animations.delete(fn);report(e)}};\n const tick=t=>{raf=0;if(!canAnimate()||!animations.size){last=0;draw(0);return}const delta=last?Math.min(.05,(t-last)/1000):0;last=t;time+=delta;draw(delta);if(animations.size)raf=requestAnimationFrame(tick)};\n const refresh=()=>{draw(0);if(canAnimate()&&animations.size){if(!raf){last=0;raf=requestAnimationFrame(tick)}}else{cancelAnimationFrame(raf);raf=0;last=0}};\n motion.addEventListener(\'change\',refresh);document.addEventListener(\'visibilitychange\',refresh);\n const formatNumber=${formatNumber.toString()};\n const api={formatNumber,get snapshot(){return structuredClone(snapshot)},subscribe(fn){if(typeof fn!==\'function\')throw Error(\'Listener required\');listeners.add(fn);fn(api.snapshot);return()=>listeners.delete(fn)},setState(patch){if(!snapshot.disabled)send(\'patch\',patch)},animate(fn){if(typeof fn!==\'function\')throw Error(\'Animation callback required\');animations.add(fn);refresh();return()=>{animations.delete(fn);if(!animations.size){cancelAnimationFrame(raf);raf=0;last=0}}}};\n Object.defineProperty(window,\'DSHUI\',{value:Object.freeze(api),writable:false});\n for(const type of [\'click\',\'input\',\'change\',\'keydown\',\'pointerdown\'])document.addEventListener(type,e=>{if(snapshot.disabled){e.preventDefault();e.stopImmediatePropagation()}},true);\n addEventListener(\'message\',event=>{\n const m=event.data;if(event.source!==parent||m?.dshCanvas!==1||m.channel!==channel||m.type!==\'snapshot\')return;\n snapshot=m.payload;for(const [k,v] of Object.entries(snapshot.theme??{}))document.documentElement.style.setProperty(\'--canvas-\'+k,v);\n document.documentElement.style.colorScheme=snapshot.theme?.scheme??\'light\';document.documentElement.dataset.canvasScheme=snapshot.theme?.scheme??\'light\';\n const wasStarted=started;\n if(!started){started=true;document.getElementById(\'canvas\').innerHTML=source.html;const style=document.createElement(\'style\');style.textContent=source.css;document.head.append(style);const script=document.createElement(\'script\');script.nonce=${json(nonce2)};script.textContent=source.script;document.body.append(script)}\n if(wasStarted)for(const fn of listeners)try{fn(api.snapshot)}catch(e){report(e)}\n refresh();if(!wasStarted)send(\'mounted\');scheduleAudit();\n });\n let resizePending=false;new ResizeObserver(()=>{if(!started||resizePending)return;resizePending=true;requestAnimationFrame(()=>{resizePending=false;send(\'height\',Math.ceil(document.getElementById(\'canvas\').getBoundingClientRect().height))})}).observe(document.getElementById(\'canvas\'));\n send(\'ready\');\n})();<\\/script></body></html>`;\n }\n\n // lib/components.js\n var define = (fields2, purpose, presentation = "") => Object.freeze({ fields: Object.freeze(fields2), purpose, presentation });\n var COMPONENTS = Object.freeze({\n heading: define(["text"], "Section heading", "tone"),\n text: define(["text"], "Readable explanation or bound text", "tone"),\n row: define(["children"], "Wrapping parallel content"),\n column: define(["children"], "Ordered vertical content"),\n card: define(["title", "children", "surface"], "Meaningful grouped section", "tone"),\n details: define(["title", "children", "open"], "Collapsible supporting content", "tone"),\n badge: define(["text"], "Short explicit status label", "tone"),\n progress: define(["label", "value", "max", "unit"], "Declared numeric progress snapshot", "tone"),\n steps: define(["items"], "Ordered declared steps"),\n metric: define(["label", "value", "unit", "decimals"], "Number with units, or a literal/bound status string", "tone"),\n input: define(["label", "bind"], "String or numeric state input"),\n slider: define(["label", "bind"], "Numeric state control"),\n select: define(["label", "bind"], "Selection from declared state options"),\n toggle: define(["label", "bind"], "Boolean state control"),\n button: define(["text", "action"], "Declared Agent follow-up", "icon"),\n table: define(["label", "rows", "columns"], "Supplied or derived values; inline rows or data/derived reference"),\n chart: define(["kind", "rows", "labelKey", "valueKey", "label", "unit", "xScale"], "Bar/line comparison with accessible data"),\n sandbox: define(["title", "html", "css", "script", "fallback", "height", "stateKeys", "dataKeys", "derivedKeys"], "Freeform isolated HTML/SVG/CSS/JavaScript visualization")\n });\n function componentFields(type) {\n const c = Object.hasOwn(COMPONENTS, type) ? COMPONENTS[type] : void 0;\n return c && ["id", "type", ...c.fields, ...c.presentation ? ["icon"] : [], ...c.presentation === "tone" ? ["tone"] : []];\n }\n\n // lib/identifiers.js\n var IDENTIFIER_SOURCE = "[\\\\p{L}_][\\\\p{L}\\\\p{M}\\\\p{N}_]{0,63}";\n var pattern = new RegExp(`^${IDENTIFIER_SOURCE}$`, "u");\n var validIdentifier = (value) => typeof value === "string" && pattern.test(value) && !["constructor", "prototype", "__proto__"].includes(value);\n\n // lib/author-expression.js\n function compileExpression(source) {\n const fail2 = () => {\n throw new Error("DSH UI: invalid formula; use state.x, data.x, derived.x, item.x, numbers, strings, + - * /, comparisons, ?: and min/max/round/abs");\n };\n if (typeof source !== "string" || !source.trim() || source.length > 2048) fail2();\n const tokens = [];\n let offset = 0;\n const token2 = new RegExp(String.raw`\\s*(?:(\\d+(?:\\.\\d*)?|\\.\\d+)([eE][+-]?\\d+)?|("(?:[^"\\\\]|\\\\.)*")|(${IDENTIFIER_SOURCE}(?:\\.${IDENTIFIER_SOURCE})?)|(===|!==|<=|>=|==|!=|[+*/()?,:<>-]))`, "uy");\n while (offset < source.length) {\n if (!source.slice(offset).trim()) break;\n token2.lastIndex = offset;\n const m = token2.exec(source);\n if (!m) fail2();\n offset = token2.lastIndex;\n tokens.push(m[1] ? { number: Number(m[1] + (m[2] ?? "")) } : m[3] ? { string: JSON.parse(m[3]) } : m[4] ?? m[5]);\n if (tokens.length > 256) fail2();\n }\n let pos = 0;\n const operators = { "==": ["eq", 1], "===": ["eq", 1], "!=": ["neq", 1], "!==": ["neq", 1], "<": ["lt", 2], "<=": ["lte", 2], ">": ["gt", 2], ">=": ["gte", 2], "+": ["add", 3], "-": ["sub", 3], "*": ["mul", 4], "/": ["div", 4] };\n const take = (t) => {\n if (tokens[pos++] !== t) fail2();\n };\n function parse(min = 0, depth = 0) {\n if (depth > 12) fail2();\n const t = tokens[pos++];\n let out;\n if (t && typeof t === "object") out = { const: Object.hasOwn(t, "number") ? t.number : t.string };\n else if (t === "true" || t === "false") out = { const: t === "true" };\n else if (t === "(") {\n out = parse(0, depth + 1);\n take(")");\n } else if (t === "-" || t === "+") {\n const arg = parse(5, depth + 1);\n out = t === "-" ? { op: "sub", args: [{ const: 0 }, arg] } : arg;\n } else if (typeof t === "string" && t.split(".").length === 2 && ["state", "data", "derived", "item"].includes(t.split(".")[0]) && validIdentifier(t.split(".")[1])) out = { ref: t };\n else if (["min", "max", "round", "abs"].includes(t)) {\n take("(");\n const args = [parse(0, depth + 1)];\n while (tokens[pos] === ",") {\n pos++;\n args.push(parse(0, depth + 1));\n if (args.length > 8) fail2();\n }\n take(")");\n out = { op: t, args };\n } else fail2();\n while (typeof tokens[pos] === "string" && Object.hasOwn(operators, tokens[pos]) && operators[tokens[pos]][1] >= min) {\n const [op, precedence] = operators[tokens[pos++]];\n out = { op, args: [out, parse(precedence + 1, depth + 1)] };\n }\n if (min === 0 && tokens[pos] === "?") {\n pos++;\n const yes = parse(0, depth + 1);\n take(":");\n out = { op: "if", args: [out, yes, parse(0, depth + 1)] };\n }\n return out;\n }\n const result = parse();\n if (pos !== tokens.length) fail2();\n return result;\n }\n function expandExpressions(doc2) {\n const expression = (e) => {\n if (!e || typeof e !== "object" || Array.isArray(e)) return e;\n if (Object.hasOwn(e, "expr")) {\n if (Object.keys(e).length !== 1) throw new Error("DSH UI: expr must be the only formula field");\n return compileExpression(e.expr);\n }\n if (Array.isArray(e.args)) e.args = e.args.map(expression);\n if (e.map?.fields) for (const k of Object.keys(e.map.fields)) e.map.fields[k] = expression(e.map.fields[k]);\n return e;\n };\n if (doc2.derived && typeof doc2.derived === "object") for (const k of Object.keys(doc2.derived)) doc2.derived[k] = expression(doc2.derived[k]);\n const walk = (nodes) => {\n if (!Array.isArray(nodes)) return;\n for (const node2 of nodes) {\n if (!node2 || typeof node2 !== "object") continue;\n for (const field of ["text", "value", "max", "rows"]) if (Object.hasOwn(node2, field)) node2[field] = expression(node2[field]);\n walk(node2.children);\n }\n };\n walk(doc2.nodes);\n return doc2;\n }\n\n // lib/protocol.js\n var LIMITS = Object.freeze({ bytes: 131072, nodes: 160, depth: 12, rows: 500, expressions: 128, steps: 4096 });\n var own = (o, k) => Object.hasOwn(o, k);\n var fail = (message) => {\n throw new Error(`DSH UI: ${message}`);\n };\n var object = (x) => x !== null && typeof x === "object" && !Array.isArray(x);\n var finite = (x) => typeof x === "number" && Number.isFinite(x);\n var scalar = (x) => typeof x === "string" || typeof x === "boolean" || finite(x);\n var text = (x, at) => {\n if (typeof x !== "string" || x.length > 8192) fail(`${at} must be a string of at most 8192 characters`);\n };\n function fields(value, allowed, at) {\n if (!object(value)) fail(`${at} must be an object`);\n for (const k of Object.keys(value)) if (!allowed.includes(k)) {\n const hint = at === "document" ? " Controls and visual components belong in nodes as registered typed nodes, not extra document fields." : "";\n fail(`unknown field ${at}.${k}; allowed fields at ${at}: ${allowed.join(", ")}.${hint}`);\n }\n }\n function safeJson(value, depth = 0, source = false) {\n if (depth > 48) fail("JSON nesting is too deep");\n if (value === null || typeof value === "boolean") return;\n if (typeof value === "string") {\n if (source) {\n if (value.length > SANDBOX_LIMITS.source) fail("canvas source exceeds 48 Ki characters");\n return;\n }\n return text(value, "value");\n }\n if (typeof value === "number") {\n if (!finite(value)) fail("numbers must be finite");\n return;\n }\n if (typeof value !== "object") fail("only JSON values are accepted");\n if (Array.isArray(value) && value.length > LIMITS.rows) fail("too many array items");\n for (const k of Object.keys(value)) {\n if (["__proto__", "prototype", "constructor"].includes(k)) fail("unsafe property name");\n safeJson(value[k], depth + 1, value.type === "sandbox" && ["html", "css", "script"].includes(k));\n }\n }\n function initialState(doc2) {\n return Object.fromEntries(Object.entries(doc2.state).map(([k, spec]) => [k, spec.default]));\n }\n function validateState(doc2, state2) {\n if (!object(state2) || Object.keys(state2).length !== Object.keys(doc2.state).length) fail("state keys do not match the document");\n const result = {};\n for (const [k, s] of Object.entries(doc2.state)) {\n if (!own(state2, k)) fail(`missing state.${k}`);\n const v = state2[k];\n if (s.type === "number") {\n if (!finite(v) || v < s.min || v > s.max) fail(`state.${k} is outside its numeric range`);\n const offset = (v - s.min) / s.step;\n if (Math.abs(offset - Math.round(offset)) > 1e-6) fail(`state.${k} does not match its step`);\n } else if (s.type === "json") {\n if (!object(v) && !Array.isArray(v)) fail(`state.${k} must be an array or object for type json`);\n safeJson(v);\n if (new TextEncoder().encode(JSON.stringify(v)).length > 16384) fail(`state.${k} JSON exceeds 16 KiB`);\n } else if (s.type === "string") text(v, `state.${k}`);\n else if (typeof v !== "boolean") fail(`state.${k} must be boolean`);\n if (s.options && !s.options.includes(v)) fail(`invalid option for state.${k}`);\n result[k] = v;\n }\n return result;\n }\n var ARITY = { add: [1, 8], sub: [2, 2], mul: [1, 8], div: [2, 2], min: [1, 8], max: [1, 8], round: [1, 1], abs: [1, 1], eq: [2, 2], neq: [2, 2], lt: [2, 2], lte: [2, 2], gt: [2, 2], gte: [2, 2], if: [3, 3] };\n function reference(doc2, ref) {\n if (typeof ref !== "string" || !["state", "data", "derived"].includes(ref.split(".")[0]) || ref.split(".").length !== 2 || !validIdentifier(ref.split(".")[1])) fail(`invalid reference ${JSON.stringify(ref)}; use state.key, data.key or derived.key with a letter/underscore identifier`);\n const [group, k] = ref.split(".");\n if (!own(doc2[group], k)) fail(`unknown reference ${ref}`);\n return [group, k];\n }\n function evaluate(doc2, state2) {\n const derived = {}, active = /* @__PURE__ */ new Set();\n let steps = 0, generatedRows = 0;\n const budget = () => {\n if (++steps > LIMITS.steps) fail("calculation budget exceeded");\n };\n const resolve = (ref) => {\n budget();\n const [group, k] = reference(doc2, ref);\n if (group !== "derived") return (group === "state" ? state2 : doc2.data)[k];\n if (own(derived, k)) return derived[k];\n if (active.has(k)) fail(`cyclic calculation ${k}`);\n active.add(k);\n const result2 = expression(doc2.derived[k]);\n active.delete(k);\n derived[k] = result2;\n return result2;\n };\n const expression = (e, item) => {\n budget();\n if (own(e, "map")) {\n const rows = resolve(e.map.source);\n if ((generatedRows += rows.length) > LIMITS.rows) fail("generated row limit exceeded");\n return rows.map((row) => Object.fromEntries(Object.entries(e.map.fields).map(([k, value]) => {\n const out2 = expression(value, row);\n if (!scalar(out2)) fail("generated cells must be scalar");\n return [k, out2];\n })));\n }\n if (own(e, "const")) return e.const;\n if (own(e, "ref")) {\n if (e.ref.startsWith("item.")) {\n const k = e.ref.slice(5);\n if (!item || !own(item, k) || !scalar(item[k])) fail("invalid item reference");\n return item[k];\n }\n return resolve(e.ref);\n }\n if (e.op === "if") {\n const condition = expression(e.args[0], item);\n if (typeof condition !== "boolean") fail("if condition must be boolean");\n return expression(e.args[condition ? 1 : 2], item);\n }\n const a = e.args.map((arg) => expression(arg, item));\n if (e.op === "eq") return a[0] === a[1];\n if (e.op === "neq") return a[0] !== a[1];\n if (!a.every(finite)) fail(`operator ${e.op} requires finite numbers`);\n let out;\n switch (e.op) {\n case "add":\n out = a.reduce((x, y) => x + y, 0);\n break;\n case "sub":\n out = a[0] - a[1];\n break;\n case "mul":\n out = a.reduce((x, y) => x * y, 1);\n break;\n case "div":\n if (a[1] === 0) fail("division by zero");\n out = a[0] / a[1];\n break;\n case "min":\n out = Math.min(...a);\n break;\n case "max":\n out = Math.max(...a);\n break;\n case "round":\n out = Math.round(a[0]);\n break;\n case "abs":\n out = Math.abs(a[0]);\n break;\n case "lt":\n return a[0] < a[1];\n case "lte":\n return a[0] <= a[1];\n case "gt":\n return a[0] > a[1];\n case "gte":\n return a[0] >= a[1];\n default:\n fail(`unsupported operator ${e.op}`);\n }\n if (!finite(out)) fail("non-finite calculation result");\n return out;\n };\n for (const k of Object.keys(doc2.derived)) resolve(`derived.${k}`);\n if (new TextEncoder().encode(JSON.stringify(derived)).length > LIMITS.bytes) fail("derived output exceeds 128 KiB");\n const result = { derived, resolveValue: (value) => {\n if (!object(value)) return value;\n return expression(value);\n } };\n checkViewValues(doc2, result);\n return result;\n }\n function checkViewValues(doc2, evaluated) {\n function walk(list) {\n for (const n of list) {\n if (n.type === "table" || n.type === "chart") {\n const rows = evaluated.resolveValue(n.rows);\n if (!Array.isArray(rows) || rows.length > LIMITS.rows || !rows.every(object)) fail("table/chart rows must reference an array of objects");\n if (n.type === "chart" && rows.some((r) => !own(r, n.labelKey) || !scalar(r[n.labelKey]) || !own(r, n.valueKey) || !finite(r[n.valueKey]))) fail("chart requires labels and finite numeric values");\n if (n.type === "chart" && n.xScale === "linear" && rows.some((r) => !finite(r[n.labelKey]))) fail("linear chart requires numeric x values");\n }\n if (n.type === "metric" && !scalar(evaluated.resolveValue(n.value))) fail(`node.${n.id}.value must resolve to a number, string or boolean; use table for rows or a canvas for structured data`);\n if (n.type === "progress") {\n const v = evaluated.resolveValue(n.value), max = evaluated.resolveValue(n.max);\n if (!finite(v) || !finite(max) || max <= 0 || v < 0 || v > max) fail("progress requires 0 <= value <= positive max");\n }\n if (n.children) walk(n.children);\n }\n }\n walk(doc2.nodes);\n }\n function validateDocument(input) {\n safeJson(input);\n const json = JSON.stringify(input);\n if (new TextEncoder().encode(json).length > LIMITS.bytes) fail("document exceeds 128 KiB");\n const doc2 = expandExpressions(JSON.parse(json));\n fields(doc2, ["version", "title", "fallback", "state", "data", "derived", "nodes", "actions", "presentation"], "document");\n if (doc2.presentation !== void 0) {\n fields(doc2.presentation, ["layout", "accent", "density"], "presentation");\n for (const [k, allowed] of Object.entries({ layout: UI_LAYOUTS, accent: UI_ACCENTS, density: ["comfortable", "compact"] }))\n if (doc2.presentation[k] !== void 0 && !allowed.includes(doc2.presentation[k])) fail(`unknown presentation ${k}`);\n }\n if (doc2.version !== 1) fail("unsupported protocol version");\n text(doc2.title, "title");\n text(doc2.fallback, "fallback");\n if (!doc2.title.trim() || !doc2.fallback.trim()) fail("title and fallback cannot be empty");\n for (const group of ["state", "data", "derived", "actions"]) {\n doc2[group] ??= {};\n if (!object(doc2[group]) || Object.keys(doc2[group]).length > 64) fail(`invalid ${group}`);\n for (const k of Object.keys(doc2[group])) if (!validIdentifier(k)) fail(`invalid key in ${group}: ${JSON.stringify(k)}; use 1..64 letters, numbers or underscores, starting with a letter/underscore (Chinese letters supported); no spaces, dots or hyphens. Put display labels in label/text`);\n }\n for (const [k, s] of Object.entries(doc2.state)) {\n fields(s, ["type", "default", "min", "max", "step", "options"], `state.${k}`);\n if (s.type === "string" && (Array.isArray(s.default) || object(s.default)) && !own(s, "options")) s.type = "json";\n if (!["number", "string", "boolean", "json"].includes(s.type)) fail(`unsupported state type ${k}; use number, string, boolean or json (arrays/objects)`);\n if (s.type === "json" && own(s, "options")) fail(`state.${k}: json state does not support select options; use scalar options or a canvas`);\n if (s.type === "number") {\n if (![s.min, s.max, s.step].every(finite) || s.min >= s.max || s.step <= 0) fail(`invalid numeric limits for ${k}`);\n if ((s.max - s.min) / s.step > 1e9) fail(`numeric step too small for ${k}`);\n } else if (["min", "max", "step"].some((p) => own(s, p))) fail(`numeric limits on non-number ${k}`);\n if (s.options && (!Array.isArray(s.options) || !s.options.length || s.options.length > 64 || !s.options.every(scalar))) fail(`invalid options for ${k}`);\n }\n const defaults = validateState(doc2, initialState(doc2));\n let expressions = 0;\n for (const [k, spec] of Object.entries(doc2.state))\n for (const option of spec.options ?? []) validateState(doc2, { ...defaults, [k]: option });\n function validateExpression(e, depth = 0, itemRows) {\n if (++expressions > LIMITS.expressions || depth > LIMITS.depth) fail("expression limit exceeded");\n if (!object(e)) fail("expression must be an object");\n if (own(e, "map")) {\n if (depth !== 0) fail("map is only allowed at the root of a derived value");\n fields(e, ["map"], "expression");\n fields(e.map, ["source", "fields"], "map");\n if (typeof e.map.source !== "string" || !e.map.source.startsWith("data.")) fail(\'map source must reference static data using a string such as "data.samples"; put object rows in document.data.samples, not inline in map.source\');\n const [, k] = reference(doc2, e.map.source), rows = doc2.data[k];\n if (!Array.isArray(rows) || rows.length > LIMITS.rows || !rows.every(object)) fail("map source must be object rows");\n if (!object(e.map.fields) || !Object.keys(e.map.fields).length || Object.keys(e.map.fields).length > 16) fail("map requires 1..16 fields");\n for (const [k2, value2] of Object.entries(e.map.fields)) {\n if (!validIdentifier(k2)) fail(`invalid map field ${JSON.stringify(k2).slice(0, 100)}; use a letter/underscore identifier such as powerW or \\u529F\\u7387, without spaces, dots or hyphens`);\n validateExpression(value2, depth + 1, rows);\n }\n return;\n }\n if (own(e, "const")) {\n fields(e, ["const"], "expression");\n if (!scalar(e.const)) fail("constant must be scalar");\n return;\n }\n if (own(e, "ref")) {\n fields(e, ["ref"], "expression");\n if (typeof e.ref === "string" && e.ref.startsWith("item.")) {\n const k = e.ref.slice(5);\n if (!itemRows || !validIdentifier(k) || itemRows.some((row) => !own(row, k) || !scalar(row[k]))) fail("invalid or unscoped item reference");\n } else reference(doc2, e.ref);\n return;\n }\n fields(e, ["op", "args"], "expression");\n const arity = ARITY[e.op];\n if (!arity || !Array.isArray(e.args) || e.args.length < arity[0] || e.args.length > arity[1]) fail("invalid operator or argument count");\n e.args.forEach((a) => validateExpression(a, depth + 1, itemRows));\n }\n Object.values(doc2.derived).forEach((e) => validateExpression(e));\n const visited = /* @__PURE__ */ new Set(), active = /* @__PURE__ */ new Set();\n function visit(k) {\n if (active.has(k)) fail(`cyclic calculation ${k}`);\n if (visited.has(k)) return;\n active.add(k);\n function walk(e) {\n if (e.ref?.startsWith("derived.")) visit(e.ref.split(".")[1]);\n for (const a of e.args ?? []) walk(a);\n for (const value2 of Object.values(e.map?.fields ?? {})) walk(value2);\n }\n walk(doc2.derived[k]);\n active.delete(k);\n visited.add(k);\n }\n Object.keys(doc2.derived).forEach(visit);\n for (const [k, a] of Object.entries(doc2.actions)) {\n fields(a, ["type", "intent", "stateKeys"], `actions.${k}`);\n if (a.type !== "agent.followup") fail("only agent.followup actions are supported");\n text(a.intent, "action intent");\n if (!a.intent.trim() || !Array.isArray(a.stateKeys) || a.stateKeys.length > 64 || new Set(a.stateKeys).size !== a.stateKeys.length || a.stateKeys.some((s) => !own(doc2.state, s))) fail("invalid action stateKeys");\n }\n const ids = /* @__PURE__ */ new Set();\n let count2 = 0;\n const value = (v, at) => {\n if (object(v)) {\n if (own(v, "map")) fail("map belongs in derived");\n validateExpression(v);\n } else if (!scalar(v)) fail(`invalid value at ${at}`);\n };\n function nodes(list, depth = 0) {\n if (!Array.isArray(list) || depth > LIMITS.depth) fail("invalid node children or depth");\n for (const n of list) {\n if (++count2 > LIMITS.nodes) fail("too many nodes");\n if (!object(n) || !validIdentifier(n.id) || ids.has(n.id)) fail("node ids must be unique identifiers");\n ids.add(n.id);\n if (!Object.hasOwn(COMPONENTS, n.type)) fail("unsupported component " + n.type);\n if (["table", "chart"].includes(n.type) && typeof n.rows === "string" && /^(data|derived)\\./.test(n.rows)) n.rows = { ref: n.rows };\n switch (n.type) {\n case "sandbox": {\n text(n.title, "canvas title");\n text(n.fallback, "canvas fallback");\n if (!n.title.trim() || !n.fallback.trim() || typeof n.html !== "string" || !n.html.trim()) fail("canvas requires title, HTML and fallback");\n for (const field of ["html", "css", "script"]) if (n[field] !== void 0 && (typeof n[field] !== "string" || n[field].length > SANDBOX_LIMITS.source)) fail("canvas source exceeds 48 Ki characters");\n if (n.height !== void 0 && (!Number.isInteger(n.height) || n.height < 160 || n.height > SANDBOX_LIMITS.height)) fail("canvas height must be 160..1000");\n for (const [field, group] of [["stateKeys", "state"], ["dataKeys", "data"], ["derivedKeys", "derived"]]) if (n[field] !== void 0 && (!Array.isArray(n[field]) || n[field].length > 64 || new Set(n[field]).size !== n[field].length || n[field].some((k) => !own(doc2[group], k)))) fail("invalid canvas " + field);\n break;\n }\n case "row":\n case "column":\n break;\n case "card":\n if (n.title !== void 0) text(n.title, "card title");\n if (n.surface !== void 0 && !UI_SURFACES.includes(n.surface)) fail("unknown card surface");\n break;\n case "details":\n text(n.title, "details title");\n if (n.open !== void 0 && typeof n.open !== "boolean") fail("details open must be boolean");\n break;\n case "badge":\n value(n.text, "badge text");\n break;\n case "progress":\n text(n.label, "progress label");\n value(n.value, "progress value");\n value(n.max, "progress max");\n if (n.unit !== void 0) text(n.unit, "progress unit");\n break;\n case "steps": {\n if (!Array.isArray(n.items) || !n.items.length || n.items.length > 12) fail("steps require 1..12 items");\n for (const item of n.items) {\n fields(item, ["title", "description", "status"], "step");\n text(item.title, "step title");\n if (item.description !== void 0) text(item.description, "step description");\n if (!["pending", "active", "done", "error"].includes(item.status)) fail("unknown step status");\n }\n break;\n }\n case "heading":\n case "text":\n value(n.text, "text");\n break;\n case "metric":\n text(n.label, "metric label");\n value(n.value, "metric value");\n if (n.unit !== void 0) text(n.unit, "unit");\n if (n.decimals !== void 0 && (!Number.isInteger(n.decimals) || n.decimals < 0 || n.decimals > 6)) fail("invalid decimals");\n break;\n case "input":\n case "slider":\n case "select":\n case "toggle": {\n text(n.label, "control label");\n if (typeof n.bind !== "string" || !n.bind.startsWith("state.")) fail("controls must bind state");\n const [, k] = reference(doc2, n.bind), spec = doc2.state[k];\n if (n.type === "slider" && spec.type !== "number") fail("slider requires numeric state");\n if (n.type === "toggle" && spec.type !== "boolean") fail("toggle requires boolean state");\n if (["input", "select"].includes(n.type) && spec.type === "json") fail(`node.${n.id}: structured state requires a sandbox with DSHUI.setState; use separate boolean states and toggle nodes for a native checklist`);\n if (n.type === "input" && spec.type === "boolean") fail("use toggle for boolean state");\n if (n.type === "select" && !spec.options) fail("select requires options");\n break;\n }\n case "button":\n text(n.text, "button text");\n if (!own(doc2.actions, n.action)) fail("unknown action");\n break;\n case "table": {\n if (n.label !== void 0) text(n.label, "table label");\n if (!Array.isArray(n.rows)) value(n.rows, "table rows");\n if (!Array.isArray(n.columns) || !n.columns.length || n.columns.length > 16) fail("invalid table columns");\n const cols = /* @__PURE__ */ new Set();\n for (const c of n.columns) {\n fields(c, ["key", "label", "unit"], "column");\n if (!validIdentifier(c.key) || cols.has(c.key)) fail("invalid or duplicate column key");\n cols.add(c.key);\n text(c.label, "column label");\n if (c.unit !== void 0) text(c.unit, "column unit");\n }\n break;\n }\n case "chart":\n if (!Array.isArray(n.rows)) value(n.rows, "chart rows");\n if (!["bar", "line"].includes(n.kind) || !validIdentifier(n.labelKey) || !validIdentifier(n.valueKey)) fail("invalid chart");\n text(n.label, "chart label");\n if (n.unit !== void 0) text(n.unit, "chart unit");\n if (n.xScale !== void 0 && (!["category", "linear"].includes(n.xScale) || n.xScale === "linear" && n.kind !== "line")) fail("invalid xScale");\n break;\n default:\n fail(`unsupported component ${n.type}`);\n }\n if (["heading", "text", "card", "metric", "button", "badge", "progress", "details"].includes(n.type)) {\n if (n.icon !== void 0 && !UI_ICONS.includes(n.icon)) fail("unknown UI icon");\n if (n.type !== "button") {\n if (n.tone !== void 0 && !UI_TONES.includes(n.tone)) fail("unknown UI tone");\n }\n }\n fields(n, componentFields(n.type), `node.${n.id}`);\n if (["row", "column", "card", "details"].includes(n.type)) nodes(n.children, depth + 1);\n }\n }\n nodes(doc2.nodes);\n if (!count2) fail("at least one node is required");\n evaluate(doc2, defaults);\n return doc2;\n }\n\n // src/export-runtime.js\n var payload = JSON.parse(document.getElementById("dsh-ui-export").textContent);\n var doc = validateDocument(payload.document);\n var node = doc.nodes.flatMap(function flatten(n) {\n return [n, ...(n.children ?? []).flatMap(flatten)];\n }).find((n) => n.id === payload.nodeId && n.type === "sandbox");\n if (!node) throw Error("\\u5BFC\\u51FA\\u7684\\u753B\\u5E03\\u4E0D\\u5B58\\u5728");\n var state = validateState(doc, payload.state);\n var connected = false;\n var start = Date.now();\n var count = 0;\n var token = () => Array.from(crypto.getRandomValues(new Uint8Array(16)), (b) => b.toString(16).padStart(2, "0")).join("");\n var channel = token();\n var nonce = payload.nonce;\n var frame = document.createElement("iframe");\n frame.title = node.title;\n frame.sandbox = "allow-scripts";\n frame.referrerPolicy = "no-referrer";\n frame.style.cssText = "display:block;width:100%;height:" + (node.height ?? 420) + "px;border:0";\n var status = document.getElementById("status");\n var publish = () => {\n try {\n frame.contentWindow.postMessage({ dshCanvas: 1, channel, type: "snapshot", payload: { ...canvasSnapshot(node, state, doc.data, evaluate(doc, state).derived, false, payload.theme), visible: !document.hidden } }, "*");\n } catch (e) {\n status.textContent = "\\u8BA1\\u7B97\\u5931\\u8D25\\uFF1A" + e.message;\n }\n };\n addEventListener("message", (event) => {\n const m = event.data;\n if (event.source !== frame.contentWindow || m?.channel !== channel || m.dshCanvas !== 1) return;\n if (Date.now() - start > 1e3) {\n start = Date.now();\n count = 0;\n }\n if (++count > SANDBOX_LIMITS.rate) return;\n if (m.type === "ready") {\n connected = true;\n publish();\n } else if (m.type === "patch" && connected) {\n try {\n const next = validateState(doc, { ...state, ...canvasPatch(m.payload, node) });\n evaluate(doc, next);\n state = next;\n status.textContent = "\\u672C\\u5730\\u53C2\\u6570\\u5DF2\\u66F4\\u65B0\\uFF1B\\u5237\\u65B0\\u6587\\u4EF6\\u4F1A\\u56DE\\u5230\\u5BFC\\u51FA\\u65F6\\u7684\\u53C2\\u6570\\u3002";\n } catch (e) {\n status.textContent = "\\u53C2\\u6570\\u65E0\\u6548\\uFF1A" + e.message;\n }\n publish();\n } else if (m.type === "height" && Number.isFinite(m.payload) && m.payload >= 0) frame.style.height = Math.max(32, Math.min(1e3, Math.ceil(m.payload))) + "px";\n else if (m.type === "error") status.textContent = "\\u753B\\u5E03\\u8FD0\\u884C\\u5F02\\u5E38\\uFF1A" + String(m.payload).slice(0, 1e3);\n });\n document.addEventListener("visibilitychange", () => {\n if (connected) publish();\n });\n document.getElementById("surface").append(frame);\n frame.srcdoc = sandboxDocument(node, channel, nonce);\n})();\n';
|
|
22739
22795
|
|
|
22740
22796
|
// lib/canvas-export.js
|
|
22741
22797
|
function standaloneCanvas(document2, node, state, theme = {}) {
|
|
@@ -22746,18 +22802,64 @@ function standaloneCanvas(document2, node, state, theme = {}) {
|
|
|
22746
22802
|
return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta http-equiv="Content-Security-Policy" content="default-src 'none';script-src 'nonce-${token}';style-src 'unsafe-inline';frame-src 'self';base-uri 'none';form-action 'none'"><title>${escape(node.title)}</title><style>body{margin:0;padding:24px;background:${theme.scheme === "dark" ? "#161b23" : "#f4f6fa"};color:${theme.scheme === "dark" ? "#e6edf6" : "#182537"};font:14px/1.6 system-ui,sans-serif}main{max-width:1100px;margin:auto}h1{font-size:22px}p{overflow-wrap:anywhere}#surface{background:${theme.scheme === "dark" ? "#161b23" : "#fff"};border-radius:12px;overflow:hidden}#status{min-height:1.6em}</style></head><body><main><h1>${escape(node.title)}</h1><p>DSH Motion UI \xB7 \u72EC\u7ACB\u526F\u672C\u3002\u5305\u542B\u5BFC\u51FA\u65F6\u53C2\u6570\uFF0C\u672C\u5730\u4EA4\u4E92\u4E0D\u4F1A\u4FDD\u5B58\u5230 DSH\uFF0C\u4E5F\u4E0D\u4F1A\u8C03\u7528 Agent\u3002</p><div id="surface"></div><p id="status" role="status"></p><details><summary>\u6587\u5B57\u8BF4\u660E</summary><p>${escape(node.fallback)}</p></details></main><script type="application/json" id="dsh-ui-export">${json}<\/script><script nonce="${token}">${EXPORT_RUNTIME.replace(/<\/script/gi, "<\\/script")}<\/script></body></html>`;
|
|
22747
22803
|
}
|
|
22748
22804
|
|
|
22805
|
+
// src/view-settings.js
|
|
22806
|
+
var import_react4 = require("react");
|
|
22807
|
+
var scope;
|
|
22808
|
+
function configureViewSettings(value) {
|
|
22809
|
+
scope = value;
|
|
22810
|
+
}
|
|
22811
|
+
var subscribe = (fn) => scope?.subscribe(fn) ?? (() => {
|
|
22812
|
+
});
|
|
22813
|
+
var snapshot = () => scope?.getSnapshot()?.value?.showDetails === true;
|
|
22814
|
+
function useViewDetails() {
|
|
22815
|
+
return (0, import_react4.useSyncExternalStore)(subscribe, snapshot, () => false);
|
|
22816
|
+
}
|
|
22817
|
+
|
|
22818
|
+
// src/action-menu.js
|
|
22819
|
+
var import_react5 = __toESM(require("react"), 1);
|
|
22820
|
+
function ActionMenu({ label, children }) {
|
|
22821
|
+
const [open, setOpen] = (0, import_react5.useState)(false), root = (0, import_react5.useRef)(null), button = (0, import_react5.useRef)(null);
|
|
22822
|
+
(0, import_react5.useEffect)(() => {
|
|
22823
|
+
if (!open) return;
|
|
22824
|
+
const outside = (e) => {
|
|
22825
|
+
if (!root.current?.contains(e.target)) setOpen(false);
|
|
22826
|
+
};
|
|
22827
|
+
const escape = (e) => {
|
|
22828
|
+
if (e.key === "Escape") {
|
|
22829
|
+
setOpen(false);
|
|
22830
|
+
button.current?.focus();
|
|
22831
|
+
}
|
|
22832
|
+
};
|
|
22833
|
+
document.addEventListener("pointerdown", outside);
|
|
22834
|
+
document.addEventListener("keydown", escape);
|
|
22835
|
+
return () => {
|
|
22836
|
+
document.removeEventListener("pointerdown", outside);
|
|
22837
|
+
document.removeEventListener("keydown", escape);
|
|
22838
|
+
};
|
|
22839
|
+
}, [open]);
|
|
22840
|
+
return import_react5.default.createElement(
|
|
22841
|
+
"div",
|
|
22842
|
+
{ className: "dgui-action-menu", ref: root },
|
|
22843
|
+
import_react5.default.createElement("button", { ref: button, type: "button", className: "dgui-menu-trigger", "aria-label": label, "aria-expanded": open, onClick: () => setOpen(!open) }, "\u22EF"),
|
|
22844
|
+
open && import_react5.default.createElement("div", { className: "dgui-menu-content", "aria-label": label, onClick: (e) => {
|
|
22845
|
+
if (e.target.closest("button")) setOpen(false);
|
|
22846
|
+
} }, children)
|
|
22847
|
+
);
|
|
22848
|
+
}
|
|
22849
|
+
|
|
22749
22850
|
// src/sandbox.js
|
|
22750
|
-
var h3 =
|
|
22851
|
+
var h3 = import_react6.default.createElement;
|
|
22751
22852
|
var randomToken = () => Array.from(crypto.getRandomValues(new Uint8Array(16)), (b) => b.toString(16).padStart(2, "0")).join("");
|
|
22752
22853
|
function Sandbox({ node, document: doc, state, data, derived, disabled, preview, update, onAudit }) {
|
|
22753
|
-
const
|
|
22754
|
-
const
|
|
22755
|
-
const [
|
|
22756
|
-
const [
|
|
22757
|
-
const [
|
|
22854
|
+
const showDetails = useViewDetails();
|
|
22855
|
+
const frame = (0, import_react6.useRef)(null), latest = (0, import_react6.useRef)(null), connected = (0, import_react6.useRef)(false), loads = (0, import_react6.useRef)(0), visible = (0, import_react6.useRef)(true), errorKind = (0, import_react6.useRef)("");
|
|
22856
|
+
const [error, setError] = (0, import_react6.useState)(""), [stopped, setStopped] = (0, import_react6.useState)(false), [generation, setGeneration] = (0, import_react6.useState)(0);
|
|
22857
|
+
const [height, setHeight] = (0, import_react6.useState)(node.height ?? 420);
|
|
22858
|
+
const [token, setToken] = (0, import_react6.useState)(0);
|
|
22859
|
+
const [mounted, setMounted] = (0, import_react6.useState)(false);
|
|
22758
22860
|
const sourceKey = JSON.stringify(node);
|
|
22759
|
-
const config = (0,
|
|
22760
|
-
const srcDoc = (0,
|
|
22861
|
+
const config = (0, import_react6.useMemo)(() => ({ channel: randomToken(), nonce: randomToken() }), [sourceKey, generation]);
|
|
22862
|
+
const srcDoc = (0, import_react6.useMemo)(() => sandboxDocument(node, config.channel, config.nonce), [sourceKey, config]);
|
|
22761
22863
|
latest.current = { node, state, data, derived, disabled, update, onAudit };
|
|
22762
22864
|
const publish = () => {
|
|
22763
22865
|
const el = frame.current, current2 = latest.current;
|
|
@@ -22767,7 +22869,7 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
|
|
|
22767
22869
|
theme.scheme = document.body.hasAttribute("data-ds-dark-theme") || el.closest("[data-preview-theme=dark]") ? "dark" : "light";
|
|
22768
22870
|
el.contentWindow?.postMessage({ dshCanvas: 1, channel: config.channel, type: "snapshot", payload: { ...canvasSnapshot(current2.node, current2.state, current2.data, current2.derived, current2.disabled, theme), visible: visible.current && !document.hidden } }, "*");
|
|
22769
22871
|
};
|
|
22770
|
-
(0,
|
|
22872
|
+
(0, import_react6.useEffect)(() => {
|
|
22771
22873
|
if (preview || stopped) return;
|
|
22772
22874
|
connected.current = false;
|
|
22773
22875
|
loads.current = 0;
|
|
@@ -22795,7 +22897,7 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
|
|
|
22795
22897
|
setToken((t) => t + 1);
|
|
22796
22898
|
} else if (m.type === "mounted" && connected.current) setMounted(true);
|
|
22797
22899
|
else if (m.type === "audit" && connected.current) latest.current.onAudit?.(node.id, m.payload?.issues, m.payload?.coverage);
|
|
22798
|
-
else if (m.type === "height" && connected.current && Number.isFinite(m.payload) && m.payload
|
|
22900
|
+
else if (m.type === "height" && connected.current && Number.isFinite(m.payload) && m.payload >= 0) setHeight(Math.max(32, Math.min(SANDBOX_LIMITS.height, Math.ceil(m.payload))));
|
|
22799
22901
|
else if (m.type === "error") {
|
|
22800
22902
|
errorKind.current = "runtime";
|
|
22801
22903
|
setError(typeof m.payload === "string" ? m.payload.slice(0, 1e3) : "\u753B\u5E03\u8FD0\u884C\u5F02\u5E38");
|
|
@@ -22841,7 +22943,7 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
|
|
|
22841
22943
|
intersection.disconnect();
|
|
22842
22944
|
};
|
|
22843
22945
|
}, [config, preview, stopped]);
|
|
22844
|
-
(0,
|
|
22946
|
+
(0, import_react6.useEffect)(() => {
|
|
22845
22947
|
publish();
|
|
22846
22948
|
}, [state, data, derived, disabled, config, token]);
|
|
22847
22949
|
const inactive = preview || stopped;
|
|
@@ -22867,6 +22969,13 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
|
|
|
22867
22969
|
return h3(
|
|
22868
22970
|
"section",
|
|
22869
22971
|
{ className: "dgui-canvas", "data-ui-node": node.id, "data-canvas-phase": inactive ? stopped ? "stopped" : "preview" : error ? "error" : mounted ? "ready" : "loading", "aria-label": node.title },
|
|
22972
|
+
!preview && !showDetails && h3(
|
|
22973
|
+
ActionMenu,
|
|
22974
|
+
{ label: `${node.title}\u64CD\u4F5C` },
|
|
22975
|
+
h3("button", { type: "button", disabled: disabled || !doc || stopped, onClick: download }, "\u5BFC\u51FA\u72EC\u7ACB HTML"),
|
|
22976
|
+
h3("button", { type: "button", disabled, onClick: restart }, stopped ? "\u6062\u590D\u4EA4\u4E92" : "\u91CD\u7F6E\u753B\u5E03"),
|
|
22977
|
+
!stopped && h3("button", { type: "button", onClick: () => setStopped(true) }, "\u505C\u6B62\u753B\u5E03")
|
|
22978
|
+
),
|
|
22870
22979
|
preview ? h3(CanvasPreview, { node }) : inactive ? h3("div", { className: "dgui-canvas-placeholder", role: "status" }, h3("p", null, "\u753B\u5E03\u5DF2\u505C\u6B62\u3002"), stopped && h3("button", { type: "button", className: "dgui-secondary", onClick: restart }, "\u6062\u590D\u4EA4\u4E92")) : h3(
|
|
22871
22980
|
"div",
|
|
22872
22981
|
{ className: "dgui-canvas-stage", style: { minHeight: mounted || error ? void 0 : Math.min(height, 420) } },
|
|
@@ -22879,7 +22988,8 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
|
|
|
22879
22988
|
}, style: { width: "100%", height, border: 0, display: "block", visibility: mounted || error ? "visible" : "hidden" }, allow: "camera 'none'; microphone 'none'; geolocation 'none'; clipboard-read 'none'; clipboard-write 'none'" })
|
|
22880
22989
|
),
|
|
22881
22990
|
error && h3("div", { className: "dgui-canvas-issue", role: "alert" }, h3("strong", null, "\u4EA4\u4E92\u9047\u5230\u95EE\u9898"), h3("p", null, "\u53EF\u4EE5\u91CD\u65B0\u8F7D\u5165\uFF1B\u5DF2\u4FDD\u5B58\u7684\u53C2\u6570\u4F1A\u4FDD\u7559\u3002"), h3("div", { className: "dgui-recovery" }, h3("button", { type: "button", className: "dgui-secondary", onClick: restart }, "\u91CD\u7F6E\u753B\u5E03"), !stopped && h3("button", { type: "button", className: "dgui-secondary", onClick: () => setStopped(true) }, "\u505C\u6B62\u753B\u5E03")), h3("details", null, h3("summary", null, "\u9519\u8BEF\u8BE6\u60C5"), h3("pre", null, error))),
|
|
22882
|
-
h3(
|
|
22991
|
+
error && !showDetails && h3("p", { className: "dgui-error" }, node.fallback),
|
|
22992
|
+
showDetails && h3(
|
|
22883
22993
|
"details",
|
|
22884
22994
|
{ className: "dgui-canvas-options" },
|
|
22885
22995
|
h3("summary", null, "\u8BF4\u660E\u4E0E\u64CD\u4F5C"),
|
|
@@ -22891,13 +23001,13 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
|
|
|
22891
23001
|
}
|
|
22892
23002
|
|
|
22893
23003
|
// lib/build-info.js
|
|
22894
|
-
var BUILD_INFO = Object.freeze({ "version": "0.5.
|
|
23004
|
+
var BUILD_INFO = Object.freeze({ "version": "0.5.4", "id": "0.5.4+92e88973eabc", "sourceHash": "92e88973eabc736e169fbb03366db183ca5cd1fbbe0e3a7e44e5742da708d96e" });
|
|
22895
23005
|
|
|
22896
23006
|
// lib/refinement.js
|
|
22897
23007
|
var AUDIT_MESSAGES = Object.freeze({ overflow: "\u5185\u5BB9\u8D85\u51FA\u89C6\u53E3\u5BBD\u5EA6", smallText: "\u6587\u5B57\u5B9E\u9645\u663E\u793A\u5C3A\u5BF8\u5C0F\u4E8E 12px", contrast: "\u6587\u5B57\u4E0E\u80CC\u666F\u5BF9\u6BD4\u5EA6\u504F\u4F4E", missingLabel: "\u4EA4\u4E92\u63A7\u4EF6\u7F3A\u5C11\u53EF\u8BBF\u95EE\u540D\u79F0", runtimeError: "\u753B\u5E03\u62A5\u544A\u8FD0\u884C\u5F02\u5E38" });
|
|
22898
23008
|
|
|
22899
23009
|
// src/current-document.js
|
|
22900
|
-
var
|
|
23010
|
+
var import_react7 = require("react");
|
|
22901
23011
|
var current = /* @__PURE__ */ new Map();
|
|
22902
23012
|
var listeners2 = /* @__PURE__ */ new Set();
|
|
22903
23013
|
function publishDocument(raw) {
|
|
@@ -22908,9 +23018,9 @@ function publishDocument(raw) {
|
|
|
22908
23018
|
listeners2.forEach((fn) => fn());
|
|
22909
23019
|
}
|
|
22910
23020
|
function useCurrentDocument(raw, sessionId) {
|
|
22911
|
-
const [, wake] = (0,
|
|
22912
|
-
const [attempt, retry] = (0,
|
|
22913
|
-
(0,
|
|
23021
|
+
const [, wake] = (0, import_react7.useState)(0);
|
|
23022
|
+
const [attempt, retry] = (0, import_react7.useState)(0), [load, setLoad] = (0, import_react7.useState)({ status: "loading" });
|
|
23023
|
+
(0, import_react7.useEffect)(() => {
|
|
22914
23024
|
if (!raw.documentId || !sessionId) return;
|
|
22915
23025
|
const notify = () => wake((v) => v + 1);
|
|
22916
23026
|
listeners2.add(notify);
|
|
@@ -22936,10 +23046,10 @@ function useCurrentDocument(raw, sessionId) {
|
|
|
22936
23046
|
}
|
|
22937
23047
|
|
|
22938
23048
|
// src/history-view.js
|
|
22939
|
-
var
|
|
22940
|
-
var h4 =
|
|
23049
|
+
var import_react8 = __toESM(require("react"), 1);
|
|
23050
|
+
var h4 = import_react8.default.createElement;
|
|
22941
23051
|
function HistoryView({ record, sessionId }) {
|
|
22942
|
-
const [versions, setVersions] = (0,
|
|
23052
|
+
const [versions, setVersions] = (0, import_react8.useState)(null), [error, setError] = (0, import_react8.useState)(""), [busy, setBusy] = (0, import_react8.useState)(false), [preview, setPreview] = (0, import_react8.useState)(null);
|
|
22943
23053
|
const url = "/api/plugins/dsh-generative-ui/history?" + new URLSearchParams({ documentId: record.documentId, sessionId });
|
|
22944
23054
|
async function request2(options) {
|
|
22945
23055
|
const r = await fetch(url, { credentials: "same-origin", ...options }), value = await r.json();
|
|
@@ -23006,11 +23116,11 @@ function HistoryView({ record, sessionId }) {
|
|
|
23006
23116
|
}
|
|
23007
23117
|
|
|
23008
23118
|
// src/presentation.js
|
|
23009
|
-
var
|
|
23119
|
+
var import_react11 = __toESM(require("react"), 1);
|
|
23010
23120
|
var import_react_dom = __toESM(require_react_dom(), 1);
|
|
23011
23121
|
|
|
23012
23122
|
// src/presentation-store.js
|
|
23013
|
-
var
|
|
23123
|
+
var import_react9 = require("react");
|
|
23014
23124
|
var records = /* @__PURE__ */ new Map();
|
|
23015
23125
|
var listeners3 = /* @__PURE__ */ new Set();
|
|
23016
23126
|
var locations = /* @__PURE__ */ new Map();
|
|
@@ -23035,7 +23145,7 @@ var subscribeUi = (fn) => {
|
|
|
23035
23145
|
return () => listeners3.delete(fn);
|
|
23036
23146
|
};
|
|
23037
23147
|
function useUiRegistry() {
|
|
23038
|
-
(0,
|
|
23148
|
+
(0, import_react9.useSyncExternalStore)(subscribeUi, () => revision, () => 0);
|
|
23039
23149
|
return uiRecords();
|
|
23040
23150
|
}
|
|
23041
23151
|
function setPanelOpener(fn) {
|
|
@@ -23063,10 +23173,10 @@ function removeMarkerLocation(id, host) {
|
|
|
23063
23173
|
}
|
|
23064
23174
|
}
|
|
23065
23175
|
var markerLocation = (id) => locations.get(id);
|
|
23066
|
-
function usePresentation(
|
|
23067
|
-
const [, wake] = (0,
|
|
23068
|
-
(0,
|
|
23069
|
-
return
|
|
23176
|
+
function usePresentation(scope2) {
|
|
23177
|
+
const [, wake] = (0, import_react9.useState)(0);
|
|
23178
|
+
(0, import_react9.useEffect)(() => scope2?.subscribe(() => wake((v) => v + 1)), [scope2]);
|
|
23179
|
+
return scope2?.getSnapshot().value?.displayMode ?? "tail";
|
|
23070
23180
|
}
|
|
23071
23181
|
|
|
23072
23182
|
// src/markers.js
|
|
@@ -23127,11 +23237,11 @@ function startUiMarkers(root, sessionId) {
|
|
|
23127
23237
|
}
|
|
23128
23238
|
|
|
23129
23239
|
// src/presentation-owner.js
|
|
23130
|
-
var
|
|
23240
|
+
var import_react10 = require("react");
|
|
23131
23241
|
var roots = /* @__PURE__ */ new WeakMap();
|
|
23132
23242
|
function usePresentationOwner(anchor, documentId, sessionId) {
|
|
23133
|
-
const [owner, setOwner] = (0,
|
|
23134
|
-
(0,
|
|
23243
|
+
const [owner, setOwner] = (0, import_react10.useState)(false);
|
|
23244
|
+
(0, import_react10.useEffect)(() => {
|
|
23135
23245
|
const element = anchor.current;
|
|
23136
23246
|
if (!element) return;
|
|
23137
23247
|
const root = element.closest("[data-conversation-scroll]") ?? element.parentElement;
|
|
@@ -23141,11 +23251,11 @@ function usePresentationOwner(anchor, documentId, sessionId) {
|
|
|
23141
23251
|
documents = /* @__PURE__ */ new Map();
|
|
23142
23252
|
roots.set(root, documents);
|
|
23143
23253
|
}
|
|
23144
|
-
const
|
|
23145
|
-
let entries = documents.get(
|
|
23254
|
+
const key2 = sessionId + ":" + documentId;
|
|
23255
|
+
let entries = documents.get(key2);
|
|
23146
23256
|
if (!entries) {
|
|
23147
23257
|
entries = /* @__PURE__ */ new Set();
|
|
23148
|
-
documents.set(
|
|
23258
|
+
documents.set(key2, entries);
|
|
23149
23259
|
}
|
|
23150
23260
|
const entry = { element, update: setOwner };
|
|
23151
23261
|
entries.add(entry);
|
|
@@ -23161,23 +23271,24 @@ function usePresentationOwner(anchor, documentId, sessionId) {
|
|
|
23161
23271
|
return () => {
|
|
23162
23272
|
entries.delete(entry);
|
|
23163
23273
|
elect();
|
|
23164
|
-
if (!entries.size) documents.delete(
|
|
23274
|
+
if (!entries.size) documents.delete(key2);
|
|
23165
23275
|
};
|
|
23166
23276
|
}, [anchor, documentId, sessionId]);
|
|
23167
23277
|
return owner;
|
|
23168
23278
|
}
|
|
23169
23279
|
|
|
23170
23280
|
// src/presentation.js
|
|
23171
|
-
var h5 =
|
|
23281
|
+
var h5 = import_react11.default.createElement;
|
|
23172
23282
|
var scanners = /* @__PURE__ */ new WeakMap();
|
|
23173
23283
|
var focused = /* @__PURE__ */ new Map();
|
|
23174
|
-
function PresentationView({ raw, sessionId, sendPrompt, scope }) {
|
|
23175
|
-
const
|
|
23284
|
+
function PresentationView({ raw, sessionId, sendPrompt, scope: scope2 }) {
|
|
23285
|
+
const showDetails = useViewDetails();
|
|
23286
|
+
const anchor = (0, import_react11.useRef)(null), records2 = useUiRegistry(), mode = usePresentation(scope2), host = markerLocation(raw.documentId);
|
|
23176
23287
|
const owner = usePresentationOwner(anchor, raw.documentId, sessionId);
|
|
23177
|
-
(0,
|
|
23288
|
+
(0, import_react11.useEffect)(() => {
|
|
23178
23289
|
rememberUi(raw, sessionId, sendPrompt);
|
|
23179
23290
|
}, [raw, sessionId, sendPrompt]);
|
|
23180
|
-
(0,
|
|
23291
|
+
(0, import_react11.useEffect)(() => {
|
|
23181
23292
|
const root = anchor.current?.closest("[data-conversation-scroll]");
|
|
23182
23293
|
if (!root) return;
|
|
23183
23294
|
let entry = scanners.get(root);
|
|
@@ -23198,7 +23309,7 @@ function PresentationView({ raw, sessionId, sendPrompt, scope }) {
|
|
|
23198
23309
|
}
|
|
23199
23310
|
};
|
|
23200
23311
|
}, [sessionId]);
|
|
23201
|
-
(0,
|
|
23312
|
+
(0, import_react11.useEffect)(() => {
|
|
23202
23313
|
const block = host?.uiMarkerBlock;
|
|
23203
23314
|
if (!block || !owner) return;
|
|
23204
23315
|
const previous = block.style.display;
|
|
@@ -23208,7 +23319,7 @@ function PresentationView({ raw, sessionId, sendPrompt, scope }) {
|
|
|
23208
23319
|
};
|
|
23209
23320
|
}, [host, mode, owner]);
|
|
23210
23321
|
const available = panelAvailable();
|
|
23211
|
-
(0,
|
|
23322
|
+
(0, import_react11.useEffect)(() => {
|
|
23212
23323
|
if (owner && mode === "sidebar" && available) openUiPanel(raw.documentId, sessionId);
|
|
23213
23324
|
}, [mode, available, sessionId, raw.documentId, owner]);
|
|
23214
23325
|
const content = h5(ValidatedView, { raw, fallback: raw.document.fallback, sessionId, sendPrompt });
|
|
@@ -23217,12 +23328,12 @@ function PresentationView({ raw, sessionId, sendPrompt, scope }) {
|
|
|
23217
23328
|
{ ref: anchor, "data-dgui-presentation": raw.documentId },
|
|
23218
23329
|
owner && available && h5("button", { type: "button", className: "dgui-secondary", onClick: () => openUiPanel(raw.documentId, sessionId) }, "\u5728\u4FA7\u680F\u6253\u5F00"),
|
|
23219
23330
|
owner && (mode === "sidebar" && available ? h5("p", { className: "dgui-copy" }, `${raw.document.title} \xB7 \u5728\u4FA7\u680F\u4E2D\u64CD\u4F5C`) : mode === "inline" && host ? (0, import_react_dom.createPortal)(content, host) : content),
|
|
23220
|
-
owner && mode === "inline" && !host && h5("small", { className: "dgui-copy" }, "\u672A\u63D0\u4F9B\u6B63\u6587\u6807\u8BB0\uFF0C\u754C\u9762\u663E\u793A\u5728\u56DE\u7B54\u4E0B\u65B9\u3002")
|
|
23331
|
+
showDetails && owner && mode === "inline" && !host && h5("small", { className: "dgui-copy" }, "\u672A\u63D0\u4F9B\u6B63\u6587\u6807\u8BB0\uFF0C\u754C\u9762\u663E\u793A\u5728\u56DE\u7B54\u4E0B\u65B9\u3002")
|
|
23221
23332
|
);
|
|
23222
23333
|
}
|
|
23223
23334
|
function UiPanel({ sessionId, sendPrompt }) {
|
|
23224
|
-
const records2 = useUiRegistry().filter((r) => r.sessionId === sessionId), [selected, setSelected] = (0,
|
|
23225
|
-
(0,
|
|
23335
|
+
const records2 = useUiRegistry().filter((r) => r.sessionId === sessionId), [selected, setSelected] = (0, import_react11.useState)(focused.get(sessionId));
|
|
23336
|
+
(0, import_react11.useEffect)(() => subscribeUi(() => setSelected(focused.get(sessionId))), [sessionId]);
|
|
23226
23337
|
const record = records2.find((r) => r.raw.documentId === selected) ?? records2.at(-1);
|
|
23227
23338
|
return h5(
|
|
23228
23339
|
"div",
|
|
@@ -23240,11 +23351,11 @@ function focusUi(id, sessionId) {
|
|
|
23240
23351
|
}
|
|
23241
23352
|
|
|
23242
23353
|
// src/view.js
|
|
23243
|
-
var h6 =
|
|
23354
|
+
var h6 = import_react12.default.createElement;
|
|
23244
23355
|
var display = (value) => value === void 0 || value === null ? "\u2014" : typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
23245
23356
|
function NumericInput({ id, spec, value, onChange, invalidChanged, disabled }) {
|
|
23246
|
-
const [draft, setDraft] = (0,
|
|
23247
|
-
(0,
|
|
23357
|
+
const [draft, setDraft] = (0, import_react12.useState)(String(value)), [invalid, setInvalid] = (0, import_react12.useState)(false);
|
|
23358
|
+
(0, import_react12.useEffect)(() => {
|
|
23248
23359
|
setDraft(String(value));
|
|
23249
23360
|
setInvalid(false);
|
|
23250
23361
|
invalidChanged(id, false);
|
|
@@ -23268,15 +23379,17 @@ function NumericInput({ id, spec, value, onChange, invalidChanged, disabled }) {
|
|
|
23268
23379
|
}
|
|
23269
23380
|
});
|
|
23270
23381
|
}
|
|
23271
|
-
function Table({ rows, columns, id }) {
|
|
23382
|
+
function Table({ rows, columns, id, label }) {
|
|
23272
23383
|
return h6("div", { className: "dgui-table-wrap" }, h6(
|
|
23273
23384
|
"table",
|
|
23274
23385
|
{ "data-ui-node": id },
|
|
23386
|
+
label && h6("caption", null, label),
|
|
23275
23387
|
h6("thead", null, h6("tr", null, columns.map((c) => h6("th", { key: c.key, scope: "col" }, c.label, c.unit ? ` (${c.unit})` : "")))),
|
|
23276
23388
|
h6("tbody", null, rows.length ? rows.map((row, i) => h6("tr", { key: i }, columns.map((c) => h6("td", { key: c.key, "data-numeric": typeof row[c.key] === "number" }, display(Object.hasOwn(row, c.key) ? row[c.key] : void 0))))) : h6("tr", null, h6("td", { colSpan: columns.length }, "\u6682\u65E0\u6570\u636E")))
|
|
23277
23389
|
));
|
|
23278
23390
|
}
|
|
23279
23391
|
function Chart({ node, rows }) {
|
|
23392
|
+
const [showData, setShowData] = (0, import_react12.useState)(false);
|
|
23280
23393
|
const data = rows.slice(0, 40), values = data.map((r) => r[node.valueKey]);
|
|
23281
23394
|
const low = node.kind === "line" && values.length ? Math.min(...values) : Math.min(0, ...values);
|
|
23282
23395
|
const high = node.kind === "line" && values.length ? Math.max(...values) : Math.max(0, ...values), range = high - low || 1;
|
|
@@ -23289,7 +23402,7 @@ function Chart({ node, rows }) {
|
|
|
23289
23402
|
return h6(
|
|
23290
23403
|
"figure",
|
|
23291
23404
|
{ className: "dgui-chart", "data-ui-node": node.id },
|
|
23292
|
-
h6("figcaption", null, h6(Icon, { name: "chart" }), node.label, node.unit && h6("span", { className: "dgui-chart-unit" }, `(${node.unit})`)),
|
|
23405
|
+
h6("figcaption", null, h6(Icon, { name: "chart" }), node.label, rows.length > 40 && "\uFF08\u56FE\u793A\u524D 40 \u9879\uFF09", node.unit && h6("span", { className: "dgui-chart-unit" }, `(${node.unit})`), h6("button", { type: "button", className: "dgui-chart-data-button", "aria-expanded": showData, onClick: () => setShowData(!showData) }, "\u56FE\u8868\u6570\u636E")),
|
|
23293
23406
|
h6("div", { className: "dgui-plot", tabIndex: 0, role: "region", "aria-label": `${node.label}\u56FE\u8868\uFF0C\u53EF\u6A2A\u5411\u6EDA\u52A8` }, h6(
|
|
23294
23407
|
"svg",
|
|
23295
23408
|
{ viewBox: `0 0 ${width} 205`, role: "img", "aria-label": `${node.label}\u3002\u5C55\u5F00\u56FE\u8868\u6570\u636E\u53EF\u67E5\u770B\u6BCF\u9879\u6570\u503C\u3002` },
|
|
@@ -23304,16 +23417,15 @@ function Chart({ node, rows }) {
|
|
|
23304
23417
|
(data.length <= 12 || i % Math.ceil(data.length / 12) === 0) && h6("text", { x: x(i), y: 192, textAnchor: "middle", fontSize: 14, fill: "var(--du-muted)" }, String(r[node.labelKey]).slice(0, 12))
|
|
23305
23418
|
))
|
|
23306
23419
|
)),
|
|
23307
|
-
h6("
|
|
23308
|
-
rows.length > 40 && h6("small", null, "\u56FE\u793A\u524D 40 \u9879\uFF0C\u5B8C\u6574\u6570\u503C\u89C1\u4E0B\u65B9\u6570\u636E\u3002"),
|
|
23309
|
-
h6("details", null, h6("summary", null, "\u56FE\u8868\u6570\u636E"), h6(Table, { rows, columns: [{ key: node.labelKey, label: "\u9879\u76EE" }, { key: node.valueKey, label: node.label, unit: node.unit }], id: `${node.id}-data` }))
|
|
23420
|
+
h6("div", { hidden: !showData }, h6(Table, { rows, columns: [{ key: node.labelKey, label: "\u9879\u76EE" }, { key: node.valueKey, label: node.label, unit: node.unit }], id: `${node.id}-data` }))
|
|
23310
23421
|
);
|
|
23311
23422
|
}
|
|
23312
23423
|
function UiView({ record, sessionId, sendPrompt, preview = false }) {
|
|
23424
|
+
const showDetails = useViewDetails();
|
|
23313
23425
|
const doc = record.document;
|
|
23314
|
-
const viewId =
|
|
23315
|
-
const root = (0,
|
|
23316
|
-
const collectAudit =
|
|
23426
|
+
const viewId = import_react12.default.useId();
|
|
23427
|
+
const root = (0, import_react12.useRef)(null), canvasAudits = (0, import_react12.useRef)(/* @__PURE__ */ new Map()), [audit, setAudit] = (0, import_react12.useState)(null), auditPending = (0, import_react12.useRef)(0);
|
|
23428
|
+
const collectAudit = import_react12.default.useCallback(() => {
|
|
23317
23429
|
clearTimeout(auditPending.current);
|
|
23318
23430
|
auditPending.current = setTimeout(() => {
|
|
23319
23431
|
if (!root.current || preview) return;
|
|
@@ -23325,7 +23437,7 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
|
|
|
23325
23437
|
});
|
|
23326
23438
|
}, 250);
|
|
23327
23439
|
}, [record.documentId, record.documentRevision, sessionId, preview]);
|
|
23328
|
-
(0,
|
|
23440
|
+
(0, import_react12.useEffect)(() => {
|
|
23329
23441
|
canvasAudits.current.clear();
|
|
23330
23442
|
collectAudit();
|
|
23331
23443
|
window.addEventListener("resize", collectAudit);
|
|
@@ -23343,22 +23455,22 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
|
|
|
23343
23455
|
collectAudit();
|
|
23344
23456
|
};
|
|
23345
23457
|
const { state, setState, ready, status, issue, epoch, retry, useRemote, keepLocal } = useSavedState(record, sessionId, preview);
|
|
23346
|
-
const [error, setError] = (0,
|
|
23347
|
-
const [busy, setBusy] = (0,
|
|
23348
|
-
const pending = (0,
|
|
23349
|
-
(0,
|
|
23458
|
+
const [error, setError] = (0, import_react12.useState)(""), [actionStatus, setActionStatus] = (0, import_react12.useState)("");
|
|
23459
|
+
const [busy, setBusy] = (0, import_react12.useState)(false), [invalidFields, setInvalidFields] = (0, import_react12.useState)({});
|
|
23460
|
+
const pending = (0, import_react12.useRef)(false);
|
|
23461
|
+
(0, import_react12.useEffect)(() => {
|
|
23350
23462
|
setInvalidFields({});
|
|
23351
23463
|
}, [epoch]);
|
|
23352
|
-
const invalidChanged =
|
|
23464
|
+
const invalidChanged = import_react12.default.useCallback((id, invalid) => setInvalidFields((previous) => previous[id] === invalid ? previous : { ...previous, [id]: invalid }), []);
|
|
23353
23465
|
let computed;
|
|
23354
23466
|
try {
|
|
23355
23467
|
computed = evaluate(doc, state);
|
|
23356
23468
|
} catch (e) {
|
|
23357
23469
|
computed = { error: e.message };
|
|
23358
23470
|
}
|
|
23359
|
-
const currentState = (0,
|
|
23471
|
+
const currentState = (0, import_react12.useRef)(state);
|
|
23360
23472
|
currentState.current = state;
|
|
23361
|
-
(0,
|
|
23473
|
+
(0, import_react12.useEffect)(() => {
|
|
23362
23474
|
collectAudit();
|
|
23363
23475
|
}, [state, ready, collectAudit]);
|
|
23364
23476
|
const updatePatch = (patch) => {
|
|
@@ -23368,9 +23480,9 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
|
|
|
23368
23480
|
setError("");
|
|
23369
23481
|
setActionStatus("");
|
|
23370
23482
|
};
|
|
23371
|
-
const update = (
|
|
23483
|
+
const update = (key2, value) => {
|
|
23372
23484
|
try {
|
|
23373
|
-
updatePatch({ [
|
|
23485
|
+
updatePatch({ [key2]: value });
|
|
23374
23486
|
} catch (e) {
|
|
23375
23487
|
setError(e.message);
|
|
23376
23488
|
}
|
|
@@ -23420,7 +23532,7 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
|
|
|
23420
23532
|
return h6("ol", { ...props, className: "dgui-steps" }, n.items.map((item, i) => h6("li", { key: i, "data-step-status": item.status }, h6("span", { className: "dgui-step-dot", "aria-hidden": true }, item.status === "done" ? h6(Icon, { name: "check" }) : item.status === "error" ? h6(Icon, { name: "warning" }) : i + 1), h6("div", null, h6("strong", null, item.title), h6("span", { className: "dgui-step-state" }, { pending: "\u5F85\u8FDB\u884C", active: "\u5F53\u524D\u6B65\u9AA4", done: "\u5DF2\u5B8C\u6210", error: "\u5F02\u5E38" }[item.status]), item.description && h6("p", null, item.description)))));
|
|
23421
23533
|
case "metric": {
|
|
23422
23534
|
const v = resolve(n.value);
|
|
23423
|
-
return h6("div", { ...props, className: "dgui-metric" }, h6("span", { className: "dgui-metric-label" }, h6(Icon, { name: n.icon ?? "gauge" }), n.label), h6("strong", null, typeof v === "number" ? formatNumber(v, n.decimals ?? 2) :
|
|
23535
|
+
return h6("div", { ...props, className: "dgui-metric" }, h6("span", { className: "dgui-metric-label" }, h6(Icon, { name: n.icon ?? "gauge" }), n.label), h6("strong", null, typeof v === "number" ? formatNumber(v, n.decimals ?? 2) : display(v), " ", h6("small", null, n.unit)));
|
|
23424
23536
|
}
|
|
23425
23537
|
case "input":
|
|
23426
23538
|
case "slider":
|
|
@@ -23430,7 +23542,7 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
|
|
|
23430
23542
|
let control;
|
|
23431
23543
|
if (n.type === "select") control = h6("select", { id, value: spec.options.indexOf(v), disabled: !ready, onChange: (e) => update(k, spec.options[Number(e.target.value)]) }, spec.options.map((o, i) => h6("option", { key: i, value: i }, display(o))));
|
|
23432
23544
|
else if (n.type === "toggle") control = h6("input", { id, className: "dgui-toggle", type: "checkbox", checked: v, disabled: !ready, onChange: (e) => update(k, e.target.checked) });
|
|
23433
|
-
else if (n.type === "slider") control = h6(
|
|
23545
|
+
else if (n.type === "slider") control = h6(import_react12.default.Fragment, null, h6("input", { id, type: "range", min: spec.min, max: spec.max, step: spec.step, value: v, disabled: !ready, onChange: (e) => update(k, Number(e.target.value)) }), h6("output", { htmlFor: id }, display(v)));
|
|
23434
23546
|
else if (spec.type === "number") control = h6(NumericInput, { id, spec, value: v, disabled: !ready, invalidChanged, onChange: (value) => update(k, value) });
|
|
23435
23547
|
else control = h6("input", { id, type: "text", value: v, maxLength: 8192, disabled: !ready, onChange: (e) => update(k, e.target.value) });
|
|
23436
23548
|
return h6("div", { ...props, className: "dgui-control" }, h6("label", { htmlFor: id }, h6(Icon, { name: n.type === "toggle" ? "layers" : n.type === "select" ? "target" : "sliders" }), h6("span", null, n.label)), control);
|
|
@@ -23438,7 +23550,7 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
|
|
|
23438
23550
|
case "button":
|
|
23439
23551
|
return h6("button", { ...props, className: "dgui-button", type: "button", disabled: disabled || !sendPrompt, onClick: () => followup(n.action) }, n.text, h6(Icon, { name: n.icon ?? "arrow" }));
|
|
23440
23552
|
case "table":
|
|
23441
|
-
return computed.error ? null : h6(Table, { key: n.id, id: n.id, rows: resolve(n.rows), columns: n.columns });
|
|
23553
|
+
return computed.error ? null : h6(Table, { key: n.id, id: n.id, label: n.label, rows: resolve(n.rows), columns: n.columns });
|
|
23442
23554
|
case "chart":
|
|
23443
23555
|
return computed.error ? null : h6(Chart, { key: n.id, node: n, rows: resolve(n.rows) });
|
|
23444
23556
|
default:
|
|
@@ -23451,12 +23563,12 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
|
|
|
23451
23563
|
{ ref: root, className: "dgui-root", "data-document-revision": record.documentRevision ?? 0, "data-dgui-build": BUILD_INFO.id, "data-dsh-generative-ui": record.documentId, "data-layout": doc.presentation?.layout, "data-accent": doc.presentation?.accent, "data-density": doc.presentation?.density, "data-preview": preview || void 0, "aria-label": doc.title, "aria-busy": preview || void 0 },
|
|
23452
23564
|
h6("header", { className: "dgui-header" }, h6("span", { className: "dgui-heading-icon" }, h6(Icon, { name: sceneIcons[doc.presentation?.layout] ?? (Object.keys(doc.state).length ? "sliders" : "layers") })), h6("strong", { className: "dgui-header-title" }, doc.title), h6("span", { className: "dgui-badge" }, h6(Icon, { name: "sparkles" }), preview ? "\u751F\u6210\u4E2D" : "\u53EF\u89C6\u5316")),
|
|
23453
23565
|
h6("div", { key: epoch, className: "dgui-content" }, doc.nodes.map(renderNode)),
|
|
23454
|
-
(Object.keys(doc.state).length > 0 || issue || actionStatus) && h6("div", { className: "dgui-status", role: "status", "data-status": /失败|冲突/.test(status) ? "error" : /正在|等待/.test(status) ? "pending" : "saved" }, h6(Icon, { name: /失败|冲突/.test(status) ? "warning" : /正在|等待/.test(status) ? "database" : "check" }), h6("span", null, status), actionStatus && h6("span", null, ` \xB7 ${actionStatus}`)),
|
|
23566
|
+
(Object.keys(doc.state).length > 0 || issue || actionStatus) && h6("div", { className: showDetails || issue || actionStatus ? "dgui-status" : "dgui-sr-only", role: "status", "data-status": /失败|冲突/.test(status) ? "error" : /正在|等待/.test(status) ? "pending" : "saved" }, h6(Icon, { name: /失败|冲突/.test(status) ? "warning" : /正在|等待/.test(status) ? "database" : "check" }), h6("span", null, status), actionStatus && h6("span", null, ` \xB7 ${actionStatus}`)),
|
|
23455
23567
|
issue && h6(
|
|
23456
23568
|
"div",
|
|
23457
23569
|
{ className: "dgui-recovery" },
|
|
23458
23570
|
issue.kind === "conflict" ? h6(
|
|
23459
|
-
|
|
23571
|
+
import_react12.default.Fragment,
|
|
23460
23572
|
null,
|
|
23461
23573
|
h6("button", { type: "button", className: "dgui-secondary", disabled: status === "\u6B63\u5728\u6062\u590D\u53C2\u6570\u2026", onClick: useRemote }, "\u4F7F\u7528\u5DF2\u4FDD\u5B58\u53C2\u6570"),
|
|
23462
23574
|
h6("button", { type: "button", className: "dgui-secondary", disabled: status === "\u6B63\u5728\u6062\u590D\u53C2\u6570\u2026", onClick: keepLocal }, "\u4FDD\u7559\u672C\u9875\u53C2\u6570\u5E76\u91CD\u8BD5")
|
|
@@ -23464,12 +23576,12 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
|
|
|
23464
23576
|
),
|
|
23465
23577
|
(error || computed.error) && h6("p", { className: "dgui-error", role: "alert" }, error || computed.error),
|
|
23466
23578
|
Object.values(invalidFields).some(Boolean) && h6("p", { className: "dgui-error", role: "alert" }, "\u8BF7\u8F93\u5165\u8303\u56F4\u5185\u4E14\u7B26\u5408\u6B65\u957F\u7684\u6570\u503C\u3002"),
|
|
23467
|
-
!preview && audit && h6("details", { className: "dgui-fallback dgui-audit" }, h6("summary", null, "\u663E\u793A\u68C0\u67E5"), h6("p", null, `${audit.width}px \xB7 ${audit.theme === "dark" ? "\u6DF1\u8272" : "\u6D45\u8272"} \xB7 \u542F\u53D1\u5F0F\u89C2\u5BDF\uFF0C\u4E0D\u4EE3\u8868\u5B8C\u6574\u89C6\u89C9\u9A8C\u6536\u3002`), h6("p", null, "\u672A\u8986\u76D6\uFF1A\u590D\u6742\u80CC\u666F\u3001\u906E\u6321\u5173\u7CFB\u53CA SVG \u914D\u8272\uFF1B\u62A5\u544A\u4E0D\u7B49\u4E8E\u5B8C\u6574\u65E0\u969C\u788D\u68C0\u67E5\u3002"), audit.coverage?.some((c) => c.truncated) && h6("p", null, "\u5185\u5BB9\u8F83\u591A\uFF0C\u672C\u6B21\u53EA\u68C0\u67E5\u4E86\u6BCF\u4E2A\u533A\u57DF\u7684\u524D 2000 \u4E2A\u5143\u7D20\u3002"), audit.issues.length ? h6("ul", null, audit.issues.map((i, j) => h6("li", { key: j }, AUDIT_MESSAGES[i.code], i.nodeId ? `\uFF08${i.nodeId}\uFF09` : ""))) : h6("p", null, "\u672C\u6B21\u68C0\u67E5\u672A\u53D1\u73B0\u6240\u8986\u76D6\u7684\u95EE\u9898\u3002")),
|
|
23468
|
-
!preview && h6(HistoryView, { record, sessionId }),
|
|
23469
|
-
h6("details", { className: "dgui-fallback" }, h6("summary", null, Object.keys(doc.state).length ? "\u539F\u59CB\u6587\u5B57\u8BF4\u660E\u4E0E\u521D\u59CB\u53C2\u6570" : "\u539F\u59CB\u6587\u5B57\u8BF4\u660E"), h6("p", null, doc.fallback), Object.keys(doc.state).length > 0 && h6("pre", null, JSON.stringify(initialState(doc), null, 2)))
|
|
23579
|
+
showDetails && !preview && audit && h6("details", { className: "dgui-fallback dgui-audit" }, h6("summary", null, "\u663E\u793A\u68C0\u67E5"), h6("p", null, `${audit.width}px \xB7 ${audit.theme === "dark" ? "\u6DF1\u8272" : "\u6D45\u8272"} \xB7 \u542F\u53D1\u5F0F\u89C2\u5BDF\uFF0C\u4E0D\u4EE3\u8868\u5B8C\u6574\u89C6\u89C9\u9A8C\u6536\u3002`), h6("p", null, "\u672A\u8986\u76D6\uFF1A\u590D\u6742\u80CC\u666F\u3001\u906E\u6321\u5173\u7CFB\u53CA SVG \u914D\u8272\uFF1B\u62A5\u544A\u4E0D\u7B49\u4E8E\u5B8C\u6574\u65E0\u969C\u788D\u68C0\u67E5\u3002"), audit.coverage?.some((c) => c.truncated) && h6("p", null, "\u5185\u5BB9\u8F83\u591A\uFF0C\u672C\u6B21\u53EA\u68C0\u67E5\u4E86\u6BCF\u4E2A\u533A\u57DF\u7684\u524D 2000 \u4E2A\u5143\u7D20\u3002"), audit.issues.length ? h6("ul", null, audit.issues.map((i, j) => h6("li", { key: j }, AUDIT_MESSAGES[i.code], i.nodeId ? `\uFF08${i.nodeId}\uFF09` : ""))) : h6("p", null, "\u672C\u6B21\u68C0\u67E5\u672A\u53D1\u73B0\u6240\u8986\u76D6\u7684\u95EE\u9898\u3002")),
|
|
23580
|
+
showDetails && !preview && h6(HistoryView, { record, sessionId }),
|
|
23581
|
+
showDetails && h6("details", { className: "dgui-fallback" }, h6("summary", null, Object.keys(doc.state).length ? "\u539F\u59CB\u6587\u5B57\u8BF4\u660E\u4E0E\u521D\u59CB\u53C2\u6570" : "\u539F\u59CB\u6587\u5B57\u8BF4\u660E"), h6("p", null, doc.fallback), Object.keys(doc.state).length > 0 && h6("pre", null, JSON.stringify(initialState(doc), null, 2)))
|
|
23470
23582
|
);
|
|
23471
23583
|
}
|
|
23472
|
-
var UiBoundary = class extends
|
|
23584
|
+
var UiBoundary = class extends import_react12.default.Component {
|
|
23473
23585
|
state = { failed: false };
|
|
23474
23586
|
static getDerivedStateFromError() {
|
|
23475
23587
|
return { failed: true };
|
|
@@ -23493,9 +23605,9 @@ function StreamingToolView(props) {
|
|
|
23493
23605
|
}
|
|
23494
23606
|
function StreamingPreview({ raw, callId = "stream", sessionId }) {
|
|
23495
23607
|
const committed = useUiRegistry().some((r) => r.sessionId === sessionId && r.raw.callId === callId);
|
|
23496
|
-
const deferred =
|
|
23497
|
-
const doc = (0,
|
|
23498
|
-
const canvas = (0,
|
|
23608
|
+
const deferred = import_react12.default.useDeferredValue(raw);
|
|
23609
|
+
const doc = (0, import_react12.useMemo)(() => previewDocument(deferred), [deferred]);
|
|
23610
|
+
const canvas = (0, import_react12.useMemo)(() => doc ? null : previewCanvas(deferred), [doc, deferred]);
|
|
23499
23611
|
if (committed) return h6("p", { className: "dgui-copy" }, "\u754C\u9762\u5DF2\u751F\u6210\u3002");
|
|
23500
23612
|
if (canvas) return h6("div", { className: "dgui-root", "data-preview": true }, h6(CanvasPreview, { node: canvas }));
|
|
23501
23613
|
if (!doc) return h6("div", { className: "dgui-pending", role: "status" }, "\u6B63\u5728\u7EC4\u7EC7\u5E76\u6821\u9A8C\u4EA4\u4E92\u754C\u9762\u2026");
|
|
@@ -23505,7 +23617,7 @@ function TurnUiView(props) {
|
|
|
23505
23617
|
return (props.turn.data.get("dshGenerativeUi") ?? []).filter((r) => r.seq < props.seq).map((r) => r.isPatch ? h6(PatchNotice, { key: `patch-${r.seq}`, raw: r.raw }) : h6(PresentationView, { key: r.raw.documentId, ...r, sessionId: props.sessionId, sendPrompt: props.sendPrompt, scope: props.presentationScope }));
|
|
23506
23618
|
}
|
|
23507
23619
|
function PatchNotice({ raw }) {
|
|
23508
|
-
(0,
|
|
23620
|
+
(0, import_react12.useEffect)(() => {
|
|
23509
23621
|
try {
|
|
23510
23622
|
if (raw) publishDocument(raw);
|
|
23511
23623
|
} catch {
|
|
@@ -23515,7 +23627,7 @@ function PatchNotice({ raw }) {
|
|
|
23515
23627
|
}
|
|
23516
23628
|
function ValidatedView({ raw, fallback, sessionId, sendPrompt }) {
|
|
23517
23629
|
const { record: current2, status, retry } = useCurrentDocument(raw ?? {}, sessionId);
|
|
23518
|
-
const result = (0,
|
|
23630
|
+
const result = (0, import_react12.useMemo)(() => {
|
|
23519
23631
|
try {
|
|
23520
23632
|
if (!current2 || current2.version !== 1 || typeof current2.documentId !== "string" || typeof current2.callId !== "string") return null;
|
|
23521
23633
|
return { ...current2, document: validateDocument(current2.document) };
|
|
@@ -23525,7 +23637,7 @@ function ValidatedView({ raw, fallback, sessionId, sendPrompt }) {
|
|
|
23525
23637
|
}, [current2]);
|
|
23526
23638
|
if (!result) return h6("div", { className: "dgui-root" }, h6("p", null, "\u6587\u5B57\u7ED3\u679C\uFF08\u672A\u63D0\u4F9B\u517C\u5BB9\u7684\u754C\u9762\u6570\u636E\uFF09"), h6("pre", null, fallback));
|
|
23527
23639
|
return h6(
|
|
23528
|
-
|
|
23640
|
+
import_react12.default.Fragment,
|
|
23529
23641
|
null,
|
|
23530
23642
|
status === "error" && h6("div", { className: "dgui-root dgui-document-warning", role: "status" }, h6("p", null, "\u672A\u80FD\u786E\u8BA4\u6700\u65B0\u754C\u9762\u7248\u672C\uFF0C\u5F53\u524D\u663E\u793A\u5DF2\u77E5\u7248\u672C\u3002"), h6("button", { type: "button", className: "dgui-secondary", onClick: retry }, "\u91CD\u65B0\u8BFB\u53D6\u6700\u65B0\u754C\u9762")),
|
|
23531
23643
|
status === "loading" && h6("p", { className: "dgui-copy", role: "status" }, "\u6B63\u5728\u8BFB\u53D6\u6700\u65B0\u754C\u9762\u7248\u672C\u2026"),
|
|
@@ -23553,8 +23665,8 @@ var turnUiDefinition = {
|
|
|
23553
23665
|
const fallback = (event.data.message.content ?? []).filter((c) => c.type === "text").map((c) => c.text).join("\n");
|
|
23554
23666
|
return { ...context.state, records: [...context.state.records, { seq: event.seq, raw, fallback, ...isPatch ? { isPatch: true } : {} }] };
|
|
23555
23667
|
},
|
|
23556
|
-
buildLocationData(context,
|
|
23557
|
-
if (
|
|
23668
|
+
buildLocationData(context, scope2, previous) {
|
|
23669
|
+
if (scope2 !== "turn" || !context.state) return null;
|
|
23558
23670
|
if (previous?.key === "dshGenerativeUi" && previous.value === context.state.records) return previous;
|
|
23559
23671
|
return { kind: "turn", turn: context.state.turn, key: "dshGenerativeUi", value: context.state.records };
|
|
23560
23672
|
}
|
|
@@ -23588,8 +23700,30 @@ var CANVAS_CSS = `
|
|
|
23588
23700
|
.dgui-canvas{min-width:0}.dgui-canvas-stage{position:relative}.dgui-canvas-loading{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;gap:10px;color:var(--du-muted);font-size:13px;background:var(--du-soft);border-radius:12px}.dgui-canvas-spinner{width:16px;height:16px;border:2px solid var(--du-line);border-top-color:var(--du-accent);border-radius:50%;animation:dgui-spin .9s linear infinite}.dgui-canvas-placeholder{padding:24px 18px;background:var(--du-soft);border:1px dashed var(--du-line);border-radius:12px;color:var(--du-muted);font-size:13px;display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.dgui-canvas-placeholder p{margin:0}.dgui-canvas-options{margin-top:6px}.dgui-root .dgui-canvas-options>summary{font-size:12px;padding:5px 0;color:var(--du-muted);width:fit-content}.dgui-canvas-options[open]{border-top:1px solid var(--du-line);padding-top:8px;margin-top:12px}.dgui-canvas-options>.dgui-copy{padding:8px 0;font-size:12px}.dgui-canvas-issue{border:1px solid color-mix(in srgb,var(--du-amber) 30%,var(--du-line));background:color-mix(in srgb,var(--du-amber) 5%,var(--du-bg));border-radius:10px;padding:14px;margin-top:10px;font-size:12px;color:var(--du-ink)}.dgui-canvas-issue>strong{font-size:13px}.dgui-canvas-issue>p{color:var(--du-muted);margin-top:4px}.dgui-canvas-issue details{margin-top:8px}.dgui-root .dgui-canvas-issue pre{max-height:160px;overflow:auto}.dgui-canvas-options .dgui-secondary{font-size:12px;padding:6px 9px;box-shadow:none}@keyframes dgui-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.dgui-canvas-spinner{animation:none}}@media(forced-colors:active){.dgui-canvas-issue,.dgui-canvas-placeholder{border-color:CanvasText}}
|
|
23589
23701
|
`;
|
|
23590
23702
|
|
|
23703
|
+
// src/soft-styles.js
|
|
23704
|
+
var SOFT_CSS = `
|
|
23705
|
+
.dgui-root{--du-radius:24px;--du-radius-inner:18px;background:linear-gradient(145deg,color-mix(in srgb,var(--du-accent) 4%,var(--du-bg)),var(--du-bg) 42%,color-mix(in srgb,var(--du-violet) 3%,var(--du-bg)));border-radius:var(--du-radius)}
|
|
23706
|
+
.dgui-root .dgui-card,.dgui-root .dgui-metric,.dgui-root .dgui-chart,.dgui-root .dgui-progress,.dgui-root .dgui-details{border-radius:var(--du-radius-inner);background:linear-gradient(135deg,color-mix(in srgb,var(--du-tone) 9%,var(--du-bg)),color-mix(in srgb,var(--du-violet) 4%,var(--du-bg)) 65%,var(--du-bg))}
|
|
23707
|
+
.dgui-root .dgui-card[data-surface=soft]{background:linear-gradient(135deg,var(--du-soft),color-mix(in srgb,var(--du-accent) 7%,var(--du-bg)))}
|
|
23708
|
+
.dgui-root .dgui-card[data-surface=featured]{border-radius:20px;background:linear-gradient(130deg,color-mix(in srgb,var(--du-accent) 14%,var(--du-bg)),color-mix(in srgb,var(--du-violet) 7%,var(--du-bg)));box-shadow:none}
|
|
23709
|
+
.dgui-root[data-layout=dashboard] .dgui-metric{background:linear-gradient(135deg,color-mix(in srgb,var(--du-tone) 11%,var(--du-bg)),var(--du-bg))}
|
|
23710
|
+
.dgui-root[data-layout=report] .dgui-card{padding:16px 18px;border:1px solid var(--du-line);border-radius:18px}
|
|
23711
|
+
.dgui-root .dgui-heading-icon{border-radius:14px;background:linear-gradient(145deg,color-mix(in srgb,var(--du-accent) 14%,var(--du-bg)),color-mix(in srgb,var(--du-violet) 8%,var(--du-bg)))}
|
|
23712
|
+
.dgui-root .dgui-button{border-radius:14px;background:linear-gradient(120deg,var(--du-action,#3e60d3),color-mix(in srgb,var(--du-action,#3e60d3) 85%,#152647))}
|
|
23713
|
+
.dgui-root input:not([type=range]):not([type=checkbox]),.dgui-root select,.dgui-root textarea,.dgui-root .dgui-secondary,.dgui-root .dgui-menu-trigger{border-radius:12px}
|
|
23714
|
+
.dgui-root .dgui-menu-content,.dgui-root .dgui-table-wrap,.dgui-root .dgui-canvas-placeholder,.dgui-root .dgui-canvas-loading,.dgui-root .dgui-canvas-issue{border-radius:18px}
|
|
23715
|
+
.dgui-root .dgui-menu-content button{border-radius:12px}.dgui-root .dgui-badge{border-radius:999px;background:linear-gradient(120deg,var(--du-soft),var(--du-tint))}
|
|
23716
|
+
.dgui-root .dgui-table-wrap caption{text-align:left;padding:12px 14px;font-size:14px;font-weight:600;color:var(--du-ink);background:linear-gradient(120deg,var(--du-tint),var(--du-bg))}
|
|
23717
|
+
.dgui-root[data-layout=status] .dgui-header{border-radius:23px 23px 0 0;background:linear-gradient(120deg,var(--du-tint),var(--du-soft))}
|
|
23718
|
+
.dgui-root[data-layout=dashboard]{background:linear-gradient(145deg,var(--du-tint),var(--du-bg) 45%,color-mix(in srgb,var(--du-violet) 4%,var(--du-bg)))}
|
|
23719
|
+
.dgui-root .dgui-content>:last-child{margin-bottom:0}.dgui-root .dgui-canvas-stage iframe{border-radius:16px}
|
|
23720
|
+
@media(max-width:600px){.dgui-root{--du-radius:22px;--du-radius-inner:18px}}
|
|
23721
|
+
@media(forced-colors:active){.dgui-root,.dgui-root .dgui-card,.dgui-root .dgui-metric,.dgui-root .dgui-chart,.dgui-root .dgui-button{background:Canvas}}
|
|
23722
|
+
`;
|
|
23723
|
+
|
|
23591
23724
|
// src/styles.js
|
|
23592
23725
|
var CSS = `
|
|
23726
|
+
.dgui-chart-data-button{margin-left:auto;border:0;background:transparent;color:var(--du-muted);font:inherit;cursor:pointer;padding:4px 8px}.dgui-chart-data-button:hover{color:var(--du-accent)}.dgui-sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip-path:inset(50%)!important;white-space:nowrap!important;border:0!important}.dgui-canvas{position:relative}.dgui-action-menu{position:absolute;top:6px;right:6px;z-index:2}.dgui-menu-trigger{width:32px;height:32px;border:1px solid var(--du-line);border-radius:8px;background:var(--du-bg);color:var(--du-muted);font-size:24px;line-height:1;cursor:pointer}.dgui-menu-content{position:absolute;top:38px;right:0;display:grid;min-width:156px;padding:5px;border:1px solid var(--du-line);border-radius:10px;background:var(--du-bg);box-shadow:0 6px 20px #0002}.dgui-menu-content button{border:0;border-radius:6px;background:transparent;color:var(--du-ink);padding:9px 12px;text-align:left;font:inherit;white-space:nowrap;cursor:pointer}.dgui-menu-content button:hover{background:var(--du-soft)}.dgui-menu-content button:disabled{opacity:.45;cursor:default}.dgui-action-menu button:focus-visible{outline:2px solid var(--du-accent);outline-offset:2px}
|
|
23593
23727
|
.dgui-root.dgui-settings{border:0;border-radius:0;box-shadow:none;background:transparent;padding:0;margin:0;max-width:720px;display:flex;flex-direction:column;gap:14px;font-size:13px;line-height:1.65}
|
|
23594
23728
|
.dgui-settings h3{font-size:14px;font-weight:600;margin:0}.dgui-settings label{font-weight:500}.dgui-settings p{color:var(--du-muted)}
|
|
23595
23729
|
.dgui-settings select{width:100%;max-width:420px;min-height:40px;border:1px solid var(--du-line);border-radius:6px;padding:9px 12px;background:var(--dsw-alias-bg-layer-3,var(--du-bg));color:inherit;font:inherit}.dgui-settings select:focus-visible{outline:2px solid var(--du-accent);outline-offset:3px}.dgui-settings select:disabled{opacity:.5}
|
|
@@ -23612,29 +23746,29 @@ body[data-ds-dark-theme] .dgui-root,.dgui-root[data-preview-theme=dark]{--du-acc
|
|
|
23612
23746
|
.dgui-panel{padding:16px;min-width:0;overflow:auto;height:100%;box-sizing:border-box}.dgui-panel>.dgui-root{margin-bottom:16px}.dgui-panel label{display:flex;align-items:center;flex-wrap:wrap;gap:10px}.dgui-panel select{max-width:100%;flex:1;min-width:120px;border:1px solid var(--du-line);border-radius:8px;padding:8px;background:var(--du-bg);color:var(--du-ink)}
|
|
23613
23747
|
.dgui-history-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:10px 0;border-bottom:1px solid var(--du-line)}.dgui-history-row>span{flex:1;min-width:140px}.dgui-version-preview{margin-top:14px;border:1px solid var(--du-line);border-radius:12px;padding:12px}.dgui-version-preview .dgui-root{margin-top:12px}
|
|
23614
23748
|
[data-dgui-presentation]>.dgui-secondary{margin:8px 0}[data-dgui-marker]{min-width:0}
|
|
23615
|
-
|
|
23749
|
+
` + SOFT_CSS;
|
|
23616
23750
|
|
|
23617
23751
|
// src/settings.js
|
|
23618
|
-
var
|
|
23619
|
-
var h7 =
|
|
23620
|
-
function ModeSettings({ scope }) {
|
|
23621
|
-
const [
|
|
23622
|
-
(0,
|
|
23623
|
-
const ready =
|
|
23624
|
-
async function change(mode,
|
|
23752
|
+
var import_react13 = __toESM(require("react"), 1);
|
|
23753
|
+
var h7 = import_react13.default.createElement;
|
|
23754
|
+
function ModeSettings({ scope: scope2 }) {
|
|
23755
|
+
const [snapshot2, setSnapshot] = (0, import_react13.useState)(() => scope2.getSnapshot()), [busy, setBusy] = (0, import_react13.useState)(false), [message, setMessage] = (0, import_react13.useState)(""), pending = (0, import_react13.useRef)(false);
|
|
23756
|
+
(0, import_react13.useEffect)(() => scope2.subscribe(() => setSnapshot(scope2.getSnapshot())), [scope2]);
|
|
23757
|
+
const ready = snapshot2.status === "ready" && snapshot2.value !== void 0;
|
|
23758
|
+
async function change(mode, key2 = "designMode") {
|
|
23625
23759
|
if (pending.current || !ready) return;
|
|
23626
23760
|
pending.current = true;
|
|
23627
23761
|
setBusy(true);
|
|
23628
23762
|
setMessage("");
|
|
23629
23763
|
try {
|
|
23630
|
-
await
|
|
23631
|
-
const actual =
|
|
23764
|
+
await scope2.mutate([{ op: "set", path: [key2], value: mode }], scope2.getSnapshot().revision);
|
|
23765
|
+
const actual = scope2.getSnapshot();
|
|
23632
23766
|
setSnapshot(actual);
|
|
23633
|
-
if (actual.status !== "ready" || actual.value?.[
|
|
23634
|
-
setMessage(
|
|
23767
|
+
if (actual.status !== "ready" || actual.value?.[key2] !== mode) throw new Error("\u8BBE\u7F6E\u672A\u4FDD\u5B58\uFF0C\u53EF\u80FD\u53D1\u751F\u914D\u7F6E\u51B2\u7A81\uFF0C\u8BF7\u91CD\u8BD5\u3002");
|
|
23768
|
+
setMessage(key2 === "designMode" ? "\u6A21\u5F0F\u5DF2\u4FDD\u5B58\uFF1B\u4ECE\u4E0B\u4E00\u6B21\u8BF7\u6C42\u5F00\u59CB\u751F\u6548\u3002" : "\u5C55\u793A\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\uFF1B\u6B63\u6587\u5B9A\u4F4D\u6307\u5BFC\u4ECE\u4E0B\u4E00\u6B21\u8BF7\u6C42\u5F00\u59CB\u751F\u6548\u3002");
|
|
23635
23769
|
} catch (e) {
|
|
23636
23770
|
setMessage(e.message ?? "\u6A21\u5F0F\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002");
|
|
23637
|
-
setSnapshot(
|
|
23771
|
+
setSnapshot(scope2.getSnapshot());
|
|
23638
23772
|
} finally {
|
|
23639
23773
|
pending.current = false;
|
|
23640
23774
|
setBusy(false);
|
|
@@ -23645,14 +23779,16 @@ function ModeSettings({ scope }) {
|
|
|
23645
23779
|
{ className: "dgui-root dgui-settings", "aria-label": "DSH Motion UI \u8BBE\u7F6E" },
|
|
23646
23780
|
h7("h3", null, "DSH Motion UI"),
|
|
23647
23781
|
h7("label", { htmlFor: "dgui-design-mode" }, "\u8BBE\u8BA1\u6A21\u5F0F"),
|
|
23648
|
-
h7("select", { id: "dgui-design-mode", value:
|
|
23782
|
+
h7("select", { id: "dgui-design-mode", value: snapshot2.value?.designMode ?? "guided", disabled: !ready || busy, onChange: (e) => change(e.target.value) }, h7("option", { value: "guided" }, "\u5F15\u5BFC\u6A21\u5F0F"), h7("option", { value: "free" }, "\u81EA\u7531\u8BBE\u8BA1\u6A21\u5F0F")),
|
|
23649
23783
|
h7("p", null, "\u5F15\u5BFC\u6A21\u5F0F\u63D0\u4F9B\u8BBE\u8BA1\u6280\u80FD\u3001\u7EC4\u4EF6\u534F\u8BAE\u4E0E\u793A\u4F8B\u3002\u81EA\u7531\u8BBE\u8BA1\u6A21\u5F0F\u53EA\u63D0\u4F9B\u753B\u5E03\u63A5\u53E3\u4E0E\u4EA4\u4E92\u7EA6\u675F\uFF0C\u5E03\u5C40\u3001\u56FE\u5F62\u3001\u914D\u8272\u548C\u52A8\u753B\u7531\u6A21\u578B\u51B3\u5B9A\uFF1B\u4E24\u79CD\u6A21\u5F0F\u7684\u8FD0\u884C\u6743\u9650\u76F8\u540C\u3002"),
|
|
23650
23784
|
h7("p", null, "\u4E24\u79CD\u6A21\u5F0F\u90FD\u4F1A\u6307\u5BFC\u6A21\u578B\u5224\u65AD\u4F55\u65F6\u4E3B\u52A8\u4F7F\u7528 UI\uFF0C\u5E76\u4F18\u5148\u4EA4\u4ED8\u5C0F\u800C\u5B8C\u6574\u7684\u754C\u9762\u3002"),
|
|
23651
23785
|
h7("label", { htmlFor: "dgui-display-mode" }, "\u754C\u9762\u5C55\u793A\u4F4D\u7F6E"),
|
|
23652
|
-
h7("select", { id: "dgui-display-mode", value:
|
|
23786
|
+
h7("select", { id: "dgui-display-mode", value: snapshot2.value?.displayMode ?? "tail", disabled: !ready || busy, onChange: (e) => change(e.target.value, "displayMode") }, h7("option", { value: "tail" }, "\u56DE\u7B54\u4E0B\u65B9"), h7("option", { value: "inline" }, "\u6B63\u6587\u6807\u8BB0\u4F4D\u7F6E"), h7("option", { value: "sidebar" }, "PC \u4FA7\u680F")),
|
|
23653
23787
|
h7("p", null, "\u6B63\u6587\u6A21\u5F0F\u7531\u6A21\u578B\u7528\u6807\u8BB0\u9009\u62E9\u63D2\u5165\u4F4D\u7F6E\uFF0C\u7F3A\u5C11\u6807\u8BB0\u65F6\u663E\u793A\u5728\u56DE\u7B54\u4E0B\u65B9\u3002\u4FA7\u680F\u4E0D\u53EF\u7528\u65F6\u81EA\u52A8\u56DE\u9000\uFF1B\u6B63\u6587\u548C\u4FA7\u680F\u5171\u4EAB\u5DF2\u4FDD\u5B58\u53C2\u6570\u3002"),
|
|
23788
|
+
h7("label", { htmlFor: "dgui-show-details" }, h7("input", { id: "dgui-show-details", type: "checkbox", checked: snapshot2.value?.showDetails === true, disabled: !ready || busy, onChange: (e) => change(e.target.checked, "showDetails") }), " \u663E\u793A\u754C\u9762\u8BE6\u60C5"),
|
|
23789
|
+
h7("p", null, "\u9ED8\u8BA4\u9690\u85CF\u5E95\u90E8\u7684\u53C2\u6570\u72B6\u6001\u3001\u539F\u59CB\u8BF4\u660E\u3001\u663E\u793A\u68C0\u67E5\u548C\u7248\u672C\u5386\u53F2\u3002\u5BFC\u51FA\u4E0E\u91CD\u7F6E\u53EF\u901A\u8FC7\u753B\u5E03\u53F3\u4E0A\u89D2\u64CD\u4F5C\u83DC\u5355\u4F7F\u7528\uFF1B\u9519\u8BEF\u63D0\u793A\u59CB\u7EC8\u4FDD\u7559\u3002"),
|
|
23654
23790
|
h7("p", null, "\u6B64\u8BBE\u7F6E\u5F71\u54CD\u5F53\u524D profile \u540E\u7EED\u8BF7\u6C42\u3002\u5DF2\u6709\u4E0A\u4E0B\u6587\u53EF\u80FD\u4FDD\u7559\u65E7\u6307\u5BFC\uFF0C\u5BF9\u6BD4\u6A21\u5F0F\u65F6\u8BF7\u65B0\u5EFA\u4F1A\u8BDD\u3002"),
|
|
23655
|
-
!ready && h7("p", { role: "status" },
|
|
23791
|
+
!ready && h7("p", { role: "status" }, snapshot2.status === "unavailable" ? "\u63D2\u4EF6\u8BBE\u7F6E\u4E0D\u53EF\u7528\uFF0C\u8BF7\u786E\u8BA4\u5BBF\u4E3B\u5DF2\u52A0\u8F7D\u65B0\u7248\u63D2\u4EF6\u3002" : "\u6B63\u5728\u8BFB\u53D6\u8BBE\u7F6E\u2026"),
|
|
23656
23792
|
message && h7("p", { role: "status" }, message)
|
|
23657
23793
|
);
|
|
23658
23794
|
}
|
|
@@ -23660,13 +23796,14 @@ function ModeSettings({ scope }) {
|
|
|
23660
23796
|
// src/client.jsx
|
|
23661
23797
|
var inject = ["slots", "sessions", "conversation", "uiConversation", "configForms"];
|
|
23662
23798
|
function apply(ctx) {
|
|
23663
|
-
const
|
|
23664
|
-
|
|
23799
|
+
const scope2 = ctx.configForms.get("motion-ui");
|
|
23800
|
+
configureViewSettings(scope2);
|
|
23801
|
+
ctx.slots.inject("plugins.bundle.config", () => ctx.slots.register({ name: "plugins.bundle.config", key: "dsh-motion-ui" }, (props) => import_react14.default.createElement(ModeSettings, { ...props, scope: scope2 })));
|
|
23665
23802
|
ctx.uiConversation.events.register(turnUiDefinition);
|
|
23666
23803
|
ctx.slots.inject("conversation.chat.turnTail", () => ctx.slots.register({
|
|
23667
23804
|
name: "conversation.chat.turnTail",
|
|
23668
23805
|
id: "dsh-generative-ui",
|
|
23669
|
-
inject: (sessionId) => ({ presentationScope:
|
|
23806
|
+
inject: (sessionId) => ({ presentationScope: scope2, sendPrompt: (prompt) => ctx.sessions.scope(sessionId).get("conversation").send(prompt) })
|
|
23670
23807
|
}, TurnUiView));
|
|
23671
23808
|
ctx.effect(() => {
|
|
23672
23809
|
const style = document.createElement("style");
|