@deot/docs-playground 1.0.9 → 1.1.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.
package/dist/index.js CHANGED
@@ -109,12 +109,14 @@ var PLAYGROUND_ICONS = {
109
109
  "c.43-.63.66-1.08.92-1.81h2.37c.25.8.51 1.26.97 1.77l.03.05zM8.12 8.4H2.9",
110
110
  "c-.64 0-1.17.53-1.17 1.19v10.75c0 .66.53 1.19 1.17 1.19h5.21c.65 0 1.18-.53 1.18-1.19V9.6",
111
111
  "a1.16 1.16 0 0 0-1.17-1.19M8.1 20.36H2.94V9.64h5.15z"
112
- ].join(""))
112
+ ].join("")),
113
+ expand: strokeIcon("M6 9l6 6 6-6"),
114
+ popup: strokeIcon(["M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3", "M3 16v3a2 2 0 0 0 2 2h3"].join(""))
113
115
  };
114
116
  //#endregion
115
117
  //#region packages/playground/src/icon/icon.vue?vue&type=script&setup=true&lang.ts
116
- var _hoisted_1$5 = ["fill", "stroke"];
117
- var _hoisted_2$4 = ["d"];
118
+ var _hoisted_1$7 = ["fill", "stroke"];
119
+ var _hoisted_2$7 = ["d"];
118
120
  //#endregion
119
121
  //#region packages/playground/src/icon/icon.vue
120
122
  var icon_default = /* @__PURE__ */ defineComponent({
@@ -145,7 +147,7 @@ var icon_default = /* @__PURE__ */ defineComponent({
145
147
  "stroke-linecap": "round",
146
148
  "stroke-linejoin": "round",
147
149
  "aria-hidden": "true"
148
- }, [createElementVNode("path", { d: icon.value.path }, null, 8, _hoisted_2$4)], 12, _hoisted_1$5);
150
+ }, [createElementVNode("path", { d: icon.value.path }, null, 8, _hoisted_2$7)], 12, _hoisted_1$7);
149
151
  };
150
152
  }
151
153
  });
