dsh-motion-ui 0.5.3 → 0.5.5

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/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 key3 of __getOwnPropNames(from))
20
- if (!__hasOwnProp.call(to, key3) && key3 !== except)
21
- __defProp(to, key3, { get: () => from[key3], enumerable: !(desc = __getOwnPropDesc(from, key3)) || desc.enumerable });
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 React9 = require("react");
507
+ var React10 = require("react");
508
508
  var Scheduler = require_scheduler();
509
- var ReactSharedInternals = React9.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
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
- React9.Children.forEach(props.children, function(child) {
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, key3) {
2510
- return prefix2 + key3.charAt(0).toUpperCase() + key3.substring(1);
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 key3 in styles) {
2660
- var longhands = shorthandToLonghand[key3] || [key3];
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]] = key3;
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 key3 in expandedUpdates) {
2676
- var originalKey = expandedUpdates[key3];
2677
- var correctOriginalKey = expandedStyles[key3];
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 key3 in props) {
3349
- var isValid = validateProperty(type, key3);
3348
+ for (var key2 in props) {
3349
+ var isValid = validateProperty(type, key2);
3350
3350
  if (!isValid) {
3351
- invalidProps.push(key3);
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 key3 in props) {
3492
- var isValid = validateProperty$1(type, key3, props[key3], eventRegistry);
3491
+ for (var key2 in props) {
3492
+ var isValid = validateProperty$1(type, key2, props[key2], eventRegistry);
3493
3493
  if (!isValid) {
3494
- unknownProps.push(key3);
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(key3) {
3800
- return key3._reactInternals;
3799
+ function get(key2) {
3800
+ return key2._reactInternals;
3801
3801
  }
3802
- function has(key3) {
3803
- return key3._reactInternals !== void 0;
3802
+ function has(key2) {
3803
+ return key2._reactInternals !== void 0;
3804
3804
  }
3805
- function set(key3, value) {
3806
- key3._reactInternals = value;
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, key3, map) {
5381
+ function attemptReplayContinuousQueuedEventInMap(queuedEvent, key2, map) {
5382
5382
  if (attemptReplayContinuousQueuedEvent(queuedEvent)) {
5383
- map.delete(key3);
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 key3 = normalizeKey[nativeEvent.key] || nativeEvent.key;
5980
- if (key3 !== "Unidentified") {
5981
- return key3;
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 key3 in contextTypes) {
9037
- context[key3] = unmaskedContext[key3];
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, key3) {
10143
+ function updateFragment2(returnFiber, current3, fragment, lanes, key2) {
10144
10144
  if (current3 === null || current3.tag !== Fragment) {
10145
- var created = createFiberFromFragment(fragment, returnFiber.mode, lanes, key3);
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 key3 = oldFiber !== null ? oldFiber.key : null;
10194
+ var key2 = oldFiber !== null ? oldFiber.key : null;
10195
10195
  if (typeof newChild === "string" && newChild !== "" || typeof newChild === "number") {
10196
- if (key3 !== null) {
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 === key3) {
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 === key3) {
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 (key3 !== null) {
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 key3 = child.key;
10281
- if (typeof key3 !== "string") {
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(key3);
10286
+ knownKeys.add(key2);
10287
10287
  break;
10288
10288
  }
10289
- if (!knownKeys.has(key3)) {
10290
- knownKeys.add(key3);
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.", key3);
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 key3 = element.key;
10541
+ var key2 = element.key;
10542
10542
  var child = currentFirstChild;
10543
10543
  while (child !== null) {
10544
- if (child.key === key3) {
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 key3 = portal.key;
10594
+ var key2 = portal.key;
10595
10595
  var child = currentFirstChild;
10596
10596
  while (child !== null) {
10597
- if (child.key === key3) {
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, subscribe) {
11932
+ function mountMutableSource(source, getSnapshot, subscribe2) {
11933
11933
  {
11934
11934
  return void 0;
11935
11935
  }
11936
11936
  }
11937
- function updateMutableSource(source, getSnapshot, subscribe) {
11937
+ function updateMutableSource(source, getSnapshot, subscribe2) {
11938
11938
  {
11939
11939
  return void 0;
11940
11940
  }
11941
11941
  }
11942
- function mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) {
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, subscribe), [subscribe]);
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(subscribe, getSnapshot, getServerSnapshot) {
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, subscribe), [subscribe]);
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, subscribe) {
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 subscribe(handleStoreChange);
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, subscribe) {
12640
+ useMutableSource: function(source, getSnapshot, subscribe2) {
12641
12641
  currentHookNameInDev = "useMutableSource";
12642
12642
  mountHookTypesDev();
12643
12643
  return mountMutableSource();
12644
12644
  },
12645
- useSyncExternalStore: function(subscribe, getSnapshot, getServerSnapshot) {
12645
+ useSyncExternalStore: function(subscribe2, getSnapshot, getServerSnapshot) {
12646
12646
  currentHookNameInDev = "useSyncExternalStore";
12647
12647
  mountHookTypesDev();
12648
- return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
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, subscribe) {
12744
+ useMutableSource: function(source, getSnapshot, subscribe2) {
12745
12745
  currentHookNameInDev = "useMutableSource";
12746
12746
  updateHookTypesDev();
12747
12747
  return mountMutableSource();
12748
12748
  },
12749
- useSyncExternalStore: function(subscribe, getSnapshot, getServerSnapshot) {
12749
+ useSyncExternalStore: function(subscribe2, getSnapshot, getServerSnapshot) {
12750
12750
  currentHookNameInDev = "useSyncExternalStore";
12751
12751
  updateHookTypesDev();
12752
- return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
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, subscribe) {
12848
+ useMutableSource: function(source, getSnapshot, subscribe2) {
12849
12849
  currentHookNameInDev = "useMutableSource";
12850
12850
  updateHookTypesDev();
12851
12851
  return updateMutableSource();
12852
12852
  },
12853
- useSyncExternalStore: function(subscribe, getSnapshot, getServerSnapshot) {
12853
+ useSyncExternalStore: function(subscribe2, getSnapshot, getServerSnapshot) {
12854
12854
  currentHookNameInDev = "useSyncExternalStore";
12855
12855
  updateHookTypesDev();
12856
- return updateSyncExternalStore(subscribe, getSnapshot);
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, subscribe) {
12952
+ useMutableSource: function(source, getSnapshot, subscribe2) {
12953
12953
  currentHookNameInDev = "useMutableSource";
12954
12954
  updateHookTypesDev();
12955
12955
  return updateMutableSource();
12956
12956
  },
12957
- useSyncExternalStore: function(subscribe, getSnapshot, getServerSnapshot) {
12957
+ useSyncExternalStore: function(subscribe2, getSnapshot, getServerSnapshot) {
12958
12958
  currentHookNameInDev = "useSyncExternalStore";
12959
12959
  updateHookTypesDev();
12960
- return updateSyncExternalStore(subscribe, getSnapshot);
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, subscribe) {
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(subscribe, getSnapshot, getServerSnapshot) {
13076
+ useSyncExternalStore: function(subscribe2, getSnapshot, getServerSnapshot) {
13077
13077
  currentHookNameInDev = "useSyncExternalStore";
13078
13078
  warnInvalidHookAccess();
13079
13079
  mountHookTypesDev();
13080
- return mountSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
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, subscribe) {
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(subscribe, getSnapshot, getServerSnapshot) {
13197
+ useSyncExternalStore: function(subscribe2, getSnapshot, getServerSnapshot) {
13198
13198
  currentHookNameInDev = "useSyncExternalStore";
13199
13199
  warnInvalidHookAccess();
13200
13200
  updateHookTypesDev();
13201
- return updateSyncExternalStore(subscribe, getSnapshot);
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, subscribe) {
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(subscribe, getSnapshot, getServerSnapshot) {
13318
+ useSyncExternalStore: function(subscribe2, getSnapshot, getServerSnapshot) {
13319
13319
  currentHookNameInDev = "useSyncExternalStore";
13320
13320
  warnInvalidHookAccess();
13321
13321
  updateHookTypesDev();
13322
- return updateSyncExternalStore(subscribe, getSnapshot);
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 key3 = callerName + "_" + callback;
13483
- if (!didWarnOnInvalidCallback.has(key3)) {
13484
- didWarnOnInvalidCallback.add(key3);
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 snapshot = instance.getSnapshotBeforeUpdate(finishedWork.elementType === finishedWork.type ? prevProps : resolveDefaultProps(finishedWork.type, prevProps), prevState);
16896
+ var snapshot2 = instance.getSnapshotBeforeUpdate(finishedWork.elementType === finishedWork.type ? prevProps : resolveDefaultProps(finishedWork.type, prevProps), prevState);
16897
16897
  {
16898
16898
  var didWarnSet = didWarnAboutUndefinedSnapshotBeforeUpdate;
16899
- if (snapshot === void 0 && !didWarnSet.has(finishedWork.type)) {
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 = snapshot;
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, key3, mode) {
20262
+ function FiberNode(tag, pendingProps, key2, mode) {
20263
20263
  this.tag = tag;
20264
- this.key = key3;
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, key3, mode) {
20306
- return new FiberNode(tag, pendingProps, key3, mode);
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, key3, pendingProps, owner, mode, lanes) {
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, key3);
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, key3);
20476
+ return createFiberFromProfiler(pendingProps, mode, lanes, key2);
20477
20477
  case REACT_SUSPENSE_TYPE:
20478
- return createFiberFromSuspense(pendingProps, mode, lanes, key3);
20478
+ return createFiberFromSuspense(pendingProps, mode, lanes, key2);
20479
20479
  case REACT_SUSPENSE_LIST_TYPE:
20480
- return createFiberFromSuspenseList(pendingProps, mode, lanes, key3);
20480
+ return createFiberFromSuspenseList(pendingProps, mode, lanes, key2);
20481
20481
  case REACT_OFFSCREEN_TYPE:
20482
- return createFiberFromOffscreen(pendingProps, mode, lanes, key3);
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, key3, mode);
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 key3 = element.key;
20546
+ var key2 = element.key;
20547
20547
  var pendingProps = element.props;
20548
- var fiber = createFiberFromTypeAndProps(type, key3, pendingProps, owner, mode, lanes);
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, key3) {
20556
- var fiber = createFiber(Fragment, elements, key3, mode);
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, key3) {
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, key3, mode | ProfileMode);
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, key3) {
20578
- var fiber = createFiber(SuspenseComponent, pendingProps, key3, mode);
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, key3) {
20584
- var fiber = createFiber(SuspenseListComponent, pendingProps, key3, mode);
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, key3) {
20590
- var fiber = createFiber(OffscreenComponent, pendingProps, key3, mode);
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 key3 = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : null;
20734
+ var key2 = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : null;
20735
20735
  {
20736
- checkKeyStringCoercion(key3);
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: key3 == null ? null : "" + key3,
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 key3 = path[index2];
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(key3, 1);
20973
+ updated.splice(key2, 1);
20974
20974
  } else {
20975
- delete updated[key3];
20975
+ delete updated[key2];
20976
20976
  }
20977
20977
  return updated;
20978
20978
  }
20979
- updated[key3] = copyWithDeleteImpl(obj[key3], path, index2 + 1);
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 key3 = path[index2];
21025
+ var key2 = path[index2];
21026
21026
  var updated = isArray(obj) ? obj.slice() : assign({}, obj);
21027
- updated[key3] = copyWithSetImpl(obj[key3], path, index2 + 1, value);
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 key3 = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : null;
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, key3);
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 import_react12 = __toESM(require("react"), 1);
21681
+ var import_react14 = __toESM(require("react"), 1);
21682
21682
 
21683
21683
  // src/view.js
21684
- var import_react10 = __toESM(require("react"), 1);
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:12px;--canvas-gap:16px;--canvas-positive:#167456;--canvas-negative:#b13b3b;--canvas-warning:#875b15}
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"], "Numeric result with units", "tone"),
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"], "Exact supplied or derived values"),
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 = /\s*(?:(\d+(?:\.\d*)?|\.\d+)([eE][+-]?\d+)?|("(?:[^"\\]|\\.)*")|([a-zA-Z][a-zA-Z0-9_]*(?:\.[a-zA-Z][a-zA-Z0-9_]*)?)|(===|!==|<=|>=|==|!=|[+*/()?,:<>-]))/y;
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" && /^(state|data|derived|item)\.[a-zA-Z][a-zA-Z0-9_]*$/.test(t)) out = { ref: t };
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" || !/^(state|data|derived)\.[a-zA-Z][a-zA-Z0-9_]{0,63}$/.test(ref)) fail("invalid reference");
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" && !finite(evaluated.resolveValue(n.value))) fail("metric requires a numeric value");
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 (!key(k)) fail(`invalid key in ${group}`);
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 (!["number", "string", "boolean"].includes(s.type)) fail(`unsupported state type ${k}`);
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 (!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`);
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 || !key(k) || itemRows.some((row) => !own(row, k) || !scalar(row[k]))) fail("invalid or unscoped item reference");
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) || !key(n.id) || ids.has(n.id)) fail("node ids must be unique identifiers");
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");
@@ -22250,7 +22262,8 @@ function validateDocument(input) {
22250
22262
  break;
22251
22263
  case "details":
22252
22264
  text(n.title, "details title");
22253
- if (n.open !== void 0 && typeof n.open !== "boolean") fail("details open must be boolean");
22265
+ if (n.open === "true" || n.open === "false") n.open = n.open === "true";
22266
+ if (n.open !== void 0 && typeof n.open !== "boolean") fail(`node.${n.id}.open must be boolean true or false`);
22254
22267
  break;
22255
22268
  case "badge":
22256
22269
  value(n.text, "badge text");
@@ -22262,12 +22275,16 @@ function validateDocument(input) {
22262
22275
  if (n.unit !== void 0) text(n.unit, "progress unit");
22263
22276
  break;
22264
22277
  case "steps": {
22265
- if (!Array.isArray(n.items) || !n.items.length || n.items.length > 12) fail("steps require 1..12 items");
22266
- for (const item of n.items) {
22267
- fields(item, ["title", "description", "status"], "step");
22268
- text(item.title, "step title");
22269
- if (item.description !== void 0) text(item.description, "step description");
22270
- if (!["pending", "active", "done", "error"].includes(item.status)) fail("unknown step status");
22278
+ if (object(n.items) && Object.keys(n.items).length === 1 && Array.isArray(n.items.item)) n.items = n.items.item;
22279
+ const at = `node.${n.id}.items`;
22280
+ if (!Array.isArray(n.items)) fail(`${at} must be an array of 1..12 step objects, received ${n.items === null ? "null" : typeof n.items}. Use items:[{"title":"First step","description":"One sentence"}], not items:{item:[...]}. status is optional for a static guide`);
22281
+ if (!n.items.length || n.items.length > 12) fail(`${at} requires 1..12 items; received ${n.items.length}. Split a longer guide into separate steps nodes`);
22282
+ for (const [i, item] of n.items.entries()) {
22283
+ const stepAt = `${at}[${i}]`;
22284
+ fields(item, ["title", "description", "status"], stepAt);
22285
+ text(item.title, `${stepAt}.title`);
22286
+ if (item.description !== void 0) text(item.description, `${stepAt}.description`);
22287
+ if (item.status !== void 0 && !["pending", "active", "done", "error"].includes(item.status)) fail(`${stepAt}.status must be pending, active, done or error; omit status for a static guide`);
22271
22288
  }
22272
22289
  break;
22273
22290
  }
@@ -22290,6 +22307,7 @@ function validateDocument(input) {
22290
22307
  const [, k] = reference(doc, n.bind), spec = doc.state[k];
22291
22308
  if (n.type === "slider" && spec.type !== "number") fail("slider requires numeric state");
22292
22309
  if (n.type === "toggle" && spec.type !== "boolean") fail("toggle requires boolean state");
22310
+ 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
22311
  if (n.type === "input" && spec.type === "boolean") fail("use toggle for boolean state");
22294
22312
  if (n.type === "select" && !spec.options) fail("select requires options");
22295
22313
  break;
@@ -22299,13 +22317,13 @@ function validateDocument(input) {
22299
22317
  if (!own(doc.actions, n.action)) fail("unknown action");
22300
22318
  break;
22301
22319
  case "table": {
22302
- 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');
22303
- value(n.rows, "table rows");
22320
+ if (n.label !== void 0) text(n.label, "table label");
22321
+ if (!Array.isArray(n.rows)) value(n.rows, "table rows");
22304
22322
  if (!Array.isArray(n.columns) || !n.columns.length || n.columns.length > 16) fail("invalid table columns");
22305
22323
  const cols = /* @__PURE__ */ new Set();
22306
22324
  for (const c of n.columns) {
22307
22325
  fields(c, ["key", "label", "unit"], "column");
22308
- if (!key(c.key) || cols.has(c.key)) fail("invalid or duplicate column key");
22326
+ if (!validIdentifier(c.key) || cols.has(c.key)) fail("invalid or duplicate column key");
22309
22327
  cols.add(c.key);
22310
22328
  text(c.label, "column label");
22311
22329
  if (c.unit !== void 0) text(c.unit, "column unit");
@@ -22313,8 +22331,8 @@ function validateDocument(input) {
22313
22331
  break;
22314
22332
  }
22315
22333
  case "chart":
22316
- value(n.rows, "chart rows");
22317
- if (!["bar", "line"].includes(n.kind) || !key(n.labelKey) || !key(n.valueKey)) fail("invalid chart");
22334
+ if (!Array.isArray(n.rows)) value(n.rows, "chart rows");
22335
+ if (!["bar", "line"].includes(n.kind) || !validIdentifier(n.labelKey) || !validIdentifier(n.valueKey)) fail("invalid chart");
22318
22336
  text(n.label, "chart label");
22319
22337
  if (n.unit !== void 0) text(n.unit, "chart unit");
22320
22338
  if (n.xScale !== void 0 && (!["category", "linear"].includes(n.xScale) || n.xScale === "linear" && n.kind !== "line")) fail("invalid xScale");
@@ -22378,9 +22396,9 @@ var import_react2 = require("react");
22378
22396
 
22379
22397
  // src/state-channel.js
22380
22398
  var listeners = /* @__PURE__ */ new Map();
22381
- var key2 = (id, sessionId) => id + "\0" + sessionId;
22399
+ var key = (id, sessionId) => id + "\0" + sessionId;
22382
22400
  function subscribeState(id, sessionId, fn) {
22383
- const k = key2(id, sessionId), set = listeners.get(k) ?? /* @__PURE__ */ new Set();
22401
+ const k = key(id, sessionId), set = listeners.get(k) ?? /* @__PURE__ */ new Set();
22384
22402
  listeners.set(k, set);
22385
22403
  set.add(fn);
22386
22404
  return () => {
@@ -22389,7 +22407,7 @@ function subscribeState(id, sessionId, fn) {
22389
22407
  };
22390
22408
  }
22391
22409
  function broadcastState(id, sessionId, saved, origin) {
22392
- for (const fn of listeners.get(key2(id, sessionId)) ?? []) if (fn !== origin) fn(saved);
22410
+ for (const fn of listeners.get(key(id, sessionId)) ?? []) if (fn !== origin) fn(saved);
22393
22411
  }
22394
22412
 
22395
22413
  // src/saved-state.js
@@ -22538,6 +22556,40 @@ function useSavedState(record, sessionId, preview = false) {
22538
22556
  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
22557
  }
22540
22558
 
22559
+ // lib/tool-json.js
22560
+ function clean(source) {
22561
+ let input = source.trim().replace(/^\uFEFF/, "");
22562
+ const fence = input.match(/^```(?:json)?\s*\n([\s\S]*?)\n```$/i);
22563
+ if (fence) input = fence[1];
22564
+ let output = "", quoted = false, escaped = false;
22565
+ for (let i = 0; i < input.length; i++) {
22566
+ const c = input[i];
22567
+ if (quoted) {
22568
+ output += c;
22569
+ if (escaped) escaped = false;
22570
+ else if (c === "\\") escaped = true;
22571
+ else if (c === '"') quoted = false;
22572
+ continue;
22573
+ }
22574
+ if (c === '"') quoted = true;
22575
+ if (c === "," && /^\s*[}\]]/.test(input.slice(i + 1))) continue;
22576
+ output += c;
22577
+ }
22578
+ return output;
22579
+ }
22580
+ function toolJson(value, field, maxBytes = 131072) {
22581
+ if (typeof value !== "string") return value;
22582
+ if (new TextEncoder().encode(value).length > maxBytes) throw new Error(`DSH UI: ${field} JSON exceeds size limit`);
22583
+ const source = clean(value);
22584
+ try {
22585
+ return JSON.parse(source);
22586
+ } catch (error) {
22587
+ const position = error.message.match(/position (\d+)/)?.[1];
22588
+ const location = position === void 0 ? "" : ` at line ${source.slice(0, Number(position)).split("\n").length}, column ${Number(position) - source.lastIndexOf("\n", Number(position) - 1)}`;
22589
+ 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.`);
22590
+ }
22591
+ }
22592
+
22541
22593
  // lib/stream.js
22542
22594
  function parseToolArguments(raw) {
22543
22595
  if (typeof raw !== "string" || raw.length > LIMITS.bytes || new TextEncoder().encode(raw).length > LIMITS.bytes) return null;
@@ -22629,7 +22681,7 @@ function previewDocument(raw) {
22629
22681
  const root = parseToolArguments(raw);
22630
22682
  if (!root) return null;
22631
22683
  const document2 = root.members?.get("document");
22632
- if (document2?.complete && typeof document2.value === "string" && root.members.size === 1) return validateDocument(JSON.parse(document2.value));
22684
+ if (document2?.complete && typeof document2.value === "string" && root.members.size === 1) return validateDocument(toolJson(document2.value, "document"));
22633
22685
  if (!document2?.members) return null;
22634
22686
  if ([...root.members.keys()].some((k) => k !== "document")) return null;
22635
22687
  const doc = { ...document2.value }, nodes = document2.members.get("nodes");
@@ -22698,12 +22750,13 @@ function updatePreview(html) {
22698
22750
  morph(document.getElementById("canvas"), template.content);
22699
22751
  }
22700
22752
  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>`;
22753
+ 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
22754
  }
22703
22755
 
22704
22756
  // src/canvas-preview.js
22705
22757
  var h2 = import_react3.default.createElement;
22706
22758
  function CanvasPreview({ node }) {
22759
+ const [height, setHeight] = (0, import_react3.useState)(node.height ?? 420);
22707
22760
  const frame = (0, import_react3.useRef)(null), latest = (0, import_react3.useRef)(node);
22708
22761
  latest.current = node;
22709
22762
  const config = (0, import_react3.useMemo)(() => {
@@ -22728,14 +22781,22 @@ function CanvasPreview({ node }) {
22728
22781
  observer.observe(document.body, { attributes: true });
22729
22782
  return () => observer.disconnect();
22730
22783
  }, []);
22731
- 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: node.height ?? 420, border: 0, pointerEvents: "none" } }));
22784
+ (0, import_react3.useEffect)(() => {
22785
+ const receive = (event) => {
22786
+ const m = event.data;
22787
+ 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))));
22788
+ };
22789
+ window.addEventListener("message", receive);
22790
+ return () => window.removeEventListener("message", receive);
22791
+ }, [config]);
22792
+ 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
22793
  }
22733
22794
 
22734
22795
  // src/sandbox.js
22735
- var import_react4 = __toESM(require("react"), 1);
22796
+ var import_react6 = __toESM(require("react"), 1);
22736
22797
 
22737
22798
  // 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';
22799
+ 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 === "true" || n.open === "false") n.open = n.open === "true";\n if (n.open !== void 0 && typeof n.open !== "boolean") fail(`node.${n.id}.open must be boolean true or false`);\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 (object(n.items) && Object.keys(n.items).length === 1 && Array.isArray(n.items.item)) n.items = n.items.item;\n const at = `node.${n.id}.items`;\n if (!Array.isArray(n.items)) fail(`${at} must be an array of 1..12 step objects, received ${n.items === null ? "null" : typeof n.items}. Use items:[{"title":"First step","description":"One sentence"}], not items:{item:[...]}. status is optional for a static guide`);\n if (!n.items.length || n.items.length > 12) fail(`${at} requires 1..12 items; received ${n.items.length}. Split a longer guide into separate steps nodes`);\n for (const [i, item] of n.items.entries()) {\n const stepAt = `${at}[${i}]`;\n fields(item, ["title", "description", "status"], stepAt);\n text(item.title, `${stepAt}.title`);\n if (item.description !== void 0) text(item.description, `${stepAt}.description`);\n if (item.status !== void 0 && !["pending", "active", "done", "error"].includes(item.status)) fail(`${stepAt}.status must be pending, active, done or error; omit status for a static guide`);\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
22800
 
22740
22801
  // lib/canvas-export.js
22741
22802
  function standaloneCanvas(document2, node, state, theme = {}) {
@@ -22746,18 +22807,64 @@ function standaloneCanvas(document2, node, state, theme = {}) {
22746
22807
  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
22808
  }
22748
22809
 
22810
+ // src/view-settings.js
22811
+ var import_react4 = require("react");
22812
+ var scope;
22813
+ function configureViewSettings(value) {
22814
+ scope = value;
22815
+ }
22816
+ var subscribe = (fn) => scope?.subscribe(fn) ?? (() => {
22817
+ });
22818
+ var snapshot = () => scope?.getSnapshot()?.value?.showDetails === true;
22819
+ function useViewDetails() {
22820
+ return (0, import_react4.useSyncExternalStore)(subscribe, snapshot, () => false);
22821
+ }
22822
+
22823
+ // src/action-menu.js
22824
+ var import_react5 = __toESM(require("react"), 1);
22825
+ function ActionMenu({ label, children }) {
22826
+ const [open, setOpen] = (0, import_react5.useState)(false), root = (0, import_react5.useRef)(null), button = (0, import_react5.useRef)(null);
22827
+ (0, import_react5.useEffect)(() => {
22828
+ if (!open) return;
22829
+ const outside = (e) => {
22830
+ if (!root.current?.contains(e.target)) setOpen(false);
22831
+ };
22832
+ const escape = (e) => {
22833
+ if (e.key === "Escape") {
22834
+ setOpen(false);
22835
+ button.current?.focus();
22836
+ }
22837
+ };
22838
+ document.addEventListener("pointerdown", outside);
22839
+ document.addEventListener("keydown", escape);
22840
+ return () => {
22841
+ document.removeEventListener("pointerdown", outside);
22842
+ document.removeEventListener("keydown", escape);
22843
+ };
22844
+ }, [open]);
22845
+ return import_react5.default.createElement(
22846
+ "div",
22847
+ { className: "dgui-action-menu", ref: root },
22848
+ import_react5.default.createElement("button", { ref: button, type: "button", className: "dgui-menu-trigger", "aria-label": label, "aria-expanded": open, onClick: () => setOpen(!open) }, "\u22EF"),
22849
+ open && import_react5.default.createElement("div", { className: "dgui-menu-content", "aria-label": label, onClick: (e) => {
22850
+ if (e.target.closest("button")) setOpen(false);
22851
+ } }, children)
22852
+ );
22853
+ }
22854
+
22749
22855
  // src/sandbox.js
22750
- var h3 = import_react4.default.createElement;
22856
+ var h3 = import_react6.default.createElement;
22751
22857
  var randomToken = () => Array.from(crypto.getRandomValues(new Uint8Array(16)), (b) => b.toString(16).padStart(2, "0")).join("");
22752
22858
  function Sandbox({ node, document: doc, state, data, derived, disabled, preview, update, onAudit }) {
22753
- const frame = (0, import_react4.useRef)(null), latest = (0, import_react4.useRef)(null), connected = (0, import_react4.useRef)(false), loads = (0, import_react4.useRef)(0), visible = (0, import_react4.useRef)(true), errorKind = (0, import_react4.useRef)("");
22754
- const [error, setError] = (0, import_react4.useState)(""), [stopped, setStopped] = (0, import_react4.useState)(false), [generation, setGeneration] = (0, import_react4.useState)(0);
22755
- const [height, setHeight] = (0, import_react4.useState)(node.height ?? 420);
22756
- const [token, setToken] = (0, import_react4.useState)(0);
22757
- const [mounted, setMounted] = (0, import_react4.useState)(false);
22859
+ const showDetails = useViewDetails();
22860
+ 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)("");
22861
+ const [error, setError] = (0, import_react6.useState)(""), [stopped, setStopped] = (0, import_react6.useState)(false), [generation, setGeneration] = (0, import_react6.useState)(0);
22862
+ const [height, setHeight] = (0, import_react6.useState)(node.height ?? 420);
22863
+ const [token, setToken] = (0, import_react6.useState)(0);
22864
+ const [mounted, setMounted] = (0, import_react6.useState)(false);
22758
22865
  const sourceKey = JSON.stringify(node);
22759
- const config = (0, import_react4.useMemo)(() => ({ channel: randomToken(), nonce: randomToken() }), [sourceKey, generation]);
22760
- const srcDoc = (0, import_react4.useMemo)(() => sandboxDocument(node, config.channel, config.nonce), [sourceKey, config]);
22866
+ const config = (0, import_react6.useMemo)(() => ({ channel: randomToken(), nonce: randomToken() }), [sourceKey, generation]);
22867
+ const srcDoc = (0, import_react6.useMemo)(() => sandboxDocument(node, config.channel, config.nonce), [sourceKey, config]);
22761
22868
  latest.current = { node, state, data, derived, disabled, update, onAudit };
22762
22869
  const publish = () => {
22763
22870
  const el = frame.current, current2 = latest.current;
@@ -22767,7 +22874,7 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
22767
22874
  theme.scheme = document.body.hasAttribute("data-ds-dark-theme") || el.closest("[data-preview-theme=dark]") ? "dark" : "light";
22768
22875
  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
22876
  };
22770
- (0, import_react4.useEffect)(() => {
22877
+ (0, import_react6.useEffect)(() => {
22771
22878
  if (preview || stopped) return;
22772
22879
  connected.current = false;
22773
22880
  loads.current = 0;
@@ -22795,7 +22902,7 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
22795
22902
  setToken((t) => t + 1);
22796
22903
  } else if (m.type === "mounted" && connected.current) setMounted(true);
22797
22904
  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 > 0) setHeight(Math.max(160, Math.min(SANDBOX_LIMITS.height, Math.ceil(m.payload))));
22905
+ 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
22906
  else if (m.type === "error") {
22800
22907
  errorKind.current = "runtime";
22801
22908
  setError(typeof m.payload === "string" ? m.payload.slice(0, 1e3) : "\u753B\u5E03\u8FD0\u884C\u5F02\u5E38");
@@ -22841,7 +22948,7 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
22841
22948
  intersection.disconnect();
22842
22949
  };
22843
22950
  }, [config, preview, stopped]);
22844
- (0, import_react4.useEffect)(() => {
22951
+ (0, import_react6.useEffect)(() => {
22845
22952
  publish();
22846
22953
  }, [state, data, derived, disabled, config, token]);
22847
22954
  const inactive = preview || stopped;
@@ -22867,6 +22974,13 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
22867
22974
  return h3(
22868
22975
  "section",
22869
22976
  { className: "dgui-canvas", "data-ui-node": node.id, "data-canvas-phase": inactive ? stopped ? "stopped" : "preview" : error ? "error" : mounted ? "ready" : "loading", "aria-label": node.title },
22977
+ !preview && !showDetails && h3(
22978
+ ActionMenu,
22979
+ { label: `${node.title}\u64CD\u4F5C` },
22980
+ h3("button", { type: "button", disabled: disabled || !doc || stopped, onClick: download }, "\u5BFC\u51FA\u72EC\u7ACB HTML"),
22981
+ h3("button", { type: "button", disabled, onClick: restart }, stopped ? "\u6062\u590D\u4EA4\u4E92" : "\u91CD\u7F6E\u753B\u5E03"),
22982
+ !stopped && h3("button", { type: "button", onClick: () => setStopped(true) }, "\u505C\u6B62\u753B\u5E03")
22983
+ ),
22870
22984
  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
22985
  "div",
22872
22986
  { className: "dgui-canvas-stage", style: { minHeight: mounted || error ? void 0 : Math.min(height, 420) } },
@@ -22879,7 +22993,8 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
22879
22993
  }, 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
22994
  ),
22881
22995
  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(
22996
+ error && !showDetails && h3("p", { className: "dgui-error" }, node.fallback),
22997
+ showDetails && h3(
22883
22998
  "details",
22884
22999
  { className: "dgui-canvas-options" },
22885
23000
  h3("summary", null, "\u8BF4\u660E\u4E0E\u64CD\u4F5C"),
@@ -22891,13 +23006,13 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
22891
23006
  }
22892
23007
 
22893
23008
  // lib/build-info.js
22894
- var BUILD_INFO = Object.freeze({ "version": "0.5.3", "id": "0.5.3+634080c7e02a", "sourceHash": "634080c7e02ae0667c17a2ce4f94d8999270f1827b7735058deee989caa7777a" });
23009
+ var BUILD_INFO = Object.freeze({ "version": "0.5.5", "id": "0.5.5+0671fce5ef19", "sourceHash": "0671fce5ef19378d59bbd2347ee2cdd7bb0ce1880e30b6ff2c50ecafa41ac438" });
22895
23010
 
22896
23011
  // lib/refinement.js
22897
23012
  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
23013
 
22899
23014
  // src/current-document.js
22900
- var import_react5 = require("react");
23015
+ var import_react7 = require("react");
22901
23016
  var current = /* @__PURE__ */ new Map();
22902
23017
  var listeners2 = /* @__PURE__ */ new Set();
22903
23018
  function publishDocument(raw) {
@@ -22908,9 +23023,9 @@ function publishDocument(raw) {
22908
23023
  listeners2.forEach((fn) => fn());
22909
23024
  }
22910
23025
  function useCurrentDocument(raw, sessionId) {
22911
- const [, wake] = (0, import_react5.useState)(0);
22912
- const [attempt, retry] = (0, import_react5.useState)(0), [load, setLoad] = (0, import_react5.useState)({ status: "loading" });
22913
- (0, import_react5.useEffect)(() => {
23026
+ const [, wake] = (0, import_react7.useState)(0);
23027
+ const [attempt, retry] = (0, import_react7.useState)(0), [load, setLoad] = (0, import_react7.useState)({ status: "loading" });
23028
+ (0, import_react7.useEffect)(() => {
22914
23029
  if (!raw.documentId || !sessionId) return;
22915
23030
  const notify = () => wake((v) => v + 1);
22916
23031
  listeners2.add(notify);
@@ -22936,10 +23051,10 @@ function useCurrentDocument(raw, sessionId) {
22936
23051
  }
22937
23052
 
22938
23053
  // src/history-view.js
22939
- var import_react6 = __toESM(require("react"), 1);
22940
- var h4 = import_react6.default.createElement;
23054
+ var import_react8 = __toESM(require("react"), 1);
23055
+ var h4 = import_react8.default.createElement;
22941
23056
  function HistoryView({ record, sessionId }) {
22942
- const [versions, setVersions] = (0, import_react6.useState)(null), [error, setError] = (0, import_react6.useState)(""), [busy, setBusy] = (0, import_react6.useState)(false), [preview, setPreview] = (0, import_react6.useState)(null);
23057
+ 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
23058
  const url = "/api/plugins/dsh-generative-ui/history?" + new URLSearchParams({ documentId: record.documentId, sessionId });
22944
23059
  async function request2(options) {
22945
23060
  const r = await fetch(url, { credentials: "same-origin", ...options }), value = await r.json();
@@ -23006,11 +23121,11 @@ function HistoryView({ record, sessionId }) {
23006
23121
  }
23007
23122
 
23008
23123
  // src/presentation.js
23009
- var import_react9 = __toESM(require("react"), 1);
23124
+ var import_react11 = __toESM(require("react"), 1);
23010
23125
  var import_react_dom = __toESM(require_react_dom(), 1);
23011
23126
 
23012
23127
  // src/presentation-store.js
23013
- var import_react7 = require("react");
23128
+ var import_react9 = require("react");
23014
23129
  var records = /* @__PURE__ */ new Map();
23015
23130
  var listeners3 = /* @__PURE__ */ new Set();
23016
23131
  var locations = /* @__PURE__ */ new Map();
@@ -23035,7 +23150,7 @@ var subscribeUi = (fn) => {
23035
23150
  return () => listeners3.delete(fn);
23036
23151
  };
23037
23152
  function useUiRegistry() {
23038
- (0, import_react7.useSyncExternalStore)(subscribeUi, () => revision, () => 0);
23153
+ (0, import_react9.useSyncExternalStore)(subscribeUi, () => revision, () => 0);
23039
23154
  return uiRecords();
23040
23155
  }
23041
23156
  function setPanelOpener(fn) {
@@ -23063,10 +23178,10 @@ function removeMarkerLocation(id, host) {
23063
23178
  }
23064
23179
  }
23065
23180
  var markerLocation = (id) => locations.get(id);
23066
- function usePresentation(scope) {
23067
- const [, wake] = (0, import_react7.useState)(0);
23068
- (0, import_react7.useEffect)(() => scope?.subscribe(() => wake((v) => v + 1)), [scope]);
23069
- return scope?.getSnapshot().value?.displayMode ?? "tail";
23181
+ function usePresentation(scope2) {
23182
+ const [, wake] = (0, import_react9.useState)(0);
23183
+ (0, import_react9.useEffect)(() => scope2?.subscribe(() => wake((v) => v + 1)), [scope2]);
23184
+ return scope2?.getSnapshot().value?.displayMode ?? "tail";
23070
23185
  }
23071
23186
 
23072
23187
  // src/markers.js
@@ -23127,11 +23242,11 @@ function startUiMarkers(root, sessionId) {
23127
23242
  }
23128
23243
 
23129
23244
  // src/presentation-owner.js
23130
- var import_react8 = require("react");
23245
+ var import_react10 = require("react");
23131
23246
  var roots = /* @__PURE__ */ new WeakMap();
23132
23247
  function usePresentationOwner(anchor, documentId, sessionId) {
23133
- const [owner, setOwner] = (0, import_react8.useState)(false);
23134
- (0, import_react8.useEffect)(() => {
23248
+ const [owner, setOwner] = (0, import_react10.useState)(false);
23249
+ (0, import_react10.useEffect)(() => {
23135
23250
  const element = anchor.current;
23136
23251
  if (!element) return;
23137
23252
  const root = element.closest("[data-conversation-scroll]") ?? element.parentElement;
@@ -23141,11 +23256,11 @@ function usePresentationOwner(anchor, documentId, sessionId) {
23141
23256
  documents = /* @__PURE__ */ new Map();
23142
23257
  roots.set(root, documents);
23143
23258
  }
23144
- const key3 = sessionId + ":" + documentId;
23145
- let entries = documents.get(key3);
23259
+ const key2 = sessionId + ":" + documentId;
23260
+ let entries = documents.get(key2);
23146
23261
  if (!entries) {
23147
23262
  entries = /* @__PURE__ */ new Set();
23148
- documents.set(key3, entries);
23263
+ documents.set(key2, entries);
23149
23264
  }
23150
23265
  const entry = { element, update: setOwner };
23151
23266
  entries.add(entry);
@@ -23161,23 +23276,24 @@ function usePresentationOwner(anchor, documentId, sessionId) {
23161
23276
  return () => {
23162
23277
  entries.delete(entry);
23163
23278
  elect();
23164
- if (!entries.size) documents.delete(key3);
23279
+ if (!entries.size) documents.delete(key2);
23165
23280
  };
23166
23281
  }, [anchor, documentId, sessionId]);
23167
23282
  return owner;
23168
23283
  }
23169
23284
 
23170
23285
  // src/presentation.js
23171
- var h5 = import_react9.default.createElement;
23286
+ var h5 = import_react11.default.createElement;
23172
23287
  var scanners = /* @__PURE__ */ new WeakMap();
23173
23288
  var focused = /* @__PURE__ */ new Map();
23174
- function PresentationView({ raw, sessionId, sendPrompt, scope }) {
23175
- const anchor = (0, import_react9.useRef)(null), records2 = useUiRegistry(), mode = usePresentation(scope), host = markerLocation(raw.documentId);
23289
+ function PresentationView({ raw, sessionId, sendPrompt, scope: scope2 }) {
23290
+ const showDetails = useViewDetails();
23291
+ const anchor = (0, import_react11.useRef)(null), records2 = useUiRegistry(), mode = usePresentation(scope2), host = markerLocation(raw.documentId);
23176
23292
  const owner = usePresentationOwner(anchor, raw.documentId, sessionId);
23177
- (0, import_react9.useEffect)(() => {
23293
+ (0, import_react11.useEffect)(() => {
23178
23294
  rememberUi(raw, sessionId, sendPrompt);
23179
23295
  }, [raw, sessionId, sendPrompt]);
23180
- (0, import_react9.useEffect)(() => {
23296
+ (0, import_react11.useEffect)(() => {
23181
23297
  const root = anchor.current?.closest("[data-conversation-scroll]");
23182
23298
  if (!root) return;
23183
23299
  let entry = scanners.get(root);
@@ -23198,7 +23314,7 @@ function PresentationView({ raw, sessionId, sendPrompt, scope }) {
23198
23314
  }
23199
23315
  };
23200
23316
  }, [sessionId]);
23201
- (0, import_react9.useEffect)(() => {
23317
+ (0, import_react11.useEffect)(() => {
23202
23318
  const block = host?.uiMarkerBlock;
23203
23319
  if (!block || !owner) return;
23204
23320
  const previous = block.style.display;
@@ -23208,7 +23324,7 @@ function PresentationView({ raw, sessionId, sendPrompt, scope }) {
23208
23324
  };
23209
23325
  }, [host, mode, owner]);
23210
23326
  const available = panelAvailable();
23211
- (0, import_react9.useEffect)(() => {
23327
+ (0, import_react11.useEffect)(() => {
23212
23328
  if (owner && mode === "sidebar" && available) openUiPanel(raw.documentId, sessionId);
23213
23329
  }, [mode, available, sessionId, raw.documentId, owner]);
23214
23330
  const content = h5(ValidatedView, { raw, fallback: raw.document.fallback, sessionId, sendPrompt });
@@ -23217,12 +23333,12 @@ function PresentationView({ raw, sessionId, sendPrompt, scope }) {
23217
23333
  { ref: anchor, "data-dgui-presentation": raw.documentId },
23218
23334
  owner && available && h5("button", { type: "button", className: "dgui-secondary", onClick: () => openUiPanel(raw.documentId, sessionId) }, "\u5728\u4FA7\u680F\u6253\u5F00"),
23219
23335
  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")
23336
+ 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
23337
  );
23222
23338
  }
23223
23339
  function UiPanel({ sessionId, sendPrompt }) {
23224
- const records2 = useUiRegistry().filter((r) => r.sessionId === sessionId), [selected, setSelected] = (0, import_react9.useState)(focused.get(sessionId));
23225
- (0, import_react9.useEffect)(() => subscribeUi(() => setSelected(focused.get(sessionId))), [sessionId]);
23340
+ const records2 = useUiRegistry().filter((r) => r.sessionId === sessionId), [selected, setSelected] = (0, import_react11.useState)(focused.get(sessionId));
23341
+ (0, import_react11.useEffect)(() => subscribeUi(() => setSelected(focused.get(sessionId))), [sessionId]);
23226
23342
  const record = records2.find((r) => r.raw.documentId === selected) ?? records2.at(-1);
23227
23343
  return h5(
23228
23344
  "div",
@@ -23240,11 +23356,11 @@ function focusUi(id, sessionId) {
23240
23356
  }
23241
23357
 
23242
23358
  // src/view.js
23243
- var h6 = import_react10.default.createElement;
23359
+ var h6 = import_react12.default.createElement;
23244
23360
  var display = (value) => value === void 0 || value === null ? "\u2014" : typeof value === "object" ? JSON.stringify(value) : String(value);
23245
23361
  function NumericInput({ id, spec, value, onChange, invalidChanged, disabled }) {
23246
- const [draft, setDraft] = (0, import_react10.useState)(String(value)), [invalid, setInvalid] = (0, import_react10.useState)(false);
23247
- (0, import_react10.useEffect)(() => {
23362
+ const [draft, setDraft] = (0, import_react12.useState)(String(value)), [invalid, setInvalid] = (0, import_react12.useState)(false);
23363
+ (0, import_react12.useEffect)(() => {
23248
23364
  setDraft(String(value));
23249
23365
  setInvalid(false);
23250
23366
  invalidChanged(id, false);
@@ -23268,15 +23384,17 @@ function NumericInput({ id, spec, value, onChange, invalidChanged, disabled }) {
23268
23384
  }
23269
23385
  });
23270
23386
  }
23271
- function Table({ rows, columns, id }) {
23387
+ function Table({ rows, columns, id, label }) {
23272
23388
  return h6("div", { className: "dgui-table-wrap" }, h6(
23273
23389
  "table",
23274
23390
  { "data-ui-node": id },
23391
+ label && h6("caption", null, label),
23275
23392
  h6("thead", null, h6("tr", null, columns.map((c) => h6("th", { key: c.key, scope: "col" }, c.label, c.unit ? ` (${c.unit})` : "")))),
23276
23393
  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
23394
  ));
23278
23395
  }
23279
23396
  function Chart({ node, rows }) {
23397
+ const [showData, setShowData] = (0, import_react12.useState)(false);
23280
23398
  const data = rows.slice(0, 40), values = data.map((r) => r[node.valueKey]);
23281
23399
  const low = node.kind === "line" && values.length ? Math.min(...values) : Math.min(0, ...values);
23282
23400
  const high = node.kind === "line" && values.length ? Math.max(...values) : Math.max(0, ...values), range = high - low || 1;
@@ -23289,7 +23407,7 @@ function Chart({ node, rows }) {
23289
23407
  return h6(
23290
23408
  "figure",
23291
23409
  { 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})`)),
23410
+ 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
23411
  h6("div", { className: "dgui-plot", tabIndex: 0, role: "region", "aria-label": `${node.label}\u56FE\u8868\uFF0C\u53EF\u6A2A\u5411\u6EDA\u52A8` }, h6(
23294
23412
  "svg",
23295
23413
  { 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 +23422,15 @@ function Chart({ node, rows }) {
23304
23422
  (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
23423
  ))
23306
23424
  )),
23307
- h6("small", { className: "dgui-chart-hint" }, "\u7A84\u5C4F\u53EF\u6A2A\u5411\u6ED1\u52A8\u56FE\u8868\uFF1B\u5C55\u5F00\u4E0B\u65B9\u6570\u636E\u53EF\u67E5\u770B\u7CBE\u786E\u503C\u3002"),
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` }))
23425
+ 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
23426
  );
23311
23427
  }
23312
23428
  function UiView({ record, sessionId, sendPrompt, preview = false }) {
23429
+ const showDetails = useViewDetails();
23313
23430
  const doc = record.document;
23314
- const viewId = import_react10.default.useId();
23315
- const root = (0, import_react10.useRef)(null), canvasAudits = (0, import_react10.useRef)(/* @__PURE__ */ new Map()), [audit, setAudit] = (0, import_react10.useState)(null), auditPending = (0, import_react10.useRef)(0);
23316
- const collectAudit = import_react10.default.useCallback(() => {
23431
+ const viewId = import_react12.default.useId();
23432
+ 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);
23433
+ const collectAudit = import_react12.default.useCallback(() => {
23317
23434
  clearTimeout(auditPending.current);
23318
23435
  auditPending.current = setTimeout(() => {
23319
23436
  if (!root.current || preview) return;
@@ -23325,7 +23442,7 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
23325
23442
  });
23326
23443
  }, 250);
23327
23444
  }, [record.documentId, record.documentRevision, sessionId, preview]);
23328
- (0, import_react10.useEffect)(() => {
23445
+ (0, import_react12.useEffect)(() => {
23329
23446
  canvasAudits.current.clear();
23330
23447
  collectAudit();
23331
23448
  window.addEventListener("resize", collectAudit);
@@ -23343,22 +23460,22 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
23343
23460
  collectAudit();
23344
23461
  };
23345
23462
  const { state, setState, ready, status, issue, epoch, retry, useRemote, keepLocal } = useSavedState(record, sessionId, preview);
23346
- const [error, setError] = (0, import_react10.useState)(""), [actionStatus, setActionStatus] = (0, import_react10.useState)("");
23347
- const [busy, setBusy] = (0, import_react10.useState)(false), [invalidFields, setInvalidFields] = (0, import_react10.useState)({});
23348
- const pending = (0, import_react10.useRef)(false);
23349
- (0, import_react10.useEffect)(() => {
23463
+ const [error, setError] = (0, import_react12.useState)(""), [actionStatus, setActionStatus] = (0, import_react12.useState)("");
23464
+ const [busy, setBusy] = (0, import_react12.useState)(false), [invalidFields, setInvalidFields] = (0, import_react12.useState)({});
23465
+ const pending = (0, import_react12.useRef)(false);
23466
+ (0, import_react12.useEffect)(() => {
23350
23467
  setInvalidFields({});
23351
23468
  }, [epoch]);
23352
- const invalidChanged = import_react10.default.useCallback((id, invalid) => setInvalidFields((previous) => previous[id] === invalid ? previous : { ...previous, [id]: invalid }), []);
23469
+ const invalidChanged = import_react12.default.useCallback((id, invalid) => setInvalidFields((previous) => previous[id] === invalid ? previous : { ...previous, [id]: invalid }), []);
23353
23470
  let computed;
23354
23471
  try {
23355
23472
  computed = evaluate(doc, state);
23356
23473
  } catch (e) {
23357
23474
  computed = { error: e.message };
23358
23475
  }
23359
- const currentState = (0, import_react10.useRef)(state);
23476
+ const currentState = (0, import_react12.useRef)(state);
23360
23477
  currentState.current = state;
23361
- (0, import_react10.useEffect)(() => {
23478
+ (0, import_react12.useEffect)(() => {
23362
23479
  collectAudit();
23363
23480
  }, [state, ready, collectAudit]);
23364
23481
  const updatePatch = (patch) => {
@@ -23368,9 +23485,9 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
23368
23485
  setError("");
23369
23486
  setActionStatus("");
23370
23487
  };
23371
- const update = (key3, value) => {
23488
+ const update = (key2, value) => {
23372
23489
  try {
23373
- updatePatch({ [key3]: value });
23490
+ updatePatch({ [key2]: value });
23374
23491
  } catch (e) {
23375
23492
  setError(e.message);
23376
23493
  }
@@ -23417,10 +23534,10 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
23417
23534
  return h6("div", { ...props, className: "dgui-progress" }, h6("div", { className: "dgui-progress-label" }, h6("span", null, h6(Icon, { name: n.icon ?? "gauge" }), n.label), h6("span", null, `${display(v)} / ${display(max)}${n.unit ? " " + n.unit : ""}`)), !computed.error && h6("progress", { value: v, max, "aria-label": n.label }), h6("small", null, !computed.error ? `${Number((v / max * 100).toFixed(1))}%` : "\u2014"));
23418
23535
  }
23419
23536
  case "steps":
23420
- 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)))));
23537
+ 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), item.status && 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
23538
  case "metric": {
23422
23539
  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) : "\u2014", " ", h6("small", null, n.unit)));
23540
+ 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
23541
  }
23425
23542
  case "input":
23426
23543
  case "slider":
@@ -23430,7 +23547,7 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
23430
23547
  let control;
23431
23548
  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
23549
  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(import_react10.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)));
23550
+ 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
23551
  else if (spec.type === "number") control = h6(NumericInput, { id, spec, value: v, disabled: !ready, invalidChanged, onChange: (value) => update(k, value) });
23435
23552
  else control = h6("input", { id, type: "text", value: v, maxLength: 8192, disabled: !ready, onChange: (e) => update(k, e.target.value) });
23436
23553
  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 +23555,7 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
23438
23555
  case "button":
23439
23556
  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
23557
  case "table":
23441
- return computed.error ? null : h6(Table, { key: n.id, id: n.id, rows: resolve(n.rows), columns: n.columns });
23558
+ return computed.error ? null : h6(Table, { key: n.id, id: n.id, label: n.label, rows: resolve(n.rows), columns: n.columns });
23442
23559
  case "chart":
23443
23560
  return computed.error ? null : h6(Chart, { key: n.id, node: n, rows: resolve(n.rows) });
23444
23561
  default:
@@ -23451,12 +23568,12 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
23451
23568
  { 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
23569
  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
23570
  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}`)),
23571
+ (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
23572
  issue && h6(
23456
23573
  "div",
23457
23574
  { className: "dgui-recovery" },
23458
23575
  issue.kind === "conflict" ? h6(
23459
- import_react10.default.Fragment,
23576
+ import_react12.default.Fragment,
23460
23577
  null,
23461
23578
  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
23579
  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 +23581,12 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
23464
23581
  ),
23465
23582
  (error || computed.error) && h6("p", { className: "dgui-error", role: "alert" }, error || computed.error),
23466
23583
  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)))
23584
+ 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")),
23585
+ showDetails && !preview && h6(HistoryView, { record, sessionId }),
23586
+ 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
23587
  );
23471
23588
  }
23472
- var UiBoundary = class extends import_react10.default.Component {
23589
+ var UiBoundary = class extends import_react12.default.Component {
23473
23590
  state = { failed: false };
23474
23591
  static getDerivedStateFromError() {
23475
23592
  return { failed: true };
@@ -23482,7 +23599,7 @@ function ToolView(props) {
23482
23599
  if (props.phase === "preparing") return h6(StreamingToolView, props);
23483
23600
  if (props.phase === "start") return h6(StreamingPreview, { raw: props.block?.argsRaw ?? "", callId: props.callId, sessionId: props.sessionId });
23484
23601
  const fallback = (props.block.content ?? []).filter((x) => x.type === "text").map((x) => x.text).join("\n");
23485
- if (props.block.isError) return h6("div", { className: "dgui-root dgui-error", role: "alert" }, "\u754C\u9762\u751F\u6210\u5931\u8D25", h6("pre", null, fallback));
23602
+ if (props.block.isError) return h6("div", { className: "dgui-tool-error", role: "alert" }, h6(Icon, { name: "warning" }), h6("span", null, fallback || "\u754C\u9762\u672A\u751F\u6210\uFF0C\u8BF7\u68C0\u67E5\u5DE5\u5177\u53C2\u6570\u3002"));
23486
23603
  const raw = props.block.meta?.dshGenerativeUi;
23487
23604
  if (raw?.version === 1) return h6("div", { className: "dgui-pending" }, "\u4EA4\u4E92\u754C\u9762\u5DF2\u751F\u6210\uFF0C\u8BF7\u5728\u672C\u8F6E\u56DE\u7B54\u4E0B\u65B9\u64CD\u4F5C\u3002", h6("details", null, h6("summary", null, "\u6587\u5B57\u7ED3\u679C"), h6("pre", null, fallback)));
23488
23605
  return h6(ValidatedView, { ...props, raw, fallback });
@@ -23493,9 +23610,9 @@ function StreamingToolView(props) {
23493
23610
  }
23494
23611
  function StreamingPreview({ raw, callId = "stream", sessionId }) {
23495
23612
  const committed = useUiRegistry().some((r) => r.sessionId === sessionId && r.raw.callId === callId);
23496
- const deferred = import_react10.default.useDeferredValue(raw);
23497
- const doc = (0, import_react10.useMemo)(() => previewDocument(deferred), [deferred]);
23498
- const canvas = (0, import_react10.useMemo)(() => doc ? null : previewCanvas(deferred), [doc, deferred]);
23613
+ const deferred = import_react12.default.useDeferredValue(raw);
23614
+ const doc = (0, import_react12.useMemo)(() => previewDocument(deferred), [deferred]);
23615
+ const canvas = (0, import_react12.useMemo)(() => doc ? null : previewCanvas(deferred), [doc, deferred]);
23499
23616
  if (committed) return h6("p", { className: "dgui-copy" }, "\u754C\u9762\u5DF2\u751F\u6210\u3002");
23500
23617
  if (canvas) return h6("div", { className: "dgui-root", "data-preview": true }, h6(CanvasPreview, { node: canvas }));
23501
23618
  if (!doc) return h6("div", { className: "dgui-pending", role: "status" }, "\u6B63\u5728\u7EC4\u7EC7\u5E76\u6821\u9A8C\u4EA4\u4E92\u754C\u9762\u2026");
@@ -23505,7 +23622,7 @@ function TurnUiView(props) {
23505
23622
  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
23623
  }
23507
23624
  function PatchNotice({ raw }) {
23508
- (0, import_react10.useEffect)(() => {
23625
+ (0, import_react12.useEffect)(() => {
23509
23626
  try {
23510
23627
  if (raw) publishDocument(raw);
23511
23628
  } catch {
@@ -23515,7 +23632,7 @@ function PatchNotice({ raw }) {
23515
23632
  }
23516
23633
  function ValidatedView({ raw, fallback, sessionId, sendPrompt }) {
23517
23634
  const { record: current2, status, retry } = useCurrentDocument(raw ?? {}, sessionId);
23518
- const result = (0, import_react10.useMemo)(() => {
23635
+ const result = (0, import_react12.useMemo)(() => {
23519
23636
  try {
23520
23637
  if (!current2 || current2.version !== 1 || typeof current2.documentId !== "string" || typeof current2.callId !== "string") return null;
23521
23638
  return { ...current2, document: validateDocument(current2.document) };
@@ -23525,7 +23642,7 @@ function ValidatedView({ raw, fallback, sessionId, sendPrompt }) {
23525
23642
  }, [current2]);
23526
23643
  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
23644
  return h6(
23528
- import_react10.default.Fragment,
23645
+ import_react12.default.Fragment,
23529
23646
  null,
23530
23647
  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
23648
  status === "loading" && h6("p", { className: "dgui-copy", role: "status" }, "\u6B63\u5728\u8BFB\u53D6\u6700\u65B0\u754C\u9762\u7248\u672C\u2026"),
@@ -23553,8 +23670,8 @@ var turnUiDefinition = {
23553
23670
  const fallback = (event.data.message.content ?? []).filter((c) => c.type === "text").map((c) => c.text).join("\n");
23554
23671
  return { ...context.state, records: [...context.state.records, { seq: event.seq, raw, fallback, ...isPatch ? { isPatch: true } : {} }] };
23555
23672
  },
23556
- buildLocationData(context, scope, previous) {
23557
- if (scope !== "turn" || !context.state) return null;
23673
+ buildLocationData(context, scope2, previous) {
23674
+ if (scope2 !== "turn" || !context.state) return null;
23558
23675
  if (previous?.key === "dshGenerativeUi" && previous.value === context.state.records) return previous;
23559
23676
  return { kind: "turn", turn: context.state.turn, key: "dshGenerativeUi", value: context.state.records };
23560
23677
  }
@@ -23588,8 +23705,31 @@ var CANVAS_CSS = `
23588
23705
  .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
23706
  `;
23590
23707
 
23708
+ // src/soft-styles.js
23709
+ var SOFT_CSS = `
23710
+ .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)}
23711
+ .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))}
23712
+ .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)))}
23713
+ .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}
23714
+ .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))}
23715
+ .dgui-root[data-layout=report] .dgui-card{padding:16px 18px;border:1px solid var(--du-line);border-radius:18px}
23716
+ .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)))}
23717
+ .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))}
23718
+ .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}
23719
+ .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}
23720
+ .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))}
23721
+ .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))}
23722
+ .dgui-root[data-layout=status] .dgui-header{border-radius:23px 23px 0 0;background:linear-gradient(120deg,var(--du-tint),var(--du-soft))}
23723
+ .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)))}
23724
+ .dgui-root .dgui-content>:last-child{margin-bottom:0}.dgui-root .dgui-canvas-stage iframe{border-radius:16px}
23725
+ @media(max-width:600px){.dgui-root{--du-radius:22px;--du-radius-inner:18px}}
23726
+ @media(forced-colors:active){.dgui-root,.dgui-root .dgui-card,.dgui-root .dgui-metric,.dgui-root .dgui-chart,.dgui-root .dgui-button{background:Canvas}}
23727
+ .dgui-tool-error{display:flex;align-items:flex-start;gap:8px;padding:8px 12px;border-radius:12px;background:color-mix(in srgb,currentColor 4%,transparent);font-size:13px;line-height:1.5;overflow-wrap:anywhere;white-space:pre-wrap}.dgui-tool-error>svg{flex:0 0 16px;width:16px;height:16px;margin-top:2px}
23728
+ `;
23729
+
23591
23730
  // src/styles.js
23592
23731
  var CSS = `
23732
+ .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
23733
  .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
23734
  .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
23735
  .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 +23752,29 @@ body[data-ds-dark-theme] .dgui-root,.dgui-root[data-preview-theme=dark]{--du-acc
23612
23752
  .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
23753
  .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
23754
  [data-dgui-presentation]>.dgui-secondary{margin:8px 0}[data-dgui-marker]{min-width:0}
23615
- `;
23755
+ ` + SOFT_CSS;
23616
23756
 
23617
23757
  // src/settings.js
23618
- var import_react11 = __toESM(require("react"), 1);
23619
- var h7 = import_react11.default.createElement;
23620
- function ModeSettings({ scope }) {
23621
- const [snapshot, setSnapshot] = (0, import_react11.useState)(() => scope.getSnapshot()), [busy, setBusy] = (0, import_react11.useState)(false), [message, setMessage] = (0, import_react11.useState)(""), pending = (0, import_react11.useRef)(false);
23622
- (0, import_react11.useEffect)(() => scope.subscribe(() => setSnapshot(scope.getSnapshot())), [scope]);
23623
- const ready = snapshot.status === "ready" && snapshot.value !== void 0;
23624
- async function change(mode, key3 = "designMode") {
23758
+ var import_react13 = __toESM(require("react"), 1);
23759
+ var h7 = import_react13.default.createElement;
23760
+ function ModeSettings({ scope: scope2 }) {
23761
+ 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);
23762
+ (0, import_react13.useEffect)(() => scope2.subscribe(() => setSnapshot(scope2.getSnapshot())), [scope2]);
23763
+ const ready = snapshot2.status === "ready" && snapshot2.value !== void 0;
23764
+ async function change(mode, key2 = "designMode") {
23625
23765
  if (pending.current || !ready) return;
23626
23766
  pending.current = true;
23627
23767
  setBusy(true);
23628
23768
  setMessage("");
23629
23769
  try {
23630
- await scope.mutate([{ op: "set", path: [key3], value: mode }], scope.getSnapshot().revision);
23631
- const actual = scope.getSnapshot();
23770
+ await scope2.mutate([{ op: "set", path: [key2], value: mode }], scope2.getSnapshot().revision);
23771
+ const actual = scope2.getSnapshot();
23632
23772
  setSnapshot(actual);
23633
- if (actual.status !== "ready" || actual.value?.[key3] !== mode) throw new Error("\u8BBE\u7F6E\u672A\u4FDD\u5B58\uFF0C\u53EF\u80FD\u53D1\u751F\u914D\u7F6E\u51B2\u7A81\uFF0C\u8BF7\u91CD\u8BD5\u3002");
23634
- setMessage(key3 === "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");
23773
+ 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");
23774
+ 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
23775
  } catch (e) {
23636
23776
  setMessage(e.message ?? "\u6A21\u5F0F\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002");
23637
- setSnapshot(scope.getSnapshot());
23777
+ setSnapshot(scope2.getSnapshot());
23638
23778
  } finally {
23639
23779
  pending.current = false;
23640
23780
  setBusy(false);
@@ -23645,14 +23785,16 @@ function ModeSettings({ scope }) {
23645
23785
  { className: "dgui-root dgui-settings", "aria-label": "DSH Motion UI \u8BBE\u7F6E" },
23646
23786
  h7("h3", null, "DSH Motion UI"),
23647
23787
  h7("label", { htmlFor: "dgui-design-mode" }, "\u8BBE\u8BA1\u6A21\u5F0F"),
23648
- h7("select", { id: "dgui-design-mode", value: snapshot.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")),
23788
+ 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
23789
  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
23790
  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
23791
  h7("label", { htmlFor: "dgui-display-mode" }, "\u754C\u9762\u5C55\u793A\u4F4D\u7F6E"),
23652
- h7("select", { id: "dgui-display-mode", value: snapshot.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")),
23792
+ 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
23793
  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"),
23794
+ 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"),
23795
+ 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
23796
  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" }, snapshot.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"),
23797
+ !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
23798
  message && h7("p", { role: "status" }, message)
23657
23799
  );
23658
23800
  }
@@ -23660,13 +23802,14 @@ function ModeSettings({ scope }) {
23660
23802
  // src/client.jsx
23661
23803
  var inject = ["slots", "sessions", "conversation", "uiConversation", "configForms"];
23662
23804
  function apply(ctx) {
23663
- const scope = ctx.configForms.get("motion-ui");
23664
- ctx.slots.inject("plugins.bundle.config", () => ctx.slots.register({ name: "plugins.bundle.config", key: "dsh-motion-ui" }, (props) => import_react12.default.createElement(ModeSettings, { ...props, scope })));
23805
+ const scope2 = ctx.configForms.get("motion-ui");
23806
+ configureViewSettings(scope2);
23807
+ 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
23808
  ctx.uiConversation.events.register(turnUiDefinition);
23666
23809
  ctx.slots.inject("conversation.chat.turnTail", () => ctx.slots.register({
23667
23810
  name: "conversation.chat.turnTail",
23668
23811
  id: "dsh-generative-ui",
23669
- inject: (sessionId) => ({ presentationScope: scope, sendPrompt: (prompt) => ctx.sessions.scope(sessionId).get("conversation").send(prompt) })
23812
+ inject: (sessionId) => ({ presentationScope: scope2, sendPrompt: (prompt) => ctx.sessions.scope(sessionId).get("conversation").send(prompt) })
23670
23813
  }, TurnUiView));
23671
23814
  ctx.effect(() => {
23672
23815
  const style = document.createElement("style");