@rinova/playground 0.1.4 → 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 (81) hide show
  1. package/README.md +23 -6
  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-BzlvncHB.js → plugin-S72dg7Tb.js} +560 -1608
  12. package/dist/style.css +2880 -9004
  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/components/PwApiBrief.vue.d.ts +16 -0
  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 +43 -5
  55. package/dist/types/index.d.ts +15 -8
  56. package/dist/types/module-api.d.ts +55 -0
  57. package/dist/types/payload/args.d.ts +22 -3
  58. package/dist/types/payload/context.d.ts +3 -0
  59. package/dist/types/payload/output.d.ts +18 -3
  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 -5
  63. package/dist/types/types.d.ts +107 -15
  64. package/dist/vue-B_A2yz16.js +30 -0
  65. package/dist/yaml-CoEYOy4X.js +2 -0
  66. package/package.json +3 -4
  67. package/dist/assets/editor.worker-G4Kxf7Y6.js +0 -15827
  68. package/dist/assets/ts.worker-Dee0cZZb.js +0 -164076
  69. package/dist/dist-CiAXGmAo.js +0 -151
  70. package/dist/editor.api-6f2aPN2V.js +0 -126730
  71. package/dist/editor.worker-VDFPHiZj.js +0 -5
  72. package/dist/monaco.contribution-jrnupplv.js +0 -220
  73. package/dist/output-Dx3ubog9.js +0 -51
  74. package/dist/ts.worker-CpQm_d0w.js +0 -5
  75. package/dist/tsMode-C6DRwdZC.js +0 -52173
  76. package/dist/types/app/PlaygroundToolbar.vue.d.ts +0 -22
  77. package/dist/types/code/CodeEditor.vue.d.ts +0 -18
  78. package/dist/types/code/monaco.d.ts +0 -6
  79. package/dist/vitesse-dark-B9O9KI0c.js +0 -3
  80. package/dist/vitesse-light-Cs2DYTIe.js +0 -3
  81. package/dist/vue-tjAT-6a9.js +0 -36
package/dist/index.js CHANGED
@@ -1,9 +1,650 @@
1
- import { a as toast, i as useSceneArgs, n as useSceneOutput, r as currentArgs, t as currentOutput } from "./output-Dx3ubog9.js";
2
- import { createApp } from "vue";
1
+ import { A as _plugin_vue_export_helper_default, C as toast, D as PW_THEME_LIGHT, E as PW_THEME_DARK, O as getHighlighter, T as createLucideIcon, _ as currentOutputSlots, b as currentArgsSlots, d as togglePlaygroundPanel, f as usePlaygroundEnv, g as currentOutput, h as usePlaygroundUi, k as PwApiBrief_default, m as usePlaygroundTheme, n as definePlaygroundPlugin, p as usePlaygroundPlugin, r as openPlaygroundPanel, t as closePlaygroundPanel, v as useSceneOutput, x as useSceneArgs, y as currentArgs } from "./plugin-S72dg7Tb.js";
2
+ import { Fragment, computed, createApp, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, defineComponent, h, nextTick, normalizeClass, normalizeStyle, onMounted, onUpdated, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, unref, watch, withCtx } from "vue";
3
3
  // src/config.ts
4
4
  var defineConfig = (config) => config;
5
5
  // src/scene-meta.ts
6
6
  var defineSceneMeta = (meta) => meta;
