@deot/docs-playground 1.0.9 → 1.0.10

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$6 = ["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$6)], 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$5 = ["title"];
178
+ var _hoisted_3$5 = { class: "docs-code-preview__code" };
179
+ var _hoisted_4$5 = ["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$5)) : createCommentVNode("v-if", true),
214
216
  createVNode(unref(Clipboard), {
215
217
  class: "docs-code-preview__copy",
216
218
  value: __props.code,
@@ -227,10 +229,10 @@ 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$5, [createElementVNode("code", {
231
233
  class: "hljs",
232
234
  innerHTML: highlightedCode.value
233
- }, null, 8, _hoisted_4$3)])
235
+ }, null, 8, _hoisted_4$5)])
234
236
  ]);
235
237
  };
236
238
  }
@@ -256,15 +258,15 @@ var filesEqual = (left, right) => {
256
258
  var playgroundViewMessage = (view) => view === "runtime" ? "playground.runtime.preview" : "playground.runtime.files";
257
259
  //#endregion
258
260
  //#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 = {
261
+ var _hoisted_1$5 = { class: "docs-playground-files" };
262
+ var _hoisted_2$4 = { class: "docs-playground-files__toolbar" };
263
+ var _hoisted_3$4 = ["data-filename", "onClick"];
264
+ var _hoisted_4$4 = {
263
265
  key: 0,
264
266
  class: "docs-playground-files__entry"
265
267
  };
266
- var _hoisted_5$2 = { class: "docs-playground-files__actions" };
267
- var _hoisted_6$2 = {
268
+ var _hoisted_5$4 = { class: "docs-playground-files__actions" };
269
+ var _hoisted_6$3 = {
268
270
  key: 0,
269
271
  class: "docs-playground__views docs-playground__views--files"
270
272
  };
@@ -298,7 +300,7 @@ var files_preview_default = /* @__PURE__ */ defineComponent({
298
300
  };
299
301
  const handleView = (view) => emit("view-change", view);
300
302
  return (_ctx, _cache) => {
301
- return openBlock(), createElementBlock("div", _hoisted_1$3, [createElementVNode("div", _hoisted_2$2, [createVNode(unref(Scroller), {
303
+ return openBlock(), createElementBlock("div", _hoisted_1$5, [createElementVNode("div", _hoisted_2$4, [createVNode(unref(Scroller), {
302
304
  class: "docs-playground-files__scroller",
303
305
  "auto-resize": true,
304
306
  native: false,
@@ -315,10 +317,10 @@ var files_preview_default = /* @__PURE__ */ defineComponent({
315
317
  class: normalizeClass(["docs-playground-files__tab", { "is-active": filename === __props.activeFilename }]),
316
318
  "data-filename": filename,
317
319
  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);
320
+ }, [createElementVNode("span", null, toDisplayString(filename), 1), filename === __props.entry ? (openBlock(), createElementBlock("small", _hoisted_4$4, toDisplayString(unref(t)("playground.files.entry")), 1)) : createCommentVNode("v-if", true)], 10, _hoisted_3$4);
319
321
  }), 128))]),
320
322
  _: 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) => {
323
+ }), createElementVNode("div", _hoisted_5$4, [__props.views.length > 1 ? (openBlock(), createElementBlock("div", _hoisted_6$3, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.views, (item) => {
322
324
  return openBlock(), createElementBlock("button", {
323
325
  key: item,
324
326
  type: "button",
@@ -459,25 +461,26 @@ var Drag = class {
459
461
  };
460
462
  //#endregion
461
463
  //#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 = [
464
+ var _hoisted_1$4 = { class: "docs-playground-editor" };
465
+ var _hoisted_2$3 = ["title"];
466
+ var _hoisted_3$3 = { class: "docs-playground-editor__files" };
467
+ var _hoisted_4$3 = [
466
468
  "data-filename",
467
469
  "onClick",
468
470
  "onDblclick"
469
471
  ];
470
- var _hoisted_5$1 = ["onKeydown"];
471
- var _hoisted_6$1 = ["title"];
472
+ var _hoisted_5$3 = ["onKeydown"];
473
+ var _hoisted_6$2 = ["title"];
472
474
  var _hoisted_7$1 = ["title", "aria-label"];
473
475
  var _hoisted_8$1 = ["title", "aria-label"];
474
- var _hoisted_9$1 = { class: "docs-playground-editor__actions" };
475
- var _hoisted_10$1 = ["title"];
476
- var _hoisted_11$1 = ["title", "disabled"];
476
+ var _hoisted_9 = { class: "docs-playground-editor__actions" };
477
+ var _hoisted_10 = ["title"];
478
+ var _hoisted_11 = ["title", "disabled"];
477
479
  var _hoisted_12 = {
478
480
  key: 0,
479
481
  class: "docs-playground-editor__error"
480
482
  };
483
+ var EDITOR_SCROLLER_MAX_HEIGHT = "calc(100vh - 110px)";
481
484
  //#endregion
482
485
  //#region packages/playground/src/editor/index.ts
483
486
  var Editor = new Portal(/* @__PURE__ */ defineComponent({
@@ -506,6 +509,7 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
506
509
  },
507
510
  setup(__props) {
508
511
  const SUPPORTED_FILE_RE = /\.(vue|js|ts|jsx|tsx|css|s[ac]ss|json|html)$/i;
512
+ /** 浮层留白 20px + 标题栏 44px + 文件栏 46px,避免大文件把标签栏挤扁。 */
509
513
  const props = __props;
510
514
  const { t } = useLocale(computed(() => props.locale));
511
515
  const initialFiles = Object.keys(props.files).length ? props.files : { "App.vue": props.value };
@@ -517,6 +521,7 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
517
521
  const textarea = ref(null);
518
522
  const filenameInput = ref(null);
519
523
  const scroller = ref(null);
524
+ const editorScroller = ref(null);
520
525
  const editor = ref(null);
521
526
  const bar = ref(null);
522
527
  const wrapper = ref(null);
@@ -524,6 +529,10 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
524
529
  const renamingFilename = ref("");
525
530
  const filenameDraft = ref("");
526
531
  const codeErrorText = computed(() => props.getCodeErrors().map((item) => item instanceof Error ? item.message : item).join("\n"));
532
+ let editorResize;
533
+ const refreshEditorScroller = () => {
534
+ editorScroller.value?.refresh();
535
+ };
527
536
  const setFilenameInput = (el) => {
528
537
  filenameInput.value = el instanceof HTMLInputElement ? el : null;
529
538
  };
@@ -561,11 +570,13 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
561
570
  filename
562
571
  });
563
572
  if (filename === currentEntry.value) props.onChange(code);
573
+ nextTick(refreshEditorScroller);
564
574
  })
565
575
  ],
566
576
  parent: textarea.value
567
577
  });
568
578
  editor.value.focus();
579
+ nextTick(refreshEditorScroller);
569
580
  };
570
581
  const handleActive = (filename) => {
571
582
  if (filename === activeFilename.value || editorFiles.value[filename] === void 0) return;
@@ -689,13 +700,18 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
689
700
  wrapper: wrapper.value,
690
701
  container: window
691
702
  });
703
+ if (typeof ResizeObserver !== "undefined") {
704
+ editorResize = new ResizeObserver(refreshEditorScroller);
705
+ editorResize.observe(textarea.value);
706
+ }
692
707
  });
693
708
  onBeforeUnmount(() => {
709
+ editorResize?.disconnect();
694
710
  drag.value?.off();
695
711
  editor.value?.destroy();
696
712
  });
697
713
  return (_ctx, _cache) => {
698
- return openBlock(), createElementBlock("div", _hoisted_1$2, [createVNode(unref(TransitionFade), { onAfterLeave: handleHide }, {
714
+ return openBlock(), createElementBlock("div", _hoisted_1$4, [createVNode(unref(TransitionFade), { onAfterLeave: handleHide }, {
699
715
  default: withCtx(() => [withDirectives(createElementVNode("div", {
700
716
  ref_key: "wrapper",
701
717
  ref: wrapper,
@@ -712,8 +728,8 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
712
728
  title: unref(t)("playground.common.close"),
713
729
  style: { "cursor": "pointer" },
714
730
  onClick: handleHide
715
- }, "✕", 8, _hoisted_2$1)], 512),
716
- createElementVNode("div", _hoisted_3$1, [createVNode(unref(Scroller), {
731
+ }, "✕", 8, _hoisted_2$3)], 512),
732
+ createElementVNode("div", _hoisted_3$3, [createVNode(unref(Scroller), {
717
733
  ref_key: "scroller",
718
734
  ref: scroller,
719
735
  class: "docs-playground-editor__scroller",
@@ -741,11 +757,11 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
741
757
  onDblclick: _cache[2] || (_cache[2] = withModifiers(() => {}, ["stop"])),
742
758
  onBlur: handleRenameSubmit,
743
759
  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 }, [
760
+ }, null, 40, _hoisted_5$3)), [[vModelText, filenameDraft.value]]) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
745
761
  filename === currentEntry.value ? (openBlock(), createElementBlock("span", {
746
762
  key: 0,
747
763
  title: unref(t)("playground.editor.entry")
748
- }, "●", 8, _hoisted_6$1)) : createCommentVNode("v-if", true),
764
+ }, "●", 8, _hoisted_6$2)) : createCommentVNode("v-if", true),
749
765
  createElementVNode("span", null, toDisplayString(filename), 1),
750
766
  filename === currentEntry.value ? (openBlock(), createElementBlock("button", {
751
767
  key: 1,
@@ -770,25 +786,37 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
770
786
  }, null, 8, _hoisted_8$1)]),
771
787
  _: 2
772
788
  }, 1032, ["title", "onOk"]))
773
- ], 64))], 42, _hoisted_4$1);
789
+ ], 64))], 42, _hoisted_4$3);
774
790
  }), 128))]),
