@deot/docs-playground 1.0.8 → 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
@@ -105,16 +105,42 @@ var highlightCodeByLanguage = (code, language) => {
105
105
  var highlightCode = (code, filename) => highlightCodeByLanguage(code, resolveHighlightLanguage(filename));
106
106
  //#endregion
107
107
  //#region packages/playground/src/icon/icons.ts
108
- var PLAYGROUND_ICON_PATHS = {
109
- runtime: "M5 3h14a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2Zm3 18h8m-4-3v3m-2-13 5 3-5 3V8Z",
110
- files: "M6 2h8l5 5v13a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2Zm8 0v6h5m-9 5-2 2 2 2m5-4 2 2-2 2",
111
- copy: "M9 8h10a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2V10a2 2 0 0 1 2-2Zm-2 8H5a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v4",
112
- editor: "M8 8 4 12l4 4m8-8 4 4-4 4m-3-10-2 12",
113
- viewport: "M3 4h12v10H3V4Zm3 14h6m-3-4v4m9-9h3v11h-6V9h3m0 9h0"
108
+ var strokeIcon = (path) => ({
109
+ path,
110
+ fill: "none",
111
+ stroke: "currentColor"
112
+ });
113
+ var solidIcon = (path) => ({
114
+ path,
115
+ fill: "currentColor",
116
+ stroke: "none"
117
+ });
118
+ var PLAYGROUND_ICONS = {
119
+ runtime: strokeIcon("M5 3h14a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2Zm3 18h8m-4-3v3m-2-13 5 3-5 3V8Z"),
120
+ files: strokeIcon("M6 2h8l5 5v13a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2Zm8 0v6h5m-9 5-2 2 2 2m5-4 2 2-2 2"),
121
+ copy: strokeIcon(["M9 8h10a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2V10a2 2 0 0 1 2-2Z", "m-2 8H5a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v4"].join("")),
122
+ refresh: solidIcon(["M12 2.5a9.5 9.5 0 1 1 0 19 1 1 0 1 1 0-2 7.5 7.5 0 1 0-7.5-7.8l.24-.23a.75.75 0 1 1 1.06 1.06", "L4.03 14.3a.75.75 0 0 1-1.06 0L1.2 12.53a.75.75 0 1 1 1.06-1.06l.24.24A9.5 9.5 0 0 1 12 2.5"].join("")),
123
+ editor: solidIcon([
124
+ "M9.38 19.32a.82.82 0 0 1-.71-1.23l5.85-10.13a.82.82 0 0 1 1.42.82l-5.85 10.13a.8.8 0 0 1-.71.4",
125
+ "m-2.52-.76a.8.8 0 0 1-.58-.25l-4.13-4.12a1.06 1.06 0 0 1 0-1.5l4.13-4.12a.82.82 0 1 1 1.16 1.16",
126
+ "l-3.72 3.71 3.72 3.71a.82.82 0 0 1-.58 1.4m10.9 0a.82.82 0 0 1-.58-1.4l3.7-3.7-3.7-3.72",
127
+ "a.82.82 0 1 1 1.16-1.16l4.12 4.13c.41.4.41 1.08 0 1.49l-4.12 4.12a.8.8 0 0 1-.59.25"
128
+ ].join("")),
129
+ viewport: solidIcon([
130
+ "M21.82 2.93c-.3-.3-.7-.47-1.1-.47H4.6c-.87 0-1.58.7-1.58 1.58v4.18h1.12V3.67h17v12.54",
131
+ "c0 .25-.2.46-.45.46H9.49v1.13h.67q-.25.66-.6 1.11l-.06.06v1.86h7.86a.56.56 0 1 0 0-1.13",
132
+ "q-1.46 0-2.2-1.9h5.55c.87 0 1.57-.71 1.57-1.59V4.04a1.6 1.6 0 0 0-.46-1.11M10.55 19.6",
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
+ "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
+ "a1.16 1.16 0 0 0-1.17-1.19M8.1 20.36H2.94V9.64h5.15z"
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(""))
114
139
  };
115
140
  //#endregion
116
141
  //#region packages/playground/src/icon/icon.vue?vue&type=script&setup=true&lang.ts
117
- var _hoisted_1$5 = ["d"];
142
+ var _hoisted_1$7 = ["fill", "stroke"];
143
+ var _hoisted_2$6 = ["d"];
118
144
  //#endregion
119
145
  //#region packages/playground/src/icon/icon.vue
120
146
  var icon_default = /* @__PURE__ */ (0, vue.defineComponent)({
@@ -125,6 +151,7 @@ var icon_default = /* @__PURE__ */ (0, vue.defineComponent)({
125
151
  },
126
152
  setup(__props) {
127
153
  const props = __props;
154
+ const icon = (0, vue.computed)(() => PLAYGROUND_ICONS[props.name]);
128
155
  const sizeStyle = (0, vue.computed)(() => {
129
156
  if (props.size == null) return;
130
157
  const value = typeof props.size === "number" ? `${props.size}px` : props.size;
@@ -138,13 +165,13 @@ var icon_default = /* @__PURE__ */ (0, vue.defineComponent)({
138
165
  class: "docs-playground-icon",
139
166
  viewBox: "0 0 24 24",
140
167
  style: (0, vue.normalizeStyle)(sizeStyle.value),
141
- fill: "none",
142
- stroke: "currentColor",
168
+ fill: icon.value.fill,
169
+ stroke: icon.value.stroke,
143
170
  "stroke-width": "1.8",
144
171
  "stroke-linecap": "round",
145
172
  "stroke-linejoin": "round",
146
173
  "aria-hidden": "true"
147
- }, [(0, vue.createElementVNode)("path", { d: (0, vue.unref)(PLAYGROUND_ICON_PATHS)[__props.name] }, null, 8, _hoisted_1$5)], 4);
174
+ }, [(0, vue.createElementVNode)("path", { d: icon.value.path }, null, 8, _hoisted_2$6)], 12, _hoisted_1$7);
148
175
  };
149
176
  }
150
177
  });
@@ -153,7 +180,7 @@ var icon_default = /* @__PURE__ */ (0, vue.defineComponent)({
153
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}";
154
181
  //#endregion
155
182
  //#region packages/playground/src/core/code-preview/code-preview.scss?inline
156
- 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}";
157
184
  //#endregion
158
185
  //#region packages/playground/src/core/code-preview/style.ts
159
186
  var CODE_PREVIEW_STYLE_ID = "docs-code-preview-style";
@@ -170,10 +197,10 @@ var ensureCodePreviewStyle = () => {
170
197
  };
171
198
  //#endregion
172
199
  //#region packages/playground/src/core/code-preview/code-preview.vue?vue&type=script&setup=true&lang.ts
173
- var _hoisted_1$4 = { class: "docs-code-preview" };
174
- var _hoisted_2$3 = ["title"];
175
- var _hoisted_3$3 = { class: "docs-code-preview__code" };
176
- 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"];
177
204
  //#endregion
178
205
  //#region packages/playground/src/core/code-preview/code-preview.vue
179
206
  var code_preview_default = /* @__PURE__ */ (0, vue.defineComponent)({
@@ -204,12 +231,12 @@ var code_preview_default = /* @__PURE__ */ (0, vue.defineComponent)({
204
231
  const highlightLanguage = (0, vue.computed)(() => props.language || resolveHighlightLanguage(props.filename));
205
232
  const highlightedCode = (0, vue.computed)(() => highlightCodeByLanguage(props.code, highlightLanguage.value));
206
233
  return (_ctx, _cache) => {
207
- return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$4, [
234
+ return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$6, [
208
235
  languageLabel.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
209
236
  key: 0,
210
237
  class: "docs-code-preview__language",
211
238
  title: languageLabel.value
212
- }, (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),
213
240
  (0, vue.createVNode)((0, vue.unref)(_deot_vc.Clipboard), {
214
241
  class: "docs-code-preview__copy",
215
242
  value: __props.code,
@@ -226,10 +253,10 @@ var code_preview_default = /* @__PURE__ */ (0, vue.defineComponent)({
226
253
  "aria-label"
227
254
  ]),
228
255
  (0, vue.createCommentVNode)(" eslint-disable-next-line vue/no-v-html "),
229
- (0, vue.createElementVNode)("pre", _hoisted_3$3, [(0, vue.createElementVNode)("code", {
256
+ (0, vue.createElementVNode)("pre", _hoisted_3$5, [(0, vue.createElementVNode)("code", {
230
257
  class: "hljs",
231
258
  innerHTML: highlightedCode.value
232
- }, null, 8, _hoisted_4$3)])
259
+ }, null, 8, _hoisted_4$5)])
233
260
  ]);
234
261
  };
235
262
  }
@@ -255,15 +282,15 @@ var filesEqual = (left, right) => {
255
282
  var playgroundViewMessage = (view) => view === "runtime" ? "playground.runtime.preview" : "playground.runtime.files";
256
283
  //#endregion
257
284
  //#region packages/playground/src/core/files-preview/files-preview.vue?vue&type=script&setup=true&lang.ts
258
- var _hoisted_1$3 = { class: "docs-playground-files" };
259
- var _hoisted_2$2 = { class: "docs-playground-files__toolbar" };
260
- var _hoisted_3$2 = ["data-filename", "onClick"];
261
- 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 = {
262
289
  key: 0,
263
290
  class: "docs-playground-files__entry"
264
291
  };
265
- var _hoisted_5$2 = { class: "docs-playground-files__actions" };
266
- var _hoisted_6$2 = {
292
+ var _hoisted_5$4 = { class: "docs-playground-files__actions" };
293
+ var _hoisted_6$3 = {
267
294
  key: 0,
268
295
  class: "docs-playground__views docs-playground__views--files"
269
296
  };
@@ -297,7 +324,7 @@ var files_preview_default = /* @__PURE__ */ (0, vue.defineComponent)({
297
324
  };
298
325
  const handleView = (view) => emit("view-change", view);
299
326
  return (_ctx, _cache) => {
300
- 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), {
301
328
  class: "docs-playground-files__scroller",
302
329
  "auto-resize": true,
303
330
  native: false,
@@ -314,10 +341,10 @@ var files_preview_default = /* @__PURE__ */ (0, vue.defineComponent)({
314
341
  class: (0, vue.normalizeClass)(["docs-playground-files__tab", { "is-active": filename === __props.activeFilename }]),
315
342
  "data-filename": filename,
316
343
  onClick: ($event) => handleActive(filename)
317
- }, [(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);
318
345
  }), 128))]),
319
346
  _: 1
320
- }), (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) => {
321
348
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
322
349
  key: item,
323
350
  type: "button",
@@ -458,25 +485,26 @@ var Drag = class {
458
485
  };
459
486
  //#endregion
460
487
  //#region packages/playground/src/editor/editor.vue?vue&type=script&setup=true&lang.ts
461
- var _hoisted_1$2 = { class: "docs-playground-editor" };
462
- var _hoisted_2$1 = ["title"];
463
- var _hoisted_3$1 = { class: "docs-playground-editor__files" };
464
- 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 = [
465
492
  "data-filename",
466
493
  "onClick",
467
494
  "onDblclick"
468
495
  ];
469
- var _hoisted_5$1 = ["onKeydown"];
470
- var _hoisted_6$1 = ["title"];
496
+ var _hoisted_5$3 = ["onKeydown"];
497
+ var _hoisted_6$2 = ["title"];
471
498
  var _hoisted_7$1 = ["title", "aria-label"];
472
499
  var _hoisted_8$1 = ["title", "aria-label"];
473
- var _hoisted_9$1 = { class: "docs-playground-editor__actions" };
474
- var _hoisted_10$1 = ["title"];
500
+ var _hoisted_9 = { class: "docs-playground-editor__actions" };
501
+ var _hoisted_10 = ["title"];
475
502
  var _hoisted_11 = ["title", "disabled"];
476
503
  var _hoisted_12 = {
477
504
  key: 0,
478
505
  class: "docs-playground-editor__error"
479
506
  };
507
+ var EDITOR_SCROLLER_MAX_HEIGHT = "calc(100vh - 110px)";
480
508
  //#endregion
481
509
  //#region packages/playground/src/editor/editor.vue
482
510
  var editor_default = /* @__PURE__ */ (0, vue.defineComponent)({
@@ -505,6 +533,7 @@ var editor_default = /* @__PURE__ */ (0, vue.defineComponent)({
505
533
  },
506
534
  setup(__props) {
507
535
  const SUPPORTED_FILE_RE = /\.(vue|js|ts|jsx|tsx|css|s[ac]ss|json|html)$/i;
536
+ /** 浮层留白 20px + 标题栏 44px + 文件栏 46px,避免大文件把标签栏挤扁。 */
508
537
  const props = __props;
509
538
  const { t } = (0, _deot_docs_locale.useLocale)((0, vue.computed)(() => props.locale));
510
539
  const initialFiles = Object.keys(props.files).length ? props.files : { "App.vue": props.value };
@@ -516,6 +545,7 @@ var editor_default = /* @__PURE__ */ (0, vue.defineComponent)({
516
545
  const textarea = (0, vue.ref)(null);
517
546
  const filenameInput = (0, vue.ref)(null);
518
547
  const scroller = (0, vue.ref)(null);
548
+ const editorScroller = (0, vue.ref)(null);
519
549
  const editor = (0, vue.ref)(null);
520
550
  const bar = (0, vue.ref)(null);
521
551
  const wrapper = (0, vue.ref)(null);
@@ -523,6 +553,10 @@ var editor_default = /* @__PURE__ */ (0, vue.defineComponent)({
523
553
  const renamingFilename = (0, vue.ref)("");
524
554
  const filenameDraft = (0, vue.ref)("");
525
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
+ };
526
560
  const setFilenameInput = (el) => {
527
561
  filenameInput.value = el instanceof HTMLInputElement ? el : null;
528
562
  };
@@ -560,11 +594,13 @@ var editor_default = /* @__PURE__ */ (0, vue.defineComponent)({
560
594
  filename
561
595
  });
562
596
  if (filename === currentEntry.value) props.onChange(code);
597
+ (0, vue.nextTick)(refreshEditorScroller);
563
598
  })
564
599
  ],
565
600
  parent: textarea.value
566
601
  });
567
602
  editor.value.focus();
603
+ (0, vue.nextTick)(refreshEditorScroller);
568
604
  };
569
605
  const handleActive = (filename) => {
570
606
  if (filename === activeFilename.value || editorFiles.value[filename] === void 0) return;
@@ -688,13 +724,18 @@ var editor_default = /* @__PURE__ */ (0, vue.defineComponent)({
688
724
  wrapper: wrapper.value,
689
725
  container: window
690
726
  });
727
+ if (typeof ResizeObserver !== "undefined") {
728
+ editorResize = new ResizeObserver(refreshEditorScroller);
729
+ editorResize.observe(textarea.value);
730
+ }
691
731
  });
692
732
  (0, vue.onBeforeUnmount)(() => {
733
+ editorResize?.disconnect();
693
734
  drag.value?.off();
694
735
  editor.value?.destroy();
695
736
  });
696
737
  return (_ctx, _cache) => {
697
- 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 }, {
698
739
  default: (0, vue.withCtx)(() => [(0, vue.withDirectives)((0, vue.createElementVNode)("div", {
699
740
  ref_key: "wrapper",
700
741
  ref: wrapper,
@@ -711,8 +752,8 @@ var editor_default = /* @__PURE__ */ (0, vue.defineComponent)({
711
752
  title: (0, vue.unref)(t)("playground.common.close"),
712
753
  style: { "cursor": "pointer" },
713
754
  onClick: handleHide
714
- }, "✕", 8, _hoisted_2$1)], 512),
715
- (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), {
716
757
  ref_key: "scroller",
717
758
  ref: scroller,
718
759
  class: "docs-playground-editor__scroller",
@@ -740,11 +781,11 @@ var editor_default = /* @__PURE__ */ (0, vue.defineComponent)({
740
781
  onDblclick: _cache[2] || (_cache[2] = (0, vue.withModifiers)(() => {}, ["stop"])),
741
782
  onBlur: handleRenameSubmit,
742
783
  onKeydown: [(0, vue.withKeys)((0, vue.withModifiers)(handleRenameSubmit, ["prevent"]), ["enter"]), (0, vue.withKeys)((0, vue.withModifiers)(handleRenameCancel, ["prevent"]), ["esc"])]
743
- }, 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 }, [
744
785
  filename === currentEntry.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
745
786
  key: 0,
746
787
  title: (0, vue.unref)(t)("playground.editor.entry")
747
- }, "●", 8, _hoisted_6$1)) : (0, vue.createCommentVNode)("v-if", true),
788
+ }, "●", 8, _hoisted_6$2)) : (0, vue.createCommentVNode)("v-if", true),
748
789
  (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(filename), 1),
749
790
  filename === currentEntry.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
750
791
  key: 1,
@@ -769,25 +810,37 @@ var editor_default = /* @__PURE__ */ (0, vue.defineComponent)({
769
810
  }, null, 8, _hoisted_8$1)]),
770
811
  _: 2
771
812
  }, 1032, ["title", "onOk"]))
772
- ], 64))], 42, _hoisted_4$1);
813
+ ], 64))], 42, _hoisted_4$3);
773
814
  }), 128))]),