7
+ var definePageMeta = (meta) => meta;
8
+ // src/components/PwDemoGrid.vue
9
+ var PwDemoGrid_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
10
+ __name: "PwDemoGrid",
11
+ props: {
12
+ columns: { default: 1 },
13
+ min: { default: 0 },
14
+ gap: { default: "md" }
15
+ },
16
+ setup(__props) {
17
+ const props = __props;
18
+ const GAPS = {
19
+ sm: "8px",
20
+ md: "12px",
21
+ lg: "16px"
22
+ };
23
+ const auto = computed(() => props.min > 0);
24
+ const style = computed(() => ({
25
+ "--pw-demo-columns": String(props.columns),
26
+ "--pw-demo-min": `${props.min || 220}px`,
27
+ "--pw-demo-gap": GAPS[props.gap]
28
+ }));
29
+ return (_ctx, _cache) => {
30
+ return openBlock(), createElementBlock("div", {
31
+ class: normalizeClass(["pw-demo-grid", { "is-auto": auto.value }]),
32
+ style: normalizeStyle(style.value)
33
+ }, [renderSlot(_ctx.$slots, "default", {}, void 0, true)], 6);
34
+ };
35
+ }
36
+ }), [["__scopeId", "data-v-68029d58"]]);
37
+ // src/components/PwDemo.vue?vue&type=script&setup=true&lang.ts
38
+ var _hoisted_1$5 = {
39
+ key: 0,
40
+ class: "pw-demo__title"
41
+ };
42
+ var _hoisted_2$4 = { class: "pw-demo__body" };
43
+ var _hoisted_3$4 = {
44
+ key: 1,
45
+ class: "pw-demo__note"
46
+ };
47
+ var _hoisted_4$1 = {
48
+ key: 2,
49
+ class: "pw-demo__footer"
50
+ };
51
+ // src/components/PwDemo.vue
52
+ var PwDemo_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
53
+ __name: "PwDemo",
54
+ props: {
55
+ title: {},
56
+ direction: { default: "row" },
57
+ align: { default: "center" },
58
+ surface: { default: "none" }
59
+ },
60
+ setup(__props) {
61
+ /**
62
+ * 单个 Demo 块:标题 + 控件区 + 可选说明/页脚。
63
+ *
64
+ * 默认 `surface="none"`:画布已经提供了底色和内边距,这里只负责排版;
65
+ * 需要独立卡片时再加 `surface="card"`。全部可选,不想用这套原语照样可以自己写。
66
+ */
67
+ return (_ctx, _cache) => {
68
+ return openBlock(), createElementBlock("figure", { class: normalizeClass(["pw-demo", [
69
+ `is-${__props.direction}`,
70
+ `align-${__props.align}`,
71
+ `surface-${__props.surface}`
72
+ ]]) }, [
73
+ __props.title ? (openBlock(), createElementBlock("figcaption", _hoisted_1$5, toDisplayString(__props.title), 1)) : createCommentVNode("", true),
74
+ createElementVNode("div", _hoisted_2$4, [renderSlot(_ctx.$slots, "default", {}, void 0, true)]),
75
+ _ctx.$slots.note ? (openBlock(), createElementBlock("p", _hoisted_3$4, [renderSlot(_ctx.$slots, "note", {}, void 0, true)])) : createCommentVNode("", true),
76
+ _ctx.$slots.footer ? (openBlock(), createElementBlock("div", _hoisted_4$1, [renderSlot(_ctx.$slots, "footer", {}, void 0, true)])) : createCommentVNode("", true)
77
+ ], 2);
78
+ };
79
+ }
80
+ }), [["__scopeId", "data-v-a3355761"]]);
81
+ // src/components/PwSceneNote.vue?vue&type=script&setup=true&lang.ts
82
+ var _hoisted_1$4 = { class: "pw-scene-note" };
83
+ // src/components/PwSceneNote.vue
84
+ var PwSceneNote_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
85
+ __name: "PwSceneNote",
86
+ props: { text: {} },
87
+ setup(__props) {
88
+ /** 场景内说明块(引用样式) */
89
+ return (_ctx, _cache) => {
90
+ return openBlock(), createElementBlock("div", _hoisted_1$4, [renderSlot(_ctx.$slots, "default", {}, () => [createTextVNode(toDisplayString(__props.text), 1)], true)]);
91
+ };
92
+ }
93
+ }), [["__scopeId", "data-v-07e42ce6"]]);
94
+ // src/components/prose/enhance.ts
95
+ /**
96
+ * 代码块增强:语法高亮 + 语言角标 + 复制按钮。
97
+ *
98
+ * Markdown 与手写内容页(`PwProse`)走同一段逻辑,保证同一个代码块在两条路上长得一样。
99
+ * 只在已渲染的 DOM 上就地改:不移动、不替换 `<pre>` 节点,Vue 重新渲染时会被覆盖,
100
+ * 于是用「按钮是否还在」当幂等标记,重渲染后自动再增强一次。
101
+ */
102
+ /** shiki 的语言别名 → 我们注册过的 lang */
103
+ var LANGS = {
104
+ ts: "typescript",
105
+ tsx: "typescript",
106
+ js: "javascript",
107
+ mjs: "javascript",
108
+ cjs: "javascript",
109
+ sh: "bash",
110
+ shell: "bash",
111
+ zsh: "bash",
112
+ md: "markdown",
113
+ yml: "yaml",
114
+ htm: "html"
115
+ };
116
+ var detectLang = (pre) => {
117
+ const langClass = [...pre.querySelector("code")?.classList ?? []].find((name) => name.startsWith("language-"));
118
+ const raw = (langClass ? langClass.slice(9) : pre.dataset.lang ?? "").toLowerCase();
119
+ if (!raw) return {
120
+ shikiLang: "text",
121
+ label: ""
122
+ };
123
+ return {
124
+ shikiLang: LANGS[raw] ?? raw,
125
+ label: raw
126
+ };
127
+ };
128
+ /** 把 `<pre><code>` 换成 shiki 的高亮结果(保留原来的 `<pre>` 节点) */
129
+ var applyHighlight = async (pre, lang) => {
130
+ if (pre.classList.contains("shiki")) return;
131
+ const code = pre.querySelector("code");
132
+ if (!code) return;
133
+ const highlighter = await getHighlighter().catch((error) => {
134
+ console.warn("[rinova-playground] 代码高亮初始化失败:", error);
135
+ return null;
136
+ });
137
+ if (!highlighter) return;
138
+ try {
139
+ const html = highlighter.codeToHtml(code.textContent ?? "", {
140
+ lang,
141
+ themes: {
142
+ light: PW_THEME_LIGHT,
143
+ dark: PW_THEME_DARK
144
+ },
145
+ defaultColor: false
146
+ });
147
+ const doc = new DOMParser().parseFromString(html, "text/html");
148
+ const next = doc.querySelector("pre");
149
+ const nextCode = doc.querySelector("code");
150
+ if (!next || !nextCode) return;
151
+ pre.setAttribute("class", next.getAttribute("class") ?? "shiki");
152
+ pre.setAttribute("style", next.getAttribute("style") ?? "");
153
+ code.innerHTML = nextCode.innerHTML;
154
+ code.removeAttribute("class");
155
+ } catch (error) {
156
+ console.warn("[rinova-playground] 代码高亮失败(保留纯文本):", error);
157
+ }
158
+ };
159
+ var COPY_LABEL = "复制";
160
+ var DONE_LABEL = "已复制";
161
+ /** 给一个 `<pre>` 加语言角标与复制按钮;带 data-pw-copy 说明已经处理过 */
162
+ var decorate = (pre, label) => {
163
+ pre.classList.add("pw-prose__code");
164
+ if (pre.querySelector("[data-pw-copy]")) return;
165
+ if (label) {
166
+ const tag = document.createElement("span");
167
+ tag.className = "pw-prose__lang";
168
+ tag.setAttribute("aria-hidden", "true");
169
+ tag.textContent = label;
170
+ pre.append(tag);
171
+ }
172
+ const button = document.createElement("button");
173
+ button.type = "button";
174
+ button.className = "pw-prose__copy";
175
+ button.dataset.pwCopy = "";
176
+ button.textContent = COPY_LABEL;
177
+ pre.append(button);
178
+ };
179
+ /** 增强 root 下所有还没处理过的代码块 */
180
+ var enhanceCodeBlocks = async (root) => {
181
+ if (!root) return;
182
+ const pending = [...root.querySelectorAll("pre")].filter((pre) => !pre.querySelector("[data-pw-copy]"));
183
+ for (const pre of pending) {
184
+ const { shikiLang, label } = detectLang(pre);
185
+ await applyHighlight(pre, shikiLang);
186
+ decorate(pre, label);
187
+ }
188
+ };
189
+ /** 复制按钮的点击:由容器统一代理(`v-html` 里的节点绑不了 Vue 事件) */
190
+ var handleCopyClick = async (event) => {
191
+ const button = event.target?.closest("[data-pw-copy]");
192
+ if (!button) return;
193
+ const text = button.closest("pre")?.querySelector("code")?.textContent ?? "";
194
+ if (!text) return;
195
+ try {
196
+ await navigator.clipboard.writeText(text);
197
+ } catch {
198
+ const area = document.createElement("textarea");
199
+ area.value = text;
200
+ area.style.position = "fixed";
201
+ area.style.opacity = "0";
202
+ document.body.append(area);
203
+ area.select();
204
+ document.execCommand("copy");
205
+ area.remove();
206
+ }
207
+ button.textContent = DONE_LABEL;
208
+ button.classList.add("is-done");
209
+ window.setTimeout(() => {
210
+ button.textContent = COPY_LABEL;
211
+ button.classList.remove("is-done");
212
+ }, 1200);
213
+ };
214
+ // src/components/prose/PwProse.vue?vue&type=script&setup=true&lang.ts
215
+ var _hoisted_1$3 = {
216
+ key: 0,
217
+ class: "pw-prose__head"
218
+ };
219
+ var _hoisted_2$3 = { key: 0 };
220
+ var _hoisted_3$3 = {
221
+ key: 1,
222
+ class: "pw-prose__lead"
223
+ };
224
+ // src/components/prose/PwProse.vue
225
+ var PwProse_default = /* @__PURE__ */ defineComponent({
226
+ __name: "PwProse",
227
+ props: {
228
+ title: { default: "" },
229
+ lead: { default: "" },
230
+ width: { default: "" }
231
+ },
232
+ setup(__props) {
233
+ /**
234
+ * 文档排版容器:给内容页(介绍、指南、说明)提供统一的标题 / 段落 / 列表 / 表格 / 代码样式。
235
+ *
236
+ * 样式之外只多做一件事:把插槽里的 `<pre><code class="language-ts">` 就地升级成
237
+ * 高亮 + 语言角标 + 复制按钮,和 Markdown 代码块完全一致。
238
+ */
239
+ const rootEl = ref(null);
240
+ /** 增强是幂等的:按钮还在就跳过,Vue 重渲染把 DOM 覆盖了才重新跑 */
241
+ const enhance = () => {
242
+ enhanceCodeBlocks(rootEl.value);
243
+ };
244
+ onMounted(enhance);
245
+ onUpdated(enhance);
246
+ return (_ctx, _cache) => {
247
+ return openBlock(), createElementBlock("article", {
248
+ ref_key: "rootEl",
249
+ ref: rootEl,
250
+ class: "pw-prose",
251
+ style: normalizeStyle(__props.width ? { "--pw-prose-width": __props.width } : void 0),
252
+ onClick: _cache[0] || (_cache[0] = (...args) => unref(handleCopyClick) && unref(handleCopyClick)(...args))
253
+ }, [__props.title || __props.lead ? (openBlock(), createElementBlock("header", _hoisted_1$3, [__props.title ? (openBlock(), createElementBlock("h1", _hoisted_2$3, toDisplayString(__props.title), 1)) : createCommentVNode("", true), __props.lead ? (openBlock(), createElementBlock("p", _hoisted_3$3, toDisplayString(__props.lead), 1)) : createCommentVNode("", true)])) : createCommentVNode("", true), renderSlot(_ctx.$slots, "default")], 4);
254
+ };
255
+ }
256
+ });
257
+ /**
258
+ * @license @lucide/vue v1.66.0 - ISC
259
+ *
260
+ * This source code is licensed under the ISC license.
261
+ * See the LICENSE file in the root directory of this source tree.
262
+ */
263
+ var Info = createLucideIcon({
264
+ name: "info",
265
+ size: 24,
266
+ node: [
267
+ ["circle", {
268
+ cx: "12",
269
+ cy: "12",
270
+ r: "10",
271
+ key: "1mglay"
272
+ }],
273
+ ["path", {
274
+ d: "M12 16v-4",
275
+ key: "1dtifu"
276
+ }],
277
+ ["path", {
278
+ d: "M12 8h.01",
279
+ key: "e9boi3"
280
+ }]
281
+ ]
282
+ });
283
+ /**
284
+ * @license @lucide/vue v1.66.0 - ISC
285
+ *
286
+ * This source code is licensed under the ISC license.
287
+ * See the LICENSE file in the root directory of this source tree.
288
+ */
289
+ var Lightbulb = createLucideIcon({
290
+ name: "lightbulb",
291
+ size: 24,
292
+ node: [
293
+ ["path", {
294
+ d: "M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5",
295
+ key: "1gvzjb"
296
+ }],
297
+ ["path", {
298
+ d: "M9 18h6",
299
+ key: "x1upvd"
300
+ }],
301
+ ["path", {
302
+ d: "M10 22h4",
303
+ key: "ceow96"
304
+ }]
305
+ ]
306
+ });
307
+ /**
308
+ * @license @lucide/vue v1.66.0 - ISC
309
+ *
310
+ * This source code is licensed under the ISC license.
311
+ * See the LICENSE file in the root directory of this source tree.
312
+ */
313
+ var OctagonAlert = createLucideIcon({
314
+ name: "octagon-alert",
315
+ size: 24,
316
+ node: [
317
+ ["path", {
318
+ d: "M12 16h.01",
319
+ key: "1drbdi"
320
+ }],
321
+ ["path", {
322
+ d: "M12 8v4",
323
+ key: "1got3b"
324
+ }],
325
+ ["path", {
326
+ d: "M15.312 2a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586l-4.688-4.688A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2z",
327
+ key: "1fd625"
328
+ }]
329
+ ],
330
+ aliases: ["alert-octagon"]
331
+ });
332
+ /**
333
+ * @license @lucide/vue v1.66.0 - ISC
334
+ *
335
+ * This source code is licensed under the ISC license.
336
+ * See the LICENSE file in the root directory of this source tree.
337
+ */
338
+ var TriangleAlert = createLucideIcon({
339
+ name: "triangle-alert",
340
+ size: 24,
341
+ node: [
342
+ ["path", {
343
+ d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3",
344
+ key: "wmoenq"
345
+ }],
346
+ ["path", {
347
+ d: "M12 9v4",
348
+ key: "juzpu7"
349
+ }],
350
+ ["path", {
351
+ d: "M12 17h.01",
352
+ key: "p32p05"
353
+ }]
354
+ ],
355
+ aliases: ["alert-triangle"]
356
+ });
357
+ // src/components/prose/PwCallout.vue?vue&type=script&setup=true&lang.ts
358
+ var _hoisted_1$2 = { class: "pw-callout__main" };
359
+ var _hoisted_2$2 = {
360
+ key: 0,
361
+ class: "pw-callout__title"
362
+ };
363
+ var _hoisted_3$2 = { class: "pw-callout__body" };
364
+ // src/components/prose/PwCallout.vue
365
+ var PwCallout_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
366
+ __name: "PwCallout",
367
+ props: {
368
+ tone: { default: "info" },
369
+ title: { default: "" }
370
+ },
371
+ setup(__props) {
372
+ /**
373
+ * 提示块:把「注意 / 建议 / 警告 / 危险」这类旁注从正文里拎出来。
374
+ *
375
+ * Markdown 里写 `::: tip 标题`,渲染出来就是同一个组件。
376
+ */
377
+ const props = __props;
378
+ const icons = {
379
+ info: Info,
380
+ tip: Lightbulb,
381
+ warn: TriangleAlert,
382
+ danger: OctagonAlert
383
+ };
384
+ const icon = computed(() => icons[props.tone]);
385
+ return (_ctx, _cache) => {
386
+ return openBlock(), createElementBlock("aside", { class: normalizeClass(["pw-callout", `pw-callout--${__props.tone}`]) }, [(openBlock(), createBlock(resolveDynamicComponent(icon.value), {
387
+ size: 15,
388
+ class: "pw-callout__icon"
389
+ })), createElementVNode("div", _hoisted_1$2, [__props.title ? (openBlock(), createElementBlock("p", _hoisted_2$2, toDisplayString(__props.title), 1)) : createCommentVNode("", true), createElementVNode("div", _hoisted_3$2, [renderSlot(_ctx.$slots, "default", {}, void 0, true)])])], 2);
390
+ };
391
+ }
392
+ }), [["__scopeId", "data-v-6a2ac811"]]);
393
+ // src/components/prose/PwSteps.vue
394
+ var PwSteps_default = /* @__PURE__ */ defineComponent({
395
+ __name: "PwSteps",
396
+ props: { start: { default: 1 } },
397
+ setup(__props) {
398
+ /**
399
+ * 步骤列表:按顺序讲一件事时用,序号由 CSS 计数器生成,增删条目不用改编号。
400
+ *
401
+ * Markdown 里写 `::: steps` + 有序列表,渲染出来是同一个组件。
402
+ */
403
+ return (_ctx, _cache) => {
404
+ return openBlock(), createElementBlock("ol", {
405
+ class: "pw-prose__steps",
406
+ style: normalizeStyle(__props.start !== 1 ? { counterReset: `pw-prose-step ${__props.start - 1}` } : void 0)
407
+ }, [renderSlot(_ctx.$slots, "default")], 4);
408
+ };
409
+ }
410
+ });
411
+ // src/components/prose/PwStep.vue?vue&type=script&setup=true&lang.ts
412
+ var _hoisted_1$1 = { class: "pw-prose__step" };
413
+ var _hoisted_2$1 = {
414
+ key: 0,
415
+ class: "pw-prose__step-title"
416
+ };
417
+ var _hoisted_3$1 = {
418
+ key: 1,
419
+ class: "pw-prose__step-desc"
420
+ };
421
+ // src/components/prose/PwStep.vue
422
+ var PwStep_default = /* @__PURE__ */ defineComponent({
423
+ __name: "PwStep",
424
+ props: {
425
+ title: { default: "" },
426
+ description: { default: "" }
427
+ },
428
+ setup(__props) {
429
+ /**
430
+ * 单条步骤,放在 `PwSteps` 里使用;标题可选,正文走默认插槽。
431
+ */
432
+ return (_ctx, _cache) => {
433
+ return openBlock(), createElementBlock("li", _hoisted_1$1, [
434
+ __props.title ? (openBlock(), createElementBlock("p", _hoisted_2$1, toDisplayString(__props.title), 1)) : createCommentVNode("", true),
435
+ __props.description ? (openBlock(), createElementBlock("p", _hoisted_3$1, toDisplayString(__props.description), 1)) : createCommentVNode("", true),
436
+ renderSlot(_ctx.$slots, "default")
437
+ ]);
438
+ };
439
+ }
440
+ });
441
+ // src/components/prose/parse.ts
442
+ /** `::: tip` 这类容器的别名表:写法尽量宽,渲染统一 */
443
+ var TONES = {
444
+ tip: "tip",
445
+ info: "info",
446
+ note: "info",
447
+ warn: "warn",
448
+ warning: "warn",
449
+ danger: "danger",
450
+ error: "danger"
451
+ };
452
+ var TONE_LABEL = {
453
+ info: "说明",
454
+ tip: "建议",
455
+ warn: "注意",
456
+ danger: "危险"
457
+ };
458
+ var FRONTMATTER = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
459
+ /** 去掉 `---` 头(内容由插件解析成 pageMeta / sceneMeta,渲染时不该出现) */
460
+ var stripFrontmatter = (source) => source.replace(FRONTMATTER, "");
461
+ /** 把正文切成「普通 Markdown / 提示块 / 步骤块」,容器不支持嵌套 */
462
+ var splitBlocks = (body) => {
463
+ const blocks = [];
464
+ let buffer = [];
465
+ let open = null;
466
+ const pushText = (text) => {
467
+ if (text.trim()) blocks.push({
468
+ kind: "md",
469
+ text
470
+ });
471
+ };
472
+ for (const line of body.split(/\r?\n/)) {
473
+ const match = /^:::\s*([a-zA-Z-]+)\s*(.*)$/.exec(line);
474
+ if (open) {
475
+ if (line.trim() === ":::") {
476
+ pushText(buffer.join("\n"));
477
+ buffer = [];
478
+ blocks.push({
479
+ kind: open.kind,
480
+ tone: open.tone,
481
+ title: open.title,
482
+ text: open.lines.join("\n")
483
+ });
484
+ open = null;
485
+ continue;
486
+ }
487
+ open.lines.push(line);
488
+ continue;
489
+ }
490
+ if (match) {
491
+ const name = (match[1] ?? "").toLowerCase();
492
+ const isSteps = name === "steps";
493
+ const tone = TONES[name];
494
+ if (!isSteps && !tone) {
495
+ buffer.push(line);
496
+ continue;
497
+ }
498
+ pushText(buffer.join("\n"));
499
+ buffer = [];
500
+ open = {
501
+ kind: isSteps ? "steps" : "callout",
502
+ tone: isSteps ? void 0 : tone,
503
+ title: isSteps ? void 0 : (match[2] ?? "").trim(),
504
+ lines: []
505
+ };
506
+ continue;
507
+ }
508
+ buffer.push(line);
509
+ }
510
+ if (open) pushText([open.kind === "steps" ? "::: steps" : `::: ${open.tone ?? "info"} ${open.title ?? ""}`.trim(), ...open.lines].join("\n"));
511
+ pushText(buffer.join("\n"));
512
+ return blocks;
513
+ };
514
+ // src/components/prose/render.ts
515
+ /**
516
+ * 把 Markdown 原文渲染成区块列表。
517
+ *
518
+ * 这里只做 Markdown → HTML;语法高亮、语言角标与复制按钮统一交给 `enhance.ts`
519
+ * (和手写内容页 `PwProse` 走同一段逻辑)。marked 按需加载,页面里没有 `.md` 场景时不会下载。
520
+ */
521
+ var renderMarkdown = async (source) => {
522
+ const { marked } = await import("./marked.esm-CNYX-ybC.js");
523
+ marked.setOptions({
524
+ gfm: true,
525
+ breaks: false
526
+ });
527
+ const blocks = splitBlocks(stripFrontmatter(source));
528
+ const out = [];
529
+ for (const block of blocks) {
530
+ const html = marked.parse(block.text, { async: false });
531
+ if (block.kind === "callout") {
532
+ const tone = block.tone ?? "info";
533
+ out.push({
534
+ kind: "callout",
535
+ tone,
536
+ title: block.title || TONE_LABEL[tone],
537
+ html
538
+ });
539
+ continue;
540
+ }
541
+ if (block.kind === "steps") {
542
+ const items = [...new DOMParser().parseFromString(html, "text/html").querySelectorAll("ol > li")].map((item) => item.innerHTML.trim());
543
+ if (items.length) {
544
+ out.push({
545
+ kind: "steps",
546
+ items
547
+ });
548
+ continue;
549
+ }
550
+ }
551
+ out.push({
552
+ kind: "html",
553
+ html
554
+ });
555
+ }
556
+ return out.filter((block) => block.kind === "steps" ? block.items.length > 0 : block.html.trim().length > 0);
557
+ };
558
+ // src/components/prose/PwMarkdown.vue?vue&type=script&setup=true&lang.ts
559
+ var _hoisted_1 = ["innerHTML"];
560
+ var _hoisted_2 = ["innerHTML"];
561
+ var _hoisted_3 = ["innerHTML"];
562
+ var _hoisted_4 = {
563
+ key: 0,
564
+ class: "pw-prose__error"
565
+ };
566
+ // src/components/prose/PwMarkdown.vue
567
+ var PwMarkdown_default = /* @__PURE__ */ defineComponent({
568
+ __name: "PwMarkdown",
569
+ props: {
570
+ source: {},
571
+ width: { default: "" }
572
+ },
573
+ setup(__props) {
574
+ /**
575
+ * Markdown 渲染:`.md` 场景就是它渲染出来的。
576
+ *
577
+ * 做法是「Markdown → 区块 → 组件」:普通段落走 `v-html`,
578
+ * `::: tip` 变成 `PwCallout`、`::: steps` 变成 `PwSteps`,
579
+ * 所以 Markdown 与手写 Vue 内容页共用同一套组件与样式。
580
+ *
581
+ * 代码块的语法高亮、语言角标、复制按钮由 `enhance.ts` 统一处理(与 `PwProse` 同一段逻辑)。
582
+ */
583
+ const props = __props;
584
+ const blocks = ref([]);
585
+ const failed = ref("");
586
+ const rootEl = ref(null);
587
+ watch(() => props.source, async (source) => {
588
+ try {
589
+ blocks.value = await renderMarkdown(source);
590
+ failed.value = "";
591
+ } catch (error) {
592
+ failed.value = error instanceof Error ? error.message : String(error);
593
+ blocks.value = [];
594
+ }
595
+ await nextTick();
596
+ await enhanceCodeBlocks(rootEl.value);
597
+ }, { immediate: true });
598
+ return (_ctx, _cache) => {
599
+ return openBlock(), createElementBlock("article", {
600
+ ref_key: "rootEl",
601
+ ref: rootEl,
602
+ class: "pw-prose",
603
+ style: normalizeStyle(__props.width ? { "--pw-prose-width": __props.width } : void 0),
604
+ onClick: _cache[0] || (_cache[0] = (...args) => unref(handleCopyClick) && unref(handleCopyClick)(...args))
605
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(blocks.value, (block, index) => {
606
+ return openBlock(), createElementBlock(Fragment, { key: index }, [block.kind === "callout" ? (openBlock(), createBlock(PwCallout_default, {
607
+ key: 0,
608
+ tone: block.tone,
609
+ title: block.title
610
+ }, {
611
+ default: withCtx(() => [createElementVNode("div", {
612
+ class: "pw-prose__block",
613
+ innerHTML: block.html
614
+ }, null, 8, _hoisted_1)]),
615
+ _: 2
616
+ }, 1032, ["tone", "title"])) : block.kind === "steps" ? (openBlock(), createBlock(PwSteps_default, { key: 1 }, {
617
+ default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(block.items, (item, itemIndex) => {
618
+ return openBlock(), createBlock(PwStep_default, { key: itemIndex }, {
619
+ default: withCtx(() => [createElementVNode("div", {
620
+ class: "pw-prose__block",
621
+ innerHTML: item
622
+ }, null, 8, _hoisted_2)]),
623
+ _: 2
624
+ }, 1024);
625
+ }), 128))]),
626
+ _: 2
627
+ }, 1024)) : (openBlock(), createElementBlock("div", {
628
+ key: 2,
629
+ class: "pw-prose__block",
630
+ innerHTML: block.html
631
+ }, null, 8, _hoisted_3))], 64);
632
+ }), 128)), failed.value ? (openBlock(), createElementBlock("p", _hoisted_4, "Markdown 渲染失败:" + toDisplayString(failed.value), 1)) : createCommentVNode("", true)], 4);
633
+ };
634
+ }
635
+ });
636
+ // src/components/prose/markdown-scene.ts
637
+ /**
638
+ * 把一个 Markdown 场景包成组件:插件扫描到 `.md` 文件时调用。
639
+ *
640
+ * ```ts
641
+ * load: () => import('./guide.md?raw').then((mod) => ({ default: defineMarkdownScene(mod.default) }))
642
+ * ```
643
+ */
644
+ var defineMarkdownScene = (source) => defineComponent({
645
+ name: "PwMarkdownScene",
646
+ setup: () => () => h(PwMarkdown_default, { source })
647
+ });
7
648
  // src/index.ts