775
791
  _: 1
776
- }, 512), createElementVNode("div", _hoisted_9$1, [createElementVNode("button", {
792
+ }, 512), createElementVNode("div", _hoisted_9, [createElementVNode("button", {
777
793
  type: "button",
778
794
  title: unref(t)("playground.editor.createFile"),
779
795
  onClick: handleCreate
780
- }, "+", 8, _hoisted_10$1), createElementVNode("button", {
796
+ }, "+", 8, _hoisted_10), createElementVNode("button", {
781
797
  type: "button",
782
798
  title: unref(t)("playground.editor.setEntry"),
783
799
  disabled: activeFilename.value === currentEntry.value,
784
800
  onClick: handleEntry
785
- }, toDisplayString(unref(t)("playground.editor.setEntry")), 9, _hoisted_11$1)])]),
801
+ }, toDisplayString(unref(t)("playground.editor.setEntry")), 9, _hoisted_11)])]),
786
802
  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)
803
+ createVNode(unref(Scroller), {
804
+ ref_key: "editorScroller",
805
+ ref: editorScroller,
806
+ class: "docs-playground-editor__body",
807
+ "auto-resize": true,
808
+ native: false,
809
+ "show-bar": true,
810
+ always: true,
811
+ "max-height": EDITOR_SCROLLER_MAX_HEIGHT
812
+ }, {
813
+ default: withCtx(() => [createElementVNode("div", {
814
+ ref_key: "textarea",
815
+ ref: textarea,
816
+ class: "docs-playground-editor__editor"
817
+ }, null, 512)]),
818
+ _: 1
819
+ }, 512)
792
820
  ], 512), [[vShow, isActive.value]])]),
793
821
  _: 1
794
822
  })]);
@@ -904,6 +932,77 @@ var useSandboxAutoHeight = (sandboxRef) => {
904
932
  });
905
933
  return height;
906
934
  };
935
+ var CLIPPING_OVERFLOW = /* @__PURE__ */ new Set([
936
+ "auto",
937
+ "scroll",
938
+ "hidden",
939
+ "overlay"
940
+ ]);
941
+ var SCROLLABLE_OVERFLOW = /* @__PURE__ */ new Set([
942
+ "auto",
943
+ "scroll",
944
+ "overlay"
945
+ ]);
946
+ var getWindowInnerHeight = () => typeof window === "undefined" ? 0 : window.innerHeight;
947
+ var getPlaygroundHost = (el) => el?.closest(".docs-playground") ?? el;
948
+ var isPlaygroundExpandEnabled = (expand) => {
949
+ if (expand === true) return true;
950
+ return typeof expand === "number" && Number.isFinite(expand) && expand > 0;
951
+ };
952
+ 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)));
953
+ var resolveExpandedPreviewHeight = (expand, availableHeight) => {
954
+ if (expand === true) return Math.max(24, Math.round(Number.isFinite(availableHeight) ? availableHeight : 0));
955
+ return Math.max(24, Math.round(expand));
956
+ };
957
+ var getVisibleViewportRect = (el) => {
958
+ const viewportHeight = getWindowInnerHeight();
959
+ let top = 0;
960
+ let bottom = viewportHeight;
961
+ if (typeof window === "undefined" || !el) return {
962
+ top,
963
+ bottom,
964
+ height: Math.max(0, Math.round(bottom - top))
965
+ };
966
+ let node = getPlaygroundHost(el)?.parentElement ?? null;
967
+ while (node && node !== document.documentElement) {
968
+ const overflowY = getComputedStyle(node).overflowY;
969
+ if (CLIPPING_OVERFLOW.has(overflowY)) {
970
+ const rect = node.getBoundingClientRect();
971
+ if (Number.isFinite(rect.top)) top = Math.max(top, rect.top);
972
+ if (Number.isFinite(rect.bottom)) bottom = Math.min(bottom, rect.bottom);
973
+ }
974
+ node = node.parentElement;
975
+ }
976
+ return {
977
+ top,
978
+ bottom,
979
+ height: Math.max(0, Math.round(bottom - top))
980
+ };
981
+ };
982
+ var findScrollableAncestor = (el) => {
983
+ if (!el || typeof window === "undefined") return null;
984
+ let node = getPlaygroundHost(el)?.parentElement ?? null;
985
+ while (node && node !== document.documentElement) {
986
+ const overflowY = getComputedStyle(node).overflowY;
987
+ if (SCROLLABLE_OVERFLOW.has(overflowY) && node.scrollHeight > node.clientHeight + 1) return node;
988
+ node = node.parentElement;
989
+ }
990
+ return null;
991
+ };
992
+ var scrollPlaygroundToViewportStart = (el) => {
993
+ if (!el) return;
994
+ const host = getPlaygroundHost(el) ?? el;
995
+ const scroller = findScrollableAncestor(host);
996
+ if (scroller) {
997
+ const delta = host.getBoundingClientRect().top - scroller.getBoundingClientRect().top;
998
+ scroller.scrollTop = Math.max(0, scroller.scrollTop + delta);
999
+ return;
1000
+ }
1001
+ if (typeof host.scrollIntoView === "function") host.scrollIntoView({
1002
+ block: "start",
1003
+ behavior: "auto"
1004
+ });
1005
+ };
907
1006
  //#endregion
