dsh-motion-ui 0.5.2 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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_react11 = __toESM(require("react"), 1);
21681
+ var import_react14 = __toESM(require("react"), 1);
21682
21682
 
21683
21683
  // src/view.js
21684
- var import_react9 = __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,11 +21770,14 @@ 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
+ .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))}
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)}}
21778
21781
  @media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}}`;
21779
21782
 
21780
21783
  // lib/sandbox.js
@@ -21838,13 +21841,13 @@ var COMPONENTS = Object.freeze({
21838
21841
  badge: define(["text"], "Short explicit status label", "tone"),
21839
21842
  progress: define(["label", "value", "max", "unit"], "Declared numeric progress snapshot", "tone"),
21840
21843
  steps: define(["items"], "Ordered declared steps"),
21841
- 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"),
21842
21845
  input: define(["label", "bind"], "String or numeric state input"),
21843
21846
  slider: define(["label", "bind"], "Numeric state control"),
21844
21847
  select: define(["label", "bind"], "Selection from declared state options"),
21845
21848
  toggle: define(["label", "bind"], "Boolean state control"),
21846
21849
  button: define(["text", "action"], "Declared Agent follow-up", "icon"),
21847
- 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"),
21848
21851
  chart: define(["kind", "rows", "labelKey", "valueKey", "label", "unit", "xScale"], "Bar/line comparison with accessible data"),
21849
21852
  sandbox: define(["title", "html", "css", "script", "fallback", "height", "stateKeys", "dataKeys", "derivedKeys"], "Freeform isolated HTML/SVG/CSS/JavaScript visualization")
21850
21853
  });
@@ -21853,6 +21856,11 @@ function componentFields(type) {
21853
21856
  return c && ["id", "type", ...c.fields, ...c.presentation ? ["icon"] : [], ...c.presentation === "tone" ? ["tone"] : []];
21854
21857
  }
21855
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
+
21856
21864
  // lib/author-expression.js
21857
21865
  function compileExpression(source) {
21858
21866
  const fail2 = () => {
@@ -21861,7 +21869,7 @@ function compileExpression(source) {
21861
21869
  if (typeof source !== "string" || !source.trim() || source.length > 2048) fail2();
21862
21870
  const tokens = [];
21863
21871
  let offset = 0;
21864
- 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");
21865
21873
  while (offset < source.length) {
21866
21874
  if (!source.slice(offset).trim()) break;
21867
21875
  token.lastIndex = offset;
@@ -21888,7 +21896,7 @@ function compileExpression(source) {
21888
21896
  } else if (t === "-" || t === "+") {
21889
21897
  const arg = parse(5, depth + 1);
21890
21898
  out = t === "-" ? { op: "sub", args: [{ const: 0 }, arg] } : arg;
21891
- } 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 };
21892
21900
  else if (["min", "max", "round", "abs"].includes(t)) {
21893
21901
  take("(");
21894
21902
  const args = [parse(0, depth + 1)];
@@ -21947,7 +21955,6 @@ var fail = (message) => {
21947
21955
  throw new Error(`DSH UI: ${message}`);
21948
21956
  };
21949
21957
  var object = (x) => x !== null && typeof x === "object" && !Array.isArray(x);
21950
- var key = (x) => typeof x === "string" && /^[a-zA-Z][a-zA-Z0-9_]{0,63}$/.test(x) && !["constructor", "prototype", "__proto__"].includes(x);
21951
21958
  var finite = (x) => typeof x === "number" && Number.isFinite(x);
21952
21959
  var scalar = (x) => typeof x === "string" || typeof x === "boolean" || finite(x);
21953
21960
  var text = (x, at) => {
@@ -21994,6 +22001,10 @@ function validateState(doc, state) {
21994
22001
  if (!finite(v) || v < s.min || v > s.max) fail(`state.${k} is outside its numeric range`);
21995
22002
  const offset = (v - s.min) / s.step;
21996
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`);
21997
22008
  } else if (s.type === "string") text(v, `state.${k}`);
21998
22009
  else if (typeof v !== "boolean") fail(`state.${k} must be boolean`);
21999
22010
  if (s.options && !s.options.includes(v)) fail(`invalid option for state.${k}`);
@@ -22003,7 +22014,7 @@ function validateState(doc, state) {
22003
22014
  }
