@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.cjs CHANGED
@@ -133,12 +133,14 @@ var PLAYGROUND_ICONS = {
133
133
  "c.43-.63.66-1.08.92-1.81h2.37c.25.8.51 1.26.97 1.77l.03.05zM8.12 8.4H2.9",
134
134
  "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",
135
135
  "a1.16 1.16 0 0 0-1.17-1.19M8.1 20.36H2.94V9.64h5.15z"
136
- ].join(""))
136
+ ].join("")),
137
+ expand: strokeIcon("M6 9l6 6 6-6"),
138
+ 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(""))
137
139
  };
138
140
  //#endregion
139
141
  //#region packages/playground/src/icon/icon.vue?vue&type=script&setup=true&lang.ts
140
- var _hoisted_1$5 = ["fill", "stroke"];
141
- var _hoisted_2$4 = ["d"];
142
+ var _hoisted_1$7 = ["fill", "stroke"];
143
+ var _hoisted_2$6 = ["d"];
142
144
  //#endregion
143
145
  //#region packages/playground/src/icon/icon.vue
144
146
  var icon_default = /* @__PURE__ */ (0, vue.defineComponent)({
@@ -169,7 +171,7 @@ var icon_default = /* @__PURE__ */ (0, vue.defineComponent)({
169
171
  "stroke-linecap": "round",
170
172
  "stroke-linejoin": "round",
171
173
  "aria-hidden": "true"
172
- }, [(0, vue.createElementVNode)("path", { d: icon.value.path }, null, 8, _hoisted_2$4)], 12, _hoisted_1$5);
174
+ }, [(0, vue.createElementVNode)("path", { d: icon.value.path }, null, 8, _hoisted_2$6)], 12, _hoisted_1$7);
173
175
  };
174
176
  }
175
177
  });
@@ -178,7 +180,7 @@ var icon_default = /* @__PURE__ */ (0, vue.defineComponent)({
178
180
  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}";
179
181
  //#endregion
180
182
  //#region packages/playground/src/core/code-preview/code-preview.scss?inline
181
- 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}";
183
+ 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}";
182
184
  //#endregion
183
185
  //#region packages/playground/src/core/code-preview/style.ts
184
186
  var CODE_PREVIEW_STYLE_ID = "docs-code-preview-style";
@@ -195,10 +197,10 @@ var ensureCodePreviewStyle = () => {
195
197
  };
196
198
  //#endregion
197
199
  //#region packages/playground/src/core/code-preview/code-preview.vue?vue&type=script&setup=true&lang.ts
198
- var _hoisted_1$4 = { class: "docs-code-preview" };
199
- var _hoisted_2$3 = ["title"];
200
- var _hoisted_3$3 = { class: "docs-code-preview__code" };
201
- var _hoisted_4$3 = ["innerHTML"];
200
+ var _hoisted_1$6 = { class: "docs-code-preview" };
201
+ var _hoisted_2$5 = ["title"];
202
+ var _hoisted_3$5 = { class: "docs-code-preview__code" };
203
+ var _hoisted_4$5 = ["innerHTML"];
202
204
  //#endregion
203
205
  //#region packages/playground/src/core/code-preview/code-preview.vue
204
206
  var code_preview_default = /* @__PURE__ */ (0, vue.defineComponent)({
@@ -229,12 +231,12 @@ var code_preview_default = /* @__PURE__ */ (0, vue.defineComponent)({
229
231
  const highlightLanguage = (0, vue.computed)(() => props.language || resolveHighlightLanguage(props.filename));
230
232
  const highlightedCode = (0, vue.computed)(() => highlightCodeByLanguage(props.code, highlightLanguage.value));
231
233
  return (_ctx, _cache) => {
232
- return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$4, [
234
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$6, [
233
235
  languageLabel.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
234
236
  key: 0,
235
237
  class: "docs-code-preview__language",
236
238
  title: languageLabel.value
237
- }, (0, vue.toDisplayString)(languageLabel.value), 9, _hoisted_2$3)) : (0, vue.createCommentVNode)("v-if", true),
239
+ }, (0, vue.toDisplayString)(languageLabel.value), 9, _hoisted_2$5)) : (0, vue.createCommentVNode)("v-if", true),
238
240
  (0, vue.createVNode)((0, vue.unref)(_deot_vc.Clipboard), {
239
241
  class: "docs-code-preview__copy",
240
242
  value: __props.code,
@@ -251,10 +253,10 @@ var code_preview_default = /* @__PURE__ */ (0, vue.defineComponent)({
251
253
  "aria-label"
252
254
  ]),
253
255
  (0, vue.createCommentVNode)(" eslint-disable-next-line vue/no-v-html "),
254
- (0, vue.createElementVNode)("pre", _hoisted_3$3, [(0, vue.createElementVNode)("code", {
256
+ (0, vue.createElementVNode)("pre", _hoisted_3$5, [(0, vue.createElementVNode)("code", {
255
257
  class: "hljs",
256
258
  innerHTML: highlightedCode.value
257
- }, null, 8, _hoisted_4$3)])
259
+ }, null, 8, _hoisted_4$5)])
258
260
  ]);
259
261
  };
260
262
  }