774
815
  _: 1
775
- }, 512), (0, vue.createElementVNode)("div", _hoisted_9$1, [(0, vue.createElementVNode)("button", {
816
+ }, 512), (0, vue.createElementVNode)("div", _hoisted_9, [(0, vue.createElementVNode)("button", {
776
817
  type: "button",
777
818
  title: (0, vue.unref)(t)("playground.editor.createFile"),
778
819
  onClick: handleCreate
779
- }, "+", 8, _hoisted_10$1), (0, vue.createElementVNode)("button", {
820
+ }, "+", 8, _hoisted_10), (0, vue.createElementVNode)("button", {
780
821
  type: "button",
781
822
  title: (0, vue.unref)(t)("playground.editor.setEntry"),
782
823
  disabled: activeFilename.value === currentEntry.value,
783
824
  onClick: handleEntry
784
825
  }, (0, vue.toDisplayString)((0, vue.unref)(t)("playground.editor.setEntry")), 9, _hoisted_11)])]),
785
826
  codeErrorText.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_12, (0, vue.toDisplayString)(codeErrorText.value), 1)) : (0, vue.createCommentVNode)("v-if", true),
786
- (0, vue.createElementVNode)("div", {
787
- ref_key: "textarea",
788
- ref: textarea,
789
- class: "docs-playground-editor__editor"
790
- }, 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)
791
844
  ], 512), [[vue.vShow, isActive.value]])]),
