@rinova/playground 0.1.5 → 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 (82) hide show
  1. package/README.md +6 -7
  2. package/dist/PlaygroundRoot-Bcq7hG6m.js +4114 -0
  3. package/dist/bash-DXbFn1Mw.js +2 -0
  4. package/dist/diff-BbCHXb9k.js +2 -0
  5. package/dist/html-BheHDAwJ.js +10 -0
  6. package/dist/index.js +646 -5
  7. package/dist/less-DcFvX2iI.js +2 -0
  8. package/dist/light-plus-DuoQWI9Q.js +3 -0
  9. package/dist/markdown-qYHfSPvL.js +2 -0
  10. package/dist/marked.esm-CNYX-ybC.js +1796 -0
  11. package/dist/{App-DUVLlDOI.js → plugin-S72dg7Tb.js} +556 -1700
  12. package/dist/style.css +2857 -554
  13. package/dist/tokyo-night-A7e3DMsQ.js +3 -0
  14. package/dist/types/app/App.vue.d.ts +1 -0
  15. package/dist/types/app/PlaygroundApiTable.vue.d.ts +16 -0
  16. package/dist/types/app/PlaygroundEditorPicker.vue.d.ts +3 -0
  17. package/dist/types/app/PlaygroundModuleApi.vue.d.ts +17 -0
  18. package/dist/types/app/PlaygroundPage.vue.d.ts +30 -0
  19. package/dist/types/app/{PlaygroundSourcePanel.vue.d.ts → PlaygroundPageIndex.vue.d.ts} +4 -4
  20. package/dist/types/app/PlaygroundPluginPanel.vue.d.ts +3 -0
  21. package/dist/types/app/PlaygroundPluginSlot.vue.d.ts +12 -0
  22. package/dist/types/app/PlaygroundPluginWrappers.vue.d.ts +25 -0
  23. package/dist/types/app/PlaygroundRoot.vue.d.ts +4 -0
  24. package/dist/types/app/{PlaygroundParamsPanel.vue.d.ts → PlaygroundSceneArgs.vue.d.ts} +1 -1
  25. package/dist/types/app/PlaygroundSceneOutput.vue.d.ts +6 -0
  26. package/dist/types/app/PlaygroundSceneSection.vue.d.ts +16 -0
  27. package/dist/types/app/{PlaygroundStage.vue.d.ts → PlaygroundSceneSource.vue.d.ts} +0 -1
  28. package/dist/types/app/PlaygroundSidebar.vue.d.ts +19 -8
  29. package/dist/types/app/viewport.d.ts +39 -0
  30. package/dist/types/code/CodeBlock.vue.d.ts +19 -1
  31. package/dist/types/code/clipboard.d.ts +2 -0
  32. package/dist/types/code/find.d.ts +42 -0
  33. package/dist/types/code/highlighter.d.ts +9 -2
  34. package/dist/types/code/openInEditor.d.ts +35 -0
  35. package/dist/types/{app/PlaygroundGroupIndex.vue.d.ts → components/PwApiBrief.vue.d.ts} +9 -9
  36. package/dist/types/components/PwButton.vue.d.ts +2 -2
  37. package/dist/types/components/PwDemo.vue.d.ts +39 -0
  38. package/dist/types/components/PwDemoGrid.vue.d.ts +32 -0
  39. package/dist/types/components/PwInput.vue.d.ts +8 -8
  40. package/dist/types/components/PwSceneBoundary.vue.d.ts +20 -0
  41. package/dist/types/components/PwSceneNote.vue.d.ts +19 -0
  42. package/dist/types/components/PwTooltip.vue.d.ts +3 -0
  43. package/dist/types/components/prose/PwCallout.vue.d.ts +24 -0
  44. package/dist/types/components/prose/PwMarkdown.vue.d.ts +11 -0
  45. package/dist/types/components/prose/PwProse.vue.d.ts +27 -0
  46. package/dist/types/components/prose/PwStep.vue.d.ts +27 -0
  47. package/dist/types/components/prose/PwSteps.vue.d.ts +26 -0
  48. package/dist/types/components/prose/enhance.d.ts +4 -0
  49. package/dist/types/components/prose/index.d.ts +7 -0
  50. package/dist/types/components/prose/markdown-scene.d.ts +10 -0
  51. package/dist/types/components/prose/parse.d.ts +20 -0
  52. package/dist/types/components/prose/render.d.ts +22 -0
  53. package/dist/types/components/scene.d.ts +5 -0
  54. package/dist/types/config.d.ts +38 -10
  55. package/dist/types/index.d.ts +11 -4
  56. package/dist/types/module-api.d.ts +55 -0
  57. package/dist/types/payload/args.d.ts +5 -3
  58. package/dist/types/payload/context.d.ts +3 -0
  59. package/dist/types/payload/output.d.ts +4 -2
  60. package/dist/types/plugin.d.ts +119 -0
  61. package/dist/types/scene-meta.d.ts +38 -3
  62. package/dist/types/shims.d.ts +26 -8
  63. package/dist/types/types.d.ts +107 -20
  64. package/dist/vue-B_A2yz16.js +30 -0
  65. package/dist/yaml-CoEYOy4X.js +2 -0
  66. package/package.json +3 -5
  67. package/dist/assets/editor.worker-G4Kxf7Y6.js +0 -15827
  68. package/dist/assets/ts.worker-Dee0cZZb.js +0 -164076
  69. package/dist/dist-B0hittbo.js +0 -151
  70. package/dist/editor.api-YVDhnHI-.js +0 -126730
  71. package/dist/editor.css +0 -1
  72. package/dist/editor.worker-VDFPHiZj.js +0 -5
  73. package/dist/monaco.contribution-CaO2YABh.js +0 -220
  74. package/dist/output-CGawAeuu.js +0 -80
  75. package/dist/ts.worker-CpQm_d0w.js +0 -5
  76. package/dist/tsMode-BOlRJVVo.js +0 -52173
  77. package/dist/types/app/PlaygroundToolbar.vue.d.ts +0 -22
  78. package/dist/types/code/CodeEditor.vue.d.ts +0 -18
  79. package/dist/types/code/monaco.d.ts +0 -6
  80. package/dist/vitesse-dark-B9O9KI0c.js +0 -3
  81. package/dist/vitesse-light-Cs2DYTIe.js +0 -3
  82. package/dist/vue-tjAT-6a9.js +0 -36
@@ -1,7 +1,4 @@
1
- import { a as currentArgsSlots, c as toastState, i as currentArgs, n as currentOutputSlots, s as toast, t as currentOutput } from "./output-CGawAeuu.js";
2
- import { Fragment, Teleport, TransitionGroup, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, h, inject, normalizeClass, onBeforeUnmount, onMounted, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, shallowRef, toDisplayString, unref, watch, watchEffect, withCtx } from "vue";
3
- import config from "virtual:playground/config";
4
- import { scenes } from "virtual:playground/scenes";
1
+ import { Fragment, computed, createCommentVNode, createElementBlock, createElementVNode, defineComponent, h, inject, onBeforeUnmount, onMounted, openBlock, provide, reactive, renderList, shallowRef, toDisplayString } from "vue";
5
2
  // \0rolldown/runtime.js
6
3
  var __defProp = Object.defineProperty;
7
4
  var __exportAll = (all, no_symbols) => {
@@ -13,6 +10,61 @@ var __exportAll = (all, no_symbols) => {
13
10
  if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
14
11
  return target;
15
12
  };
13
+ // \0plugin-vue:export-helper
14
+ var _plugin_vue_export_helper_default = (sfc, props) => {
15
+ const target = sfc.__vccOpts || sfc;
16
+ for (const [key, val] of props) target[key] = val;
17
+ return target;
18
+ };
19
+ // src/components/PwApiBrief.vue?vue&type=script&setup=true&lang.ts
20
+ var _hoisted_1 = {
21
+ key: 0,
22
+ class: "pw-api-brief"
23
+ };
24
+ var _hoisted_2 = ["title", "onClick"];
25
+ var _hoisted_3 = { class: "pw-api-brief__name" };
26
+ var _hoisted_4 = {
27
+ key: 0,
28
+ class: "pw-api-brief__type"
29
+ };
30
+ var _hoisted_5 = {
31
+ key: 1,
32
+ class: "pw-api-brief__default"
33
+ };
34
+ // src/components/PwApiBrief.vue
35
+ var PwApiBrief_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
36
+ __name: "PwApiBrief",
37
+ props: { items: {} },
38
+ emits: ["inspect"],
39
+ setup(__props, { emit: __emit }) {
40
+ /** 场景顶部 API 摘要行:一个场景演示了哪些 API,类型与默认值来自 manifest */
41
+ const emit = __emit;
42
+ return (_ctx, _cache) => {
43
+ return __props.items.length ? (openBlock(), createElementBlock("ul", _hoisted_1, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.items, (item) => {
44
+ return openBlock(), createElementBlock("li", {
45
+ key: item.name,
46
+ class: "pw-api-brief__item"
47
+ }, [createElementVNode("button", {
48
+ type: "button",
49
+ class: "pw-api-brief__chip",
50
+ title: `在 API 表里查看 ${item.name}`,
51
+ onClick: ($event) => emit("inspect", item.name)
52
+ }, [
53
+ createElementVNode("code", _hoisted_3, toDisplayString(item.name), 1),
54
+ item.type ? (openBlock(), createElementBlock("span", _hoisted_4, toDisplayString(item.type), 1)) : createCommentVNode("", true),
55
+ item.default ? (openBlock(), createElementBlock("span", _hoisted_5, "= " + toDisplayString(item.default), 1)) : createCommentVNode("", true)
56
+ ], 8, _hoisted_2)]);
57
+ }), 128))])) : createCommentVNode("", true);
58
+ };
59
+ }
60
+ }), [["__scopeId", "data-v-20ccf753"]]);
61
+ // ../../node_modules/.pnpm/@shikijs+types@4.6.0/node_modules/@shikijs/types/dist/index.mjs
62
+ var ShikiError = class extends Error {
63
+ constructor(message) {
64
+ super(message);
65
+ this.name = "ShikiError";
66
+ }
67
+ };
16
68
  // ../../node_modules/.pnpm/@shikijs+vscode-textmate@10.1.0/node_modules/@shikijs/vscode-textmate/dist/index.js
17
69
  function clone(something) {
18
70
  return doClone(something);
@@ -2378,760 +2430,108 @@ var Registry$1 = class {
2378
2430
  }
2379
2431
  };
2380
2432
  var INITIAL = StateStackImpl.NULL;