8
649
  /**
9
650
  * 挂载 playground。
@@ -16,7 +657,7 @@ var defineSceneMeta = (meta) => meta;
16
657
  var createPlayground = async (options = {}) => {
17
658
  const target = typeof options.el === "string" ? document.querySelector(options.el) : options.el ?? document.querySelector("#app");
18
659
  if (!target) throw new Error("[rinova-playground] 未找到挂载容器。请在 index.html 中提供 <div id=\"app\"></div>,或调用 createPlayground({ el })");
19
- const { default: App } = await import("./App-BzlvncHB.js");
20
- createApp(App).mount(target);
660
+ const { default: Root } = await import("./PlaygroundRoot-Bcq7hG6m.js");
661
+ createApp(Root).mount(target);
21
662
  };
22
- export { createPlayground, currentArgs, currentOutput, defineConfig, defineSceneMeta, toast, useSceneArgs, useSceneOutput };
663
+ export { PwApiBrief_default as PwApiBrief, PwCallout_default as PwCallout, PwDemo_default as PwDemo, PwDemoGrid_default as PwDemoGrid, PwMarkdown_default as PwMarkdown, PwProse_default as PwProse, PwSceneNote_default as PwSceneNote, PwStep_default as PwStep, PwSteps_default as PwSteps, closePlaygroundPanel, createPlayground, currentArgs, currentArgsSlots, currentOutput, currentOutputSlots, defineConfig, defineMarkdownScene, definePageMeta, definePlaygroundPlugin, defineSceneMeta, openPlaygroundPanel, toast, togglePlaygroundPanel, usePlaygroundEnv, usePlaygroundPlugin, usePlaygroundTheme, usePlaygroundUi, useSceneArgs, useSceneOutput };