792
845
  _: 1
793
846
  })]);
@@ -906,6 +959,77 @@ var useSandboxAutoHeight = (sandboxRef) => {
906
959
  });
907
960
  return height;
908
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
+ };
909
1033
  //#endregion
910
1034
  //#region packages/playground/src/core/runtime/error-guard.ts
911
1035
  var UNKNOWN_RUNTIME_ERROR = "运行时发生未知错误";
@@ -969,6 +1093,89 @@ var useSandboxRuntimeErrorGuard = (sandboxRef) => {
969
1093
  return error;
970
1094
  };
971
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
972
1179
  //#region packages/playground/src/core/runtime/theme.ts
973
1180
  var resolveElementTheme = (element) => {
974
1181
  const vcTheme = element?.getAttribute("data-vc-theme");
@@ -1061,40 +1268,157 @@ var useSandboxTheme = (sandboxRef) => {
1061
1268
  });
1062
1269
  };
1063
1270
  //#endregion
1064
- //#region packages/playground/src/core/runtime/viewport.ts
1065
- var DEFAULT_VIEWPORT_OPTIONS = ["auto", 375];
1066
- var isValidViewport = (viewport) => {
1067
- if (viewport === "auto") return true;
1068
- if (typeof viewport === "number") return Number.isFinite(viewport) && viewport > 0;
1069
- return Array.isArray(viewport) && viewport.length === 2 && viewport.every((value) => typeof value === "number" && Number.isFinite(value) && value > 0);
1070
- };
1071
- var getViewportKey = (viewport) => Array.isArray(viewport) ? `${viewport[0]}x${viewport[1]}` : String(viewport);
1072
- var viewportEquals = (left, right) => getViewportKey(left) === getViewportKey(right);
1073
- var cloneViewport = (viewport) => Array.isArray(viewport) ? [viewport[0], viewport[1]] : viewport;
1074
- var normalizeViewportOptions = (options) => {
1075
- const source = options === void 0 ? DEFAULT_VIEWPORT_OPTIONS : options;
1076
- const normalized = [];
1077
- for (const viewport of source) {
1078
- if (!isValidViewport(viewport)) continue;
1079
- if (normalized.some((item) => viewportEquals(item, viewport))) continue;
1080
- 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
+ };
1081
1420
  }