2381
- // src/components/PwToastHost.vue?vue&type=script&setup=true&lang.ts
2382
- var _hoisted_1$11 = {
2383
- class: "pw-toast-host",
2384
- role: "status",
2385
- "aria-live": "polite"
2386
- };
2387
- var PwToastHost_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
2388
- __name: "PwToastHost",
2389
- setup(__props) {
2390
- return (_ctx, _cache) => {
2391
- return openBlock(), createBlock(Teleport, { to: "body" }, [createElementVNode("div", _hoisted_1$11, [createVNode(TransitionGroup, { name: "pw-toast" }, {
2392
- default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(toastState), (item) => {
2393
- return openBlock(), createElementBlock("div", {
2394
- key: item.id,
2395
- class: normalizeClass(["pw-toast", `pw-toast--${item.type}`])
2396
- }, toDisplayString(item.text), 3);
2397
- }), 128))]),
2398
- _: 1
2399
- })])]);
2400
- };
2401
- }
2402
- });
2403
- // \0plugin-vue:export-helper
2404
- var _plugin_vue_export_helper_default = (sfc, props) => {
2405
- const target = sfc.__vccOpts || sfc;
2406
- for (const [key, val] of props) target[key] = val;
2407
- return target;
2408
- };
2409
- // src/components/PwToastHost.vue
2410
- var PwToastHost_default = /*#__PURE__*/ _plugin_vue_export_helper_default(PwToastHost_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-4f7c0a94"]]);
2411
- // ../../node_modules/.pnpm/@lucide+vue@1.66.0_vue@3.5.44_typescript@5.9.3_/node_modules/@lucide/vue/dist/esm/shared/src/build/defaultAttributes.mjs
2433
+ // ../../node_modules/.pnpm/@shikijs+primitive@4.6.0/node_modules/@shikijs/primitive/dist/index.mjs
2434
+ function resolveColorReplacements(theme, options) {
2435
+ const replacements = typeof theme === "string" ? {} : { ...theme.colorReplacements };
2436
+ const themeName = typeof theme === "string" ? theme : theme.name;
2437
+ for (const [key, value] of Object.entries(options?.colorReplacements || {})) if (typeof value === "string") replacements[key] = value;
2438
+ else if (key === themeName) Object.assign(replacements, value);
2439
+ return replacements;
2440
+ }
2441
+ function applyColorReplacements(color, replacements) {
2442
+ if (!color) return color;
2443
+ return replacements?.[color?.toLowerCase()] || color;
2444
+ }
2445
+ function toArray(x) {
2446
+ return Array.isArray(x) ? x : [x];
2447
+ }
2412
2448
  /**
2413
- * @license @lucide/vue v1.66.0 - ISC
2414
- *
2415
- * This source code is licensed under the ISC license.
2416
- * See the LICENSE file in the root directory of this source tree.
2449
+ * Normalize a getter to a promise.
2417
2450
  */
2418
- var defaultAttributes = {
2419
- xmlns: "http://www.w3.org/2000/svg",
2420
- width: 24,
2421
- height: 24,
2422
- viewBox: "0 0 24 24",
2423
- fill: "none",
2424
- stroke: "currentColor",
2425
- "stroke-width": 2,
2426
- "stroke-linecap": "round",
2427
- "stroke-linejoin": "round"
2428
- };
2429
- // ../../node_modules/.pnpm/@lucide+vue@1.66.0_vue@3.5.44_typescript@5.9.3_/node_modules/@lucide/vue/dist/esm/shared/src/utils/mergeClasses.mjs
2451
+ async function normalizeGetter(p) {
2452
+ return Promise.resolve(typeof p === "function" ? p() : p).then((r) => r.default || r);
2453
+ }
2430
2454
  /**
2431
- * @license @lucide/vue v1.66.0 - ISC
2455
+ * Check if the language is plaintext that is ignored by Shiki.
2432
2456
  *
2433
- * This source code is licensed under the ISC license.
2434
- * See the LICENSE file in the root directory of this source tree.
2457
+ * Hard-coded plain text languages: `plaintext`, `txt`, `text`, `plain`.
2435
2458
  */
2436
- var mergeClasses = (...classes) => classes.filter((className, index, array) => {
2437
- return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index;
2438
- }).join(" ").trim();
2439
- // ../../node_modules/.pnpm/@lucide+vue@1.66.0_vue@3.5.44_typescript@5.9.3_/node_modules/@lucide/vue/dist/esm/shared/src/build/buildLucideIconNode.mjs
2459
+ function isPlainLang(lang) {
2460
+ return !lang || [
2461
+ "plaintext",
2462
+ "txt",
2463
+ "text",
2464
+ "plain"
2465
+ ].includes(lang);
2466
+ }
2440
2467
  /**
2441
- * @license @lucide/vue v1.66.0 - ISC
2468
+ * Check if the language is specially handled or bypassed by Shiki.
2442
2469
  *
2443
- * This source code is licensed under the ISC license.
2444
- * See the LICENSE file in the root directory of this source tree.
2470
+ * Hard-coded languages: `ansi` and plaintexts like `plaintext`, `txt`, `text`, `plain`.
2445
2471
  */
2446
- function isDefined(value) {
2447
- return value !== null && value !== void 0;
2448
- }
2449
- function buildLucideIconNode(icon, params = {}) {
2450
- const attributeNames = params.attributeNames ?? {};
2451
- const getAttributeName = (attributeName) => attributeNames[attributeName] ?? attributeName;
2452
- const viewBoxWidth = icon.size ?? icon.width ?? defaultAttributes["width"];
2453
- const viewBoxHeight = icon.size ?? icon.height ?? defaultAttributes["height"];
2454
- const aliasClassNames = icon.aliases?.filter((alias) => typeof alias === "string" && alias.trim() !== "").map((alias) => `lucide-${alias}`) ?? [];
2455
- const iconClassNames = [...icon.name ? [`lucide-${icon.name}`] : [], ...aliasClassNames];
2456
- const classNamesFromClassName = params.className?.split(" ").filter(Boolean) ?? [];
2457
- const className = params.includeDefaultClasses === false ? mergeClasses(...classNamesFromClassName) : mergeClasses("lucide", ...iconClassNames, ...classNamesFromClassName);
2458
- const calculatedStrokeWidth = params.absoluteStrokeWidth ? Number(params.strokeWidth ?? defaultAttributes["stroke-width"]) * Number(icon.size ?? icon.width ?? defaultAttributes["width"]) / Number(params.size ?? params.width ?? defaultAttributes["width"]) : params.strokeWidth ?? defaultAttributes["stroke-width"];
2459
- return [
2460
- "svg",
2461
- {
2462
- ...Object.entries(defaultAttributes).reduce((attrs, [attrName, value]) => {
2463
- attrs[getAttributeName(attrName)] = value;
2464
- return attrs;
2465
- }, {}),
2466
- ..."color" in params && params.color && { [getAttributeName("stroke")]: params.color },
2467
- ..."size" in params && isDefined(params.size) && {
2468
- [getAttributeName("width")]: params.size,
2469
- [getAttributeName("height")]: params.size
2470
- },
2471
- ..."width" in params && isDefined(params.width) && { [getAttributeName("width")]: params.width },
2472
- ..."height" in params && isDefined(params.height) && { [getAttributeName("height")]: params.height },
2473
- [getAttributeName("stroke-width")]: calculatedStrokeWidth,
2474
- ...className && { [getAttributeName("class")]: className },
2475
- [getAttributeName("viewBox")]: `0 0 ${viewBoxWidth} ${viewBoxHeight}`,
2476
- ...params.hasA11yProp === false ? { [getAttributeName("aria-hidden")]: "true" } : {},
2477
- ..."attributes" in params && params.attributes
2478
- },
2479
- icon.node.map((child) => {
2480
- const [name, attrs, children] = child;
2481
- const nextAttrs = params.nonScalingStroke ? {
2482
- [getAttributeName("vector-effect")]: "non-scaling-stroke",
2483
- ...attrs
2484
- } : attrs;
2485
- return children ? [
2486
- name,
2487
- nextAttrs,
2488
- children
2489
- ] : [name, nextAttrs];
2490
- })
2491
- ];
2472
+ function isSpecialLang(lang) {
2473
+ return lang === "ansi" || isPlainLang(lang);
2492
2474
  }
2493
- // ../../node_modules/.pnpm/@lucide+vue@1.66.0_vue@3.5.44_typescript@5.9.3_/node_modules/@lucide/vue/dist/esm/shared/src/utils/hasA11yProp.mjs
2494
2475
  /**
2495
- * @license @lucide/vue v1.66.0 - ISC
2476
+ * Check if the theme is specially handled or bypassed by Shiki.
2496
2477
  *
2497
- * This source code is licensed under the ISC license.
2498
- * See the LICENSE file in the root directory of this source tree.
2478
+ * Hard-coded themes: `none`.
2499
2479
  */
2500
- var hasA11yProp = (props) => {
2501
- for (const prop in props) if (prop.startsWith("aria-") || prop === "role" || prop === "title") return true;
2502
- return false;
2503
- };
2504
- // ../../node_modules/.pnpm/@lucide+vue@1.66.0_vue@3.5.44_typescript@5.9.3_/node_modules/@lucide/vue/dist/esm/shared/src/utils/isEmptyString.mjs
2480
+ function isNoneTheme(theme) {
2481
+ return theme === "none";
2482
+ }
2505
2483
  /**
2506
- * @license @lucide/vue v1.66.0 - ISC
2484
+ * Check if the theme is specially handled or bypassed by Shiki.
2507
2485
  *
2508
- * This source code is licensed under the ISC license.
2509
- * See the LICENSE file in the root directory of this source tree.
2486
+ * Hard-coded themes: `none`.
2510
2487
  */
2511
- var isEmptyString = (value) => value === "";
2512
- // ../../node_modules/.pnpm/@lucide+vue@1.66.0_vue@3.5.44_typescript@5.9.3_/node_modules/@lucide/vue/dist/esm/shared/src/utils/toKebabCase.mjs
2488
+ function isSpecialTheme(theme) {
2489
+ return isNoneTheme(theme);
2490
+ }
2513
2491
  /**
2514
- * @license @lucide/vue v1.66.0 - ISC
2492
+ * Split a string into lines, each line preserves the line ending.
2515
2493
  *
2516
- * This source code is licensed under the ISC license.
2517
- * See the LICENSE file in the root directory of this source tree.
2518
- */
2519
- var toKebabCase = (string) => string?.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
2520
- // ../../node_modules/.pnpm/@lucide+vue@1.66.0_vue@3.5.44_typescript@5.9.3_/node_modules/@lucide/vue/dist/esm/context.mjs
2521
- /**
2522
- * @license @lucide/vue v1.66.0 - ISC
2494
+ * @param code - The code string to split into lines
2495
+ * @param preserveEnding - Whether to preserve line endings in the result
2496
+ * @returns Array of tuples containing [line content, offset index]
2523
2497
  *
2524
- * This source code is licensed under the ISC license.
2525
- * See the LICENSE file in the root directory of this source tree.
2498
+ * @example
2499
+ * ```ts
2500
+ * splitLines('hello\nworld', false)
2501
+ * // => [['hello', 0], ['world', 6]]
2502
+ *
2503
+ * splitLines('hello\nworld', true)
2504
+ * // => [['hello\n', 0], ['world', 6]]
2505
+ * ```
2526
2506
  */
2527
- var LUCIDE_CONTEXT = /* @__PURE__ */ Symbol("lucide-icons");
2528
- function useLucideProps() {
2529
- return inject(LUCIDE_CONTEXT, {});
2507
+ var RE_NEWLINE = /(\r?\n)/g;
2508
+ function splitLines(code, preserveEnding = false) {
2509
+ if (code.length === 0) return [["", 0]];
2510
+ const parts = code.split(RE_NEWLINE);
2511
+ let index = 0;
2512
+ const lines = [];
2513
+ for (let i = 0; i < parts.length; i += 2) {
2514
+ const line = preserveEnding ? parts[i] + (parts[i + 1] || "") : parts[i];
2515
+ lines.push([line, index]);
2516
+ index += parts[i].length;
2517
+ index += parts[i + 1]?.length || 0;
2518
+ }
2519
+ return lines;
2530
2520
  }
2531
- // ../../node_modules/.pnpm/@lucide+vue@1.66.0_vue@3.5.44_typescript@5.9.3_/node_modules/@lucide/vue/dist/esm/Icon.mjs
2532
2521
  /**
2533
- * @license @lucide/vue v1.66.0 - ISC
2534
- *
2535
- * This source code is licensed under the ISC license.
2536
- * See the LICENSE file in the root directory of this source tree.
2522
+ * https://github.com/microsoft/vscode/blob/f7f05dee53fb33fe023db2e06e30a89d3094488f/src/vs/platform/theme/common/colorRegistry.ts#L258-L268
2537
2523
  */
2538
- var Icon = ({ name, iconNode, "icon-node": iconNodeKebabCase, icon = {
2539
- name: name && toKebabCase(name),
2540
- node: iconNode ?? iconNodeKebabCase ?? [],
2541
- size: 24,
2542
- aliases: []
2543
- }, absoluteStrokeWidth, "absolute-stroke-width": absoluteStrokeWidthKebabCase, nonScalingStroke, "non-scaling-stroke": nonScalingStrokeKebabCase, strokeWidth, "stroke-width": strokeWidthKebabCase, size, width = size, height = size, color, ...props }, { slots }) => {
2544
- const { size: contextSize, color: contextColor, strokeWidth: contextStrokeWidth = 2, absoluteStrokeWidth: contextAbsoluteStrokeWidth = false, nonScalingStroke: contextNonScalingStroke = false, class: contextClass = "" } = useLucideProps();
2545
- const isAbsoluteStrokeWidth = isEmptyString(absoluteStrokeWidth) || isEmptyString(absoluteStrokeWidthKebabCase) || absoluteStrokeWidth === true || absoluteStrokeWidthKebabCase === true || contextAbsoluteStrokeWidth === true;
2546
- const isNonScalingStroke = isEmptyString(nonScalingStroke) || isEmptyString(nonScalingStrokeKebabCase) || nonScalingStroke === true || nonScalingStrokeKebabCase === true || contextNonScalingStroke === true;
2547
- delete props.class;
2548
- const defaultSlot = slots.default?.();
2549
- const [, svgAttributes, builtIconNode = []] = buildLucideIconNode(icon, {
2550
- color: color ?? contextColor,
2551
- width: width ?? size ?? contextSize,
2552
- height: height ?? size ?? contextSize,
2553
- strokeWidth: strokeWidth ?? strokeWidthKebabCase ?? contextStrokeWidth,
2554
- absoluteStrokeWidth: isAbsoluteStrokeWidth,
2555
- nonScalingStroke: isNonScalingStroke,
2556
- className: contextClass,
2557
- hasA11yProp: defaultSlot != null && defaultSlot.length > 0 || hasA11yProp(props),
2558
- attributes: props
2559
- });
2560
- return h("svg", svgAttributes, [...builtIconNode.map(([tag, attrs]) => h(tag, attrs)), ...defaultSlot ?? []]);
2524
+ var VSCODE_FALLBACK_EDITOR_FG = {
2525
+ light: "#333333",
2526
+ dark: "#bbbbbb"
2561
2527
  };
2562
- // ../../node_modules/.pnpm/@lucide+vue@1.66.0_vue@3.5.44_typescript@5.9.3_/node_modules/@lucide/vue/dist/esm/createLucideIcon.mjs
2528
+ var VSCODE_FALLBACK_EDITOR_BG = {
2529
+ light: "#fffffe",
2530
+ dark: "#1e1e1e"
2531
+ };
2532
+ var RESOLVED_KEY = "__shiki_resolved";
2563
2533
  /**
2564
- * @license @lucide/vue v1.66.0 - ISC
2565
- *
2566
- * This source code is licensed under the ISC license.
2567
- * See the LICENSE file in the root directory of this source tree.
2568
- */
2569
- function createLucideIcon(iconDataOrName, iconNode = []) {
2570
- const icon = typeof iconDataOrName === "string" ? {
2571
- name: iconDataOrName,
2572
- node: iconNode
2573
- } : iconDataOrName;
2574
- return (props, { slots }) => h(Icon, {
2575
- ...props,
2576
- icon
2577
- }, slots.default ? { default: slots.default } : void 0);
2578
- }
2579
- /**
2580
- * @license @lucide/vue v1.66.0 - ISC
2581
- *
2582
- * This source code is licensed under the ISC license.
2583
- * See the LICENSE file in the root directory of this source tree.
2584
- */
2585
- var Check = createLucideIcon({
2586
- name: "check",
2587
- size: 24,
2588
- node: [["path", {
2589
- d: "M20 6 9 17l-5-5",
2590
- key: "1gmf2c"
2591
- }]]
2592
- });
2593
- /**
2594
- * @license @lucide/vue v1.66.0 - ISC
2595
- *
2596
- * This source code is licensed under the ISC license.
2597
- * See the LICENSE file in the root directory of this source tree.
2598
- */
2599
- var CodeXml = createLucideIcon({
2600
- name: "code-xml",
2601
- size: 24,
2602
- node: [
2603
- ["path", {
2604
- d: "m18 16 4-4-4-4",
2605
- key: "1inbqp"
2606
- }],
2607
- ["path", {
2608
- d: "m6 8-4 4 4 4",
2609
- key: "15zrgr"
2610
- }],
2611
- ["path", {
2612
- d: "m14.5 4-5 16",
2613
- key: "e7oirm"
2614
- }]
2615
- ],
2616
- aliases: ["code-2"]
2617
- });
2618
- /**
2619
- * @license @lucide/vue v1.66.0 - ISC
2620
- *
2621
- * This source code is licensed under the ISC license.
2622
- * See the LICENSE file in the root directory of this source tree.
2623
- */
2624
- var Copy = createLucideIcon({
2625
- name: "copy",
2626
- size: 24,
2627
- node: [["rect", {
2628
- width: "14",
2629
- height: "14",
2630
- x: "8",
2631
- y: "8",
2632
- rx: "2",
2633
- ry: "2",
2634
- key: "17jyea"
2635
- }], ["path", {
2636
- d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",
2637
- key: "zix9uf"
2638
- }]]
2639
- });
2640
- /**
2641
- * @license @lucide/vue v1.66.0 - ISC
2642
- *
2643
- * This source code is licensed under the ISC license.
2644
- * See the LICENSE file in the root directory of this source tree.
2645
- */
2646
- var Monitor = createLucideIcon({
2647
- name: "monitor",
2648
- size: 24,
2649
- node: [
2650
- ["rect", {
2651
- width: "20",
2652
- height: "14",
2653
- x: "2",
2654
- y: "3",
2655
- rx: "2",
2656
- key: "48i651"
2657
- }],
2658
- ["line", {
2659
- x1: "8",
2660
- x2: "16",
2661
- y1: "21",
2662
- y2: "21",
2663
- key: "1svkeh"
2664
- }],
2665
- ["line", {
2666
- x1: "12",
2667
- x2: "12",
2668
- y1: "17",
2669
- y2: "21",
2670
- key: "vw1qmm"
2671
- }]
2672
- ]
2673
- });
2674
- /**
2675
- * @license @lucide/vue v1.66.0 - ISC
2676
- *
2677
- * This source code is licensed under the ISC license.
2678
- * See the LICENSE file in the root directory of this source tree.
2679
- */
2680
- var Moon = createLucideIcon({
2681
- name: "moon",
2682
- size: 24,
2683
- node: [["path", {
2684
- d: "M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401",
2685
- key: "kfwtm"
2686
- }]]
2687
- });
2688
- /**
2689
- * @license @lucide/vue v1.66.0 - ISC
2690
- *
2691
- * This source code is licensed under the ISC license.
2692
- * See the LICENSE file in the root directory of this source tree.
2693
- */
2694
- var RotateCcw = createLucideIcon({
2695
- name: "rotate-ccw",
2696
- size: 24,
2697
- node: [["path", {
2698
- d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",
2699
- key: "1357e3"
2700
- }], ["path", {
2701
- d: "M3 3v5h5",
2702
- key: "1xhq8a"
2703
- }]]
2704
- });
2705
- /**
2706
- * @license @lucide/vue v1.66.0 - ISC
2707
- *
2708
- * This source code is licensed under the ISC license.
2709
- * See the LICENSE file in the root directory of this source tree.
2710
- */
2711
- var Search = createLucideIcon({
2712
- name: "search",
2713
- size: 24,
2714
- node: [["path", {
2715
- d: "m21 21-4.34-4.34",
2716
- key: "14j7rj"
2717
- }], ["circle", {
2718
- cx: "11",
2719
- cy: "11",
2720
- r: "8",
2721
- key: "4ej97u"
2722
- }]]
2723
- });
2724
- /**
2725
- * @license @lucide/vue v1.66.0 - ISC
2726
- *
2727
- * This source code is licensed under the ISC license.
2728
- * See the LICENSE file in the root directory of this source tree.
2729
- */
2730
- var SlidersHorizontal = createLucideIcon({
2731
- name: "sliders-horizontal",
2732
- size: 24,
2733
- node: [
2734
- ["path", {
2735
- d: "M10 5H3",
2736
- key: "1qgfaw"
2737
- }],
2738
- ["path", {
2739
- d: "M12 19H3",
2740
- key: "yhmn1j"
2741
- }],
2742
- ["path", {
2743
- d: "M14 3v4",
2744
- key: "1sua03"
2745
- }],
2746
- ["path", {
2747
- d: "M16 17v4",
2748
- key: "1q0r14"
2749
- }],
2750
- ["path", {
2751
- d: "M21 12h-9",
2752
- key: "1o4lsq"
2753
- }],
2754
- ["path", {
2755
- d: "M21 19h-5",
2756
- key: "1rlt1p"
2757
- }],
2758
- ["path", {
2759
- d: "M21 5h-7",
2760
- key: "1oszz2"
2761
- }],
2762
- ["path", {
2763
- d: "M8 10v4",
2764
- key: "tgpxqk"
2765
- }],
2766
- ["path", {
2767
- d: "M8 12H3",
2768
- key: "a7s4jb"
2769
- }]
2770
- ]
2771
- });
2772
- /**
2773
- * @license @lucide/vue v1.66.0 - ISC
2774
- *
2775
- * This source code is licensed under the ISC license.
2776
- * See the LICENSE file in the root directory of this source tree.
2777
- */
2778
- var Smartphone = createLucideIcon({
2779
- name: "smartphone",
2780
- size: 24,
2781
- node: [["rect", {
2782
- width: "14",
2783
- height: "20",
2784
- x: "5",
2785
- y: "2",
2786
- rx: "2",
2787
- ry: "2",
2788
- key: "1yt0o3"
2789
- }], ["path", {
2790
- d: "M12 18h.01",
2791
- key: "mhygvu"
2792
- }]]
2793
- });
2794
- /**
2795
- * @license @lucide/vue v1.66.0 - ISC
2796
- *
2797
- * This source code is licensed under the ISC license.
2798
- * See the LICENSE file in the root directory of this source tree.
2799
- */
2800
- var Sun = createLucideIcon({
2801
- name: "sun",
2802
- size: 24,
2803
- node: [
2804
- ["circle", {
2805
- cx: "12",
2806
- cy: "12",
2807
- r: "4",
2808
- key: "4exip2"
2809
- }],
2810
- ["path", {
2811
- d: "M12 2v2",
2812
- key: "tus03m"
2813
- }],
2814
- ["path", {
2815
- d: "M12 20v2",
2816
- key: "1lh1kg"
2817
- }],
2818
- ["path", {
2819
- d: "m4.93 4.93 1.41 1.41",
2820
- key: "149t6j"
2821
- }],
2822
- ["path", {
2823
- d: "m17.66 17.66 1.41 1.41",
2824
- key: "ptbguv"
2825
- }],
2826
- ["path", {
2827
- d: "M2 12h2",
2828
- key: "1t8f8n"
2829
- }],
2830
- ["path", {
2831
- d: "M20 12h2",
2832
- key: "1q8mjw"
2833
- }],
2834
- ["path", {
2835
- d: "m6.34 17.66-1.41 1.41",
2836
- key: "1m8zz5"
2837
- }],
2838
- ["path", {
2839
- d: "m19.07 4.93-1.41 1.41",
2840
- key: "1shlcs"
2841
- }]
2842
- ]
2843
- });
2844
- /**
2845
- * @license @lucide/vue v1.66.0 - ISC
2846
- *
2847
- * This source code is licensed under the ISC license.
2848
- * See the LICENSE file in the root directory of this source tree.
2849
- */
2850
- var Tablet = createLucideIcon({
2851
- name: "tablet",
2852
- size: 24,
2853
- node: [["rect", {
2854
- width: "16",
2855
- height: "20",
2856
- x: "4",
2857
- y: "2",
2858
- rx: "2",
2859
- ry: "2",
2860
- key: "76otgf"
2861
- }], ["line", {
2862
- x1: "12",
2863
- x2: "12.01",
2864
- y1: "18",
2865
- y2: "18",
2866
- key: "1dp563"
2867
- }]]
2868
- });
2869
- /**
2870
- * @license @lucide/vue v1.66.0 - ISC
2871
- *
2872
- * This source code is licensed under the ISC license.
2873
- * See the LICENSE file in the root directory of this source tree.
2874
- */
2875
- var X$2 = createLucideIcon({
2876
- name: "x",
2877
- size: 24,
2878
- node: [["path", {
2879
- d: "M18 6 6 18",
2880
- key: "1bl5f8"
2881
- }], ["path", {
2882
- d: "m6 6 12 12",
2883
- key: "d8bk6v"
2884
- }]]
2885
- });
2886
- // src/components/PwButton.vue?vue&type=script&setup=true&lang.ts
2887
- var _hoisted_1$10 = ["disabled", "title"];
2888
- var _hoisted_2$9 = {
2889
- key: 0,
2890
- class: "pw-btn__spinner",
2891
- "aria-hidden": "true"
2892
- };
2893
- var _hoisted_3$8 = {
2894
- key: 2,
2895
- class: "pw-btn__label"
2896
- };
2897
- // src/components/PwButton.vue
2898
- var PwButton_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
2899
- __name: "PwButton",
2900
- props: {
2901
- variant: { default: "ghost" },
2902
- size: { default: "md" },
2903
- disabled: {
2904
- type: Boolean,
2905
- default: false
2906
- },
2907
- loading: {
2908
- type: Boolean,
2909
- default: false
2910
- },
2911
- title: {}
2912
- },
2913
- setup(__props) {
2914
- return (_ctx, _cache) => {
2915
- return openBlock(), createElementBlock("button", {
2916
- class: normalizeClass(["pw-btn", [
2917
- `pw-btn--${__props.variant}`,
2918
- `pw-btn--${__props.size}`,
2919
- { "is-loading": __props.loading }
2920
- ]]),
2921
- disabled: __props.disabled || __props.loading,
2922
- title: __props.title,
2923
- type: "button"
2924
- }, [__props.loading ? (openBlock(), createElementBlock("span", _hoisted_2$9)) : renderSlot(_ctx.$slots, "icon", {}, void 0, true, 1), _ctx.$slots.default ? (openBlock(), createElementBlock("span", _hoisted_3$8, [renderSlot(_ctx.$slots, "default", {}, void 0, true)])) : createCommentVNode("", true)], 10, _hoisted_1$10);
2925
- };
2926
- }
2927
- }), [["__scopeId", "data-v-8c5978c8"]]);
2928
- // src/components/PwInput.vue?vue&type=script&setup=true&lang.ts
2929
- var _hoisted_1$9 = ["data-empty"];
2930
- var _hoisted_2$8 = [
2931
- "type",
2932
- "value",
2933
- "placeholder",
2934
- "autofocus"
2935
- ];
2936
- // src/components/PwInput.vue
2937
- var PwInput_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
2938
- __name: "PwInput",
2939
- props: {
2940
- modelValue: { default: "" },
2941
- placeholder: {},
2942
- clearable: {
2943
- type: Boolean,
2944
- default: true
2945
- },
2946
- size: { default: "md" },
2947
- autofocus: {
2948
- type: Boolean,
2949
- default: false
2950
- },
2951
- type: { default: "text" }
2952
- },
2953
- emits: [
2954
- "update:modelValue",
2955
- "keydown",
2956
- "focus",
2957
- "blur"
2958
- ],
2959
- setup(__props, { expose: __expose, emit: __emit }) {
2960
- const props = __props;
2961
- const emit = __emit;
2962
- const inputRef = ref();
2963
- const onInput = (event) => {
2964
- emit("update:modelValue", event.target.value);
2965
- };
2966
- const clear = () => {
2967
- emit("update:modelValue", "");
2968
- inputRef.value?.focus();
2969
- };
2970
- __expose({ focus: () => inputRef.value?.focus() });
2971
- return (_ctx, _cache) => {
2972
- return openBlock(), createElementBlock("div", {
2973
- class: normalizeClass(["pw-input", `pw-input--${__props.size}`]),
2974
- "data-empty": !props.modelValue
2975
- }, [
2976
- renderSlot(_ctx.$slots, "prefix", {}, void 0, true),
2977
- createElementVNode("input", {
2978
- ref_key: "inputRef",
2979
- ref: inputRef,
2980
- class: "pw-input__field",
2981
- type: __props.type,
2982
- value: __props.modelValue,
2983
- placeholder: __props.placeholder,
2984
- autofocus: __props.autofocus,
2985
- onInput,
2986
- onKeydown: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("keydown", $event)),
2987
- onFocus: _cache[1] || (_cache[1] = ($event) => _ctx.$emit("focus", $event)),
2988
- onBlur: _cache[2] || (_cache[2] = ($event) => _ctx.$emit("blur", $event))
2989
- }, null, 40, _hoisted_2$8),
2990
- __props.clearable && __props.modelValue ? (openBlock(), createElementBlock("button", {
2991
- key: 0,
2992
- class: "pw-input__clear",
2993
- type: "button",
2994
- title: "清空",
2995
- onClick: clear
2996
- }, " × ")) : createCommentVNode("", true),
2997
- renderSlot(_ctx.$slots, "suffix", {}, void 0, true)
2998
- ], 10, _hoisted_1$9);
2999
- };
3000
- }
3001
- }), [["__scopeId", "data-v-e249cd4b"]]);
3002
- // src/components/PwSwitch.vue?vue&type=script&setup=true&lang.ts
3003
- var _hoisted_1$8 = ["aria-checked", "disabled"];
3004
- // src/components/PwSwitch.vue
3005
- var PwSwitch_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
3006
- __name: "PwSwitch",
3007
- props: {
3008
- modelValue: { type: Boolean },
3009
- disabled: { type: Boolean }
3010
- },
3011
- emits: ["update:modelValue"],
3012
- setup(__props, { emit: __emit }) {
3013
- const emit = __emit;
3014
- return (_ctx, _cache) => {
3015
- return openBlock(), createElementBlock("button", {
3016
- type: "button",
3017
- role: "switch",
3018
- class: normalizeClass(["pw-switch", { "is-on": __props.modelValue }]),
3019
- "aria-checked": __props.modelValue,
3020
- disabled: __props.disabled,
3021
- onClick: _cache[0] || (_cache[0] = ($event) => emit("update:modelValue", !__props.modelValue))
3022
- }, [..._cache[1] || (_cache[1] = [createElementVNode("span", { class: "pw-switch__thumb" }, null, -1)])], 10, _hoisted_1$8);
3023
- };
3024
- }
3025
- }), [["__scopeId", "data-v-64fffbcb"]]);
3026
- // ../../node_modules/.pnpm/@shikijs+types@4.6.0/node_modules/@shikijs/types/dist/index.mjs
3027
- var ShikiError = class extends Error {
3028
- constructor(message) {
3029
- super(message);
3030
- this.name = "ShikiError";
3031
- }
3032
- };
3033
- // ../../node_modules/.pnpm/@shikijs+primitive@4.6.0/node_modules/@shikijs/primitive/dist/index.mjs
3034
- function resolveColorReplacements(theme, options) {
3035
- const replacements = typeof theme === "string" ? {} : { ...theme.colorReplacements };
3036
- const themeName = typeof theme === "string" ? theme : theme.name;
3037
- for (const [key, value] of Object.entries(options?.colorReplacements || {})) if (typeof value === "string") replacements[key] = value;
3038
- else if (key === themeName) Object.assign(replacements, value);
3039
- return replacements;
3040
- }
3041
- function applyColorReplacements(color, replacements) {
3042
- if (!color) return color;
3043
- return replacements?.[color?.toLowerCase()] || color;
3044
- }
3045
- function toArray(x) {
3046
- return Array.isArray(x) ? x : [x];
3047
- }
3048
- /**
3049
- * Normalize a getter to a promise.
3050
- */
3051
- async function normalizeGetter(p) {
3052
- return Promise.resolve(typeof p === "function" ? p() : p).then((r) => r.default || r);
3053
- }
3054
- /**
3055
- * Check if the language is plaintext that is ignored by Shiki.
3056
- *
3057
- * Hard-coded plain text languages: `plaintext`, `txt`, `text`, `plain`.
3058
- */
3059
- function isPlainLang(lang) {
3060
- return !lang || [
3061
- "plaintext",
3062
- "txt",
3063
- "text",
3064
- "plain"
3065
- ].includes(lang);
3066
- }
3067
- /**
3068
- * Check if the language is specially handled or bypassed by Shiki.
3069
- *
3070
- * Hard-coded languages: `ansi` and plaintexts like `plaintext`, `txt`, `text`, `plain`.
3071
- */
3072
- function isSpecialLang(lang) {
3073
- return lang === "ansi" || isPlainLang(lang);
3074
- }
3075
- /**
3076
- * Check if the theme is specially handled or bypassed by Shiki.
3077
- *
3078
- * Hard-coded themes: `none`.
3079
- */
3080
- function isNoneTheme(theme) {
3081
- return theme === "none";
3082
- }
3083
- /**
3084
- * Check if the theme is specially handled or bypassed by Shiki.
3085
- *
3086
- * Hard-coded themes: `none`.
3087
- */
3088
- function isSpecialTheme(theme) {
3089
- return isNoneTheme(theme);
3090
- }
3091
- /**
3092
- * Split a string into lines, each line preserves the line ending.
3093
- *
3094
- * @param code - The code string to split into lines
3095
- * @param preserveEnding - Whether to preserve line endings in the result
3096
- * @returns Array of tuples containing [line content, offset index]
3097
- *
3098
- * @example
3099
- * ```ts
3100
- * splitLines('hello\nworld', false)
3101
- * // => [['hello', 0], ['world', 6]]
3102
- *
3103
- * splitLines('hello\nworld', true)
3104
- * // => [['hello\n', 0], ['world', 6]]
3105
- * ```
3106
- */
3107
- var RE_NEWLINE = /(\r?\n)/g;
3108
- function splitLines(code, preserveEnding = false) {
3109
- if (code.length === 0) return [["", 0]];
3110
- const parts = code.split(RE_NEWLINE);
3111
- let index = 0;
3112
- const lines = [];
3113
- for (let i = 0; i < parts.length; i += 2) {
3114
- const line = preserveEnding ? parts[i] + (parts[i + 1] || "") : parts[i];
3115
- lines.push([line, index]);
3116
- index += parts[i].length;
3117
- index += parts[i + 1]?.length || 0;
3118
- }
3119
- return lines;
3120
- }
3121
- /**
3122
- * https://github.com/microsoft/vscode/blob/f7f05dee53fb33fe023db2e06e30a89d3094488f/src/vs/platform/theme/common/colorRegistry.ts#L258-L268
3123
- */
3124
- var VSCODE_FALLBACK_EDITOR_FG = {
3125
- light: "#333333",
3126
- dark: "#bbbbbb"
3127
- };
3128
- var VSCODE_FALLBACK_EDITOR_BG = {
3129
- light: "#fffffe",
3130
- dark: "#1e1e1e"
3131
- };
3132
- var RESOLVED_KEY = "__shiki_resolved";
3133
- /**
3134
- * Normalize a textmate theme to shiki theme
2534
+ * Normalize a textmate theme to shiki theme
3135
2535
  */