@@ -154,7 +156,7 @@ var icon_default = /* @__PURE__ */ defineComponent({
154
156
  var github_default = "pre code.hljs{display:block;padding:1em;overflow-x:auto}code.hljs{padding:3px 5px}.hljs{color:#24292e;background:#fff}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#d73a49}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#6f42c1}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#005cc5}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#032f62}.hljs-built_in,.hljs-symbol{color:#e36209}.hljs-code,.hljs-comment,.hljs-formula{color:#6a737d}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#22863a}.hljs-subst{color:#24292e}.hljs-section{font-weight:700;color:#005cc5}.hljs-bullet{color:#735c0f}.hljs-emphasis{font-style:italic;color:#24292e}.hljs-strong{font-weight:700;color:#24292e}.hljs-addition{color:#22863a;background-color:#f0fff4}.hljs-deletion{color:#b31d28;background-color:#ffeef0}[data-doc-theme=dark] .hljs,[data-vc-theme=dark] .hljs{color:#c9d1d9;background:#0d1117}[data-doc-theme=dark] .hljs-doctag,[data-doc-theme=dark] .hljs-keyword,[data-doc-theme=dark] .hljs-meta .hljs-keyword,[data-doc-theme=dark] .hljs-template-tag,[data-doc-theme=dark] .hljs-template-variable,[data-doc-theme=dark] .hljs-type,[data-doc-theme=dark] .hljs-variable.language_,[data-vc-theme=dark] .hljs-doctag,[data-vc-theme=dark] .hljs-keyword,[data-vc-theme=dark] .hljs-meta .hljs-keyword,[data-vc-theme=dark] .hljs-template-tag,[data-vc-theme=dark] .hljs-template-variable,[data-vc-theme=dark] .hljs-type,[data-vc-theme=dark] .hljs-variable.language_{color:#ff7b72}[data-doc-theme=dark] .hljs-title,[data-doc-theme=dark] .hljs-title.class_,[data-doc-theme=dark] .hljs-title.function_,[data-vc-theme=dark] .hljs-title,[data-vc-theme=dark] .hljs-title.class_,[data-vc-theme=dark] .hljs-title.function_{color:#d2a8ff}[data-doc-theme=dark] .hljs-attr,[data-doc-theme=dark] .hljs-literal,[data-doc-theme=dark] .hljs-number,[data-doc-theme=dark] .hljs-variable,[data-vc-theme=dark] .hljs-attr,[data-vc-theme=dark] .hljs-literal,[data-vc-theme=dark] .hljs-number,[data-vc-theme=dark] .hljs-variable{color:#79c0ff}[data-doc-theme=dark] .hljs-regexp,[data-doc-theme=dark] .hljs-string,[data-vc-theme=dark] .hljs-regexp,[data-vc-theme=dark] .hljs-string{color:#a5d6ff}[data-doc-theme=dark] .hljs-code,[data-doc-theme=dark] .hljs-comment,[data-vc-theme=dark] .hljs-code,[data-vc-theme=dark] .hljs-comment{color:#8b949e}[data-doc-theme=dark] .hljs-name,[data-doc-theme=dark] .hljs-selector-tag,[data-vc-theme=dark] .hljs-name,[data-vc-theme=dark] .hljs-selector-tag{color:#7ee787}";
155
157
  //#endregion
156
158
  //#region packages/playground/src/core/code-preview/code-preview.scss?inline
157
- var code_preview_default$1 = ".docs-code-preview{position:relative;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;min-height:0;overflow:hidden;background:var(--docs-background-color-soft,var(--vc-background-color,#f7f8fa));border-radius:8px}.docs-code-preview__language{z-index:1;overflow:hidden;font-size:12px;line-height:18px;text-overflow:ellipsis;white-space:nowrap}.docs-code-preview__copy,.docs-code-preview__language{position:absolute;top:6px;right:12px;display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;width:28px;height:28px;color:var(--docs-foreground-color-mute,var(--vc-color-dark-extralight,#71717a));-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center}.docs-code-preview__copy{z-index:2;padding:0;pointer-events:none;cursor:pointer;background:var(--docs-background-color-soft,var(--vc-background-color,#f7f8fa));border:1px solid var(--docs-border-color,var(--vc-color-light-deeper,#d4d4d8));border-radius:8px;opacity:0;-webkit-transition:opacity .15s ease,background-color .15s ease;transition:opacity .15s ease,background-color .15s ease}.docs-code-preview__copy:hover{background:var(--docs-background-color,var(--vc-background-color-light,#fff))}.docs-code-preview__copy:focus-visible{pointer-events:auto;opacity:1}.docs-code-preview:hover .docs-code-preview__copy{pointer-events:auto;opacity:1}.docs-code-preview__code{width:100%;min-height:0;margin:0;overflow:auto;-webkit-box-flex:1;-webkit-flex:1 1 auto;-ms-flex:1 1 auto;flex:1 1 auto}.docs-code-preview__code,.docs-code-preview__code code.hljs{background:var(--docs-background-color-soft,var(--vc-background-color,#f7f8fa))}.docs-code-preview__code code.hljs{min-height:100%;padding:12px 56px 12px 24px;-webkit-box-sizing:border-box;box-sizing:border-box}";
159
+ var code_preview_default$1 = ".docs-code-preview{position:relative;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;min-height:0;overflow:hidden;background:var(--docs-background-color-soft,var(--vc-background-color,#f7f8fa));border-radius:8px}.docs-code-preview__language{z-index:1;min-width:28px;padding:0 8px;font-size:12px;line-height:18px;white-space:nowrap;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-transition:opacity .15s ease;transition:opacity .15s ease}.docs-code-preview__copy,.docs-code-preview__language{position:absolute;top:6px;right:12px;display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;height:28px;color:var(--docs-foreground-color-mute,var(--vc-color-dark-extralight,#71717a));-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center}.docs-code-preview__copy{z-index:2;width:28px;padding:0;pointer-events:none;cursor:pointer;background:var(--docs-background-color-soft,var(--vc-background-color,#f7f8fa));border:1px solid var(--docs-border-color,var(--vc-color-light-deeper,#d4d4d8));border-radius:8px;opacity:0;-webkit-transition:opacity .15s ease,background-color .15s ease;transition:opacity .15s ease,background-color .15s ease}.docs-code-preview__copy:hover{background:var(--docs-background-color,var(--vc-background-color-light,#fff))}.docs-code-preview__copy:focus-visible{pointer-events:auto;opacity:1}.docs-code-preview:has(.docs-code-preview__copy:focus-visible) .docs-code-preview__language,.docs-code-preview:hover .docs-code-preview__language{opacity:0}.docs-code-preview:has(.docs-code-preview__copy:focus-visible) .docs-code-preview__copy,.docs-code-preview:hover .docs-code-preview__copy{pointer-events:auto;opacity:1}.docs-code-preview__code{width:100%;min-height:0;margin:0;overflow:auto;-webkit-box-flex:1;-webkit-flex:1 1 auto;-ms-flex:1 1 auto;flex:1 1 auto}.docs-code-preview__code,.docs-code-preview__code code.hljs{background:var(--docs-background-color-soft,var(--vc-background-color,#f7f8fa))}.docs-code-preview__code code.hljs{min-height:100%;padding:12px 96px 12px 24px;-webkit-box-sizing:border-box;box-sizing:border-box}";
158
160
  //#endregion
159
161
  //#region packages/playground/src/core/code-preview/style.ts
160
162
  var CODE_PREVIEW_STYLE_ID = "docs-code-preview-style";
@@ -171,10 +173,10 @@ var ensureCodePreviewStyle = () => {
171
173
  };
172
174
  //#endregion
173
175
  //#region packages/playground/src/core/code-preview/code-preview.vue?vue&type=script&setup=true&lang.ts
174
- var _hoisted_1$4 = { class: "docs-code-preview" };
175
- var _hoisted_2$3 = ["title"];
176
- var _hoisted_3$3 = { class: "docs-code-preview__code" };
177
- var _hoisted_4$3 = ["innerHTML"];
176
+ var _hoisted_1$6 = { class: "docs-code-preview" };
177
+ var _hoisted_2$6 = ["title"];
178
+ var _hoisted_3$6 = { class: "docs-code-preview__code" };
179
+ var _hoisted_4$6 = ["innerHTML"];
178
180
  //#endregion
179
181
  //#region packages/playground/src/core/code-preview/code-preview.vue
180
182
  var code_preview_default = /* @__PURE__ */ defineComponent({
@@ -205,12 +207,12 @@ var code_preview_default = /* @__PURE__ */ defineComponent({
205
207
  const highlightLanguage = computed(() => props.language || resolveHighlightLanguage(props.filename));
206
208
  const highlightedCode = computed(() => highlightCodeByLanguage(props.code, highlightLanguage.value));
207
209
  return (_ctx, _cache) => {
208
- return openBlock(), createElementBlock("div", _hoisted_1$4, [
210
+ return openBlock(), createElementBlock("div", _hoisted_1$6, [
209
211
  languageLabel.value ? (openBlock(), createElementBlock("span", {
210
212
  key: 0,
211
213
  class: "docs-code-preview__language",
212
214
  title: languageLabel.value
213
- }, toDisplayString(languageLabel.value), 9, _hoisted_2$3)) : createCommentVNode("v-if", true),
215
+ }, toDisplayString(languageLabel.value), 9, _hoisted_2$6)) : createCommentVNode("v-if", true),
214
216
  createVNode(unref(Clipboard), {
215
217
  class: "docs-code-preview__copy",
216
218
  value: __props.code,
@@ -227,53 +229,23 @@ var code_preview_default = /* @__PURE__ */ defineComponent({
227
229
  "aria-label"
228
230
  ]),
229
231
  createCommentVNode(" eslint-disable-next-line vue/no-v-html "),
230
- createElementVNode("pre", _hoisted_3$3, [createElementVNode("code", {
232
+ createElementVNode("pre", _hoisted_3$6, [createElementVNode("code", {
231
233
  class: "hljs",
232
234
  innerHTML: highlightedCode.value
233
- }, null, 8, _hoisted_4$3)])
235
+ }, null, 8, _hoisted_4$6)])
234
236
  ]);
235
237
  };
236
238
  }
237
239
  });
238
240
  //#endregion
239
- //#region packages/playground/src/utils.ts
240
- /**
241
- * 比较两组 playground 文件是否完全一致。
242
- * @param left 左侧文件表。
243
- * @param right 右侧文件表。
244
- * @returns 键集合与各文件内容是否都相同。
245
- */
246
- var filesEqual = (left, right) => {
247
- const leftKeys = Object.keys(left);
248
- const rightKeys = Object.keys(right);
249
- return leftKeys.length === rightKeys.length && leftKeys.every((key) => left[key] === right[key]);
250
- };
251
- /**
252
- * 视图切换条使用的文案键。
253
- * @param view 当前预览视图。
254
- * @returns locale 消息键。
255
- */
256
- var playgroundViewMessage = (view) => view === "runtime" ? "playground.runtime.preview" : "playground.runtime.files";
257
- //#endregion
258
241
  //#region packages/playground/src/core/files-preview/files-preview.vue?vue&type=script&setup=true&lang.ts
259
- var _hoisted_1$3 = { class: "docs-playground-files" };
260
- var _hoisted_2$2 = { class: "docs-playground-files__toolbar" };
261
- var _hoisted_3$2 = ["data-filename", "onClick"];
262
- var _hoisted_4$2 = {
242
+ var _hoisted_1$5 = { class: "docs-playground-files" };
243
+ var _hoisted_2$5 = { class: "docs-playground-files__tabs-row" };
244
+ var _hoisted_3$5 = ["data-filename", "onClick"];
245
+ var _hoisted_4$5 = {
263
246
  key: 0,
264
247
  class: "docs-playground-files__entry"
265
248
  };
266
- var _hoisted_5$2 = { class: "docs-playground-files__actions" };
267
- var _hoisted_6$2 = {
268
- key: 0,
269
- class: "docs-playground__views docs-playground__views--files"
270
- };
271
- var _hoisted_7$2 = [
272
- "title",
273
- "aria-label",
274
- "aria-pressed",
275
- "onClick"
276
- ];
277
249
  //#endregion
278
250
  //#region packages/playground/src/core/files-preview/files-preview.vue
279
251
  var files_preview_default = /* @__PURE__ */ defineComponent({
@@ -285,28 +257,26 @@ var files_preview_default = /* @__PURE__ */ defineComponent({
285
257
  activeView: {},
286
258
  activeFilename: {}
287
259
  },
288
- emits: ["active-change", "view-change"],
260
+ emits: ["active-change"],
289
261
  setup(__props, { emit: __emit }) {
290
262
  const props = __props;
291
263
  const { t } = useLocale();
292
- const getViewText = (view) => t(playgroundViewMessage(view));
293
264
  const emit = __emit;
294
265
  const filenames = computed(() => Object.keys(props.files));
295
266
  const activeCode = computed(() => props.files[props.activeFilename] || "");
296
267
  const handleActive = (filename) => {
297
268
  if (filename !== props.activeFilename) emit("active-change", filename);
298
269
  };
299
- const handleView = (view) => emit("view-change", view);
300
270
  return (_ctx, _cache) => {
301
- return openBlock(), createElementBlock("div", _hoisted_1$3, [createElementVNode("div", _hoisted_2$2, [createVNode(unref(Scroller), {
271
+ return openBlock(), createElementBlock("div", _hoisted_1$5, [createElementVNode("div", _hoisted_2$5, [createVNode(unref(Scroller), {
302
272
  class: "docs-playground-files__scroller",
303
273
  "auto-resize": true,
304
274
  native: false,
305
275
  "show-bar": true,
306
- height: "44",
276
+ height: "40",
307
277
  "content-class": "docs-playground-files__tabs",
308
- "content-style": "height: 44px; overflow: hidden;",
309
- "wrapper-style": "height: 44px; overflow-x: auto; overflow-y: hidden;"
278
+ "content-style": "height: 40px; overflow: hidden;",
279
+ "wrapper-style": "height: 40px; overflow-x: auto; overflow-y: hidden;"
310
280
  }, {
311
281
  default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(filenames.value, (filename) => {
312
282
  return openBlock(), createElementBlock("button", {
@@ -315,20 +285,10 @@ var files_preview_default = /* @__PURE__ */ defineComponent({
315
285
  class: normalizeClass(["docs-playground-files__tab", { "is-active": filename === __props.activeFilename }]),
316
286
  "data-filename": filename,
317
287
  onClick: ($event) => handleActive(filename)
318
- }, [createElementVNode("span", null, toDisplayString(filename), 1), filename === __props.entry ? (openBlock(), createElementBlock("small", _hoisted_4$2, toDisplayString(unref(t)("playground.files.entry")), 1)) : createCommentVNode("v-if", true)], 10, _hoisted_3$2);
288
+ }, [createElementVNode("span", null, toDisplayString(filename), 1), filename === __props.entry ? (openBlock(), createElementBlock("small", _hoisted_4$5, toDisplayString(unref(t)("playground.files.entry")), 1)) : createCommentVNode("v-if", true)], 10, _hoisted_3$5);
319
289
  }), 128))]),
320
290
  _: 1
321
- }), createElementVNode("div", _hoisted_5$2, [__props.views.length > 1 ? (openBlock(), createElementBlock("div", _hoisted_6$2, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.views, (item) => {
322
- return openBlock(), createElementBlock("button", {
323
- key: item,
324
- type: "button",
325
- class: normalizeClass(["docs-playground__view", { "is-active": item === __props.activeView }]),
326
- title: getViewText(item),
327
- "aria-label": getViewText(item),
328
- "aria-pressed": item === __props.activeView,
329
- onClick: ($event) => handleView(item)
330
- }, [createVNode(unref(icon_default), { name: item }, null, 8, ["name"])], 10, _hoisted_7$2);
331
- }), 128))])) : createCommentVNode("v-if", true)])]), createVNode(unref(code_preview_default), {
291
+ })]), createVNode(unref(code_preview_default), {
332
292
  class: "docs-playground-files__body",
333
293
  code: activeCode.value,
334
294
  filename: __props.activeFilename,
@@ -459,25 +419,26 @@ var Drag = class {
459
419
  };
460
420
  //#endregion
461
421
  //#region packages/playground/src/editor/editor.vue?vue&type=script&setup=true&lang.ts
462
- var _hoisted_1$2 = { class: "docs-playground-editor" };
463
- var _hoisted_2$1 = ["title"];
464
- var _hoisted_3$1 = { class: "docs-playground-editor__files" };
465
- var _hoisted_4$1 = [
422
+ var _hoisted_1$4 = { class: "docs-playground-editor" };
423
+ var _hoisted_2$4 = ["title"];
424
+ var _hoisted_3$4 = { class: "docs-playground-editor__files" };
425
+ var _hoisted_4$4 = [
466
426
  "data-filename",
467
427
  "onClick",
468
428
  "onDblclick"
469
429
  ];
470
- var _hoisted_5$1 = ["onKeydown"];
471
- var _hoisted_6$1 = ["title"];
472
- var _hoisted_7$1 = ["title", "aria-label"];
473
- var _hoisted_8$1 = ["title", "aria-label"];
474
- var _hoisted_9$1 = { class: "docs-playground-editor__actions" };
430
+ var _hoisted_5$4 = ["onKeydown"];
431
+ var _hoisted_6$3 = ["title"];
432
+ var _hoisted_7$3 = ["title", "aria-label"];
433
+ var _hoisted_8$2 = ["title", "aria-label"];
434
+ var _hoisted_9$2 = { class: "docs-playground-editor__actions" };
475
435
  var _hoisted_10$1 = ["title"];
476
436
  var _hoisted_11$1 = ["title", "disabled"];
477
- var _hoisted_12 = {
437
+ var _hoisted_12$1 = {
478
438
  key: 0,
479
439
  class: "docs-playground-editor__error"
480
440
  };
441
+ var EDITOR_SCROLLER_MAX_HEIGHT = "calc(100vh - 110px)";
481
442
  //#endregion
482
443
  //#region packages/playground/src/editor/index.ts
483
444
  var Editor = new Portal(/* @__PURE__ */ defineComponent({
@@ -506,6 +467,7 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
506
467
  },
507
468
  setup(__props) {
508
469
  const SUPPORTED_FILE_RE = /\.(vue|js|ts|jsx|tsx|css|s[ac]ss|json|html)$/i;
470
+ /** 浮层留白 20px + 标题栏 44px + 文件栏 46px,避免大文件把标签栏挤扁。 */
509
471
  const props = __props;
510
472
  const { t } = useLocale(computed(() => props.locale));
511
473
  const initialFiles = Object.keys(props.files).length ? props.files : { "App.vue": props.value };
@@ -517,6 +479,7 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
517
479
  const textarea = ref(null);
518
480
  const filenameInput = ref(null);
519
481
  const scroller = ref(null);
482
+ const editorScroller = ref(null);
520
483
  const editor = ref(null);
521
484
  const bar = ref(null);
522
485
  const wrapper = ref(null);
@@ -524,6 +487,10 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
524
487
  const renamingFilename = ref("");
525
488
  const filenameDraft = ref("");
526
489
  const codeErrorText = computed(() => props.getCodeErrors().map((item) => item instanceof Error ? item.message : item).join("\n"));
490
+ let editorResize;
491
+ const refreshEditorScroller = () => {
492
+ editorScroller.value?.refresh();
493
+ };
527
494
  const setFilenameInput = (el) => {
528
495
  filenameInput.value = el instanceof HTMLInputElement ? el : null;
529
496
  };
@@ -561,11 +528,13 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
561
528
  filename
562
529
  });
563
530
  if (filename === currentEntry.value) props.onChange(code);
531
+ nextTick(refreshEditorScroller);
564
532
  })
565
533
  ],
566
534
  parent: textarea.value
567
535
  });
568
536
  editor.value.focus();
537
+ nextTick(refreshEditorScroller);
569
538
  };
570
539
  const handleActive = (filename) => {
571
540
  if (filename === activeFilename.value || editorFiles.value[filename] === void 0) return;
@@ -689,13 +658,18 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
689
658
  wrapper: wrapper.value,
690
659
  container: window
691
660
  });
661
+ if (typeof ResizeObserver !== "undefined") {
662
+ editorResize = new ResizeObserver(refreshEditorScroller);
663
+ editorResize.observe(textarea.value);
664
+ }
692
665
  });
693
666
  onBeforeUnmount(() => {
667
+ editorResize?.disconnect();
694
668
  drag.value?.off();
695
669
  editor.value?.destroy();
696
670
  });
697
671
  return (_ctx, _cache) => {
698
- return openBlock(), createElementBlock("div", _hoisted_1$2, [createVNode(unref(TransitionFade), { onAfterLeave: handleHide }, {
672
+ return openBlock(), createElementBlock("div", _hoisted_1$4, [createVNode(unref(TransitionFade), { onAfterLeave: handleHide }, {
699
673
  default: withCtx(() => [withDirectives(createElementVNode("div", {
700
674
  ref_key: "wrapper",
701
675
  ref: wrapper,
@@ -712,8 +686,8 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
712
686
  title: unref(t)("playground.common.close"),
713
687
  style: { "cursor": "pointer" },
714
688
  onClick: handleHide
715
- }, "✕", 8, _hoisted_2$1)], 512),
716
- createElementVNode("div", _hoisted_3$1, [createVNode(unref(Scroller), {
689
+ }, "✕", 8, _hoisted_2$4)], 512),
690
+ createElementVNode("div", _hoisted_3$4, [createVNode(unref(Scroller), {
717
691
  ref_key: "scroller",
718
692
  ref: scroller,
719
693
  class: "docs-playground-editor__scroller",
@@ -741,11 +715,11 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
741
715
  onDblclick: _cache[2] || (_cache[2] = withModifiers(() => {}, ["stop"])),
742
716
  onBlur: handleRenameSubmit,
743
717
  onKeydown: [withKeys(withModifiers(handleRenameSubmit, ["prevent"]), ["enter"]), withKeys(withModifiers(handleRenameCancel, ["prevent"]), ["esc"])]
744
- }, null, 40, _hoisted_5$1)), [[vModelText, filenameDraft.value]]) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
718
+ }, null, 40, _hoisted_5$4)), [[vModelText, filenameDraft.value]]) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
745
719
  filename === currentEntry.value ? (openBlock(), createElementBlock("span", {
746
720
  key: 0,
747
721
  title: unref(t)("playground.editor.entry")
748
- }, "●", 8, _hoisted_6$1)) : createCommentVNode("v-if", true),
722
+ }, "●", 8, _hoisted_6$3)) : createCommentVNode("v-if", true),
749
723
  createElementVNode("span", null, toDisplayString(filename), 1),
750
724
  filename === currentEntry.value ? (openBlock(), createElementBlock("button", {
751
725
  key: 1,
@@ -754,7 +728,7 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
754
728
  title: unref(t)("playground.editor.entryCannotDelete"),
755
729
  "aria-label": unref(t)("playground.editor.entryCannotDelete"),
756
730
  disabled: ""
757
- }, null, 8, _hoisted_7$1)) : (openBlock(), createBlock(unref(Popconfirm), {
731
+ }, null, 8, _hoisted_7$3)) : (openBlock(), createBlock(unref(Popconfirm), {
758
732
  key: 2,
759
733
  class: "docs-playground-editor__delete",
760
734
  title: unref(t)("playground.editor.confirmDelete", { filename }),
@@ -767,13 +741,13 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
767
741
  class: "docs-playground-editor__close",
768
742
  title: unref(t)("playground.editor.deleteFile"),
769
743
  "aria-label": unref(t)("playground.editor.confirmDelete", { filename })
770
- }, null, 8, _hoisted_8$1)]),
744
+ }, null, 8, _hoisted_8$2)]),
771
745
  _: 2
772
746
  }, 1032, ["title", "onOk"]))