1082
- return normalized;
1083
- };
1084
- var resolveInitialViewport = (viewport, options) => isValidViewport(viewport) ? cloneViewport(viewport) : cloneViewport(options[0] || "auto");
1085
- var includeActiveViewport = (options, viewport) => {
1086
- if (!options.length || options.some((item) => viewportEquals(item, viewport))) return options;
1087
- return [...options, cloneViewport(viewport)];
1088
- };
1089
- var getViewportWidth = (viewport) => {
1090
- if (viewport === "auto") return null;
1091
- return Array.isArray(viewport) ? viewport[0] : viewport;
1092
- };
1093
- var getViewportHeight = (viewport) => Array.isArray(viewport) ? viewport[1] : null;
1094
- var formatViewportLabel = (viewport, autoLabel = "Auto") => {
1095
- if (viewport === "auto") return autoLabel;
1096
- return Array.isArray(viewport) ? `${viewport[0]} × ${viewport[1]}px` : `${viewport}px`;
1097
- };
1421
+ });
1098
1422
  //#endregion
1099
1423
  //#region packages/playground/src/cdn.ts
1100
1424
  var PREVIEW_STYLE_ASSETS = [
@@ -1443,6 +1767,12 @@ var DOCS_LINK_USE_CODE = [
1443
1767
  "})"
1444
1768
  ].join("");
1445
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))";
1446
1776
  var createRuntimePreviewOptions = (cdnURL = DEFAULT_CDN_URL) => {
1447
1777
  return {
1448
1778
  showRuntimeError: false,
@@ -1456,8 +1786,8 @@ var createRuntimePreviewOptions = (cdnURL = DEFAULT_CDN_URL) => {
1456
1786
  ...getPlaygroundStyleOverrides()
1457
1787
  }).map((href) => `<link rel="stylesheet" href="${escapeHtmlAttr(href)}">`),
1458
1788
  "<style>",
1459
- "html,body{height:auto;min-height:0}",
1460
- "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)}",
1461
1791
  "</style>"
1462
1792
  ].join("\n"),