@@ -280,15 +282,15 @@ var filesEqual = (left, right) => {
280
282
  var playgroundViewMessage = (view) => view === "runtime" ? "playground.runtime.preview" : "playground.runtime.files";
281
283
  //#endregion
282
284
  //#region packages/playground/src/core/files-preview/files-preview.vue?vue&type=script&setup=true&lang.ts
283
- var _hoisted_1$3 = { class: "docs-playground-files" };
284
- var _hoisted_2$2 = { class: "docs-playground-files__toolbar" };
285
- var _hoisted_3$2 = ["data-filename", "onClick"];
286
- var _hoisted_4$2 = {
285
+ var _hoisted_1$5 = { class: "docs-playground-files" };
286
+ var _hoisted_2$4 = { class: "docs-playground-files__toolbar" };
287
+ var _hoisted_3$4 = ["data-filename", "onClick"];
288
+ var _hoisted_4$4 = {
287
289
  key: 0,
288
290
  class: "docs-playground-files__entry"
289
291
  };
290
- var _hoisted_5$2 = { class: "docs-playground-files__actions" };
291
- var _hoisted_6$2 = {
292
+ var _hoisted_5$4 = { class: "docs-playground-files__actions" };
293
+ var _hoisted_6$3 = {
292
294
  key: 0,
293
295
  class: "docs-playground__views docs-playground__views--files"
294
296
  };
@@ -322,7 +324,7 @@ var files_preview_default = /* @__PURE__ */ (0, vue.defineComponent)({
322
324
  };
323
325
  const handleView = (view) => emit("view-change", view);
324
326
  return (_ctx, _cache) => {
325
- return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$3, [(0, vue.createElementVNode)("div", _hoisted_2$2, [(0, vue.createVNode)((0, vue.unref)(_deot_vc.Scroller), {
327
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$5, [(0, vue.createElementVNode)("div", _hoisted_2$4, [(0, vue.createVNode)((0, vue.unref)(_deot_vc.Scroller), {
326
328
  class: "docs-playground-files__scroller",
327
329
  "auto-resize": true,
328
330
  native: false,
@@ -339,10 +341,10 @@ var files_preview_default = /* @__PURE__ */ (0, vue.defineComponent)({
339
341
  class: (0, vue.normalizeClass)(["docs-playground-files__tab", { "is-active": filename === __props.activeFilename }]),
340
342
  "data-filename": filename,
341
343
  onClick: ($event) => handleActive(filename)
342
- }, [(0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(filename), 1), filename === __props.entry ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("small", _hoisted_4$2, (0, vue.toDisplayString)((0, vue.unref)(t)("playground.files.entry")), 1)) : (0, vue.createCommentVNode)("v-if", true)], 10, _hoisted_3$2);
344
+ }, [(0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(filename), 1), filename === __props.entry ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("small", _hoisted_4$4, (0, vue.toDisplayString)((0, vue.unref)(t)("playground.files.entry")), 1)) : (0, vue.createCommentVNode)("v-if", true)], 10, _hoisted_3$4);
343
345
  }), 128))]),
344
346
  _: 1
345
- }), (0, vue.createElementVNode)("div", _hoisted_5$2, [__props.views.length > 1 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_6$2, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.views, (item) => {
347
+ }), (0, vue.createElementVNode)("div", _hoisted_5$4, [__props.views.length > 1 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_6$3, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.views, (item) => {
346
348
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
347
349
  key: item,
348
350
  type: "button",
@@ -483,25 +485,26 @@ var Drag = class {
483
485
  };
484
486
  //#endregion
485
487
  //#region packages/playground/src/editor/editor.vue?vue&type=script&setup=true&lang.ts
486
- var _hoisted_1$2 = { class: "docs-playground-editor" };
487
- var _hoisted_2$1 = ["title"];
488
- var _hoisted_3$1 = { class: "docs-playground-editor__files" };
489
- var _hoisted_4$1 = [
488
+ var _hoisted_1$4 = { class: "docs-playground-editor" };
489
+ var _hoisted_2$3 = ["title"];
490
+ var _hoisted_3$3 = { class: "docs-playground-editor__files" };
491
+ var _hoisted_4$3 = [
490
492
  "data-filename",
491
493
  "onClick",
492
494
  "onDblclick"
493
495
  ];
494
- var _hoisted_5$1 = ["onKeydown"];
495
- var _hoisted_6$1 = ["title"];
496
+ var _hoisted_5$3 = ["onKeydown"];
497
+ var _hoisted_6$2 = ["title"];
496
498
  var _hoisted_7$1 = ["title", "aria-label"];
497
499
  var _hoisted_8$1 = ["title", "aria-label"];
498
- var _hoisted_9$1 = { class: "docs-playground-editor__actions" };
499
- var _hoisted_10$1 = ["title"];
500
- var _hoisted_11$1 = ["title", "disabled"];
500
+ var _hoisted_9 = { class: "docs-playground-editor__actions" };
501
+ var _hoisted_10 = ["title"];
502
+ var _hoisted_11 = ["title", "disabled"];
501
503
  var _hoisted_12 = {
502
504
  key: 0,
503
505
  class: "docs-playground-editor__error"
504
506
  };
507
+ var EDITOR_SCROLLER_MAX_HEIGHT = "calc(100vh - 110px)";
505
508
  //#endregion
506
509
  //#region packages/playground/src/editor/editor.vue
507
510
  var editor_default = /* @__PURE__ */ (0, vue.defineComponent)({
@@ -530,6 +533,7 @@ var editor_default = /* @__PURE__ */ (0, vue.defineComponent)({
530
533
  },
531
534
  setup(__props) {
532
535
  const SUPPORTED_FILE_RE = /\.(vue|js|ts|jsx|tsx|css|s[ac]ss|json|html)$/i;
536
+ /** 浮层留白 20px + 标题栏 44px + 文件栏 46px,避免大文件把标签栏挤扁。 */
533
537
  const props = __props;
534
538
  const { t } = (0, _deot_docs_locale.useLocale)((0, vue.computed)(() => props.locale));
535
539
  const initialFiles = Object.keys(props.files).length ? props.files : { "App.vue": props.value };
@@ -541,6 +545,7 @@ var editor_default = /* @__PURE__ */ (0, vue.defineComponent)({
541
545
  const textarea = (0, vue.ref)(null);
542
546
  const filenameInput = (0, vue.ref)(null);
543
547
  const scroller = (0, vue.ref)(null);
548
+ const editorScroller = (0, vue.ref)(null);
544
549
  const editor = (0, vue.ref)(null);
545
550
  const bar = (0, vue.ref)(null);
546
551
  const wrapper = (0, vue.ref)(null);
@@ -548,6 +553,10 @@ var editor_default = /* @__PURE__ */ (0, vue.defineComponent)({
548
553
  const renamingFilename = (0, vue.ref)("");
549
554
  const filenameDraft = (0, vue.ref)("");
550
555
  const codeErrorText = (0, vue.computed)(() => props.getCodeErrors().map((item) => item instanceof Error ? item.message : item).join("\n"));
556
+ let editorResize;
557
+ const refreshEditorScroller = () => {
558
+ editorScroller.value?.refresh();
559
+ };
551
560
  const setFilenameInput = (el) => {
552
561
  filenameInput.value = el instanceof HTMLInputElement ? el : null;
553
562
  };
@@ -585,11 +594,13 @@ var editor_default = /* @__PURE__ */ (0, vue.defineComponent)({
585
594
  filename
586
595
  });
587
596
  if (filename === currentEntry.value) props.onChange(code);
597
+ (0, vue.nextTick)(refreshEditorScroller);
588
598
  })
589
599
  ],
590
600
  parent: textarea.value
591
601
  });
592
602
  editor.value.focus();
603
+ (0, vue.nextTick)(refreshEditorScroller);
593
604
  };
594
605
  const handleActive = (filename) => {
595
606
  if (filename === activeFilename.value || editorFiles.value[filename] === void 0) return;
@@ -713,13 +724,18 @@ var editor_default = /* @__PURE__ */ (0, vue.defineComponent)({
713
724
  wrapper: wrapper.value,
714
725
  container: window
715
726
  });
727
+ if (typeof ResizeObserver !== "undefined") {
728
+ editorResize = new ResizeObserver(refreshEditorScroller);
729
+ editorResize.observe(textarea.value);
730
+ }
716
731
  });
717
732
  (0, vue.onBeforeUnmount)(() => {
733
+ editorResize?.disconnect();
718
734
  drag.value?.off();
719
735
  editor.value?.destroy();
720
736
  });
721
737
  return (_ctx, _cache) => {
722
- return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$2, [(0, vue.createVNode)((0, vue.unref)(_deot_vc.TransitionFade), { onAfterLeave: handleHide }, {
738
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$4, [(0, vue.createVNode)((0, vue.unref)(_deot_vc.TransitionFade), { onAfterLeave: handleHide }, {
723
739
  default: (0, vue.withCtx)(() => [(0, vue.withDirectives)((0, vue.createElementVNode)("div", {
724
740
  ref_key: "wrapper",
725
741
  ref: wrapper,
@@ -736,8 +752,8 @@ var editor_default = /* @__PURE__ */ (0, vue.defineComponent)({
736
752
  title: (0, vue.unref)(t)("playground.common.close"),
737
753
  style: { "cursor": "pointer" },
738
754
  onClick: handleHide
739
- }, "✕", 8, _hoisted_2$1)], 512),
740
- (0, vue.createElementVNode)("div", _hoisted_3$1, [(0, vue.createVNode)((0, vue.unref)(_deot_vc.Scroller), {
755
+ }, "✕", 8, _hoisted_2$3)], 512),
756
+ (0, vue.createElementVNode)("div", _hoisted_3$3, [(0, vue.createVNode)((0, vue.unref)(_deot_vc.Scroller), {
741
757
  ref_key: "scroller",
742
758
  ref: scroller,
743
759
  class: "docs-playground-editor__scroller",
@@ -765,11 +781,11 @@ var editor_default = /* @__PURE__ */ (0, vue.defineComponent)({
765
781
  onDblclick: _cache[2] || (_cache[2] = (0, vue.withModifiers)(() => {}, ["stop"])),
766
782
  onBlur: handleRenameSubmit,
767
783
  onKeydown: [(0, vue.withKeys)((0, vue.withModifiers)(handleRenameSubmit, ["prevent"]), ["enter"]), (0, vue.withKeys)((0, vue.withModifiers)(handleRenameCancel, ["prevent"]), ["esc"])]
768
- }, null, 40, _hoisted_5$1)), [[vue.vModelText, filenameDraft.value]]) : ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, [
784
+ }, null, 40, _hoisted_5$3)), [[vue.vModelText, filenameDraft.value]]) : ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, [
769
785
  filename === currentEntry.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
770
786
  key: 0,
771
787
  title: (0, vue.unref)(t)("playground.editor.entry")
772
- }, "●", 8, _hoisted_6$1)) : (0, vue.createCommentVNode)("v-if", true),
788
+ }, "●", 8, _hoisted_6$2)) : (0, vue.createCommentVNode)("v-if", true),
773
789
  (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(filename), 1),
774
790
  filename === currentEntry.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
775
791
  key: 1,
@@ -794,25 +810,37 @@ var editor_default = /* @__PURE__ */ (0, vue.defineComponent)({
794
810
  }, null, 8, _hoisted_8$1)]),
795
811
  _: 2
796
812
  }, 1032, ["title", "onOk"]))
797
- ], 64))], 42, _hoisted_4$1);
813
+ ], 64))], 42, _hoisted_4$3);
798
814
  }), 128))]),
799
815
  _: 1
800
- }, 512), (0, vue.createElementVNode)("div", _hoisted_9$1, [(0, vue.createElementVNode)("button", {
816
+ }, 512), (0, vue.createElementVNode)("div", _hoisted_9, [(0, vue.createElementVNode)("button", {
801
817
  type: "button",
802
818
  title: (0, vue.unref)(t)("playground.editor.createFile"),
803
819
  onClick: handleCreate
804
- }, "+", 8, _hoisted_10$1), (0, vue.createElementVNode)("button", {
820
+ }, "+", 8, _hoisted_10), (0, vue.createElementVNode)("button", {
805
821
  type: "button",
806
822
  title: (0, vue.unref)(t)("playground.editor.setEntry"),
807
823
  disabled: activeFilename.value === currentEntry.value,
808
824
  onClick: handleEntry
809
- }, (0, vue.toDisplayString)((0, vue.unref)(t)("playground.editor.setEntry")), 9, _hoisted_11$1)])]),
825
+ }, (0, vue.toDisplayString)((0, vue.unref)(t)("playground.editor.setEntry")), 9, _hoisted_11)])]),
810
826
  codeErrorText.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_12, (0, vue.toDisplayString)(codeErrorText.value), 1)) : (0, vue.createCommentVNode)("v-if", true),
811
- (0, vue.createElementVNode)("div", {
812
- ref_key: "textarea",
813
- ref: textarea,
814
- class: "docs-playground-editor__editor"
815
- }, null, 512)
827
+ (0, vue.createVNode)((0, vue.unref)(_deot_vc.Scroller), {
828
+ ref_key: "editorScroller",
829
+ ref: editorScroller,
830
+ class: "docs-playground-editor__body",
831
+ "auto-resize": true,
832
+ native: false,
833
+ "show-bar": true,
834
+ always: true,
835
+ "max-height": EDITOR_SCROLLER_MAX_HEIGHT
836
+ }, {
837
+ default: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", {
838
+ ref_key: "textarea",
839
+ ref: textarea,
840
+ class: "docs-playground-editor__editor"
841
+ }, null, 512)]),
842
+ _: 1
843
+ }, 512)
816
844
  ], 512), [[vue.vShow, isActive.value]])]),