22004
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] };
22005
22016
  function reference(doc, ref) {
22006
- 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`);
22007
22018
  const [group, k] = ref.split(".");
22008
22019
  if (!own(doc[group], k)) fail(`unknown reference ${ref}`);
22009
22020
  return [group, k];
@@ -22114,7 +22125,7 @@ function checkViewValues(doc, evaluated) {
22114
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");
22115
22126
  if (n.type === "chart" && n.xScale === "linear" && rows.some((r) => !finite(r[n.labelKey]))) fail("linear chart requires numeric x values");
22116
22127
  }
22117
- 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`);
22118
22129
  if (n.type === "progress") {
22119
22130
  const v = evaluated.resolveValue(n.value), max = evaluated.resolveValue(n.max);
22120
22131
  if (!finite(v) || !finite(max) || max <= 0 || v < 0 || v > max) fail("progress requires 0 <= value <= positive max");
@@ -22142,11 +22153,13 @@ function validateDocument(input) {
22142
22153
  for (const group of ["state", "data", "derived", "actions"]) {
22143
22154
  doc[group] ??= {};
22144
22155
  if (!object(doc[group]) || Object.keys(doc[group]).length > 64) fail(`invalid ${group}`);
22145
- 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`);
22146
22157
  }
22147
22158
  for (const [k, s] of Object.entries(doc.state)) {
22148
22159
  fields(s, ["type", "default", "min", "max", "step", "options"], `state.${k}`);
22149
- 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`);
22150
22163
  if (s.type === "number") {
22151
22164
  if (![s.min, s.max, s.step].every(finite) || s.min >= s.max || s.step <= 0) fail(`invalid numeric limits for ${k}`);
22152
22165
  if ((s.max - s.min) / s.step > 1e9) fail(`numeric step too small for ${k}`);
@@ -22169,7 +22182,7 @@ function validateDocument(input) {
22169
22182
  if (!Array.isArray(rows) || rows.length > LIMITS.rows || !rows.every(object)) fail("map source must be object rows");
22170
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");
22171
22184
  for (const [k2, value2] of Object.entries(e.map.fields)) {
22172
- 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`);
22173
22186
  validateExpression(value2, depth + 1, rows);
22174
22187
  }
22175
22188
  return;
@@ -22183,7 +22196,7 @@ function validateDocument(input) {
22183
22196
  fields(e, ["ref"], "expression");
22184
22197
  if (typeof e.ref === "string" && e.ref.startsWith("item.")) {
22185
22198
  const k = e.ref.slice(5);
22186
- 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");
22187
22200
  } else reference(doc, e.ref);
22188
22201
  return;
22189
22202
  }
@@ -22226,9 +22239,10 @@ function validateDocument(input) {
22226
22239
  if (!Array.isArray(list) || depth > LIMITS.depth) fail("invalid node children or depth");
22227
22240
  for (const n of list) {
22228
22241
  if (++count > LIMITS.nodes) fail("too many nodes");
22229
- 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");
22230
22243
  ids.add(n.id);
22231
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 };
22232
22246
  switch (n.type) {
22233
22247
  case "sandbox": {
22234
22248
  text(n.title, "canvas title");
@@ -22288,6 +22302,7 @@ function validateDocument(input) {
22288
22302
  const [, k] = reference(doc, n.bind), spec = doc.state[k];
22289
22303
  if (n.type === "slider" && spec.type !== "number") fail("slider requires numeric state");
22290
22304
  if (n.type === "toggle" && spec.type !== "boolean") fail("toggle requires boolean state");
22305
+ if (["input", "select"].includes(n.type) && spec.type === "json") fail(`node.${n.id}: structured state requires a sandbox with DSHUI.setState; use separate boolean states and toggle nodes for a native checklist`);
22291
22306
  if (n.type === "input" && spec.type === "boolean") fail("use toggle for boolean state");
22292
22307
  if (n.type === "select" && !spec.options) fail("select requires options");
22293
22308
  break;
@@ -22297,12 +22312,13 @@ function validateDocument(input) {
22297
22312
  if (!own(doc.actions, n.action)) fail("unknown action");
22298
22313
  break;
22299
22314
  case "table": {
22300
- value(n.rows, "table rows");
22315
+ if (n.label !== void 0) text(n.label, "table label");
22316
+ if (!Array.isArray(n.rows)) value(n.rows, "table rows");
22301
22317
  if (!Array.isArray(n.columns) || !n.columns.length || n.columns.length > 16) fail("invalid table columns");
22302
22318
  const cols = /* @__PURE__ */ new Set();
22303
22319
  for (const c of n.columns) {
22304
22320
  fields(c, ["key", "label", "unit"], "column");
22305
- if (!key(c.key) || cols.has(c.key)) fail("invalid or duplicate column key");
22321
+ if (!validIdentifier(c.key) || cols.has(c.key)) fail("invalid or duplicate column key");
22306
22322
  cols.add(c.key);
22307
22323
  text(c.label, "column label");
22308
22324
  if (c.unit !== void 0) text(c.unit, "column unit");
@@ -22310,8 +22326,8 @@ function validateDocument(input) {
22310
22326
  break;
22311
22327
  }
22312
22328
  case "chart":
22313
- value(n.rows, "chart rows");
22314
- if (!["bar", "line"].includes(n.kind) || !key(n.labelKey) || !key(n.valueKey)) fail("invalid chart");
22329
+ if (!Array.isArray(n.rows)) value(n.rows, "chart rows");
22330
+ if (!["bar", "line"].includes(n.kind) || !validIdentifier(n.labelKey) || !validIdentifier(n.valueKey)) fail("invalid chart");
22315
22331
  text(n.label, "chart label");
22316
22332
  if (n.unit !== void 0) text(n.unit, "chart unit");
22317
22333
  if (n.xScale !== void 0 && (!["category", "linear"].includes(n.xScale) || n.xScale === "linear" && n.kind !== "line")) fail("invalid xScale");
@@ -22375,9 +22391,9 @@ var import_react2 = require("react");
22375
22391
 
22376
22392
  // src/state-channel.js
22377
22393
  var listeners = /* @__PURE__ */ new Map();
22378
- var key2 = (id, sessionId) => id + "\0" + sessionId;
22394
+ var key = (id, sessionId) => id + "\0" + sessionId;
22379
22395
  function subscribeState(id, sessionId, fn) {
22380
- const k = key2(id, sessionId), set = listeners.get(k) ?? /* @__PURE__ */ new Set();
22396
+ const k = key(id, sessionId), set = listeners.get(k) ?? /* @__PURE__ */ new Set();
22381
22397
  listeners.set(k, set);
22382
22398
  set.add(fn);
22383
22399
  return () => {
@@ -22386,7 +22402,7 @@ function subscribeState(id, sessionId, fn) {
22386
22402
  };
22387
22403
  }
22388
22404
  function broadcastState(id, sessionId, saved, origin) {
22389
- for (const fn of listeners.get(key2(id, sessionId)) ?? []) if (fn !== origin) fn(saved);
22405
+ for (const fn of listeners.get(key(id, sessionId)) ?? []) if (fn !== origin) fn(saved);
22390
22406
  }
22391
22407
 
22392
22408
  // src/saved-state.js
@@ -22495,10 +22511,10 @@ function useSavedState(record, sessionId, preview = false) {
22495
22511
  const timer = setTimeout(async () => {
22496
22512
  r.saving = true;
22497
22513
  if (r.alive) setStatus("\u6B63\u5728\u4FDD\u5B58\u53C2\u6570\u2026");
22498
- const revision = r.revision;
22514
+ const revision2 = r.revision;
22499
22515
  try {
22500
- const saved = checked(await request(STATE_URL, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ documentId: record.documentId, sessionId, revision, state }) }));
22501
- if (saved.revision !== revision + 1 || JSON.stringify(saved.state) !== signature) throw new Error("Unexpected save response");
22516
+ const saved = checked(await request(STATE_URL, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ documentId: record.documentId, sessionId, revision: revision2, state }) }));
22517
+ if (saved.revision !== revision2 + 1 || JSON.stringify(saved.state) !== signature) throw new Error("Unexpected save response");
22502
22518
  r.revision = saved.revision;
22503
22519
  r.saved = signature;
22504
22520
  broadcastState(record.documentId, sessionId, saved, receive.current);
@@ -22535,6 +22551,40 @@ function useSavedState(record, sessionId, preview = false) {
22535
22551
  return { state: preview ? initialState(doc) : state, setState, ready: !preview && ready, status: preview ? "\u751F\u6210\u9884\u89C8 \xB7 \u5B8C\u6210\u6821\u9A8C\u540E\u53EF\u64CD\u4F5C" : status, issue, epoch, retry, useRemote: () => load(), keepLocal: () => load(true) };
22536
22552
  }
22537
22553
 
22554
+ // lib/tool-json.js
22555
+ function clean(source) {
22556
+ let input = source.trim().replace(/^\uFEFF/, "");
22557
+ const fence = input.match(/^```(?:json)?\s*\n([\s\S]*?)\n```$/i);
22558
+ if (fence) input = fence[1];
22559
+ let output = "", quoted = false, escaped = false;
22560
+ for (let i = 0; i < input.length; i++) {
22561
+ const c = input[i];
22562
+ if (quoted) {
22563
+ output += c;
22564
+ if (escaped) escaped = false;
22565
+ else if (c === "\\") escaped = true;
22566
+ else if (c === '"') quoted = false;
22567
+ continue;
22568
+ }
22569
+ if (c === '"') quoted = true;
22570
+ if (c === "," && /^\s*[}\]]/.test(input.slice(i + 1))) continue;
22571
+ output += c;
22572
+ }
22573
+ return output;
22574
+ }
22575
+ function toolJson(value, field, maxBytes = 131072) {
22576
+ if (typeof value !== "string") return value;
22577
+ if (new TextEncoder().encode(value).length > maxBytes) throw new Error(`DSH UI: ${field} JSON exceeds size limit`);
22578
+ const source = clean(value);
22579
+ try {
22580
+ return JSON.parse(source);
22581
+ } catch (error) {
22582
+ const position = error.message.match(/position (\d+)/)?.[1];
22583
+ const location = position === void 0 ? "" : ` at line ${source.slice(0, Number(position)).split("\n").length}, column ${Number(position) - source.lastIndexOf("\n", Number(position) - 1)}`;
22584
+ throw new Error(`DSH UI: ${field} must contain valid JSON${location}. Pass an object directly, not a manually escaped JSON string. Do not use single-quoted keys or raw newlines inside strings. For HTML/SVG use render_canvas with separate html/css/script fields. No partial document was saved.`);
22585
+ }
22586
+ }
22587
+
22538
22588
  // lib/stream.js
22539
22589
  function parseToolArguments(raw) {
22540
22590
  if (typeof raw !== "string" || raw.length > LIMITS.bytes || new TextEncoder().encode(raw).length > LIMITS.bytes) return null;
@@ -22626,7 +22676,7 @@ function previewDocument(raw) {
22626
22676
  const root = parseToolArguments(raw);
22627
22677
  if (!root) return null;
22628
22678
  const document2 = root.members?.get("document");
22629
- if (document2?.complete && typeof document2.value === "string" && root.members.size === 1) return validateDocument(JSON.parse(document2.value));
22679
+ if (document2?.complete && typeof document2.value === "string" && root.members.size === 1) return validateDocument(toolJson(document2.value, "document"));
22630
22680
  if (!document2?.members) return null;
22631
22681
  if ([...root.members.keys()].some((k) => k !== "document")) return null;
22632
22682
  const doc = { ...document2.value }, nodes = document2.members.get("nodes");
@@ -22695,12 +22745,13 @@ function updatePreview(html) {
22695
22745
  morph(document.getElementById("canvas"), template.content);
22696
22746
  }
22697
22747
  function previewFrameDocument(channel, nonce) {
22698
- return `<!doctype html><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none';script-src 'nonce-${nonce}';style-src 'unsafe-inline';img-src data:;base-uri 'none';form-action 'none';frame-src 'none'"><style>${CANVAS_SYSTEM_CSS}</style><style id="custom"></style><style>#canvas,#canvas *,#canvas *::before,#canvas *::after{animation:none!important;transition:none!important}html,body{overflow:hidden}</style><main id="canvas" inert></main><script nonce="${nonce}">const update=${updatePreview.toString()};addEventListener('message',e=>{if(e.source!==parent||e.data?.channel!==${JSON.stringify(channel)})return;document.getElementById('custom').textContent=e.data.css;for(const [k,v] of Object.entries(e.data.theme||{}))document.documentElement.style.setProperty('--canvas-'+k,v);document.documentElement.dataset.canvasScheme=e.data.theme?.scheme||'light';update(e.data.html)});<\/script>`;
22748
+ return `<!doctype html><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none';script-src 'nonce-${nonce}';style-src 'unsafe-inline';img-src data:;base-uri 'none';form-action 'none';frame-src 'none'"><style>${CANVAS_SYSTEM_CSS}</style><style id="custom"></style><style>#canvas,#canvas *,#canvas *::before,#canvas *::after{animation:none!important;transition:none!important}html,body{overflow:hidden}</style><main id="canvas" inert></main><script nonce="${nonce}">const update=${updatePreview.toString()};addEventListener('message',e=>{if(e.source!==parent||e.data?.channel!==${JSON.stringify(channel)})return;document.getElementById('custom').textContent=e.data.css;for(const [k,v] of Object.entries(e.data.theme||{}))document.documentElement.style.setProperty('--canvas-'+k,v);document.documentElement.dataset.canvasScheme=e.data.theme?.scheme||'light';update(e.data.html)});new ResizeObserver(()=>parent.postMessage({channel:${JSON.stringify(channel)},previewHeight:Math.ceil(document.getElementById('canvas').getBoundingClientRect().height)},'*')).observe(document.getElementById('canvas'));<\/script>`;
22699
22749
  }
22700
22750
 
22701
22751
  // src/canvas-preview.js
22702
22752
  var h2 = import_react3.default.createElement;
22703
22753
  function CanvasPreview({ node }) {
22754
+ const [height, setHeight] = (0, import_react3.useState)(node.height ?? 420);
22704
22755
  const frame = (0, import_react3.useRef)(null), latest = (0, import_react3.useRef)(node);
22705
22756
  latest.current = node;
22706
22757
  const config = (0, import_react3.useMemo)(() => {
@@ -22725,14 +22776,22 @@ function CanvasPreview({ node }) {
22725
22776
  observer.observe(document.body, { attributes: true });
22726
22777
  return () => observer.disconnect();
22727
22778
  }, []);
22728
- 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" } }));
22779
+ (0, import_react3.useEffect)(() => {
22780
+ const receive = (event) => {
22781
+ const m = event.data;
22782
+ if (event.source === frame.current?.contentWindow && m?.channel === config.channel && Number.isFinite(m.previewHeight) && m.previewHeight >= 0) setHeight(Math.max(32, Math.min(1e3, Math.ceil(m.previewHeight))));
22783
+ };
22784
+ window.addEventListener("message", receive);
22785
+ return () => window.removeEventListener("message", receive);
22786
+ }, [config]);
22787
+ return h2("section", { className: "dgui-canvas", "data-canvas-phase": "preview", "aria-label": node.title }, h2("p", { className: "dgui-copy", role: "status" }, "\u9759\u6001\u9884\u89C8 \xB7 \u63D0\u4EA4\u6210\u529F\u540E\u542F\u7528\u4EA4\u4E92"), h2("iframe", { ref: frame, title: node.title + "\uFF08\u9759\u6001\u9884\u89C8\uFF09", sandbox: "allow-scripts", referrerPolicy: "no-referrer", srcDoc, onLoad: publish, style: { display: "block", width: "100%", height, border: 0, pointerEvents: "none" } }));
22729
22788
  }
22730
22789
 
22731
22790
  // src/sandbox.js
22732
- var import_react4 = __toESM(require("react"), 1);
22791
+ var import_react6 = __toESM(require("react"), 1);
22733
22792
 
22734
22793
  // lib/export-runtime-bundle.js
22735
- 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@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 value(n.rows, "table rows");\n if (!Array.isArray(n.columns) || !n.columns.length || n.columns.length > 16) fail("invalid table columns");\n const cols = /* @__PURE__ */ new Set();\n for (const c of n.columns) {\n fields(c, ["key", "label", "unit"], "column");\n if (!key(c.key) || cols.has(c.key)) fail("invalid or duplicate column key");\n cols.add(c.key);\n text(c.label, "column label");\n if (c.unit !== void 0) text(c.unit, "column unit");\n }\n break;\n }\n case "chart":\n value(n.rows, "chart rows");\n if (!["bar", "line"].includes(n.kind) || !key(n.labelKey) || !key(n.valueKey)) fail("invalid chart");\n text(n.label, "chart label");\n if (n.unit !== void 0) text(n.unit, "chart unit");\n if (n.xScale !== void 0 && (!["category", "linear"].includes(n.xScale) || n.xScale === "linear" && n.kind !== "line")) fail("invalid xScale");\n break;\n default:\n fail(`unsupported component ${n.type}`);\n }\n if (["heading", "text", "card", "metric", "button", "badge", "progress", "details"].includes(n.type)) {\n if (n.icon !== void 0 && !UI_ICONS.includes(n.icon)) fail("unknown UI icon");\n if (n.type !== "button") {\n if (n.tone !== void 0 && !UI_TONES.includes(n.tone)) fail("unknown UI tone");\n }\n }\n fields(n, componentFields(n.type), `node.${n.id}`);\n if (["row", "column", "card", "details"].includes(n.type)) nodes(n.children, depth + 1);\n }\n }\n nodes(doc2.nodes);\n if (!count2) fail("at least one node is required");\n evaluate(doc2, defaults);\n return doc2;\n }\n\n // src/export-runtime.js\n var payload = JSON.parse(document.getElementById("dsh-ui-export").textContent);\n var doc = validateDocument(payload.document);\n var node = doc.nodes.flatMap(function flatten(n) {\n return [n, ...(n.children ?? []).flatMap(flatten)];\n }).find((n) => n.id === payload.nodeId && n.type === "sandbox");\n if (!node) throw Error("\\u5BFC\\u51FA\\u7684\\u753B\\u5E03\\u4E0D\\u5B58\\u5728");\n var state = validateState(doc, payload.state);\n var connected = false;\n var start = Date.now();\n var count = 0;\n var token = () => Array.from(crypto.getRandomValues(new Uint8Array(16)), (b) => b.toString(16).padStart(2, "0")).join("");\n var channel = token();\n var nonce = payload.nonce;\n var frame = document.createElement("iframe");\n frame.title = node.title;\n frame.sandbox = "allow-scripts";\n frame.referrerPolicy = "no-referrer";\n frame.style.cssText = "display:block;width:100%;height:" + (node.height ?? 420) + "px;border:0";\n var status = document.getElementById("status");\n var publish = () => {\n try {\n frame.contentWindow.postMessage({ dshCanvas: 1, channel, type: "snapshot", payload: { ...canvasSnapshot(node, state, doc.data, evaluate(doc, state).derived, false, payload.theme), visible: !document.hidden } }, "*");\n } catch (e) {\n status.textContent = "\\u8BA1\\u7B97\\u5931\\u8D25\\uFF1A" + e.message;\n }\n };\n addEventListener("message", (event) => {\n const m = event.data;\n if (event.source !== frame.contentWindow || m?.channel !== channel || m.dshCanvas !== 1) return;\n if (Date.now() - start > 1e3) {\n start = Date.now();\n count = 0;\n }\n if (++count > SANDBOX_LIMITS.rate) return;\n if (m.type === "ready") {\n connected = true;\n publish();\n } else if (m.type === "patch" && connected) {\n try {\n const next = validateState(doc, { ...state, ...canvasPatch(m.payload, node) });\n evaluate(doc, next);\n state = next;\n status.textContent = "\\u672C\\u5730\\u53C2\\u6570\\u5DF2\\u66F4\\u65B0\\uFF1B\\u5237\\u65B0\\u6587\\u4EF6\\u4F1A\\u56DE\\u5230\\u5BFC\\u51FA\\u65F6\\u7684\\u53C2\\u6570\\u3002";\n } catch (e) {\n status.textContent = "\\u53C2\\u6570\\u65E0\\u6548\\uFF1A" + e.message;\n }\n publish();\n } else if (m.type === "height" && Number.isFinite(m.payload)) frame.style.height = Math.max(160, Math.min(1e3, Math.ceil(m.payload))) + "px";\n else if (m.type === "error") status.textContent = "\\u753B\\u5E03\\u8FD0\\u884C\\u5F02\\u5E38\\uFF1A" + String(m.payload).slice(0, 1e3);\n });\n document.addEventListener("visibilitychange", () => {\n if (connected) publish();\n });\n document.getElementById("surface").append(frame);\n frame.srcdoc = sandboxDocument(node, channel, nonce);\n})();\n';
22794
+ var EXPORT_RUNTIME = '(() => {\n // lib/presentation.js\n var UI_ICONS = Object.freeze(["sparkles", "sliders", "layers", "chart", "gauge", "cpu", "database", "info", "check", "warning", "arrow", "target"]);\n var UI_TONES = Object.freeze(["neutral", "accent", "success", "warning", "danger"]);\n var UI_LAYOUTS = Object.freeze(["dashboard", "workbench", "comparison", "guide", "status", "report"]);\n var UI_ACCENTS = Object.freeze(["blue", "teal", "violet", "amber", "rose"]);\n var UI_SURFACES = Object.freeze(["outline", "soft", "featured"]);\n\n // lib/visual-audit.js\n function measureVisual(root, nodeId = "") {\n const issues = [], seen = /* @__PURE__ */ new Set(), coverage = { nodeId, elements: 0, truncated: false, contrastChecked: 0, contrastUncovered: 0 };\n const add = (code, value, el2) => {\n const id = el2?.closest("[data-ui-node]")?.getAttribute("data-ui-node") ?? nodeId;\n const k = id + ":" + code + ":" + Math.round(value ?? 0);\n if (!seen.has(k) && issues.length < 40) {\n seen.add(k);\n issues.push({ code, nodeId: id, ...value === void 0 ? {} : { value: Number(value.toFixed(2)) } });\n }\n };\n const color = (s) => {\n let m = s.match(/^rgba?\\(([^)]+)\\)/);\n if (m) {\n const a = m[1].split(/[\\s,\\/]+/).map(Number);\n return [a[0] / 255, a[1] / 255, a[2] / 255, a[3] ?? 1];\n }\n m = s.match(/^color\\(srgb ([^)]+)\\)/);\n if (m) {\n const a = m[1].split(/[\\s\\/]+/).map(Number);\n return [a[0], a[1], a[2], a[3] ?? 1];\n }\n return null;\n };\n const luminance = (c) => c.slice(0, 3).map((v) => v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4).reduce((s, v, i) => s + v * [0.2126, 0.7152, 0.0722][i], 0);\n const widthRoot = root.id === "canvas" ? document.documentElement : root;\n if (widthRoot.scrollWidth > widthRoot.clientWidth + 2) add("overflow", widthRoot.scrollWidth - widthRoot.clientWidth);\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);\n let el;\n while (el = walker.nextNode()) {\n if (coverage.elements >= 2e3) {\n coverage.truncated = true;\n break;\n }\n coverage.elements++;\n if (el.matches("[data-canvas-phase=error]")) add("runtimeError", void 0, el);\n const css = getComputedStyle(el), box = el.getBoundingClientRect();\n if (!box.width || !box.height || css.visibility === "hidden" || css.display === "none") continue;\n const text2 = [...el.childNodes].some((n) => n.nodeType === 3 && n.textContent.trim());\n if (text2) {\n let size = parseFloat(css.fontSize);\n if (el instanceof SVGElement && el.getScreenCTM) {\n const m = el.getScreenCTM();\n if (m) size *= Math.hypot(m.c, m.d);\n }\n if (size < 11.9) add("smallText", size, el);\n const fg = color(css.color);\n let ancestor = el, bg = null, depth = 0;\n while (ancestor && depth++ < 64) {\n const style = getComputedStyle(ancestor);\n if (style.backgroundImage !== "none") break;\n const c = color(style.backgroundColor);\n if (c?.[3] === 1) {\n bg = c;\n break;\n }\n if (c?.[3] > 0) break;\n ancestor = ancestor.parentElement;\n }\n if (!(el instanceof SVGElement) && fg?.[3] === 1 && bg) {\n coverage.contrastChecked++;\n const a = luminance(fg), b = luminance(bg), ratio = (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);\n if (ratio < (size >= 24 || size >= 18.66 && parseFloat(css.fontWeight) >= 700 ? 3 : 4.5)) add("contrast", ratio, el);\n } else coverage.contrastUncovered++;\n }\n if (el.matches("input:not([type=hidden]),select,textarea,button,[role=button]") && !el.getAttribute("aria-label") && !el.getAttribute("aria-labelledby") && !el.labels?.length && !el.textContent.trim() && !el.getAttribute("title")) add("missingLabel", void 0, el);\n }\n Object.defineProperty(issues, "coverage", { value: coverage });\n return issues;\n }\n\n // lib/format-number.js\n function formatNumber(value, decimals = 2) {\n if (typeof value !== "number" || !Number.isFinite(value)) throw new Error("DSH UI: formatNumber requires a finite number");\n if (!Number.isInteger(decimals) || decimals < 0 || decimals > 6) throw new Error("DSH UI: formatNumber decimals must be an integer from 0 to 6");\n return value.toLocaleString("en-US", { minimumFractionDigits: decimals, maximumFractionDigits: decimals });\n }\n\n // lib/canvas-system.js\n var CANVAS_SYSTEM_CSS = `\n:root{--canvas-radius:20px;--canvas-gap:16px;--canvas-positive:#167456;--canvas-negative:#b13b3b;--canvas-warning:#875b15}\n:root[data-canvas-scheme=dark]{--canvas-positive:#78d9b4;--canvas-negative:#ffaaaa;--canvas-warning:#edc87e}\n#canvas{display:flow-root}html,body{margin:0;min-width:0;background:var(--canvas-bg,#fff);color:var(--canvas-ink,#182537);font:14px/1.6 system-ui,"Microsoft YaHei",sans-serif}*{box-sizing:border-box}svg{max-width:100%;height:auto}button,input,select,textarea{font:inherit;color:inherit}button,input,select,textarea{border:1px solid var(--canvas-line,#ced4df);border-radius:8px;background:var(--canvas-bg,#fff);padding:8px 12px;max-width:100%}button{cursor:pointer}button:disabled{cursor:default;opacity:.55}input[type=range]{padding:0;accent-color:var(--canvas-accent,#3e60d3)}input[type=checkbox],input[type=radio]{accent-color:var(--canvas-accent,#3e60d3)}button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[tabindex]:focus-visible{outline:2px solid var(--canvas-accent,#3e60d3);outline-offset:3px}\n.ui-stack{display:grid;gap:var(--canvas-gap)}.ui-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));gap:var(--canvas-gap)}.ui-surface{padding:20px;border:1px solid var(--canvas-line,#ced4df);border-radius:var(--canvas-radius);background:var(--canvas-soft,#f3f5f8)}.ui-title{margin:0;font-size:clamp(20px,3vw,28px);line-height:1.3;letter-spacing:-.02em}.ui-caption{color:var(--canvas-muted,#526176);margin:8px 0;font-size:14px}.ui-value{font-size:clamp(24px,4vw,36px);font-variant-numeric:tabular-nums;line-height:1.2}.ui-controls{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.ui-field{display:grid;gap:6px;min-width:0}.ui-legend{display:flex;gap:16px;flex-wrap:wrap;font-size:13px}.ui-status{min-height:1.6em}.ui-error{color:var(--canvas-negative)}.ui-primary{background:var(--canvas-accent,#3e60d3);color:var(--canvas-accent-ink,#fff);border-color:transparent}\nsvg .ui-node{fill:var(--canvas-soft,#f3f5f8);stroke:var(--canvas-line,#ced4df);stroke-width:1}svg .ui-edge{fill:none;stroke:var(--canvas-muted,#526176);stroke-width:1.5}svg .ui-label{fill:var(--canvas-ink,#182537);font:500 14px system-ui,sans-serif}svg .ui-note{fill:var(--canvas-muted,#526176);font:400 13px system-ui,sans-serif}svg .ui-leader{fill:none;stroke:var(--canvas-muted,#526176);stroke-dasharray:3 4}svg .ui-accent{fill:color-mix(in srgb,var(--canvas-accent,#3e60d3) 12%,var(--canvas-bg,#fff));stroke:var(--canvas-accent,#3e60d3)}\n.ui-flow{display:flex;align-items:center;justify-content:center;gap:16px;padding:24px 8px;flex-wrap:wrap}.ui-step{display:grid;gap:6px;min-width:130px;max-width:240px;padding:16px 20px;border:1px solid var(--canvas-line);border-radius:6px;background:var(--canvas-bg)}.ui-step strong{font-size:16px;font-weight:600}.ui-step span{font-size:14px;color:var(--canvas-muted)}.ui-arrow{color:var(--canvas-muted);font-size:22px}.ui-callout{border-inline-start:3px solid var(--canvas-accent);padding:8px 16px;color:var(--canvas-ink)}\n.ui-surface,.ui-step{border-radius:var(--canvas-radius);background:linear-gradient(135deg,color-mix(in srgb,var(--canvas-accent,#3e60d3) 9%,var(--canvas-bg,#fff)),var(--canvas-soft,#f3f5f8))}button,input:not([type=checkbox]):not([type=radio]):not([type=range]),select,textarea{border-radius:14px}.ui-primary{background:linear-gradient(120deg,var(--canvas-accent,#3e60d3),color-mix(in srgb,var(--canvas-accent,#3e60d3) 85%,#152647))}.ui-callout{border-radius:14px;background:linear-gradient(120deg,color-mix(in srgb,var(--canvas-accent,#3e60d3) 7%,var(--canvas-bg,#fff)),var(--canvas-bg,#fff))}\n@media(max-width:480px){.ui-flow{flex-direction:column;padding:16px 8px;gap:12px}.ui-step{width:100%;max-width:none}.ui-arrow{transform:rotate(90deg)}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}}`;\n\n // lib/sandbox.js\n var SANDBOX_LIMITS = Object.freeze({ source: 49152, height: 1e3, message: 16384, rate: 30 });\n function canvasSnapshot(node2, state2, data, derived, disabled, theme) {\n const pick = (keys, values) => Object.fromEntries((keys ?? []).map((k) => [k, values[k]]));\n return { state: pick(node2.stateKeys, state2), data: pick(node2.dataKeys, data), derived: pick(node2.derivedKeys, derived), disabled, theme };\n }\n function canvasPatch(message, node2) {\n if (!message || typeof message !== "object" || Array.isArray(message)) throw new Error("Invalid canvas patch");\n const keys = Object.keys(message);\n if (!keys.length || keys.length > 64 || keys.some((k) => !(node2.stateKeys ?? []).includes(k))) throw new Error("Canvas state key is not declared");\n if (JSON.stringify(message).length > SANDBOX_LIMITS.message) throw new Error("Canvas patch is too large");\n return message;\n }\n function sandboxDocument(node2, channel2, nonce2) {\n const json = (value) => JSON.stringify(value).replace(/</g, "\\\\u003c").replace(/\\u2028/g, "\\\\u2028").replace(/\\u2029/g, "\\\\u2029");\n return `<!doctype html><html><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src \'none\'; script-src \'nonce-${nonce2}\'; style-src \'unsafe-inline\'; img-src data:; font-src \'none\'; connect-src \'none\'; media-src \'none\'; object-src \'none\'; frame-src \'none\'; worker-src \'none\'; base-uri \'none\'; form-action \'none\'"><meta name="viewport" content="width=device-width,initial-scale=1"><style>${CANVAS_SYSTEM_CSS}</style></head><body><main id="canvas"></main><script nonce="${nonce2}">(()=>{\n const channel=${json(channel2)}, source=${json({ html: node2.html, css: node2.css ?? "", script: node2.script ?? "" })};\n let snapshot={state:{},data:{},derived:{},disabled:true,theme:{}}, started=false;\n const listeners=new Set(), send=(type,payload)=>parent.postMessage({dshCanvas:1,channel,type,payload},\'*\');\n const report=e=>send(\'error\',String(e?.message??e).slice(0,1000));\n const audit=${measureVisual.toString()};let auditTimer;const scheduleAudit=()=>{clearTimeout(auditTimer);auditTimer=setTimeout(()=>{const issues=audit(document.getElementById(\'canvas\'),${json(node2.id ?? "")});send(\'audit\',{issues,coverage:issues.coverage})},400)};\n addEventListener(\'resize\',scheduleAudit);\n addEventListener(\'error\',e=>report(e.error??e.message));addEventListener(\'unhandledrejection\',e=>report(e.reason));\n const animations=new Set(), motion=matchMedia(\'(prefers-reduced-motion: reduce)\');\n let raf=0,last=0,time=0;\n const visible=()=>snapshot.visible!==false&&!document.hidden;\n const canAnimate=()=>visible()&&!snapshot.disabled&&!motion.matches;\n const draw=delta=>{for(const fn of animations)try{fn({time,delta,reducedMotion:motion.matches,visible:visible()})}catch(e){animations.delete(fn);report(e)}};\n const tick=t=>{raf=0;if(!canAnimate()||!animations.size){last=0;draw(0);return}const delta=last?Math.min(.05,(t-last)/1000):0;last=t;time+=delta;draw(delta);if(animations.size)raf=requestAnimationFrame(tick)};\n const refresh=()=>{draw(0);if(canAnimate()&&animations.size){if(!raf){last=0;raf=requestAnimationFrame(tick)}}else{cancelAnimationFrame(raf);raf=0;last=0}};\n motion.addEventListener(\'change\',refresh);document.addEventListener(\'visibilitychange\',refresh);\n const formatNumber=${formatNumber.toString()};\n const api={formatNumber,get snapshot(){return structuredClone(snapshot)},subscribe(fn){if(typeof fn!==\'function\')throw Error(\'Listener required\');listeners.add(fn);fn(api.snapshot);return()=>listeners.delete(fn)},setState(patch){if(!snapshot.disabled)send(\'patch\',patch)},animate(fn){if(typeof fn!==\'function\')throw Error(\'Animation callback required\');animations.add(fn);refresh();return()=>{animations.delete(fn);if(!animations.size){cancelAnimationFrame(raf);raf=0;last=0}}}};\n Object.defineProperty(window,\'DSHUI\',{value:Object.freeze(api),writable:false});\n for(const type of [\'click\',\'input\',\'change\',\'keydown\',\'pointerdown\'])document.addEventListener(type,e=>{if(snapshot.disabled){e.preventDefault();e.stopImmediatePropagation()}},true);\n addEventListener(\'message\',event=>{\n const m=event.data;if(event.source!==parent||m?.dshCanvas!==1||m.channel!==channel||m.type!==\'snapshot\')return;\n snapshot=m.payload;for(const [k,v] of Object.entries(snapshot.theme??{}))document.documentElement.style.setProperty(\'--canvas-\'+k,v);\n document.documentElement.style.colorScheme=snapshot.theme?.scheme??\'light\';document.documentElement.dataset.canvasScheme=snapshot.theme?.scheme??\'light\';\n const wasStarted=started;\n if(!started){started=true;document.getElementById(\'canvas\').innerHTML=source.html;const style=document.createElement(\'style\');style.textContent=source.css;document.head.append(style);const script=document.createElement(\'script\');script.nonce=${json(nonce2)};script.textContent=source.script;document.body.append(script)}\n if(wasStarted)for(const fn of listeners)try{fn(api.snapshot)}catch(e){report(e)}\n refresh();if(!wasStarted)send(\'mounted\');scheduleAudit();\n });\n let resizePending=false;new ResizeObserver(()=>{if(!started||resizePending)return;resizePending=true;requestAnimationFrame(()=>{resizePending=false;send(\'height\',Math.ceil(document.getElementById(\'canvas\').getBoundingClientRect().height))})}).observe(document.getElementById(\'canvas\'));\n send(\'ready\');\n})();<\\/script></body></html>`;\n }\n\n // lib/components.js\n var define = (fields2, purpose, presentation = "") => Object.freeze({ fields: Object.freeze(fields2), purpose, presentation });\n var COMPONENTS = Object.freeze({\n heading: define(["text"], "Section heading", "tone"),\n text: define(["text"], "Readable explanation or bound text", "tone"),\n row: define(["children"], "Wrapping parallel content"),\n column: define(["children"], "Ordered vertical content"),\n card: define(["title", "children", "surface"], "Meaningful grouped section", "tone"),\n details: define(["title", "children", "open"], "Collapsible supporting content", "tone"),\n badge: define(["text"], "Short explicit status label", "tone"),\n progress: define(["label", "value", "max", "unit"], "Declared numeric progress snapshot", "tone"),\n steps: define(["items"], "Ordered declared steps"),\n metric: define(["label", "value", "unit", "decimals"], "Number with units, or a literal/bound status string", "tone"),\n input: define(["label", "bind"], "String or numeric state input"),\n slider: define(["label", "bind"], "Numeric state control"),\n select: define(["label", "bind"], "Selection from declared state options"),\n toggle: define(["label", "bind"], "Boolean state control"),\n button: define(["text", "action"], "Declared Agent follow-up", "icon"),\n table: define(["label", "rows", "columns"], "Supplied or derived values; inline rows or data/derived reference"),\n chart: define(["kind", "rows", "labelKey", "valueKey", "label", "unit", "xScale"], "Bar/line comparison with accessible data"),\n sandbox: define(["title", "html", "css", "script", "fallback", "height", "stateKeys", "dataKeys", "derivedKeys"], "Freeform isolated HTML/SVG/CSS/JavaScript visualization")\n });\n function componentFields(type) {\n const c = Object.hasOwn(COMPONENTS, type) ? COMPONENTS[type] : void 0;\n return c && ["id", "type", ...c.fields, ...c.presentation ? ["icon"] : [], ...c.presentation === "tone" ? ["tone"] : []];\n }\n\n // lib/identifiers.js\n var IDENTIFIER_SOURCE = "[\\\\p{L}_][\\\\p{L}\\\\p{M}\\\\p{N}_]{0,63}";\n var pattern = new RegExp(`^${IDENTIFIER_SOURCE}$`, "u");\n var validIdentifier = (value) => typeof value === "string" && pattern.test(value) && !["constructor", "prototype", "__proto__"].includes(value);\n\n // lib/author-expression.js\n function compileExpression(source) {\n const fail2 = () => {\n throw new Error("DSH UI: invalid formula; use state.x, data.x, derived.x, item.x, numbers, strings, + - * /, comparisons, ?: and min/max/round/abs");\n };\n if (typeof source !== "string" || !source.trim() || source.length > 2048) fail2();\n const tokens = [];\n let offset = 0;\n const token2 = new RegExp(String.raw`\\s*(?:(\\d+(?:\\.\\d*)?|\\.\\d+)([eE][+-]?\\d+)?|("(?:[^"\\\\]|\\\\.)*")|(${IDENTIFIER_SOURCE}(?:\\.${IDENTIFIER_SOURCE})?)|(===|!==|<=|>=|==|!=|[+*/()?,:<>-]))`, "uy");\n while (offset < source.length) {\n if (!source.slice(offset).trim()) break;\n token2.lastIndex = offset;\n const m = token2.exec(source);\n if (!m) fail2();\n offset = token2.lastIndex;\n tokens.push(m[1] ? { number: Number(m[1] + (m[2] ?? "")) } : m[3] ? { string: JSON.parse(m[3]) } : m[4] ?? m[5]);\n if (tokens.length > 256) fail2();\n }\n let pos = 0;\n const operators = { "==": ["eq", 1], "===": ["eq", 1], "!=": ["neq", 1], "!==": ["neq", 1], "<": ["lt", 2], "<=": ["lte", 2], ">": ["gt", 2], ">=": ["gte", 2], "+": ["add", 3], "-": ["sub", 3], "*": ["mul", 4], "/": ["div", 4] };\n const take = (t) => {\n if (tokens[pos++] !== t) fail2();\n };\n function parse(min = 0, depth = 0) {\n if (depth > 12) fail2();\n const t = tokens[pos++];\n let out;\n if (t && typeof t === "object") out = { const: Object.hasOwn(t, "number") ? t.number : t.string };\n else if (t === "true" || t === "false") out = { const: t === "true" };\n else if (t === "(") {\n out = parse(0, depth + 1);\n take(")");\n } else if (t === "-" || t === "+") {\n const arg = parse(5, depth + 1);\n out = t === "-" ? { op: "sub", args: [{ const: 0 }, arg] } : arg;\n } else if (typeof t === "string" && t.split(".").length === 2 && ["state", "data", "derived", "item"].includes(t.split(".")[0]) && validIdentifier(t.split(".")[1])) out = { ref: t };\n else if (["min", "max", "round", "abs"].includes(t)) {\n take("(");\n const args = [parse(0, depth + 1)];\n while (tokens[pos] === ",") {\n pos++;\n args.push(parse(0, depth + 1));\n if (args.length > 8) fail2();\n }\n take(")");\n out = { op: t, args };\n } else fail2();\n while (typeof tokens[pos] === "string" && Object.hasOwn(operators, tokens[pos]) && operators[tokens[pos]][1] >= min) {\n const [op, precedence] = operators[tokens[pos++]];\n out = { op, args: [out, parse(precedence + 1, depth + 1)] };\n }\n if (min === 0 && tokens[pos] === "?") {\n pos++;\n const yes = parse(0, depth + 1);\n take(":");\n out = { op: "if", args: [out, yes, parse(0, depth + 1)] };\n }\n return out;\n }\n const result = parse();\n if (pos !== tokens.length) fail2();\n return result;\n }\n function expandExpressions(doc2) {\n const expression = (e) => {\n if (!e || typeof e !== "object" || Array.isArray(e)) return e;\n if (Object.hasOwn(e, "expr")) {\n if (Object.keys(e).length !== 1) throw new Error("DSH UI: expr must be the only formula field");\n return compileExpression(e.expr);\n }\n if (Array.isArray(e.args)) e.args = e.args.map(expression);\n if (e.map?.fields) for (const k of Object.keys(e.map.fields)) e.map.fields[k] = expression(e.map.fields[k]);\n return e;\n };\n if (doc2.derived && typeof doc2.derived === "object") for (const k of Object.keys(doc2.derived)) doc2.derived[k] = expression(doc2.derived[k]);\n const walk = (nodes) => {\n if (!Array.isArray(nodes)) return;\n for (const node2 of nodes) {\n if (!node2 || typeof node2 !== "object") continue;\n for (const field of ["text", "value", "max", "rows"]) if (Object.hasOwn(node2, field)) node2[field] = expression(node2[field]);\n walk(node2.children);\n }\n };\n walk(doc2.nodes);\n return doc2;\n }\n\n // lib/protocol.js\n var LIMITS = Object.freeze({ bytes: 131072, nodes: 160, depth: 12, rows: 500, expressions: 128, steps: 4096 });\n var own = (o, k) => Object.hasOwn(o, k);\n var fail = (message) => {\n throw new Error(`DSH UI: ${message}`);\n };\n var object = (x) => x !== null && typeof x === "object" && !Array.isArray(x);\n var finite = (x) => typeof x === "number" && Number.isFinite(x);\n var scalar = (x) => typeof x === "string" || typeof x === "boolean" || finite(x);\n var text = (x, at) => {\n if (typeof x !== "string" || x.length > 8192) fail(`${at} must be a string of at most 8192 characters`);\n };\n function fields(value, allowed, at) {\n if (!object(value)) fail(`${at} must be an object`);\n for (const k of Object.keys(value)) if (!allowed.includes(k)) {\n const hint = at === "document" ? " Controls and visual components belong in nodes as registered typed nodes, not extra document fields." : "";\n fail(`unknown field ${at}.${k}; allowed fields at ${at}: ${allowed.join(", ")}.${hint}`);\n }\n }\n function safeJson(value, depth = 0, source = false) {\n if (depth > 48) fail("JSON nesting is too deep");\n if (value === null || typeof value === "boolean") return;\n if (typeof value === "string") {\n if (source) {\n if (value.length > SANDBOX_LIMITS.source) fail("canvas source exceeds 48 Ki characters");\n return;\n }\n return text(value, "value");\n }\n if (typeof value === "number") {\n if (!finite(value)) fail("numbers must be finite");\n return;\n }\n if (typeof value !== "object") fail("only JSON values are accepted");\n if (Array.isArray(value) && value.length > LIMITS.rows) fail("too many array items");\n for (const k of Object.keys(value)) {\n if (["__proto__", "prototype", "constructor"].includes(k)) fail("unsafe property name");\n safeJson(value[k], depth + 1, value.type === "sandbox" && ["html", "css", "script"].includes(k));\n }\n }\n function initialState(doc2) {\n return Object.fromEntries(Object.entries(doc2.state).map(([k, spec]) => [k, spec.default]));\n }\n function validateState(doc2, state2) {\n if (!object(state2) || Object.keys(state2).length !== Object.keys(doc2.state).length) fail("state keys do not match the document");\n const result = {};\n for (const [k, s] of Object.entries(doc2.state)) {\n if (!own(state2, k)) fail(`missing state.${k}`);\n const v = state2[k];\n if (s.type === "number") {\n if (!finite(v) || v < s.min || v > s.max) fail(`state.${k} is outside its numeric range`);\n const offset = (v - s.min) / s.step;\n if (Math.abs(offset - Math.round(offset)) > 1e-6) fail(`state.${k} does not match its step`);\n } else if (s.type === "json") {\n if (!object(v) && !Array.isArray(v)) fail(`state.${k} must be an array or object for type json`);\n safeJson(v);\n if (new TextEncoder().encode(JSON.stringify(v)).length > 16384) fail(`state.${k} JSON exceeds 16 KiB`);\n } else if (s.type === "string") text(v, `state.${k}`);\n else if (typeof v !== "boolean") fail(`state.${k} must be boolean`);\n if (s.options && !s.options.includes(v)) fail(`invalid option for state.${k}`);\n result[k] = v;\n }\n return result;\n }\n var ARITY = { add: [1, 8], sub: [2, 2], mul: [1, 8], div: [2, 2], min: [1, 8], max: [1, 8], round: [1, 1], abs: [1, 1], eq: [2, 2], neq: [2, 2], lt: [2, 2], lte: [2, 2], gt: [2, 2], gte: [2, 2], if: [3, 3] };\n function reference(doc2, ref) {\n if (typeof ref !== "string" || !["state", "data", "derived"].includes(ref.split(".")[0]) || ref.split(".").length !== 2 || !validIdentifier(ref.split(".")[1])) fail(`invalid reference ${JSON.stringify(ref)}; use state.key, data.key or derived.key with a letter/underscore identifier`);\n const [group, k] = ref.split(".");\n if (!own(doc2[group], k)) fail(`unknown reference ${ref}`);\n return [group, k];\n }\n function evaluate(doc2, state2) {\n const derived = {}, active = /* @__PURE__ */ new Set();\n let steps = 0, generatedRows = 0;\n const budget = () => {\n if (++steps > LIMITS.steps) fail("calculation budget exceeded");\n };\n const resolve = (ref) => {\n budget();\n const [group, k] = reference(doc2, ref);\n if (group !== "derived") return (group === "state" ? state2 : doc2.data)[k];\n if (own(derived, k)) return derived[k];\n if (active.has(k)) fail(`cyclic calculation ${k}`);\n active.add(k);\n const result2 = expression(doc2.derived[k]);\n active.delete(k);\n derived[k] = result2;\n return result2;\n };\n const expression = (e, item) => {\n budget();\n if (own(e, "map")) {\n const rows = resolve(e.map.source);\n if ((generatedRows += rows.length) > LIMITS.rows) fail("generated row limit exceeded");\n return rows.map((row) => Object.fromEntries(Object.entries(e.map.fields).map(([k, value]) => {\n const out2 = expression(value, row);\n if (!scalar(out2)) fail("generated cells must be scalar");\n return [k, out2];\n })));\n }\n if (own(e, "const")) return e.const;\n if (own(e, "ref")) {\n if (e.ref.startsWith("item.")) {\n const k = e.ref.slice(5);\n if (!item || !own(item, k) || !scalar(item[k])) fail("invalid item reference");\n return item[k];\n }\n return resolve(e.ref);\n }\n if (e.op === "if") {\n const condition = expression(e.args[0], item);\n if (typeof condition !== "boolean") fail("if condition must be boolean");\n return expression(e.args[condition ? 1 : 2], item);\n }\n const a = e.args.map((arg) => expression(arg, item));\n if (e.op === "eq") return a[0] === a[1];\n if (e.op === "neq") return a[0] !== a[1];\n if (!a.every(finite)) fail(`operator ${e.op} requires finite numbers`);\n let out;\n switch (e.op) {\n case "add":\n out = a.reduce((x, y) => x + y, 0);\n break;\n case "sub":\n out = a[0] - a[1];\n break;\n case "mul":\n out = a.reduce((x, y) => x * y, 1);\n break;\n case "div":\n if (a[1] === 0) fail("division by zero");\n out = a[0] / a[1];\n break;\n case "min":\n out = Math.min(...a);\n break;\n case "max":\n out = Math.max(...a);\n break;\n case "round":\n out = Math.round(a[0]);\n break;\n case "abs":\n out = Math.abs(a[0]);\n break;\n case "lt":\n return a[0] < a[1];\n case "lte":\n return a[0] <= a[1];\n case "gt":\n return a[0] > a[1];\n case "gte":\n return a[0] >= a[1];\n default:\n fail(`unsupported operator ${e.op}`);\n }\n if (!finite(out)) fail("non-finite calculation result");\n return out;\n };\n for (const k of Object.keys(doc2.derived)) resolve(`derived.${k}`);\n if (new TextEncoder().encode(JSON.stringify(derived)).length > LIMITS.bytes) fail("derived output exceeds 128 KiB");\n const result = { derived, resolveValue: (value) => {\n if (!object(value)) return value;\n return expression(value);\n } };\n checkViewValues(doc2, result);\n return result;\n }\n function checkViewValues(doc2, evaluated) {\n function walk(list) {\n for (const n of list) {\n if (n.type === "table" || n.type === "chart") {\n const rows = evaluated.resolveValue(n.rows);\n if (!Array.isArray(rows) || rows.length > LIMITS.rows || !rows.every(object)) fail("table/chart rows must reference an array of objects");\n if (n.type === "chart" && rows.some((r) => !own(r, n.labelKey) || !scalar(r[n.labelKey]) || !own(r, n.valueKey) || !finite(r[n.valueKey]))) fail("chart requires labels and finite numeric values");\n if (n.type === "chart" && n.xScale === "linear" && rows.some((r) => !finite(r[n.labelKey]))) fail("linear chart requires numeric x values");\n }\n if (n.type === "metric" && !scalar(evaluated.resolveValue(n.value))) fail(`node.${n.id}.value must resolve to a number, string or boolean; use table for rows or a canvas for structured data`);\n if (n.type === "progress") {\n const v = evaluated.resolveValue(n.value), max = evaluated.resolveValue(n.max);\n if (!finite(v) || !finite(max) || max <= 0 || v < 0 || v > max) fail("progress requires 0 <= value <= positive max");\n }\n if (n.children) walk(n.children);\n }\n }\n walk(doc2.nodes);\n }\n function validateDocument(input) {\n safeJson(input);\n const json = JSON.stringify(input);\n if (new TextEncoder().encode(json).length > LIMITS.bytes) fail("document exceeds 128 KiB");\n const doc2 = expandExpressions(JSON.parse(json));\n fields(doc2, ["version", "title", "fallback", "state", "data", "derived", "nodes", "actions", "presentation"], "document");\n if (doc2.presentation !== void 0) {\n fields(doc2.presentation, ["layout", "accent", "density"], "presentation");\n for (const [k, allowed] of Object.entries({ layout: UI_LAYOUTS, accent: UI_ACCENTS, density: ["comfortable", "compact"] }))\n if (doc2.presentation[k] !== void 0 && !allowed.includes(doc2.presentation[k])) fail(`unknown presentation ${k}`);\n }\n if (doc2.version !== 1) fail("unsupported protocol version");\n text(doc2.title, "title");\n text(doc2.fallback, "fallback");\n if (!doc2.title.trim() || !doc2.fallback.trim()) fail("title and fallback cannot be empty");\n for (const group of ["state", "data", "derived", "actions"]) {\n doc2[group] ??= {};\n if (!object(doc2[group]) || Object.keys(doc2[group]).length > 64) fail(`invalid ${group}`);\n for (const k of Object.keys(doc2[group])) if (!validIdentifier(k)) fail(`invalid key in ${group}: ${JSON.stringify(k)}; use 1..64 letters, numbers or underscores, starting with a letter/underscore (Chinese letters supported); no spaces, dots or hyphens. Put display labels in label/text`);\n }\n for (const [k, s] of Object.entries(doc2.state)) {\n fields(s, ["type", "default", "min", "max", "step", "options"], `state.${k}`);\n if (s.type === "string" && (Array.isArray(s.default) || object(s.default)) && !own(s, "options")) s.type = "json";\n if (!["number", "string", "boolean", "json"].includes(s.type)) fail(`unsupported state type ${k}; use number, string, boolean or json (arrays/objects)`);\n if (s.type === "json" && own(s, "options")) fail(`state.${k}: json state does not support select options; use scalar options or a canvas`);\n if (s.type === "number") {\n if (![s.min, s.max, s.step].every(finite) || s.min >= s.max || s.step <= 0) fail(`invalid numeric limits for ${k}`);\n if ((s.max - s.min) / s.step > 1e9) fail(`numeric step too small for ${k}`);\n } else if (["min", "max", "step"].some((p) => own(s, p))) fail(`numeric limits on non-number ${k}`);\n if (s.options && (!Array.isArray(s.options) || !s.options.length || s.options.length > 64 || !s.options.every(scalar))) fail(`invalid options for ${k}`);\n }\n const defaults = validateState(doc2, initialState(doc2));\n let expressions = 0;\n for (const [k, spec] of Object.entries(doc2.state))\n for (const option of spec.options ?? []) validateState(doc2, { ...defaults, [k]: option });\n function validateExpression(e, depth = 0, itemRows) {\n if (++expressions > LIMITS.expressions || depth > LIMITS.depth) fail("expression limit exceeded");\n if (!object(e)) fail("expression must be an object");\n if (own(e, "map")) {\n if (depth !== 0) fail("map is only allowed at the root of a derived value");\n fields(e, ["map"], "expression");\n fields(e.map, ["source", "fields"], "map");\n if (typeof e.map.source !== "string" || !e.map.source.startsWith("data.")) fail(\'map source must reference static data using a string such as "data.samples"; put object rows in document.data.samples, not inline in map.source\');\n const [, k] = reference(doc2, e.map.source), rows = doc2.data[k];\n if (!Array.isArray(rows) || rows.length > LIMITS.rows || !rows.every(object)) fail("map source must be object rows");\n if (!object(e.map.fields) || !Object.keys(e.map.fields).length || Object.keys(e.map.fields).length > 16) fail("map requires 1..16 fields");\n for (const [k2, value2] of Object.entries(e.map.fields)) {\n if (!validIdentifier(k2)) fail(`invalid map field ${JSON.stringify(k2).slice(0, 100)}; use a letter/underscore identifier such as powerW or \\u529F\\u7387, without spaces, dots or hyphens`);\n validateExpression(value2, depth + 1, rows);\n }\n return;\n }\n if (own(e, "const")) {\n fields(e, ["const"], "expression");\n if (!scalar(e.const)) fail("constant must be scalar");\n return;\n }\n if (own(e, "ref")) {\n fields(e, ["ref"], "expression");\n if (typeof e.ref === "string" && e.ref.startsWith("item.")) {\n const k = e.ref.slice(5);\n if (!itemRows || !validIdentifier(k) || itemRows.some((row) => !own(row, k) || !scalar(row[k]))) fail("invalid or unscoped item reference");\n } else reference(doc2, e.ref);\n return;\n }\n fields(e, ["op", "args"], "expression");\n const arity = ARITY[e.op];\n if (!arity || !Array.isArray(e.args) || e.args.length < arity[0] || e.args.length > arity[1]) fail("invalid operator or argument count");\n e.args.forEach((a) => validateExpression(a, depth + 1, itemRows));\n }\n Object.values(doc2.derived).forEach((e) => validateExpression(e));\n const visited = /* @__PURE__ */ new Set(), active = /* @__PURE__ */ new Set();\n function visit(k) {\n if (active.has(k)) fail(`cyclic calculation ${k}`);\n if (visited.has(k)) return;\n active.add(k);\n function walk(e) {\n if (e.ref?.startsWith("derived.")) visit(e.ref.split(".")[1]);\n for (const a of e.args ?? []) walk(a);\n for (const value2 of Object.values(e.map?.fields ?? {})) walk(value2);\n }\n walk(doc2.derived[k]);\n active.delete(k);\n visited.add(k);\n }\n Object.keys(doc2.derived).forEach(visit);\n for (const [k, a] of Object.entries(doc2.actions)) {\n fields(a, ["type", "intent", "stateKeys"], `actions.${k}`);\n if (a.type !== "agent.followup") fail("only agent.followup actions are supported");\n text(a.intent, "action intent");\n if (!a.intent.trim() || !Array.isArray(a.stateKeys) || a.stateKeys.length > 64 || new Set(a.stateKeys).size !== a.stateKeys.length || a.stateKeys.some((s) => !own(doc2.state, s))) fail("invalid action stateKeys");\n }\n const ids = /* @__PURE__ */ new Set();\n let count2 = 0;\n const value = (v, at) => {\n if (object(v)) {\n if (own(v, "map")) fail("map belongs in derived");\n validateExpression(v);\n } else if (!scalar(v)) fail(`invalid value at ${at}`);\n };\n function nodes(list, depth = 0) {\n if (!Array.isArray(list) || depth > LIMITS.depth) fail("invalid node children or depth");\n for (const n of list) {\n if (++count2 > LIMITS.nodes) fail("too many nodes");\n if (!object(n) || !validIdentifier(n.id) || ids.has(n.id)) fail("node ids must be unique identifiers");\n ids.add(n.id);\n if (!Object.hasOwn(COMPONENTS, n.type)) fail("unsupported component " + n.type);\n if (["table", "chart"].includes(n.type) && typeof n.rows === "string" && /^(data|derived)\\./.test(n.rows)) n.rows = { ref: n.rows };\n switch (n.type) {\n case "sandbox": {\n text(n.title, "canvas title");\n text(n.fallback, "canvas fallback");\n if (!n.title.trim() || !n.fallback.trim() || typeof n.html !== "string" || !n.html.trim()) fail("canvas requires title, HTML and fallback");\n for (const field of ["html", "css", "script"]) if (n[field] !== void 0 && (typeof n[field] !== "string" || n[field].length > SANDBOX_LIMITS.source)) fail("canvas source exceeds 48 Ki characters");\n if (n.height !== void 0 && (!Number.isInteger(n.height) || n.height < 160 || n.height > SANDBOX_LIMITS.height)) fail("canvas height must be 160..1000");\n for (const [field, group] of [["stateKeys", "state"], ["dataKeys", "data"], ["derivedKeys", "derived"]]) if (n[field] !== void 0 && (!Array.isArray(n[field]) || n[field].length > 64 || new Set(n[field]).size !== n[field].length || n[field].some((k) => !own(doc2[group], k)))) fail("invalid canvas " + field);\n break;\n }\n case "row":\n case "column":\n break;\n case "card":\n if (n.title !== void 0) text(n.title, "card title");\n if (n.surface !== void 0 && !UI_SURFACES.includes(n.surface)) fail("unknown card surface");\n break;\n case "details":\n text(n.title, "details title");\n if (n.open !== void 0 && typeof n.open !== "boolean") fail("details open must be boolean");\n break;\n case "badge":\n value(n.text, "badge text");\n break;\n case "progress":\n text(n.label, "progress label");\n value(n.value, "progress value");\n value(n.max, "progress max");\n if (n.unit !== void 0) text(n.unit, "progress unit");\n break;\n case "steps": {\n if (!Array.isArray(n.items) || !n.items.length || n.items.length > 12) fail("steps require 1..12 items");\n for (const item of n.items) {\n fields(item, ["title", "description", "status"], "step");\n text(item.title, "step title");\n if (item.description !== void 0) text(item.description, "step description");\n if (!["pending", "active", "done", "error"].includes(item.status)) fail("unknown step status");\n }\n break;\n }\n case "heading":\n case "text":\n value(n.text, "text");\n break;\n case "metric":\n text(n.label, "metric label");\n value(n.value, "metric value");\n if (n.unit !== void 0) text(n.unit, "unit");\n if (n.decimals !== void 0 && (!Number.isInteger(n.decimals) || n.decimals < 0 || n.decimals > 6)) fail("invalid decimals");\n break;\n case "input":\n case "slider":\n case "select":\n case "toggle": {\n text(n.label, "control label");\n if (typeof n.bind !== "string" || !n.bind.startsWith("state.")) fail("controls must bind state");\n const [, k] = reference(doc2, n.bind), spec = doc2.state[k];\n if (n.type === "slider" && spec.type !== "number") fail("slider requires numeric state");\n if (n.type === "toggle" && spec.type !== "boolean") fail("toggle requires boolean state");\n if (["input", "select"].includes(n.type) && spec.type === "json") fail(`node.${n.id}: structured state requires a sandbox with DSHUI.setState; use separate boolean states and toggle nodes for a native checklist`);\n if (n.type === "input" && spec.type === "boolean") fail("use toggle for boolean state");\n if (n.type === "select" && !spec.options) fail("select requires options");\n break;\n }\n case "button":\n text(n.text, "button text");\n if (!own(doc2.actions, n.action)) fail("unknown action");\n break;\n case "table": {\n if (n.label !== void 0) text(n.label, "table label");\n if (!Array.isArray(n.rows)) value(n.rows, "table rows");\n if (!Array.isArray(n.columns) || !n.columns.length || n.columns.length > 16) fail("invalid table columns");\n const cols = /* @__PURE__ */ new Set();\n for (const c of n.columns) {\n fields(c, ["key", "label", "unit"], "column");\n if (!validIdentifier(c.key) || cols.has(c.key)) fail("invalid or duplicate column key");\n cols.add(c.key);\n text(c.label, "column label");\n if (c.unit !== void 0) text(c.unit, "column unit");\n }\n break;\n }\n case "chart":\n if (!Array.isArray(n.rows)) value(n.rows, "chart rows");\n if (!["bar", "line"].includes(n.kind) || !validIdentifier(n.labelKey) || !validIdentifier(n.valueKey)) fail("invalid chart");\n text(n.label, "chart label");\n if (n.unit !== void 0) text(n.unit, "chart unit");\n if (n.xScale !== void 0 && (!["category", "linear"].includes(n.xScale) || n.xScale === "linear" && n.kind !== "line")) fail("invalid xScale");\n break;\n default:\n fail(`unsupported component ${n.type}`);\n }\n if (["heading", "text", "card", "metric", "button", "badge", "progress", "details"].includes(n.type)) {\n if (n.icon !== void 0 && !UI_ICONS.includes(n.icon)) fail("unknown UI icon");\n if (n.type !== "button") {\n if (n.tone !== void 0 && !UI_TONES.includes(n.tone)) fail("unknown UI tone");\n }\n }\n fields(n, componentFields(n.type), `node.${n.id}`);\n if (["row", "column", "card", "details"].includes(n.type)) nodes(n.children, depth + 1);\n }\n }\n nodes(doc2.nodes);\n if (!count2) fail("at least one node is required");\n evaluate(doc2, defaults);\n return doc2;\n }\n\n // src/export-runtime.js\n var payload = JSON.parse(document.getElementById("dsh-ui-export").textContent);\n var doc = validateDocument(payload.document);\n var node = doc.nodes.flatMap(function flatten(n) {\n return [n, ...(n.children ?? []).flatMap(flatten)];\n }).find((n) => n.id === payload.nodeId && n.type === "sandbox");\n if (!node) throw Error("\\u5BFC\\u51FA\\u7684\\u753B\\u5E03\\u4E0D\\u5B58\\u5728");\n var state = validateState(doc, payload.state);\n var connected = false;\n var start = Date.now();\n var count = 0;\n var token = () => Array.from(crypto.getRandomValues(new Uint8Array(16)), (b) => b.toString(16).padStart(2, "0")).join("");\n var channel = token();\n var nonce = payload.nonce;\n var frame = document.createElement("iframe");\n frame.title = node.title;\n frame.sandbox = "allow-scripts";\n frame.referrerPolicy = "no-referrer";\n frame.style.cssText = "display:block;width:100%;height:" + (node.height ?? 420) + "px;border:0";\n var status = document.getElementById("status");\n var publish = () => {\n try {\n frame.contentWindow.postMessage({ dshCanvas: 1, channel, type: "snapshot", payload: { ...canvasSnapshot(node, state, doc.data, evaluate(doc, state).derived, false, payload.theme), visible: !document.hidden } }, "*");\n } catch (e) {\n status.textContent = "\\u8BA1\\u7B97\\u5931\\u8D25\\uFF1A" + e.message;\n }\n };\n addEventListener("message", (event) => {\n const m = event.data;\n if (event.source !== frame.contentWindow || m?.channel !== channel || m.dshCanvas !== 1) return;\n if (Date.now() - start > 1e3) {\n start = Date.now();\n count = 0;\n }\n if (++count > SANDBOX_LIMITS.rate) return;\n if (m.type === "ready") {\n connected = true;\n publish();\n } else if (m.type === "patch" && connected) {\n try {\n const next = validateState(doc, { ...state, ...canvasPatch(m.payload, node) });\n evaluate(doc, next);\n state = next;\n status.textContent = "\\u672C\\u5730\\u53C2\\u6570\\u5DF2\\u66F4\\u65B0\\uFF1B\\u5237\\u65B0\\u6587\\u4EF6\\u4F1A\\u56DE\\u5230\\u5BFC\\u51FA\\u65F6\\u7684\\u53C2\\u6570\\u3002";\n } catch (e) {\n status.textContent = "\\u53C2\\u6570\\u65E0\\u6548\\uFF1A" + e.message;\n }\n publish();\n } else if (m.type === "height" && Number.isFinite(m.payload) && m.payload >= 0) frame.style.height = Math.max(32, Math.min(1e3, Math.ceil(m.payload))) + "px";\n else if (m.type === "error") status.textContent = "\\u753B\\u5E03\\u8FD0\\u884C\\u5F02\\u5E38\\uFF1A" + String(m.payload).slice(0, 1e3);\n });\n document.addEventListener("visibilitychange", () => {\n if (connected) publish();\n });\n document.getElementById("surface").append(frame);\n frame.srcdoc = sandboxDocument(node, channel, nonce);\n})();\n';
22736
22795
 