1463
1793
  customCode: {
@@ -1503,40 +1833,206 @@ var createRuntimeStore = (files, entry, options) => {
1503
1833
  return store;
1504
1834
  };
1505
1835
  //#endregion
1506
- //#region packages/playground/src/core/runtime/runtime.vue?vue&type=script&setup=true&lang.ts
1507
- 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 = {
1508
1841
  key: 0,
1509
1842
  class: "docs-playground__runtime-error",
1510
1843
  role: "alert"
1511
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" };
1512
2009
  var _hoisted_2 = {
1513
- key: 1,
1514
- class: "docs-playground-runtime"
2010
+ key: 0,
2011
+ class: "docs-playground__runtime-error",
2012
+ role: "alert"
1515
2013
  };
1516
2014
  var _hoisted_3 = { class: "docs-playground__header" };
1517
- var _hoisted_4 = { class: "docs-playground__tools" };
1518
- var _hoisted_5 = [
1519
- "title",
1520
- "aria-label",
1521
- "aria-expanded"
1522
- ];
1523
- var _hoisted_6 = ["title", "aria-label"];
1524
- var _hoisted_7 = {
2015
+ var _hoisted_4 = {
1525
2016
  key: 0,
1526
2017
  class: "docs-playground__views"
1527
2018
  };
1528
- var _hoisted_8 = [
2019
+ var _hoisted_5 = [
1529
2020
  "title",
1530
2021
  "aria-label",
1531
2022
  "aria-pressed",
1532
2023
  "onClick"
1533
2024
  ];
1534
- var _hoisted_9 = {
2025
+ var _hoisted_6 = {
1535
2026
  key: 0,
1536
2027
  class: "docs-playground__runtime-error",
1537
2028
  role: "alert"
1538
2029
  };
1539
- var _hoisted_10 = { 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
+ ];
1540
2036
  //#endregion
1541
2037
  //#region packages/playground/src/core/runtime/runtime.vue
1542
2038
  var runtime_default = /* @__PURE__ */ (0, vue.defineComponent)({
@@ -1553,6 +2049,7 @@ var runtime_default = /* @__PURE__ */ (0, vue.defineComponent)({
1553
2049
  type: Boolean,
1554
2050
  default: false
1555
2051
  },
2052
+ expand: { type: [Boolean, Number] },
1556
2053
  viewport: { default: "auto" },
1557
2054
  viewportOptions: { default: () => ["auto", 375] }
1558
2055
  },
@@ -1568,18 +2065,24 @@ var runtime_default = /* @__PURE__ */ (0, vue.defineComponent)({
1568
2065
  const getViewText = (view) => t(playgroundViewMessage(view));
1569
2066
  const emit = __emit;
1570
2067
  const joinCode = (...values) => values.filter(Boolean).join("\n");
1571
- const mergedPreviewOptions = (0, vue.computed)(() => {
2068
+ const mergePreviewOptions = (extraHeadHTML) => {
1572
2069
  const runtimePreviewOptions = createRuntimePreviewOptions(props.options.cdnURL);
1573
2070
  return {
1574
2071
  ...runtimePreviewOptions,
1575
2072
  ...props.previewOptions,
1576
- 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"),
1577
2078
  customCode: {
1578
2079
  importCode: joinCode(runtimePreviewOptions.customCode?.importCode, props.previewOptions?.customCode?.importCode),
1579
2080
  useCode: joinCode(runtimePreviewOptions.customCode?.useCode, props.previewOptions?.customCode?.useCode)
1580
2081
  }
1581
2082
  };
1582
- });
2083
+ };
2084
+ const mergedPreviewOptions = (0, vue.computed)(() => mergePreviewOptions());
2085
+ const popupPreviewOptions = (0, vue.computed)(() => mergePreviewOptions("<style>html,body{height:100%;min-height:100%}</style>"));
1583
2086
  const clearConsole = {
1584
2087
  "BASE_URL": "/",
1585
2088
  "DEV": false,
@@ -1590,6 +2093,7 @@ var runtime_default = /* @__PURE__ */ (0, vue.defineComponent)({
1590
2093
  const copyValue = (0, vue.computed)(() => props.files[props.entry] || "");
1591
2094
  const store = createRuntimeStore(props.files, props.entry, props.options);
1592
2095
  const sandboxRef = (0, vue.ref)(null);
2096
+ const sandboxKey = (0, vue.ref)(0);
1593
2097
  const runtimeHeight = useSandboxAutoHeight(sandboxRef);
1594
2098
  const runtimeError = useSandboxRuntimeErrorGuard(sandboxRef);
1595
2099
  useSandboxTheme(sandboxRef);
@@ -1605,11 +2109,63 @@ var runtime_default = /* @__PURE__ */ (0, vue.defineComponent)({
1605
2109
  if (!data || data.action !== "docs:navigate" || typeof data.to !== "string") return;
1606
2110
  emit("navigate", data.to);
1607
2111
  };
1608
- if (typeof window !== "undefined") window.addEventListener("message", handleBridgeMessage);
1609
- (0, vue.onBeforeUnmount)(() => window.removeEventListener("message", handleBridgeMessage));
1610
- const viewportMenuVisible = (0, vue.ref)(false);
1611
- const viewportLabel = (0, vue.computed)(() => formatViewportLabel(props.viewport, t("playground.runtime.auto")));
1612
- 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
+ });
1613
2169
  const normalizedPreviewInset = (0, vue.computed)(() => {
1614
2170
  const value = props.previewInset;
1615
2171
  if (typeof value === "number") return Number.isFinite(value) && value >= 0 ? [value, value] : [10, 10];
@@ -1620,7 +2176,8 @@ var runtime_default = /* @__PURE__ */ (0, vue.defineComponent)({
1620
2176
  const [vertical, horizontal] = normalizedPreviewInset.value;
1621
2177
  return {
1622
2178
  height: `${desiredViewportHeight.value + vertical * 2}px`,
1623
- 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
1624
2181
  };
1625
2182
  });
1626
2183
  const stylelessStyle = (0, vue.computed)(() => errorText.value ? void 0 : { height: `${desiredViewportHeight.value}px` });
@@ -1672,14 +2229,30 @@ var runtime_default = /* @__PURE__ */ (0, vue.defineComponent)({
1672
2229
  onActiveChange: (filename) => store.setActive(toReplFilename(filename))
1673
2230
  });
1674
2231
  };
2232
+ const handleInlineRefresh = () => {
2233
+ runtimeError.value = "";
2234
+ sandboxKey.value++;
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
+ };
1675
2252
  const handleView = (view) => emit("view-change", view);
1676
- const handleViewport = (index) => {
1677
- const viewport = props.viewportOptions[index];
1678
- if (viewport && !viewportEquals(viewport, props.viewport)) emit("viewport-change", viewport);
2253
+ const handleViewportChange = (viewport) => {
2254
+ emit("viewport-change", viewport);
1679
2255
  };
1680
- (0, vue.watch)(() => props.viewportOptions.length, (length) => {
1681
- if (length <= 1) viewportMenuVisible.value = false;
1682
- });
1683
2256
  (0, vue.watch)(() => props.files, (files) => {
1684
2257
  if (filesEqual(files, syncedFiles)) return;
1685
2258
  syncedFiles = { ...files };
@@ -1693,12 +2266,22 @@ var runtime_default = /* @__PURE__ */ (0, vue.defineComponent)({
1693
2266
  store.mainFile = toReplFilename(entry);
1694
2267
  store.setActive(toReplFilename(entry));
1695
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
+ });
1696
2277
  return (_ctx, _cache) => {
1697
- 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", {
1698
2279
  key: 0,
2280
+ ref_key: "runtimeRoot",
2281
+ ref: runtimeRoot,
1699
2282
  class: "docs-playground-runtime--styleless",
1700
2283
  style: (0, vue.normalizeStyle)(stylelessStyle.value)
1701
- }, [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", {
1702
2285
  class: "docs-playground-runtime__viewport",
1703
2286
  style: (0, vue.normalizeStyle)(viewportStyle.value)
1704
2287
  }, [(0, vue.createVNode)((0, vue.unref)(_vue_repl.Sandbox), {
@@ -1707,77 +2290,26 @@ var runtime_default = /* @__PURE__ */ (0, vue.defineComponent)({
1707
2290
  store: (0, vue.unref)(store),
1708
2291
  "auto-store-init": false,
1709
2292
  "preview-options": mergedPreviewOptions.value
1710
- }, null, 8, ["store", "preview-options"])], 4)], 4)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_2, [
1711
- (0, vue.createElementVNode)("div", _hoisted_3, [(0, vue.createElementVNode)("div", _hoisted_4, [
1712
- __props.viewportOptions.length > 1 ? ((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_deot_vc.Dropdown), {
1713
- key: 0,
1714
- modelValue: viewportMenuVisible.value,
1715
- "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => viewportMenuVisible.value = $event),
1716
- class: "docs-playground__viewport-menu",
1717
- portal: true,
1718
- trigger: "click",
1719
- placement: "bottom-right"
1720
- }, {
1721
- content: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(_deot_vc.DropdownMenu), {
1722
- class: "docs-playground__viewport-options",
1723
- role: "menu",
1724
- "aria-label": (0, vue.unref)(t)("playground.runtime.viewportMenu")
1725
- }, {
1726
- default: (0, vue.withCtx)(() => [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(__props.viewportOptions, (item, index) => {
1727
- return (0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_deot_vc.DropdownItem), {
1728
- key: (0, vue.unref)(getViewportKey)(item),
1729
- class: "docs-playground__viewport-option",
1730
- value: index,
1731
- selected: (0, vue.unref)(viewportEquals)(item, __props.viewport),
1732
- role: "menuitemradio",
1733
- "aria-checked": (0, vue.unref)(viewportEquals)(item, __props.viewport),
1734
- onClick: ($event) => handleViewport(index)
1735
- }, {
1736
- default: (0, vue.withCtx)(() => [(0, vue.createTextVNode)((0, vue.toDisplayString)((0, vue.unref)(formatViewportLabel)(item, (0, vue.unref)(t)("playground.runtime.auto"))), 1)]),
1737
- _: 2
1738
- }, 1032, [
1739
- "value",
1740
- "selected",
1741
- "aria-checked",
1742
- "onClick"
1743
- ]);
1744
- }), 128))]),
1745
- _: 1
1746
- }, 8, ["aria-label"])]),
1747
- default: (0, vue.withCtx)(() => [(0, vue.createElementVNode)("button", {
1748
- type: "button",
1749
- class: (0, vue.normalizeClass)(["docs-playground__tool docs-playground__viewport-trigger", { "is-active": __props.viewport !== "auto" }]),
1750
- title: (0, vue.unref)(t)("playground.runtime.viewport", { value: viewportLabel.value }),
1751
- "aria-label": (0, vue.unref)(t)("playground.runtime.viewport", { value: viewportLabel.value }),
1752
- "aria-expanded": viewportMenuVisible.value,
1753
- "aria-haspopup": "menu"
1754
- }, [(0, vue.createVNode)((0, vue.unref)(icon_default), { name: "viewport" })], 10, _hoisted_5)]),
1755
- _: 1
1756
- }, 8, ["modelValue"])) : (0, vue.createCommentVNode)("v-if", true),
1757
- (0, vue.createVNode)((0, vue.unref)(_deot_vc.Clipboard), {
1758
- class: "docs-playground__tool",
1759
- value: copyValue.value,
1760
- tag: "button",
1761
- type: "button",
1762
- title: (0, vue.unref)(t)("playground.common.copy"),
1763
- "aria-label": (0, vue.unref)(t)("playground.common.copy")
1764
- }, {
1765
- default: (0, vue.withCtx)(() => [(0, vue.createVNode)((0, vue.unref)(icon_default), { name: "copy" })]),
1766
- _: 1
1767
- }, 8, [
1768
- "value",
1769
- "title",
1770
- "aria-label"
1771
- ]),
1772
- (0, vue.createElementVNode)("button", {
1773
- type: "button",
1774
- class: "docs-playground__tool docs-playground__editor",
1775
- "data-action": "edit",
1776
- title: (0, vue.unref)(t)("playground.runtime.editFiles"),
1777
- "aria-label": (0, vue.unref)(t)("playground.runtime.editFiles"),
1778
- onClick: handleEditor
1779
- }, [(0, vue.createVNode)((0, vue.unref)(icon_default), { name: "editor" })], 8, _hoisted_6)
1780
- ]), __props.views.length > 1 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_7, [((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) => {
1781
2313
  return (0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
1782
2314
  key: item,
1783
2315
  type: "button",
@@ -1786,24 +2318,34 @@ var runtime_default = /* @__PURE__ */ (0, vue.defineComponent)({
1786
2318
  "aria-label": getViewText(item),
1787
2319
  "aria-pressed": item === __props.activeView,
1788
2320
  onClick: ($event) => handleView(item)
1789
- }, [(0, vue.createVNode)((0, vue.unref)(icon_default), { name: item }, null, 8, ["name"])], 10, _hoisted_8);
2321
+ }, [(0, vue.createVNode)((0, vue.unref)(icon_default), { name: item }, null, 8, ["name"])], 10, _hoisted_5);
1790
2322
  }), 128))])) : (0, vue.createCommentVNode)("v-if", true)]),
1791
- errorText.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("pre", _hoisted_9, (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),
1792
2324
  (0, vue.createElementVNode)("section", {
1793
- class: "docs-playground__preview",
2325
+ class: (0, vue.normalizeClass)(["docs-playground__preview", { "is-expanded": previewExpanded.value }]),
1794
2326
  style: (0, vue.normalizeStyle)(previewStyle.value)
1795
- }, [(0, vue.createElementVNode)("div", _hoisted_10, [(0, vue.createElementVNode)("div", {
2327
+ }, [(0, vue.createElementVNode)("div", _hoisted_7, [(0, vue.createElementVNode)("div", {
1796
2328
  class: "docs-playground-runtime__viewport",
1797
2329
  style: (0, vue.normalizeStyle)(viewportStyle.value)
1798
- }, [(0, vue.createVNode)((0, vue.unref)(_vue_repl.Sandbox), {
2330
+ }, [((0, vue.openBlock)(), (0, vue.createBlock)((0, vue.unref)(_vue_repl.Sandbox), {
2331
+ key: sandboxKey.value,
1799
2332
  ref_key: "sandboxRef",
1800
2333
  ref: sandboxRef,
1801
2334
  store: (0, vue.unref)(store),
1802
2335
  "auto-store-init": false,
1803
2336
  "clear-console": clearConsole,
1804
2337
  "preview-options": mergedPreviewOptions.value
1805
- }, null, 8, ["store", "preview-options"])], 4)])], 4)
1806
- ]));
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))]);
1807
2349
  };
1808
2350
  }
1809
2351
  });