3136
2536
  function normalizeTheme(rawTheme) {
3137
2537
  if (rawTheme?.[RESOLVED_KEY]) return rawTheme;
@@ -11076,1001 +10476,457 @@ function createJavaScriptRegexEngine(options = {}) {
11076
10476
  * 静态代码块与后续的 Monaco 编辑器必须共用这一个实例,避免两套主题色。
11077
10477
  */
11078
10478
  var highlighterPromise = null;
11079
- var PW_THEME_LIGHT = "vitesse-light";
11080
- var PW_THEME_DARK = "vitesse-dark";
10479
+ /**
10480
+ * 代码配色:浅色用 light-plus(VSCode 默认浅色)、深色用 tokyo-night。
10481
+ *
10482
+ * 早先用 vitesse-light / vitesse-dark(低彩度),在 13px 的代码块里
10483
+ * 标签名、属性名、字符串几乎一个色,看着像“没有高亮”;换成这两套后
10484
+ * token 色相分得开(粉 / 紫 / 绿 / 青),深色底 #1a1b26 也贴着外壳的 #16181d。
10485
+ */
10486
+ var PW_THEME_LIGHT = "light-plus";
10487
+ var PW_THEME_DARK = "tokyo-night";
11081
10488
  var getHighlighter = () => {
11082
10489
  highlighterPromise ??= createHighlighterCore({
11083
- themes: [import("./vitesse-light-Cs2DYTIe.js"), import("./vitesse-dark-B9O9KI0c.js")],
10490
+ themes: [import("./light-plus-DuoQWI9Q.js"), import("./tokyo-night-A7e3DMsQ.js")],
11084
10491
  langs: [
11085
- import("./vue-tjAT-6a9.js"),
10492
+ import("./vue-B_A2yz16.js"),
11086
10493
  import("./typescript-CqzjXQdw.js"),
11087
10494
  import("./javascript-drpK16Ry.js"),
11088
10495
  import("./css-CZhy9mCC.js"),
11089
- import("./json-BRBnC4S4.js")
10496
+ import("./json-BRBnC4S4.js"),
10497
+ import("./less-DcFvX2iI.js"),
10498
+ import("./html-BheHDAwJ.js"),
10499
+ import("./bash-DXbFn1Mw.js"),
10500
+ import("./markdown-qYHfSPvL.js"),
10501
+ import("./yaml-CoEYOy4X.js"),
10502
+ import("./diff-BbCHXb9k.js")
11090
10503
  ],
11091
10504
  engine: createJavaScriptRegexEngine()
11092
10505
  });
11093
10506
  return highlighterPromise;
11094
10507
  };
11095
- // src/code/CodeBlock.vue?vue&type=script&setup=true&lang.ts
11096
- var _hoisted_1$7 = { class: "pw-code" };
11097
- var _hoisted_2$7 = {
11098
- key: 0,
11099
- class: "pw-code__hint"
11100
- };
11101
- var _hoisted_3$7 = {
11102
- key: 1,
11103
- class: "pw-code__error"
11104
- };
11105
- var _hoisted_4$7 = ["innerHTML"];
11106
- // src/code/CodeBlock.vue
11107
- var CodeBlock_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
11108
- __name: "CodeBlock",
11109
- props: {
11110
- code: {},
11111
- lang: { default: "vue" }
11112
- },
11113
- setup(__props) {
11114
- const props = __props;
11115
- const html = ref("");
11116
- const state = ref("loading");
11117
- const error = ref("");
11118
- watch(() => [props.code, props.lang], async ([code, lang]) => {
11119
- state.value = "loading";
11120
- try {
11121
- const highlighter = await getHighlighter();
11122
- html.value = highlighter.codeToHtml(code, {
11123
- lang,
11124
- themes: {
11125
- light: PW_THEME_LIGHT,
11126
- dark: PW_THEME_DARK
11127
- },
11128
- defaultColor: false
11129
- });
11130
- state.value = "ready";
11131
- } catch (err) {
11132
- error.value = err instanceof Error ? err.message : String(err);
11133
- state.value = "error";
11134
- }
11135
- }, { immediate: true });
11136
- return (_ctx, _cache) => {
11137
- return openBlock(), createElementBlock("div", _hoisted_1$7, [state.value === "loading" ? (openBlock(), createElementBlock("div", _hoisted_2$7, "高亮中…")) : state.value === "error" ? (openBlock(), createElementBlock("pre", _hoisted_3$7, toDisplayString(error.value), 1)) : (openBlock(), createElementBlock("div", {
11138
- key: 2,
11139
- class: "pw-code__body",
11140
- innerHTML: html.value
11141
- }, null, 8, _hoisted_4$7))]);
11142
- };
11143
- }
11144
- }), [["__scopeId", "data-v-feddef62"]]);
11145
- // src/app/PlaygroundParamsPanel.vue?vue&type=script&setup=true&lang.ts
11146
- var _hoisted_1$6 = { class: "pw-params" };
11147
- var _hoisted_2$6 = { class: "pw-params__head" };
11148
- var _hoisted_3$6 = ["disabled"];
11149
- var _hoisted_4$6 = ["disabled"];
11150
- var _hoisted_5$6 = { class: "pw-params__body" };
11151
- var _hoisted_6$4 = {
11152
- key: 0,
11153
- class: "pw-params__slots"
11154
- };
11155
- var _hoisted_7$4 = {
11156
- key: 0,
11157
- class: "pw-slot__head"
10508
+ // ../../node_modules/.pnpm/@lucide+vue@1.66.0_vue@3.5.44_typescript@5.9.3_/node_modules/@lucide/vue/dist/esm/shared/src/build/defaultAttributes.mjs
10509
+ /**
10510
+ * @license @lucide/vue v1.66.0 - ISC
10511
+ *
10512
+ * This source code is licensed under the ISC license.
10513
+ * See the LICENSE file in the root directory of this source tree.
10514
+ */
10515
+ var defaultAttributes = {
10516
+ xmlns: "http://www.w3.org/2000/svg",
10517
+ width: 24,
10518
+ height: 24,
10519
+ viewBox: "0 0 24 24",
10520
+ fill: "none",
10521
+ stroke: "currentColor",
10522
+ "stroke-width": 2,
10523
+ "stroke-linecap": "round",
10524
+ "stroke-linejoin": "round"
11158
10525
  };
11159
- var _hoisted_8$2 = { class: "pw-slot__name" };
11160
- var _hoisted_9$1 = { class: "pw-form" };
11161
- var _hoisted_10$1 = ["title"];
11162
- var _hoisted_11 = ["value", "onChange"];
11163
- var _hoisted_12 = ["value"];
11164
- var _hoisted_13 = {
11165
- key: 0,
11166
- class: "pw-params__hint"
10526
+ // ../../node_modules/.pnpm/@lucide+vue@1.66.0_vue@3.5.44_typescript@5.9.3_/node_modules/@lucide/vue/dist/esm/shared/src/utils/mergeClasses.mjs
10527
+ /**
10528
+ * @license @lucide/vue v1.66.0 - ISC
10529
+ *
10530
+ * This source code is licensed under the ISC license.
10531
+ * See the LICENSE file in the root directory of this source tree.
10532
+ */
10533
+ var mergeClasses = (...classes) => classes.filter((className, index, array) => {
10534
+ return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index;
10535
+ }).join(" ").trim();
10536
+ // ../../node_modules/.pnpm/@lucide+vue@1.66.0_vue@3.5.44_typescript@5.9.3_/node_modules/@lucide/vue/dist/esm/shared/src/build/buildLucideIconNode.mjs
10537
+ /**
10538
+ * @license @lucide/vue v1.66.0 - ISC
10539
+ *
10540
+ * This source code is licensed under the ISC license.
10541
+ * See the LICENSE file in the root directory of this source tree.
10542
+ */
10543
+ function isDefined(value) {
10544
+ return value !== null && value !== void 0;
10545
+ }
10546
+ function buildLucideIconNode(icon, params = {}) {
10547
+ const attributeNames = params.attributeNames ?? {};
10548
+ const getAttributeName = (attributeName) => attributeNames[attributeName] ?? attributeName;
10549
+ const viewBoxWidth = icon.size ?? icon.width ?? defaultAttributes["width"];
10550
+ const viewBoxHeight = icon.size ?? icon.height ?? defaultAttributes["height"];
10551
+ const aliasClassNames = icon.aliases?.filter((alias) => typeof alias === "string" && alias.trim() !== "").map((alias) => `lucide-${alias}`) ?? [];
10552
+ const iconClassNames = [...icon.name ? [`lucide-${icon.name}`] : [], ...aliasClassNames];
10553
+ const classNamesFromClassName = params.className?.split(" ").filter(Boolean) ?? [];
10554
+ const className = params.includeDefaultClasses === false ? mergeClasses(...classNamesFromClassName) : mergeClasses("lucide", ...iconClassNames, ...classNamesFromClassName);
10555
+ const calculatedStrokeWidth = params.absoluteStrokeWidth ? Number(params.strokeWidth ?? defaultAttributes["stroke-width"]) * Number(icon.size ?? icon.width ?? defaultAttributes["width"]) / Number(params.size ?? params.width ?? defaultAttributes["width"]) : params.strokeWidth ?? defaultAttributes["stroke-width"];
10556
+ return [
10557
+ "svg",
10558
+ {
10559
+ ...Object.entries(defaultAttributes).reduce((attrs, [attrName, value]) => {
10560
+ attrs[getAttributeName(attrName)] = value;
10561
+ return attrs;
10562
+ }, {}),
10563
+ ..."color" in params && params.color && { [getAttributeName("stroke")]: params.color },
10564
+ ..."size" in params && isDefined(params.size) && {
10565
+ [getAttributeName("width")]: params.size,
10566
+ [getAttributeName("height")]: params.size
10567
+ },
10568
+ ..."width" in params && isDefined(params.width) && { [getAttributeName("width")]: params.width },
10569
+ ..."height" in params && isDefined(params.height) && { [getAttributeName("height")]: params.height },
10570
+ [getAttributeName("stroke-width")]: calculatedStrokeWidth,
10571
+ ...className && { [getAttributeName("class")]: className },
10572
+ [getAttributeName("viewBox")]: `0 0 ${viewBoxWidth} ${viewBoxHeight}`,
10573
+ ...params.hasA11yProp === false ? { [getAttributeName("aria-hidden")]: "true" } : {},
10574
+ ..."attributes" in params && params.attributes
10575
+ },
10576
+ icon.node.map((child) => {
10577
+ const [name, attrs, children] = child;
10578
+ const nextAttrs = params.nonScalingStroke ? {
10579
+ [getAttributeName("vector-effect")]: "non-scaling-stroke",
10580
+ ...attrs
10581
+ } : attrs;
10582
+ return children ? [
10583
+ name,
10584
+ nextAttrs,
10585
+ children
10586
+ ] : [name, nextAttrs];
10587
+ })
10588
+ ];
10589
+ }
10590
+ // ../../node_modules/.pnpm/@lucide+vue@1.66.0_vue@3.5.44_typescript@5.9.3_/node_modules/@lucide/vue/dist/esm/shared/src/utils/hasA11yProp.mjs
10591
+ /**
10592
+ * @license @lucide/vue v1.66.0 - ISC
10593
+ *
10594
+ * This source code is licensed under the ISC license.
10595
+ * See the LICENSE file in the root directory of this source tree.
10596
+ */
10597
+ var hasA11yProp = (props) => {
10598
+ for (const prop in props) if (prop.startsWith("aria-") || prop === "role" || prop === "title") return true;
10599
+ return false;
11167
10600
  };
11168
- var _hoisted_14 = {
11169
- key: 0,
11170
- class: "pw-params__hint pw-params__hint--empty"
10601
+ // ../../node_modules/.pnpm/@lucide+vue@1.66.0_vue@3.5.44_typescript@5.9.3_/node_modules/@lucide/vue/dist/esm/shared/src/utils/isEmptyString.mjs
10602
+ /**
10603
+ * @license @lucide/vue v1.66.0 - ISC
10604
+ *
10605
+ * This source code is licensed under the ISC license.
10606
+ * See the LICENSE file in the root directory of this source tree.
10607
+ */
10608
+ var isEmptyString = (value) => value === "";
10609
+ // ../../node_modules/.pnpm/@lucide+vue@1.66.0_vue@3.5.44_typescript@5.9.3_/node_modules/@lucide/vue/dist/esm/shared/src/utils/toKebabCase.mjs
10610
+ /**
10611
+ * @license @lucide/vue v1.66.0 - ISC
10612
+ *
10613
+ * This source code is licensed under the ISC license.
10614
+ * See the LICENSE file in the root directory of this source tree.
10615
+ */
10616
+ var toKebabCase = (string) => string?.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
10617
+ // ../../node_modules/.pnpm/@lucide+vue@1.66.0_vue@3.5.44_typescript@5.9.3_/node_modules/@lucide/vue/dist/esm/context.mjs
10618
+ /**
10619
+ * @license @lucide/vue v1.66.0 - ISC
10620
+ *
10621
+ * This source code is licensed under the ISC license.
10622
+ * See the LICENSE file in the root directory of this source tree.
10623
+ */
10624
+ var LUCIDE_CONTEXT = /* @__PURE__ */ Symbol("lucide-icons");
10625
+ function useLucideProps() {
10626
+ return inject(LUCIDE_CONTEXT, {});
10627
+ }
10628
+ // ../../node_modules/.pnpm/@lucide+vue@1.66.0_vue@3.5.44_typescript@5.9.3_/node_modules/@lucide/vue/dist/esm/Icon.mjs
10629
+ /**
10630
+ * @license @lucide/vue v1.66.0 - ISC
10631
+ *
10632
+ * This source code is licensed under the ISC license.
10633
+ * See the LICENSE file in the root directory of this source tree.
10634
+ */
10635
+ var Icon = ({ name, iconNode, "icon-node": iconNodeKebabCase, icon = {
10636
+ name: name && toKebabCase(name),
10637
+ node: iconNode ?? iconNodeKebabCase ?? [],
10638
+ size: 24,
10639
+ aliases: []
10640
+ }, absoluteStrokeWidth, "absolute-stroke-width": absoluteStrokeWidthKebabCase, nonScalingStroke, "non-scaling-stroke": nonScalingStrokeKebabCase, strokeWidth, "stroke-width": strokeWidthKebabCase, size, width = size, height = size, color, ...props }, { slots }) => {
10641
+ const { size: contextSize, color: contextColor, strokeWidth: contextStrokeWidth = 2, absoluteStrokeWidth: contextAbsoluteStrokeWidth = false, nonScalingStroke: contextNonScalingStroke = false, class: contextClass = "" } = useLucideProps();
10642
+ const isAbsoluteStrokeWidth = isEmptyString(absoluteStrokeWidth) || isEmptyString(absoluteStrokeWidthKebabCase) || absoluteStrokeWidth === true || absoluteStrokeWidthKebabCase === true || contextAbsoluteStrokeWidth === true;
10643
+ const isNonScalingStroke = isEmptyString(nonScalingStroke) || isEmptyString(nonScalingStrokeKebabCase) || nonScalingStroke === true || nonScalingStrokeKebabCase === true || contextNonScalingStroke === true;
10644
+ delete props.class;
10645
+ const defaultSlot = slots.default?.();
10646
+ const [, svgAttributes, builtIconNode = []] = buildLucideIconNode(icon, {
10647
+ color: color ?? contextColor,
10648
+ width: width ?? size ?? contextSize,
10649
+ height: height ?? size ?? contextSize,
10650
+ strokeWidth: strokeWidth ?? strokeWidthKebabCase ?? contextStrokeWidth,
10651
+ absoluteStrokeWidth: isAbsoluteStrokeWidth,
10652
+ nonScalingStroke: isNonScalingStroke,
10653
+ className: contextClass,
10654
+ hasA11yProp: defaultSlot != null && defaultSlot.length > 0 || hasA11yProp(props),
10655
+ attributes: props
10656
+ });
10657
+ return h("svg", svgAttributes, [...builtIconNode.map(([tag, attrs]) => h(tag, attrs)), ...defaultSlot ?? []]);
11171
10658
  };
11172
- var _hoisted_15 = {
11173
- key: 1,
11174
- class: "pw-params__slots"
10659
+ // ../../node_modules/.pnpm/@lucide+vue@1.66.0_vue@3.5.44_typescript@5.9.3_/node_modules/@lucide/vue/dist/esm/createLucideIcon.mjs
10660
+ /**
10661
+ * @license @lucide/vue v1.66.0 - ISC
10662
+ *
10663
+ * This source code is licensed under the ISC license.
10664
+ * See the LICENSE file in the root directory of this source tree.
10665
+ */
10666
+ function createLucideIcon(iconDataOrName, iconNode = []) {
10667
+ const icon = typeof iconDataOrName === "string" ? {
10668
+ name: iconDataOrName,
10669
+ node: iconNode
10670
+ } : iconDataOrName;
10671
+ return (props, { slots }) => h(Icon, {
10672
+ ...props,
10673
+ icon
10674
+ }, slots.default ? { default: slots.default } : void 0);
10675
+ }
10676
+ // src/components/toast.ts
10677
+ var toastState = reactive([]);
10678
+ var seed = 0;
10679
+ /** 轻提示。用法:toast('已复制'), toast('保存失败', 'error') */
10680
+ var toast = (text, type = "info", duration = 2400) => {
10681
+ const id = ++seed;
10682
+ toastState.push({
10683
+ id,
10684
+ text,
10685
+ type
10686
+ });
10687
+ window.setTimeout(() => {
10688
+ const index = toastState.findIndex((item) => item.id === id);
10689
+ if (index > -1) toastState.splice(index, 1);
10690
+ }, duration);
11175
10691
  };
11176
- var _hoisted_16 = {
11177
- key: 0,
11178
- class: "pw-slot__head"
10692
+ // src/payload/context.ts
10693
+ /** 当前场景标识:由 PlaygroundSceneSection 提供,`useSceneArgs` / `useSceneOutput` 用来标记归属 */
10694
+ var sceneContextKey = Symbol("rinova-playground:scene");
10695
+ var provideSceneContext = (name) => provide(sceneContextKey, name);
10696
+ /** 不在场景里调用(例如自己在别处挂组件)时返回空串 */
10697
+ var useSceneContext = () => inject(sceneContextKey, "");
10698
+ // src/payload/args.ts
10699
+ /** setup 期递增,保证面板里槽位顺序与代码里声明的顺序一致 */
10700
+ var seq$2 = 0;
10701
+ /** 当前场景挂载的全部输入槽位(同一时刻只有一个场景挂载) */
10702
+ var currentArgsSlots = shallowRef([]);
10703
+ /** 兼容旧接口:第一个槽位 */
10704
+ var currentArgs = computed(() => currentArgsSlots.value[0] ?? null);
10705
+ var sortSlots$1 = (list) => [...list].sort((a, b) => a.order - b.order);
10706
+ /**
10707
+ * 在场景的 `<script setup>` 里声明可变输入,返回响应式对象:
10708
+ * 面板改表单 → 这里同步变化 → 组件跟着重渲染。纯浏览器能力,生产环境同样可用。
10709
+ *
10710
+ * 一个场景里有多个 demo 时,各自调用一次并传 `slot` 区分:
10711
+ * ```ts
10712
+ * const primary = useSceneArgs({ size: 'md' }, { slot: '主按钮' })
10713
+ * const ghost = useSceneArgs({ size: 'sm' }, { slot: '次按钮' })
10714
+ * ```
10715
+ */
10716
+ var useSceneArgs = (defaults, options = {}) => {
10717
+ const values = reactive({ ...defaults });
10718
+ const slot = {
10719
+ order: seq$2++,
10720
+ sceneId: useSceneContext(),
10721
+ key: options.slot ?? "default",
10722
+ label: options.slot ?? "",
10723
+ values,
10724
+ defaults: { ...defaults },
10725
+ options
10726
+ };
10727
+ onMounted(() => {
10728
+ currentArgsSlots.value = sortSlots$1([...currentArgsSlots.value, slot]);
10729
+ });
10730
+ onBeforeUnmount(() => {
10731
+ currentArgsSlots.value = currentArgsSlots.value.filter((item) => item !== slot);
10732
+ });
10733
+ return values;
11179
10734
  };
11180
- var _hoisted_17 = { class: "pw-slot__name" };
11181
- var _hoisted_18 = {
11182
- key: 0,
11183
- class: "pw-params__hint pw-params__hint--empty"
10735
+ // src/payload/output.ts
10736
+ /** setup 期递增,保证面板里顺序与声明顺序一致 */
10737
+ var seq$1 = 0;
10738
+ /** 当前场景挂载的全部输出槽位;由面板轮询调用,纯前端实现 */
10739
+ var currentOutputSlots = shallowRef([]);
10740
+ /** 兼容旧接口:第一个槽位 */
10741
+ var currentOutput = computed(() => currentOutputSlots.value[0]?.getter ?? null);
10742
+ var sortSlots = (list) => [...list].sort((a, b) => a.order - b.order);
10743
+ /**
10744
+ * 把场景里的响应式状态暴露成「输出」快照。
10745
+ * 一个场景多个 demo 时传 `slot` 区分,例如 `useSceneOutput(() => ({ ... }), '主按钮')`。
10746
+ */
10747
+ var useSceneOutput = (getter, slot) => {
10748
+ const entry = {
10749
+ order: seq$1++,
10750
+ sceneId: useSceneContext(),
10751
+ key: slot ?? "default",
10752
+ label: slot ?? "",
10753
+ getter
10754
+ };
10755
+ onMounted(() => {
10756
+ currentOutputSlots.value = sortSlots([...currentOutputSlots.value, entry]);
10757
+ });
10758
+ onBeforeUnmount(() => {
10759
+ currentOutputSlots.value = currentOutputSlots.value.filter((item) => item !== entry);
10760
+ });
11184
10761
  };
11185
- // src/app/PlaygroundParamsPanel.vue
11186
- var PlaygroundParamsPanel_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
11187
- __name: "PlaygroundParamsPanel",
11188
- props: { theme: {} },
11189
- setup(__props) {
11190
- const tab = ref("args");
11191
- const snapshots = ref([]);
11192
- let timer = null;
11193
- const argsSlots = computed(() => currentArgsSlots.value);
11194
- const outputSlots = computed(() => currentOutputSlots.value);
11195
- const hasArgs = computed(() => argsSlots.value.length > 0);
11196
- const hasOutput = computed(() => outputSlots.value.length > 0);
11197
- /** 多槽位(一个场景多个 demo)时,每块都加小标题 */
11198
- const multiSlot = computed(() => argsSlots.value.length > 1 || outputSlots.value.length > 1);
11199
- const activeTab = computed(() => {
11200
- if (tab.value === "args" && hasArgs.value) return "args";
11201
- if (tab.value === "output" && hasOutput.value) return "output";
11202
- return hasArgs.value ? "args" : "output";
11203
- });
11204
- const fieldsOf = (binding) => Object.entries(binding.values).map(([key, value]) => ({
11205
- key,
11206
- value,
11207
- label: binding.options.labels?.[key] ?? key,
11208
- kind: typeof value === "boolean" ? "boolean" : typeof value === "number" ? "number" : "string",
11209
- options: binding.options.options?.[key]
11210
- }));
11211
- const setValue = (binding, key, value) => {
11212
- binding.values[key] = value;
11213
- };
11214
- const setString = (binding, key, raw) => setValue(binding, key, raw);
11215
- const setNumber = (binding, key, raw) => {
11216
- const parsed = Number(raw);
11217
- setValue(binding, key, Number.isFinite(parsed) ? parsed : 0);
11218
- };
11219
- const resetSlot = (binding) => {
11220
- for (const [key, value] of Object.entries(binding.defaults)) binding.values[key] = value;
11221
- };
11222
- const resetAll = () => {
11223
- argsSlots.value.forEach(resetSlot);
11224
- };
11225
- const readOutput = () => {
11226
- snapshots.value = outputSlots.value.map((binding) => {
11227
- try {
11228
- const value = binding.getter();
11229
- return {
11230
- label: binding.label || binding.key,
11231
- text: JSON.stringify(value, null, 2) ?? String(value)
11232
- };
11233
- } catch (err) {
11234
- return {
11235
- label: binding.label || binding.key,
11236
- text: err instanceof Error ? err.message : String(err)
11237
- };
11238
- }
11239
- });
11240
- };
11241
- const startPolling = () => {
11242
- readOutput();
11243
- timer = window.setInterval(readOutput, 400);
11244
- };
11245
- watch(activeTab, (value) => {
11246
- if (value === "output") readOutput();
11247
- });
11248
- startPolling();
11249
- onBeforeUnmount(() => {
11250
- if (timer !== null) window.clearInterval(timer);
11251
- });
11252
- return (_ctx, _cache) => {
11253
- return openBlock(), createElementBlock("aside", _hoisted_1$6, [createElementVNode("header", _hoisted_2$6, [
11254
- createElementVNode("button", {
11255
- type: "button",
11256
- class: normalizeClass(["pw-params__tab", { "is-active": activeTab.value === "args" }]),
11257
- disabled: !hasArgs.value,
11258
- onClick: _cache[0] || (_cache[0] = ($event) => tab.value = "args")
11259
- }, " 入参 ", 10, _hoisted_3$6),
11260
- createElementVNode("button", {
11261
- type: "button",
11262
- class: normalizeClass(["pw-params__tab", { "is-active": activeTab.value === "output" }]),
11263
- disabled: !hasOutput.value,
11264
- onClick: _cache[1] || (_cache[1] = ($event) => tab.value = "output")
11265
- }, " 出参 ", 10, _hoisted_4$6),
11266
- _cache[2] || (_cache[2] = createElementVNode("span", { class: "pw-params__spacer" }, null, -1)),
11267
- activeTab.value === "args" && hasArgs.value ? (openBlock(), createBlock(PwButton_default, {
11268
- key: 0,
11269
- size: "sm",
11270
- variant: "text",
11271
- title: "恢复默认值",
11272
- onClick: resetAll
11273
- }, {
11274
- icon: withCtx(() => [createVNode(unref(RotateCcw), { size: 13 })]),
11275
- _: 1
11276
- })) : createCommentVNode("", true)
11277
- ]), createElementVNode("div", _hoisted_5$6, [activeTab.value === "args" ? (openBlock(), createElementBlock("div", _hoisted_6$4, [(openBlock(true), createElementBlock(Fragment, null, renderList(argsSlots.value, (slot) => {
11278
- return openBlock(), createElementBlock("section", {
11279
- key: `${slot.key}:${slot.label}`,
11280
- class: "pw-slot"
11281
- }, [multiSlot.value ? (openBlock(), createElementBlock("header", _hoisted_7$4, [createElementVNode("span", _hoisted_8$2, toDisplayString(slot.label || slot.key), 1), createVNode(PwButton_default, {
11282
- size: "sm",
11283
- variant: "text",
11284
- title: "只恢复这一块",
11285
- onClick: ($event) => resetSlot(slot)
11286
- }, {
11287
- icon: withCtx(() => [createVNode(unref(RotateCcw), { size: 12 })]),
11288
- _: 1
11289
- }, 8, ["onClick"])])) : createCommentVNode("", true), createElementVNode("div", _hoisted_9$1, [(openBlock(true), createElementBlock(Fragment, null, renderList(fieldsOf(slot), (field) => {
11290
- return openBlock(), createElementBlock("div", {
11291
- key: field.key,
11292
- class: "pw-form__row"
11293
- }, [createElementVNode("label", {
11294
- class: "pw-form__label",
11295
- title: field.key
11296
- }, toDisplayString(field.label), 9, _hoisted_10$1), field.kind === "boolean" ? (openBlock(), createBlock(PwSwitch_default, {
11297
- key: 0,
11298
- "model-value": field.value === true,
11299
- "onUpdate:modelValue": ($event) => setValue(slot, field.key, $event)
11300
- }, null, 8, ["model-value", "onUpdate:modelValue"])) : field.options ? (openBlock(), createElementBlock("select", {
11301
- key: 1,
11302
- class: "pw-form__select",
11303
- value: String(field.value),
11304
- onChange: ($event) => setString(slot, field.key, $event.target.value)
11305
- }, [(openBlock(true), createElementBlock(Fragment, null, renderList(field.options, (option) => {
11306
- return openBlock(), createElementBlock("option", {
11307
- key: String(option),
11308
- value: String(option)
11309
- }, toDisplayString(option), 9, _hoisted_12);
11310
- }), 128))], 40, _hoisted_11)) : (openBlock(), createBlock(PwInput_default, {
11311
- key: 2,
11312
- size: "sm",
11313
- type: field.kind === "number" ? "number" : "text",
11314
- "model-value": String(field.value ?? ""),
11315
- "onUpdate:modelValue": ($event) => field.kind === "number" ? setNumber(slot, field.key, $event) : setString(slot, field.key, $event)
11316
- }, null, 8, [
11317
- "type",
11318
- "model-value",
11319
- "onUpdate:modelValue"
11320
- ]))]);
11321
- }), 128)), !fieldsOf(slot).length ? (openBlock(), createElementBlock("p", _hoisted_13, "这一块没有声明入参")) : createCommentVNode("", true)])]);
11322
- }), 128)), !argsSlots.value.length ? (openBlock(), createElementBlock("p", _hoisted_14, " 该场景没有声明入参 ")) : createCommentVNode("", true)])) : (openBlock(), createElementBlock("div", _hoisted_15, [(openBlock(true), createElementBlock(Fragment, null, renderList(snapshots.value, (item) => {
11323
- return openBlock(), createElementBlock("section", {
11324
- key: item.label,
11325
- class: "pw-slot pw-slot--output"
11326
- }, [multiSlot.value ? (openBlock(), createElementBlock("header", _hoisted_16, [createElementVNode("span", _hoisted_17, toDisplayString(item.label), 1)])) : createCommentVNode("", true), createVNode(CodeBlock_default, {
11327
- code: item.text,
11328
- lang: "json"
11329
- }, null, 8, ["code"])]);
11330
- }), 128)), !snapshots.value.length ? (openBlock(), createElementBlock("p", _hoisted_18, "(无数据)")) : createCommentVNode("", true)]))])]);
11331
- };
11332
- }
11333
- }), [["__scopeId", "data-v-582d049e"]]);
11334
- // src/app/PlaygroundGroupIndex.vue?vue&type=script&setup=true&lang.ts
11335
- var _hoisted_1$5 = { class: "pw-group-index" };
11336
- var _hoisted_2$5 = { class: "pw-group-index__head" };
11337
- var _hoisted_3$5 = { class: "pw-group-index__title" };
11338
- var _hoisted_4$5 = { class: "pw-group-index__count" };
11339
- var _hoisted_5$5 = { class: "pw-group-index__list" };
11340
- var _hoisted_6$3 = ["onClick"];
11341
- var _hoisted_7$3 = {
11342
- key: 0,
11343
- class: "pw-group-index__desc"
10762
+ // src/plugin.ts
10763
+ /**
10764
+ * 声明一个 playground 插件(只做类型收窄,没有运行时逻辑)。
10765
+ *
10766
+ * ```ts
10767
+ * export default [
10768
+ * definePlaygroundPlugin({ name: 'auth', async setup(ctx) { return { user } } }),
10769
+ * ]
10770
+ * ```
10771
+ */
10772
+ var definePlaygroundPlugin = (plugin) => plugin;
10773
+ var headerSlots = shallowRef([]);
10774
+ var footerSlots = shallowRef([]);
10775
+ var wrapperEntries = shallowRef([]);
10776
+ var panelEntries = shallowRef([]);
10777
+ var openPanelId = shallowRef("");
10778
+ var envValues = shallowRef({});
10779
+ /** 插件 setup 的返回值,按插件名存 */
10780
+ var apis = /* @__PURE__ */ new Map();
10781
+ var pluginHeaderSlots = headerSlots;
10782
+ var pluginFooterSlots = footerSlots;
10783
+ var pluginWrapperEntries = wrapperEntries;
10784
+ var pluginPanelEntries = panelEntries;
10785
+ var pluginOpenPanelId = openPanelId;
10786
+ var sortEntries = (list) => [...list].sort((a, b) => a.order - b.order || a.key.localeCompare(b.key));
10787
+ var closePlaygroundPanel = () => {
10788
+ openPanelId.value = "";
11344
10789
  };
11345
- var _hoisted_8$1 = { class: "pw-group-index__id" };
11346
- // src/app/PlaygroundGroupIndex.vue
11347
- var PlaygroundGroupIndex_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
11348
- __name: "PlaygroundGroupIndex",
11349
- props: {
11350
- group: {},
11351
- items: {}
11352
- },
11353
- emits: ["select"],
11354
- setup(__props) {
11355
- /**
11356
- * 分组落地页:由 `groupIndex: true` 时框架合成的条目使用。
11357
- * 没有源文件,只是把该组其它场景列出来。
11358
- */
11359
- return (_ctx, _cache) => {
11360
- return openBlock(), createElementBlock("section", _hoisted_1$5, [createElementVNode("header", _hoisted_2$5, [createElementVNode("h2", _hoisted_3$5, toDisplayString(__props.group), 1), createElementVNode("span", _hoisted_4$5, toDisplayString(__props.items.length) + " 个场景", 1)]), createElementVNode("ul", _hoisted_5$5, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.items, (item) => {
11361
- return openBlock(), createElementBlock("li", {
11362
- key: item.id,
11363
- class: "pw-group-index__item"
11364
- }, [
11365
- createElementVNode("button", {
11366
- type: "button",
11367
- class: "pw-group-index__link",
11368
- onClick: ($event) => _ctx.$emit("select", item.id)
11369
- }, toDisplayString(item.title), 9, _hoisted_6$3),
11370
- item.description ? (openBlock(), createElementBlock("p", _hoisted_7$3, toDisplayString(item.description), 1)) : createCommentVNode("", true),
11371
- createElementVNode("code", _hoisted_8$1, toDisplayString(item.id), 1)
11372
- ]);
11373
- }), 128))])]);
11374
- };
11375
- }
11376
- }), [["__scopeId", "data-v-97e3a4f9"]]);
11377
- // src/app/PlaygroundSidebar.vue?vue&type=script&setup=true&lang.ts
11378
- var _hoisted_1$4 = { class: "pw-sidebar" };
11379
- var _hoisted_2$4 = { class: "pw-sidebar__brand" };
11380
- var _hoisted_3$4 = { class: "pw-sidebar__title" };
11381
- var _hoisted_4$4 = { class: "pw-sidebar__search" };
11382
- var _hoisted_5$4 = { class: "pw-sidebar__nav" };
11383
- var _hoisted_6$2 = { class: "pw-nav-group__title" };
11384
- var _hoisted_7$2 = ["onClick"];
11385
- var _hoisted_8 = ["onClick"];
11386
- var _hoisted_9 = {
11387
- key: 0,
11388
- class: "pw-sidebar__empty"
10790
+ var openPlaygroundPanel = (id) => {
10791
+ openPanelId.value = id;
11389
10792
  };
11390
- var _hoisted_10 = { class: "pw-sidebar__footer" };
11391
- // src/app/PlaygroundSidebar.vue
11392
- var PlaygroundSidebar_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
11393
- __name: "PlaygroundSidebar",
11394
- props: {
11395
- title: {},
11396
- groups: {},
11397
- activeId: {},
11398
- sceneCount: {}
11399
- },
11400
- emits: ["select"],
11401
- setup(__props, { expose: __expose }) {
11402
- const props = __props;
11403
- const query = ref("");
11404
- const inputRef = ref(null);
11405
- /** 分组头点击聚焦该组的合成落地页;没有落地页时返回 null */
11406
- const groupIndexId = (group) => group.items.find((item) => item.kind === "group-index")?.id ?? null;
11407
- const focusSearch = () => {
11408
- inputRef.value?.focus();
11409
- };
11410
- __expose({ focusSearch });
11411
- const filteredGroups = computed(() => {
11412
- const q = query.value.trim().toLowerCase();
11413
- if (!q) return props.groups;
11414
- return props.groups.map((group) => ({
11415
- name: group.name,
11416
- items: group.items.filter((item) => item.title.toLowerCase().includes(q) || item.id.toLowerCase().includes(q))
11417
- })).filter((group) => group.items.length > 0);
11418
- });
11419
- return (_ctx, _cache) => {
11420
- return openBlock(), createElementBlock("aside", _hoisted_1$4, [
11421
- createElementVNode("div", _hoisted_2$4, [_cache[1] || (_cache[1] = createElementVNode("span", {
11422
- class: "pw-sidebar__logo",
11423
- "aria-hidden": "true"
11424
- }, null, -1)), createElementVNode("span", _hoisted_3$4, toDisplayString(__props.title), 1)]),
11425
- createElementVNode("div", _hoisted_4$4, [createVNode(PwInput_default, {
11426
- ref_key: "inputRef",
11427
- ref: inputRef,
11428
- modelValue: query.value,
11429
- "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => query.value = $event),
11430
- size: "sm",
11431
- placeholder: "搜索场景"
11432
- }, {
11433
- prefix: withCtx(() => [createVNode(unref(Search), {
11434
- size: 13,
11435
- class: "pw-sidebar__search-icon"
11436
- })]),
11437
- suffix: withCtx(() => [..._cache[2] || (_cache[2] = [createElementVNode("kbd", { class: "pw-sidebar__kbd" }, "⌘K", -1)])]),
11438
- _: 1
11439
- }, 8, ["modelValue"])]),
11440
- createElementVNode("nav", _hoisted_5$4, [(openBlock(true), createElementBlock(Fragment, null, renderList(filteredGroups.value, (group) => {
11441
- return openBlock(), createElementBlock("section", {
11442
- key: group.name,
11443
- class: "pw-nav-group"
11444
- }, [createElementVNode("div", _hoisted_6$2, [groupIndexId(group) ? (openBlock(), createElementBlock("button", {
11445
- key: 0,
11446
- type: "button",
11447
- class: normalizeClass(["pw-nav-group__title-btn", { "is-active": groupIndexId(group) === __props.activeId }]),
11448
- onClick: ($event) => _ctx.$emit("select", groupIndexId(group))
11449
- }, toDisplayString(group.name), 11, _hoisted_7$2)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode(toDisplayString(group.name), 1)], 64))]), (openBlock(true), createElementBlock(Fragment, null, renderList(group.items, (item) => {
11450
- return openBlock(), createElementBlock("button", {
11451
- key: item.id,
11452
- type: "button",
11453
- class: normalizeClass(["pw-nav-item", { "is-active": item.id === __props.activeId }]),
11454
- onClick: ($event) => _ctx.$emit("select", item.id)
11455
- }, toDisplayString(item.title), 11, _hoisted_8);
11456
- }), 128))]);
11457
- }), 128)), !filteredGroups.value.length ? (openBlock(), createElementBlock("p", _hoisted_9, "没有匹配的场景")) : createCommentVNode("", true)]),
11458
- createElementVNode("footer", _hoisted_10, toDisplayString(__props.sceneCount) + " 个场景", 1)
11459
- ]);
11460
- };
11461
- }
11462
- }), [["__scopeId", "data-v-cda96938"]]);
11463
- // src/code/monaco.ts
11464
- /**
11465
- * Monaco 单例:worker 环境只能设置一次,highlighter 也只注入一次。
11466
- * 所有路径都是懒加载,首屏不会碰到编辑器代码。
11467
- */
11468
- var loader = null;
11469
- var PW_MONACO_LANGS = [
11470
- "vue",
11471
- "typescript",
11472
- "javascript",
11473
- "css",
11474
- "html",
11475
- "json",
11476
- "less"
11477
- ];
11478
- /** 不同打包链路下 @shikijs/monaco 可能以 default 形式出现,两种形态都接受 */
11479
- var resolveShikiToMonaco = (mod) => {
11480
- const candidate = mod;
11481
- const inject = candidate.shikiToMonaco ?? candidate.default?.shikiToMonaco;
11482
- if (typeof inject !== "function") throw new Error("@shikijs/monaco 未导出 shikiToMonaco");
11483
- return inject;
10793
+ var togglePlaygroundPanel = (id) => {
10794
+ openPanelId.value = openPanelId.value === id ? "" : id;
11484
10795
  };
11485
- var loadMonaco = () => {
11486
- loader ??= (async () => {
11487
- const [editorWorker, tsWorker, monaco, _contribution, shikiModule] = await Promise.all([
11488
- import("./editor.worker-VDFPHiZj.js"),
11489
- import("./ts.worker-CpQm_d0w.js"),
11490
- import("./editor.api-YVDhnHI-.js").then((n) => n.s),
11491
- import("./monaco.contribution-CaO2YABh.js").then((n) => n.t),
11492
- import("./dist-B0hittbo.js"),
11493
- import("@rinova/playground/editor.css")
11494
- ]);
11495
- const EditorWorker = editorWorker.default;
11496
- const TsWorker = tsWorker.default;
11497
- self.MonacoEnvironment = { getWorker: (_workerId, label) => label === "typescript" || label === "javascript" ? new TsWorker() : new EditorWorker() };
11498
- for (const id of PW_MONACO_LANGS) monaco.languages.register({ id });
11499
- resolveShikiToMonaco(shikiModule)(await getHighlighter(), monaco);
11500
- monaco.editor.setTheme(PW_THEME_LIGHT);
11501
- return monaco;
11502
- })();
11503
- return loader;
10796
+ /** 供插件自己的 UI 组件使用(也可以在 ctx.ui 里拿到句柄) */
10797
+ var usePlaygroundUi = () => ({
10798
+ openPanel: openPlaygroundPanel,
10799
+ closePanel: closePlaygroundPanel,
10800
+ togglePanel: togglePlaygroundPanel
10801
+ });
10802
+ /** 场景里读全局变量 + 插件返回值(`globals` 打底,插件按声明顺序覆盖) */
10803
+ var usePlaygroundEnv = () => envValues.value;
10804
+ /** 场景里读单个插件的返回值;插件不存在直接抛错,避免静默 undefined */
10805
+ var usePlaygroundPlugin = (name) => {
10806
+ if (!apis.has(name)) throw new Error(`[rinova-playground] 插件「${name}」未注册或初始化失败。检查 playground.config.ts 的 plugins 与该插件的 name。`);
10807
+ return apis.get(name);
11504
10808
  };
11505
- var applyMonacoTheme = (monaco, theme) => {
11506
- monaco.editor.setTheme(theme === "dark" ? PW_THEME_DARK : PW_THEME_LIGHT);
10809
+ var themeKey = Symbol("rinova-playground:theme");
10810
+ var providePlaygroundTheme = (theme) => {
10811
+ provide(themeKey, theme);
11507
10812
  };
11508
- /** 按扩展名判断 Monaco 语言 */
11509
- var langFromFile = (file) => {
11510
- if (file.endsWith(".ts")) return "typescript";
11511
- if (file.endsWith(".js")) return "javascript";
11512
- if (file.endsWith(".json")) return "json";
11513
- if (file.endsWith(".less")) return "less";
11514
- if (file.endsWith(".css")) return "css";
11515
- if (file.endsWith(".html")) return "html";
11516
- return "vue";
10813
+ /**
10814
+ * 插件 UI 跟随外壳主题。框架不替第三方库切 `dark` class,
10815
+ * 这里只给当前值,怎么用由插件决定。
10816
+ */
10817
+ var usePlaygroundTheme = () => {
10818
+ const injected = inject(themeKey, null);
10819
+ if (injected) return injected;
10820
+ return computed(() => document.documentElement.dataset.pwTheme === "dark" ? "dark" : "light");
11517
10821
  };
11518
- // src/code/CodeEditor.vue
11519
- var CodeEditor_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
11520
- __name: "CodeEditor",
11521
- props: {
11522
- modelValue: {},
11523
- filename: {},
11524
- readOnly: {
11525
- type: Boolean,
11526
- default: true
11527
- },
11528
- theme: { default: "light" }
11529
- },
11530
- emits: ["update:modelValue", "fail"],
11531
- setup(__props, { emit: __emit }) {
11532
- const props = __props;
11533
- const emit = __emit;
11534
- const host = ref();
11535
- let editor = null;
11536
- let monacoRef = null;
11537
- let observer = null;
11538
- let applying = false;
11539
- const options = () => {
11540
- const mono = getComputedStyle(document.documentElement).getPropertyValue("--rp-font-mono").trim();
11541
- return {
11542
- value: props.modelValue,
11543
- language: langFromFile(props.filename),
11544
- theme: props.theme === "dark" ? "vitesse-dark" : "vitesse-light",
11545
- readOnly: props.readOnly,
11546
- domReadOnly: props.readOnly,
11547
- minimap: { enabled: false },
11548
- lineNumbers: "on",
11549
- folding: true,
11550
- scrollBeyondLastLine: false,
11551
- automaticLayout: false,
11552
- fontSize: 12.5,
11553
- lineHeight: 20,
11554
- fontFamily: mono || "ui-monospace, SFMono-Regular, Menlo, monospace",
11555
- padding: {
11556
- top: 12,
11557
- bottom: 16
11558
- },
11559
- renderLineHighlight: "none",
11560
- overviewRulerLanes: 0,
11561
- scrollbar: {
11562
- verticalScrollbarSize: 8,
11563
- horizontalScrollbarSize: 8
11564
- },
11565
- contextmenu: true,
11566
- wordWrap: "off",
11567
- tabSize: 2
11568
- };
11569
- };
11570
- onMounted(async () => {
11571
- try {
11572
- const monaco = await loadMonaco();
11573
- monacoRef = monaco;
11574
- if (!host.value) return;
11575
- applyMonacoTheme(monaco, props.theme);
11576
- editor = monaco.editor.create(host.value, options());
11577
- const instance = editor;
11578
- observer = new ResizeObserver(() => {
11579
- const box = host.value?.getBoundingClientRect();
11580
- if (!box || box.width === 0 || box.height === 0) return;
11581
- instance.layout();
11582
- });
11583
- observer.observe(host.value);
11584
- requestAnimationFrame(() => instance.layout());
11585
- instance.onDidChangeModelContent(() => {
11586
- if (applying) return;
11587
- emit("update:modelValue", instance.getValue());
11588
- });
11589
- } catch (error) {
11590
- const message = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
11591
- console.error("[rinova-playground] Monaco 启动失败,已降级为静态高亮:", message);
11592
- emit("fail", message);
11593
- }
11594
- });
11595
- watch(() => props.modelValue, (value) => {
11596
- if (!editor || editor.getValue() === value) return;
11597
- applying = true;
11598
- editor.setValue(value);
11599
- applying = false;
11600
- });
11601
- watch(() => props.filename, (file) => {
11602
- const model = editor?.getModel();
11603
- if (model && monacoRef) monacoRef.editor.setModelLanguage(model, langFromFile(file));
11604
- });
11605
- watch(() => props.readOnly, (value) => editor?.updateOptions({
11606
- readOnly: value,
11607
- domReadOnly: value
11608
- }));
11609
- watch(() => props.theme, (value) => {
11610
- if (monacoRef) applyMonacoTheme(monacoRef, value);
11611
- });
11612
- onBeforeUnmount(() => {
11613
- observer?.disconnect();
11614
- editor?.getModel()?.dispose();
11615
- editor?.dispose();
11616
- editor = null;
11617
- });
11618
- return (_ctx, _cache) => {
11619
- return openBlock(), createElementBlock("div", {
11620
- ref_key: "host",
11621
- ref: host,
11622
- class: "pw-monaco"
11623
- }, null, 512);
11624
- };
11625
- }
11626
- }), [["__scopeId", "data-v-c45e6fcb"]]);
11627
- // src/app/PlaygroundSourcePanel.vue?vue&type=script&setup=true&lang.ts
11628
- var _hoisted_1$3 = { class: "pw-source" };
11629
- var _hoisted_2$3 = { class: "pw-source__head" };
11630
- var _hoisted_3$3 = { class: "pw-source__tabs" };
11631
- var _hoisted_4$3 = ["title", "onClick"];
11632
- var _hoisted_5$3 = { class: "pw-source__actions" };
11633
- var _hoisted_6$1 = { class: "pw-source__body" };
11634
- var _hoisted_7$1 = {
11635
- key: 0,
11636
- class: "pw-source__hint"
10822
+ var describeError = (error) => error instanceof Error ? error.message : String(error);
10823
+ var pluginError = (plugin, error) => {
10824
+ const next = /* @__PURE__ */ new Error(`[rinova-playground] 插件「${plugin}」初始化失败:${describeError(error)}`);
10825
+ next.name = "PlaygroundPluginError";
10826
+ if (error instanceof Error && error.stack) next.stack = `${next.message}\n${error.stack}`;
10827
+ return next;
11637
10828
  };
11638
- // src/app/PlaygroundSourcePanel.vue
11639
- var PlaygroundSourcePanel_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
11640
- __name: "PlaygroundSourcePanel",
11641
- props: {
11642
- scene: {},
11643
- theme: {}
11644
- },
11645
- emits: ["close"],
11646
- setup(__props) {
11647
- const props = __props;
11648
- const activeIndex = ref(0);
11649
- const text = ref("");
11650
- const loading = ref(true);
11651
- const failed = ref(false);
11652
- const copied = ref(false);
11653
- const cache = /* @__PURE__ */ new Map();
11654
- const viewer = config.codeViewer ?? "monaco";
11655
- const active = computed(() => props.scene.sources[activeIndex.value] ?? props.scene.sources[0]);
11656
- const fileName = (file) => file.split("/").pop() ?? file;
11657
- const load = async (index) => {
11658
- const source = props.scene.sources[index];
11659
- if (!source) return;
11660
- loading.value = true;
11661
- try {
11662
- const content = cache.get(source.rel) ?? await source.raw();
11663
- cache.set(source.rel, content);
11664
- text.value = content;
11665
- } catch (error) {
11666
- toast(`源码读取失败:${error instanceof Error ? error.message : String(error)}`, "error");
11667
- text.value = "";
11668
- } finally {
11669
- loading.value = false;
11670
- }
11671
- };
11672
- watch(() => props.scene, () => {
11673
- activeIndex.value = 0;
11674
- load(0);
11675
- }, { immediate: true });
11676
- const select = (index) => {
11677
- if (index === activeIndex.value) return;
11678
- activeIndex.value = index;
11679
- load(index);
11680
- };
11681
- const copy = async () => {
11682
- try {
11683
- await navigator.clipboard.writeText(text.value);
11684
- copied.value = true;
11685
- toast("已复制源码", "success");
11686
- window.setTimeout(() => copied.value = false, 1500);
11687
- } catch {
11688
- toast("复制失败,请手动选择", "error");
11689
- }
11690
- };
11691
- return (_ctx, _cache) => {
11692
- return openBlock(), createElementBlock("section", _hoisted_1$3, [createElementVNode("header", _hoisted_2$3, [createElementVNode("div", _hoisted_3$3, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.scene.sources, (source, index) => {
11693
- return openBlock(), createElementBlock("button", {
11694
- key: source.rel,
11695
- type: "button",
11696
- class: normalizeClass(["pw-tab", { "is-active": index === activeIndex.value }]),
11697
- title: source.rel,
11698
- onClick: ($event) => select(index)
11699
- }, toDisplayString(fileName(source.rel)), 11, _hoisted_4$3);
11700
- }), 128))]), createElementVNode("div", _hoisted_5$3, [createVNode(PwButton_default, {
11701
- size: "sm",
11702
- variant: "text",
11703
- title: copied.value ? "已复制" : "复制源码",
11704
- onClick: copy
11705
- }, {
11706
- icon: withCtx(() => [copied.value ? (openBlock(), createBlock(unref(Check), {
11707
- key: 0,
11708
- size: 13
11709
- })) : (openBlock(), createBlock(unref(Copy), {
11710
- key: 1,
11711
- size: 13
11712
- }))]),
11713
- _: 1
11714
- }, 8, ["title"]), createVNode(PwButton_default, {
11715
- size: "sm",
11716
- variant: "text",
11717
- title: "关闭(Esc)",
11718
- onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("close"))
11719
- }, {
11720
- icon: withCtx(() => [createVNode(unref(X$2), { size: 13 })]),
11721
- _: 1
11722
- })])]), createElementVNode("div", _hoisted_6$1, [loading.value ? (openBlock(), createElementBlock("span", _hoisted_7$1, "读取源码中…")) : active.value ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [unref(viewer) === "monaco" && !failed.value ? (openBlock(), createBlock(CodeEditor_default, {
11723
- key: 0,
11724
- "model-value": text.value,
11725
- filename: active.value.rel,
11726
- "read-only": "",
11727
- theme: __props.theme,
11728
- onFail: _cache[1] || (_cache[1] = ($event) => failed.value = true)
11729
- }, null, 8, [
11730
- "model-value",
11731
- "filename",
11732
- "theme"
11733
- ])) : (openBlock(), createBlock(CodeBlock_default, {
11734
- key: 1,
11735
- code: text.value,
11736
- lang: unref(langFromFile)(active.value.rel)
11737
- }, null, 8, ["code", "lang"]))], 64)) : createCommentVNode("", true)])]);
11738
- };
10829
+ /**
10830
+ * 依次加载插件模块并串行执行 setup。
10831
+ *
10832
+ * 串行而不是并行:后一个插件经常要读前一个的结果(请求层依赖登录态)。
10833
+ * 全部完成前 `PlaygroundRoot` 不渲染 App,所以场景挂载时环境一定就绪。
10834
+ */
10835
+ var runPlugins = async (options) => {
10836
+ const { app, config, scenes, modules } = options;
10837
+ if (!modules.length) return;
10838
+ const globals = { ...config.globals ?? {} };
10839
+ const merged = { ...globals };
10840
+ const queue = [];
10841
+ for (const load of modules) {
10842
+ let loaded;
10843
+ try {
10844
+ loaded = await load();
10845
+ } catch (error) {
10846
+ throw pluginError("(模块加载)", error);
10847
+ }
10848
+ const value = loaded && typeof loaded === "object" && "default" in loaded ? loaded.default : loaded;
10849
+ for (const item of Array.isArray(value) ? value : [value]) {
10850
+ const plugin = item;
10851
+ if (!plugin || typeof plugin !== "object" || typeof plugin.name !== "string" || !plugin.name) throw new Error("[rinova-playground] 插件模块必须默认导出 definePlaygroundPlugin(...) 或它的数组,且每项都要有 name");
10852
+ queue.push(plugin);
10853
+ }
11739
10854
  }
11740
- }), [["__scopeId", "data-v-16eca20a"]]);
11741
- // src/app/PlaygroundStage.vue?vue&type=script&setup=true&lang.ts
11742
- var _hoisted_1$2 = { class: "pw-stage__frame" };
11743
- var _hoisted_2$2 = {
11744
- key: 0,
11745
- class: "pw-stage__desc"
11746
- };
11747
- var _hoisted_3$2 = { class: "pw-stage__inner" };
11748
- var _hoisted_4$2 = {
11749
- key: 0,
11750
- class: "pw-stage__error"
11751
- };
11752
- var _hoisted_5$2 = {
11753
- key: 2,
11754
- class: "pw-stage__loading"
11755
- };
11756
- // src/app/PlaygroundStage.vue
11757
- var PlaygroundStage_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
11758
- __name: "PlaygroundStage",
11759
- props: {
11760
- scene: {},
11761
- width: {}
11762
- },
11763
- setup(__props) {
11764
- const props = __props;
11765
- const comp = shallowRef(null);
11766
- const error = ref("");
11767
- let token = 0;
11768
- watch(() => props.scene, async (scene) => {
11769
- const current = ++token;
11770
- comp.value = null;
11771
- error.value = "";
11772
- try {
11773
- const mod = await scene.load();
11774
- if (current === token) comp.value = mod.default;
11775
- } catch (err) {
11776
- if (current === token) error.value = err instanceof Error ? err.message : String(err);
11777
- }
11778
- }, { immediate: true });
11779
- return (_ctx, _cache) => {
11780
- return openBlock(), createElementBlock("section", { class: normalizeClass(["pw-stage", `pw-stage--${__props.width}`]) }, [createElementVNode("div", _hoisted_1$2, [__props.scene.description ? (openBlock(), createElementBlock("p", _hoisted_2$2, toDisplayString(__props.scene.description), 1)) : createCommentVNode("", true), createElementVNode("div", _hoisted_3$2, [error.value ? (openBlock(), createElementBlock("p", _hoisted_4$2, [
11781
- _cache[0] || (_cache[0] = createElementVNode("strong", null, "场景加载失败", -1)),
11782
- createElementVNode("code", null, toDisplayString(__props.scene.rel), 1),
11783
- createElementVNode("span", null, toDisplayString(error.value), 1)
11784
- ])) : comp.value ? (openBlock(), createBlock(resolveDynamicComponent(comp.value), { key: __props.scene.id })) : (openBlock(), createElementBlock("span", _hoisted_5$2, "加载中…"))])])], 2);
10855
+ const seen = /* @__PURE__ */ new Set();
10856
+ for (const plugin of queue) {
10857
+ if (seen.has(plugin.name)) throw new Error(`[rinova-playground] 插件名重复:「${plugin.name}」`);
10858
+ seen.add(plugin.name);
10859
+ }
10860
+ const createContext = (plugin) => {
10861
+ const uiEntry = (options_, slot) => {
10862
+ const entry = {
10863
+ key: `${plugin.name}:${slot}:${nextSeq()}`,
10864
+ plugin: plugin.name,
10865
+ component: options_.component,
10866
+ props: options_.props,
10867
+ order: options_.order ?? Number.MAX_SAFE_INTEGER
10868
+ };
10869
+ if (slot === "header") headerSlots.value = sortEntries([...headerSlots.value, entry]);
10870
+ else footerSlots.value = sortEntries([...footerSlots.value, entry]);
11785
10871
  };
11786
- }
11787
- }), [["__scopeId", "data-v-2c6f2a44"]]);
11788
- // src/app/PlaygroundToolbar.vue?vue&type=script&setup=true&lang.ts
11789
- var _hoisted_1$1 = { class: "pw-toolbar" };
11790
- var _hoisted_2$1 = { class: "pw-toolbar__crumb" };
11791
- var _hoisted_3$1 = { class: "pw-toolbar__group" };
11792
- var _hoisted_4$1 = { class: "pw-toolbar__title" };
11793
- var _hoisted_5$1 = { class: "pw-toolbar__actions" };
11794
- var _hoisted_6 = {
11795
- class: "pw-width-group",
11796
- role: "group",
11797
- "aria-label": "预览宽度"
11798
- };
11799
- var _hoisted_7 = ["title", "onClick"];
11800
- // src/app/PlaygroundToolbar.vue
11801
- var PlaygroundToolbar_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
11802
- __name: "PlaygroundToolbar",
11803
- props: {
11804
- group: {},
11805
- title: {},
11806
- showCode: { type: Boolean },
11807
- showPayload: { type: Boolean },
11808
- hasPayload: { type: Boolean },
11809
- width: {},
11810
- theme: {}
11811
- },
11812
- emits: [
11813
- "toggle-code",
11814
- "toggle-payload",
11815
- "update:width",
11816
- "toggle-theme"
11817
- ],
11818
- setup(__props, { emit: __emit }) {
11819
- const emit = __emit;
11820
- const widths = [
11821
- {
11822
- value: "auto",
11823
- icon: Monitor,
11824
- label: "自适应"
11825
- },
11826
- {
11827
- value: "tablet",
11828
- icon: Tablet,
11829
- label: "平板 820px"
10872
+ return {
10873
+ app,
10874
+ config,
10875
+ globals,
10876
+ scenes,
10877
+ get: (name) => apis.get(name),
10878
+ wrap: (component, props) => {
10879
+ wrapperEntries.value = [...wrapperEntries.value, {
10880
+ key: `${plugin.name}:wrap:${nextSeq()}`,
10881
+ plugin: plugin.name,
10882
+ component,
10883
+ props,
10884
+ order: wrapperEntries.value.length
10885
+ }];
11830
10886
  },
11831
- {
11832
- value: "mobile",
11833
- icon: Smartphone,
11834
- label: "手机 420px"
10887
+ ui: {
10888
+ header: (entry) => uiEntry(entry, "header"),
10889
+ sidebarFooter: (entry) => uiEntry(entry, "footer"),
10890
+ panel: (entry) => {
10891
+ const panel = {
10892
+ key: `${plugin.name}:panel:${entry.id}`,
10893
+ plugin: plugin.name,
10894
+ id: entry.id,
10895
+ title: entry.title,
10896
+ component: entry.component,
10897
+ props: entry.props,
10898
+ order: entry.order ?? Number.MAX_SAFE_INTEGER
10899
+ };
10900
+ panelEntries.value = sortEntries([...panelEntries.value, panel]);
10901
+ return {
10902
+ id: entry.id,
10903
+ open: () => openPlaygroundPanel(entry.id),
10904
+ close: () => closePlaygroundPanel(),
10905
+ toggle: () => togglePlaygroundPanel(entry.id)
10906
+ };
10907
+ }
11835
10908
  }
11836
- ];
11837
- return (_ctx, _cache) => {
11838
- return openBlock(), createElementBlock("header", _hoisted_1$1, [createElementVNode("div", _hoisted_2$1, [
11839
- createElementVNode("span", _hoisted_3$1, toDisplayString(__props.group), 1),
11840
- _cache[3] || (_cache[3] = createElementVNode("span", { class: "pw-toolbar__sep" }, "/", -1)),
11841
- createElementVNode("span", _hoisted_4$1, toDisplayString(__props.title), 1)
11842
- ]), createElementVNode("div", _hoisted_5$1, [
11843
- createElementVNode("div", _hoisted_6, [(openBlock(), createElementBlock(Fragment, null, renderList(widths, (item) => {
11844
- return createElementVNode("button", {
11845
- key: item.value,
11846
- type: "button",
11847
- class: normalizeClass(["pw-width-btn", { "is-active": __props.width === item.value }]),
11848
- title: item.label,
11849
- onClick: ($event) => emit("update:width", item.value)
11850
- }, [(openBlock(), createBlock(resolveDynamicComponent(item.icon), { size: 14 }))], 10, _hoisted_7);
11851
- }), 64))]),
11852
- createVNode(PwButton_default, {
11853
- size: "sm",
11854
- title: __props.theme === "dark" ? "切换到浅色" : "切换到深色",
11855
- onClick: _cache[0] || (_cache[0] = ($event) => emit("toggle-theme"))
11856
- }, {
11857
- icon: withCtx(() => [__props.theme === "light" ? (openBlock(), createBlock(unref(Moon), {
11858
- key: 0,
11859
- size: 14
11860
- })) : (openBlock(), createBlock(unref(Sun), {
11861
- key: 1,
11862
- size: 14
11863
- }))]),
11864
- _: 1
11865
- }, 8, ["title"]),
11866
- createVNode(PwButton_default, {
11867
- size: "sm",
11868
- variant: __props.showPayload ? "primary" : "ghost",
11869
- disabled: !__props.hasPayload,
11870
- title: __props.hasPayload ? "入参 / 出参" : "该场景没有声明 sceneMeta 或 useScenePayload",
11871
- onClick: _cache[1] || (_cache[1] = ($event) => emit("toggle-payload"))
11872
- }, {
11873
- icon: withCtx(() => [createVNode(unref(SlidersHorizontal), { size: 14 })]),
11874
- default: withCtx(() => [_cache[4] || (_cache[4] = createTextVNode(" 参数 ", -1))]),
11875
- _: 1
11876
- }, 8, [
11877
- "variant",
11878
- "disabled",
11879
- "title"
11880
- ]),
11881
- createVNode(PwButton_default, {
11882
- size: "sm",
11883
- variant: __props.showCode ? "primary" : "ghost",
11884
- onClick: _cache[2] || (_cache[2] = ($event) => emit("toggle-code"))
11885
- }, {
11886
- icon: withCtx(() => [createVNode(unref(CodeXml), { size: 14 })]),
11887
- default: withCtx(() => [_cache[5] || (_cache[5] = createTextVNode(" 代码 ", -1))]),
11888
- _: 1
11889
- }, 8, ["variant"])
11890
- ])]);
11891
10909
  };
10910
+ };
10911
+ for (const plugin of queue) try {
10912
+ const result = await plugin.setup?.(createContext(plugin));
10913
+ if (result !== void 0) {
10914
+ apis.set(plugin.name, result);
10915
+ if (result && typeof result === "object") Object.assign(merged, result);
10916
+ }
10917
+ } catch (error) {
10918
+ if (plugin.optional) {
10919
+ console.warn(`[rinova-playground] 可选插件「${plugin.name}」初始化失败,已跳过:`, describeError(error));
10920
+ continue;
10921
+ }
10922
+ throw pluginError(plugin.name, error);
11892
10923
  }
11893
- }), [["__scopeId", "data-v-b90c60a6"]]);
11894
- // src/app/App.vue?vue&type=script&setup=true&lang.ts
11895
- var _hoisted_1 = { class: "pw-app" };
11896
- var _hoisted_2 = { class: "pw-main" };
11897
- var _hoisted_3 = { class: "pw-body" };
11898
- var _hoisted_4 = {
11899
- key: 2,
11900
- class: "pw-empty"
10924
+ envValues.value = merged;
11901
10925
  };