908
1007
  //#region packages/playground/src/core/runtime/error-guard.ts
909
1008
  var UNKNOWN_RUNTIME_ERROR = "运行时发生未知错误";
@@ -967,6 +1066,89 @@ var useSandboxRuntimeErrorGuard = (sandboxRef) => {
967
1066
  return error;
968
1067
  };
969
1068
  //#endregion
1069
+ //#region packages/playground/src/core/runtime/viewport.ts
1070
+ var DEFAULT_VIEWPORT_OPTIONS = ["auto", 375];
1071
+ var isValidViewport = (viewport) => {
1072
+ if (viewport === "auto") return true;
1073
+ if (typeof viewport === "number") return Number.isFinite(viewport) && viewport > 0;
1074
+ return Array.isArray(viewport) && viewport.length === 2 && viewport.every((value) => typeof value === "number" && Number.isFinite(value) && value > 0);
1075
+ };
1076
+ var getViewportKey = (viewport) => Array.isArray(viewport) ? `${viewport[0]}x${viewport[1]}` : String(viewport);
1077
+ var viewportEquals = (left, right) => getViewportKey(left) === getViewportKey(right);
1078
+ var cloneViewport = (viewport) => Array.isArray(viewport) ? [viewport[0], viewport[1]] : viewport;
1079
+ var normalizeViewportOptions = (options) => {
1080
+ const source = options === void 0 ? DEFAULT_VIEWPORT_OPTIONS : options;
1081
+ const normalized = [];
1082
+ for (const viewport of source) {
1083
+ if (!isValidViewport(viewport)) continue;
1084
+ if (normalized.some((item) => viewportEquals(item, viewport))) continue;
1085
+ normalized.push(cloneViewport(viewport));
1086
+ }
1087
+ return normalized;
1088
+ };
1089
+ var resolveInitialViewport = (viewport, options) => isValidViewport(viewport) ? cloneViewport(viewport) : cloneViewport(options[0] || "auto");
1090
+ var includeActiveViewport = (options, viewport) => {
1091
+ if (!options.length || options.some((item) => viewportEquals(item, viewport))) return options;
1092
+ return [...options, cloneViewport(viewport)];
1093
+ };
1094
+ var getViewportWidth = (viewport) => {
1095
+ if (viewport === "auto") return null;
1096
+ return Array.isArray(viewport) ? viewport[0] : viewport;
1097
+ };
1098
+ var getViewportHeight = (viewport) => Array.isArray(viewport) ? viewport[1] : null;
1099
+ var formatViewportLabel = (viewport, autoLabel = "Auto") => {
1100
+ if (viewport === "auto") return autoLabel;
1101
+ return Array.isArray(viewport) ? `${viewport[0]} × ${viewport[1]}px` : `${viewport}px`;
1102
+ };
1103
+ var getWindowInnerSize = () => {
1104
+ if (typeof window === "undefined") return {
1105
+ width: 0,
1106
+ height: 0
1107
+ };
1108
+ return {
1109
+ width: window.innerWidth,
1110
+ height: window.innerHeight
1111
+ };
1112
+ };
1113
+ var resolvePopupRequestedSize = (viewport, screen = getWindowInnerSize(), gap = 40) => {
1114
+ const safeGap = Number.isFinite(gap) ? Math.max(0, gap) : 40;
1115
+ const maxWidth = Math.max(0, Math.round((Number.isFinite(screen.width) ? screen.width : 0) - safeGap));
1116
+ const maxHeight = Math.max(0, Math.round((Number.isFinite(screen.height) ? screen.height : 0) - safeGap));
1117
+ const viewportWidth = getViewportWidth(viewport);
1118
+ const viewportHeight = getViewportHeight(viewport);
1119
+ return {
1120
+ width: viewportWidth ?? maxWidth,
1121
+ height: viewportHeight ?? maxHeight,
1122
+ maxWidth,
1123
+ maxHeight
1124
+ };
1125
+ };
1126
+ /**
1127
+ * 壳层封顶到 `screen - gap`。未设 viewport 边时,画布铺满工具栏以下区域;
1128
+ * 请求尺寸大于可用区域时由 Scroller 处理溢出。
1129
+ * @param viewport 当前 playground 视口配置。
1130
+ * @param screen 屏幕可用宽高,默认取 `window.inner*`.
1131
+ * @param gap 相对屏幕边缘的留白。
1132
+ * @returns 壳层、内容区与画布尺寸,以及是否需要滚动。
1133
+ */
1134
+ var resolvePopupLayout = (viewport, screen = getWindowInnerSize(), gap = 40) => {
1135
+ const requested = resolvePopupRequestedSize(viewport, screen, gap);
1136
+ const shellWidth = Math.min(requested.width, requested.maxWidth);
1137
+ const shellHeight = Math.min(requested.height, requested.maxHeight);
1138
+ const bodyHeight = Math.max(0, shellHeight - 44);
1139
+ const canvasWidth = getViewportWidth(viewport) ?? shellWidth;
1140
+ const canvasHeight = getViewportHeight(viewport) ?? bodyHeight;
1141
+ return {
1142
+ shellWidth,
1143
+ shellHeight,
1144
+ bodyHeight,
1145
+ canvasWidth,
1146
+ canvasHeight,
1147
+ needsScrollX: canvasWidth > shellWidth,
1148
+ needsScrollY: canvasHeight > bodyHeight
1149
+ };
1150
+ };
1151
+ //#endregion
970
1152
  //#region packages/playground/src/core/runtime/theme.ts
971
1153
  var resolveElementTheme = (element) => {
972
1154
  const vcTheme = element?.getAttribute("data-vc-theme");
@@ -1059,40 +1241,157 @@ var useSandboxTheme = (sandboxRef) => {
1059
1241
  });
1060
1242
  };
1061
1243
  //#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);