22737
22796
  // lib/canvas-export.js
22738
22797
  function standaloneCanvas(document2, node, state, theme = {}) {
@@ -22743,18 +22802,64 @@ function standaloneCanvas(document2, node, state, theme = {}) {
22743
22802
  return `<!doctype html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta http-equiv="Content-Security-Policy" content="default-src 'none';script-src 'nonce-${token}';style-src 'unsafe-inline';frame-src 'self';base-uri 'none';form-action 'none'"><title>${escape(node.title)}</title><style>body{margin:0;padding:24px;background:${theme.scheme === "dark" ? "#161b23" : "#f4f6fa"};color:${theme.scheme === "dark" ? "#e6edf6" : "#182537"};font:14px/1.6 system-ui,sans-serif}main{max-width:1100px;margin:auto}h1{font-size:22px}p{overflow-wrap:anywhere}#surface{background:${theme.scheme === "dark" ? "#161b23" : "#fff"};border-radius:12px;overflow:hidden}#status{min-height:1.6em}</style></head><body><main><h1>${escape(node.title)}</h1><p>DSH Motion UI \xB7 \u72EC\u7ACB\u526F\u672C\u3002\u5305\u542B\u5BFC\u51FA\u65F6\u53C2\u6570\uFF0C\u672C\u5730\u4EA4\u4E92\u4E0D\u4F1A\u4FDD\u5B58\u5230 DSH\uFF0C\u4E5F\u4E0D\u4F1A\u8C03\u7528 Agent\u3002</p><div id="surface"></div><p id="status" role="status"></p><details><summary>\u6587\u5B57\u8BF4\u660E</summary><p>${escape(node.fallback)}</p></details></main><script type="application/json" id="dsh-ui-export">${json}<\/script><script nonce="${token}">${EXPORT_RUNTIME.replace(/<\/script/gi, "<\\/script")}<\/script></body></html>`;
22744
22803
  }
22745
22804
 
22805
+ // src/view-settings.js
22806
+ var import_react4 = require("react");
22807
+ var scope;
22808
+ function configureViewSettings(value) {
22809
+ scope = value;
22810
+ }
22811
+ var subscribe = (fn) => scope?.subscribe(fn) ?? (() => {
22812
+ });
22813
+ var snapshot = () => scope?.getSnapshot()?.value?.showDetails === true;
22814
+ function useViewDetails() {
22815
+ return (0, import_react4.useSyncExternalStore)(subscribe, snapshot, () => false);
22816
+ }
22817
+
22818
+ // src/action-menu.js
22819
+ var import_react5 = __toESM(require("react"), 1);
22820
+ function ActionMenu({ label, children }) {
22821
+ const [open, setOpen] = (0, import_react5.useState)(false), root = (0, import_react5.useRef)(null), button = (0, import_react5.useRef)(null);
22822
+ (0, import_react5.useEffect)(() => {
22823
+ if (!open) return;
22824
+ const outside = (e) => {
22825
+ if (!root.current?.contains(e.target)) setOpen(false);
22826
+ };
22827
+ const escape = (e) => {
22828
+ if (e.key === "Escape") {
22829
+ setOpen(false);
22830
+ button.current?.focus();
22831
+ }
22832
+ };
22833
+ document.addEventListener("pointerdown", outside);
22834
+ document.addEventListener("keydown", escape);
22835
+ return () => {
22836
+ document.removeEventListener("pointerdown", outside);
22837
+ document.removeEventListener("keydown", escape);
22838
+ };
22839
+ }, [open]);
22840
+ return import_react5.default.createElement(
22841
+ "div",
22842
+ { className: "dgui-action-menu", ref: root },
22843
+ import_react5.default.createElement("button", { ref: button, type: "button", className: "dgui-menu-trigger", "aria-label": label, "aria-expanded": open, onClick: () => setOpen(!open) }, "\u22EF"),
22844
+ open && import_react5.default.createElement("div", { className: "dgui-menu-content", "aria-label": label, onClick: (e) => {
22845
+ if (e.target.closest("button")) setOpen(false);
22846
+ } }, children)
22847
+ );
22848
+ }
22849
+
22746
22850
  // src/sandbox.js
22747
- var h3 = import_react4.default.createElement;
22851
+ var h3 = import_react6.default.createElement;
22748
22852
  var randomToken = () => Array.from(crypto.getRandomValues(new Uint8Array(16)), (b) => b.toString(16).padStart(2, "0")).join("");
22749
22853
  function Sandbox({ node, document: doc, state, data, derived, disabled, preview, update, onAudit }) {
22750
- 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)("");
22751
- const [error, setError] = (0, import_react4.useState)(""), [stopped, setStopped] = (0, import_react4.useState)(false), [generation, setGeneration] = (0, import_react4.useState)(0);
22752
- const [height, setHeight] = (0, import_react4.useState)(node.height ?? 420);
22753
- const [token, setToken] = (0, import_react4.useState)(0);
22754
- const [mounted, setMounted] = (0, import_react4.useState)(false);
22854
+ const showDetails = useViewDetails();
22855
+ const frame = (0, import_react6.useRef)(null), latest = (0, import_react6.useRef)(null), connected = (0, import_react6.useRef)(false), loads = (0, import_react6.useRef)(0), visible = (0, import_react6.useRef)(true), errorKind = (0, import_react6.useRef)("");
22856
+ const [error, setError] = (0, import_react6.useState)(""), [stopped, setStopped] = (0, import_react6.useState)(false), [generation, setGeneration] = (0, import_react6.useState)(0);
22857
+ const [height, setHeight] = (0, import_react6.useState)(node.height ?? 420);
22858
+ const [token, setToken] = (0, import_react6.useState)(0);
22859
+ const [mounted, setMounted] = (0, import_react6.useState)(false);
22755
22860
  const sourceKey = JSON.stringify(node);
22756
- const config = (0, import_react4.useMemo)(() => ({ channel: randomToken(), nonce: randomToken() }), [sourceKey, generation]);
22757
- const srcDoc = (0, import_react4.useMemo)(() => sandboxDocument(node, config.channel, config.nonce), [sourceKey, config]);
22861
+ const config = (0, import_react6.useMemo)(() => ({ channel: randomToken(), nonce: randomToken() }), [sourceKey, generation]);
22862
+ const srcDoc = (0, import_react6.useMemo)(() => sandboxDocument(node, config.channel, config.nonce), [sourceKey, config]);
22758
22863
  latest.current = { node, state, data, derived, disabled, update, onAudit };
22759
22864
  const publish = () => {
22760
22865
  const el = frame.current, current2 = latest.current;
@@ -22764,7 +22869,7 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
22764
22869
  theme.scheme = document.body.hasAttribute("data-ds-dark-theme") || el.closest("[data-preview-theme=dark]") ? "dark" : "light";
22765
22870
  el.contentWindow?.postMessage({ dshCanvas: 1, channel: config.channel, type: "snapshot", payload: { ...canvasSnapshot(current2.node, current2.state, current2.data, current2.derived, current2.disabled, theme), visible: visible.current && !document.hidden } }, "*");
22766
22871
  };
22767
- (0, import_react4.useEffect)(() => {
22872
+ (0, import_react6.useEffect)(() => {
22768
22873
  if (preview || stopped) return;
22769
22874
  connected.current = false;
22770
22875
  loads.current = 0;
@@ -22792,7 +22897,7 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
22792
22897
  setToken((t) => t + 1);
22793
22898
  } else if (m.type === "mounted" && connected.current) setMounted(true);
22794
22899
  else if (m.type === "audit" && connected.current) latest.current.onAudit?.(node.id, m.payload?.issues, m.payload?.coverage);
22795
- 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))));
22900
+ else if (m.type === "height" && connected.current && Number.isFinite(m.payload) && m.payload >= 0) setHeight(Math.max(32, Math.min(SANDBOX_LIMITS.height, Math.ceil(m.payload))));
22796
22901
  else if (m.type === "error") {
22797
22902
  errorKind.current = "runtime";
22798
22903
  setError(typeof m.payload === "string" ? m.payload.slice(0, 1e3) : "\u753B\u5E03\u8FD0\u884C\u5F02\u5E38");
@@ -22838,7 +22943,7 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
22838
22943
  intersection.disconnect();
22839
22944
  };