817
845
  _: 1
818
846
  })]);
@@ -931,6 +959,77 @@ var useSandboxAutoHeight = (sandboxRef) => {
931
959
  });
932
960
  return height;
933
961
  };
962
+ var CLIPPING_OVERFLOW = /* @__PURE__ */ new Set([
963
+ "auto",
964
+ "scroll",
965
+ "hidden",
966
+ "overlay"
967
+ ]);
968
+ var SCROLLABLE_OVERFLOW = /* @__PURE__ */ new Set([
969
+ "auto",
970
+ "scroll",
971
+ "overlay"
972
+ ]);
973
+ var getWindowInnerHeight = () => typeof window === "undefined" ? 0 : window.innerHeight;
974
+ var getPlaygroundHost = (el) => el?.closest(".docs-playground") ?? el;
975
+ var isPlaygroundExpandEnabled = (expand) => {
976
+ if (expand === true) return true;
977
+ return typeof expand === "number" && Number.isFinite(expand) && expand > 0;
978
+ };
979
+ 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)));
980
+ var resolveExpandedPreviewHeight = (expand, availableHeight) => {
981
+ if (expand === true) return Math.max(24, Math.round(Number.isFinite(availableHeight) ? availableHeight : 0));
982
+ return Math.max(24, Math.round(expand));
983
+ };
984
+ var getVisibleViewportRect = (el) => {
985
+ const viewportHeight = getWindowInnerHeight();
986
+ let top = 0;
987
+ let bottom = viewportHeight;
988
+ if (typeof window === "undefined" || !el) return {
989
+ top,
990
+ bottom,
991
+ height: Math.max(0, Math.round(bottom - top))
992
+ };
993
+ let node = getPlaygroundHost(el)?.parentElement ?? null;
994
+ while (node && node !== document.documentElement) {
995
+ const overflowY = getComputedStyle(node).overflowY;
996
+ if (CLIPPING_OVERFLOW.has(overflowY)) {
997
+ const rect = node.getBoundingClientRect();
998
+ if (Number.isFinite(rect.top)) top = Math.max(top, rect.top);
999
+ if (Number.isFinite(rect.bottom)) bottom = Math.min(bottom, rect.bottom);
1000
+ }
1001
+ node = node.parentElement;
1002
+ }
1003
+ return {
1004
+ top,
1005
+ bottom,
1006
+ height: Math.max(0, Math.round(bottom - top))
1007
+ };
1008
+ };
1009
+ var findScrollableAncestor = (el) => {
1010
+ if (!el || typeof window === "undefined") return null;
1011
+ let node = getPlaygroundHost(el)?.parentElement ?? null;
1012
+ while (node && node !== document.documentElement) {
1013
+ const overflowY = getComputedStyle(node).overflowY;
1014
+ if (SCROLLABLE_OVERFLOW.has(overflowY) && node.scrollHeight > node.clientHeight + 1) return node;
1015
+ node = node.parentElement;
1016
+ }
1017
+ return null;
1018
+ };
1019
+ var scrollPlaygroundToViewportStart = (el) => {
1020
+ if (!el) return;
1021
+ const host = getPlaygroundHost(el) ?? el;
1022
+ const scroller = findScrollableAncestor(host);
1023
+ if (scroller) {
1024
+ const delta = host.getBoundingClientRect().top - scroller.getBoundingClientRect().top;
1025
+ scroller.scrollTop = Math.max(0, scroller.scrollTop + delta);
1026
+ return;
1027
+ }
1028
+ if (typeof host.scrollIntoView === "function") host.scrollIntoView({
1029
+ block: "start",
1030
+ behavior: "auto"
1031
+ });
1032
+ };
934
1033
  //#endregion
935
1034
  //#region packages/playground/src/core/runtime/error-guard.ts
936
1035
  var UNKNOWN_RUNTIME_ERROR = "运行时发生未知错误";
@@ -994,6 +1093,89 @@ var useSandboxRuntimeErrorGuard = (sandboxRef) => {
994
1093
  return error;
995
1094
  };
996
1095
  //#endregion
1096
+ //#region packages/playground/src/core/runtime/viewport.ts
1097
+ var DEFAULT_VIEWPORT_OPTIONS = ["auto", 375];
1098
+ var isValidViewport = (viewport) => {
1099
+ if (viewport === "auto") return true;
1100
+ if (typeof viewport === "number") return Number.isFinite(viewport) && viewport > 0;
1101
+ return Array.isArray(viewport) && viewport.length === 2 && viewport.every((value) => typeof value === "number" && Number.isFinite(value) && value > 0);
1102
+ };
1103
+ var getViewportKey = (viewport) => Array.isArray(viewport) ? `${viewport[0]}x${viewport[1]}` : String(viewport);
1104
+ var viewportEquals = (left, right) => getViewportKey(left) === getViewportKey(right);
1105
+ var cloneViewport = (viewport) => Array.isArray(viewport) ? [viewport[0], viewport[1]] : viewport;
1106
+ var normalizeViewportOptions = (options) => {
1107
+ const source = options === void 0 ? DEFAULT_VIEWPORT_OPTIONS : options;
1108
+ const normalized = [];
1109
+ for (const viewport of source) {
1110
+ if (!isValidViewport(viewport)) continue;
1111
+ if (normalized.some((item) => viewportEquals(item, viewport))) continue;
1112
+ normalized.push(cloneViewport(viewport));
1113
+ }
1114
+ return normalized;
1115
+ };
1116
+ var resolveInitialViewport = (viewport, options) => isValidViewport(viewport) ? cloneViewport(viewport) : cloneViewport(options[0] || "auto");
1117
+ var includeActiveViewport = (options, viewport) => {
1118
+ if (!options.length || options.some((item) => viewportEquals(item, viewport))) return options;
1119
+ return [...options, cloneViewport(viewport)];
1120
+ };
1121
+ var getViewportWidth = (viewport) => {
1122
+ if (viewport === "auto") return null;
1123
+ return Array.isArray(viewport) ? viewport[0] : viewport;
1124
+ };
1125
+ var getViewportHeight = (viewport) => Array.isArray(viewport) ? viewport[1] : null;
1126
+ var formatViewportLabel = (viewport, autoLabel = "Auto") => {
1127
+ if (viewport === "auto") return autoLabel;
1128
+ return Array.isArray(viewport) ? `${viewport[0]} × ${viewport[1]}px` : `${viewport}px`;
1129
+ };
1130
+ var getWindowInnerSize = () => {
1131
+ if (typeof window === "undefined") return {
1132
+ width: 0,
1133
+ height: 0
1134
+ };
1135
+ return {
1136
+ width: window.innerWidth,
1137
+ height: window.innerHeight
1138
+ };
1139
+ };
1140
+ var resolvePopupRequestedSize = (viewport, screen = getWindowInnerSize(), gap = 40) => {
1141
+ const safeGap = Number.isFinite(gap) ? Math.max(0, gap) : 40;
1142
+ const maxWidth = Math.max(0, Math.round((Number.isFinite(screen.width) ? screen.width : 0) - safeGap));
1143
+ const maxHeight = Math.max(0, Math.round((Number.isFinite(screen.height) ? screen.height : 0) - safeGap));
1144
+ const viewportWidth = getViewportWidth(viewport);
1145
+ const viewportHeight = getViewportHeight(viewport);
1146
+ return {
1147
+ width: viewportWidth ?? maxWidth,
1148
+ height: viewportHeight ?? maxHeight,
1149
+ maxWidth,
1150
+ maxHeight
1151
+ };
1152
+ };
1153
+ /**
1154
+ * 壳层封顶到 `screen - gap`。未设 viewport 边时,画布铺满工具栏以下区域;
1155
+ * 请求尺寸大于可用区域时由 Scroller 处理溢出。
1156
+ * @param viewport 当前 playground 视口配置。
1157
+ * @param screen 屏幕可用宽高,默认取 `window.inner*`.
1158
+ * @param gap 相对屏幕边缘的留白。
1159
+ * @returns 壳层、内容区与画布尺寸,以及是否需要滚动。
1160
+ */
1161
+ var resolvePopupLayout = (viewport, screen = getWindowInnerSize(), gap = 40) => {
1162
+ const requested = resolvePopupRequestedSize(viewport, screen, gap);
1163
+ const shellWidth = Math.min(requested.width, requested.maxWidth);
1164
+ const shellHeight = Math.min(requested.height, requested.maxHeight);
1165
+ const bodyHeight = Math.max(0, shellHeight - 44);
1166
+ const canvasWidth = getViewportWidth(viewport) ?? shellWidth;
1167
+ const canvasHeight = getViewportHeight(viewport) ?? bodyHeight;
1168
+ return {
1169
+ shellWidth,
1170
+ shellHeight,
1171
+ bodyHeight,
1172
+ canvasWidth,
1173
+ canvasHeight,
1174
+ needsScrollX: canvasWidth > shellWidth,
1175
+ needsScrollY: canvasHeight > bodyHeight
1176
+ };
1177
+ };
1178
+ //#endregion
997
1179
  //#region packages/playground/src/core/runtime/theme.ts