773
- ], 64))], 42, _hoisted_4$1);
747
+ ], 64))], 42, _hoisted_4$4);
774
748
  }), 128))]),
775
749
  _: 1
776
- }, 512), createElementVNode("div", _hoisted_9$1, [createElementVNode("button", {
750
+ }, 512), createElementVNode("div", _hoisted_9$2, [createElementVNode("button", {
777
751
  type: "button",
778
752
  title: unref(t)("playground.editor.createFile"),
779
753
  onClick: handleCreate
@@ -783,18 +757,74 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
783
757
  disabled: activeFilename.value === currentEntry.value,
784
758
  onClick: handleEntry
785
759
  }, toDisplayString(unref(t)("playground.editor.setEntry")), 9, _hoisted_11$1)])]),
786
- codeErrorText.value ? (openBlock(), createElementBlock("div", _hoisted_12, toDisplayString(codeErrorText.value), 1)) : createCommentVNode("v-if", true),
787
- createElementVNode("div", {
788
- ref_key: "textarea",
789
- ref: textarea,
790
- class: "docs-playground-editor__editor"
791
- }, null, 512)
760
+ codeErrorText.value ? (openBlock(), createElementBlock("div", _hoisted_12$1, toDisplayString(codeErrorText.value), 1)) : createCommentVNode("v-if", true),
761
+ createVNode(unref(Scroller), {
762
+ ref_key: "editorScroller",
763
+ ref: editorScroller,
764
+ class: "docs-playground-editor__body",
765
+ "auto-resize": true,
766
+ native: false,
767
+ "show-bar": true,
768
+ always: true,
769
+ "max-height": EDITOR_SCROLLER_MAX_HEIGHT
770
+ }, {
771
+ default: withCtx(() => [createElementVNode("div", {
772
+ ref_key: "textarea",
773
+ ref: textarea,
774
+ class: "docs-playground-editor__editor"
775
+ }, null, 512)]),
776
+ _: 1
777
+ }, 512)
792
778
  ], 512), [[vShow, isActive.value]])]),
793
779
  _: 1
794
780
  })]);
795
781
  };
796
782
  }
797
783
  }), { aliveRegExp: { className: /(PORTAL_TAG_DISABLE)/ } });
784
+ //#endregion
785
+ //#region packages/playground/src/utils.ts
786
+ /**
787
+ * 比较两组 playground 文件是否完全一致。
788
+ * @param left 左侧文件表。
789
+ * @param right 右侧文件表。
790
+ * @returns 键集合与各文件内容是否都相同。
791
+ */
792
+ var filesEqual = (left, right) => {
793
+ const leftKeys = Object.keys(left);
794
+ const rightKeys = Object.keys(right);
795
+ return leftKeys.length === rightKeys.length && leftKeys.every((key) => left[key] === right[key]);
796
+ };
797
+ /**
798
+ * 视图切换条使用的文案键。
799
+ * @param view 当前预览视图。
800
+ * @returns locale 消息键。
801
+ */
802
+ var playgroundViewMessage = (view) => view === "runtime" ? "playground.runtime.preview" : "playground.runtime.files";
803
+ /**
804
+ * 与 markdown-it-anchor 默认 `slugify` 对齐,用于标题锚点 id。
805
+ * @param title 标题文本。
806
+ * @returns 可用作元素 id / hash 的字符串;空标题返回空串。
807
+ */
808
+ var slugifyPlaygroundTitle = (title) => {
809
+ const normalized = String(title).trim().toLowerCase().replace(/\s+/g, "-");
810
+ return normalized ? encodeURIComponent(normalized) : "";
811
+ };
812
+ /**
813
+ * 解析标题锚点 id:显式 id 优先,否则从标题 slugify;必要时避开已占用 id。
814
+ * @param title 标题文本。
815
+ * @param explicitId 可选显式 id。
816
+ * @param isOccupied 返回该 id 是否已被其他元素占用。
817
+ * @returns 锚点 id;无标题时为空串。
818
+ */
819
+ var resolvePlaygroundTitleId = (title, explicitId = "", isOccupied) => {
820
+ if (!String(title).trim()) return "";
821
+ const base = String(explicitId).trim() || slugifyPlaygroundTitle(title);
822
+ if (!base) return "";
823
+ if (!isOccupied || !isOccupied(base)) return base;
824
+ let index = 1;
825
+ while (isOccupied(`${base}-${index}`)) index += 1;
826
+ return `${base}-${index}`;
827
+ };
798
828
  var resolveSandboxContainer = (sandbox) => sandbox?.container ? unref(sandbox.container) : null;
799
829
  var useSandboxAutoHeight = (sandboxRef) => {
800
830
  const height = ref(24);
@@ -904,6 +934,77 @@ var useSandboxAutoHeight = (sandboxRef) => {
904
934
  });
905
935
  return height;
906
936
  };
937
+ var CLIPPING_OVERFLOW = /* @__PURE__ */ new Set([
938
+ "auto",
939
+ "scroll",
940
+ "hidden",
941
+ "overlay"
942
+ ]);
943
+ var SCROLLABLE_OVERFLOW = /* @__PURE__ */ new Set([
944
+ "auto",
945
+ "scroll",
946
+ "overlay"
947
+ ]);
948
+ var getWindowInnerHeight = () => typeof window === "undefined" ? 0 : window.innerHeight;
949
+ var getPlaygroundHost = (el) => el?.closest(".docs-playground") ?? el;
950
+ var isPlaygroundExpandable = (value) => {
951
+ if (value === true) return true;
952
+ return typeof value === "number" && Number.isFinite(value) && value > 0;
953
+ };
954
+ var resolveRemainingPreviewHeight = ({ viewportHeight, chromeHeight, gap = 16 }) => Math.max(0, Math.round((Number.isFinite(viewportHeight) ? viewportHeight : 0) - (Number.isFinite(chromeHeight) ? Math.max(0, chromeHeight) : 0) - (Number.isFinite(gap) ? gap : 16)));
955
+ var resolveExpandedPreviewHeight = (expandable, availableHeight) => {
956
+ if (expandable === true) return Math.max(24, Math.round(Number.isFinite(availableHeight) ? availableHeight : 0));
957
+ return Math.max(24, Math.round(expandable));
958
+ };
959
+ var getVisibleViewportRect = (el) => {
960
+ const viewportHeight = getWindowInnerHeight();
961
+ let top = 0;
962
+ let bottom = viewportHeight;
963
+ if (typeof window === "undefined" || !el) return {
964
+ top,
965
+ bottom,
966
+ height: Math.max(0, Math.round(bottom - top))
967
+ };
968
+ let node = getPlaygroundHost(el)?.parentElement ?? null;
969
+ while (node && node !== document.documentElement) {
970
+ const overflowY = getComputedStyle(node).overflowY;
971
+ if (CLIPPING_OVERFLOW.has(overflowY)) {
972
+ const rect = node.getBoundingClientRect();
973
+ if (Number.isFinite(rect.top)) top = Math.max(top, rect.top);
974
+ if (Number.isFinite(rect.bottom)) bottom = Math.min(bottom, rect.bottom);
975
+ }
976
+ node = node.parentElement;
977
+ }
978
+ return {
979
+ top,
980
+ bottom,
981
+ height: Math.max(0, Math.round(bottom - top))
982
+ };
983
+ };
984
+ var findScrollableAncestor = (el) => {
985
+ if (!el || typeof window === "undefined") return null;
986
+ let node = getPlaygroundHost(el)?.parentElement ?? null;
987
+ while (node && node !== document.documentElement) {
988
+ const overflowY = getComputedStyle(node).overflowY;
989
+ if (SCROLLABLE_OVERFLOW.has(overflowY) && node.scrollHeight > node.clientHeight + 1) return node;
990
+ node = node.parentElement;
991
+ }
992
+ return null;
993
+ };
994
+ var scrollPlaygroundToViewportStart = (el) => {
995
+ if (!el) return;
996
+ const host = getPlaygroundHost(el) ?? el;
997
+ const scroller = findScrollableAncestor(host);
998
+ if (scroller) {
999
+ const delta = host.getBoundingClientRect().top - scroller.getBoundingClientRect().top;
1000
+ scroller.scrollTop = Math.max(0, scroller.scrollTop + delta);
1001
+ return;
1002
+ }
1003
+ if (typeof host.scrollIntoView === "function") host.scrollIntoView({
1004
+ block: "start",
1005
+ behavior: "auto"
1006
+ });
1007
+ };
907
1008
  //#endregion
908
1009
  //#region packages/playground/src/core/runtime/error-guard.ts
909
1010
  var UNKNOWN_RUNTIME_ERROR = "运行时发生未知错误";
@@ -967,6 +1068,96 @@ var useSandboxRuntimeErrorGuard = (sandboxRef) => {
967
1068
  return error;
968
1069
  };
969
1070
  //#endregion
1071
+ //#region packages/playground/src/core/runtime/viewport.ts
1072
+ var DEFAULT_VIEWPORT_OPTIONS = ["auto", 375];
1073
+ var isValidViewport = (viewport) => {
1074
+ if (viewport === "auto") return true;
1075
+ if (typeof viewport === "number") return Number.isFinite(viewport) && viewport > 0;
1076
+ return Array.isArray(viewport) && viewport.length === 2 && viewport.every((value) => typeof value === "number" && Number.isFinite(value) && value > 0);
1077
+ };
1078
+ var getViewportKey = (viewport) => Array.isArray(viewport) ? `${viewport[0]}x${viewport[1]}` : String(viewport);
1079
+ var viewportEquals = (left, right) => getViewportKey(left) === getViewportKey(right);
1080
+ var cloneViewport = (viewport) => Array.isArray(viewport) ? [viewport[0], viewport[1]] : viewport;
1081
+ var normalizeViewportOptions = (options) => {
1082
+ const source = options === void 0 ? DEFAULT_VIEWPORT_OPTIONS : options;
1083
+ const normalized = [];
1084
+ for (const viewport of source) {
1085
+ if (!isValidViewport(viewport)) continue;
1086
+ if (normalized.some((item) => viewportEquals(item, viewport))) continue;
1087
+ normalized.push(cloneViewport(viewport));
1088
+ }
1089
+ return normalized;
1090
+ };
1091
+ var resolveInitialViewport = (viewport, options) => isValidViewport(viewport) ? cloneViewport(viewport) : cloneViewport(options[0] || "auto");
1092
+ var includeActiveViewport = (options, viewport) => {
1093
+ if (!options.length || options.some((item) => viewportEquals(item, viewport))) return options;
1094
+ return [...options, cloneViewport(viewport)];
1095
+ };
1096
+ var getViewportWidth = (viewport) => {
1097
+ if (viewport === "auto") return null;
1098
+ return Array.isArray(viewport) ? viewport[0] : viewport;
1099
+ };
1100
+ var getViewportHeight = (viewport) => Array.isArray(viewport) ? viewport[1] : null;
1101
+ var formatViewportLabel = (viewport, autoLabel = "Auto") => {
1102
+ if (viewport === "auto") return autoLabel;
1103
+ return Array.isArray(viewport) ? `${viewport[0]} × ${viewport[1]}px` : `${viewport}px`;
1104
+ };
1105
+ var resolvePopupScreenInset = (gap = 40) => {
1106
+ const safeGap = Number.isFinite(gap) ? Math.max(0, gap) : 40;
1107
+ return {
1108
+ x: safeGap * 2,
1109
+ y: safeGap
1110
+ };
1111
+ };
1112
+ var getWindowInnerSize = () => {
1113
+ if (typeof window === "undefined") return {
1114
+ width: 0,
1115
+ height: 0
1116
+ };
1117
+ return {
1118
+ width: window.innerWidth,
1119
+ height: window.innerHeight
1120
+ };
1121
+ };
1122
+ var resolvePopupRequestedSize = (viewport, screen = getWindowInnerSize(), gap = 40) => {
1123
+ const inset = resolvePopupScreenInset(gap);
1124
+ const maxWidth = Math.max(0, Math.round((Number.isFinite(screen.width) ? screen.width : 0) - inset.x));
1125
+ const maxHeight = Math.max(0, Math.round((Number.isFinite(screen.height) ? screen.height : 0) - inset.y));
1126
+ const viewportWidth = getViewportWidth(viewport);
1127
+ const viewportHeight = getViewportHeight(viewport);
1128
+ return {
1129
+ width: viewportWidth ?? maxWidth,
1130
+ height: viewportHeight ?? maxHeight,
1131
+ maxWidth,
1132
+ maxHeight
1133
+ };
1134
+ };
1135
+ /**
1136
+ * 壳层封顶到 `screen.width - gap * 2`、`screen.height - gap`。
1137
+ * 未设 viewport 边时,画布铺满工具栏以下区域;请求尺寸大于可用区域时由 Scroller 处理溢出。
1138
+ * @param viewport 当前 playground 视口配置。
1139
+ * @param screen 屏幕可用宽高,默认取 `window.inner*`。
1140
+ * @param gap 相对屏幕上下边缘的留白;左右为该值的 2 倍。
1141
+ * @returns 壳层、内容区与画布尺寸,以及是否需要滚动。
1142
+ */
1143
+ var resolvePopupLayout = (viewport, screen = getWindowInnerSize(), gap = 40) => {
1144
+ const requested = resolvePopupRequestedSize(viewport, screen, gap);
1145
+ const shellWidth = Math.min(requested.width, requested.maxWidth);
1146
+ const shellHeight = Math.min(requested.height, requested.maxHeight);
1147
+ const bodyHeight = Math.max(0, shellHeight - 44);
1148
+ const canvasWidth = getViewportWidth(viewport) ?? shellWidth;
1149
+ const canvasHeight = getViewportHeight(viewport) ?? bodyHeight;
1150
+ return {
1151
+ shellWidth,
1152
+ shellHeight,
1153
+ bodyHeight,
1154
+ canvasWidth,
1155
+ canvasHeight,
1156
+ needsScrollX: canvasWidth > shellWidth,
1157
+ needsScrollY: canvasHeight > bodyHeight
1158
+ };
1159
+ };
1160
+ //#endregion
970
1161
  //#region packages/playground/src/core/runtime/theme.ts