1068
- };
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));
1244
+ //#region packages/playground/src/core/runtime/toolbar.vue?vue&type=script&setup=true&lang.ts
1245
+ var _hoisted_1$3 = { class: "docs-playground__tools" };
1246
+ var _hoisted_2$2 = ["title", "aria-label"];
1247
+ var _hoisted_3$2 = [
1248
+ "title",
1249
+ "aria-label",
1250
+ "aria-expanded"
1251
+ ];
1252
+ var _hoisted_4$2 = ["title", "aria-label"];
1253
+ var _hoisted_5$2 = ["title", "aria-label"];
1254
+ var _hoisted_6$1 = ["title", "aria-label"];
1255
+ //#endregion
1256
+ //#region packages/playground/src/core/runtime/toolbar.vue
1257
+ var toolbar_default = /* @__PURE__ */ defineComponent({
1258
+ __name: "toolbar",
1259
+ props: {
1260
+ copyValue: {},
1261
+ viewport: { default: "auto" },
1262
+ viewportOptions: { default: () => ["auto", 375] },
1263
+ showOpenPopup: {
1264
+ type: Boolean,
1265
+ default: false
1266
+ },
1267
+ showClose: {
1268
+ type: Boolean,
1269
+ default: false
1270
+ }
1271
+ },
1272
+ emits: [
1273
+ "refresh",
1274
+ "edit",
1275
+ "open-popup",
1276
+ "close-popup",
1277
+ "viewport-change"
1278
+ ],
1279
+ setup(__props, { emit: __emit }) {
1280
+ const props = __props;
1281
+ const emit = __emit;
1282
+ const { t } = useLocale();
1283
+ const viewportMenuVisible = ref(false);
1284
+ const viewportLabel = computed(() => formatViewportLabel(props.viewport, t("playground.runtime.auto")));
1285
+ const handleViewport = (index) => {
1286
+ const viewport = props.viewportOptions[index];
1287
+ if (viewport && !viewportEquals(viewport, props.viewport)) emit("viewport-change", viewport);
1288
+ };
1289
+ watch(() => props.viewportOptions.length, (length) => {
1290
+ if (length <= 1) viewportMenuVisible.value = false;
1291
+ });
1292
+ return (_ctx, _cache) => {
1293
+ return openBlock(), createElementBlock("div", _hoisted_1$3, [
1294
+ createElementVNode("button", {
1295
+ type: "button",
1296
+ class: "docs-playground__tool docs-playground__refresh",
1297
+ "data-action": "refresh",
1298
+ title: unref(t)("playground.runtime.refresh"),
1299
+ "aria-label": unref(t)("playground.runtime.refresh"),
1300
+ onClick: _cache[0] || (_cache[0] = ($event) => emit("refresh"))
1301
+ }, [createVNode(unref(icon_default), { name: "refresh" })], 8, _hoisted_2$2),
1302
+ __props.viewportOptions.length > 1 ? (openBlock(), createBlock(unref(Dropdown), {
1303
+ key: 0,
1304
+ modelValue: viewportMenuVisible.value,
1305
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => viewportMenuVisible.value = $event),
1306
+ class: "docs-playground__viewport-menu",
1307
+ portal: true,
1308
+ trigger: "click",
1309
+ placement: "bottom-right"
1310
+ }, {
1311
+ content: withCtx(() => [createVNode(unref(DropdownMenu), {
1312
+ class: "docs-playground__viewport-options",
1313
+ role: "menu",
1314
+ "aria-label": unref(t)("playground.runtime.viewportMenu")
1315
+ }, {
1316
+ default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.viewportOptions, (item, index) => {
1317
+ return openBlock(), createBlock(unref(DropdownItem), {
1318
+ key: unref(getViewportKey)(item),
1319
+ class: "docs-playground__viewport-option",
1320
+ value: index,
1321
+ selected: unref(viewportEquals)(item, __props.viewport),
1322
+ role: "menuitemradio",
1323
+ "aria-checked": unref(viewportEquals)(item, __props.viewport),
1324
+ onClick: ($event) => handleViewport(index)
1325
+ }, {
1326
+ default: withCtx(() => [createTextVNode(toDisplayString(unref(formatViewportLabel)(item, unref(t)("playground.runtime.auto"))), 1)]),
1327
+ _: 2
1328
+ }, 1032, [
1329
+ "value",
1330
+ "selected",
1331
+ "aria-checked",
1332
+ "onClick"
1333
+ ]);
1334
+ }), 128))]),
1335
+ _: 1
1336
+ }, 8, ["aria-label"])]),
1337
+ default: withCtx(() => [createElementVNode("button", {
1338
+ type: "button",
1339
+ class: normalizeClass(["docs-playground__tool docs-playground__viewport-trigger", { "is-active": __props.viewport !== "auto" }]),
1340
+ title: unref(t)("playground.runtime.viewport", { value: viewportLabel.value }),
1341
+ "aria-label": unref(t)("playground.runtime.viewport", { value: viewportLabel.value }),
1342
+ "aria-expanded": viewportMenuVisible.value,
1343
+ "aria-haspopup": "menu"
1344
+ }, [createVNode(unref(icon_default), { name: "viewport" })], 10, _hoisted_3$2)]),
1345
+ _: 1
1346
+ }, 8, ["modelValue"])) : createCommentVNode("v-if", true),
1347
+ createVNode(unref(Clipboard), {
1348
+ class: "docs-playground__tool",
1349
+ value: __props.copyValue,
1350
+ tag: "button",
1351
+ type: "button",
1352
+ title: unref(t)("playground.common.copy"),
1353
+ "aria-label": unref(t)("playground.common.copy")
1354
+ }, {
1355
+ default: withCtx(() => [createVNode(unref(icon_default), { name: "copy" })]),
1356
+ _: 1
1357
+ }, 8, [
1358
+ "value",
1359
+ "title",
1360
+ "aria-label"
1361
+ ]),
1362
+ createElementVNode("button", {
1363
+ type: "button",
1364
+ class: "docs-playground__tool docs-playground__editor",
1365
+ "data-action": "edit",
1366
+ title: unref(t)("playground.runtime.editFiles"),
1367
+ "aria-label": unref(t)("playground.runtime.editFiles"),
1368
+ onClick: _cache[2] || (_cache[2] = ($event) => emit("edit"))
1369
+ }, [createVNode(unref(icon_default), { name: "editor" })], 8, _hoisted_4$2),
1370
+ __props.showOpenPopup ? (openBlock(), createElementBlock("button", {
1371
+ key: 1,
1372
+ type: "button",
1373
+ class: "docs-playground__tool docs-playground__popup",
1374
+ "data-action": "open-popup",
1375
+ title: unref(t)("playground.runtime.openPopup"),
1376
+ "aria-label": unref(t)("playground.runtime.openPopup"),
1377
+ onClick: _cache[3] || (_cache[3] = ($event) => emit("open-popup"))
1378
+ }, [createVNode(unref(icon_default), { name: "popup" })], 8, _hoisted_5$2)) : createCommentVNode("v-if", true),
1379
+ __props.showClose ? (openBlock(), createElementBlock("button", {
1380
+ key: 2,
1381
+ type: "button",
1382
+ class: "docs-playground__tool docs-playground__popup-close",
1383
+ "data-action": "close-popup",
1384
+ title: unref(t)("playground.runtime.closePopup"),
1385
+ "aria-label": unref(t)("playground.runtime.closePopup"),
1386
+ onClick: _cache[4] || (_cache[4] = ($event) => emit("close-popup"))
1387
+ }, [..._cache[5] || (_cache[5] = [createElementVNode("span", {
1388
+ class: "docs-playground__popup-close-mark",
1389
+ "aria-hidden": "true"
1390
+ }, "✕", -1)])], 8, _hoisted_6$1)) : createCommentVNode("v-if", true)
1391
+ ]);
1392
+ };
1079
1393
  }