998
1180
  var resolveElementTheme = (element) => {
999
1181
  const vcTheme = element?.getAttribute("data-vc-theme");
@@ -1086,40 +1268,157 @@ var useSandboxTheme = (sandboxRef) => {
1086
1268
  });
1087
1269
  };
1088
1270
  //#endregion
1089
- //#region packages/playground/src/core/runtime/viewport.ts
1090
- var DEFAULT_VIEWPORT_OPTIONS = ["auto", 375];
1091
- var isValidViewport = (viewport) => {
1092
- if (viewport === "auto") return true;
1093
- if (typeof viewport === "number") return Number.isFinite(viewport) && viewport > 0;
1094
- return Array.isArray(viewport) && viewport.length === 2 && viewport.every((value) => typeof value === "number" && Number.isFinite(value) && value > 0);
1095
- };
1096
- var getViewportKey = (viewport) => Array.isArray(viewport) ? `${viewport[0]}x${viewport[1]}` : String(viewport);
1097
- var viewportEquals = (left, right) => getViewportKey(left) === getViewportKey(right);
1098
- var cloneViewport = (viewport) => Array.isArray(viewport) ? [viewport[0], viewport[1]] : viewport;
1099
- var normalizeViewportOptions = (options) => {
1100
- const source = options === void 0 ? DEFAULT_VIEWPORT_OPTIONS : options;
1101
- const normalized = [];
1102
- for (const viewport of source) {
1103
- if (!isValidViewport(viewport)) continue;
1104
- if (normalized.some((item) => viewportEquals(item, viewport))) continue;
1105
- normalized.push(cloneViewport(viewport));
1271
+ //#region packages/playground/src/core/runtime/toolbar.vue?vue&type=script&setup=true&lang.ts
1272
+ var _hoisted_1$3 = { class: "docs-playground__tools" };
1273
+ var _hoisted_2$2 = ["title", "aria-label"];
1274
+ var _hoisted_3$2 = [
1275
+ "title",
1276
+ "aria-label",
1277
+ "aria-expanded"
1278
+ ];
1279
+ var _hoisted_4$2 = ["title", "aria-label"];
1280
+ var _hoisted_5$2 = ["title", "aria-label"];
1281
+ var _hoisted_6$1 = ["title", "aria-label"];
1282
+ //#endregion
1283
+ //#region packages/playground/src/core/runtime/toolbar.vue
1284
+ var toolbar_default = /* @__PURE__ */ (0, vue.defineComponent)({
1285
+ __name: "toolbar",
1286
+ props: {
1287
+ copyValue: {},
1288
+ viewport: { default: "auto" },
1289
+ viewportOptions: { default: () => ["auto", 375] },
1290
+ showOpenPopup: {
1291
+ type: Boolean,
1292
+ default: false
1293
+ },
1294
+ showClose: {
1295
+ type: Boolean,
1296
+ default: false
1297
+ }
1298
+ },
1299
+ emits: [
1300
+ "refresh",
1301
+ "edit",
1302
+ "open-popup",
1303
+ "close-popup",
1304
+ "viewport-change"
1305
+ ],
1306
+ setup(__props, { emit: __emit }) {
1307
+ const props = __props;
1308
+ const emit = __emit;
1309
+ const { t } = (0, _deot_docs_locale.useLocale)();
1310
+ const viewportMenuVisible = (0, vue.ref)(false);
1311
+ const viewportLabel = (0, vue.computed)(() => formatViewportLabel(props.viewport, t("playground.runtime.auto")));
1312
+ const handleViewport = (index) => {
1313
+ const viewport = props.viewportOptions[index];
1314
+ if (viewport && !viewportEquals(viewport, props.viewport)) emit("viewport-change", viewport);
1315
+ };
1316
+ (0, vue.watch)(() => props.viewportOptions.length, (length) => {
1317
+ if (length <= 1) viewportMenuVisible.value = false;
1318
+ });
1319
+ return (_ctx, _cache) => {
1320
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$3, [
1321
+ (0, vue.createElementVNode)("button", {
1322
+ type: "button",
1323
+ class: "docs-playground__tool docs-playground__refresh",
1324
+ "data-action": "refresh",
1325
+ title: (0, vue.unref)(t)("playground.runtime.refresh"),
1326
+ "aria-label": (0, vue.unref)(t)("playground.runtime.refresh"),
1327
+ onClick: _cache[0] || (_cache[0] = ($event) => emit("refresh"))
1328
+ }, [(0, vue.createVNode)((0, vue.unref)(icon_default), { name: "refresh" })], 8, _hoisted_2$2),
1329
+ __props.viewportOptions.length > 1 ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_deot_vc.Dropdown), {
1330
+ key: 0,
1331
+ modelValue: viewportMenuVisible.value,
1332
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => viewportMenuVisible.value = $event),
1333
+ class: "docs-playground__viewport-menu",
1334
+ portal: true,
1335
+ trigger: "click",
1336
+ placement: "bottom-right"
1337
+ }, {
1338
+ content: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_deot_vc.DropdownMenu), {
1339
+ class: "docs-playground__viewport-options",
1340
+ role: "menu",
1341
+ "aria-label": (0, vue.unref)(t)("playground.runtime.viewportMenu")
1342
+ }, {
1343
+ default: (0, vue.withCtx)(() => [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.viewportOptions, (item, index) => {
1344
+ return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_deot_vc.DropdownItem), {
1345
+ key: (0, vue.unref)(getViewportKey)(item),
1346
+ class: "docs-playground__viewport-option",
1347
+ value: index,
1348
+ selected: (0, vue.unref)(viewportEquals)(item, __props.viewport),
1349
+ role: "menuitemradio",
1350
+ "aria-checked": (0, vue.unref)(viewportEquals)(item, __props.viewport),
1351
+ onClick: ($event) => handleViewport(index)
1352
+ }, {
1353
+ default: (0, vue.withCtx)(() => [(0, vue.createTextVNode)((0, vue.toDisplayString)((0, vue.unref)(formatViewportLabel)(item, (0, vue.unref)(t)("playground.runtime.auto"))), 1)]),
1354
+ _: 2
1355
+ }, 1032, [
1356
+ "value",
1357
+ "selected",
1358
+ "aria-checked",
1359
+ "onClick"
1360
+ ]);
1361
+ }), 128))]),
1362
+ _: 1
1363
+ }, 8, ["aria-label"])]),
1364
+ default: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("button", {
1365
+ type: "button",
1366
+ class: (0, vue.normalizeClass)(["docs-playground__tool docs-playground__viewport-trigger", { "is-active": __props.viewport !== "auto" }]),
1367
+ title: (0, vue.unref)(t)("playground.runtime.viewport", { value: viewportLabel.value }),
1368
+ "aria-label": (0, vue.unref)(t)("playground.runtime.viewport", { value: viewportLabel.value }),
1369
+ "aria-expanded": viewportMenuVisible.value,
1370
+ "aria-haspopup": "menu"
1371
+ }, [(0, vue.createVNode)((0, vue.unref)(icon_default), { name: "viewport" })], 10, _hoisted_3$2)]),
1372
+ _: 1
1373
+ }, 8, ["modelValue"])) : (0, vue.createCommentVNode)("v-if", true),
1374
+ (0, vue.createVNode)((0, vue.unref)(_deot_vc.Clipboard), {
1375
+ class: "docs-playground__tool",
1376
+ value: __props.copyValue,
1377
+ tag: "button",
1378
+ type: "button",
1379
+ title: (0, vue.unref)(t)("playground.common.copy"),
1380
+ "aria-label": (0, vue.unref)(t)("playground.common.copy")
1381
+ }, {
1382
+ default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(icon_default), { name: "copy" })]),
1383
+ _: 1
1384
+ }, 8, [
1385
+ "value",
1386
+ "title",
1387
+ "aria-label"
1388
+ ]),
1389
+ (0, vue.createElementVNode)("button", {
1390
+ type: "button",
1391
+ class: "docs-playground__tool docs-playground__editor",
1392
+ "data-action": "edit",
1393
+ title: (0, vue.unref)(t)("playground.runtime.editFiles"),
1394
+ "aria-label": (0, vue.unref)(t)("playground.runtime.editFiles"),
1395
+ onClick: _cache[2] || (_cache[2] = ($event) => emit("edit"))
1396
+ }, [(0, vue.createVNode)((0, vue.unref)(icon_default), { name: "editor" })], 8, _hoisted_4$2),
1397
+ __props.showOpenPopup ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
1398
+ key: 1,
1399
+ type: "button",
1400
+ class: "docs-playground__tool docs-playground__popup",
1401
+ "data-action": "open-popup",
1402
+ title: (0, vue.unref)(t)("playground.runtime.openPopup"),
1403
+ "aria-label": (0, vue.unref)(t)("playground.runtime.openPopup"),
1404
+ onClick: _cache[3] || (_cache[3] = ($event) => emit("open-popup"))
1405
+ }, [(0, vue.createVNode)((0, vue.unref)(icon_default), { name: "popup" })], 8, _hoisted_5$2)) : (0, vue.createCommentVNode)("v-if", true),
1406
+ __props.showClose ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
1407
+ key: 2,
1408
+ type: "button",
1409
+ class: "docs-playground__tool docs-playground__popup-close",
1410
+ "data-action": "close-popup",
1411
+ title: (0, vue.unref)(t)("playground.runtime.closePopup"),
1412
+ "aria-label": (0, vue.unref)(t)("playground.runtime.closePopup"),
1413
+ onClick: _cache[4] || (_cache[4] = ($event) => emit("close-popup"))
1414
+ }, [..._cache[5] || (_cache[5] = [(0, vue.createElementVNode)("span", {
1415
+ class: "docs-playground__popup-close-mark",
1416
+ "aria-hidden": "true"
1417
+ }, "✕", -1)])], 8, _hoisted_6$1)) : (0, vue.createCommentVNode)("v-if", true)
1418
+ ]);
1419
+ };
1106
1420
  }
