@webskill/sdk 0.3.0 → 0.5.0

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.
Files changed (35) hide show
  1. package/dist/agent.d.ts +2 -0
  2. package/dist/agent.js +867 -0
  3. package/dist/browser.d.ts +137 -4
  4. package/dist/browser.js +458 -22
  5. package/dist/{catalogComponents-C_V39rbF-BOHveMWa.js → catalogComponents-DV7cPpUm-C77AEEx9.js} +477 -157
  6. package/dist/{dist-rorEJsNi.js → dist-6C03DShK.js} +654 -298
  7. package/dist/{dist-ZKaM8j06.js → dist-bewtXYlO.js} +1061 -807
  8. package/dist/governance.d.ts +87 -10
  9. package/dist/governance.js +194 -24
  10. package/dist/{index-wiV5X8Rz.d.ts → index-Bsqg4ftU.d.ts} +151 -143
  11. package/dist/index-D_7ZZjkl.d.ts +411 -0
  12. package/dist/{index-8d-oEDww.d.ts → index-vBz_FC9w.d.ts} +289 -24
  13. package/dist/index.d.ts +3 -3
  14. package/dist/index.js +3 -2
  15. package/dist/mcp.d.ts +2 -2
  16. package/dist/mcp.js +1 -1
  17. package/dist/memoryArtifactStore-BtOeB_hm-tj3fC5ip.js +78 -0
  18. package/dist/node.d.ts +8 -4
  19. package/dist/node.js +1 -1
  20. package/dist/{openUiLibrary-B8-Cvou9-BbpNTXS3.js → openUiLibrary-W3Ce896k-ClFTRZFs.js} +6 -5
  21. package/dist/{skillVersionStore-DOEI9ptb-BxbYL70B.d.ts → skillVersionStore-BzLbzFOL-CxwIewHJ.d.ts} +43 -11
  22. package/dist/{testing-CsrG3XLz.js → testing-DDCJWvgA.js} +7 -5
  23. package/dist/testing.d.ts +1 -1
  24. package/dist/testing.js +2 -2
  25. package/dist/{types-AmKCKJn_-VGabeXK4.d.ts → types-D_hoCri8-BnNPiZCi.d.ts} +111 -72
  26. package/dist/ui-react.d.ts +352 -20
  27. package/dist/ui-react.js +3804 -3478
  28. package/dist/ui-vue.d.ts +1 -1
  29. package/dist/ui-vue.js +25 -6
  30. package/dist/ui.d.ts +4 -3
  31. package/dist/ui.js +3 -3
  32. package/dist/{webskillLitCatalog-CNaUpasU-BslMcxRZ.js → webskillLitCatalog-_mugzRHx-DiuJpCuf.js} +398 -122
  33. package/package.json +6 -1
  34. package/dist/jsonRenderRegistry-9GrWP_hE-U6Do3Kid.js +0 -2468
  35. package/dist/memoryArtifactStore-C9lFVqPF-yFz6yJj0.js +0 -48
@@ -1,8 +1,10 @@
1
1
  import { a as __require, i as __reExport, n as __esmMin, o as __toCommonJS, r as __exportAll$2, s as __toESM$1, t as __commonJSMin$1 } from "./rolldown-runtime-BOF7iYI8.js";
2
+ import { m as WebSkillError } from "./dist-8oQRa8Xz.js";
3
+ import { M as qualifyFieldName, Q as chartSpecFromProps, et as mountEchart, v as collectFormScopes, y as collectScopedValues } from "./dist-bewtXYlO.js";
2
4
  import minpath$1 from "node:path";
3
5
  import { fileURLToPath as urlToPath$1 } from "node:url";
4
6
  import * as React$10 from "react";
5
- import React, { Fragment, createContext, createElement, forwardRef, memo, useCallback, useContext, useDeferredValue, useEffect, useInsertionEffect, useLayoutEffect, useMemo, useRef, useState, default as react_default } from "react";
7
+ import React, { Fragment, createContext, createElement, forwardRef, memo, useCallback, useContext, useDeferredValue, useEffect, useId, useInsertionEffect, useLayoutEffect, useMemo, useRef, useState, default as react_default } from "react";
6
8
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
7
9
  import * as ReactDOM from "react-dom";
8
10
  import minproc$1 from "node:process";
@@ -5549,14 +5551,14 @@ var __name$10 = (target, value) => __defProp$12(target, "name", {
5549
5551
  });
5550
5552
  var useReactId = React$10[" useId ".trim().toString()] || (() => void 0);
5551
5553
  var count = 0;