1080
- return normalized;
1081
- };
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)];
1086
- };
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`;
1095
- };
1394
+ });
1096
1395
  //#endregion
1097
1396
  //#region packages/playground/src/cdn.ts
1098
1397
  var PREVIEW_STYLE_ASSETS = [
@@ -1441,6 +1740,12 @@ var DOCS_LINK_USE_CODE = [
1441
1740
  "})"
1442
1741
  ].join("");
1443
1742
  var escapeHtmlAttr = (value) => value.replace(/&/gu, "&amp;").replace(/"/gu, "&quot;").replace(/'/gu, "&#39;").replace(/</gu, "&lt;").replace(/>/gu, "&gt;");
1743
+ /**
1744
+ * runtime 画布色。`previewInset` 露出的 padding、iframe chrome 和 sandbox
1745
+ * `html`/`body` 必须共用这一变量,暗色下 `--docs-background-color` 与
1746
+ * `--vc-background-color-light` 不同,否则会出现色带割裂。
1747
+ */
1748
+ var PLAYGROUND_RUNTIME_CANVAS_BACKGROUND = "var(--vc-background-color-light, var(--docs-background-color, #fff))";
1444
1749
  var createRuntimePreviewOptions = (cdnURL = DEFAULT_CDN_URL) => {
1445
1750
  return {
1446
1751
  showRuntimeError: false,
@@ -1454,8 +1759,8 @@ var createRuntimePreviewOptions = (cdnURL = DEFAULT_CDN_URL) => {
1454
1759
  ...getPlaygroundStyleOverrides()
1455
1760
  }).map((href) => `<link rel="stylesheet" href="${escapeHtmlAttr(href)}">`),
1456
1761
  "<style>",
1457
- "html,body{height:auto;min-height:0}",
1458
- "body{color:var(--vc-foreground-color,#080f20);background:var(--vc-background-color-light,#fff)}",
1762
+ `html,body{height:auto;min-height:0;background:${PLAYGROUND_RUNTIME_CANVAS_BACKGROUND}}`,
1763
+ "body{color:var(--vc-foreground-color,#080f20)}",
1459
1764
  "</style>"
1460
1765
  ].join("\n"),
1461
1766
  customCode: {
@@ -1501,41 +1806,203 @@ var createRuntimeStore = (files, entry, options) => {
1501
1806
  return store;
1502
1807
  };
1503
1808
  //#endregion
1504
- //#region packages/playground/src/core/runtime/runtime.vue?vue&type=script&setup=true&lang.ts
1505
- var _hoisted_1$1 = {
1809
+ //#region packages/playground/src/core/runtime/alone/wrapper.vue?vue&type=script&setup=true&lang.ts
1810
+ var _hoisted_1$2 = ["aria-label"];
1811
+ var _hoisted_2$1 = { class: "docs-playground-popup__frame" };
1812
+ var _hoisted_3$1 = { class: "docs-playground-popup__header" };
1813
+ var _hoisted_4$1 = {
1506
1814
  key: 0,
1507
1815
  class: "docs-playground__runtime-error",
1508
1816
  role: "alert"
1509
1817
  };
1818
+ var _hoisted_5$1 = { class: "docs-playground-popup__body" };
1819
+ //#endregion
1820
+ //#region packages/playground/src/core/runtime/alone/index.ts
1821
+ var Alone = new Portal(/* @__PURE__ */ defineComponent({
1822
+ __name: "wrapper",
1823
+ props: {
1824
+ store: {},
1825
+ copyValue: {},
1826
+ viewport: { default: "auto" },
1827
+ viewportOptions: { default: () => ["auto", 375] },
1828
+ previewOptions: {},
1829
+ clearConsole: {
1830
+ type: Boolean,
1831
+ default: true
1832
+ }
1833
+ },
1834
+ emits: [
1835
+ "edit",
1836
+ "navigate",
1837
+ "viewport-change",
1838
+ "portal-fulfilled"
1839
+ ],
1840
+ setup(__props, { emit: __emit }) {
1841
+ const props = __props;
1842
+ const emit = __emit;
1843
+ const { t } = useLocale();
1844
+ const currentViewport = ref(props.viewport);
1845
+ const sandboxRef = ref(null);
1846
+ const sandboxKey = ref(0);
1847
+ const layoutTick = ref(0);
1848
+ const runtimeError = useSandboxRuntimeErrorGuard(sandboxRef);
1849
+ useSandboxTheme(sandboxRef);
1850
+ const storeErrors = computed(() => (props.store.errors || []).map(toErrorText).filter(Boolean).join("\n"));
1851
+ const errorText = computed(() => {
1852
+ const runtime = runtimeError.value ? formatSandboxRuntimeError(runtimeError.value, t("playground.runtime.importMapTip")) : "";
1853
+ return [storeErrors.value, runtime].filter(Boolean).join("\n\n");
1854
+ });
1855
+ const layout = computed(() => {
1856
+ layoutTick.value;
1857
+ return resolvePopupLayout(currentViewport.value);
1858
+ });
1859
+ const shellStyle = computed(() => ({
1860
+ width: `${layout.value.shellWidth}px`,
1861
+ height: `${layout.value.shellHeight}px`
1862
+ }));
1863
+ const canvasStyle = computed(() => ({
1864
+ width: `${layout.value.canvasWidth}px`,
1865
+ height: `${layout.value.canvasHeight}px`,
1866
+ background: PLAYGROUND_RUNTIME_CANVAS_BACKGROUND
1867
+ }));
1868
+ const handleRefresh = () => {
1869
+ runtimeError.value = "";
1870
+ sandboxKey.value++;
1871
+ };
1872
+ const handleViewportChange = (viewport) => {
1873
+ currentViewport.value = viewport;
1874
+ emit("viewport-change", viewport);
1875
+ };
1876
+ const handleClose = () => emit("portal-fulfilled");
1877
+ const isPlaygroundEditorOpen = () => {
1878
+ if (typeof document === "undefined") return false;
1879
+ const editor = document.querySelector(".docs-playground-editor__wrapper");
1880
+ if (!(editor instanceof HTMLElement)) return false;
1881
+ const style = getComputedStyle(editor);
1882
+ return style.display !== "none" && style.visibility !== "hidden";
1883
+ };
1884
+ const handleKeydown = (event) => {
1885
+ if (event.key !== "Escape") return;
1886
+ if (isPlaygroundEditorOpen()) return;
1887
+ event.preventDefault();
1888
+ handleClose();
1889
+ };
1890
+ const handleResize = () => {
1891
+ layoutTick.value++;
1892
+ };
1893
+ const handleBridgeMessage = (event) => {
1894
+ const iframe = resolveSandboxContainer(sandboxRef.value)?.querySelector("iframe");
1895
+ if (!iframe || event.source !== iframe.contentWindow) return;
1896
+ const data = event.data;
1897
+ if (!data || data.action !== "docs:navigate" || typeof data.to !== "string") return;
1898
+ emit("navigate", data.to);
1899
+ };
1900
+ watch(() => props.viewport, (viewport) => {
1901
+ currentViewport.value = viewport;
1902
+ });
1903
+ if (typeof window !== "undefined") {
1904
+ window.addEventListener("keydown", handleKeydown);
1905
+ window.addEventListener("resize", handleResize);
1906
+ window.addEventListener("message", handleBridgeMessage);
1907
+ }
1908
+ onBeforeUnmount(() => {
1909
+ window.removeEventListener("keydown", handleKeydown);
1910
+ window.removeEventListener("resize", handleResize);
1911
+ window.removeEventListener("message", handleBridgeMessage);
1912
+ });
1913
+ return (_ctx, _cache) => {
1914
+ return openBlock(), createElementBlock("div", {
1915
+ class: "docs-playground-popup",
1916
+ role: "dialog",
1917
+ "aria-modal": "true",
1918
+ "aria-label": unref(t)("playground.runtime.openPopup")
1919
+ }, [createElementVNode("div", {
1920
+ class: "docs-playground-popup__mask",
1921
+ "data-action": "popup-mask",
1922
+ onClick: handleClose
1923
+ }), createElementVNode("div", {
1924
+ class: "docs-playground-popup__shell",
1925
+ style: normalizeStyle(shellStyle.value)
1926
+ }, [createElementVNode("div", _hoisted_2$1, [
1927
+ createElementVNode("div", _hoisted_3$1, [createVNode(toolbar_default, {
1928
+ "copy-value": __props.copyValue,
1929
+ viewport: currentViewport.value,
1930
+ "viewport-options": __props.viewportOptions,
1931
+ "show-close": true,
1932
+ onRefresh: handleRefresh,
1933
+ onEdit: _cache[0] || (_cache[0] = ($event) => emit("edit")),
1934
+ onClosePopup: handleClose,
1935
+ onViewportChange: handleViewportChange
1936
+ }, null, 8, [
1937
+ "copy-value",
1938
+ "viewport",
1939
+ "viewport-options"
1940
+ ])]),
1941
+ errorText.value ? (openBlock(), createElementBlock("pre", _hoisted_4$1, toDisplayString(errorText.value), 1)) : createCommentVNode("v-if", true),
1942
+ createElementVNode("div", _hoisted_5$1, [createVNode(unref(Scroller), {
1943
+ class: "docs-playground-popup__scroller",
1944
+ "content-class": "docs-playground-popup__scroller-content",
1945
+ "auto-resize": true,
1946
+ native: false,
1947
+ "show-bar": true,
1948
+ height: "100%"
1949
+ }, {
1950
+ default: withCtx(() => [createElementVNode("div", {
1951
+ class: "docs-playground-popup__canvas",
1952
+ style: normalizeStyle(canvasStyle.value)
1953
+ }, [(openBlock(), createBlock(unref(Sandbox), {
1954
+ key: sandboxKey.value,
1955
+ ref_key: "sandboxRef",
1956
+ ref: sandboxRef,
1957
+ store: __props.store,
1958
+ "auto-store-init": false,
1959
+ "clear-console": __props.clearConsole,
1960
+ "preview-options": __props.previewOptions
1961
+ }, null, 8, [
1962
+ "store",
1963
+ "clear-console",
1964
+ "preview-options"
1965
+ ]))], 4)]),
1966
+ _: 1
1967
+ })])
1968
+ ])], 4)], 8, _hoisted_1$2);
1969
+ };
1970
+ }
1971
+ }), {
1972
+ name: "docs-playground-alone",
1973
+ leaveDelay: 0,
1974
+ multiple: false
1975
+ });
1976
+ //#endregion
1977
+ //#region packages/playground/src/core/runtime/runtime.vue?vue&type=script&setup=true&lang.ts
1978
+ var _hoisted_1$1 = { class: "docs-playground-runtime-host" };
1510
1979
  var _hoisted_2 = {
1511
- key: 1,
1512
- class: "docs-playground-runtime"
1980
+ key: 0,
1981
+ class: "docs-playground__runtime-error",
1982
+ role: "alert"
1513
1983
  };
1514
1984
  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 = {
1985
+ var _hoisted_4 = {
1524
1986
  key: 0,
1525
1987
  class: "docs-playground__views"
1526
1988
  };
1527
- var _hoisted_9 = [
1989
+ var _hoisted_5 = [
1528
1990
  "title",
1529
1991
  "aria-label",
1530
1992
  "aria-pressed",
1531
1993
  "onClick"
1532
1994
  ];
1533
- var _hoisted_10 = {
1995
+ var _hoisted_6 = {
1534
1996
  key: 0,
1535
1997
  class: "docs-playground__runtime-error",
1536
1998
  role: "alert"
1537
1999
  };
1538
- var _hoisted_11 = { class: "docs-playground-runtime__viewport-stage" };
2000
+ var _hoisted_7 = { class: "docs-playground-runtime__viewport-stage" };
2001
+ var _hoisted_8 = [
2002
+ "aria-expanded",
2003
+ "title",
2004
+ "aria-label"
2005
+ ];
1539
2006
  //#endregion
1540
2007
  //#region packages/playground/src/core/runtime/runtime.vue
1541
2008
  var runtime_default = /* @__PURE__ */ defineComponent({
@@ -1552,6 +2019,7 @@ var runtime_default = /* @__PURE__ */ defineComponent({
1552
2019
  type: Boolean,
1553
2020
  default: false
1554
2021
  },
2022
+ expand: { type: [Boolean, Number] },
1555
2023
  viewport: { default: "auto" },
1556
2024
  viewportOptions: { default: () => ["auto", 375] }
1557
2025
  },
@@ -1567,18 +2035,24 @@ var runtime_default = /* @__PURE__ */ defineComponent({
1567
2035
  const getViewText = (view) => t(playgroundViewMessage(view));
1568
2036
  const emit = __emit;
1569
2037
  const joinCode = (...values) => values.filter(Boolean).join("\n");
1570
- const mergedPreviewOptions = computed(() => {
2038
+ const mergePreviewOptions = (extraHeadHTML) => {
1571
2039
  const runtimePreviewOptions = createRuntimePreviewOptions(props.options.cdnURL);
1572
2040
  return {
1573
2041
  ...runtimePreviewOptions,
1574
2042
  ...props.previewOptions,
1575
- headHTML: [runtimePreviewOptions.headHTML, props.previewOptions?.headHTML].filter(Boolean).join("\n"),
2043
+ headHTML: [
2044
+ runtimePreviewOptions.headHTML,
2045
+ props.previewOptions?.headHTML,
2046
+ extraHeadHTML
2047
+ ].filter(Boolean).join("\n"),
1576
2048
  customCode: {
1577
2049
  importCode: joinCode(runtimePreviewOptions.customCode?.importCode, props.previewOptions?.customCode?.importCode),
1578
2050
  useCode: joinCode(runtimePreviewOptions.customCode?.useCode, props.previewOptions?.customCode?.useCode)
1579
2051
  }
1580
2052
  };
1581
- });
2053
+ };
2054
+ const mergedPreviewOptions = computed(() => mergePreviewOptions());
2055
+ const popupPreviewOptions = computed(() => mergePreviewOptions("<style>html,body{height:100%;min-height:100%}</style>"));
1582
2056
  const clearConsole = {
1583
2057
  "BASE_URL": "/",
1584
2058
  "DEV": false,
@@ -1605,11 +2079,63 @@ var runtime_default = /* @__PURE__ */ defineComponent({
1605
2079
  if (!data || data.action !== "docs:navigate" || typeof data.to !== "string") return;
1606
2080
  emit("navigate", data.to);
1607
2081
  };
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);
2082
+ const runtimeRoot = ref(null);
2083
+ const previewExpanded = ref(false);
2084
+ /** `expand: true` 时在展开瞬间冻结,避免滚动重算高度造成抖动。 */
2085
+ const frozenExpandedHeight = ref(0);
2086
+ const measurePreviewChromeHeight = () => {
2087
+ const root = runtimeRoot.value;
2088
+ if (!root) return 0;
2089
+ const header = root.querySelector(".docs-playground__header");
2090
+ const error = root.querySelector(".docs-playground__runtime-error");
2091
+ return (header instanceof HTMLElement ? header.offsetHeight : 0) + (error instanceof HTMLElement ? error.offsetHeight : 0);
2092
+ };
2093
+ const measureExpandedPreviewHeight = () => {
2094
+ if (typeof window === "undefined") return runtimeHeight.value;
2095
+ const chromeHeight = measurePreviewChromeHeight();
2096
+ return resolveExpandedPreviewHeight(true, resolveRemainingPreviewHeight({
2097
+ viewportHeight: getVisibleViewportRect(runtimeRoot.value).height,
2098
+ chromeHeight
2099
+ }));
2100
+ };
2101
+ const syncFrozenExpandedHeight = () => {
2102
+ if (!previewExpanded.value || props.expand !== true) return;
2103
+ frozenExpandedHeight.value = measureExpandedPreviewHeight();
2104
+ };
2105
+ if (typeof window !== "undefined") {
2106
+ window.addEventListener("message", handleBridgeMessage);
2107
+ window.addEventListener("resize", syncFrozenExpandedHeight);
2108
+ }
2109
+ const canExpandPreview = computed(() => !props.styleless && isPlaygroundExpandEnabled(props.expand));
2110
+ const expandLabel = computed(() => t(previewExpanded.value ? "playground.runtime.collapsePreview" : "playground.runtime.expandPreview"));
2111
+ const desiredViewportHeight = computed(() => {
2112
+ if (previewExpanded.value && props.expand === true) return frozenExpandedHeight.value;
2113
+ if (previewExpanded.value && isPlaygroundExpandEnabled(props.expand)) return resolveExpandedPreviewHeight(props.expand, 0);
2114
+ const fixedHeight = getViewportHeight(props.viewport);
2115
+ if (fixedHeight) return fixedHeight;
2116
+ return runtimeHeight.value;
2117
+ });
2118
+ const scrollExpandedPreviewIntoView = () => {
2119
+ scrollPlaygroundToViewportStart(runtimeRoot.value);
2120
+ };
2121
+ const handleTogglePreviewExpand = () => {
2122
+ if (!canExpandPreview.value) return;
2123
+ if (!previewExpanded.value) {
2124
+ if (props.expand === true) frozenExpandedHeight.value = measureExpandedPreviewHeight();
2125
+ else frozenExpandedHeight.value = 0;
2126
+ previewExpanded.value = true;
2127
+ nextTick(scrollExpandedPreviewIntoView);
2128
+ return;
2129
+ }
2130
+ previewExpanded.value = false;
2131
+ frozenExpandedHeight.value = 0;
2132
+ };
2133
+ watch(canExpandPreview, (enabled) => {
2134
+ if (!enabled) {
2135
+ previewExpanded.value = false;
2136
+ frozenExpandedHeight.value = 0;
2137
+ }
2138
+ });
1613
2139
  const normalizedPreviewInset = computed(() => {
1614
2140
  const value = props.previewInset;
1615
2141
  if (typeof value === "number") return Number.isFinite(value) && value >= 0 ? [value, value] : [10, 10];
@@ -1620,7 +2146,8 @@ var runtime_default = /* @__PURE__ */ defineComponent({
1620
2146
  const [vertical, horizontal] = normalizedPreviewInset.value;
1621
2147
  return {
1622
2148
  height: `${desiredViewportHeight.value + vertical * 2}px`,
1623
- padding: vertical === horizontal ? `${vertical}px` : `${vertical}px ${horizontal}px`
2149
+ padding: vertical === horizontal ? `${vertical}px` : `${vertical}px ${horizontal}px`,
2150
+ background: PLAYGROUND_RUNTIME_CANVAS_BACKGROUND
1624
2151
  };
1625
2152
  });
1626
2153
  const stylelessStyle = computed(() => errorText.value ? void 0 : { height: `${desiredViewportHeight.value}px` });
@@ -1672,18 +2199,30 @@ var runtime_default = /* @__PURE__ */ defineComponent({
1672
2199
  onActiveChange: (filename) => store.setActive(toReplFilename(filename))
1673
2200
  });
1674
2201
  };
1675
- const handleRefresh = () => {
2202
+ const handleInlineRefresh = () => {
1676
2203
  runtimeError.value = "";
1677
2204
  sandboxKey.value++;
1678
2205
  };
2206
+ const handleClosePopup = () => {
2207
+ Alone.destroy();
2208
+ };
2209
+ const handleOpenPopup = () => {
2210
+ Alone.popup({
2211
+ store,
2212
+ copyValue: copyValue.value,
2213
+ viewport: props.viewport,
2214
+ viewportOptions: props.viewportOptions,
2215
+ previewOptions: popupPreviewOptions.value,
2216
+ clearConsole,
2217
+ onEdit: handleEditor,
2218
+ onViewportChange: handleViewportChange,
2219
+ onNavigate: (to) => emit("navigate", to)
2220
+ });
2221
+ };
1679
2222
  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);
2223
+ const handleViewportChange = (viewport) => {
2224
+ emit("viewport-change", viewport);
1683
2225
  };
1684
- watch(() => props.viewportOptions.length, (length) => {
1685
- if (length <= 1) viewportMenuVisible.value = false;
1686
- });
1687
2226
  watch(() => props.files, (files) => {
1688
2227
  if (filesEqual(files, syncedFiles)) return;
1689
2228
  syncedFiles = { ...files };
@@ -1697,12 +2236,22 @@ var runtime_default = /* @__PURE__ */ defineComponent({
1697
2236
  store.mainFile = toReplFilename(entry);
1698
2237
  store.setActive(toReplFilename(entry));
1699
2238
  });
2239
+ watch(() => props.activeView, (view) => {
2240
+ if (view !== "runtime") handleClosePopup();
2241
+ });
2242
+ onBeforeUnmount(() => {
2243
+ window.removeEventListener("message", handleBridgeMessage);
2244
+ window.removeEventListener("resize", syncFrozenExpandedHeight);
2245
+ handleClosePopup();
2246
+ });
1700
2247
  return (_ctx, _cache) => {
1701
- return __props.styleless ? (openBlock(), createElementBlock("div", {
2248
+ return openBlock(), createElementBlock("div", _hoisted_1$1, [__props.styleless ? (openBlock(), createElementBlock("div", {
1702
2249
  key: 0,
2250
+ ref_key: "runtimeRoot",
2251
+ ref: runtimeRoot,
1703
2252
  class: "docs-playground-runtime--styleless",
1704
2253
  style: normalizeStyle(stylelessStyle.value)
1705
- }, [errorText.value ? (openBlock(), createElementBlock("pre", _hoisted_1$1, toDisplayString(errorText.value), 1)) : createCommentVNode("v-if", true), createElementVNode("div", {
2254
+ }, [errorText.value ? (openBlock(), createElementBlock("pre", _hoisted_2, toDisplayString(errorText.value), 1)) : createCommentVNode("v-if", true), createElementVNode("div", {
1706
2255
  class: "docs-playground-runtime__viewport",
1707
2256
  style: normalizeStyle(viewportStyle.value)
1708
2257
  }, [createVNode(unref(Sandbox), {
@@ -1711,85 +2260,26 @@ var runtime_default = /* @__PURE__ */ defineComponent({
1711
2260
  store: unref(store),
1712
2261
  "auto-store-init": false,
1713
2262
  "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) => {
2263
+ }, null, 8, ["store", "preview-options"])], 4)], 4)) : (openBlock(), createElementBlock("div", {
2264
+ key: 1,
2265
+ ref_key: "runtimeRoot",
2266
+ ref: runtimeRoot,
2267
+ class: "docs-playground-runtime"
2268
+ }, [
2269
+ createElementVNode("div", _hoisted_3, [createVNode(toolbar_default, {
2270
+ "copy-value": copyValue.value,
2271
+ viewport: __props.viewport,
2272
+ "viewport-options": __props.viewportOptions,
2273
+ "show-open-popup": true,
2274
+ onRefresh: handleInlineRefresh,
2275
+ onEdit: handleEditor,
2276
+ onOpenPopup: handleOpenPopup,
2277
+ onViewportChange: handleViewportChange
2278
+ }, null, 8, [
2279
+ "copy-value",
2280
+ "viewport",
2281
+ "viewport-options"
2282
+ ]), __props.views.length > 1 ? (openBlock(), createElementBlock("div", _hoisted_4, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.views, (item) => {
1793
2283
  return openBlock(), createElementBlock("button", {
1794
2284
  key: item,
1795
2285
  type: "button",
@@ -1798,13 +2288,13 @@ var runtime_default = /* @__PURE__ */ defineComponent({
1798
2288
  "aria-label": getViewText(item),
1799
2289
  "aria-pressed": item === __props.activeView,
1800
2290
  onClick: ($event) => handleView(item)
1801
- }, [createVNode(unref(icon_default), { name: item }, null, 8, ["name"])], 10, _hoisted_9);
2291
+ }, [createVNode(unref(icon_default), { name: item }, null, 8, ["name"])], 10, _hoisted_5);
1802
2292
  }), 128))])) : createCommentVNode("v-if", true)]),
1803
- errorText.value ? (openBlock(), createElementBlock("pre", _hoisted_10, toDisplayString(errorText.value), 1)) : createCommentVNode("v-if", true),
2293
+ errorText.value ? (openBlock(), createElementBlock("pre", _hoisted_6, toDisplayString(errorText.value), 1)) : createCommentVNode("v-if", true),
1804
2294
  createElementVNode("section", {
1805
- class: "docs-playground__preview",
2295
+ class: normalizeClass(["docs-playground__preview", { "is-expanded": previewExpanded.value }]),
1806
2296
  style: normalizeStyle(previewStyle.value)
1807
- }, [createElementVNode("div", _hoisted_11, [createElementVNode("div", {
2297
+ }, [createElementVNode("div", _hoisted_7, [createElementVNode("div", {
1808
2298
  class: "docs-playground-runtime__viewport",
1809
2299
  style: normalizeStyle(viewportStyle.value)
1810
2300
  }, [(openBlock(), createBlock(unref(Sandbox), {
@@ -1815,8 +2305,17 @@ var runtime_default = /* @__PURE__ */ defineComponent({
1815
2305
  "auto-store-init": false,
1816
2306
  "clear-console": clearConsole,
1817
2307
  "preview-options": mergedPreviewOptions.value
1818
- }, null, 8, ["store", "preview-options"]))], 4)])], 4)
1819
- ]));
2308
+ }, null, 8, ["store", "preview-options"]))], 4)]), canExpandPreview.value ? (openBlock(), createElementBlock("button", {
2309
+ key: 0,
2310
+ type: "button",
2311
+ class: normalizeClass(["docs-playground__expand", { "is-expanded": previewExpanded.value }]),
2312
+ "data-action": "expand-preview",
2313
+ "aria-expanded": previewExpanded.value,
2314
+ title: expandLabel.value,
2315
+ "aria-label": expandLabel.value,
2316
+ onClick: handleTogglePreviewExpand
2317
+ }, [createVNode(unref(icon_default), { name: "expand" })], 10, _hoisted_8)) : createCommentVNode("v-if", true)], 6)
2318
+ ], 512))]);
1820
2319
  };
1821
2320
  }
1822
2321
  });
@@ -1843,6 +2342,7 @@ var playground_default = /* @__PURE__ */ defineComponent({
1843
2342
  },
1844
2343
  options: { default: () => ({}) },
1845
2344
  previewInset: { default: 0 },
2345
+ expand: { type: [Boolean, Number] },
1846
2346
  previewOptions: {},
1847
2347
  locale: {}
1848
2348
  },
@@ -1976,6 +2476,7 @@ var playground_default = /* @__PURE__ */ defineComponent({
1976
2476
  options: __props.options,
1977
2477
  "preview-options": __props.previewOptions,
1978
2478
  "preview-inset": __props.previewInset,
2479
+ expand: __props.expand,
1979
2480
  styleless: true,
1980
2481
  viewport: activeViewport.value,
1981
2482
  "viewport-options": selectableViewportOptions.value,
@@ -1988,6 +2489,7 @@ var playground_default = /* @__PURE__ */ defineComponent({
1988
2489
  "options",
1989
2490
  "preview-options",
1990
2491
  "preview-inset",
2492
+ "expand",
1991
2493
  "viewport",
1992
2494
  "viewport-options"
1993
2495
  ])) : (openBlock(), createElementBlock("div", {
@@ -2002,6 +2504,7 @@ var playground_default = /* @__PURE__ */ defineComponent({
2002
2504
  options: __props.options,
2003
2505
  "preview-options": __props.previewOptions,
2004
2506
  "preview-inset": __props.previewInset,
2507
+ expand: __props.expand,
2005
2508
  "active-view": activeView.value,
2006
2509
  views: normalizedViews.value,
2007
2510
  viewport: activeViewport.value,
@@ -2016,6 +2519,7 @@ var playground_default = /* @__PURE__ */ defineComponent({
2016
2519
  "options",
2017
2520
  "preview-options",
2018
2521
  "preview-inset",
2522
+ "expand",
2019
2523
  "active-view",
2020
2524
  "views",
2021
2525
  "viewport",