1107
- return normalized;
1108
- };
1109
- var resolveInitialViewport = (viewport, options) => isValidViewport(viewport) ? cloneViewport(viewport) : cloneViewport(options[0] || "auto");
1110
- var includeActiveViewport = (options, viewport) => {
1111
- if (!options.length || options.some((item) => viewportEquals(item, viewport))) return options;
1112
- return [...options, cloneViewport(viewport)];
1113
- };
1114
- var getViewportWidth = (viewport) => {
1115
- if (viewport === "auto") return null;
1116
- return Array.isArray(viewport) ? viewport[0] : viewport;
1117
- };
1118
- var getViewportHeight = (viewport) => Array.isArray(viewport) ? viewport[1] : null;
1119
- var formatViewportLabel = (viewport, autoLabel = "Auto") => {
1120
- if (viewport === "auto") return autoLabel;
1121
- return Array.isArray(viewport) ? `${viewport[0]} × ${viewport[1]}px` : `${viewport}px`;
1122
- };
1421
+ });
1123
1422
  //#endregion
1124
1423
  //#region packages/playground/src/cdn.ts
1125
1424
  var PREVIEW_STYLE_ASSETS = [
@@ -1468,6 +1767,12 @@ var DOCS_LINK_USE_CODE = [
1468
1767
  "})"
1469
1768
  ].join("");
1470
1769
  var escapeHtmlAttr = (value) => value.replace(/&/gu, "&amp;").replace(/"/gu, "&quot;").replace(/'/gu, "&#39;").replace(/</gu, "&lt;").replace(/>/gu, "&gt;");
1770
+ /**
1771
+ * runtime 画布色。`previewInset` 露出的 padding、iframe chrome 和 sandbox
1772
+ * `html`/`body` 必须共用这一变量,暗色下 `--docs-background-color` 与
1773
+ * `--vc-background-color-light` 不同,否则会出现色带割裂。
1774
+ */
1775
+ var PLAYGROUND_RUNTIME_CANVAS_BACKGROUND = "var(--vc-background-color-light, var(--docs-background-color, #fff))";
1471
1776
  var createRuntimePreviewOptions = (cdnURL = DEFAULT_CDN_URL) => {
1472
1777
  return {
1473
1778
  showRuntimeError: false,
@@ -1481,8 +1786,8 @@ var createRuntimePreviewOptions = (cdnURL = DEFAULT_CDN_URL) => {
1481
1786
  ...getPlaygroundStyleOverrides()
1482
1787
  }).map((href) => `<link rel="stylesheet" href="${escapeHtmlAttr(href)}">`),
1483
1788
  "<style>",
1484
- "html,body{height:auto;min-height:0}",
1485
- "body{color:var(--vc-foreground-color,#080f20);background:var(--vc-background-color-light,#fff)}",
1789
+ `html,body{height:auto;min-height:0;background:${PLAYGROUND_RUNTIME_CANVAS_BACKGROUND}}`,
1790
+ "body{color:var(--vc-foreground-color,#080f20)}",
1486
1791
  "</style>"
1487
1792
  ].join("\n"),
1488
1793
  customCode: {
@@ -1528,41 +1833,206 @@ var createRuntimeStore = (files, entry, options) => {
1528
1833
  return store;
1529
1834
  };
1530
1835
  //#endregion
1531
- //#region packages/playground/src/core/runtime/runtime.vue?vue&type=script&setup=true&lang.ts
1532
- var _hoisted_1$1 = {
1836
+ //#region packages/playground/src/core/runtime/alone/wrapper.vue?vue&type=script&setup=true&lang.ts
1837
+ var _hoisted_1$2 = ["aria-label"];
1838
+ var _hoisted_2$1 = { class: "docs-playground-popup__frame" };
1839
+ var _hoisted_3$1 = { class: "docs-playground-popup__header" };
1840
+ var _hoisted_4$1 = {
1533
1841
  key: 0,
1534
1842
  class: "docs-playground__runtime-error",
1535
1843
  role: "alert"
1536
1844
  };
1845
+ var _hoisted_5$1 = { class: "docs-playground-popup__body" };
1846
+ //#endregion
1847
+ //#region packages/playground/src/core/runtime/alone/wrapper.vue
1848
+ var wrapper_default = /* @__PURE__ */ (0, vue.defineComponent)({
1849
+ __name: "wrapper",
1850
+ props: {
1851
+ store: {},
1852
+ copyValue: {},
1853
+ viewport: { default: "auto" },
1854
+ viewportOptions: { default: () => ["auto", 375] },
1855
+ previewOptions: {},
1856
+ clearConsole: {
1857
+ type: Boolean,
1858
+ default: true
1859
+ }
1860
+ },
1861
+ emits: [
1862
+ "edit",
1863
+ "navigate",
1864
+ "viewport-change",
1865
+ "portal-fulfilled"
1866
+ ],
1867
+ setup(__props, { emit: __emit }) {
1868
+ const props = __props;
1869
+ const emit = __emit;
1870
+ const { t } = (0, _deot_docs_locale.useLocale)();
1871
+ const currentViewport = (0, vue.ref)(props.viewport);
1872
+ const sandboxRef = (0, vue.ref)(null);
1873
+ const sandboxKey = (0, vue.ref)(0);
1874
+ const layoutTick = (0, vue.ref)(0);
1875
+ const runtimeError = useSandboxRuntimeErrorGuard(sandboxRef);
1876
+ useSandboxTheme(sandboxRef);
1877
+ const storeErrors = (0, vue.computed)(() => (props.store.errors || []).map(toErrorText).filter(Boolean).join("\n"));
1878
+ const errorText = (0, vue.computed)(() => {
1879
+ const runtime = runtimeError.value ? formatSandboxRuntimeError(runtimeError.value, t("playground.runtime.importMapTip")) : "";
1880
+ return [storeErrors.value, runtime].filter(Boolean).join("\n\n");
1881
+ });
1882
+ const layout = (0, vue.computed)(() => {
1883
+ layoutTick.value;
1884
+ return resolvePopupLayout(currentViewport.value);
1885
+ });
1886
+ const shellStyle = (0, vue.computed)(() => ({
1887
+ width: `${layout.value.shellWidth}px`,
1888
+ height: `${layout.value.shellHeight}px`
1889
+ }));
1890
+ const canvasStyle = (0, vue.computed)(() => ({
1891
+ width: `${layout.value.canvasWidth}px`,
1892
+ height: `${layout.value.canvasHeight}px`,
1893
+ background: PLAYGROUND_RUNTIME_CANVAS_BACKGROUND
1894
+ }));
1895
+ const handleRefresh = () => {
1896
+ runtimeError.value = "";
1897
+ sandboxKey.value++;
1898
+ };
1899
+ const handleViewportChange = (viewport) => {
1900
+ currentViewport.value = viewport;
1901
+ emit("viewport-change", viewport);
1902
+ };
1903
+ const handleClose = () => emit("portal-fulfilled");
1904
+ const isPlaygroundEditorOpen = () => {
1905
+ if (typeof document === "undefined") return false;
1906
+ const editor = document.querySelector(".docs-playground-editor__wrapper");
1907
+ if (!(editor instanceof HTMLElement)) return false;
1908
+ const style = getComputedStyle(editor);
1909
+ return style.display !== "none" && style.visibility !== "hidden";
1910
+ };
1911
+ const handleKeydown = (event) => {
1912
+ if (event.key !== "Escape") return;
1913
+ if (isPlaygroundEditorOpen()) return;
1914
+ event.preventDefault();
1915
+ handleClose();
1916
+ };
1917
+ const handleResize = () => {
1918
+ layoutTick.value++;
1919
+ };
1920
+ const handleBridgeMessage = (event) => {
1921
+ const iframe = resolveSandboxContainer(sandboxRef.value)?.querySelector("iframe");
1922
+ if (!iframe || event.source !== iframe.contentWindow) return;
1923
+ const data = event.data;
1924
+ if (!data || data.action !== "docs:navigate" || typeof data.to !== "string") return;
1925
+ emit("navigate", data.to);
1926
+ };
1927
+ (0, vue.watch)(() => props.viewport, (viewport) => {
1928
+ currentViewport.value = viewport;
1929
+ });
1930
+ if (typeof window !== "undefined") {
1931
+ window.addEventListener("keydown", handleKeydown);
1932
+ window.addEventListener("resize", handleResize);
1933
+ window.addEventListener("message", handleBridgeMessage);
1934
+ }
1935
+ (0, vue.onBeforeUnmount)(() => {
1936
+ window.removeEventListener("keydown", handleKeydown);
1937
+ window.removeEventListener("resize", handleResize);
1938
+ window.removeEventListener("message", handleBridgeMessage);
1939
+ });
1940
+ return (_ctx, _cache) => {
1941
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
1942
+ class: "docs-playground-popup",
1943
+ role: "dialog",
1944
+ "aria-modal": "true",
1945
+ "aria-label": (0, vue.unref)(t)("playground.runtime.openPopup")
1946
+ }, [(0, vue.createElementVNode)("div", {
1947
+ class: "docs-playground-popup__mask",
1948
+ "data-action": "popup-mask",
1949
+ onClick: handleClose
1950
+ }), (0, vue.createElementVNode)("div", {
1951
+ class: "docs-playground-popup__shell",
1952
+ style: (0, vue.normalizeStyle)(shellStyle.value)
1953
+ }, [(0, vue.createElementVNode)("div", _hoisted_2$1, [
1954
+ (0, vue.createElementVNode)("div", _hoisted_3$1, [(0, vue.createVNode)(toolbar_default, {
1955
+ "copy-value": __props.copyValue,
1956
+ viewport: currentViewport.value,
1957
+ "viewport-options": __props.viewportOptions,
1958
+ "show-close": true,
1959
+ onRefresh: handleRefresh,
1960
+ onEdit: _cache[0] || (_cache[0] = ($event) => emit("edit")),
1961
+ onClosePopup: handleClose,
1962
+ onViewportChange: handleViewportChange
1963
+ }, null, 8, [
1964
+ "copy-value",
1965
+ "viewport",
1966
+ "viewport-options"
1967
+ ])]),
1968
+ errorText.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("pre", _hoisted_4$1, (0, vue.toDisplayString)(errorText.value), 1)) : (0, vue.createCommentVNode)("v-if", true),
1969
+ (0, vue.createElementVNode)("div", _hoisted_5$1, [(0, vue.createVNode)((0, vue.unref)(_deot_vc.Scroller), {
1970
+ class: "docs-playground-popup__scroller",
1971
+ "content-class": "docs-playground-popup__scroller-content",
1972
+ "auto-resize": true,
1973
+ native: false,
1974
+ "show-bar": true,
1975
+ height: "100%"
1976
+ }, {
1977
+ default: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("div", {
1978
+ class: "docs-playground-popup__canvas",
1979
+ style: (0, vue.normalizeStyle)(canvasStyle.value)
1980
+ }, [((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_vue_repl.Sandbox), {
1981
+ key: sandboxKey.value,
1982
+ ref_key: "sandboxRef",
1983
+ ref: sandboxRef,
1984
+ store: __props.store,
1985
+ "auto-store-init": false,
1986
+ "clear-console": __props.clearConsole,
1987
+ "preview-options": __props.previewOptions
1988
+ }, null, 8, [
1989
+ "store",
1990
+ "clear-console",
1991
+ "preview-options"
1992
+ ]))], 4)]),
1993
+ _: 1
1994
+ })])
1995
+ ])], 4)], 8, _hoisted_1$2);
1996
+ };
1997
+ }
1998
+ });
1999
+ //#endregion
2000
+ //#region packages/playground/src/core/runtime/alone/index.ts
2001
+ var Alone = new _deot_vc.Portal(wrapper_default, {
2002
+ name: "docs-playground-alone",
2003
+ leaveDelay: 0,
2004
+ multiple: false
2005
+ });
2006
+ //#endregion
2007
+ //#region packages/playground/src/core/runtime/runtime.vue?vue&type=script&setup=true&lang.ts
2008
+ var _hoisted_1$1 = { class: "docs-playground-runtime-host" };
1537
2009
  var _hoisted_2 = {
1538
- key: 1,
1539
- class: "docs-playground-runtime"
2010
+ key: 0,
2011
+ class: "docs-playground__runtime-error",
2012
+ role: "alert"
1540
2013
  };