971
1162
  var resolveElementTheme = (element) => {
972
1163
  const vcTheme = element?.getAttribute("data-vc-theme");
@@ -1059,40 +1250,221 @@ var useSandboxTheme = (sandboxRef) => {
1059
1250
  });
1060
1251
  };
1061
1252
  //#endregion
1062
- //#region packages/playground/src/core/runtime/viewport.ts
1063
- var DEFAULT_VIEWPORT_OPTIONS = ["auto", 375];
1064
- var isValidViewport = (viewport) => {
1065
- if (viewport === "auto") return true;
1066
- if (typeof viewport === "number") return Number.isFinite(viewport) && viewport > 0;
1067
- return Array.isArray(viewport) && viewport.length === 2 && viewport.every((value) => typeof value === "number" && Number.isFinite(value) && value > 0);
1253
+ //#region packages/playground/src/core/runtime/toolbar.vue?vue&type=script&setup=true&lang.ts
1254
+ var _hoisted_1$3 = { class: "docs-playground__tools" };
1255
+ var _hoisted_2$3 = {
1256
+ key: 0,
1257
+ class: "docs-playground__tool-group"
1068
1258
  };
1069
- var getViewportKey = (viewport) => Array.isArray(viewport) ? `${viewport[0]}x${viewport[1]}` : String(viewport);
1070
- var viewportEquals = (left, right) => getViewportKey(left) === getViewportKey(right);
1071
- var cloneViewport = (viewport) => Array.isArray(viewport) ? [viewport[0], viewport[1]] : viewport;
1072
- var normalizeViewportOptions = (options) => {
1073
- const source = options === void 0 ? DEFAULT_VIEWPORT_OPTIONS : options;
1074
- const normalized = [];
1075
- for (const viewport of source) {
1076
- if (!isValidViewport(viewport)) continue;
1077
- if (normalized.some((item) => viewportEquals(item, viewport))) continue;
1078
- normalized.push(cloneViewport(viewport));
1079
- }
1080
- return normalized;
1259
+ var _hoisted_3$3 = [
1260
+ "title",
1261
+ "aria-label",
1262
+ "aria-expanded"
1263
+ ];
1264
+ var _hoisted_4$3 = {
1265
+ key: 1,
1266
+ class: "docs-playground__tool-divider",
1267
+ "aria-hidden": "true"
1081
1268
  };
1082
- var resolveInitialViewport = (viewport, options) => isValidViewport(viewport) ? cloneViewport(viewport) : cloneViewport(options[0] || "auto");
1083
- var includeActiveViewport = (options, viewport) => {
1084
- if (!options.length || options.some((item) => viewportEquals(item, viewport))) return options;
1085
- return [...options, cloneViewport(viewport)];
1269
+ var _hoisted_5$3 = ["title", "aria-label"];
1270
+ var _hoisted_6$2 = ["title", "aria-label"];
1271
+ var _hoisted_7$2 = ["title", "aria-label"];
1272
+ var _hoisted_8$1 = {
1273
+ key: 3,
1274
+ class: "docs-playground__tool-divider",
1275
+ "aria-hidden": "true"
1086
1276
  };
1087
- var getViewportWidth = (viewport) => {
1088
- if (viewport === "auto") return null;
1089
- return Array.isArray(viewport) ? viewport[0] : viewport;
1090
- };
1091
- var getViewportHeight = (viewport) => Array.isArray(viewport) ? viewport[1] : null;
1092
- var formatViewportLabel = (viewport, autoLabel = "Auto") => {
1093
- if (viewport === "auto") return autoLabel;
1094
- return Array.isArray(viewport) ? `${viewport[0]} × ${viewport[1]}px` : `${viewport}px`;
1277
+ var _hoisted_9$1 = ["aria-label"];
1278
+ var _hoisted_10 = [
1279
+ "title",
1280
+ "aria-label",
1281
+ "aria-selected",
1282
+ "aria-pressed",
1283
+ "onClick"
1284
+ ];
1285
+ var _hoisted_11 = {
1286
+ key: 2,
1287
+ class: "docs-playground__tool-divider",
1288
+ "aria-hidden": "true"
1095
1289
  };
1290
+ var _hoisted_12 = ["title", "aria-label"];
1291
+ //#endregion
1292
+ //#region packages/playground/src/core/runtime/toolbar.vue
1293
+ var toolbar_default = /* @__PURE__ */ defineComponent({
1294
+ __name: "toolbar",
1295
+ props: {
1296
+ copyValue: { default: "" },
1297
+ viewport: { default: "auto" },
1298
+ viewportOptions: { default: () => ["auto", 375] },
1299
+ views: { default: () => [] },
1300
+ activeView: { default: "runtime" },
1301
+ showRuntimeActions: {
1302
+ type: Boolean,
1303
+ default: true
1304
+ },
1305
+ showOpenPopup: {
1306
+ type: Boolean,
1307
+ default: false
1308
+ },
1309
+ showClose: {
1310
+ type: Boolean,
1311
+ default: false
1312
+ }
1313
+ },
1314
+ emits: [
1315
+ "refresh",
1316
+ "edit",
1317
+ "open-popup",
1318
+ "close-popup",
1319
+ "viewport-change",
1320
+ "view-change"
1321
+ ],
1322
+ setup(__props, { emit: __emit }) {
1323
+ const props = __props;
1324
+ const emit = __emit;
1325
+ const { t } = useLocale();
1326
+ const VIEW_ORDER = ["runtime", "files"];
1327
+ const viewportMenuVisible = ref(false);
1328
+ const orderedViews = computed(() => VIEW_ORDER.filter((view) => props.views.includes(view)));
1329
+ const showViews = computed(() => orderedViews.value.length > 1);
1330
+ const viewportLabel = computed(() => formatViewportLabel(props.viewport, t("playground.runtime.auto")));
1331
+ const getViewAriaLabel = (view) => t(playgroundViewMessage(view));
1332
+ const getViewLabel = (view) => view === "runtime" ? t("playground.runtime.previewLabel") : t("playground.runtime.codeLabel");
1333
+ const handleViewport = (index) => {
1334
+ const viewport = props.viewportOptions[index];
1335
+ if (viewport && !viewportEquals(viewport, props.viewport)) emit("viewport-change", viewport);
1336
+ };
1337
+ watch(() => props.viewportOptions.length, (length) => {
1338
+ if (length <= 1) viewportMenuVisible.value = false;
1339
+ });
1340
+ watch(() => props.showRuntimeActions, (enabled) => {
1341
+ if (!enabled) viewportMenuVisible.value = false;
1342
+ });
1343
+ return (_ctx, _cache) => {
1344
+ return openBlock(), createElementBlock("div", _hoisted_1$3, [
1345
+ __props.showRuntimeActions ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
1346
+ __props.viewportOptions.length > 1 ? (openBlock(), createElementBlock("div", _hoisted_2$3, [createVNode(unref(Dropdown), {
1347
+ modelValue: viewportMenuVisible.value,
1348
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => viewportMenuVisible.value = $event),
1349
+ class: "docs-playground__viewport-menu",
1350
+ portal: true,
1351
+ trigger: "click",
1352
+ placement: "bottom-right"
1353
+ }, {
1354
+ content: withCtx(() => [createVNode(unref(DropdownMenu), {
1355
+ class: "docs-playground__viewport-options",
1356
+ role: "menu",
1357
+ "aria-label": unref(t)("playground.runtime.viewportMenu")
1358
+ }, {
1359
+ default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.viewportOptions, (item, index) => {
1360
+ return openBlock(), createBlock(unref(DropdownItem), {
1361
+ key: unref(getViewportKey)(item),
1362
+ class: "docs-playground__viewport-option",
1363
+ value: index,
1364
+ selected: unref(viewportEquals)(item, __props.viewport),
1365
+ role: "menuitemradio",
1366
+ "aria-checked": unref(viewportEquals)(item, __props.viewport),
1367
+ onClick: ($event) => handleViewport(index)
1368
+ }, {
1369
+ default: withCtx(() => [createTextVNode(toDisplayString(unref(formatViewportLabel)(item, unref(t)("playground.runtime.auto"))), 1)]),
1370
+ _: 2
1371
+ }, 1032, [
1372
+ "value",
1373
+ "selected",
1374
+ "aria-checked",
1375
+ "onClick"
1376
+ ]);
1377
+ }), 128))]),
1378
+ _: 1
1379
+ }, 8, ["aria-label"])]),
1380
+ default: withCtx(() => [createElementVNode("button", {
1381
+ type: "button",
1382
+ class: normalizeClass(["docs-playground__tool docs-playground__viewport-trigger", { "is-active": __props.viewport !== "auto" }]),
1383
+ title: unref(t)("playground.runtime.viewport", { value: viewportLabel.value }),
1384
+ "aria-label": unref(t)("playground.runtime.viewport", { value: viewportLabel.value }),
1385
+ "aria-expanded": viewportMenuVisible.value,
1386
+ "aria-haspopup": "menu"
1387
+ }, [createVNode(unref(icon_default), { name: "viewport" })], 10, _hoisted_3$3)]),
1388
+ _: 1
1389
+ }, 8, ["modelValue"])])) : createCommentVNode("v-if", true),
1390
+ __props.viewportOptions.length > 1 ? (openBlock(), createElementBlock("span", _hoisted_4$3)) : createCommentVNode("v-if", true),
1391
+ createElementVNode("button", {
1392
+ type: "button",
1393
+ class: "docs-playground__tool docs-playground__refresh",
1394
+ "data-action": "refresh",
1395
+ title: unref(t)("playground.runtime.refresh"),
1396
+ "aria-label": unref(t)("playground.runtime.refresh"),
1397
+ onClick: _cache[1] || (_cache[1] = ($event) => emit("refresh"))
1398
+ }, [createVNode(unref(icon_default), { name: "refresh" })], 8, _hoisted_5$3),
1399
+ createElementVNode("button", {
1400
+ type: "button",
1401
+ class: "docs-playground__tool docs-playground__editor",
1402
+ "data-action": "edit",
1403
+ title: unref(t)("playground.runtime.editFiles"),
1404
+ "aria-label": unref(t)("playground.runtime.editFiles"),
1405
+ onClick: _cache[2] || (_cache[2] = ($event) => emit("edit"))
1406
+ }, [createVNode(unref(icon_default), { name: "editor" })], 8, _hoisted_6$2),
1407
+ __props.showOpenPopup ? (openBlock(), createElementBlock("button", {
1408
+ key: 2,
1409
+ type: "button",
1410
+ class: "docs-playground__tool docs-playground__popup",
1411
+ "data-action": "open-popup",
1412
+ title: unref(t)("playground.runtime.openPopup"),
1413
+ "aria-label": unref(t)("playground.runtime.openPopup"),
1414
+ onClick: _cache[3] || (_cache[3] = ($event) => emit("open-popup"))
1415
+ }, [createVNode(unref(icon_default), { name: "popup" })], 8, _hoisted_7$2)) : createCommentVNode("v-if", true),
1416
+ createVNode(unref(Clipboard), {
1417
+ class: "docs-playground__tool",
1418
+ value: __props.copyValue,
1419
+ tag: "button",
1420
+ type: "button",
1421
+ title: unref(t)("playground.common.copy"),
1422
+ "aria-label": unref(t)("playground.common.copy")
1423
+ }, {
1424
+ default: withCtx(() => [createVNode(unref(icon_default), { name: "copy" })]),
1425
+ _: 1
1426
+ }, 8, [
1427
+ "value",
1428
+ "title",
1429
+ "aria-label"
1430
+ ]),
1431
+ showViews.value ? (openBlock(), createElementBlock("span", _hoisted_8$1)) : createCommentVNode("v-if", true)
1432
+ ], 64)) : createCommentVNode("v-if", true),
1433
+ showViews.value ? (openBlock(), createElementBlock("div", {
1434
+ key: 1,
1435
+ class: "docs-playground__views",
1436
+ role: "tablist",
1437
+ "aria-label": unref(t)("playground.runtime.views")
1438
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(orderedViews.value, (item) => {
1439
+ return openBlock(), createElementBlock("button", {
1440
+ key: item,
1441
+ type: "button",
1442
+ class: normalizeClass(["docs-playground__view", { "is-active": item === __props.activeView }]),
1443
+ role: "tab",
1444
+ title: getViewAriaLabel(item),
1445
+ "aria-label": getViewAriaLabel(item),
1446
+ "aria-selected": item === __props.activeView,
1447
+ "aria-pressed": item === __props.activeView,
1448
+ onClick: ($event) => emit("view-change", item)
1449
+ }, toDisplayString(getViewLabel(item)), 11, _hoisted_10);
1450
+ }), 128))], 8, _hoisted_9$1)) : createCommentVNode("v-if", true),
1451
+ __props.showClose && (__props.showRuntimeActions || showViews.value) ? (openBlock(), createElementBlock("span", _hoisted_11)) : createCommentVNode("v-if", true),
1452
+ __props.showClose ? (openBlock(), createElementBlock("button", {
1453
+ key: 3,
1454
+ type: "button",
1455
+ class: "docs-playground__tool docs-playground__popup-close",
1456
+ "data-action": "close-popup",
1457
+ title: unref(t)("playground.runtime.closePopup"),
1458
+ "aria-label": unref(t)("playground.runtime.closePopup"),
1459
+ onClick: _cache[4] || (_cache[4] = ($event) => emit("close-popup"))
1460
+ }, [..._cache[5] || (_cache[5] = [createElementVNode("span", {
1461
+ class: "docs-playground__popup-close-mark",
1462
+ "aria-hidden": "true"
1463
+ }, "✕", -1)])], 8, _hoisted_12)) : createCommentVNode("v-if", true)
1464
+ ]);
1465
+ };
1466
+ }
1467
+ });
1096
1468
  //#endregion