11902
- var _hoisted_5 = {
11903
- key: 1,
11904
- class: "pw-source-slot"
10926
+ /** 注册序号:同一插件注册多个缝位时保证排序稳定 */
10927
+ var seq = 0;
10928
+ var nextSeq = () => {
10929
+ seq += 1;
10930
+ return seq;
11905
10931
  };
11906
- var STORAGE_KEY = "rinova-playground:ui-theme";
11907
- // src/app/App.vue
11908
- var App_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
11909
- __name: "App",
11910
- setup(__props) {
11911
- const title = config.title ?? "Playground";
11912
- /** config.groups 的声明顺序即侧栏分组顺序;未声明的组排到后面 */
11913
- const groupLabelOrder = Object.values(config.groups ?? {});
11914
- const groupRank = (name) => {
11915
- const index = groupLabelOrder.indexOf(name);
11916
- return index === -1 ? Number.MAX_SAFE_INTEGER : index;
11917
- };
11918
- const groups = computed(() => {
11919
- const map = /* @__PURE__ */ new Map();
11920
- for (const scene of scenes) {
11921
- if (scene.hidden) continue;
11922
- const list = map.get(scene.group) ?? [];
11923
- list.push(scene);
11924
- map.set(scene.group, list);
11925
- }
11926
- return [...map.entries()].map(([name, items]) => ({
11927
- name,
11928
- items,
11929
- weight: items.filter((item) => item.kind !== "group-index").reduce((min, item) => Math.min(min, item.order), Number.MAX_SAFE_INTEGER)
11930
- })).sort((a, b) => groupRank(a.name) - groupRank(b.name) || a.weight - b.weight || a.name.localeCompare(b.name));
11931
- });
11932
- const visibleCount = computed(() => scenes.filter((scene) => !scene.hidden && scene.kind !== "group-index").length);
11933
- const activeId = ref(scenes.find((scene) => !scene.hidden)?.id ?? scenes[0]?.id ?? "");
11934
- const activeScene = computed(() => scenes.find((scene) => scene.id === activeId.value) ?? scenes[0]);
11935
- /** 当前是分组落地页时,列出该组的普通场景(不含其它合成页) */
11936
- const groupSceneItems = computed(() => {
11937
- const scene = activeScene.value;
11938
- if (!scene || scene.kind !== "group-index") return [];
11939
- return scenes.filter((item) => item.group === scene.group && item.kind !== "group-index" && !item.hidden);
11940
- });
11941
- const isGroupIndex = computed(() => activeScene.value?.kind === "group-index");
11942
- const showCode = ref(false);
11943
- const showPayload = ref(false);
11944
- const hasPayload = computed(() => currentArgs.value !== null || currentOutput.value !== null);
11945
- watch(hasPayload, (value) => {
11946
- if (!value) showPayload.value = false;
11947
- });
11948
- const sidebarRef = ref(null);
11949
- const width = ref("auto");
11950
- const readStoredTheme = () => {
11951
- const value = localStorage.getItem(STORAGE_KEY);
11952
- return value === "light" || value === "dark" ? value : null;
11953
- };
11954
- const preference = ref(readStoredTheme() ?? config.theme?.ui ?? "auto");
11955
- const systemDark = ref(false);
11956
- const theme = computed(() => preference.value === "auto" ? systemDark.value ? "dark" : "light" : preference.value);
11957
- watchEffect(() => {
11958
- document.documentElement.dataset.pwTheme = theme.value;
11959
- });
11960
- const toggleTheme = () => {
11961
- preference.value = theme.value === "dark" ? "light" : "dark";
11962
- localStorage.setItem(STORAGE_KEY, preference.value);
11963
- };
11964
- const basePath = (() => {
11965
- const raw = config.routeBase ?? config.base ?? "/";
11966
- return raw.endsWith("/") ? raw : `${raw}/`;
11967
- })();
11968
- /** 从 location.pathname 解析出场景 id(去掉 base 与尾部斜杠) */
11969
- const sceneIdFromPath = () => {
11970
- const path = decodeURIComponent(window.location.pathname);
11971
- return (path.startsWith(basePath) ? path.slice(basePath.length) : path.replace(/^\//, "")).replace(/\/+$/, "");
11972
- };
11973
- const readLocation = () => {
11974
- const id = sceneIdFromPath();
11975
- if (id && scenes.some((scene) => scene.id === id)) activeId.value = id;
11976
- };
11977
- watch(activeId, (id) => {
11978
- if (!id) return;
11979
- const target = `${basePath}${id}`;
11980
- if (decodeURIComponent(window.location.pathname) !== target) window.history.pushState(null, "", target);
11981
- });
11982
- const onKeydown = (event) => {
11983
- const meta = event.metaKey || event.ctrlKey;
11984
- if (meta && event.key.toLowerCase() === "k") {
11985
- event.preventDefault();
11986
- sidebarRef.value?.focusSearch();
11987
- return;
11988
- }
11989
- if (meta && event.key === ".") {
11990
- event.preventDefault();
11991
- return;
11992
- }
11993
- if (event.key === "Escape" && showCode.value) showCode.value = false;
11994
- };
11995
- const media = window.matchMedia("(prefers-color-scheme: dark)");
11996
- const onMediaChange = (event) => {
11997
- systemDark.value = event.matches;
11998
- };
11999
- onMounted(() => {
12000
- document.title = title;
12001
- systemDark.value = media.matches;
12002
- media.addEventListener("change", onMediaChange);
12003
- readLocation();
12004
- if (activeId.value && sceneIdFromPath() !== activeId.value) window.history.replaceState(null, "", `${basePath}${activeId.value}`);
12005
- window.addEventListener("popstate", readLocation);
12006
- window.addEventListener("keydown", onKeydown);
12007
- });
12008
- onBeforeUnmount(() => {
12009
- media.removeEventListener("change", onMediaChange);
12010
- window.removeEventListener("popstate", readLocation);
12011
- window.removeEventListener("keydown", onKeydown);
12012
- });
12013
- return (_ctx, _cache) => {
12014
- return openBlock(), createElementBlock("div", _hoisted_1, [
12015
- createVNode(PlaygroundSidebar_default, {
12016
- ref_key: "sidebarRef",
12017
- ref: sidebarRef,
12018
- title: unref(title),
12019
- groups: groups.value,
12020
- "active-id": activeId.value,
12021
- "scene-count": visibleCount.value,
12022
- onSelect: _cache[0] || (_cache[0] = ($event) => activeId.value = $event)
12023
- }, null, 8, [
12024
- "title",
12025
- "groups",
12026
- "active-id",
12027
- "scene-count"
12028
- ]),
12029
- createElementVNode("main", _hoisted_2, [
12030
- activeScene.value ? (openBlock(), createBlock(PlaygroundToolbar_default, {
12031
- key: 0,
12032
- group: activeScene.value.group,
12033
- title: activeScene.value.title,
12034
- "show-code": showCode.value,
12035
- "show-payload": showPayload.value,
12036
- "has-payload": hasPayload.value,
12037
- width: width.value,
12038
- theme: theme.value,
12039
- onToggleCode: _cache[1] || (_cache[1] = ($event) => showCode.value = !showCode.value),
12040
- onTogglePayload: _cache[2] || (_cache[2] = ($event) => showPayload.value = !showPayload.value),
12041
- "onUpdate:width": _cache[3] || (_cache[3] = ($event) => width.value = $event),
12042
- onToggleTheme: toggleTheme
12043
- }, null, 8, [
12044
- "group",
12045
- "title",
12046
- "show-code",
12047
- "show-payload",
12048
- "has-payload",
12049
- "width",
12050
- "theme"
12051
- ])) : createCommentVNode("", true),
12052
- createElementVNode("div", _hoisted_3, [isGroupIndex.value && activeScene.value ? (openBlock(), createBlock(PlaygroundGroupIndex_default, {
12053
- key: 0,
12054
- group: activeScene.value.group,
12055
- items: groupSceneItems.value,
12056
- onSelect: _cache[4] || (_cache[4] = ($event) => activeId.value = $event)
12057
- }, null, 8, ["group", "items"])) : activeScene.value ? (openBlock(), createBlock(PlaygroundStage_default, {
12058
- key: 1,
12059
- scene: activeScene.value,
12060
- width: width.value
12061
- }, null, 8, ["scene", "width"])) : (openBlock(), createElementBlock("div", _hoisted_4, "没有找到任何场景,请在 scenes 目录下新建 .vue 文件。")), showPayload.value && hasPayload.value ? (openBlock(), createBlock(PlaygroundParamsPanel_default, {
12062
- key: 3,
12063
- theme: theme.value
12064
- }, null, 8, ["theme"])) : createCommentVNode("", true)]),
12065
- showCode.value && activeScene.value && !isGroupIndex.value ? (openBlock(), createElementBlock("div", _hoisted_5, [createVNode(PlaygroundSourcePanel_default, {
12066
- scene: activeScene.value,
12067
- theme: theme.value,
12068
- onClose: _cache[5] || (_cache[5] = ($event) => showCode.value = false)
12069
- }, null, 8, ["scene", "theme"])])) : createCommentVNode("", true)
12070
- ]),
12071
- createVNode(PwToastHost_default)
12072
- ]);
12073
- };
12074
- }
12075
- }), [["__scopeId", "data-v-5c38b5f6"]]);
12076
- export { App_default as default, __exportAll as i, FontStyle as n, INITIAL as r, EncodedTokenMetadata as t };
10932
+ export { _plugin_vue_export_helper_default as A, toast as C, PW_THEME_LIGHT as D, PW_THEME_DARK as E, getHighlighter as O, provideSceneContext as S, createLucideIcon as T, currentOutputSlots as _, pluginHeaderSlots as a, currentArgsSlots as b, pluginWrapperEntries as c, togglePlaygroundPanel as d, usePlaygroundEnv as f, currentOutput as g, usePlaygroundUi as h, pluginFooterSlots as i, PwApiBrief_default as k, providePlaygroundTheme as l, usePlaygroundTheme as m, definePlaygroundPlugin as n, pluginOpenPanelId as o, usePlaygroundPlugin as p, openPlaygroundPanel as r, pluginPanelEntries as s, closePlaygroundPanel as t, runPlugins as u, useSceneOutput as v, toastState as w, useSceneArgs as x, currentArgs as y };