1541
2014
  var _hoisted_3 = { class: "docs-playground__header" };
1542
- var _hoisted_4 = { class: "docs-playground__tools" };
1543
- var _hoisted_5 = ["title", "aria-label"];
1544
- var _hoisted_6 = [
1545
- "title",
1546
- "aria-label",
1547
- "aria-expanded"
1548
- ];
1549
- var _hoisted_7 = ["title", "aria-label"];
1550
- var _hoisted_8 = {
2015
+ var _hoisted_4 = {
1551
2016
  key: 0,
1552
2017
  class: "docs-playground__views"
1553
2018
  };
1554
- var _hoisted_9 = [
2019
+ var _hoisted_5 = [
1555
2020
  "title",
1556
2021
  "aria-label",
1557
2022
  "aria-pressed",
1558
2023
  "onClick"
1559
2024
  ];
1560
- var _hoisted_10 = {
2025
+ var _hoisted_6 = {
1561
2026
  key: 0,
1562
2027
  class: "docs-playground__runtime-error",
1563
2028
  role: "alert"
1564
2029
  };
1565
- var _hoisted_11 = { class: "docs-playground-runtime__viewport-stage" };
2030
+ var _hoisted_7 = { class: "docs-playground-runtime__viewport-stage" };
2031
+ var _hoisted_8 = [
2032
+ "aria-expanded",
2033
+ "title",
2034
+ "aria-label"
2035
+ ];
1566
2036
  //#endregion
1567
2037
  //#region packages/playground/src/core/runtime/runtime.vue
1568
2038
  var runtime_default = /* @__PURE__ */ (0, vue.defineComponent)({
@@ -1579,6 +2049,7 @@ var runtime_default = /* @__PURE__ */ (0, vue.defineComponent)({
1579
2049
  type: Boolean,
1580
2050
  default: false
1581
2051
  },
2052
+ expand: { type: [Boolean, Number] },
1582
2053
  viewport: { default: "auto" },
1583
2054
  viewportOptions: { default: () => ["auto", 375] }
1584
2055
  },
@@ -1594,18 +2065,24 @@ var runtime_default = /* @__PURE__ */ (0, vue.defineComponent)({
1594
2065
  const getViewText = (view) => t(playgroundViewMessage(view));
1595
2066
  const emit = __emit;
1596
2067
  const joinCode = (...values) => values.filter(Boolean).join("\n");
1597
- const mergedPreviewOptions = (0, vue.computed)(() => {
2068
+ const mergePreviewOptions = (extraHeadHTML) => {
1598
2069
  const runtimePreviewOptions = createRuntimePreviewOptions(props.options.cdnURL);
1599
2070
  return {
1600
2071
  ...runtimePreviewOptions,
1601
2072
  ...props.previewOptions,
1602
- headHTML: [runtimePreviewOptions.headHTML, props.previewOptions?.headHTML].filter(Boolean).join("\n"),
2073
+ headHTML: [
2074
+ runtimePreviewOptions.headHTML,
2075
+ props.previewOptions?.headHTML,
2076
+ extraHeadHTML
2077
+ ].filter(Boolean).join("\n"),
1603
2078
  customCode: {
1604
2079
  importCode: joinCode(runtimePreviewOptions.customCode?.importCode, props.previewOptions?.customCode?.importCode),
1605
2080
  useCode: joinCode(runtimePreviewOptions.customCode?.useCode, props.previewOptions?.customCode?.useCode)
1606
2081
  }
1607
2082
  };
1608
- });
2083
+ };
2084
+ const mergedPreviewOptions = (0, vue.computed)(() => mergePreviewOptions());
2085
+ const popupPreviewOptions = (0, vue.computed)(() => mergePreviewOptions("<style>html,body{height:100%;min-height:100%}</style>"));
1609
2086
  const clearConsole = {
1610
2087
  "BASE_URL": "/",
1611
2088
  "DEV": false,
@@ -1632,11 +2109,63 @@ var runtime_default = /* @__PURE__ */ (0, vue.defineComponent)({
1632
2109
  if (!data || data.action !== "docs:navigate" || typeof data.to !== "string") return;
1633
2110
  emit("navigate", data.to);
1634
2111
  };
1635
- if (typeof window !== "undefined") window.addEventListener("message", handleBridgeMessage);
1636
- (0, vue.onBeforeUnmount)(() => window.removeEventListener("message", handleBridgeMessage));
1637
- const viewportMenuVisible = (0, vue.ref)(false);
1638
- const viewportLabel = (0, vue.computed)(() => formatViewportLabel(props.viewport, t("playground.runtime.auto")));
1639
- const desiredViewportHeight = (0, vue.computed)(() => getViewportHeight(props.viewport) || runtimeHeight.value);
2112
+ const runtimeRoot = (0, vue.ref)(null);
2113
+ const previewExpanded = (0, vue.ref)(false);
2114
+ /** `expand: true` 时在展开瞬间冻结,避免滚动重算高度造成抖动。 */
2115
+ const frozenExpandedHeight = (0, vue.ref)(0);
2116
+ const measurePreviewChromeHeight = () => {
2117
+ const root = runtimeRoot.value;
2118
+ if (!root) return 0;
2119
+ const header = root.querySelector(".docs-playground__header");
2120
+ const error = root.querySelector(".docs-playground__runtime-error");
2121
+ return (header instanceof HTMLElement ? header.offsetHeight : 0) + (error instanceof HTMLElement ? error.offsetHeight : 0);
2122
+ };
2123
+ const measureExpandedPreviewHeight = () => {
2124
+ if (typeof window === "undefined") return runtimeHeight.value;
2125
+ const chromeHeight = measurePreviewChromeHeight();
2126
+ return resolveExpandedPreviewHeight(true, resolveRemainingPreviewHeight({
2127
+ viewportHeight: getVisibleViewportRect(runtimeRoot.value).height,
2128
+ chromeHeight
2129
+ }));
2130
+ };
2131
+ const syncFrozenExpandedHeight = () => {
2132
+ if (!previewExpanded.value || props.expand !== true) return;
2133
+ frozenExpandedHeight.value = measureExpandedPreviewHeight();
2134
+ };
2135
+ if (typeof window !== "undefined") {
2136
+ window.addEventListener("message", handleBridgeMessage);
2137
+ window.addEventListener("resize", syncFrozenExpandedHeight);
2138
+ }
2139
+ const canExpandPreview = (0, vue.computed)(() => !props.styleless && isPlaygroundExpandEnabled(props.expand));
2140
+ const expandLabel = (0, vue.computed)(() => t(previewExpanded.value ? "playground.runtime.collapsePreview" : "playground.runtime.expandPreview"));
2141
+ const desiredViewportHeight = (0, vue.computed)(() => {
2142
+ if (previewExpanded.value && props.expand === true) return frozenExpandedHeight.value;
2143
+ if (previewExpanded.value && isPlaygroundExpandEnabled(props.expand)) return resolveExpandedPreviewHeight(props.expand, 0);
2144
+ const fixedHeight = getViewportHeight(props.viewport);
2145
+ if (fixedHeight) return fixedHeight;
2146
+ return runtimeHeight.value;
2147
+ });
2148
+ const scrollExpandedPreviewIntoView = () => {
2149
+ scrollPlaygroundToViewportStart(runtimeRoot.value);
2150
+ };
2151
+ const handleTogglePreviewExpand = () => {
2152
+ if (!canExpandPreview.value) return;
2153
+ if (!previewExpanded.value) {
2154
+ if (props.expand === true) frozenExpandedHeight.value = measureExpandedPreviewHeight();
2155
+ else frozenExpandedHeight.value = 0;
2156
+ previewExpanded.value = true;
2157
+ (0, vue.nextTick)(scrollExpandedPreviewIntoView);
2158
+ return;
2159
+ }
2160
+ previewExpanded.value = false;
2161
+ frozenExpandedHeight.value = 0;
2162
+ };
2163
+ (0, vue.watch)(canExpandPreview, (enabled) => {
2164
+ if (!enabled) {
2165
+ previewExpanded.value = false;
2166
+ frozenExpandedHeight.value = 0;
2167
+ }
2168
+ });
1640
2169
  const normalizedPreviewInset = (0, vue.computed)(() => {
1641
2170
  const value = props.previewInset;
1642
2171
  if (typeof value === "number") return Number.isFinite(value) && value >= 0 ? [value, value] : [10, 10];
@@ -1647,7 +2176,8 @@ var runtime_default = /* @__PURE__ */ (0, vue.defineComponent)({
1647
2176
  const [vertical, horizontal] = normalizedPreviewInset.value;
1648
2177
  return {
1649
2178
  height: `${desiredViewportHeight.value + vertical * 2}px`,
1650
- padding: vertical === horizontal ? `${vertical}px` : `${vertical}px ${horizontal}px`
2179
+ padding: vertical === horizontal ? `${vertical}px` : `${vertical}px ${horizontal}px`,
2180
+ background: PLAYGROUND_RUNTIME_CANVAS_BACKGROUND
1651
2181
  };
1652
2182
  });
1653
2183
  const stylelessStyle = (0, vue.computed)(() => errorText.value ? void 0 : { height: `${desiredViewportHeight.value}px` });
@@ -1699,18 +2229,30 @@ var runtime_default = /* @__PURE__ */ (0, vue.defineComponent)({
1699
2229
  onActiveChange: (filename) => store.setActive(toReplFilename(filename))
1700
2230
  });
1701
2231
  };
1702
- const handleRefresh = () => {
2232
+ const handleInlineRefresh = () => {
1703
2233
  runtimeError.value = "";
1704
2234
  sandboxKey.value++;
1705
2235
  };
2236
+ const handleClosePopup = () => {
2237
+ Alone.destroy();
2238
+ };
2239
+ const handleOpenPopup = () => {
2240
+ Alone.popup({
2241
+ store,
2242
+ copyValue: copyValue.value,
2243
+ viewport: props.viewport,
2244
+ viewportOptions: props.viewportOptions,
2245
+ previewOptions: popupPreviewOptions.value,
2246
+ clearConsole,
2247
+ onEdit: handleEditor,
2248
+ onViewportChange: handleViewportChange,
2249
+ onNavigate: (to) => emit("navigate", to)
2250
+ });
2251
+ };
1706
2252
  const handleView = (view) => emit("view-change", view);
1707
- const handleViewport = (index) => {
1708
- const viewport = props.viewportOptions[index];
1709
- if (viewport && !viewportEquals(viewport, props.viewport)) emit("viewport-change", viewport);
2253
+ const handleViewportChange = (viewport) => {
2254
+ emit("viewport-change", viewport);
1710
2255
  };
1711
- (0, vue.watch)(() => props.viewportOptions.length, (length) => {
1712
- if (length <= 1) viewportMenuVisible.value = false;
1713
- });
1714
2256
  (0, vue.watch)(() => props.files, (files) => {
1715
2257
  if (filesEqual(files, syncedFiles)) return;
1716
2258
  syncedFiles = { ...files };
@@ -1724,12 +2266,22 @@ var runtime_default = /* @__PURE__ */ (0, vue.defineComponent)({
1724
2266
  store.mainFile = toReplFilename(entry);
1725
2267
  store.setActive(toReplFilename(entry));
1726
2268
  });
2269
+ (0, vue.watch)(() => props.activeView, (view) => {
2270
+ if (view !== "runtime") handleClosePopup();
2271
+ });
2272
+ (0, vue.onBeforeUnmount)(() => {
2273
+ window.removeEventListener("message", handleBridgeMessage);
2274
+ window.removeEventListener("resize", syncFrozenExpandedHeight);
2275
+ handleClosePopup();
2276
+ });
1727
2277
  return (_ctx, _cache) => {
1728
- return __props.styleless ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
2278
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$1, [__props.styleless ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
1729
2279
  key: 0,
2280
+ ref_key: "runtimeRoot",
2281
+ ref: runtimeRoot,
1730
2282
  class: "docs-playground-runtime--styleless",
1731
2283
  style: (0, vue.normalizeStyle)(stylelessStyle.value)
1732
- }, [errorText.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("pre", _hoisted_1$1, (0, vue.toDisplayString)(errorText.value), 1)) : (0, vue.createCommentVNode)("v-if", true), (0, vue.createElementVNode)("div", {
2284
+ }, [errorText.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("pre", _hoisted_2, (0, vue.toDisplayString)(errorText.value), 1)) : (0, vue.createCommentVNode)("v-if", true), (0, vue.createElementVNode)("div", {
1733
2285
  class: "docs-playground-runtime__viewport",
1734
2286
  style: (0, vue.normalizeStyle)(viewportStyle.value)
1735
2287
  }, [(0, vue.createVNode)((0, vue.unref)(_vue_repl.Sandbox), {
@@ -1738,85 +2290,26 @@ var runtime_default = /* @__PURE__ */ (0, vue.defineComponent)({
1738
2290
  store: (0, vue.unref)(store),
1739
2291
  "auto-store-init": false,
1740
2292
  "preview-options": mergedPreviewOptions.value
1741
- }, null, 8, ["store", "preview-options"])], 4)], 4)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_2, [
1742
- (0, vue.createElementVNode)("div", _hoisted_3, [(0, vue.createElementVNode)("div", _hoisted_4, [
1743
- (0, vue.createElementVNode)("button", {
1744
- type: "button",
1745
- class: "docs-playground__tool docs-playground__refresh",
1746
- "data-action": "refresh",
1747
- title: (0, vue.unref)(t)("playground.runtime.refresh"),
1748
- "aria-label": (0, vue.unref)(t)("playground.runtime.refresh"),
1749
- onClick: handleRefresh
1750
- }, [(0, vue.createVNode)((0, vue.unref)(icon_default), { name: "refresh" })], 8, _hoisted_5),
1751
- __props.viewportOptions.length > 1 ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_deot_vc.Dropdown), {
1752
- key: 0,
1753
- modelValue: viewportMenuVisible.value,
1754
- "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => viewportMenuVisible.value = $event),
1755
- class: "docs-playground__viewport-menu",
1756
- portal: true,
1757
- trigger: "click",
1758
- placement: "bottom-right"
1759
- }, {
1760
- content: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_deot_vc.DropdownMenu), {
1761
- class: "docs-playground__viewport-options",
1762
- role: "menu",
1763
- "aria-label": (0, vue.unref)(t)("playground.runtime.viewportMenu")
1764
- }, {
1765
- default: (0, vue.withCtx)(() => [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.viewportOptions, (item, index) => {
1766
- return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_deot_vc.DropdownItem), {
1767
- key: (0, vue.unref)(getViewportKey)(item),
1768
- class: "docs-playground__viewport-option",
1769
- value: index,
1770
- selected: (0, vue.unref)(viewportEquals)(item, __props.viewport),
1771
- role: "menuitemradio",
1772
- "aria-checked": (0, vue.unref)(viewportEquals)(item, __props.viewport),
1773
- onClick: ($event) => handleViewport(index)
1774
- }, {
1775
- default: (0, vue.withCtx)(() => [(0, vue.createTextVNode)((0, vue.toDisplayString)((0, vue.unref)(formatViewportLabel)(item, (0, vue.unref)(t)("playground.runtime.auto"))), 1)]),
1776
- _: 2
1777
- }, 1032, [
1778
- "value",
1779
- "selected",
1780
- "aria-checked",
1781
- "onClick"
1782
- ]);
1783
- }), 128))]),
1784
- _: 1
1785
- }, 8, ["aria-label"])]),
1786
- default: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("button", {
1787
- type: "button",
1788
- class: (0, vue.normalizeClass)(["docs-playground__tool docs-playground__viewport-trigger", { "is-active": __props.viewport !== "auto" }]),
1789
- title: (0, vue.unref)(t)("playground.runtime.viewport", { value: viewportLabel.value }),
1790
- "aria-label": (0, vue.unref)(t)("playground.runtime.viewport", { value: viewportLabel.value }),
1791
- "aria-expanded": viewportMenuVisible.value,
1792
- "aria-haspopup": "menu"
1793
- }, [(0, vue.createVNode)((0, vue.unref)(icon_default), { name: "viewport" })], 10, _hoisted_6)]),
1794
- _: 1
1795
- }, 8, ["modelValue"])) : (0, vue.createCommentVNode)("v-if", true),
1796
- (0, vue.createVNode)((0, vue.unref)(_deot_vc.Clipboard), {
1797
- class: "docs-playground__tool",
1798
- value: copyValue.value,
1799
- tag: "button",
1800
- type: "button",
1801
- title: (0, vue.unref)(t)("playground.common.copy"),
1802
- "aria-label": (0, vue.unref)(t)("playground.common.copy")
1803
- }, {
1804
- default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(icon_default), { name: "copy" })]),
1805
- _: 1
1806
- }, 8, [
1807
- "value",
1808
- "title",
1809
- "aria-label"
1810
- ]),
1811
- (0, vue.createElementVNode)("button", {
1812
- type: "button",
1813
- class: "docs-playground__tool docs-playground__editor",
1814
- "data-action": "edit",
1815
- title: (0, vue.unref)(t)("playground.runtime.editFiles"),
1816
- "aria-label": (0, vue.unref)(t)("playground.runtime.editFiles"),
1817
- onClick: handleEditor
1818
- }, [(0, vue.createVNode)((0, vue.unref)(icon_default), { name: "editor" })], 8, _hoisted_7)
1819
- ]), __props.views.length > 1 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_8, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.views, (item) => {
2293
+ }, null, 8, ["store", "preview-options"])], 4)], 4)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
2294
+ key: 1,
2295
+ ref_key: "runtimeRoot",
2296
+ ref: runtimeRoot,
2297
+ class: "docs-playground-runtime"
2298
+ }, [
2299
+ (0, vue.createElementVNode)("div", _hoisted_3, [(0, vue.createVNode)(toolbar_default, {
2300
+ "copy-value": copyValue.value,
2301
+ viewport: __props.viewport,
2302
+ "viewport-options": __props.viewportOptions,
2303
+ "show-open-popup": true,
2304
+ onRefresh: handleInlineRefresh,
2305
+ onEdit: handleEditor,
2306
+ onOpenPopup: handleOpenPopup,
2307
+ onViewportChange: handleViewportChange
2308
+ }, null, 8, [
2309
+ "copy-value",
2310
+ "viewport",
2311
+ "viewport-options"
2312
+ ]), __props.views.length > 1 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_4, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.views, (item) => {
1820
2313
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
1821
2314
  key: item,
1822
2315
  type: "button",
@@ -1825,13 +2318,13 @@ var runtime_default = /* @__PURE__ */ (0, vue.defineComponent)({
1825
2318
  "aria-label": getViewText(item),
1826
2319
  "aria-pressed": item === __props.activeView,
1827
2320
  onClick: ($event) => handleView(item)
1828
- }, [(0, vue.createVNode)((0, vue.unref)(icon_default), { name: item }, null, 8, ["name"])], 10, _hoisted_9);
2321
+ }, [(0, vue.createVNode)((0, vue.unref)(icon_default), { name: item }, null, 8, ["name"])], 10, _hoisted_5);
1829
2322
  }), 128))])) : (0, vue.createCommentVNode)("v-if", true)]),