@@ -1830,6 +2372,7 @@ var playground_default = /* @__PURE__ */ (0, vue.defineComponent)({
1830
2372
  },
1831
2373
  options: { default: () => ({}) },
1832
2374
  previewInset: { default: 0 },
2375
+ expand: { type: [Boolean, Number] },
1833
2376
  previewOptions: {},
1834
2377
  locale: {}
1835
2378
  },
@@ -1963,6 +2506,7 @@ var playground_default = /* @__PURE__ */ (0, vue.defineComponent)({
1963
2506
  options: __props.options,
1964
2507
  "preview-options": __props.previewOptions,
1965
2508
  "preview-inset": __props.previewInset,
2509
+ expand: __props.expand,
1966
2510
  styleless: true,
1967
2511
  viewport: activeViewport.value,
1968
2512
  "viewport-options": selectableViewportOptions.value,
@@ -1975,6 +2519,7 @@ var playground_default = /* @__PURE__ */ (0, vue.defineComponent)({
1975
2519
  "options",
1976
2520
  "preview-options",
1977
2521
  "preview-inset",
2522
+ "expand",
1978
2523
  "viewport",
1979
2524
  "viewport-options"
1980
2525
  ])) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
@@ -1989,6 +2534,7 @@ var playground_default = /* @__PURE__ */ (0, vue.defineComponent)({
1989
2534
  options: __props.options,
1990
2535
  "preview-options": __props.previewOptions,
1991
2536
  "preview-inset": __props.previewInset,
2537
+ expand: __props.expand,
1992
2538
  "active-view": activeView.value,
1993
2539
  views: normalizedViews.value,
1994
2540
  viewport: activeViewport.value,
@@ -2003,6 +2549,7 @@ var playground_default = /* @__PURE__ */ (0, vue.defineComponent)({
2003
2549
  "options",
2004
2550
  "preview-options",
2005
2551
  "preview-inset",
2552
+ "expand",
2006
2553
  "active-view",
2007
2554
  "views",
2008
2555
  "viewport",