5552
- function useId(deterministicId) {
5554
+ function useId$1(deterministicId) {
5553
5555
  const [id, setId] = React$10.useState(useReactId());
5554
5556
  useLayoutEffect2(() => {
5555
5557
  if (!deterministicId) setId((reactId) => reactId ?? String(count++));
5556
5558
  }, [deterministicId]);
5557
5559
  return deterministicId || (id ? `radix-${id}` : "");
5558
5560
  }
5559
- __name$10(useId, "useId");
5561
+ __name$10(useId$1, "useId");
5560
5562
 
5561
5563
  //#endregion
5562
5564
  //#region ../../node_modules/.pnpm/@floating-ui+utils@0.2.12/node_modules/@floating-ui/utils/dist/floating-ui.utils.mjs
@@ -7562,7 +7564,7 @@ var RovingFocusGroupImpl = /* @__PURE__ */ React$10.forwardRef(/* @__PURE__ */ _
7562
7564
  var ITEM_NAME$1 = "RovingFocusGroupItem";
7563
7565
  var RovingFocusGroupItem = /* @__PURE__ */ React$10.forwardRef(/* @__PURE__ */ __name$6(function RovingFocusGroupItem2(props, forwardedRef) {
7564
7566
  const { __scopeRovingFocusGroup, focusable = true, active = false, tabStopId, children, ...itemProps } = props;
7565
- const autoId = useId();
7567
+ const autoId = useId$1();
7566
7568
  const id = tabStopId || autoId;
7567
7569
  const context = useRovingFocusContext(ITEM_NAME$1, __scopeRovingFocusGroup);
7568
7570
  const isCurrentTabStop = context.currentTabStopId === id;
@@ -10239,9 +10241,9 @@ var DropdownMenu$1 = /* @__PURE__ */ __name$4((props) => {
10239
10241
  });
10240
10242
  return /* @__PURE__ */ jsx(DropdownMenuProvider, {
10241
10243
  scope: __scopeDropdownMenu,
10242
- triggerId: useId(),
10244
+ triggerId: useId$1(),
10243
10245
  triggerRef,
10244
- contentId: useId(),
10246
+ contentId: useId$1(),
10245
10247
  open,
10246
10248
  onOpenChange: setOpen,
10247
10249
  onOpenToggle: React$10.useCallback(() => setOpen((prevOpen) => !prevOpen), [setOpen]),
@@ -11155,9 +11157,9 @@ var Dialog = /* @__PURE__ */ __name((props) => {
11155
11157
  scope: __scopeDialog,
11156
11158
  triggerRef,
11157
11159
  contentRef,
11158
- contentId: useId(),
11159
- titleId: useId(),
11160
- descriptionId: useId(),
11160
+ contentId: useId$1(),
11161
+ titleId: useId$1(),
11162
+ descriptionId: useId$1(),
11161
11163
  titlePresent: titleCount > 0,
11162
11164
  descriptionPresent: descriptionCount > 0,
11163
11165
  setTitleCount,
@@ -11347,7 +11349,7 @@ var me = React$10.forwardRef((r, o) => {
11347
11349
  groups: /* @__PURE__ */ new Set()
11348
11350
  }
11349
11351
  };
11350
- }), u = L(() => /* @__PURE__ */ new Set()), c = L(() => /* @__PURE__ */ new Map()), d = L(() => /* @__PURE__ */ new Map()), f = L(() => /* @__PURE__ */ new Set()), p = pe(r), { label: b, children: m, value: R, onValueChange: x, filter: C, shouldFilter: S, loop: A, disablePointerSelection: ge = !1, vimBindings: j = !0, ...O } = r, $ = useId(), q = useId(), _ = useId(), I = React$10.useRef(null), v = ke();
11352
+ }), u = L(() => /* @__PURE__ */ new Set()), c = L(() => /* @__PURE__ */ new Map()), d = L(() => /* @__PURE__ */ new Map()), f = L(() => /* @__PURE__ */ new Set()), p = pe(r), { label: b, children: m, value: R, onValueChange: x, filter: C, shouldFilter: S, loop: A, disablePointerSelection: ge = !1, vimBindings: j = !0, ...O } = r, $ = useId$1(), q = useId$1(), _ = useId$1(), I = React$10.useRef(null), v = ke();
11351
11353
  k(() => {
11352
11354
  if (R !== void 0) {
11353
11355
  let e = R.trim();
@@ -11545,7 +11547,7 @@ var me = React$10.forwardRef((r, o) => {
11545
11547
  });
11546
11548
  var he = React$10.forwardRef((r, o) => {
11547
11549
  var _, I;
11548
- let n = useId(), u = React$10.useRef(null), c = React$10.useContext(fe), d = K(), f = pe(r), p = (I = (_ = f.current) == null ? void 0 : _.forceMount) != null ? I : c == null ? void 0 : c.forceMount;
11550
+ let n = useId$1(), u = React$10.useRef(null), c = React$10.useContext(fe), d = K(), f = pe(r), p = (I = (_ = f.current) == null ? void 0 : _.forceMount) != null ? I : c == null ? void 0 : c.forceMount;
11549
11551
  k(() => {
11550
11552
  if (!p) return d.item(n, c == null ? void 0 : c.id);
11551
11553
  }, [p]);
@@ -11586,7 +11588,7 @@ var he = React$10.forwardRef((r, o) => {
11586
11588
  }, r.children);
11587
11589
  });
11588
11590
  var Ee = React$10.forwardRef((r, o) => {
11589
- let { heading: n, children: u, forceMount: c, ...d } = r, f = useId(), p = React$10.useRef(null), b = React$10.useRef(null), m = useId(), R = K(), x = P((S) => c || R.filter() === !1 ? !0 : S.search ? S.filtered.groups.has(f) : !0);
11591
+ let { heading: n, children: u, forceMount: c, ...d } = r, f = useId$1(), p = React$10.useRef(null), b = React$10.useRef(null), m = useId$1(), R = K(), x = P((S) => c || R.filter() === !1 ? !0 : S.search ? S.filtered.groups.has(f) : !0);
11590
11592
  k(() => R.group(f), []), ve(f, p, [
11591
11593
  r.value,
11592
11594
  r.heading,
@@ -14884,7 +14886,7 @@ function checkRule(state) {
14884
14886
  * @param {Info} info
14885
14887
  * @returns {string}
14886
14888
  */
14887
- function list$4(node, parent, state, info) {
14889
+ function list$5(node, parent, state, info) {
14888
14890
  const exit = state.enter("list");
14889
14891
  const bulletCurrent = state.bulletCurrent;
14890
14892
  /** @type {string} */
@@ -15170,7 +15172,7 @@ const handle = {
15170
15172
  inlineCode: inlineCode$2,
15171
15173
  link: link$2,
15172
15174
  linkReference: linkReference$2,
15173
- list: list$4,
15175
+ list: list$5,
15174
15176
  listItem: listItem$2,
15175
15177
  paragraph: paragraph$2,
15176
15178
  root: root$4,
@@ -24085,7 +24087,7 @@ function tokenizeThematicBreak$1(effects, ok, nok) {
24085
24087
  * } from 'micromark-util-types'
24086
24088
  */
24087
24089
  /** @type {Construct} */
24088
- const list$3 = {
24090
+ const list$4 = {
24089
24091
  continuation: { tokenize: tokenizeListContinuation$1 },
24090
24092
  exit: tokenizeListEnd$1,
24091
24093
  name: "list",
@@ -24205,7 +24207,7 @@ function tokenizeListContinuation$1(effects, ok, nok) {
24205
24207
  function notInCurrentItem(code) {
24206
24208
  self.containerState._closeFlow = true;
24207
24209
  self.interrupt = void 0;
24208
- return factorySpace$1(effects, effects.attempt(list$3, ok, nok), "linePrefix", self.parser.constructs.disable.null.includes("codeIndented") ? void 0 : 4)(code);
24210
+ return factorySpace$1(effects, effects.attempt(list$4, ok, nok), "linePrefix", self.parser.constructs.disable.null.includes("codeIndented") ? void 0 : 4)(code);
24209
24211
  }
24210
24212
  }
24211
24213
  /**
@@ -34366,19 +34368,19 @@ var constructs_exports$1 = /* @__PURE__ */ __exportAll$2({
34366
34368
  });
34367
34369
  /** @satisfies {Extension['document']} */
34368
34370
  const document$3 = {
34369
- [42]: list$3,
34370
- [43]: list$3,
34371
- [45]: list$3,
34372
- [48]: list$3,
34373
- [49]: list$3,
34374
- [50]: list$3,
34375
- [51]: list$3,
34376
- [52]: list$3,
34377
- [53]: list$3,
34378
- [54]: list$3,
34379
- [55]: list$3,
34380
- [56]: list$3,
34381
- [57]: list$3,
34371
+ [42]: list$4,
34372
+ [43]: list$4,
34373
+ [45]: list$4,
34374
+ [48]: list$4,
34375
+ [49]: list$4,
34376
+ [50]: list$4,
34377
+ [51]: list$4,
34378
+ [52]: list$4,
34379
+ [53]: list$4,
34380
+ [54]: list$4,
34381
+ [55]: list$4,
34382
+ [56]: list$4,
34383
+ [57]: list$4,
34382
34384
  [62]: blockQuote$1
34383
34385
  };
34384
34386
  /** @satisfies {Extension['contentInitial']} */
@@ -36684,7 +36686,7 @@ function listItemLoose$1(node) {
36684
36686
  * @returns {Element}
36685
36687
  * hast node.
36686
36688
  */
36687
- function list$2(state, node) {
36689
+ function list$3(state, node) {
36688
36690
  /** @type {Properties} */
36689
36691
  const properties = {};
36690
36692
  const results = state.all(node);
@@ -37079,7 +37081,7 @@ const handlers$1 = {
37079
37081
  linkReference: linkReference$1,
37080
37082
  link: link$1,
37081
37083
  listItem: listItem$1,
37082
- list: list$2,
37084
+ list: list$3,
37083
37085
  paragraph: paragraph$1,
37084
37086
  root: root$2,
37085
37087
  strong: strong$1,
@@ -99760,7 +99762,6 @@ function DataTable({ children, className = "", containerClassName = "", ...props
99760
99762
  }
99761
99763
  const toneClasses$1 = {
99762
99764
  neutral: "bg-subtle text-muted",
99763
- primary: "bg-subtle text-ink",
99764
99765
  success: "bg-success-soft text-success",
99765
99766
  warning: "bg-warning-soft text-warning",
99766
99767
  info: "bg-info-soft text-info",
@@ -99792,32 +99793,6 @@ const sidebarMenuButtonVariants = cva("peer/menu-button flex w-full cursor-point
99792
99793
  size: "default"
99793
99794
  }
99794
99795
  });
99795
- function Select({ options, value, onChange, placeholder, disabled = false, id, label, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, className = "" }) {
99796
- return /* @__PURE__ */ jsxs("span", {
99797
- className: `relative inline-flex ${className}`,
99798
- children: [/* @__PURE__ */ jsxs("select", {
99799
- id,
99800
- value,
99801
- disabled,
99802
- "aria-label": label,
99803
- "aria-labelledby": ariaLabelledBy,
99804
- "aria-describedby": ariaDescribedBy,
99805
- onChange: (event) => onChange(event.target.value),
99806
- className: "h-9 w-full cursor-pointer appearance-none rounded-lg border border-border bg-surface pr-8 pl-3 text-sm text-ink transition-colors hover:border-ring disabled:cursor-not-allowed disabled:opacity-50",
99807
- children: [placeholder !== void 0 && /* @__PURE__ */ jsx("option", {
99808
- value: "",
99809
- disabled: true,
99810
- children: placeholder
99811
- }), options.map((option) => /* @__PURE__ */ jsx("option", {
99812
- value: option.value,
99813
- children: option.label
99814
- }, option.value))]
99815
- }), /* @__PURE__ */ jsx(ChevronDown, {
99816
- className: "pointer-events-none absolute top-1/2 right-2.5 size-4 -translate-y-1/2 text-muted",
99817
- "aria-hidden": true
99818
- })]
99819
- });
99820
- }
99821
99796
  /**
99822
99797
  * @typedef Options
99823
99798
  * Configuration for `stringify`.
@@ -111476,7 +111451,7 @@ function listItemLoose(node) {
111476
111451
  * @returns {Element}
111477
111452
  * hast node.
111478
111453
  */
111479
- function list(state, node) {
111454
+ function list$2(state, node) {
111480
111455
  /** @type {Properties} */
111481
111456
  const properties = {};
111482
111457
  const results = state.all(node);
@@ -111841,7 +111816,7 @@ const handlers = {
111841
111816
  linkReference,
111842
111817
  link,
111843
111818
  listItem,
111844
- list,
111819
+ list: list$2,
111845
111820
  paragraph,
111846
111821
  root,
111847
111822
  strong,
@@ -120111,77 +120086,436 @@ const MarkdownText = memo(function MarkdownText({ className }) {
120111
120086
  });
120112
120087
 
120113
120088
  //#endregion
120114
- //#region ../ui-react/dist/catalogComponents-C_V39rbF.js
120115
- function toEchartsOption(chart) {
120116
- return {
120117
- animation: false,
120118
- title: chart.title ? {
120119
- text: chart.title,
120120
- left: "center",
120121
- textStyle: { fontSize: 14 }
120122
- } : void 0,
120123
- tooltip: { trigger: chart.kind === "pie" ? "item" : "axis" },
120124
- legend: { bottom: 0 },
120125
- xAxis: chart.kind === "pie" ? void 0 : {
120126
- type: "category",
120127
- data: chart.labels
120128
- },
120129
- yAxis: chart.kind === "pie" ? void 0 : { type: "value" },
120130
- series: chart.kind === "pie" ? chart.series.map((series) => ({
120131
- type: "pie",
120132
- name: series.name,
120133
- data: chart.labels.map((label, index) => ({
120134
- name: label,
120135
- value: series.data[index] ?? 0
120136
- }))
120137
- })) : chart.series.map((series) => ({
120138
- type: chart.kind,
120139
- name: series.name,
120140
- data: series.data
120141
- }))
120142
- };
120143
- }
120144
- /** echarts 懒加载挂载点:surface 图表与 catalog 声明树的 Chart 节点共用 */
120089
+ //#region ../ui-react/dist/catalogComponents-DV7cPpUm.js
120090
+ /** echarts 挂载点:surface 图表与 catalog 声明树的 Chart 节点共用,实现在 `@webskill/ui`,与 A2UI 档同一份 */
120145
120091
  function EChart({ chart }) {
120146
120092
  const containerRef = useRef(null);
120147
- const chartRef = useRef(void 0);
120148
- const [ready, setReady] = useState(false);
120093
+ const handleRef = useRef(void 0);
120149
120094
  useEffect(() => {
120150
- let disposed = false;
120151
- let observer;
120152
- import("./echarts-DhNm2ene.js").then((echarts) => {
120153
- const container = containerRef.current;
120154
- if (disposed || !container) return;
120155
- const instance = echarts.init(container);
120156
- chartRef.current = instance;
120157
- setReady(true);
120158
- if (typeof ResizeObserver !== "undefined") {
120159
- observer = new ResizeObserver(() => instance.resize());
120160
- observer.observe(container);
120161
- }
120162
- });
120095
+ const container = containerRef.current;
120096
+ if (!container) return;
120097
+ const handle = mountEchart(container);
120098
+ handleRef.current = handle;
120163
120099
  return () => {
120164
- disposed = true;
120165
- observer?.disconnect();
120166
- chartRef.current?.dispose();
120167
- chartRef.current = void 0;
120100
+ handle.dispose();
120101
+ handleRef.current = void 0;
120168
120102
  };
120169
120103
  }, []);
120170
120104
  useEffect(() => {
120171
- if (ready) chartRef.current?.setOption(toEchartsOption(chart), {
120172
- notMerge: true,
120173
- lazyUpdate: true
120174
- });
120175
- }, [ready, chart]);
120105
+ handleRef.current?.setChart(chart);
120106
+ }, [chart]);
120176
120107
  return /* @__PURE__ */ jsx("div", {
120177
120108
  className: "webskill-surface__chart",
120178
- ref: containerRef,
120179
- "aria-label": chart.title
120109
+ ref: containerRef
120180
120110
  });
120181
120111
  }
120112
+ const REQUIRED_MESSAGE = "This field is required";
120182
120113
  const str = (props, key, fallback = "") => typeof props[key] === "string" ? props[key] : fallback;
120114
+ function collectFields(node, out) {
120115
+ if (node.component === "Field" && typeof node.props?.["name"] === "string") out.push(node.props);
120116
+ for (const child of node.children ?? []) collectFields(child, out);
120117
+ }
120118
+ const isBlank = (value) => value === void 0 || value === null || value === "" || Array.isArray(value) && value.length === 0;
120119
+ function useSurfaceForm({ surfaceId, spec, actions, runId, draft, onAction, onDraftChange }) {
120120
+ const [touched, setTouched] = useState(() => ({ ...draft }));
120121
+ const [errors, setErrors] = useState({});
120122
+ const fields = useMemo(() => {
120123
+ const out = [];
120124
+ collectFields(spec, out);
120125
+ return out;
120126
+ }, [spec]);
120127
+ const scopes = useMemo(() => collectFormScopes(spec), [spec]);
120128
+ const scoping = scopes.length > 1;
120129
+ const scopeFields = useMemo(() => new Map(scopes.map((scope) => {
120130
+ const out = [];
120131
+ collectFields(scope.form, out);
120132
+ return [scope.scopeId, out];
120133
+ })), [scopes]);
120134
+ const nodeScopes = useMemo(() => new Map(scopes.map((scope) => [scope.form, scope])), [scopes]);
120135
+ const defaults = useMemo(() => {
120136
+ const out = {};
120137
+ const add = (field, scopeId) => {
120138
+ if (field["defaultValue"] !== void 0) out[qualifyFieldName(String(field["name"]), scopeId)] = field["defaultValue"];
120139
+ };
120140
+ if (!scoping) {
120141
+ for (const field of fields) add(field);
120142
+ return out;
120143
+ }
120144
+ for (const scope of scopes) for (const field of scopeFields.get(scope.scopeId) ?? []) add(field, scope.scopeId);
120145
+ return out;
120146
+ }, [
120147
+ fields,
120148
+ scopes,
120149
+ scopeFields,
120150
+ scoping
120151
+ ]);
120152
+ const claims = useRef({
120153
+ spec,
120154
+ map: /* @__PURE__ */ new Map()
120155
+ });
120156
+ if (claims.current.spec !== spec) claims.current = {
120157
+ spec,
120158
+ map: /* @__PURE__ */ new Map()
120159
+ };
120160
+ const values = {
120161
+ ...defaults,
120162
+ ...touched
120163
+ };
120164
+ const resolveActionId = (intent, nodeId) => nodeId ?? actions.find((action) => action.intent === intent)?.id ?? intent;
120165
+ const dispatch = (actionId, withValues, scope) => {
120166
+ const declared = actions.find((action) => action.id === actionId);
120167
+ onAction?.({
120168
+ surfaceId,
120169
+ actionId,
120170
+ intent: declared?.intent ?? "select",
120171
+ ...declared?.nonce ? { nonce: declared.nonce } : {},
120172
+ ...scope ? { scopeId: scope.scopeId } : {},
120173
+ ...withValues ? { value: collectScopedValues(values, scope) } : {}
120174
+ });
120175
+ };
120176
+ return {
120177
+ surfaceId,
120178
+ actions,
120179
+ values,
120180
+ errors,
120181
+ scopes,
120182
+ resolveActionId,
120183
+ scopeOfNode: (node) => scoping ? nodeScopes.get(node) : void 0,
120184
+ claimScope: (instanceId, formProps) => {
120185
+ if (!scoping) return void 0;
120186
+ const claimed = claims.current.map.get(instanceId);
120187
+ if (claimed) return claimed;
120188
+ const taken = new Set([...claims.current.map.values()].map((scope) => scope.scopeId));
120189
+ const match = scopes.find((scope) => !taken.has(scope.scopeId) && Object.entries(scope.form.props ?? {}).every(([key, value]) => value === formProps[key]));
120190
+ if (match) claims.current.map.set(instanceId, match);
120191
+ return match;
120192
+ },
120193
+ setValue: (key, value) => {
120194
+ const next = {
120195
+ ...touched,
120196
+ [key]: value
120197
+ };
120198
+ setTouched(next);
120199
+ setErrors(({ [key]: _cleared, ...rest }) => rest);
120200
+ if (runId) onDraftChange?.({
120201
+ runId,
120202
+ surfaceId,
120203
+ value: next
120204
+ });
120205
+ },
120206
+ emit: (actionId, scope) => dispatch(actionId, false, scope),
120207
+ submit: (intent, nodeId, scope) => {
120208
+ const missing = (scope ? scopeFields.get(scope.scopeId) ?? [] : fields).filter((field) => field["required"] === true && isBlank(values[qualifyFieldName(String(field["name"]), scope?.scopeId)]));
120209
+ if (missing.length > 0) {
120210
+ const flagged = Object.fromEntries(missing.map((field) => [qualifyFieldName(String(field["name"]), scope?.scopeId), REQUIRED_MESSAGE]));
120211
+ setErrors((prev) => ({
120212
+ ...scope ? withoutScope(prev, scope.scopeId) : {},
120213
+ ...flagged
120214
+ }));
120215
+ return;
120216
+ }
120217
+ setErrors((prev) => scope ? withoutScope(prev, scope.scopeId) : {});
120218
+ dispatch(scope && !nodeId ? scope.submitActionId : resolveActionId(intent, nodeId), true, scope);
120219
+ }
120220
+ };
120221
+ }
120222
+ const withoutScope = (errors, scopeId) => Object.fromEntries(Object.entries(errors).filter(([key]) => !key.startsWith(`${scopeId}.`)));
120223
+ /** catalog `Field` 的唯一控件实现:8 种 type 的取值语义在这里定死 */
120224
+ function SurfaceField({ form, props, scope }) {
120225
+ const name = str(props, "name");
120226
+ const key = qualifyFieldName(name, scope?.scopeId);
120227
+ const label = str(props, "label", name);
120228
+ const type = str(props, "type", "text");
120229
+ const required = props["required"] === true;
120230
+ const value = form.values[key];
120231
+ const error = form.errors[key];
120232
+ const errorId = error ? `webskill-surface-${form.surfaceId}-${key}-error` : void 0;
120233
+ const options = Array.isArray(props["options"]) ? props["options"] : [];
120234
+ const suggestion = props["suggestion"];
120235
+ /** 控件的机器可读锚点:宿主与测试据此定位字段,不依赖标签文案 */
120236
+ const anchor = {
120237
+ "data-webskill-surface-control": key,
120238
+ ...error ? {
120239
+ "aria-invalid": true,
120240
+ "aria-describedby": errorId
120241
+ } : {}
120242
+ };
120243
+ const control = () => {
120244
+ if (type === "textarea") return /* @__PURE__ */ jsx(Textarea, {
120245
+ id: key,
120246
+ ...anchor,
120247
+ invalid: Boolean(error),
120248
+ value: typeof value === "string" ? value : "",
120249
+ onChange: (event) => form.setValue(key, event.target.value)
120250
+ });
120251
+ if (type === "toggle") return /* @__PURE__ */ jsx(Switch, {
120252
+ id: key,
120253
+ ...anchor,
120254
+ checked: value === true,
120255
+ onCheckedChange: (next) => form.setValue(key, next)
120256
+ });
120257
+ if (type === "select" || type === "multi-select") {
120258
+ const multiple = type === "multi-select";
120259
+ const indexOf = (candidate) => {
120260
+ const index = options.findIndex((option) => option.value === candidate);
120261
+ return index < 0 ? "" : String(index);
120262
+ };
120263
+ return /* @__PURE__ */ jsx("select", {
120264
+ id: key,
120265
+ ...anchor,
120266
+ multiple,
120267
+ value: multiple ? Array.isArray(value) ? value.map(indexOf) : [] : indexOf(value),
120268
+ onChange: (event) => {
120269
+ const pick = (index) => options[Number(index)].value;
120270
+ form.setValue(key, multiple ? [...event.target.selectedOptions].map((option) => pick(option.value)) : pick(event.target.value));
120271
+ },
120272
+ children: options.map((option, index) => /* @__PURE__ */ jsx("option", {
120273
+ value: String(index),
120274
+ children: option.label
120275
+ }, index))
120276
+ });
120277
+ }
120278
+ if (type === "file") return /* @__PURE__ */ jsx("input", {
120279
+ id: key,
120280
+ ...anchor,
120281
+ type: "file",
120282
+ onChange: (event) => form.setValue(key, event.target.files?.[0]?.name ?? "")
120283
+ });
120284
+ return /* @__PURE__ */ jsx(Input, {
120285
+ id: key,
120286
+ ...anchor,
120287
+ invalid: Boolean(error),
120288
+ type: type === "number" ? "number" : type === "date" ? "date" : "text",
120289
+ value: typeof value === "string" || typeof value === "number" ? String(value) : "",
120290
+ onChange: (event) => form.setValue(key, type === "number" ? Number(event.target.value) : event.target.value)
120291
+ });
120292
+ };
120293
+ return /* @__PURE__ */ jsxs("label", {
120294
+ className: "flex flex-col gap-1 text-sm",
120295
+ htmlFor: key,
120296
+ children: [
120297
+ /* @__PURE__ */ jsxs("span", {
120298
+ className: "text-ink",
120299
+ children: [label, required ? " *" : ""]
120300
+ }),
120301
+ control(),
120302
+ suggestion !== void 0 && isBlank(value) ? /* @__PURE__ */ jsxs("span", {
120303
+ "data-webskill-suggestion": key,
120304
+ className: "flex items-center gap-2 text-xs text-muted",
120305
+ children: [/* @__PURE__ */ jsxs("span", { children: ["Last entered: ", String(suggestion.value)] }), /* @__PURE__ */ jsx("button", {
120306
+ type: "button",
120307
+ "data-webskill-suggestion-use": key,
120308
+ onClick: () => form.setValue(key, suggestion.value),
120309
+ className: "rounded-md border border-border px-2 py-0.5 text-ink transition-colors hover:bg-accent",
120310
+ children: "Use"
120311
+ })]
120312
+ }) : null,
120313
+ props["description"] ? /* @__PURE__ */ jsx("span", {
120314
+ className: "text-xs text-muted",
120315
+ children: str(props, "description")
120316
+ }) : null,
120317
+ error ? /* @__PURE__ */ jsx("small", {
120318
+ id: errorId,
120319
+ role: "alert",
120320
+ className: "text-xs text-destructive",
120321
+ children: error
120322
+ }) : null
120323
+ ]
120324
+ });
120325
+ }
120326
+ /** catalog `Form` 的提交 / 取消按钮:提交带表单值,取消不带 */
120327
+ function SurfaceFormButtons({ form, props, scope }) {
120328
+ const submitId = scope ? scope.submitActionId : form.resolveActionId("submit");
120329
+ const cancelId = scope ? scope.cancelActionId : form.resolveActionId("cancel");
120330
+ return /* @__PURE__ */ jsxs("div", {
120331
+ className: "flex gap-2",
120332
+ children: [/* @__PURE__ */ jsx(Button, {
120333
+ type: "submit",
120334
+ size: "sm",
120335
+ "data-webskill-surface-action": submitId,
120336
+ children: str(props, "submitLabel", "Submit")
120337
+ }), props["cancelLabel"] ? /* @__PURE__ */ jsx(Button, {
120338
+ type: "button",
120339
+ size: "sm",
120340
+ variant: "secondary",
120341
+ "data-webskill-surface-action": cancelId,
120342
+ onClick: () => form.emit(cancelId, scope),
120343
+ children: str(props, "cancelLabel")
120344
+ }) : null]
120345
+ });
120346
+ }
120347
+ /** catalog `Button` 的唯一实现:submit 走带值提交,其余走裸动作 */
120348
+ function SurfaceButton({ form, props, nodeId, scope }) {
120349
+ const intent = str(props, "action");
120350
+ const actionId = form.resolveActionId(intent, nodeId);
120351
+ return /* @__PURE__ */ jsx(Button, {
120352
+ size: "sm",
120353
+ type: "button",
120354
+ disabled: props["disabled"] === true,
120355
+ "data-webskill-surface-action": actionId,
120356
+ onClick: () => intent === "submit" ? form.submit(intent, nodeId, scope) : form.emit(actionId, scope),
120357
+ children: str(props, "label")
120358
+ });
120359
+ }
120360
+ /**
120361
+ * FR-6.2 的四个布局/展示组件。四档渲染共用同一份实现:
120362
+ * native 的 switch 与 json-render / OpenUI 的组件表都调这里,
120363
+ * 语义(tablist、grid、ol/li、progressbar)因此不会随渲染器分叉。
120364
+ */
120365
+ const num = (props, key, fallback) => typeof props[key] === "number" ? props[key] : fallback;
120366
+ const list = (value) => Array.isArray(value) ? value : [];
120367
+ function SpecTabs({ props, children }) {
120368
+ const labels = list(props["labels"]);
120369
+ const panels = Array.isArray(children) ? children : [children];
120370
+ const [active, setActive] = useState(0);
120371
+ const index = Math.min(active, Math.max(panels.length - 1, 0));
120372
+ return /* @__PURE__ */ jsxs("div", {
120373
+ className: "flex flex-col gap-3",
120374
+ children: [/* @__PURE__ */ jsx("div", {
120375
+ role: "tablist",
120376
+ className: "flex gap-1 border-b border-border",
120377
+ children: labels.map((label, position) => /* @__PURE__ */ jsx(Button, {
120378
+ role: "tab",
120379
+ type: "button",
120380
+ size: "sm",
120381
+ variant: position === index ? "secondary" : "ghost",
120382
+ "aria-selected": position === index,
120383
+ onClick: () => setActive(position),
120384
+ children: label
120385
+ }, position))
120386
+ }), panels[index] ?? null]
120387
+ });
120388
+ }
120389
+ function SpecGrid({ props, children }) {
120390
+ return /* @__PURE__ */ jsx("div", {
120391
+ className: "grid gap-3",
120392
+ style: { gridTemplateColumns: `repeat(${Math.min(4, Math.max(2, num(props, "columns", 2)))}, minmax(0, 1fr))` },
120393
+ children
120394
+ });
120395
+ }
120396
+ function SpecTimeline({ props }) {
120397
+ return /* @__PURE__ */ jsx("ol", {
120398
+ className: "flex flex-col gap-2 pl-4",
120399
+ children: list(props["items"]).map((item, index) => /* @__PURE__ */ jsxs("li", {
120400
+ className: "flex flex-col gap-0.5",
120401
+ "data-state": str(item, "state", "pending"),
120402
+ children: [
120403
+ /* @__PURE__ */ jsx("strong", {
120404
+ className: "text-sm text-ink",
120405
+ children: str(item, "title")
120406
+ }),
120407
+ item["time"] ? /* @__PURE__ */ jsx("p", {
120408
+ className: "text-xs text-muted",
120409
+ children: str(item, "time")
120410
+ }) : null,
120411
+ item["description"] ? /* @__PURE__ */ jsx("p", {
120412
+ className: "text-sm text-ink",
120413
+ children: str(item, "description")
120414
+ }) : null
120415
+ ]
120416
+ }, index))
120417
+ });
120418
+ }
120419
+ function SpecProgress({ props }) {
120420
+ const value = Math.max(0, Math.min(100, num(props, "value", 0)));
120421
+ const label = str(props, "label");
120422
+ return /* @__PURE__ */ jsxs("div", {
120423
+ className: "flex flex-col gap-1",
120424
+ children: [label ? /* @__PURE__ */ jsx("span", {
120425
+ className: "text-xs text-muted",
120426
+ children: label
120427
+ }) : null, /* @__PURE__ */ jsx("div", {
120428
+ role: "progressbar",
120429
+ "aria-label": label || "Progress",
120430
+ "aria-valuenow": value,
120431
+ "aria-valuemin": 0,
120432
+ "aria-valuemax": 100,
120433
+ className: "h-2 overflow-hidden rounded-full bg-secondary",
120434
+ children: /* @__PURE__ */ jsx("span", {
120435
+ className: "block h-full bg-ink",
120436
+ style: { width: `${value}%` }
120437
+ })
120438
+ })]
120439
+ });
120440
+ }
120441
+ /**
120442
+ * json-render 与 OpenUI 两档的 Renderer 都只把 props 交给组件实现,拿不到节点 id,
120443
+ * 也拿不到表单状态,因此表单值与动作回传统一走这个 Context。
120444
+ * 缺省值故意不给空实现:没包 Provider 就是宿主接线错了,必须失败而不是“点了没反应”。
120445
+ */
120446
+ const CatalogSurfaceContext = createContext(void 0);
120447
+ function useCatalogSurfaceForm() {
120448
+ const form = useContext(CatalogSurfaceContext);
120449
+ if (!form) throw new WebSkillError("UI_UNAVAILABLE", "Catalog surface components must be rendered inside a CatalogSurfaceProvider");
120450
+ return form;
120451
+ }
120452
+ /** 非 native 档的表单状态宿主:状态必须在 Renderer 之上,否则每次重渲染都会丢值 */
120453
+ function CatalogSurfaceProvider({ surfaceId, spec, actions, onAction, children }) {
120454
+ const form = useSurfaceForm({
120455
+ surfaceId,
120456
+ spec,
120457
+ actions,
120458
+ onAction
120459
+ });
120460
+ return /* @__PURE__ */ jsx(CatalogSurfaceContext.Provider, {
120461
+ value: form,
120462
+ children
120463
+ });
120464
+ }
120465
+ /** 当前子树所属的表单作用域;surface 上只有一个表单时为 undefined(行为与放宽前一致) */
120466
+ const FormScopeContext = createContext(void 0);
120467
+ /** 把实现表的条目包成真正的 React 组件,使其内部的 hook 调用处于自己的渲染周期 */
120468
+ function CatalogNode({ name, props, children }) {
120469
+ const Impl = catalogComponentImpls[name];
120470
+ if (!Impl) return null;
120471
+ return /* @__PURE__ */ jsx(Impl, {
120472
+ props,
120473
+ children
120474
+ });
120475
+ }
120476
+ function CatalogForm({ props, children }) {
120477
+ const form = useCatalogSurfaceForm();
120478
+ const scope = form.claimScope(useId(), props);
120479
+ return /* @__PURE__ */ jsx(FormScopeContext.Provider, {
120480
+ value: scope,
120481
+ children: /* @__PURE__ */ jsxs("form", {
120482
+ className: "flex flex-col gap-3",
120483
+ noValidate: true,
120484
+ onSubmit: (event) => {
120485
+ event.preventDefault();
120486
+ form.submit("submit", void 0, scope);
120487
+ },
120488
+ children: [
120489
+ props["title"] ? /* @__PURE__ */ jsx("h3", {
120490
+ className: "text-sm font-semibold text-ink",
120491
+ children: str(props, "title")
120492
+ }) : null,
120493
+ children,
120494
+ /* @__PURE__ */ jsx(SurfaceFormButtons, {
120495
+ form,
120496
+ props,
120497
+ scope
120498
+ })
120499
+ ]
120500
+ })
120501
+ });
120502
+ }
120503
+ function CatalogField({ props }) {
120504
+ return /* @__PURE__ */ jsx(SurfaceField, {
120505
+ form: useCatalogSurfaceForm(),
120506
+ props,
120507
+ scope: useContext(FormScopeContext)
120508
+ });
120509
+ }
120510
+ function CatalogButton({ props }) {
120511
+ return /* @__PURE__ */ jsx(SurfaceButton, {
120512
+ form: useCatalogSurfaceForm(),
120513
+ props,
120514
+ scope: useContext(FormScopeContext)
120515
+ });
120516
+ }
120183
120517
  /**
120184
- * catalog 16 个组件的展示实现:json-render 与 OpenUI 两档共用同一份,
120518
+ * catalog 展示类组件的实现:json-render 与 OpenUI 两档共用同一份,
120185
120519
  * 避免"一个 catalog、多套 registry"退化成多套各自演进的视觉。
120186
120520
  * 交互(表单值收集 / action 回传)由各档的宿主组件负责。
120187
120521
  */
@@ -120240,50 +120574,36 @@ const catalogComponentImpls = {
120240
120574
  const rows = Array.isArray(props["rows"]) ? props["rows"] : [];
120241
120575
  return /* @__PURE__ */ jsxs(DataTable, {
120242
120576
  "aria-label": str(props, "title", "Data"),
120243
- children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { children: columns.map((column) => /* @__PURE__ */ jsx("th", {
120244
- scope: "col",
120245
- children: column
120246
- }, column)) }) }), /* @__PURE__ */ jsx("tbody", { children: rows.map((row, rowIndex) => /* @__PURE__ */ jsx("tr", { children: row.map((cell, cellIndex) => /* @__PURE__ */ jsx("td", { children: String(cell ?? "") }, cellIndex)) }, rowIndex)) })]
120577
+ children: [/* @__PURE__ */ jsx("thead", {
120578
+ className: "webskill-surface__table-header",
120579
+ children: /* @__PURE__ */ jsx("tr", { children: columns.map((column) => /* @__PURE__ */ jsx("th", {
120580
+ scope: "col",
120581
+ children: column
120582
+ }, column)) })
120583
+ }), /* @__PURE__ */ jsx("tbody", {
120584
+ className: "webskill-surface__table-body",
120585
+ children: rows.map((row, rowIndex) => /* @__PURE__ */ jsx("tr", { children: row.map((cell, cellIndex) => /* @__PURE__ */ jsx("td", { children: String(cell ?? "") }, cellIndex)) }, rowIndex))
120586
+ })]
120247
120587
  });
120248
120588
  },
120249
- Chart: ({ props }) => {
120250
- const series = Array.isArray(props["series"]) ? props["series"] : [];
120251
- return /* @__PURE__ */ jsx(EChart, { chart: {
120252
- kind: str(props, "type", "bar"),
120253
- labels: Array.isArray(props["labels"]) ? props["labels"] : [],
120254
- series: series.map((item) => ({
120255
- name: item.name,
120256
- data: item.values
120257
- })),
120258
- ...props["title"] ? { title: str(props, "title") } : {}
120259
- } });
120260
- },
120589
+ Chart: ({ props }) => /* @__PURE__ */ jsx(EChart, { chart: chartSpecFromProps(props) }),
120590
+ Tabs: ({ props, children }) => /* @__PURE__ */ jsx(SpecTabs, {
120591
+ props,
120592
+ children
120593
+ }),
120594
+ Grid: ({ props, children }) => /* @__PURE__ */ jsx(SpecGrid, {
120595
+ props,
120596
+ children
120597
+ }),
120598
+ Timeline: ({ props }) => /* @__PURE__ */ jsx(SpecTimeline, { props }),
120599
+ Progress: ({ props }) => /* @__PURE__ */ jsx(SpecProgress, { props }),
120261
120600
  FileLink: ({ props }) => /* @__PURE__ */ jsx("span", {
120262
120601
  className: "text-sm text-ink",
120263
120602
  children: str(props, "label", str(props, "path"))
120264
120603
  }),
120265
- Form: ({ props, children }) => /* @__PURE__ */ jsxs("form", {
120266
- className: "flex flex-col gap-3",
120267
- children: [props["title"] ? /* @__PURE__ */ jsx("h3", {
120268
- className: "text-sm font-semibold text-ink",
120269
- children: str(props, "title")
120270
- }) : null, children]
120271
- }),
120272
- Field: ({ props }) => {
120273
- const name = str(props, "name");
120274
- return /* @__PURE__ */ jsxs("label", {
120275
- className: "flex flex-col gap-1 text-sm",
120276
- htmlFor: name,
120277
- children: [/* @__PURE__ */ jsx("span", {
120278
- className: "text-ink",
120279
- children: str(props, "label", name)
120280
- }), str(props, "type") === "textarea" ? /* @__PURE__ */ jsx(Textarea, { id: name }) : /* @__PURE__ */ jsx(Input, { id: name })]
120281
- });
120282
- },
120283
- Button: ({ props }) => /* @__PURE__ */ jsx(Button, {
120284
- size: "sm",
120285
- children: str(props, "label")
120286
- }),
120604
+ Form: CatalogForm,
120605
+ Field: CatalogField,
120606
+ Button: CatalogButton,
120287
120607
  Alert: ({ props }) => /* @__PURE__ */ jsxs("div", {
120288
120608
  role: "alert",
120289
120609
  className: "rounded-md border border-border p-2 text-sm",
@@ -120300,4 +120620,4 @@ const catalogComponentImpls = {
120300
120620
  };
120301
120621
 
120302
120622
  //#endregion
120303
- export { Checkbox as a, DropdownMenuCheckboxItem as c, Input as d, Markdown as f, Textarea as g, Switch as h, Button as i, DropdownMenuContent as l, Separator as m, catalogComponentImpls as n, DataTable as o, Select as p, Badge as r, DropdownMenu as s, EChart as t, DropdownMenuTrigger as u };
120623
+ export { Input as C, DropdownMenuTrigger as S, Separator as T, Checkbox as _, SpecProgress as a, DropdownMenuCheckboxItem as b, SurfaceButton as c, catalogComponentImpls as d, str as f, Button as g, Badge as h, SpecGrid as i, SurfaceField as l, useSurfaceForm as m, CatalogSurfaceProvider as n, SpecTabs as o, useCatalogSurfaceForm as p, EChart as r, SpecTimeline as s, CatalogNode as t, SurfaceFormButtons as u, DataTable as v, Markdown as w, DropdownMenuContent as x, DropdownMenu as y };