1830
- errorText.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("pre", _hoisted_10, (0, vue.toDisplayString)(errorText.value), 1)) : (0, vue.createCommentVNode)("v-if", true),
2323
+ errorText.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("pre", _hoisted_6, (0, vue.toDisplayString)(errorText.value), 1)) : (0, vue.createCommentVNode)("v-if", true),
1831
2324
  (0, vue.createElementVNode)("section", {
1832
- class: "docs-playground__preview",
2325
+ class: (0, vue.normalizeClass)(["docs-playground__preview", { "is-expanded": previewExpanded.value }]),
1833
2326
  style: (0, vue.normalizeStyle)(previewStyle.value)
1834
- }, [(0, vue.createElementVNode)("div", _hoisted_11, [(0, vue.createElementVNode)("div", {
2327
+ }, [(0, vue.createElementVNode)("div", _hoisted_7, [(0, vue.createElementVNode)("div", {
1835
2328
  class: "docs-playground-runtime__viewport",
1836
2329
  style: (0, vue.normalizeStyle)(viewportStyle.value)
1837
2330
  }, [((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_vue_repl.Sandbox), {
@@ -1842,8 +2335,17 @@ var runtime_default = /* @__PURE__ */ (0, vue.defineComponent)({
1842
2335
  "auto-store-init": false,
1843
2336
  "clear-console": clearConsole,
1844
2337
  "preview-options": mergedPreviewOptions.value
1845
- }, null, 8, ["store", "preview-options"]))], 4)])], 4)
1846
- ]));
2338
+ }, null, 8, ["store", "preview-options"]))], 4)]), canExpandPreview.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
2339
+ key: 0,
2340
+ type: "button",
2341
+ class: (0, vue.normalizeClass)(["docs-playground__expand", { "is-expanded": previewExpanded.value }]),
2342
+ "data-action": "expand-preview",
2343
+ "aria-expanded": previewExpanded.value,
2344
+ title: expandLabel.value,
2345
+ "aria-label": expandLabel.value,
2346
+ onClick: handleTogglePreviewExpand
2347
+ }, [(0, vue.createVNode)((0, vue.unref)(icon_default), { name: "expand" })], 10, _hoisted_8)) : (0, vue.createCommentVNode)("v-if", true)], 6)
2348
+ ], 512))]);
1847
2349
  };