1097
1469
  //#region packages/playground/src/cdn.ts
1098
1470
  var PREVIEW_STYLE_ASSETS = [
@@ -1441,6 +1813,12 @@ var DOCS_LINK_USE_CODE = [
1441
1813
  "})"
1442
1814
  ].join("");
1443
1815
  var escapeHtmlAttr = (value) => value.replace(/&/gu, "&amp;").replace(/"/gu, "&quot;").replace(/'/gu, "&#39;").replace(/</gu, "&lt;").replace(/>/gu, "&gt;");
1816
+ /**
1817
+ * runtime 画布色。`previewInset` 露出的 padding、iframe chrome 和 sandbox
1818
+ * `html`/`body` 必须共用这一变量,暗色下 `--docs-background-color` 与
1819
+ * `--vc-background-color-light` 不同,否则会出现色带割裂。
1820
+ */
1821
+ var PLAYGROUND_RUNTIME_CANVAS_BACKGROUND = "var(--vc-background-color-light, var(--docs-background-color, #fff))";
1444
1822
  var createRuntimePreviewOptions = (cdnURL = DEFAULT_CDN_URL) => {
1445
1823
  return {
1446
1824
  showRuntimeError: false,
@@ -1454,8 +1832,8 @@ var createRuntimePreviewOptions = (cdnURL = DEFAULT_CDN_URL) => {
1454
1832
  ...getPlaygroundStyleOverrides()
1455
1833
  }).map((href) => `<link rel="stylesheet" href="${escapeHtmlAttr(href)}">`),
1456
1834
  "<style>",
1457
- "html,body{height:auto;min-height:0}",
1458
- "body{color:var(--vc-foreground-color,#080f20);background:var(--vc-background-color-light,#fff)}",
1835
+ `html,body{height:auto;min-height:0;background:${PLAYGROUND_RUNTIME_CANVAS_BACKGROUND}}`,
1836
+ "body{color:var(--vc-foreground-color,#080f20)}",
1459
1837
  "</style>"
1460
1838
  ].join("\n"),
1461
1839
  customCode: {
@@ -1501,41 +1879,206 @@ var createRuntimeStore = (files, entry, options) => {
1501
1879
  return store;
1502
1880
  };
1503
1881
  //#endregion
1504
- //#region packages/playground/src/core/runtime/runtime.vue?vue&type=script&setup=true&lang.ts
1505
- var _hoisted_1$1 = {
1882
+ //#region packages/playground/src/core/runtime/alone/wrapper.vue?vue&type=script&setup=true&lang.ts
1883
+ var _hoisted_1$2 = ["aria-label"];
1884
+ var _hoisted_2$2 = { class: "docs-playground-popup__frame" };
1885
+ var _hoisted_3$2 = { class: "docs-playground-popup__header" };
1886
+ var _hoisted_4$2 = ["title"];
1887
+ var _hoisted_5$2 = { class: "docs-playground__title-text" };
1888
+ var _hoisted_6$1 = {
1506
1889
  key: 0,
1507
1890
  class: "docs-playground__runtime-error",
1508
1891
  role: "alert"
1509
1892
  };
1510
- var _hoisted_2 = {
1511
- key: 1,
1512
- class: "docs-playground-runtime"
1513
- };
1514
- var _hoisted_3 = { class: "docs-playground__header" };
1515
- var _hoisted_4 = { class: "docs-playground__tools" };
1516
- var _hoisted_5 = ["title", "aria-label"];
1517
- var _hoisted_6 = [
1518
- "title",
1519
- "aria-label",
1520
- "aria-expanded"
1521
- ];
1522
- var _hoisted_7 = ["title", "aria-label"];
1523
- var _hoisted_8 = {
1893
+ var _hoisted_7$1 = { class: "docs-playground-popup__body" };
1894
+ //#endregion
1895
+ //#region packages/playground/src/core/runtime/alone/index.ts
1896
+ var Alone = new Portal(/* @__PURE__ */ defineComponent({
1897
+ __name: "wrapper",
1898
+ props: {
1899
+ store: {},
1900
+ copyValue: {},
1901
+ title: { default: "" },
1902
+ viewport: { default: "auto" },
1903
+ viewportOptions: { default: () => ["auto", 375] },
1904
+ previewOptions: {},
1905
+ clearConsole: {
1906
+ type: Boolean,
1907
+ default: true
1908
+ }
1909
+ },
1910
+ emits: [
1911
+ "edit",
1912
+ "navigate",
1913
+ "viewport-change",
1914
+ "portal-fulfilled"
1915
+ ],
1916
+ setup(__props, { emit: __emit }) {
1917
+ const props = __props;
1918
+ const emit = __emit;
1919
+ const { t } = useLocale();
1920
+ const currentViewport = ref(props.viewport);
1921
+ const sandboxRef = ref(null);
1922
+ const sandboxKey = ref(0);
1923
+ const layoutTick = ref(0);
1924
+ const runtimeError = useSandboxRuntimeErrorGuard(sandboxRef);
1925
+ useSandboxTheme(sandboxRef);
1926
+ const storeErrors = computed(() => (props.store.errors || []).map(toErrorText).filter(Boolean).join("\n"));
1927
+ const errorText = computed(() => {
1928
+ const runtime = runtimeError.value ? formatSandboxRuntimeError(runtimeError.value, t("playground.runtime.importMapTip")) : "";
1929
+ return [storeErrors.value, runtime].filter(Boolean).join("\n\n");
1930
+ });
1931
+ const layout = computed(() => {
1932
+ layoutTick.value;
1933
+ return resolvePopupLayout(currentViewport.value);
1934
+ });
1935
+ const shellStyle = computed(() => ({
1936
+ width: `${layout.value.shellWidth}px`,
1937
+ height: `${layout.value.shellHeight}px`
1938
+ }));
1939
+ const canvasStyle = computed(() => ({
1940
+ width: `${layout.value.canvasWidth}px`,
1941
+ height: `${layout.value.canvasHeight}px`,
1942
+ background: PLAYGROUND_RUNTIME_CANVAS_BACKGROUND
1943
+ }));
1944
+ const handleRefresh = () => {
1945
+ runtimeError.value = "";
1946
+ sandboxKey.value++;
1947
+ };
1948
+ const handleViewportChange = (viewport) => {
1949
+ currentViewport.value = viewport;
1950
+ emit("viewport-change", viewport);
1951
+ };
1952
+ const handleClose = () => emit("portal-fulfilled");
1953
+ const isPlaygroundEditorOpen = () => {
1954
+ if (typeof document === "undefined") return false;
1955
+ const editor = document.querySelector(".docs-playground-editor__wrapper");
1956
+ if (!(editor instanceof HTMLElement)) return false;
1957
+ const style = getComputedStyle(editor);
1958
+ return style.display !== "none" && style.visibility !== "hidden";
1959
+ };
1960
+ const handleKeydown = (event) => {
1961
+ if (event.key !== "Escape") return;
1962
+ if (isPlaygroundEditorOpen()) return;
1963
+ event.preventDefault();
1964
+ handleClose();
1965
+ };
1966
+ const handleResize = () => {
1967
+ layoutTick.value++;
1968
+ };
1969
+ const handleBridgeMessage = (event) => {
1970
+ const iframe = resolveSandboxContainer(sandboxRef.value)?.querySelector("iframe");
1971
+ if (!iframe || event.source !== iframe.contentWindow) return;
1972
+ const data = event.data;
1973
+ if (!data || data.action !== "docs:navigate" || typeof data.to !== "string") return;
1974
+ emit("navigate", data.to);
1975
+ };
1976
+ watch(() => props.viewport, (viewport) => {
1977
+ currentViewport.value = viewport;
1978
+ });
1979
+ if (typeof window !== "undefined") {
1980
+ window.addEventListener("keydown", handleKeydown);
1981
+ window.addEventListener("resize", handleResize);
1982
+ window.addEventListener("message", handleBridgeMessage);
1983
+ }
1984
+ onBeforeUnmount(() => {
1985
+ window.removeEventListener("keydown", handleKeydown);
1986
+ window.removeEventListener("resize", handleResize);
1987
+ window.removeEventListener("message", handleBridgeMessage);
1988
+ });
1989
+ return (_ctx, _cache) => {
1990
+ return openBlock(), createElementBlock("div", {
1991
+ class: "docs-playground-popup",
1992
+ role: "dialog",
1993
+ "aria-modal": "true",
1994
+ "aria-label": unref(t)("playground.runtime.openPopup")
1995
+ }, [createElementVNode("div", {
1996
+ class: "docs-playground-popup__mask",
1997
+ "data-action": "popup-mask",
1998
+ onClick: handleClose
1999
+ }), createElementVNode("div", {
2000
+ class: "docs-playground-popup__shell",
2001
+ style: normalizeStyle(shellStyle.value)
2002
+ }, [createElementVNode("div", _hoisted_2$2, [
2003
+ createElementVNode("div", _hoisted_3$2, [__props.title.trim() ? (openBlock(), createElementBlock("span", {
2004
+ key: 0,
2005
+ class: "docs-playground__title",
2006
+ title: __props.title.trim()
2007
+ }, [createElementVNode("span", _hoisted_5$2, toDisplayString(__props.title.trim()), 1)], 8, _hoisted_4$2)) : createCommentVNode("v-if", true), createVNode(toolbar_default, {
2008
+ "copy-value": __props.copyValue,
2009
+ viewport: currentViewport.value,
2010
+ "viewport-options": __props.viewportOptions,
2011
+ "show-close": true,
2012
+ onRefresh: handleRefresh,
2013
+ onEdit: _cache[0] || (_cache[0] = ($event) => emit("edit")),
2014
+ onClosePopup: handleClose,
2015
+ onViewportChange: handleViewportChange
2016
+ }, null, 8, [
2017
+ "copy-value",
2018
+ "viewport",
2019
+ "viewport-options"
2020
+ ])]),
2021
+ errorText.value ? (openBlock(), createElementBlock("pre", _hoisted_6$1, toDisplayString(errorText.value), 1)) : createCommentVNode("v-if", true),
2022
+ createElementVNode("div", _hoisted_7$1, [createVNode(unref(Scroller), {
2023
+ class: "docs-playground-popup__scroller",
2024
+ "content-class": "docs-playground-popup__scroller-content",
2025
+ "auto-resize": true,
2026
+ native: false,
2027
+ "show-bar": true,
2028
+ height: "100%"
2029
+ }, {
2030
+ default: withCtx(() => [createElementVNode("div", {
2031
+ class: "docs-playground-popup__canvas",
2032
+ style: normalizeStyle(canvasStyle.value)
2033
+ }, [(openBlock(), createBlock(unref(Sandbox), {
2034
+ key: sandboxKey.value,
2035
+ ref_key: "sandboxRef",
2036
+ ref: sandboxRef,
2037
+ store: __props.store,
2038
+ "auto-store-init": false,
2039
+ "clear-console": __props.clearConsole,
2040
+ "preview-options": __props.previewOptions
2041
+ }, null, 8, [
2042
+ "store",
2043
+ "clear-console",
2044
+ "preview-options"
2045
+ ]))], 4)]),
2046
+ _: 1
2047
+ })])
2048
+ ])], 4)], 8, _hoisted_1$2);
2049
+ };
2050
+ }
2051
+ }), {
2052
+ name: "docs-playground-alone",
2053
+ leaveDelay: 0,
2054
+ multiple: false
2055
+ });
2056
+ //#endregion
2057
+ //#region packages/playground/src/core/runtime/runtime.vue?vue&type=script&setup=true&lang.ts
2058
+ var _hoisted_1$1 = { class: "docs-playground-runtime-host" };
2059
+ var _hoisted_2$1 = {
1524
2060
  key: 0,
1525
- class: "docs-playground__views"
2061
+ class: "docs-playground__runtime-error",
2062
+ role: "alert"
1526
2063
  };
1527
- var _hoisted_9 = [
1528
- "title",
1529
- "aria-label",
1530
- "aria-pressed",
1531
- "onClick"
1532
- ];
1533
- var _hoisted_10 = {
2064
+ var _hoisted_3$1 = {
1534
2065
  key: 0,
2066
+ class: "docs-playground__header"
2067
+ };
2068
+ var _hoisted_4$1 = ["id", "title"];
2069
+ var _hoisted_5$1 = ["href"];
2070
+ var _hoisted_6 = { class: "docs-playground__title-text" };
2071
+ var _hoisted_7 = {
2072
+ key: 1,
1535
2073
  class: "docs-playground__runtime-error",
1536
2074
  role: "alert"
1537
2075
  };
1538
- var _hoisted_11 = { class: "docs-playground-runtime__viewport-stage" };
2076
+ var _hoisted_8 = { class: "docs-playground-runtime__viewport-stage" };
2077
+ var _hoisted_9 = [
2078
+ "aria-expanded",
2079
+ "title",
2080
+ "aria-label"
2081
+ ];
1539
2082
  //#endregion
1540
2083
  //#region packages/playground/src/core/runtime/runtime.vue
1541
2084
  var runtime_default = /* @__PURE__ */ defineComponent({
@@ -1552,6 +2095,13 @@ var runtime_default = /* @__PURE__ */ defineComponent({
1552
2095
  type: Boolean,
1553
2096
  default: false
1554
2097
  },
2098
+ hideChrome: {
2099
+ type: Boolean,
2100
+ default: false
2101
+ },
2102
+ expandable: { type: [Boolean, Number] },
2103
+ title: { default: "" },
2104
+ id: { default: "" },
1555
2105
  viewport: { default: "auto" },
1556
2106
  viewportOptions: { default: () => ["auto", 375] }
1557
2107
  },
@@ -1561,24 +2111,36 @@ var runtime_default = /* @__PURE__ */ defineComponent({
1561
2111
  "viewport-change",
1562
2112
  "navigate"
1563
2113
  ],
1564
- setup(__props, { emit: __emit }) {
2114
+ setup(__props, { expose: __expose, emit: __emit }) {
1565
2115
  const props = __props;
1566
2116
  const { locale, t } = useLocale();
1567
- const getViewText = (view) => t(playgroundViewMessage(view));
2117
+ const displayTitle = computed(() => props.title.trim());
2118
+ const titleEl = ref(null);
2119
+ const titleId = computed(() => resolvePlaygroundTitleId(displayTitle.value, props.id, (candidate) => {
2120
+ if (typeof document === "undefined") return false;
2121
+ const existing = document.getElementById(candidate);
2122
+ return !!existing && existing !== titleEl.value;
2123
+ }));
1568
2124
  const emit = __emit;
1569
2125
  const joinCode = (...values) => values.filter(Boolean).join("\n");
1570
- const mergedPreviewOptions = computed(() => {
2126
+ const mergePreviewOptions = (extraHeadHTML) => {
1571
2127
  const runtimePreviewOptions = createRuntimePreviewOptions(props.options.cdnURL);
1572
2128
  return {
1573
2129
  ...runtimePreviewOptions,
1574
2130
  ...props.previewOptions,
1575
- headHTML: [runtimePreviewOptions.headHTML, props.previewOptions?.headHTML].filter(Boolean).join("\n"),
2131
+ headHTML: [
2132
+ runtimePreviewOptions.headHTML,
2133
+ props.previewOptions?.headHTML,
2134
+ extraHeadHTML
2135
+ ].filter(Boolean).join("\n"),
1576
2136
  customCode: {
1577
2137
  importCode: joinCode(runtimePreviewOptions.customCode?.importCode, props.previewOptions?.customCode?.importCode),
1578
2138
  useCode: joinCode(runtimePreviewOptions.customCode?.useCode, props.previewOptions?.customCode?.useCode)
1579
2139
  }
1580
2140
  };
1581
- });
2141
+ };
2142
+ const mergedPreviewOptions = computed(() => mergePreviewOptions());
2143
+ const popupPreviewOptions = computed(() => mergePreviewOptions("<style>html,body{height:100%;min-height:100%}</style>"));
1582
2144
  const clearConsole = {
1583
2145
  "BASE_URL": "/",
1584
2146
  "DEV": false,
@@ -1605,11 +2167,63 @@ var runtime_default = /* @__PURE__ */ defineComponent({
1605
2167
  if (!data || data.action !== "docs:navigate" || typeof data.to !== "string") return;
1606
2168
  emit("navigate", data.to);
1607
2169
  };
1608
- if (typeof window !== "undefined") window.addEventListener("message", handleBridgeMessage);
1609
- onBeforeUnmount(() => window.removeEventListener("message", handleBridgeMessage));
1610
- const viewportMenuVisible = ref(false);
1611
- const viewportLabel = computed(() => formatViewportLabel(props.viewport, t("playground.runtime.auto")));
1612
- const desiredViewportHeight = computed(() => getViewportHeight(props.viewport) || runtimeHeight.value);
2170
+ const runtimeRoot = ref(null);
2171
+ const previewExpanded = ref(false);
2172
+ /** `expandable: true` 时在展开瞬间冻结,避免滚动重算高度造成抖动。 */
2173
+ const frozenExpandedHeight = ref(0);
2174
+ const measurePreviewChromeHeight = () => {
2175
+ const root = runtimeRoot.value;
2176
+ if (!root) return 0;
2177
+ const header = (root.closest(".docs-playground") ?? root).querySelector(".docs-playground__header");
2178
+ const error = root.querySelector(".docs-playground__runtime-error");
2179
+ return (header instanceof HTMLElement ? header.offsetHeight : 0) + (error instanceof HTMLElement ? error.offsetHeight : 0);
2180
+ };
2181
+ const measureExpandedPreviewHeight = () => {
2182
+ if (typeof window === "undefined") return runtimeHeight.value;
2183
+ const chromeHeight = measurePreviewChromeHeight();
2184
+ return resolveExpandedPreviewHeight(true, resolveRemainingPreviewHeight({
2185
+ viewportHeight: getVisibleViewportRect(runtimeRoot.value).height,
2186
+ chromeHeight
2187
+ }));
2188
+ };
2189
+ const syncFrozenExpandedHeight = () => {
2190
+ if (!previewExpanded.value || props.expandable !== true) return;
2191
+ frozenExpandedHeight.value = measureExpandedPreviewHeight();
2192
+ };
2193
+ if (typeof window !== "undefined") {
2194
+ window.addEventListener("message", handleBridgeMessage);
2195
+ window.addEventListener("resize", syncFrozenExpandedHeight);
2196
+ }
2197
+ const canExpandPreview = computed(() => !props.styleless && isPlaygroundExpandable(props.expandable));
2198
+ const expandLabel = computed(() => t(previewExpanded.value ? "playground.runtime.collapsePreview" : "playground.runtime.expandPreview"));
2199
+ const desiredViewportHeight = computed(() => {
2200
+ if (previewExpanded.value && props.expandable === true) return frozenExpandedHeight.value;
2201
+ if (previewExpanded.value && isPlaygroundExpandable(props.expandable)) return resolveExpandedPreviewHeight(props.expandable, 0);
2202
+ const fixedHeight = getViewportHeight(props.viewport);
2203
+ if (fixedHeight) return fixedHeight;
2204
+ return runtimeHeight.value;
2205
+ });
2206
+ const scrollExpandedPreviewIntoView = () => {
2207
+ scrollPlaygroundToViewportStart(runtimeRoot.value);
2208
+ };
2209
+ const handleTogglePreviewExpand = () => {
2210
+ if (!canExpandPreview.value) return;
2211
+ if (!previewExpanded.value) {
2212
+ if (props.expandable === true) frozenExpandedHeight.value = measureExpandedPreviewHeight();
2213
+ else frozenExpandedHeight.value = 0;
2214
+ previewExpanded.value = true;
2215
+ nextTick(scrollExpandedPreviewIntoView);
2216
+ return;
2217
+ }
2218
+ previewExpanded.value = false;
2219
+ frozenExpandedHeight.value = 0;
2220
+ };
2221
+ watch(canExpandPreview, (enabled) => {
2222
+ if (!enabled) {
2223
+ previewExpanded.value = false;
2224
+ frozenExpandedHeight.value = 0;
2225
+ }
2226
+ });
1613
2227
  const normalizedPreviewInset = computed(() => {
1614
2228
  const value = props.previewInset;
1615
2229
  if (typeof value === "number") return Number.isFinite(value) && value >= 0 ? [value, value] : [10, 10];
@@ -1620,7 +2234,8 @@ var runtime_default = /* @__PURE__ */ defineComponent({
1620
2234
  const [vertical, horizontal] = normalizedPreviewInset.value;
1621
2235
  return {
1622
2236
  height: `${desiredViewportHeight.value + vertical * 2}px`,
1623
- padding: vertical === horizontal ? `${vertical}px` : `${vertical}px ${horizontal}px`
2237
+ padding: vertical === horizontal ? `${vertical}px` : `${vertical}px ${horizontal}px`,
2238
+ background: PLAYGROUND_RUNTIME_CANVAS_BACKGROUND
1624
2239
  };
1625
2240
  });
1626
2241
  const stylelessStyle = computed(() => errorText.value ? void 0 : { height: `${desiredViewportHeight.value}px` });
@@ -1672,18 +2287,30 @@ var runtime_default = /* @__PURE__ */ defineComponent({
1672
2287
  onActiveChange: (filename) => store.setActive(toReplFilename(filename))
1673
2288
  });
1674
2289
  };
1675
- const handleRefresh = () => {
2290
+ const handleInlineRefresh = () => {
1676
2291
  runtimeError.value = "";
1677
2292
  sandboxKey.value++;
1678
2293
  };
1679
- const handleView = (view) => emit("view-change", view);
1680
- const handleViewport = (index) => {
1681
- const viewport = props.viewportOptions[index];
1682
- if (viewport && !viewportEquals(viewport, props.viewport)) emit("viewport-change", viewport);
2294
+ const handleClosePopup = () => {
2295
+ Alone.destroy();
2296
+ };
2297
+ const handleOpenPopup = () => {
2298
+ Alone.popup({
2299
+ store,
2300
+ copyValue: copyValue.value,
2301
+ title: props.title,
2302
+ viewport: props.viewport,
2303
+ viewportOptions: props.viewportOptions,
2304
+ previewOptions: popupPreviewOptions.value,
2305
+ clearConsole,
2306
+ onEdit: handleEditor,
2307
+ onViewportChange: handleViewportChange,
2308
+ onNavigate: (to) => emit("navigate", to)
2309
+ });
2310
+ };
2311
+ const handleViewportChange = (viewport) => {
2312
+ emit("viewport-change", viewport);
1683
2313
  };
1684
- watch(() => props.viewportOptions.length, (length) => {
1685
- if (length <= 1) viewportMenuVisible.value = false;
1686
- });
1687
2314
  watch(() => props.files, (files) => {
1688
2315
  if (filesEqual(files, syncedFiles)) return;
1689
2316
  syncedFiles = { ...files };
@@ -1697,12 +2324,27 @@ var runtime_default = /* @__PURE__ */ defineComponent({
1697
2324
  store.mainFile = toReplFilename(entry);
1698
2325
  store.setActive(toReplFilename(entry));
1699
2326
  });
2327
+ watch(() => props.activeView, (view) => {
2328
+ if (view !== "runtime") handleClosePopup();
2329
+ });
2330
+ onBeforeUnmount(() => {
2331
+ window.removeEventListener("message", handleBridgeMessage);
2332
+ window.removeEventListener("resize", syncFrozenExpandedHeight);
2333
+ handleClosePopup();
2334
+ });
2335
+ __expose({
2336
+ refresh: handleInlineRefresh,
2337
+ edit: handleEditor,
2338
+ openPopup: handleOpenPopup
2339
+ });
1700
2340
  return (_ctx, _cache) => {
1701
- return __props.styleless ? (openBlock(), createElementBlock("div", {
2341
+ return openBlock(), createElementBlock("div", _hoisted_1$1, [__props.styleless ? (openBlock(), createElementBlock("div", {
1702
2342
  key: 0,
2343
+ ref_key: "runtimeRoot",
2344
+ ref: runtimeRoot,
1703
2345
  class: "docs-playground-runtime--styleless",
1704
2346
  style: normalizeStyle(stylelessStyle.value)
1705
- }, [errorText.value ? (openBlock(), createElementBlock("pre", _hoisted_1$1, toDisplayString(errorText.value), 1)) : createCommentVNode("v-if", true), createElementVNode("div", {
2347
+ }, [errorText.value ? (openBlock(), createElementBlock("pre", _hoisted_2$1, toDisplayString(errorText.value), 1)) : createCommentVNode("v-if", true), createElementVNode("div", {
1706
2348
  class: "docs-playground-runtime__viewport",
1707
2349
  style: normalizeStyle(viewportStyle.value)
1708
2350
  }, [createVNode(unref(Sandbox), {
@@ -1711,100 +2353,42 @@ var runtime_default = /* @__PURE__ */ defineComponent({
1711
2353
  store: unref(store),
1712
2354
  "auto-store-init": false,
1713
2355
  "preview-options": mergedPreviewOptions.value
1714
- }, null, 8, ["store", "preview-options"])], 4)], 4)) : (openBlock(), createElementBlock("div", _hoisted_2, [
1715
- createElementVNode("div", _hoisted_3, [createElementVNode("div", _hoisted_4, [
1716
- createElementVNode("button", {
1717
- type: "button",
1718
- class: "docs-playground__tool docs-playground__refresh",
1719
- "data-action": "refresh",
1720
- title: unref(t)("playground.runtime.refresh"),
1721
- "aria-label": unref(t)("playground.runtime.refresh"),
1722
- onClick: handleRefresh
1723
- }, [createVNode(unref(icon_default), { name: "refresh" })], 8, _hoisted_5),
1724
- __props.viewportOptions.length > 1 ? (openBlock(), createBlock(unref(Dropdown), {
1725
- key: 0,
1726
- modelValue: viewportMenuVisible.value,
1727
- "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => viewportMenuVisible.value = $event),
1728
- class: "docs-playground__viewport-menu",
1729
- portal: true,
1730
- trigger: "click",
1731
- placement: "bottom-right"
1732
- }, {
1733
- content: withCtx(() => [createVNode(unref(DropdownMenu), {
1734
- class: "docs-playground__viewport-options",
1735
- role: "menu",
1736
- "aria-label": unref(t)("playground.runtime.viewportMenu")
1737
- }, {
1738
- default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.viewportOptions, (item, index) => {
1739
- return openBlock(), createBlock(unref(DropdownItem), {
1740
- key: unref(getViewportKey)(item),
1741
- class: "docs-playground__viewport-option",
1742
- value: index,
1743
- selected: unref(viewportEquals)(item, __props.viewport),
1744
- role: "menuitemradio",
1745
- "aria-checked": unref(viewportEquals)(item, __props.viewport),
1746
- onClick: ($event) => handleViewport(index)
1747
- }, {
1748
- default: withCtx(() => [createTextVNode(toDisplayString(unref(formatViewportLabel)(item, unref(t)("playground.runtime.auto"))), 1)]),
1749
- _: 2
1750
- }, 1032, [
1751
- "value",
1752
- "selected",
1753
- "aria-checked",
1754
- "onClick"
1755
- ]);
1756
- }), 128))]),
1757
- _: 1
1758
- }, 8, ["aria-label"])]),
1759
- default: withCtx(() => [createElementVNode("button", {
1760
- type: "button",
1761
- class: normalizeClass(["docs-playground__tool docs-playground__viewport-trigger", { "is-active": __props.viewport !== "auto" }]),
1762
- title: unref(t)("playground.runtime.viewport", { value: viewportLabel.value }),
1763
- "aria-label": unref(t)("playground.runtime.viewport", { value: viewportLabel.value }),
1764
- "aria-expanded": viewportMenuVisible.value,
1765
- "aria-haspopup": "menu"
1766
- }, [createVNode(unref(icon_default), { name: "viewport" })], 10, _hoisted_6)]),
1767
- _: 1
1768
- }, 8, ["modelValue"])) : createCommentVNode("v-if", true),
1769
- createVNode(unref(Clipboard), {
1770
- class: "docs-playground__tool",
1771
- value: copyValue.value,
1772
- tag: "button",
1773
- type: "button",
1774
- title: unref(t)("playground.common.copy"),
1775
- "aria-label": unref(t)("playground.common.copy")
1776
- }, {
1777
- default: withCtx(() => [createVNode(unref(icon_default), { name: "copy" })]),
1778
- _: 1
1779
- }, 8, [
1780
- "value",
1781
- "title",
1782
- "aria-label"
1783
- ]),
1784
- createElementVNode("button", {
1785
- type: "button",
1786
- class: "docs-playground__tool docs-playground__editor",
1787
- "data-action": "edit",
1788
- title: unref(t)("playground.runtime.editFiles"),
1789
- "aria-label": unref(t)("playground.runtime.editFiles"),
1790
- onClick: handleEditor
1791
- }, [createVNode(unref(icon_default), { name: "editor" })], 8, _hoisted_7)
1792
- ]), __props.views.length > 1 ? (openBlock(), createElementBlock("div", _hoisted_8, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.views, (item) => {
1793
- return openBlock(), createElementBlock("button", {
1794
- key: item,
1795
- type: "button",
1796
- class: normalizeClass(["docs-playground__view", { "is-active": item === __props.activeView }]),
1797
- title: getViewText(item),
1798
- "aria-label": getViewText(item),
1799
- "aria-pressed": item === __props.activeView,
1800
- onClick: ($event) => handleView(item)
1801
- }, [createVNode(unref(icon_default), { name: item }, null, 8, ["name"])], 10, _hoisted_9);
1802
- }), 128))])) : createCommentVNode("v-if", true)]),
1803
- errorText.value ? (openBlock(), createElementBlock("pre", _hoisted_10, toDisplayString(errorText.value), 1)) : createCommentVNode("v-if", true),
2356
+ }, null, 8, ["store", "preview-options"])], 4)], 4)) : (openBlock(), createElementBlock("div", {
2357
+ key: 1,
2358
+ ref_key: "runtimeRoot",
2359
+ ref: runtimeRoot,
2360
+ class: "docs-playground-runtime"
2361
+ }, [
2362
+ !__props.hideChrome ? (openBlock(), createElementBlock("div", _hoisted_3$1, [displayTitle.value ? (openBlock(), createElementBlock("span", {
2363
+ key: 0,
2364
+ ref_key: "titleEl",
2365
+ ref: titleEl,
2366
+ class: "docs-playground__title",
2367
+ id: titleId.value,
2368
+ tabindex: "-1",
2369
+ title: displayTitle.value
2370
+ }, [createElementVNode("a", {
2371
+ class: "docs-playground__title-anchor",
2372
+ href: `#${titleId.value}`
2373
+ }, "#", 8, _hoisted_5$1), createElementVNode("span", _hoisted_6, toDisplayString(displayTitle.value), 1)], 8, _hoisted_4$1)) : createCommentVNode("v-if", true), createVNode(toolbar_default, {
2374
+ "copy-value": copyValue.value,
2375
+ viewport: __props.viewport,
2376
+ "viewport-options": __props.viewportOptions,
2377
+ "show-open-popup": true,
2378
+ onRefresh: handleInlineRefresh,
2379
+ onEdit: handleEditor,
2380
+ onOpenPopup: handleOpenPopup,
2381
+ onViewportChange: handleViewportChange
2382
+ }, null, 8, [
2383
+ "copy-value",
2384
+ "viewport",
2385
+ "viewport-options"
2386
+ ])])) : createCommentVNode("v-if", true),
2387
+ errorText.value ? (openBlock(), createElementBlock("pre", _hoisted_7, toDisplayString(errorText.value), 1)) : createCommentVNode("v-if", true),
1804
2388
  createElementVNode("section", {
1805
- class: "docs-playground__preview",
2389
+ class: normalizeClass(["docs-playground__preview", { "is-expanded": previewExpanded.value }]),
1806
2390
  style: normalizeStyle(previewStyle.value)
1807
- }, [createElementVNode("div", _hoisted_11, [createElementVNode("div", {
2391
+ }, [createElementVNode("div", _hoisted_8, [createElementVNode("div", {
1808
2392
  class: "docs-playground-runtime__viewport",
1809
2393
  style: normalizeStyle(viewportStyle.value)
1810
2394
  }, [(openBlock(), createBlock(unref(Sandbox), {
@@ -1815,8 +2399,17 @@ var runtime_default = /* @__PURE__ */ defineComponent({
1815
2399
  "auto-store-init": false,
1816
2400
  "clear-console": clearConsole,
1817
2401
  "preview-options": mergedPreviewOptions.value
1818
- }, null, 8, ["store", "preview-options"]))], 4)])], 4)
1819
- ]));
2402
+ }, null, 8, ["store", "preview-options"]))], 4)]), canExpandPreview.value ? (openBlock(), createElementBlock("button", {
2403
+ key: 0,
2404
+ type: "button",
2405
+ class: normalizeClass(["docs-playground__expand", { "is-expanded": previewExpanded.value }]),
2406
+ "data-action": "expand-preview",
2407
+ "aria-expanded": previewExpanded.value,
2408
+ title: expandLabel.value,
2409
+ "aria-label": expandLabel.value,
2410
+ onClick: handleTogglePreviewExpand
2411
+ }, [createVNode(unref(icon_default), { name: "expand" })], 10, _hoisted_9)) : createCommentVNode("v-if", true)], 6)
2412
+ ], 512))]);
1820
2413
  };
1821
2414
  }
1822
2415
  });
@@ -1826,6 +2419,13 @@ var _hoisted_1 = {
1826
2419
  key: 0,
1827
2420
  class: "docs-playground__error"
1828
2421
  };
2422
+ var _hoisted_2 = {
2423
+ key: 0,
2424
+ class: "docs-playground__header"
2425
+ };
2426
+ var _hoisted_3 = ["id", "title"];
2427
+ var _hoisted_4 = ["href"];
2428
+ var _hoisted_5 = { class: "docs-playground__title-text" };
1829
2429
  //#endregion
1830
2430
  //#region packages/playground/src/playground.vue
1831
2431
  var playground_default = /* @__PURE__ */ defineComponent({
@@ -1843,6 +2443,9 @@ var playground_default = /* @__PURE__ */ defineComponent({
1843
2443
  },
1844
2444
  options: { default: () => ({}) },
1845
2445
  previewInset: { default: 0 },
2446
+ expandable: { type: [Boolean, Number] },
2447
+ title: { default: "" },
2448
+ id: { default: "" },
1846
2449
  previewOptions: {},
1847
2450
  locale: {}
1848
2451
  },
@@ -1866,6 +2469,8 @@ var playground_default = /* @__PURE__ */ defineComponent({
1866
2469
  const sourceFiles = ref(initialFiles);
1867
2470
  const currentEntry = ref(initialEntry);
1868
2471
  const fileActiveFilename = ref(initialEntry);
2472
+ const runtimeRef = ref(null);
2473
+ const titleEl = ref(null);
1869
2474
  const normalizeViews = (views) => {
1870
2475
  const normalized = [];
1871
2476
  for (const view of views) {
@@ -1876,12 +2481,25 @@ var playground_default = /* @__PURE__ */ defineComponent({
1876
2481
  return normalized.length ? normalized : ["runtime"];
1877
2482
  };
1878
2483
  const normalizedViews = computed(() => normalizeViews(props.views));
2484
+ const hasRuntimeView = computed(() => normalizedViews.value.includes("runtime"));
2485
+ const hasFilesView = computed(() => normalizedViews.value.includes("files"));
1879
2486
  const activeView = ref(normalizedViews.value[0]);
1880
2487
  const runtimeActivated = ref(props.styleless || activeView.value === "runtime");
1881
2488
  const normalizedViewportOptions = computed(() => normalizeViewportOptions(props.viewportOptions));
1882
2489
  const activeViewport = ref(resolveInitialViewport(props.viewport, normalizedViewportOptions.value));
1883
2490
  const selectableViewportOptions = computed(() => includeActiveViewport(normalizedViewportOptions.value, activeViewport.value));
1884
2491
  const error = ref(props.entry && initialFiles[props.entry] === void 0 ? t("playground.validation.entryMissing", { filename: props.entry }) : "");
2492
+ const displayTitle = computed(() => props.title.trim());
2493
+ const titleId = computed(() => resolvePlaygroundTitleId(displayTitle.value, props.id, (candidate) => {
2494
+ if (typeof document === "undefined") return false;
2495
+ const existing = document.getElementById(candidate);
2496
+ return !!existing && existing !== titleEl.value;
2497
+ }));
2498
+ const copyValue = computed(() => sourceFiles.value[currentEntry.value] || "");
2499
+ /** runtime / 双视图始终有顶栏;files-only 仅有标题时渲染。 */
2500
+ const showHeader = computed(() => hasRuntimeView.value || !!displayTitle.value);
2501
+ const showToolbar = computed(() => hasRuntimeView.value);
2502
+ const showRuntimeActions = computed(() => activeView.value === "runtime");
1885
2503
  watch(locale, () => {
1886
2504
  if (props.entry && sourceFiles.value[props.entry] === void 0) error.value = t("playground.validation.entryMissing", { filename: props.entry });
1887
2505
  });
@@ -1895,6 +2513,15 @@ var playground_default = /* @__PURE__ */ defineComponent({
1895
2513
  activeViewport.value = cloneViewport(viewport);
1896
2514
  emit("update:viewport", cloneViewport(viewport));
1897
2515
  };
2516
+ const handleRefresh = () => {
2517
+ runtimeRef.value?.refresh();
2518
+ };
2519
+ const handleEdit = () => {
2520
+ runtimeRef.value?.edit();
2521
+ };
2522
+ const handleOpenPopup = () => {
2523
+ runtimeRef.value?.openPopup();
2524
+ };
1898
2525
  const handleFileActive = (filename) => {
1899
2526
  if (sourceFiles.value[filename] !== void 0) fileActiveFilename.value = filename;
1900
2527
  };
@@ -1976,7 +2603,10 @@ var playground_default = /* @__PURE__ */ defineComponent({
1976
2603
  options: __props.options,
1977
2604
  "preview-options": __props.previewOptions,
1978
2605
  "preview-inset": __props.previewInset,
2606
+ expandable: __props.expandable,
1979
2607
  styleless: true,
2608
+ title: __props.title,
2609
+ id: __props.id,
1980
2610
  viewport: activeViewport.value,
1981
2611
  "viewport-options": selectableViewportOptions.value,
1982
2612
  onFilesChange: handleFilesChange,
@@ -1988,27 +2618,68 @@ var playground_default = /* @__PURE__ */ defineComponent({
1988
2618
  "options",
1989
2619
  "preview-options",
1990
2620
  "preview-inset",
2621
+ "expandable",
2622
+ "title",
2623
+ "id",
1991
2624
  "viewport",
1992
2625
  "viewport-options"
1993
2626
  ])) : (openBlock(), createElementBlock("div", {
1994
2627
  key: 1,
1995
2628
  class: normalizeClass(["docs-playground", { "docs-playground--files": activeView.value === "files" }])
1996
- }, [
1997
- error.value ? (openBlock(), createElementBlock("div", _hoisted_1, toDisplayString(error.value), 1)) : createCommentVNode("v-if", true),
1998
- runtimeActivated.value && normalizedViews.value.includes("runtime") ? withDirectives((openBlock(), createBlock(unref(runtime_default), {
2629
+ }, [error.value ? (openBlock(), createElementBlock("div", _hoisted_1, toDisplayString(error.value), 1)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
2630
+ showHeader.value ? (openBlock(), createElementBlock("div", _hoisted_2, [displayTitle.value ? (openBlock(), createElementBlock("span", {
2631
+ key: 0,
2632
+ ref_key: "titleEl",
2633
+ ref: titleEl,
2634
+ class: "docs-playground__title",
2635
+ id: titleId.value,
2636
+ tabindex: "-1",
2637
+ title: displayTitle.value
2638
+ }, [createElementVNode("a", {
2639
+ class: "docs-playground__title-anchor",
2640
+ href: `#${titleId.value}`
2641
+ }, "#", 8, _hoisted_4), createElementVNode("span", _hoisted_5, toDisplayString(displayTitle.value), 1)], 8, _hoisted_3)) : createCommentVNode("v-if", true), showToolbar.value ? (openBlock(), createBlock(toolbar_default, {
1999
2642
  key: 1,
2643
+ "copy-value": copyValue.value,
2644
+ viewport: activeViewport.value,
2645
+ "viewport-options": selectableViewportOptions.value,
2646
+ views: normalizedViews.value,
2647
+ "active-view": activeView.value,
2648
+ "show-runtime-actions": showRuntimeActions.value,
2649
+ "show-open-popup": hasRuntimeView.value,
2650
+ onRefresh: handleRefresh,
2651
+ onEdit: handleEdit,
2652
+ onOpenPopup: handleOpenPopup,
2653
+ onViewportChange: handleViewport,
2654
+ onViewChange: handleView
2655
+ }, null, 8, [
2656
+ "copy-value",
2657
+ "viewport",
2658
+ "viewport-options",
2659
+ "views",
2660
+ "active-view",
2661
+ "show-runtime-actions",
2662
+ "show-open-popup"
2663
+ ])) : createCommentVNode("v-if", true)])) : createCommentVNode("v-if", true),
2664
+ runtimeActivated.value && hasRuntimeView.value ? withDirectives((openBlock(), createBlock(unref(runtime_default), {
2665
+ key: 1,
2666
+ ref_key: "runtimeRef",
2667
+ ref: runtimeRef,
2000
2668
  files: sourceFiles.value,
2001
2669
  entry: currentEntry.value,
2002
2670
  options: __props.options,
2003
2671
  "preview-options": __props.previewOptions,
2004
2672
  "preview-inset": __props.previewInset,
2673
+ expandable: __props.expandable,
2674
+ "hide-chrome": true,
2675
+ title: __props.title,
2676
+ id: __props.id,
2005
2677
  "active-view": activeView.value,
2006
2678
  views: normalizedViews.value,
2007
2679
  viewport: activeViewport.value,
2008
2680
  "viewport-options": selectableViewportOptions.value,
2009
2681
  onFilesChange: handleFilesChange,
2010
2682
  onNavigate: _cache[1] || (_cache[1] = ($event) => emit("navigate", $event)),
2011
- onViewChange: handleView,
2012
2683
  onViewportChange: handleViewport
2013
2684
  }, null, 8, [
2014
2685
  "files",
@@ -2016,30 +2687,32 @@ var playground_default = /* @__PURE__ */ defineComponent({
2016
2687
  "options",
2017
2688
  "preview-options",
2018
2689
  "preview-inset",
2690
+ "expandable",
2691
+ "title",
2692
+ "id",
2019
2693
  "active-view",
2020
2694
  "views",
2021
2695
  "viewport",
2022
2696
  "viewport-options"
2023
- ])), [[vShow, !error.value && activeView.value === "runtime"]]) : createCommentVNode("v-if", true),
2024
- normalizedViews.value.includes("files") ? withDirectives((openBlock(), createBlock(unref(files_preview_default), {
2697
+ ])), [[vShow, activeView.value === "runtime"]]) : createCommentVNode("v-if", true),
2698
+ hasFilesView.value ? withDirectives((openBlock(), createBlock(unref(files_preview_default), {
2025
2699
  key: 2,
2026
2700
  files: sourceFiles.value,
2027
2701
  entry: currentEntry.value,
2028
2702
  "active-filename": fileActiveFilename.value,
2029
2703
  "active-view": activeView.value,
2030
2704
  views: normalizedViews.value,
2031
- onActiveChange: handleFileActive,
2032
- onViewChange: handleView
2705
+ onActiveChange: handleFileActive
2033
2706
  }, null, 8, [
2034
2707
  "files",
2035
2708
  "entry",
2036
2709
  "active-filename",
2037
2710
  "active-view",
2038
2711
  "views"
2039
- ])), [[vShow, !error.value && activeView.value === "files"]]) : createCommentVNode("v-if", true)
2040
- ], 2));
2712
+ ])), [[vShow, activeView.value === "files"]]) : createCommentVNode("v-if", true)
2713
+ ], 64))], 2));
2041
2714
  };
2042
2715
  }
2043
2716
  });
2044
2717
  //#endregion
2045
- export { code_preview_default as CodePreview, DEFAULT_CDN_URL, Editor, playground_default as Playground, applyPlaygroundImportMapOverride, applyPlaygroundStyleOverride, clearPlaygroundMaps, createBuiltinImports, createBuiltinStyles, createRuntimePreviewOptions, getPlaygroundImportMapOverrides, getPlaygroundSiteModules, getPlaygroundSiteStyles, getPlaygroundStyleOverrides, highlightCode, highlightCodeByLanguage, isSafePlaygroundHref, normalizeCdnURL, registerVueHighlight, removePlaygroundImportMapOverride, removePlaygroundStyleOverride, resolveHighlightLanguage, setPlaygroundImportMapOverrides, setPlaygroundSiteModules, setPlaygroundSiteStyles, setPlaygroundStyleOverrides, vueHighlight };
2718
+ export { code_preview_default as CodePreview, DEFAULT_CDN_URL, Editor, playground_default as Playground, applyPlaygroundImportMapOverride, applyPlaygroundStyleOverride, clearPlaygroundMaps, createBuiltinImports, createBuiltinStyles, createRuntimePreviewOptions, getPlaygroundImportMapOverrides, getPlaygroundSiteModules, getPlaygroundSiteStyles, getPlaygroundStyleOverrides, highlightCode, highlightCodeByLanguage, isSafePlaygroundHref, normalizeCdnURL, registerVueHighlight, removePlaygroundImportMapOverride, removePlaygroundStyleOverride, resolveHighlightLanguage, resolvePlaygroundTitleId, setPlaygroundImportMapOverrides, setPlaygroundSiteModules, setPlaygroundSiteStyles, setPlaygroundStyleOverrides, slugifyPlaygroundTitle, vueHighlight };