22840
22945
  }, [config, preview, stopped]);
22841
- (0, import_react4.useEffect)(() => {
22946
+ (0, import_react6.useEffect)(() => {
22842
22947
  publish();
22843
22948
  }, [state, data, derived, disabled, config, token]);
22844
22949
  const inactive = preview || stopped;
@@ -22864,6 +22969,13 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
22864
22969
  return h3(
22865
22970
  "section",
22866
22971
  { className: "dgui-canvas", "data-ui-node": node.id, "data-canvas-phase": inactive ? stopped ? "stopped" : "preview" : error ? "error" : mounted ? "ready" : "loading", "aria-label": node.title },
22972
+ !preview && !showDetails && h3(
22973
+ ActionMenu,
22974
+ { label: `${node.title}\u64CD\u4F5C` },
22975
+ h3("button", { type: "button", disabled: disabled || !doc || stopped, onClick: download }, "\u5BFC\u51FA\u72EC\u7ACB HTML"),
22976
+ h3("button", { type: "button", disabled, onClick: restart }, stopped ? "\u6062\u590D\u4EA4\u4E92" : "\u91CD\u7F6E\u753B\u5E03"),
22977
+ !stopped && h3("button", { type: "button", onClick: () => setStopped(true) }, "\u505C\u6B62\u753B\u5E03")
22978
+ ),
22867
22979
  preview ? h3(CanvasPreview, { node }) : inactive ? h3("div", { className: "dgui-canvas-placeholder", role: "status" }, h3("p", null, "\u753B\u5E03\u5DF2\u505C\u6B62\u3002"), stopped && h3("button", { type: "button", className: "dgui-secondary", onClick: restart }, "\u6062\u590D\u4EA4\u4E92")) : h3(
22868
22980
  "div",
22869
22981
  { className: "dgui-canvas-stage", style: { minHeight: mounted || error ? void 0 : Math.min(height, 420) } },
@@ -22876,7 +22988,8 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
22876
22988
  }, style: { width: "100%", height, border: 0, display: "block", visibility: mounted || error ? "visible" : "hidden" }, allow: "camera 'none'; microphone 'none'; geolocation 'none'; clipboard-read 'none'; clipboard-write 'none'" })
22877
22989
  ),