1848
2350
  }
1849
2351
  });
@@ -1870,6 +2372,7 @@ var playground_default = /* @__PURE__ */ (0, vue.defineComponent)({
1870
2372
  },
1871
2373
  options: { default: () => ({}) },
1872
2374
  previewInset: { default: 0 },
2375
+ expand: { type: [Boolean, Number] },
1873
2376
  previewOptions: {},
1874
2377
  locale: {}
1875
2378
  },
@@ -2003,6 +2506,7 @@ var playground_default = /* @__PURE__ */ (0, vue.defineComponent)({
2003
2506
  options: __props.options,
2004
2507
  "preview-options": __props.previewOptions,
2005
2508
  "preview-inset": __props.previewInset,
2509
+ expand: __props.expand,
2006
2510
  styleless: true,
2007
2511
  viewport: activeViewport.value,
2008
2512
  "viewport-options": selectableViewportOptions.value,
@@ -2015,6 +2519,7 @@ var playground_default = /* @__PURE__ */ (0, vue.defineComponent)({
2015
2519
  "options",
2016
2520
  "preview-options",
2017
2521
  "preview-inset",
2522
+ "expand",
2018
2523
  "viewport",
2019
2524
  "viewport-options"
2020
2525
  ])) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
@@ -2029,6 +2534,7 @@ var playground_default = /* @__PURE__ */ (0, vue.defineComponent)({
2029
2534
  options: __props.options,
2030
2535
  "preview-options": __props.previewOptions,
2031
2536
  "preview-inset": __props.previewInset,
2537
+ expand: __props.expand,
2032
2538
  "active-view": activeView.value,
2033
2539
  views: normalizedViews.value,
2034
2540
  viewport: activeViewport.value,
@@ -2043,6 +2549,7 @@ var playground_default = /* @__PURE__ */ (0, vue.defineComponent)({
2043
2549
  "options",
2044
2550
  "preview-options",
2045
2551
  "preview-inset",
2552
+ "expand",
2046
2553
  "active-view",
2047
2554
  "views",
2048
2555
  "viewport",