22878
22990
  error && h3("div", { className: "dgui-canvas-issue", role: "alert" }, h3("strong", null, "\u4EA4\u4E92\u9047\u5230\u95EE\u9898"), h3("p", null, "\u53EF\u4EE5\u91CD\u65B0\u8F7D\u5165\uFF1B\u5DF2\u4FDD\u5B58\u7684\u53C2\u6570\u4F1A\u4FDD\u7559\u3002"), h3("div", { className: "dgui-recovery" }, h3("button", { type: "button", className: "dgui-secondary", onClick: restart }, "\u91CD\u7F6E\u753B\u5E03"), !stopped && h3("button", { type: "button", className: "dgui-secondary", onClick: () => setStopped(true) }, "\u505C\u6B62\u753B\u5E03")), h3("details", null, h3("summary", null, "\u9519\u8BEF\u8BE6\u60C5"), h3("pre", null, error))),
22879
- h3(
22991
+ error && !showDetails && h3("p", { className: "dgui-error" }, node.fallback),
22992
+ showDetails && h3(
22880
22993
  "details",
22881
22994
  { className: "dgui-canvas-options" },
22882
22995
  h3("summary", null, "\u8BF4\u660E\u4E0E\u64CD\u4F5C"),
@@ -22888,13 +23001,13 @@ function Sandbox({ node, document: doc, state, data, derived, disabled, preview,
22888
23001
  }
22889
23002
 
22890
23003
  // lib/build-info.js
22891
- var BUILD_INFO = Object.freeze({ "version": "0.5.2", "id": "0.5.2+af2abef3c448", "sourceHash": "af2abef3c4483e0ce89fb9438a032ad133c7039193778388acb821ce9d353449" });
23004
+ var BUILD_INFO = Object.freeze({ "version": "0.5.4", "id": "0.5.4+92e88973eabc", "sourceHash": "92e88973eabc736e169fbb03366db183ca5cd1fbbe0e3a7e44e5742da708d96e" });
22892
23005
 
22893
23006
  // lib/refinement.js
22894
23007
  var AUDIT_MESSAGES = Object.freeze({ overflow: "\u5185\u5BB9\u8D85\u51FA\u89C6\u53E3\u5BBD\u5EA6", smallText: "\u6587\u5B57\u5B9E\u9645\u663E\u793A\u5C3A\u5BF8\u5C0F\u4E8E 12px", contrast: "\u6587\u5B57\u4E0E\u80CC\u666F\u5BF9\u6BD4\u5EA6\u504F\u4F4E", missingLabel: "\u4EA4\u4E92\u63A7\u4EF6\u7F3A\u5C11\u53EF\u8BBF\u95EE\u540D\u79F0", runtimeError: "\u753B\u5E03\u62A5\u544A\u8FD0\u884C\u5F02\u5E38" });
22895
23008
 
22896
23009
  // src/current-document.js
22897
- var import_react5 = require("react");
23010
+ var import_react7 = require("react");
22898
23011
  var current = /* @__PURE__ */ new Map();
22899
23012
  var listeners2 = /* @__PURE__ */ new Set();
22900
23013
  function publishDocument(raw) {
@@ -22905,9 +23018,9 @@ function publishDocument(raw) {
22905
23018
  listeners2.forEach((fn) => fn());
22906
23019
  }
22907
23020
  function useCurrentDocument(raw, sessionId) {
22908
- const [, wake] = (0, import_react5.useState)(0);
22909
- const [attempt, retry] = (0, import_react5.useState)(0), [load, setLoad] = (0, import_react5.useState)({ status: "loading" });
22910
- (0, import_react5.useEffect)(() => {
23021
+ const [, wake] = (0, import_react7.useState)(0);
23022
+ const [attempt, retry] = (0, import_react7.useState)(0), [load, setLoad] = (0, import_react7.useState)({ status: "loading" });
23023
+ (0, import_react7.useEffect)(() => {
22911
23024
  if (!raw.documentId || !sessionId) return;
22912
23025
  const notify = () => wake((v) => v + 1);
22913
23026
  listeners2.add(notify);
@@ -22933,10 +23046,10 @@ function useCurrentDocument(raw, sessionId) {
22933
23046
  }
22934
23047
 
22935
23048
  // src/history-view.js
22936
- var import_react6 = __toESM(require("react"), 1);
22937
- var h4 = import_react6.default.createElement;
23049
+ var import_react8 = __toESM(require("react"), 1);
23050
+ var h4 = import_react8.default.createElement;
22938
23051
  function HistoryView({ record, sessionId }) {
22939
- 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);
23052
+ const [versions, setVersions] = (0, import_react8.useState)(null), [error, setError] = (0, import_react8.useState)(""), [busy, setBusy] = (0, import_react8.useState)(false), [preview, setPreview] = (0, import_react8.useState)(null);
22940
23053
  const url = "/api/plugins/dsh-generative-ui/history?" + new URLSearchParams({ documentId: record.documentId, sessionId });
22941
23054
  async function request2(options) {
22942
23055
  const r = await fetch(url, { credentials: "same-origin", ...options }), value = await r.json();
@@ -22954,11 +23067,11 @@ function HistoryView({ record, sessionId }) {
22954
23067
  setBusy(false);
22955
23068
  }
22956
23069
  }
22957
- async function restore(revision) {
23070
+ async function restore(revision2) {
22958
23071
  setBusy(true);
22959
23072
  setError("");
22960
23073
  try {
22961
- const next = await request2({ method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ documentRevision: record.documentRevision ?? 0, targetRevision: revision }) });
23074
+ const next = await request2({ method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ documentRevision: record.documentRevision ?? 0, targetRevision: revision2 }) });
22962
23075
  publishDocument(next);
22963
23076
  setPreview(null);
22964
23077
  setVersions(await request2());
@@ -22968,11 +23081,11 @@ function HistoryView({ record, sessionId }) {
22968
23081
  setBusy(false);
22969
23082
  }
22970
23083
  }
22971
- async function inspect(revision) {
23084
+ async function inspect(revision2) {
22972
23085
  setBusy(true);
22973
23086
  setError("");
22974
23087
  try {
22975
- const r = await fetch(url + "&revision=" + revision, { credentials: "same-origin" }), v = await r.json();
23088
+ const r = await fetch(url + "&revision=" + revision2, { credentials: "same-origin" }), v = await r.json();
22976
23089
  if (!r.ok) throw new Error(v.error ?? "\u5386\u53F2\u8BFB\u53D6\u5931\u8D25");
22977
23090
  setPreview({ ...v, document: validateDocument(v.document) });
22978
23091
  } catch (e) {
@@ -23003,16 +23116,20 @@ function HistoryView({ record, sessionId }) {
23003
23116
  }
23004
23117
 
23005
23118
  // src/presentation.js
23006
- var import_react8 = __toESM(require("react"), 1);
23119
+ var import_react11 = __toESM(require("react"), 1);
23007
23120
  var import_react_dom = __toESM(require_react_dom(), 1);
23008
23121
 
23009
23122
  // src/presentation-store.js
23010
- var import_react7 = require("react");
23123
+ var import_react9 = require("react");
23011
23124
  var records = /* @__PURE__ */ new Map();
23012
23125
  var listeners3 = /* @__PURE__ */ new Set();
23013
23126
  var locations = /* @__PURE__ */ new Map();
23014
23127
  var opener;
23015
- var emit = () => listeners3.forEach((fn) => fn());
23128
+ var revision = 0;
23129
+ var emit = () => {
23130
+ revision++;
23131
+ listeners3.forEach((fn) => fn());
23132
+ };
23016
23133
  var notifyUi = emit;
23017
23134
  function rememberUi(raw, sessionId, sendPrompt) {
23018
23135
  if (raw?.version !== 1 || raw.sessionId !== sessionId) return;
@@ -23028,8 +23145,7 @@ var subscribeUi = (fn) => {
23028
23145
  return () => listeners3.delete(fn);
23029
23146
  };
23030
23147
  function useUiRegistry() {
23031
- const [, wake] = (0, import_react7.useState)(0);
23032
- (0, import_react7.useEffect)(() => subscribeUi(() => wake((v) => v + 1)), []);
23148
+ (0, import_react9.useSyncExternalStore)(subscribeUi, () => revision, () => 0);
23033
23149
  return uiRecords();
23034
23150
  }
23035
23151
  function setPanelOpener(fn) {
@@ -23057,10 +23173,10 @@ function removeMarkerLocation(id, host) {
23057
23173
  }
23058
23174
  }
23059
23175
  var markerLocation = (id) => locations.get(id);
23060
- function usePresentation(scope) {
23061
- const [, wake] = (0, import_react7.useState)(0);
23062
- (0, import_react7.useEffect)(() => scope?.subscribe(() => wake((v) => v + 1)), [scope]);
23063
- return scope?.getSnapshot().value?.displayMode ?? "tail";
23176
+ function usePresentation(scope2) {
23177
+ const [, wake] = (0, import_react9.useState)(0);
23178
+ (0, import_react9.useEffect)(() => scope2?.subscribe(() => wake((v) => v + 1)), [scope2]);
23179
+ return scope2?.getSnapshot().value?.displayMode ?? "tail";
23064
23180
  }
23065
23181
 
23066
23182
  // src/markers.js
@@ -23120,16 +23236,59 @@ function startUiMarkers(root, sessionId) {
23120
23236
  };
23121
23237
  }
23122
23238
 
23239
+ // src/presentation-owner.js
23240
+ var import_react10 = require("react");
23241
+ var roots = /* @__PURE__ */ new WeakMap();
23242
+ function usePresentationOwner(anchor, documentId, sessionId) {
23243
+ const [owner, setOwner] = (0, import_react10.useState)(false);
23244
+ (0, import_react10.useEffect)(() => {
23245
+ const element = anchor.current;
23246
+ if (!element) return;
23247
+ const root = element.closest("[data-conversation-scroll]") ?? element.parentElement;
23248
+ if (!root) return;
23249
+ let documents = roots.get(root);
23250
+ if (!documents) {
23251
+ documents = /* @__PURE__ */ new Map();
23252
+ roots.set(root, documents);
23253
+ }
23254
+ const key2 = sessionId + ":" + documentId;
23255
+ let entries = documents.get(key2);
23256
+ if (!entries) {
23257
+ entries = /* @__PURE__ */ new Set();
23258
+ documents.set(key2, entries);
23259
+ }
23260
+ const entry = { element, update: setOwner };
23261
+ entries.add(entry);
23262
+ const elect = () => {
23263
+ let winner;
23264
+ for (const candidate of entries) {
23265
+ if (!candidate.element.isConnected) continue;
23266
+ if (!winner || winner.element.compareDocumentPosition(candidate.element) & 4) winner = candidate;
23267
+ }
23268
+ for (const candidate of entries) candidate.update(candidate === winner);
23269
+ };
23270
+ elect();
23271
+ return () => {
23272
+ entries.delete(entry);
23273
+ elect();
23274
+ if (!entries.size) documents.delete(key2);
23275
+ };
23276
+ }, [anchor, documentId, sessionId]);
23277
+ return owner;
23278
+ }
23279
+
23123
23280
  // src/presentation.js
23124
- var h5 = import_react8.default.createElement;
23281
+ var h5 = import_react11.default.createElement;
23125
23282
  var scanners = /* @__PURE__ */ new WeakMap();
23126
23283
  var focused = /* @__PURE__ */ new Map();
23127
- function PresentationView({ raw, sessionId, sendPrompt, scope }) {
23128
- const anchor = (0, import_react8.useRef)(null), records2 = useUiRegistry(), mode = usePresentation(scope), host = markerLocation(raw.documentId);
23129
- (0, import_react8.useEffect)(() => {
23284
+ function PresentationView({ raw, sessionId, sendPrompt, scope: scope2 }) {
23285
+ const showDetails = useViewDetails();
23286
+ const anchor = (0, import_react11.useRef)(null), records2 = useUiRegistry(), mode = usePresentation(scope2), host = markerLocation(raw.documentId);
23287
+ const owner = usePresentationOwner(anchor, raw.documentId, sessionId);
23288
+ (0, import_react11.useEffect)(() => {
23130
23289
  rememberUi(raw, sessionId, sendPrompt);
23131
23290
  }, [raw, sessionId, sendPrompt]);
23132
- (0, import_react8.useEffect)(() => {
23291
+ (0, import_react11.useEffect)(() => {
23133
23292
  const root = anchor.current?.closest("[data-conversation-scroll]");
23134
23293
  if (!root) return;
23135
23294
  let entry = scanners.get(root);
@@ -23150,31 +23309,31 @@ function PresentationView({ raw, sessionId, sendPrompt, scope }) {
23150
23309
  }
23151
23310
  };
23152
23311
  }, [sessionId]);
23153
- (0, import_react8.useEffect)(() => {
23312
+ (0, import_react11.useEffect)(() => {
23154
23313
  const block = host?.uiMarkerBlock;
23155
- if (!block) return;
23314
+ if (!block || !owner) return;
23156
23315
  const previous = block.style.display;
23157
23316
  block.style.display = mode === "inline" ? "none" : previous;
23158
23317
  return () => {
23159
23318
  block.style.display = previous;
23160
23319
  };
23161
- }, [host, mode]);
23320
+ }, [host, mode, owner]);
23162
23321
  const available = panelAvailable();
23163
- (0, import_react8.useEffect)(() => {
23164
- if (mode === "sidebar" && available) openUiPanel(raw.documentId, sessionId);
23165
- }, [mode, available, sessionId, raw.documentId]);
23322
+ (0, import_react11.useEffect)(() => {
23323
+ if (owner && mode === "sidebar" && available) openUiPanel(raw.documentId, sessionId);
23324
+ }, [mode, available, sessionId, raw.documentId, owner]);
23166
23325
  const content = h5(ValidatedView, { raw, fallback: raw.document.fallback, sessionId, sendPrompt });
23167
23326
  return h5(
23168
23327
  "div",
23169
23328
  { ref: anchor, "data-dgui-presentation": raw.documentId },
23170
- available && h5("button", { type: "button", className: "dgui-secondary", onClick: () => openUiPanel(raw.documentId, sessionId) }, "\u5728\u4FA7\u680F\u6253\u5F00"),
23171
- 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,
23172
- mode === "inline" && !host && h5("small", { className: "dgui-copy" }, "\u6B63\u6587\u6807\u8BB0\u5C1A\u672A\u51FA\u73B0\uFF0C\u6682\u5728\u56DE\u7B54\u4E0B\u65B9\u663E\u793A\u3002")
23329
+ owner && available && h5("button", { type: "button", className: "dgui-secondary", onClick: () => openUiPanel(raw.documentId, sessionId) }, "\u5728\u4FA7\u680F\u6253\u5F00"),
23330
+ owner && (mode === "sidebar" && available ? h5("p", { className: "dgui-copy" }, `${raw.document.title} \xB7 \u5728\u4FA7\u680F\u4E2D\u64CD\u4F5C`) : mode === "inline" && host ? (0, import_react_dom.createPortal)(content, host) : content),
23331
+ showDetails && owner && mode === "inline" && !host && h5("small", { className: "dgui-copy" }, "\u672A\u63D0\u4F9B\u6B63\u6587\u6807\u8BB0\uFF0C\u754C\u9762\u663E\u793A\u5728\u56DE\u7B54\u4E0B\u65B9\u3002")
23173
23332
  );
23174
23333
  }
23175
23334
  function UiPanel({ sessionId, sendPrompt }) {
23176
- const records2 = useUiRegistry().filter((r) => r.sessionId === sessionId), [selected, setSelected] = (0, import_react8.useState)(focused.get(sessionId));
23177
- (0, import_react8.useEffect)(() => subscribeUi(() => setSelected(focused.get(sessionId))), [sessionId]);
23335
+ const records2 = useUiRegistry().filter((r) => r.sessionId === sessionId), [selected, setSelected] = (0, import_react11.useState)(focused.get(sessionId));
23336
+ (0, import_react11.useEffect)(() => subscribeUi(() => setSelected(focused.get(sessionId))), [sessionId]);
23178
23337
  const record = records2.find((r) => r.raw.documentId === selected) ?? records2.at(-1);
23179
23338
  return h5(
23180
23339
  "div",
@@ -23192,11 +23351,11 @@ function focusUi(id, sessionId) {
23192
23351
  }
23193
23352
 
23194
23353
  // src/view.js
23195
- var h6 = import_react9.default.createElement;
23354
+ var h6 = import_react12.default.createElement;
23196
23355
  var display = (value) => value === void 0 || value === null ? "\u2014" : typeof value === "object" ? JSON.stringify(value) : String(value);
23197
23356
  function NumericInput({ id, spec, value, onChange, invalidChanged, disabled }) {
23198
- const [draft, setDraft] = (0, import_react9.useState)(String(value)), [invalid, setInvalid] = (0, import_react9.useState)(false);
23199
- (0, import_react9.useEffect)(() => {
23357
+ const [draft, setDraft] = (0, import_react12.useState)(String(value)), [invalid, setInvalid] = (0, import_react12.useState)(false);
23358
+ (0, import_react12.useEffect)(() => {
23200
23359
  setDraft(String(value));
23201
23360
  setInvalid(false);
23202
23361
  invalidChanged(id, false);
@@ -23220,15 +23379,17 @@ function NumericInput({ id, spec, value, onChange, invalidChanged, disabled }) {
23220
23379
  }
23221
23380
  });
23222
23381
  }
23223
- function Table({ rows, columns, id }) {
23382
+ function Table({ rows, columns, id, label }) {
23224
23383
  return h6("div", { className: "dgui-table-wrap" }, h6(
23225
23384
  "table",
23226
23385
  { "data-ui-node": id },
23386
+ label && h6("caption", null, label),
23227
23387
  h6("thead", null, h6("tr", null, columns.map((c) => h6("th", { key: c.key, scope: "col" }, c.label, c.unit ? ` (${c.unit})` : "")))),
23228
23388
  h6("tbody", null, rows.length ? rows.map((row, i) => h6("tr", { key: i }, columns.map((c) => h6("td", { key: c.key, "data-numeric": typeof row[c.key] === "number" }, display(Object.hasOwn(row, c.key) ? row[c.key] : void 0))))) : h6("tr", null, h6("td", { colSpan: columns.length }, "\u6682\u65E0\u6570\u636E")))
23229
23389
  ));
23230
23390
  }
23231
23391
  function Chart({ node, rows }) {
23392
+ const [showData, setShowData] = (0, import_react12.useState)(false);
23232
23393
  const data = rows.slice(0, 40), values = data.map((r) => r[node.valueKey]);
23233
23394
  const low = node.kind === "line" && values.length ? Math.min(...values) : Math.min(0, ...values);
23234
23395
  const high = node.kind === "line" && values.length ? Math.max(...values) : Math.max(0, ...values), range = high - low || 1;
@@ -23241,7 +23402,7 @@ function Chart({ node, rows }) {
23241
23402
  return h6(
23242
23403
  "figure",
23243
23404
  { className: "dgui-chart", "data-ui-node": node.id },
23244
- h6("figcaption", null, h6(Icon, { name: "chart" }), node.label, node.unit && h6("span", { className: "dgui-chart-unit" }, `(${node.unit})`)),
23405
+ h6("figcaption", null, h6(Icon, { name: "chart" }), node.label, rows.length > 40 && "\uFF08\u56FE\u793A\u524D 40 \u9879\uFF09", node.unit && h6("span", { className: "dgui-chart-unit" }, `(${node.unit})`), h6("button", { type: "button", className: "dgui-chart-data-button", "aria-expanded": showData, onClick: () => setShowData(!showData) }, "\u56FE\u8868\u6570\u636E")),
23245
23406
  h6("div", { className: "dgui-plot", tabIndex: 0, role: "region", "aria-label": `${node.label}\u56FE\u8868\uFF0C\u53EF\u6A2A\u5411\u6EDA\u52A8` }, h6(
23246
23407
  "svg",
23247
23408
  { viewBox: `0 0 ${width} 205`, role: "img", "aria-label": `${node.label}\u3002\u5C55\u5F00\u56FE\u8868\u6570\u636E\u53EF\u67E5\u770B\u6BCF\u9879\u6570\u503C\u3002` },
@@ -23256,16 +23417,15 @@ function Chart({ node, rows }) {
23256
23417
  (data.length <= 12 || i % Math.ceil(data.length / 12) === 0) && h6("text", { x: x(i), y: 192, textAnchor: "middle", fontSize: 14, fill: "var(--du-muted)" }, String(r[node.labelKey]).slice(0, 12))
23257
23418
  ))
23258
23419
  )),
23259
- 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"),
23260
- rows.length > 40 && h6("small", null, "\u56FE\u793A\u524D 40 \u9879\uFF0C\u5B8C\u6574\u6570\u503C\u89C1\u4E0B\u65B9\u6570\u636E\u3002"),
23261
- h6("details", null, h6("summary", null, "\u56FE\u8868\u6570\u636E"), h6(Table, { rows, columns: [{ key: node.labelKey, label: "\u9879\u76EE" }, { key: node.valueKey, label: node.label, unit: node.unit }], id: `${node.id}-data` }))
23420
+ h6("div", { hidden: !showData }, h6(Table, { rows, columns: [{ key: node.labelKey, label: "\u9879\u76EE" }, { key: node.valueKey, label: node.label, unit: node.unit }], id: `${node.id}-data` }))
23262
23421
  );
23263
23422
  }
23264
23423
  function UiView({ record, sessionId, sendPrompt, preview = false }) {
23424
+ const showDetails = useViewDetails();
23265
23425
  const doc = record.document;
23266
- const viewId = import_react9.default.useId();
23267
- const root = (0, import_react9.useRef)(null), canvasAudits = (0, import_react9.useRef)(/* @__PURE__ */ new Map()), [audit, setAudit] = (0, import_react9.useState)(null), auditPending = (0, import_react9.useRef)(0);
23268
- const collectAudit = import_react9.default.useCallback(() => {
23426
+ const viewId = import_react12.default.useId();
23427
+ const root = (0, import_react12.useRef)(null), canvasAudits = (0, import_react12.useRef)(/* @__PURE__ */ new Map()), [audit, setAudit] = (0, import_react12.useState)(null), auditPending = (0, import_react12.useRef)(0);
23428
+ const collectAudit = import_react12.default.useCallback(() => {
23269
23429
  clearTimeout(auditPending.current);
23270
23430
  auditPending.current = setTimeout(() => {
23271
23431
  if (!root.current || preview) return;
@@ -23277,7 +23437,7 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
23277
23437
  });
23278
23438
  }, 250);
23279
23439
  }, [record.documentId, record.documentRevision, sessionId, preview]);
23280
- (0, import_react9.useEffect)(() => {
23440
+ (0, import_react12.useEffect)(() => {
23281
23441
  canvasAudits.current.clear();
23282
23442
  collectAudit();
23283
23443
  window.addEventListener("resize", collectAudit);
@@ -23295,22 +23455,22 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
23295
23455
  collectAudit();
23296
23456
  };
23297
23457
  const { state, setState, ready, status, issue, epoch, retry, useRemote, keepLocal } = useSavedState(record, sessionId, preview);
23298
- const [error, setError] = (0, import_react9.useState)(""), [actionStatus, setActionStatus] = (0, import_react9.useState)("");
23299
- const [busy, setBusy] = (0, import_react9.useState)(false), [invalidFields, setInvalidFields] = (0, import_react9.useState)({});
23300
- const pending = (0, import_react9.useRef)(false);
23301
- (0, import_react9.useEffect)(() => {
23458
+ const [error, setError] = (0, import_react12.useState)(""), [actionStatus, setActionStatus] = (0, import_react12.useState)("");
23459
+ const [busy, setBusy] = (0, import_react12.useState)(false), [invalidFields, setInvalidFields] = (0, import_react12.useState)({});
23460
+ const pending = (0, import_react12.useRef)(false);
23461
+ (0, import_react12.useEffect)(() => {
23302
23462
  setInvalidFields({});
23303
23463
  }, [epoch]);
23304
- const invalidChanged = import_react9.default.useCallback((id, invalid) => setInvalidFields((previous) => previous[id] === invalid ? previous : { ...previous, [id]: invalid }), []);
23464
+ const invalidChanged = import_react12.default.useCallback((id, invalid) => setInvalidFields((previous) => previous[id] === invalid ? previous : { ...previous, [id]: invalid }), []);
23305
23465
  let computed;
23306
23466
  try {
23307
23467
  computed = evaluate(doc, state);
23308
23468
  } catch (e) {
23309
23469
  computed = { error: e.message };
23310
23470
  }
23311
- const currentState = (0, import_react9.useRef)(state);
23471
+ const currentState = (0, import_react12.useRef)(state);
23312
23472
  currentState.current = state;
23313
- (0, import_react9.useEffect)(() => {
23473
+ (0, import_react12.useEffect)(() => {
23314
23474
  collectAudit();
23315
23475
  }, [state, ready, collectAudit]);
23316
23476
  const updatePatch = (patch) => {
@@ -23320,9 +23480,9 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
23320
23480
  setError("");
23321
23481
  setActionStatus("");
23322
23482
  };
23323
- const update = (key3, value) => {
23483
+ const update = (key2, value) => {
23324
23484
  try {
23325
- updatePatch({ [key3]: value });
23485
+ updatePatch({ [key2]: value });
23326
23486
  } catch (e) {
23327
23487
  setError(e.message);
23328
23488
  }
@@ -23372,7 +23532,7 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
23372
23532
  return h6("ol", { ...props, className: "dgui-steps" }, n.items.map((item, i) => h6("li", { key: i, "data-step-status": item.status }, h6("span", { className: "dgui-step-dot", "aria-hidden": true }, item.status === "done" ? h6(Icon, { name: "check" }) : item.status === "error" ? h6(Icon, { name: "warning" }) : i + 1), h6("div", null, h6("strong", null, item.title), h6("span", { className: "dgui-step-state" }, { pending: "\u5F85\u8FDB\u884C", active: "\u5F53\u524D\u6B65\u9AA4", done: "\u5DF2\u5B8C\u6210", error: "\u5F02\u5E38" }[item.status]), item.description && h6("p", null, item.description)))));
23373
23533
  case "metric": {
23374
23534
  const v = resolve(n.value);
23375
- 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)));
23535
+ return h6("div", { ...props, className: "dgui-metric" }, h6("span", { className: "dgui-metric-label" }, h6(Icon, { name: n.icon ?? "gauge" }), n.label), h6("strong", null, typeof v === "number" ? formatNumber(v, n.decimals ?? 2) : display(v), " ", h6("small", null, n.unit)));
23376
23536
  }
23377
23537
  case "input":
23378
23538
  case "slider":
@@ -23382,7 +23542,7 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
23382
23542
  let control;
23383
23543
  if (n.type === "select") control = h6("select", { id, value: spec.options.indexOf(v), disabled: !ready, onChange: (e) => update(k, spec.options[Number(e.target.value)]) }, spec.options.map((o, i) => h6("option", { key: i, value: i }, display(o))));
23384
23544
  else if (n.type === "toggle") control = h6("input", { id, className: "dgui-toggle", type: "checkbox", checked: v, disabled: !ready, onChange: (e) => update(k, e.target.checked) });
23385
- else if (n.type === "slider") control = h6(import_react9.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)));
23545
+ else if (n.type === "slider") control = h6(import_react12.default.Fragment, null, h6("input", { id, type: "range", min: spec.min, max: spec.max, step: spec.step, value: v, disabled: !ready, onChange: (e) => update(k, Number(e.target.value)) }), h6("output", { htmlFor: id }, display(v)));
23386
23546
  else if (spec.type === "number") control = h6(NumericInput, { id, spec, value: v, disabled: !ready, invalidChanged, onChange: (value) => update(k, value) });
23387
23547
  else control = h6("input", { id, type: "text", value: v, maxLength: 8192, disabled: !ready, onChange: (e) => update(k, e.target.value) });
23388
23548
  return h6("div", { ...props, className: "dgui-control" }, h6("label", { htmlFor: id }, h6(Icon, { name: n.type === "toggle" ? "layers" : n.type === "select" ? "target" : "sliders" }), h6("span", null, n.label)), control);
@@ -23390,7 +23550,7 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
23390
23550
  case "button":
23391
23551
  return h6("button", { ...props, className: "dgui-button", type: "button", disabled: disabled || !sendPrompt, onClick: () => followup(n.action) }, n.text, h6(Icon, { name: n.icon ?? "arrow" }));
23392
23552
  case "table":
23393
- return computed.error ? null : h6(Table, { key: n.id, id: n.id, rows: resolve(n.rows), columns: n.columns });
23553
+ return computed.error ? null : h6(Table, { key: n.id, id: n.id, label: n.label, rows: resolve(n.rows), columns: n.columns });
23394
23554
  case "chart":
23395
23555
  return computed.error ? null : h6(Chart, { key: n.id, node: n, rows: resolve(n.rows) });
23396
23556
  default:
@@ -23401,14 +23561,14 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
23401
23561
  return h6(
23402
23562
  "section",
23403
23563
  { ref: root, className: "dgui-root", "data-document-revision": record.documentRevision ?? 0, "data-dgui-build": BUILD_INFO.id, "data-dsh-generative-ui": record.documentId, "data-layout": doc.presentation?.layout, "data-accent": doc.presentation?.accent, "data-density": doc.presentation?.density, "data-preview": preview || void 0, "aria-label": doc.title, "aria-busy": preview || void 0 },
23404
- h6("header", { className: "dgui-header" }, h6("span", { className: "dgui-heading-icon" }, h6(Icon, { name: sceneIcons[doc.presentation?.layout] ?? "sliders" })), h6("strong", { className: "dgui-header-title" }, doc.title), h6("span", { className: "dgui-badge" }, h6(Icon, { name: "sparkles" }), preview ? "\u751F\u6210\u4E2D" : "\u4EA4\u4E92\u754C\u9762")),
23564
+ h6("header", { className: "dgui-header" }, h6("span", { className: "dgui-heading-icon" }, h6(Icon, { name: sceneIcons[doc.presentation?.layout] ?? (Object.keys(doc.state).length ? "sliders" : "layers") })), h6("strong", { className: "dgui-header-title" }, doc.title), h6("span", { className: "dgui-badge" }, h6(Icon, { name: "sparkles" }), preview ? "\u751F\u6210\u4E2D" : "\u53EF\u89C6\u5316")),
23405
23565
  h6("div", { key: epoch, className: "dgui-content" }, doc.nodes.map(renderNode)),
23406
- h6("div", { className: "dgui-status", role: "status", "data-status": /失败|冲突/.test(status) ? "error" : /正在|等待/.test(status) ? "pending" : "saved" }, h6(Icon, { name: /失败|冲突/.test(status) ? "warning" : /正在|等待/.test(status) ? "database" : "check" }), h6("span", null, status), actionStatus && h6("span", null, ` \xB7 ${actionStatus}`)),
23566
+ (Object.keys(doc.state).length > 0 || issue || actionStatus) && h6("div", { className: showDetails || issue || actionStatus ? "dgui-status" : "dgui-sr-only", role: "status", "data-status": /失败|冲突/.test(status) ? "error" : /正在|等待/.test(status) ? "pending" : "saved" }, h6(Icon, { name: /失败|冲突/.test(status) ? "warning" : /正在|等待/.test(status) ? "database" : "check" }), h6("span", null, status), actionStatus && h6("span", null, ` \xB7 ${actionStatus}`)),
23407
23567
  issue && h6(
23408
23568
  "div",
23409
23569
  { className: "dgui-recovery" },
23410
23570
  issue.kind === "conflict" ? h6(
23411
- import_react9.default.Fragment,
23571
+ import_react12.default.Fragment,
23412
23572
  null,
23413
23573
  h6("button", { type: "button", className: "dgui-secondary", disabled: status === "\u6B63\u5728\u6062\u590D\u53C2\u6570\u2026", onClick: useRemote }, "\u4F7F\u7528\u5DF2\u4FDD\u5B58\u53C2\u6570"),
23414
23574
  h6("button", { type: "button", className: "dgui-secondary", disabled: status === "\u6B63\u5728\u6062\u590D\u53C2\u6570\u2026", onClick: keepLocal }, "\u4FDD\u7559\u672C\u9875\u53C2\u6570\u5E76\u91CD\u8BD5")
@@ -23416,12 +23576,12 @@ function UiView({ record, sessionId, sendPrompt, preview = false }) {
23416
23576
  ),
23417
23577
  (error || computed.error) && h6("p", { className: "dgui-error", role: "alert" }, error || computed.error),
23418
23578
  Object.values(invalidFields).some(Boolean) && h6("p", { className: "dgui-error", role: "alert" }, "\u8BF7\u8F93\u5165\u8303\u56F4\u5185\u4E14\u7B26\u5408\u6B65\u957F\u7684\u6570\u503C\u3002"),
23419
- !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")),
23420
- !preview && h6(HistoryView, { record, sessionId }),
23421
- h6("details", { className: "dgui-fallback" }, h6("summary", null, Object.keys(doc.state).length ? "\u539F\u59CB\u6587\u5B57\u8BF4\u660E\u4E0E\u521D\u59CB\u53C2\u6570" : "\u539F\u59CB\u6587\u5B57\u8BF4\u660E"), h6("p", null, doc.fallback), Object.keys(doc.state).length > 0 && h6("pre", null, JSON.stringify(initialState(doc), null, 2)))
23579
+ showDetails && !preview && audit && h6("details", { className: "dgui-fallback dgui-audit" }, h6("summary", null, "\u663E\u793A\u68C0\u67E5"), h6("p", null, `${audit.width}px \xB7 ${audit.theme === "dark" ? "\u6DF1\u8272" : "\u6D45\u8272"} \xB7 \u542F\u53D1\u5F0F\u89C2\u5BDF\uFF0C\u4E0D\u4EE3\u8868\u5B8C\u6574\u89C6\u89C9\u9A8C\u6536\u3002`), h6("p", null, "\u672A\u8986\u76D6\uFF1A\u590D\u6742\u80CC\u666F\u3001\u906E\u6321\u5173\u7CFB\u53CA SVG \u914D\u8272\uFF1B\u62A5\u544A\u4E0D\u7B49\u4E8E\u5B8C\u6574\u65E0\u969C\u788D\u68C0\u67E5\u3002"), audit.coverage?.some((c) => c.truncated) && h6("p", null, "\u5185\u5BB9\u8F83\u591A\uFF0C\u672C\u6B21\u53EA\u68C0\u67E5\u4E86\u6BCF\u4E2A\u533A\u57DF\u7684\u524D 2000 \u4E2A\u5143\u7D20\u3002"), audit.issues.length ? h6("ul", null, audit.issues.map((i, j) => h6("li", { key: j }, AUDIT_MESSAGES[i.code], i.nodeId ? `\uFF08${i.nodeId}\uFF09` : ""))) : h6("p", null, "\u672C\u6B21\u68C0\u67E5\u672A\u53D1\u73B0\u6240\u8986\u76D6\u7684\u95EE\u9898\u3002")),
23580
+ showDetails && !preview && h6(HistoryView, { record, sessionId }),
23581
+ showDetails && h6("details", { className: "dgui-fallback" }, h6("summary", null, Object.keys(doc.state).length ? "\u539F\u59CB\u6587\u5B57\u8BF4\u660E\u4E0E\u521D\u59CB\u53C2\u6570" : "\u539F\u59CB\u6587\u5B57\u8BF4\u660E"), h6("p", null, doc.fallback), Object.keys(doc.state).length > 0 && h6("pre", null, JSON.stringify(initialState(doc), null, 2)))
23422
23582
  );
23423
23583
  }
23424
- var UiBoundary = class extends import_react9.default.Component {
23584
+ var UiBoundary = class extends import_react12.default.Component {
23425
23585
  state = { failed: false };
23426
23586
  static getDerivedStateFromError() {
23427
23587
  return { failed: true };
@@ -23444,9 +23604,11 @@ function StreamingToolView(props) {
23444
23604
  return h6(StreamingPreview, { raw, callId: props.callId, sessionId: props.sessionId });
23445
23605
  }
23446
23606
  function StreamingPreview({ raw, callId = "stream", sessionId }) {
23447
- const deferred = import_react9.default.useDeferredValue(raw);
23448
- const doc = (0, import_react9.useMemo)(() => previewDocument(deferred), [deferred]);
23449
- const canvas = (0, import_react9.useMemo)(() => doc ? null : previewCanvas(deferred), [doc, deferred]);
23607
+ const committed = useUiRegistry().some((r) => r.sessionId === sessionId && r.raw.callId === callId);
23608
+ const deferred = import_react12.default.useDeferredValue(raw);
23609
+ const doc = (0, import_react12.useMemo)(() => previewDocument(deferred), [deferred]);
23610
+ const canvas = (0, import_react12.useMemo)(() => doc ? null : previewCanvas(deferred), [doc, deferred]);
23611
+ if (committed) return h6("p", { className: "dgui-copy" }, "\u754C\u9762\u5DF2\u751F\u6210\u3002");
23450
23612
  if (canvas) return h6("div", { className: "dgui-root", "data-preview": true }, h6(CanvasPreview, { node: canvas }));
23451
23613
  if (!doc) return h6("div", { className: "dgui-pending", role: "status" }, "\u6B63\u5728\u7EC4\u7EC7\u5E76\u6821\u9A8C\u4EA4\u4E92\u754C\u9762\u2026");
23452
23614
  return h6(UiBoundary, { key: callId, fallback: doc.fallback }, h6(UiView, { record: { document: doc, documentId: `preview-${callId}` }, sessionId, preview: true }));
@@ -23455,7 +23617,7 @@ function TurnUiView(props) {
23455
23617
  return (props.turn.data.get("dshGenerativeUi") ?? []).filter((r) => r.seq < props.seq).map((r) => r.isPatch ? h6(PatchNotice, { key: `patch-${r.seq}`, raw: r.raw }) : h6(PresentationView, { key: r.raw.documentId, ...r, sessionId: props.sessionId, sendPrompt: props.sendPrompt, scope: props.presentationScope }));
23456
23618
  }
23457
23619
  function PatchNotice({ raw }) {
23458
- (0, import_react9.useEffect)(() => {
23620
+ (0, import_react12.useEffect)(() => {
23459
23621
  try {
23460
23622
  if (raw) publishDocument(raw);
23461
23623
  } catch {
@@ -23465,7 +23627,7 @@ function PatchNotice({ raw }) {
23465
23627
  }
23466
23628
  function ValidatedView({ raw, fallback, sessionId, sendPrompt }) {
23467
23629
  const { record: current2, status, retry } = useCurrentDocument(raw ?? {}, sessionId);
23468
- const result = (0, import_react9.useMemo)(() => {
23630
+ const result = (0, import_react12.useMemo)(() => {
23469
23631
  try {
23470
23632
  if (!current2 || current2.version !== 1 || typeof current2.documentId !== "string" || typeof current2.callId !== "string") return null;
23471
23633
  return { ...current2, document: validateDocument(current2.document) };
@@ -23475,7 +23637,7 @@ function ValidatedView({ raw, fallback, sessionId, sendPrompt }) {
23475
23637
  }, [current2]);
23476
23638
  if (!result) return h6("div", { className: "dgui-root" }, h6("p", null, "\u6587\u5B57\u7ED3\u679C\uFF08\u672A\u63D0\u4F9B\u517C\u5BB9\u7684\u754C\u9762\u6570\u636E\uFF09"), h6("pre", null, fallback));
23477
23639
  return h6(
23478
- import_react9.default.Fragment,
23640
+ import_react12.default.Fragment,
23479
23641
  null,
23480
23642
  status === "error" && h6("div", { className: "dgui-root dgui-document-warning", role: "status" }, h6("p", null, "\u672A\u80FD\u786E\u8BA4\u6700\u65B0\u754C\u9762\u7248\u672C\uFF0C\u5F53\u524D\u663E\u793A\u5DF2\u77E5\u7248\u672C\u3002"), h6("button", { type: "button", className: "dgui-secondary", onClick: retry }, "\u91CD\u65B0\u8BFB\u53D6\u6700\u65B0\u754C\u9762")),
23481
23643
  status === "loading" && h6("p", { className: "dgui-copy", role: "status" }, "\u6B63\u5728\u8BFB\u53D6\u6700\u65B0\u754C\u9762\u7248\u672C\u2026"),
@@ -23503,8 +23665,8 @@ var turnUiDefinition = {
23503
23665
  const fallback = (event.data.message.content ?? []).filter((c) => c.type === "text").map((c) => c.text).join("\n");
23504
23666
  return { ...context.state, records: [...context.state.records, { seq: event.seq, raw, fallback, ...isPatch ? { isPatch: true } : {} }] };
23505
23667
  },
23506
- buildLocationData(context, scope, previous) {
23507
- if (scope !== "turn" || !context.state) return null;
23668
+ buildLocationData(context, scope2, previous) {
23669
+ if (scope2 !== "turn" || !context.state) return null;
23508
23670
  if (previous?.key === "dshGenerativeUi" && previous.value === context.state.records) return previous;
23509
23671
  return { kind: "turn", turn: context.state.turn, key: "dshGenerativeUi", value: context.state.records };
23510
23672
  }
@@ -23538,8 +23700,30 @@ var CANVAS_CSS = `
23538
23700
  .dgui-canvas{min-width:0}.dgui-canvas-stage{position:relative}.dgui-canvas-loading{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;gap:10px;color:var(--du-muted);font-size:13px;background:var(--du-soft);border-radius:12px}.dgui-canvas-spinner{width:16px;height:16px;border:2px solid var(--du-line);border-top-color:var(--du-accent);border-radius:50%;animation:dgui-spin .9s linear infinite}.dgui-canvas-placeholder{padding:24px 18px;background:var(--du-soft);border:1px dashed var(--du-line);border-radius:12px;color:var(--du-muted);font-size:13px;display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}.dgui-canvas-placeholder p{margin:0}.dgui-canvas-options{margin-top:6px}.dgui-root .dgui-canvas-options>summary{font-size:12px;padding:5px 0;color:var(--du-muted);width:fit-content}.dgui-canvas-options[open]{border-top:1px solid var(--du-line);padding-top:8px;margin-top:12px}.dgui-canvas-options>.dgui-copy{padding:8px 0;font-size:12px}.dgui-canvas-issue{border:1px solid color-mix(in srgb,var(--du-amber) 30%,var(--du-line));background:color-mix(in srgb,var(--du-amber) 5%,var(--du-bg));border-radius:10px;padding:14px;margin-top:10px;font-size:12px;color:var(--du-ink)}.dgui-canvas-issue>strong{font-size:13px}.dgui-canvas-issue>p{color:var(--du-muted);margin-top:4px}.dgui-canvas-issue details{margin-top:8px}.dgui-root .dgui-canvas-issue pre{max-height:160px;overflow:auto}.dgui-canvas-options .dgui-secondary{font-size:12px;padding:6px 9px;box-shadow:none}@keyframes dgui-spin{to{transform:rotate(360deg)}}@media(prefers-reduced-motion:reduce){.dgui-canvas-spinner{animation:none}}@media(forced-colors:active){.dgui-canvas-issue,.dgui-canvas-placeholder{border-color:CanvasText}}
23539
23701
  `;
23540
23702
 
23703
+ // src/soft-styles.js
23704
+ var SOFT_CSS = `
23705
+ .dgui-root{--du-radius:24px;--du-radius-inner:18px;background:linear-gradient(145deg,color-mix(in srgb,var(--du-accent) 4%,var(--du-bg)),var(--du-bg) 42%,color-mix(in srgb,var(--du-violet) 3%,var(--du-bg)));border-radius:var(--du-radius)}
23706
+ .dgui-root .dgui-card,.dgui-root .dgui-metric,.dgui-root .dgui-chart,.dgui-root .dgui-progress,.dgui-root .dgui-details{border-radius:var(--du-radius-inner);background:linear-gradient(135deg,color-mix(in srgb,var(--du-tone) 9%,var(--du-bg)),color-mix(in srgb,var(--du-violet) 4%,var(--du-bg)) 65%,var(--du-bg))}
23707
+ .dgui-root .dgui-card[data-surface=soft]{background:linear-gradient(135deg,var(--du-soft),color-mix(in srgb,var(--du-accent) 7%,var(--du-bg)))}
23708
+ .dgui-root .dgui-card[data-surface=featured]{border-radius:20px;background:linear-gradient(130deg,color-mix(in srgb,var(--du-accent) 14%,var(--du-bg)),color-mix(in srgb,var(--du-violet) 7%,var(--du-bg)));box-shadow:none}
23709
+ .dgui-root[data-layout=dashboard] .dgui-metric{background:linear-gradient(135deg,color-mix(in srgb,var(--du-tone) 11%,var(--du-bg)),var(--du-bg))}
23710
+ .dgui-root[data-layout=report] .dgui-card{padding:16px 18px;border:1px solid var(--du-line);border-radius:18px}
23711
+ .dgui-root .dgui-heading-icon{border-radius:14px;background:linear-gradient(145deg,color-mix(in srgb,var(--du-accent) 14%,var(--du-bg)),color-mix(in srgb,var(--du-violet) 8%,var(--du-bg)))}
23712
+ .dgui-root .dgui-button{border-radius:14px;background:linear-gradient(120deg,var(--du-action,#3e60d3),color-mix(in srgb,var(--du-action,#3e60d3) 85%,#152647))}
23713
+ .dgui-root input:not([type=range]):not([type=checkbox]),.dgui-root select,.dgui-root textarea,.dgui-root .dgui-secondary,.dgui-root .dgui-menu-trigger{border-radius:12px}
23714
+ .dgui-root .dgui-menu-content,.dgui-root .dgui-table-wrap,.dgui-root .dgui-canvas-placeholder,.dgui-root .dgui-canvas-loading,.dgui-root .dgui-canvas-issue{border-radius:18px}
23715
+ .dgui-root .dgui-menu-content button{border-radius:12px}.dgui-root .dgui-badge{border-radius:999px;background:linear-gradient(120deg,var(--du-soft),var(--du-tint))}
23716
+ .dgui-root .dgui-table-wrap caption{text-align:left;padding:12px 14px;font-size:14px;font-weight:600;color:var(--du-ink);background:linear-gradient(120deg,var(--du-tint),var(--du-bg))}
23717
+ .dgui-root[data-layout=status] .dgui-header{border-radius:23px 23px 0 0;background:linear-gradient(120deg,var(--du-tint),var(--du-soft))}
23718
+ .dgui-root[data-layout=dashboard]{background:linear-gradient(145deg,var(--du-tint),var(--du-bg) 45%,color-mix(in srgb,var(--du-violet) 4%,var(--du-bg)))}
23719
+ .dgui-root .dgui-content>:last-child{margin-bottom:0}.dgui-root .dgui-canvas-stage iframe{border-radius:16px}
23720
+ @media(max-width:600px){.dgui-root{--du-radius:22px;--du-radius-inner:18px}}
23721
+ @media(forced-colors:active){.dgui-root,.dgui-root .dgui-card,.dgui-root .dgui-metric,.dgui-root .dgui-chart,.dgui-root .dgui-button{background:Canvas}}
23722
+ `;
23723
+
23541
23724
  // src/styles.js
23542
23725
  var CSS = `
23726
+ .dgui-chart-data-button{margin-left:auto;border:0;background:transparent;color:var(--du-muted);font:inherit;cursor:pointer;padding:4px 8px}.dgui-chart-data-button:hover{color:var(--du-accent)}.dgui-sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip-path:inset(50%)!important;white-space:nowrap!important;border:0!important}.dgui-canvas{position:relative}.dgui-action-menu{position:absolute;top:6px;right:6px;z-index:2}.dgui-menu-trigger{width:32px;height:32px;border:1px solid var(--du-line);border-radius:8px;background:var(--du-bg);color:var(--du-muted);font-size:24px;line-height:1;cursor:pointer}.dgui-menu-content{position:absolute;top:38px;right:0;display:grid;min-width:156px;padding:5px;border:1px solid var(--du-line);border-radius:10px;background:var(--du-bg);box-shadow:0 6px 20px #0002}.dgui-menu-content button{border:0;border-radius:6px;background:transparent;color:var(--du-ink);padding:9px 12px;text-align:left;font:inherit;white-space:nowrap;cursor:pointer}.dgui-menu-content button:hover{background:var(--du-soft)}.dgui-menu-content button:disabled{opacity:.45;cursor:default}.dgui-action-menu button:focus-visible{outline:2px solid var(--du-accent);outline-offset:2px}
23543
23727
  .dgui-root.dgui-settings{border:0;border-radius:0;box-shadow:none;background:transparent;padding:0;margin:0;max-width:720px;display:flex;flex-direction:column;gap:14px;font-size:13px;line-height:1.65}
23544
23728
  .dgui-settings h3{font-size:14px;font-weight:600;margin:0}.dgui-settings label{font-weight:500}.dgui-settings p{color:var(--du-muted)}
23545
23729
  .dgui-settings select{width:100%;max-width:420px;min-height:40px;border:1px solid var(--du-line);border-radius:6px;padding:9px 12px;background:var(--dsw-alias-bg-layer-3,var(--du-bg));color:inherit;font:inherit}.dgui-settings select:focus-visible{outline:2px solid var(--du-accent);outline-offset:3px}.dgui-settings select:disabled{opacity:.5}
@@ -23562,29 +23746,29 @@ body[data-ds-dark-theme] .dgui-root,.dgui-root[data-preview-theme=dark]{--du-acc
23562
23746
  .dgui-panel{padding:16px;min-width:0;overflow:auto;height:100%;box-sizing:border-box}.dgui-panel>.dgui-root{margin-bottom:16px}.dgui-panel label{display:flex;align-items:center;flex-wrap:wrap;gap:10px}.dgui-panel select{max-width:100%;flex:1;min-width:120px;border:1px solid var(--du-line);border-radius:8px;padding:8px;background:var(--du-bg);color:var(--du-ink)}
23563
23747
  .dgui-history-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:10px 0;border-bottom:1px solid var(--du-line)}.dgui-history-row>span{flex:1;min-width:140px}.dgui-version-preview{margin-top:14px;border:1px solid var(--du-line);border-radius:12px;padding:12px}.dgui-version-preview .dgui-root{margin-top:12px}
23564
23748
  [data-dgui-presentation]>.dgui-secondary{margin:8px 0}[data-dgui-marker]{min-width:0}
23565
- `;
23749
+ ` + SOFT_CSS;
23566
23750
 
23567
23751
  // src/settings.js
23568
- var import_react10 = __toESM(require("react"), 1);
23569
- var h7 = import_react10.default.createElement;
23570
- function ModeSettings({ scope }) {
23571
- const [snapshot, setSnapshot] = (0, import_react10.useState)(() => scope.getSnapshot()), [busy, setBusy] = (0, import_react10.useState)(false), [message, setMessage] = (0, import_react10.useState)(""), pending = (0, import_react10.useRef)(false);
23572
- (0, import_react10.useEffect)(() => scope.subscribe(() => setSnapshot(scope.getSnapshot())), [scope]);
23573
- const ready = snapshot.status === "ready" && snapshot.value !== void 0;
23574
- async function change(mode, key3 = "designMode") {
23752
+ var import_react13 = __toESM(require("react"), 1);
23753
+ var h7 = import_react13.default.createElement;
23754
+ function ModeSettings({ scope: scope2 }) {
23755
+ const [snapshot2, setSnapshot] = (0, import_react13.useState)(() => scope2.getSnapshot()), [busy, setBusy] = (0, import_react13.useState)(false), [message, setMessage] = (0, import_react13.useState)(""), pending = (0, import_react13.useRef)(false);
23756
+ (0, import_react13.useEffect)(() => scope2.subscribe(() => setSnapshot(scope2.getSnapshot())), [scope2]);
23757
+ const ready = snapshot2.status === "ready" && snapshot2.value !== void 0;
23758
+ async function change(mode, key2 = "designMode") {
23575
23759
  if (pending.current || !ready) return;
23576
23760
  pending.current = true;
23577
23761
  setBusy(true);
23578
23762
  setMessage("");
23579
23763
  try {
23580
- await scope.mutate([{ op: "set", path: [key3], value: mode }], scope.getSnapshot().revision);
23581
- const actual = scope.getSnapshot();
23764
+ await scope2.mutate([{ op: "set", path: [key2], value: mode }], scope2.getSnapshot().revision);
23765
+ const actual = scope2.getSnapshot();
23582
23766
  setSnapshot(actual);
23583
- 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");
23584
- 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");
23767
+ if (actual.status !== "ready" || actual.value?.[key2] !== mode) throw new Error("\u8BBE\u7F6E\u672A\u4FDD\u5B58\uFF0C\u53EF\u80FD\u53D1\u751F\u914D\u7F6E\u51B2\u7A81\uFF0C\u8BF7\u91CD\u8BD5\u3002");
23768
+ setMessage(key2 === "designMode" ? "\u6A21\u5F0F\u5DF2\u4FDD\u5B58\uFF1B\u4ECE\u4E0B\u4E00\u6B21\u8BF7\u6C42\u5F00\u59CB\u751F\u6548\u3002" : "\u5C55\u793A\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\uFF1B\u6B63\u6587\u5B9A\u4F4D\u6307\u5BFC\u4ECE\u4E0B\u4E00\u6B21\u8BF7\u6C42\u5F00\u59CB\u751F\u6548\u3002");
23585
23769
  } catch (e) {
23586
23770
  setMessage(e.message ?? "\u6A21\u5F0F\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002");
23587
- setSnapshot(scope.getSnapshot());
23771
+ setSnapshot(scope2.getSnapshot());
23588
23772
  } finally {
23589
23773
  pending.current = false;
23590
23774
  setBusy(false);
@@ -23595,14 +23779,16 @@ function ModeSettings({ scope }) {
23595
23779
  { className: "dgui-root dgui-settings", "aria-label": "DSH Motion UI \u8BBE\u7F6E" },
23596
23780
  h7("h3", null, "DSH Motion UI"),
23597
23781
  h7("label", { htmlFor: "dgui-design-mode" }, "\u8BBE\u8BA1\u6A21\u5F0F"),
23598
- 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")),
23782
+ h7("select", { id: "dgui-design-mode", value: snapshot2.value?.designMode ?? "guided", disabled: !ready || busy, onChange: (e) => change(e.target.value) }, h7("option", { value: "guided" }, "\u5F15\u5BFC\u6A21\u5F0F"), h7("option", { value: "free" }, "\u81EA\u7531\u8BBE\u8BA1\u6A21\u5F0F")),
23599
23783
  h7("p", null, "\u5F15\u5BFC\u6A21\u5F0F\u63D0\u4F9B\u8BBE\u8BA1\u6280\u80FD\u3001\u7EC4\u4EF6\u534F\u8BAE\u4E0E\u793A\u4F8B\u3002\u81EA\u7531\u8BBE\u8BA1\u6A21\u5F0F\u53EA\u63D0\u4F9B\u753B\u5E03\u63A5\u53E3\u4E0E\u4EA4\u4E92\u7EA6\u675F\uFF0C\u5E03\u5C40\u3001\u56FE\u5F62\u3001\u914D\u8272\u548C\u52A8\u753B\u7531\u6A21\u578B\u51B3\u5B9A\uFF1B\u4E24\u79CD\u6A21\u5F0F\u7684\u8FD0\u884C\u6743\u9650\u76F8\u540C\u3002"),
23600
23784
  h7("p", null, "\u4E24\u79CD\u6A21\u5F0F\u90FD\u4F1A\u6307\u5BFC\u6A21\u578B\u5224\u65AD\u4F55\u65F6\u4E3B\u52A8\u4F7F\u7528 UI\uFF0C\u5E76\u4F18\u5148\u4EA4\u4ED8\u5C0F\u800C\u5B8C\u6574\u7684\u754C\u9762\u3002"),
23601
23785
  h7("label", { htmlFor: "dgui-display-mode" }, "\u754C\u9762\u5C55\u793A\u4F4D\u7F6E"),
23602
- 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")),
23786
+ h7("select", { id: "dgui-display-mode", value: snapshot2.value?.displayMode ?? "tail", disabled: !ready || busy, onChange: (e) => change(e.target.value, "displayMode") }, h7("option", { value: "tail" }, "\u56DE\u7B54\u4E0B\u65B9"), h7("option", { value: "inline" }, "\u6B63\u6587\u6807\u8BB0\u4F4D\u7F6E"), h7("option", { value: "sidebar" }, "PC \u4FA7\u680F")),
23603
23787
  h7("p", null, "\u6B63\u6587\u6A21\u5F0F\u7531\u6A21\u578B\u7528\u6807\u8BB0\u9009\u62E9\u63D2\u5165\u4F4D\u7F6E\uFF0C\u7F3A\u5C11\u6807\u8BB0\u65F6\u663E\u793A\u5728\u56DE\u7B54\u4E0B\u65B9\u3002\u4FA7\u680F\u4E0D\u53EF\u7528\u65F6\u81EA\u52A8\u56DE\u9000\uFF1B\u6B63\u6587\u548C\u4FA7\u680F\u5171\u4EAB\u5DF2\u4FDD\u5B58\u53C2\u6570\u3002"),
23788
+ h7("label", { htmlFor: "dgui-show-details" }, h7("input", { id: "dgui-show-details", type: "checkbox", checked: snapshot2.value?.showDetails === true, disabled: !ready || busy, onChange: (e) => change(e.target.checked, "showDetails") }), " \u663E\u793A\u754C\u9762\u8BE6\u60C5"),
23789
+ h7("p", null, "\u9ED8\u8BA4\u9690\u85CF\u5E95\u90E8\u7684\u53C2\u6570\u72B6\u6001\u3001\u539F\u59CB\u8BF4\u660E\u3001\u663E\u793A\u68C0\u67E5\u548C\u7248\u672C\u5386\u53F2\u3002\u5BFC\u51FA\u4E0E\u91CD\u7F6E\u53EF\u901A\u8FC7\u753B\u5E03\u53F3\u4E0A\u89D2\u64CD\u4F5C\u83DC\u5355\u4F7F\u7528\uFF1B\u9519\u8BEF\u63D0\u793A\u59CB\u7EC8\u4FDD\u7559\u3002"),
23604
23790
  h7("p", null, "\u6B64\u8BBE\u7F6E\u5F71\u54CD\u5F53\u524D profile \u540E\u7EED\u8BF7\u6C42\u3002\u5DF2\u6709\u4E0A\u4E0B\u6587\u53EF\u80FD\u4FDD\u7559\u65E7\u6307\u5BFC\uFF0C\u5BF9\u6BD4\u6A21\u5F0F\u65F6\u8BF7\u65B0\u5EFA\u4F1A\u8BDD\u3002"),
23605
- !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"),
23791
+ !ready && h7("p", { role: "status" }, snapshot2.status === "unavailable" ? "\u63D2\u4EF6\u8BBE\u7F6E\u4E0D\u53EF\u7528\uFF0C\u8BF7\u786E\u8BA4\u5BBF\u4E3B\u5DF2\u52A0\u8F7D\u65B0\u7248\u63D2\u4EF6\u3002" : "\u6B63\u5728\u8BFB\u53D6\u8BBE\u7F6E\u2026"),
23606
23792
  message && h7("p", { role: "status" }, message)
23607
23793
  );
23608
23794
  }
@@ -23610,13 +23796,14 @@ function ModeSettings({ scope }) {
23610
23796
  // src/client.jsx
23611
23797
  var inject = ["slots", "sessions", "conversation", "uiConversation", "configForms"];
23612
23798
  function apply(ctx) {
23613
- const scope = ctx.configForms.get("motion-ui");
23614
- ctx.slots.inject("plugins.bundle.config", () => ctx.slots.register({ name: "plugins.bundle.config", key: "dsh-motion-ui" }, (props) => import_react11.default.createElement(ModeSettings, { ...props, scope })));
23799
+ const scope2 = ctx.configForms.get("motion-ui");
23800
+ configureViewSettings(scope2);
23801
+ ctx.slots.inject("plugins.bundle.config", () => ctx.slots.register({ name: "plugins.bundle.config", key: "dsh-motion-ui" }, (props) => import_react14.default.createElement(ModeSettings, { ...props, scope: scope2 })));
23615
23802
  ctx.uiConversation.events.register(turnUiDefinition);
23616
23803
  ctx.slots.inject("conversation.chat.turnTail", () => ctx.slots.register({
23617
23804
  name: "conversation.chat.turnTail",
23618
23805
  id: "dsh-generative-ui",
23619
- inject: (sessionId) => ({ presentationScope: scope, sendPrompt: (prompt) => ctx.sessions.scope(sessionId).get("conversation").send(prompt) })
23806
+ inject: (sessionId) => ({ presentationScope: scope2, sendPrompt: (prompt) => ctx.sessions.scope(sessionId).get("conversation").send(prompt) })
23620
23807
  }, TurnUiView));
23621
23808
  ctx.effect(() => {
23622
23809
  const style = document.createElement("style");