@deot/docs-playground 1.0.10 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -116,7 +116,7 @@ var PLAYGROUND_ICONS = {
116
116
  //#endregion
117
117
  //#region packages/playground/src/icon/icon.vue?vue&type=script&setup=true&lang.ts
118
118
  var _hoisted_1$7 = ["fill", "stroke"];
119
- var _hoisted_2$6 = ["d"];
119
+ var _hoisted_2$7 = ["d"];
120
120
  //#endregion
121
121
  //#region packages/playground/src/icon/icon.vue
122
122
  var icon_default = /* @__PURE__ */ defineComponent({
@@ -147,7 +147,7 @@ var icon_default = /* @__PURE__ */ defineComponent({
147
147
  "stroke-linecap": "round",
148
148
  "stroke-linejoin": "round",
149
149
  "aria-hidden": "true"
150
- }, [createElementVNode("path", { d: icon.value.path }, null, 8, _hoisted_2$6)], 12, _hoisted_1$7);
150
+ }, [createElementVNode("path", { d: icon.value.path }, null, 8, _hoisted_2$7)], 12, _hoisted_1$7);
151
151
  };
152
152
  }
153
153
  });
@@ -174,9 +174,9 @@ var ensureCodePreviewStyle = () => {
174
174
  //#endregion
175
175
  //#region packages/playground/src/core/code-preview/code-preview.vue?vue&type=script&setup=true&lang.ts
176
176
  var _hoisted_1$6 = { class: "docs-code-preview" };
177
- var _hoisted_2$5 = ["title"];
178
- var _hoisted_3$5 = { class: "docs-code-preview__code" };
179
- var _hoisted_4$5 = ["innerHTML"];
177
+ var _hoisted_2$6 = ["title"];
178
+ var _hoisted_3$6 = { class: "docs-code-preview__code" };
179
+ var _hoisted_4$6 = ["innerHTML"];
180
180
  //#endregion
181
181
  //#region packages/playground/src/core/code-preview/code-preview.vue
182
182
  var code_preview_default = /* @__PURE__ */ defineComponent({
@@ -212,7 +212,7 @@ var code_preview_default = /* @__PURE__ */ defineComponent({
212
212
  key: 0,
213
213
  class: "docs-code-preview__language",
214
214
  title: languageLabel.value
215
- }, toDisplayString(languageLabel.value), 9, _hoisted_2$5)) : createCommentVNode("v-if", true),
215
+ }, toDisplayString(languageLabel.value), 9, _hoisted_2$6)) : createCommentVNode("v-if", true),
216
216
  createVNode(unref(Clipboard), {
217
217
  class: "docs-code-preview__copy",
218
218
  value: __props.code,
@@ -229,53 +229,23 @@ var code_preview_default = /* @__PURE__ */ defineComponent({
229
229
  "aria-label"
230
230
  ]),
231
231
  createCommentVNode(" eslint-disable-next-line vue/no-v-html "),
232
- createElementVNode("pre", _hoisted_3$5, [createElementVNode("code", {
232
+ createElementVNode("pre", _hoisted_3$6, [createElementVNode("code", {
233
233
  class: "hljs",
234
234
  innerHTML: highlightedCode.value
235
- }, null, 8, _hoisted_4$5)])
235
+ }, null, 8, _hoisted_4$6)])
236
236
  ]);
237
237
  };
238
238
  }
239
239
  });
240
240
  //#endregion
241
- //#region packages/playground/src/utils.ts
242
- /**
243
- * 比较两组 playground 文件是否完全一致。
244
- * @param left 左侧文件表。
245
- * @param right 右侧文件表。
246
- * @returns 键集合与各文件内容是否都相同。
247
- */
248
- var filesEqual = (left, right) => {
249
- const leftKeys = Object.keys(left);
250
- const rightKeys = Object.keys(right);
251
- return leftKeys.length === rightKeys.length && leftKeys.every((key) => left[key] === right[key]);
252
- };
253
- /**
254
- * 视图切换条使用的文案键。
255
- * @param view 当前预览视图。
256
- * @returns locale 消息键。
257
- */
258
- var playgroundViewMessage = (view) => view === "runtime" ? "playground.runtime.preview" : "playground.runtime.files";
259
- //#endregion
260
241
  //#region packages/playground/src/core/files-preview/files-preview.vue?vue&type=script&setup=true&lang.ts
261
242
  var _hoisted_1$5 = { class: "docs-playground-files" };
262
- var _hoisted_2$4 = { class: "docs-playground-files__toolbar" };
263
- var _hoisted_3$4 = ["data-filename", "onClick"];
264
- var _hoisted_4$4 = {
243
+ var _hoisted_2$5 = { class: "docs-playground-files__tabs-row" };
244
+ var _hoisted_3$5 = ["data-filename", "onClick"];
245
+ var _hoisted_4$5 = {
265
246
  key: 0,
266
247
  class: "docs-playground-files__entry"
267
248
  };
268
- var _hoisted_5$4 = { class: "docs-playground-files__actions" };
269
- var _hoisted_6$3 = {
270
- key: 0,
271
- class: "docs-playground__views docs-playground__views--files"
272
- };
273
- var _hoisted_7$2 = [
274
- "title",
275
- "aria-label",
276
- "aria-pressed",
277
- "onClick"
278
- ];
279
249
  //#endregion
280
250
  //#region packages/playground/src/core/files-preview/files-preview.vue
281
251
  var files_preview_default = /* @__PURE__ */ defineComponent({
@@ -287,28 +257,26 @@ var files_preview_default = /* @__PURE__ */ defineComponent({
287
257
  activeView: {},
288
258
  activeFilename: {}
289
259
  },
290
- emits: ["active-change", "view-change"],
260
+ emits: ["active-change"],
291
261
  setup(__props, { emit: __emit }) {
292
262
  const props = __props;
293
263
  const { t } = useLocale();
294
- const getViewText = (view) => t(playgroundViewMessage(view));
295
264
  const emit = __emit;
296
265
  const filenames = computed(() => Object.keys(props.files));
297
266
  const activeCode = computed(() => props.files[props.activeFilename] || "");
298
267
  const handleActive = (filename) => {
299
268
  if (filename !== props.activeFilename) emit("active-change", filename);
300
269
  };
301
- const handleView = (view) => emit("view-change", view);
302
270
  return (_ctx, _cache) => {
303
- return openBlock(), createElementBlock("div", _hoisted_1$5, [createElementVNode("div", _hoisted_2$4, [createVNode(unref(Scroller), {
271
+ return openBlock(), createElementBlock("div", _hoisted_1$5, [createElementVNode("div", _hoisted_2$5, [createVNode(unref(Scroller), {
304
272
  class: "docs-playground-files__scroller",
305
273
  "auto-resize": true,
306
274
  native: false,
307
275
  "show-bar": true,
308
- height: "44",
276
+ height: "40",
309
277
  "content-class": "docs-playground-files__tabs",
310
- "content-style": "height: 44px; overflow: hidden;",
311
- "wrapper-style": "height: 44px; overflow-x: auto; overflow-y: hidden;"
278
+ "content-style": "height: 40px; overflow: hidden;",
279
+ "wrapper-style": "height: 40px; overflow-x: auto; overflow-y: hidden;"
312
280
  }, {
313
281
  default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(filenames.value, (filename) => {
314
282
  return openBlock(), createElementBlock("button", {
@@ -317,20 +285,10 @@ var files_preview_default = /* @__PURE__ */ defineComponent({
317
285
  class: normalizeClass(["docs-playground-files__tab", { "is-active": filename === __props.activeFilename }]),
318
286
  "data-filename": filename,
319
287
  onClick: ($event) => handleActive(filename)
320
- }, [createElementVNode("span", null, toDisplayString(filename), 1), filename === __props.entry ? (openBlock(), createElementBlock("small", _hoisted_4$4, toDisplayString(unref(t)("playground.files.entry")), 1)) : createCommentVNode("v-if", true)], 10, _hoisted_3$4);
288
+ }, [createElementVNode("span", null, toDisplayString(filename), 1), filename === __props.entry ? (openBlock(), createElementBlock("small", _hoisted_4$5, toDisplayString(unref(t)("playground.files.entry")), 1)) : createCommentVNode("v-if", true)], 10, _hoisted_3$5);
321
289
  }), 128))]),
322
290
  _: 1
323
- }), createElementVNode("div", _hoisted_5$4, [__props.views.length > 1 ? (openBlock(), createElementBlock("div", _hoisted_6$3, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.views, (item) => {
324
- return openBlock(), createElementBlock("button", {
325
- key: item,
326
- type: "button",
327
- class: normalizeClass(["docs-playground__view", { "is-active": item === __props.activeView }]),
328
- title: getViewText(item),
329
- "aria-label": getViewText(item),
330
- "aria-pressed": item === __props.activeView,
331
- onClick: ($event) => handleView(item)
332
- }, [createVNode(unref(icon_default), { name: item }, null, 8, ["name"])], 10, _hoisted_7$2);
333
- }), 128))])) : createCommentVNode("v-if", true)])]), createVNode(unref(code_preview_default), {
291
+ })]), createVNode(unref(code_preview_default), {
334
292
  class: "docs-playground-files__body",
335
293
  code: activeCode.value,
336
294
  filename: __props.activeFilename,
@@ -462,21 +420,21 @@ var Drag = class {
462
420
  //#endregion
463
421
  //#region packages/playground/src/editor/editor.vue?vue&type=script&setup=true&lang.ts
464
422
  var _hoisted_1$4 = { class: "docs-playground-editor" };
465
- var _hoisted_2$3 = ["title"];
466
- var _hoisted_3$3 = { class: "docs-playground-editor__files" };
467
- var _hoisted_4$3 = [
423
+ var _hoisted_2$4 = ["title"];
424
+ var _hoisted_3$4 = { class: "docs-playground-editor__files" };
425
+ var _hoisted_4$4 = [
468
426
  "data-filename",
469
427
  "onClick",
470
428
  "onDblclick"
471
429
  ];
472
- var _hoisted_5$3 = ["onKeydown"];
473
- var _hoisted_6$2 = ["title"];
474
- var _hoisted_7$1 = ["title", "aria-label"];
475
- var _hoisted_8$1 = ["title", "aria-label"];
476
- var _hoisted_9 = { class: "docs-playground-editor__actions" };
477
- var _hoisted_10 = ["title"];
478
- var _hoisted_11 = ["title", "disabled"];
479
- var _hoisted_12 = {
430
+ var _hoisted_5$4 = ["onKeydown"];
431
+ var _hoisted_6$3 = ["title"];
432
+ var _hoisted_7$3 = ["title", "aria-label"];
433
+ var _hoisted_8$2 = ["title", "aria-label"];
434
+ var _hoisted_9$2 = { class: "docs-playground-editor__actions" };
435
+ var _hoisted_10$1 = ["title"];
436
+ var _hoisted_11$1 = ["title", "disabled"];
437
+ var _hoisted_12$1 = {
480
438
  key: 0,
481
439
  class: "docs-playground-editor__error"
482
440
  };
@@ -728,8 +686,8 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
728
686
  title: unref(t)("playground.common.close"),
729
687
  style: { "cursor": "pointer" },
730
688
  onClick: handleHide
731
- }, "✕", 8, _hoisted_2$3)], 512),
732
- createElementVNode("div", _hoisted_3$3, [createVNode(unref(Scroller), {
689
+ }, "✕", 8, _hoisted_2$4)], 512),
690
+ createElementVNode("div", _hoisted_3$4, [createVNode(unref(Scroller), {
733
691
  ref_key: "scroller",
734
692
  ref: scroller,
735
693
  class: "docs-playground-editor__scroller",
@@ -757,11 +715,11 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
757
715
  onDblclick: _cache[2] || (_cache[2] = withModifiers(() => {}, ["stop"])),
758
716
  onBlur: handleRenameSubmit,
759
717
  onKeydown: [withKeys(withModifiers(handleRenameSubmit, ["prevent"]), ["enter"]), withKeys(withModifiers(handleRenameCancel, ["prevent"]), ["esc"])]
760
- }, null, 40, _hoisted_5$3)), [[vModelText, filenameDraft.value]]) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
718
+ }, null, 40, _hoisted_5$4)), [[vModelText, filenameDraft.value]]) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
761
719
  filename === currentEntry.value ? (openBlock(), createElementBlock("span", {
762
720
  key: 0,
763
721
  title: unref(t)("playground.editor.entry")
764
- }, "●", 8, _hoisted_6$2)) : createCommentVNode("v-if", true),
722
+ }, "●", 8, _hoisted_6$3)) : createCommentVNode("v-if", true),
765
723
  createElementVNode("span", null, toDisplayString(filename), 1),
766
724
  filename === currentEntry.value ? (openBlock(), createElementBlock("button", {
767
725
  key: 1,
@@ -770,7 +728,7 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
770
728
  title: unref(t)("playground.editor.entryCannotDelete"),
771
729
  "aria-label": unref(t)("playground.editor.entryCannotDelete"),
772
730
  disabled: ""
773
- }, null, 8, _hoisted_7$1)) : (openBlock(), createBlock(unref(Popconfirm), {
731
+ }, null, 8, _hoisted_7$3)) : (openBlock(), createBlock(unref(Popconfirm), {
774
732
  key: 2,
775
733
  class: "docs-playground-editor__delete",
776
734
  title: unref(t)("playground.editor.confirmDelete", { filename }),
@@ -783,23 +741,23 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
783
741
  class: "docs-playground-editor__close",
784
742
  title: unref(t)("playground.editor.deleteFile"),
785
743
  "aria-label": unref(t)("playground.editor.confirmDelete", { filename })
786
- }, null, 8, _hoisted_8$1)]),
744
+ }, null, 8, _hoisted_8$2)]),
787
745
  _: 2
788
746
  }, 1032, ["title", "onOk"]))
789
- ], 64))], 42, _hoisted_4$3);
747
+ ], 64))], 42, _hoisted_4$4);
790
748
  }), 128))]),
791
749
  _: 1
792
- }, 512), createElementVNode("div", _hoisted_9, [createElementVNode("button", {
750
+ }, 512), createElementVNode("div", _hoisted_9$2, [createElementVNode("button", {
793
751
  type: "button",
794
752
  title: unref(t)("playground.editor.createFile"),
795
753
  onClick: handleCreate
796
- }, "+", 8, _hoisted_10), createElementVNode("button", {
754
+ }, "+", 8, _hoisted_10$1), createElementVNode("button", {
797
755
  type: "button",
798
756
  title: unref(t)("playground.editor.setEntry"),
799
757
  disabled: activeFilename.value === currentEntry.value,
800
758
  onClick: handleEntry
801
- }, toDisplayString(unref(t)("playground.editor.setEntry")), 9, _hoisted_11)])]),
802
- codeErrorText.value ? (openBlock(), createElementBlock("div", _hoisted_12, toDisplayString(codeErrorText.value), 1)) : createCommentVNode("v-if", true),
759
+ }, toDisplayString(unref(t)("playground.editor.setEntry")), 9, _hoisted_11$1)])]),
760
+ codeErrorText.value ? (openBlock(), createElementBlock("div", _hoisted_12$1, toDisplayString(codeErrorText.value), 1)) : createCommentVNode("v-if", true),
803
761
  createVNode(unref(Scroller), {
804
762
  ref_key: "editorScroller",
805
763
  ref: editorScroller,
@@ -823,6 +781,50 @@ var Editor = new Portal(/* @__PURE__ */ defineComponent({
823
781
  };
824
782
  }
825
783
  }), { aliveRegExp: { className: /(PORTAL_TAG_DISABLE)/ } });
784
+ //#endregion
785
+ //#region packages/playground/src/utils.ts
786
+ /**
787
+ * 比较两组 playground 文件是否完全一致。
788
+ * @param left 左侧文件表。
789
+ * @param right 右侧文件表。
790
+ * @returns 键集合与各文件内容是否都相同。
791
+ */
792
+ var filesEqual = (left, right) => {
793
+ const leftKeys = Object.keys(left);
794
+ const rightKeys = Object.keys(right);
795
+ return leftKeys.length === rightKeys.length && leftKeys.every((key) => left[key] === right[key]);
796
+ };
797
+ /**
798
+ * 视图切换条使用的文案键。
799
+ * @param view 当前预览视图。
800
+ * @returns locale 消息键。
801
+ */
802
+ var playgroundViewMessage = (view) => view === "runtime" ? "playground.runtime.preview" : "playground.runtime.files";
803
+ /**
804
+ * 与 markdown-it-anchor 默认 `slugify` 对齐,用于标题锚点 id。
805
+ * @param title 标题文本。
806
+ * @returns 可用作元素 id / hash 的字符串;空标题返回空串。
807
+ */
808
+ var slugifyPlaygroundTitle = (title) => {
809
+ const normalized = String(title).trim().toLowerCase().replace(/\s+/g, "-");
810
+ return normalized ? encodeURIComponent(normalized) : "";
811
+ };
812
+ /**
813
+ * 解析标题锚点 id:显式 id 优先,否则从标题 slugify;必要时避开已占用 id。
814
+ * @param title 标题文本。
815
+ * @param explicitId 可选显式 id。
816
+ * @param isOccupied 返回该 id 是否已被其他元素占用。
817
+ * @returns 锚点 id;无标题时为空串。
818
+ */
819
+ var resolvePlaygroundTitleId = (title, explicitId = "", isOccupied) => {
820
+ if (!String(title).trim()) return "";
821
+ const base = String(explicitId).trim() || slugifyPlaygroundTitle(title);
822
+ if (!base) return "";
823
+ if (!isOccupied || !isOccupied(base)) return base;
824
+ let index = 1;
825
+ while (isOccupied(`${base}-${index}`)) index += 1;
826
+ return `${base}-${index}`;
827
+ };
826
828
  var resolveSandboxContainer = (sandbox) => sandbox?.container ? unref(sandbox.container) : null;
827
829
  var useSandboxAutoHeight = (sandboxRef) => {
828
830
  const height = ref(24);
@@ -945,14 +947,14 @@ var SCROLLABLE_OVERFLOW = /* @__PURE__ */ new Set([
945
947
  ]);
946
948
  var getWindowInnerHeight = () => typeof window === "undefined" ? 0 : window.innerHeight;
947
949
  var getPlaygroundHost = (el) => el?.closest(".docs-playground") ?? el;
948
- var isPlaygroundExpandEnabled = (expand) => {
949
- if (expand === true) return true;
950
- return typeof expand === "number" && Number.isFinite(expand) && expand > 0;
950
+ var isPlaygroundExpandable = (value) => {
951
+ if (value === true) return true;
952
+ return typeof value === "number" && Number.isFinite(value) && value > 0;
951
953
  };
952
954
  var resolveRemainingPreviewHeight = ({ viewportHeight, chromeHeight, gap = 16 }) => Math.max(0, Math.round((Number.isFinite(viewportHeight) ? viewportHeight : 0) - (Number.isFinite(chromeHeight) ? Math.max(0, chromeHeight) : 0) - (Number.isFinite(gap) ? gap : 16)));
953
- var resolveExpandedPreviewHeight = (expand, availableHeight) => {
954
- if (expand === true) return Math.max(24, Math.round(Number.isFinite(availableHeight) ? availableHeight : 0));
955
- return Math.max(24, Math.round(expand));
955
+ var resolveExpandedPreviewHeight = (expandable, availableHeight) => {
956
+ if (expandable === true) return Math.max(24, Math.round(Number.isFinite(availableHeight) ? availableHeight : 0));
957
+ return Math.max(24, Math.round(expandable));
956
958
  };
957
959
  var getVisibleViewportRect = (el) => {
958
960
  const viewportHeight = getWindowInnerHeight();
@@ -1100,6 +1102,13 @@ var formatViewportLabel = (viewport, autoLabel = "Auto") => {
1100
1102
  if (viewport === "auto") return autoLabel;
1101
1103
  return Array.isArray(viewport) ? `${viewport[0]} × ${viewport[1]}px` : `${viewport}px`;
1102
1104
  };
1105
+ var resolvePopupScreenInset = (gap = 40) => {
1106
+ const safeGap = Number.isFinite(gap) ? Math.max(0, gap) : 40;
1107
+ return {
1108
+ x: safeGap * 2,
1109
+ y: safeGap
1110
+ };
1111
+ };
1103
1112
  var getWindowInnerSize = () => {
1104
1113
  if (typeof window === "undefined") return {
1105
1114
  width: 0,
@@ -1111,9 +1120,9 @@ var getWindowInnerSize = () => {
1111
1120
  };
1112
1121
  };
1113
1122
  var resolvePopupRequestedSize = (viewport, screen = getWindowInnerSize(), gap = 40) => {
1114
- const safeGap = Number.isFinite(gap) ? Math.max(0, gap) : 40;
1115
- const maxWidth = Math.max(0, Math.round((Number.isFinite(screen.width) ? screen.width : 0) - safeGap));
1116
- const maxHeight = Math.max(0, Math.round((Number.isFinite(screen.height) ? screen.height : 0) - safeGap));
1123
+ const inset = resolvePopupScreenInset(gap);
1124
+ const maxWidth = Math.max(0, Math.round((Number.isFinite(screen.width) ? screen.width : 0) - inset.x));
1125
+ const maxHeight = Math.max(0, Math.round((Number.isFinite(screen.height) ? screen.height : 0) - inset.y));
1117
1126
  const viewportWidth = getViewportWidth(viewport);
1118
1127
  const viewportHeight = getViewportHeight(viewport);
1119
1128
  return {
@@ -1124,11 +1133,11 @@ var resolvePopupRequestedSize = (viewport, screen = getWindowInnerSize(), gap =
1124
1133
  };
1125
1134
  };
1126
1135
  /**
1127
- * 壳层封顶到 `screen - gap`。未设 viewport 边时,画布铺满工具栏以下区域;
1128
- * 请求尺寸大于可用区域时由 Scroller 处理溢出。
1136
+ * 壳层封顶到 `screen.width - gap * 2`、`screen.height - gap`。
1137
+ * 未设 viewport 边时,画布铺满工具栏以下区域;请求尺寸大于可用区域时由 Scroller 处理溢出。
1129
1138
  * @param viewport 当前 playground 视口配置。
1130
- * @param screen 屏幕可用宽高,默认取 `window.inner*`.
1131
- * @param gap 相对屏幕边缘的留白。
1139
+ * @param screen 屏幕可用宽高,默认取 `window.inner*`。
1140
+ * @param gap 相对屏幕上下边缘的留白;左右为该值的 2 倍。
1132
1141
  * @returns 壳层、内容区与画布尺寸,以及是否需要滚动。
1133
1142
  */
1134
1143
  var resolvePopupLayout = (viewport, screen = getWindowInnerSize(), gap = 40) => {
@@ -1243,23 +1252,56 @@ var useSandboxTheme = (sandboxRef) => {
1243
1252
  //#endregion
1244
1253
  //#region packages/playground/src/core/runtime/toolbar.vue?vue&type=script&setup=true&lang.ts
1245
1254
  var _hoisted_1$3 = { class: "docs-playground__tools" };
1246
- var _hoisted_2$2 = ["title", "aria-label"];
1247
- var _hoisted_3$2 = [
1255
+ var _hoisted_2$3 = {
1256
+ key: 0,
1257
+ class: "docs-playground__tool-group"
1258
+ };
1259
+ var _hoisted_3$3 = [
1248
1260
  "title",
1249
1261
  "aria-label",
1250
1262
  "aria-expanded"
1251
1263
  ];
1252
- var _hoisted_4$2 = ["title", "aria-label"];
1253
- var _hoisted_5$2 = ["title", "aria-label"];
1254
- var _hoisted_6$1 = ["title", "aria-label"];
1264
+ var _hoisted_4$3 = {
1265
+ key: 1,
1266
+ class: "docs-playground__tool-divider",
1267
+ "aria-hidden": "true"
1268
+ };
1269
+ var _hoisted_5$3 = ["title", "aria-label"];
1270
+ var _hoisted_6$2 = ["title", "aria-label"];
1271
+ var _hoisted_7$2 = ["title", "aria-label"];
1272
+ var _hoisted_8$1 = {
1273
+ key: 3,
1274
+ class: "docs-playground__tool-divider",
1275
+ "aria-hidden": "true"
1276
+ };
1277
+ var _hoisted_9$1 = ["aria-label"];
1278
+ var _hoisted_10 = [
1279
+ "title",
1280
+ "aria-label",
1281
+ "aria-selected",
1282
+ "aria-pressed",
1283
+ "onClick"
1284
+ ];
1285
+ var _hoisted_11 = {
1286
+ key: 2,
1287
+ class: "docs-playground__tool-divider",
1288
+ "aria-hidden": "true"
1289
+ };
1290
+ var _hoisted_12 = ["title", "aria-label"];
1255
1291
  //#endregion
1256
1292
  //#region packages/playground/src/core/runtime/toolbar.vue
1257
1293
  var toolbar_default = /* @__PURE__ */ defineComponent({
1258
1294
  __name: "toolbar",
1259
1295
  props: {
1260
- copyValue: {},
1296
+ copyValue: { default: "" },
1261
1297
  viewport: { default: "auto" },
1262
1298
  viewportOptions: { default: () => ["auto", 375] },
1299
+ views: { default: () => [] },
1300
+ activeView: { default: "runtime" },
1301
+ showRuntimeActions: {
1302
+ type: Boolean,
1303
+ default: true
1304
+ },
1263
1305
  showOpenPopup: {
1264
1306
  type: Boolean,
1265
1307
  default: false
@@ -1274,14 +1316,20 @@ var toolbar_default = /* @__PURE__ */ defineComponent({
1274
1316
  "edit",
1275
1317
  "open-popup",
1276
1318
  "close-popup",
1277
- "viewport-change"
1319
+ "viewport-change",
1320
+ "view-change"
1278
1321
  ],
1279
1322
  setup(__props, { emit: __emit }) {
1280
1323
  const props = __props;
1281
1324
  const emit = __emit;
1282
1325
  const { t } = useLocale();
1326
+ const VIEW_ORDER = ["runtime", "files"];
1283
1327
  const viewportMenuVisible = ref(false);
1328
+ const orderedViews = computed(() => VIEW_ORDER.filter((view) => props.views.includes(view)));
1329
+ const showViews = computed(() => orderedViews.value.length > 1);
1284
1330
  const viewportLabel = computed(() => formatViewportLabel(props.viewport, t("playground.runtime.auto")));
1331
+ const getViewAriaLabel = (view) => t(playgroundViewMessage(view));
1332
+ const getViewLabel = (view) => view === "runtime" ? t("playground.runtime.previewLabel") : t("playground.runtime.codeLabel");
1285
1333
  const handleViewport = (index) => {
1286
1334
  const viewport = props.viewportOptions[index];
1287
1335
  if (viewport && !viewportEquals(viewport, props.viewport)) emit("viewport-change", viewport);
@@ -1289,95 +1337,120 @@ var toolbar_default = /* @__PURE__ */ defineComponent({
1289
1337
  watch(() => props.viewportOptions.length, (length) => {
1290
1338
  if (length <= 1) viewportMenuVisible.value = false;
1291
1339
  });
1340
+ watch(() => props.showRuntimeActions, (enabled) => {
1341
+ if (!enabled) viewportMenuVisible.value = false;
1342
+ });
1292
1343
  return (_ctx, _cache) => {
1293
1344
  return openBlock(), createElementBlock("div", _hoisted_1$3, [
1294
- createElementVNode("button", {
1295
- type: "button",
1296
- class: "docs-playground__tool docs-playground__refresh",
1297
- "data-action": "refresh",
1298
- title: unref(t)("playground.runtime.refresh"),
1299
- "aria-label": unref(t)("playground.runtime.refresh"),
1300
- onClick: _cache[0] || (_cache[0] = ($event) => emit("refresh"))
1301
- }, [createVNode(unref(icon_default), { name: "refresh" })], 8, _hoisted_2$2),
1302
- __props.viewportOptions.length > 1 ? (openBlock(), createBlock(unref(Dropdown), {
1303
- key: 0,
1304
- modelValue: viewportMenuVisible.value,
1305
- "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => viewportMenuVisible.value = $event),
1306
- class: "docs-playground__viewport-menu",
1307
- portal: true,
1308
- trigger: "click",
1309
- placement: "bottom-right"
1310
- }, {
1311
- content: withCtx(() => [createVNode(unref(DropdownMenu), {
1312
- class: "docs-playground__viewport-options",
1313
- role: "menu",
1314
- "aria-label": unref(t)("playground.runtime.viewportMenu")
1345
+ __props.showRuntimeActions ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
1346
+ __props.viewportOptions.length > 1 ? (openBlock(), createElementBlock("div", _hoisted_2$3, [createVNode(unref(Dropdown), {
1347
+ modelValue: viewportMenuVisible.value,
1348
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => viewportMenuVisible.value = $event),
1349
+ class: "docs-playground__viewport-menu",
1350
+ portal: true,
1351
+ trigger: "click",
1352
+ placement: "bottom-right"
1315
1353
  }, {
1316
- default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.viewportOptions, (item, index) => {
1317
- return openBlock(), createBlock(unref(DropdownItem), {
1318
- key: unref(getViewportKey)(item),
1319
- class: "docs-playground__viewport-option",
1320
- value: index,
1321
- selected: unref(viewportEquals)(item, __props.viewport),
1322
- role: "menuitemradio",
1323
- "aria-checked": unref(viewportEquals)(item, __props.viewport),
1324
- onClick: ($event) => handleViewport(index)
1325
- }, {
1326
- default: withCtx(() => [createTextVNode(toDisplayString(unref(formatViewportLabel)(item, unref(t)("playground.runtime.auto"))), 1)]),
1327
- _: 2
1328
- }, 1032, [
1329
- "value",
1330
- "selected",
1331
- "aria-checked",
1332
- "onClick"
1333
- ]);
1334
- }), 128))]),
1354
+ content: withCtx(() => [createVNode(unref(DropdownMenu), {
1355
+ class: "docs-playground__viewport-options",
1356
+ role: "menu",
1357
+ "aria-label": unref(t)("playground.runtime.viewportMenu")
1358
+ }, {
1359
+ default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.viewportOptions, (item, index) => {
1360
+ return openBlock(), createBlock(unref(DropdownItem), {
1361
+ key: unref(getViewportKey)(item),
1362
+ class: "docs-playground__viewport-option",
1363
+ value: index,
1364
+ selected: unref(viewportEquals)(item, __props.viewport),
1365
+ role: "menuitemradio",
1366
+ "aria-checked": unref(viewportEquals)(item, __props.viewport),
1367
+ onClick: ($event) => handleViewport(index)
1368
+ }, {
1369
+ default: withCtx(() => [createTextVNode(toDisplayString(unref(formatViewportLabel)(item, unref(t)("playground.runtime.auto"))), 1)]),
1370
+ _: 2
1371
+ }, 1032, [
1372
+ "value",
1373
+ "selected",
1374
+ "aria-checked",
1375
+ "onClick"
1376
+ ]);
1377
+ }), 128))]),
1378
+ _: 1
1379
+ }, 8, ["aria-label"])]),
1380
+ default: withCtx(() => [createElementVNode("button", {
1381
+ type: "button",
1382
+ class: normalizeClass(["docs-playground__tool docs-playground__viewport-trigger", { "is-active": __props.viewport !== "auto" }]),
1383
+ title: unref(t)("playground.runtime.viewport", { value: viewportLabel.value }),
1384
+ "aria-label": unref(t)("playground.runtime.viewport", { value: viewportLabel.value }),
1385
+ "aria-expanded": viewportMenuVisible.value,
1386
+ "aria-haspopup": "menu"
1387
+ }, [createVNode(unref(icon_default), { name: "viewport" })], 10, _hoisted_3$3)]),
1335
1388
  _: 1
1336
- }, 8, ["aria-label"])]),
1337
- default: withCtx(() => [createElementVNode("button", {
1389
+ }, 8, ["modelValue"])])) : createCommentVNode("v-if", true),
1390
+ __props.viewportOptions.length > 1 ? (openBlock(), createElementBlock("span", _hoisted_4$3)) : createCommentVNode("v-if", true),
1391
+ createElementVNode("button", {
1338
1392
  type: "button",
1339
- class: normalizeClass(["docs-playground__tool docs-playground__viewport-trigger", { "is-active": __props.viewport !== "auto" }]),
1340
- title: unref(t)("playground.runtime.viewport", { value: viewportLabel.value }),
1341
- "aria-label": unref(t)("playground.runtime.viewport", { value: viewportLabel.value }),
1342
- "aria-expanded": viewportMenuVisible.value,
1343
- "aria-haspopup": "menu"
1344
- }, [createVNode(unref(icon_default), { name: "viewport" })], 10, _hoisted_3$2)]),
1345
- _: 1
1346
- }, 8, ["modelValue"])) : createCommentVNode("v-if", true),
1347
- createVNode(unref(Clipboard), {
1348
- class: "docs-playground__tool",
1349
- value: __props.copyValue,
1350
- tag: "button",
1351
- type: "button",
1352
- title: unref(t)("playground.common.copy"),
1353
- "aria-label": unref(t)("playground.common.copy")
1354
- }, {
1355
- default: withCtx(() => [createVNode(unref(icon_default), { name: "copy" })]),
1356
- _: 1
1357
- }, 8, [
1358
- "value",
1359
- "title",
1360
- "aria-label"
1361
- ]),
1362
- createElementVNode("button", {
1363
- type: "button",
1364
- class: "docs-playground__tool docs-playground__editor",
1365
- "data-action": "edit",
1366
- title: unref(t)("playground.runtime.editFiles"),
1367
- "aria-label": unref(t)("playground.runtime.editFiles"),
1368
- onClick: _cache[2] || (_cache[2] = ($event) => emit("edit"))
1369
- }, [createVNode(unref(icon_default), { name: "editor" })], 8, _hoisted_4$2),
1370
- __props.showOpenPopup ? (openBlock(), createElementBlock("button", {
1393
+ class: "docs-playground__tool docs-playground__refresh",
1394
+ "data-action": "refresh",
1395
+ title: unref(t)("playground.runtime.refresh"),
1396
+ "aria-label": unref(t)("playground.runtime.refresh"),
1397
+ onClick: _cache[1] || (_cache[1] = ($event) => emit("refresh"))
1398
+ }, [createVNode(unref(icon_default), { name: "refresh" })], 8, _hoisted_5$3),
1399
+ createElementVNode("button", {
1400
+ type: "button",
1401
+ class: "docs-playground__tool docs-playground__editor",
1402
+ "data-action": "edit",
1403
+ title: unref(t)("playground.runtime.editFiles"),
1404
+ "aria-label": unref(t)("playground.runtime.editFiles"),
1405
+ onClick: _cache[2] || (_cache[2] = ($event) => emit("edit"))
1406
+ }, [createVNode(unref(icon_default), { name: "editor" })], 8, _hoisted_6$2),
1407
+ __props.showOpenPopup ? (openBlock(), createElementBlock("button", {
1408
+ key: 2,
1409
+ type: "button",
1410
+ class: "docs-playground__tool docs-playground__popup",
1411
+ "data-action": "open-popup",
1412
+ title: unref(t)("playground.runtime.openPopup"),
1413
+ "aria-label": unref(t)("playground.runtime.openPopup"),
1414
+ onClick: _cache[3] || (_cache[3] = ($event) => emit("open-popup"))
1415
+ }, [createVNode(unref(icon_default), { name: "popup" })], 8, _hoisted_7$2)) : createCommentVNode("v-if", true),
1416
+ createVNode(unref(Clipboard), {
1417
+ class: "docs-playground__tool",
1418
+ value: __props.copyValue,
1419
+ tag: "button",
1420
+ type: "button",
1421
+ title: unref(t)("playground.common.copy"),
1422
+ "aria-label": unref(t)("playground.common.copy")
1423
+ }, {
1424
+ default: withCtx(() => [createVNode(unref(icon_default), { name: "copy" })]),
1425
+ _: 1
1426
+ }, 8, [
1427
+ "value",
1428
+ "title",
1429
+ "aria-label"
1430
+ ]),
1431
+ showViews.value ? (openBlock(), createElementBlock("span", _hoisted_8$1)) : createCommentVNode("v-if", true)
1432
+ ], 64)) : createCommentVNode("v-if", true),
1433
+ showViews.value ? (openBlock(), createElementBlock("div", {
1371
1434
  key: 1,
1372
- type: "button",
1373
- class: "docs-playground__tool docs-playground__popup",
1374
- "data-action": "open-popup",
1375
- title: unref(t)("playground.runtime.openPopup"),
1376
- "aria-label": unref(t)("playground.runtime.openPopup"),
1377
- onClick: _cache[3] || (_cache[3] = ($event) => emit("open-popup"))
1378
- }, [createVNode(unref(icon_default), { name: "popup" })], 8, _hoisted_5$2)) : createCommentVNode("v-if", true),
1435
+ class: "docs-playground__views",
1436
+ role: "tablist",
1437
+ "aria-label": unref(t)("playground.runtime.views")
1438
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(orderedViews.value, (item) => {
1439
+ return openBlock(), createElementBlock("button", {
1440
+ key: item,
1441
+ type: "button",
1442
+ class: normalizeClass(["docs-playground__view", { "is-active": item === __props.activeView }]),
1443
+ role: "tab",
1444
+ title: getViewAriaLabel(item),
1445
+ "aria-label": getViewAriaLabel(item),
1446
+ "aria-selected": item === __props.activeView,
1447
+ "aria-pressed": item === __props.activeView,
1448
+ onClick: ($event) => emit("view-change", item)
1449
+ }, toDisplayString(getViewLabel(item)), 11, _hoisted_10);
1450
+ }), 128))], 8, _hoisted_9$1)) : createCommentVNode("v-if", true),
1451
+ __props.showClose && (__props.showRuntimeActions || showViews.value) ? (openBlock(), createElementBlock("span", _hoisted_11)) : createCommentVNode("v-if", true),
1379
1452
  __props.showClose ? (openBlock(), createElementBlock("button", {
1380
- key: 2,
1453
+ key: 3,
1381
1454
  type: "button",
1382
1455
  class: "docs-playground__tool docs-playground__popup-close",
1383
1456
  "data-action": "close-popup",
@@ -1387,7 +1460,7 @@ var toolbar_default = /* @__PURE__ */ defineComponent({
1387
1460
  }, [..._cache[5] || (_cache[5] = [createElementVNode("span", {
1388
1461
  class: "docs-playground__popup-close-mark",
1389
1462
  "aria-hidden": "true"
1390
- }, "✕", -1)])], 8, _hoisted_6$1)) : createCommentVNode("v-if", true)
1463
+ }, "✕", -1)])], 8, _hoisted_12)) : createCommentVNode("v-if", true)
1391
1464
  ]);
1392
1465
  };
1393
1466
  }
@@ -1808,14 +1881,16 @@ var createRuntimeStore = (files, entry, options) => {
1808
1881
  //#endregion
1809
1882
  //#region packages/playground/src/core/runtime/alone/wrapper.vue?vue&type=script&setup=true&lang.ts
1810
1883
  var _hoisted_1$2 = ["aria-label"];
1811
- var _hoisted_2$1 = { class: "docs-playground-popup__frame" };
1812
- var _hoisted_3$1 = { class: "docs-playground-popup__header" };
1813
- var _hoisted_4$1 = {
1884
+ var _hoisted_2$2 = { class: "docs-playground-popup__frame" };
1885
+ var _hoisted_3$2 = { class: "docs-playground-popup__header" };
1886
+ var _hoisted_4$2 = ["title"];
1887
+ var _hoisted_5$2 = { class: "docs-playground__title-text" };
1888
+ var _hoisted_6$1 = {
1814
1889
  key: 0,
1815
1890
  class: "docs-playground__runtime-error",
1816
1891
  role: "alert"
1817
1892
  };
1818
- var _hoisted_5$1 = { class: "docs-playground-popup__body" };
1893
+ var _hoisted_7$1 = { class: "docs-playground-popup__body" };
1819
1894
  //#endregion
1820
1895
  //#region packages/playground/src/core/runtime/alone/index.ts
1821
1896
  var Alone = new Portal(/* @__PURE__ */ defineComponent({
@@ -1823,6 +1898,7 @@ var Alone = new Portal(/* @__PURE__ */ defineComponent({
1823
1898
  props: {
1824
1899
  store: {},
1825
1900
  copyValue: {},
1901
+ title: { default: "" },
1826
1902
  viewport: { default: "auto" },
1827
1903
  viewportOptions: { default: () => ["auto", 375] },
1828
1904
  previewOptions: {},
@@ -1923,8 +1999,12 @@ var Alone = new Portal(/* @__PURE__ */ defineComponent({
1923
1999
  }), createElementVNode("div", {
1924
2000
  class: "docs-playground-popup__shell",
1925
2001
  style: normalizeStyle(shellStyle.value)
1926
- }, [createElementVNode("div", _hoisted_2$1, [
1927
- createElementVNode("div", _hoisted_3$1, [createVNode(toolbar_default, {
2002
+ }, [createElementVNode("div", _hoisted_2$2, [
2003
+ createElementVNode("div", _hoisted_3$2, [__props.title.trim() ? (openBlock(), createElementBlock("span", {
2004
+ key: 0,
2005
+ class: "docs-playground__title",
2006
+ title: __props.title.trim()
2007
+ }, [createElementVNode("span", _hoisted_5$2, toDisplayString(__props.title.trim()), 1)], 8, _hoisted_4$2)) : createCommentVNode("v-if", true), createVNode(toolbar_default, {
1928
2008
  "copy-value": __props.copyValue,
1929
2009
  viewport: currentViewport.value,
1930
2010
  "viewport-options": __props.viewportOptions,
@@ -1938,8 +2018,8 @@ var Alone = new Portal(/* @__PURE__ */ defineComponent({
1938
2018
  "viewport",
1939
2019
  "viewport-options"
1940
2020
  ])]),
1941
- errorText.value ? (openBlock(), createElementBlock("pre", _hoisted_4$1, toDisplayString(errorText.value), 1)) : createCommentVNode("v-if", true),
1942
- createElementVNode("div", _hoisted_5$1, [createVNode(unref(Scroller), {
2021
+ errorText.value ? (openBlock(), createElementBlock("pre", _hoisted_6$1, toDisplayString(errorText.value), 1)) : createCommentVNode("v-if", true),
2022
+ createElementVNode("div", _hoisted_7$1, [createVNode(unref(Scroller), {
1943
2023
  class: "docs-playground-popup__scroller",
1944
2024
  "content-class": "docs-playground-popup__scroller-content",
1945
2025
  "auto-resize": true,
@@ -1976,29 +2056,25 @@ var Alone = new Portal(/* @__PURE__ */ defineComponent({
1976
2056
  //#endregion
1977
2057
  //#region packages/playground/src/core/runtime/runtime.vue?vue&type=script&setup=true&lang.ts
1978
2058
  var _hoisted_1$1 = { class: "docs-playground-runtime-host" };
1979
- var _hoisted_2 = {
2059
+ var _hoisted_2$1 = {
1980
2060
  key: 0,
1981
2061
  class: "docs-playground__runtime-error",
1982
2062
  role: "alert"
1983
2063
  };
1984
- var _hoisted_3 = { class: "docs-playground__header" };
1985
- var _hoisted_4 = {
2064
+ var _hoisted_3$1 = {
1986
2065
  key: 0,
1987
- class: "docs-playground__views"
2066
+ class: "docs-playground__header"
1988
2067
  };
1989
- var _hoisted_5 = [
1990
- "title",
1991
- "aria-label",
1992
- "aria-pressed",
1993
- "onClick"
1994
- ];
1995
- var _hoisted_6 = {
1996
- key: 0,
2068
+ var _hoisted_4$1 = ["id", "title"];
2069
+ var _hoisted_5$1 = ["href"];
2070
+ var _hoisted_6 = { class: "docs-playground__title-text" };
2071
+ var _hoisted_7 = {
2072
+ key: 1,
1997
2073
  class: "docs-playground__runtime-error",
1998
2074
  role: "alert"
1999
2075
  };
2000
- var _hoisted_7 = { class: "docs-playground-runtime__viewport-stage" };
2001
- var _hoisted_8 = [
2076
+ var _hoisted_8 = { class: "docs-playground-runtime__viewport-stage" };
2077
+ var _hoisted_9 = [
2002
2078
  "aria-expanded",
2003
2079
  "title",
2004
2080
  "aria-label"
@@ -2019,7 +2095,13 @@ var runtime_default = /* @__PURE__ */ defineComponent({
2019
2095
  type: Boolean,
2020
2096
  default: false
2021
2097
  },
2022
- expand: { type: [Boolean, Number] },
2098
+ hideChrome: {
2099
+ type: Boolean,
2100
+ default: false
2101
+ },
2102
+ expandable: { type: [Boolean, Number] },
2103
+ title: { default: "" },
2104
+ id: { default: "" },
2023
2105
  viewport: { default: "auto" },
2024
2106
  viewportOptions: { default: () => ["auto", 375] }
2025
2107
  },
@@ -2029,10 +2111,16 @@ var runtime_default = /* @__PURE__ */ defineComponent({
2029
2111
  "viewport-change",
2030
2112
  "navigate"
2031
2113
  ],
2032
- setup(__props, { emit: __emit }) {
2114
+ setup(__props, { expose: __expose, emit: __emit }) {
2033
2115
  const props = __props;
2034
2116
  const { locale, t } = useLocale();
2035
- const getViewText = (view) => t(playgroundViewMessage(view));
2117
+ const displayTitle = computed(() => props.title.trim());
2118
+ const titleEl = ref(null);
2119
+ const titleId = computed(() => resolvePlaygroundTitleId(displayTitle.value, props.id, (candidate) => {
2120
+ if (typeof document === "undefined") return false;
2121
+ const existing = document.getElementById(candidate);
2122
+ return !!existing && existing !== titleEl.value;
2123
+ }));
2036
2124
  const emit = __emit;
2037
2125
  const joinCode = (...values) => values.filter(Boolean).join("\n");
2038
2126
  const mergePreviewOptions = (extraHeadHTML) => {
@@ -2081,12 +2169,12 @@ var runtime_default = /* @__PURE__ */ defineComponent({
2081
2169
  };
2082
2170
  const runtimeRoot = ref(null);
2083
2171
  const previewExpanded = ref(false);
2084
- /** `expand: true` 时在展开瞬间冻结,避免滚动重算高度造成抖动。 */
2172
+ /** `expandable: true` 时在展开瞬间冻结,避免滚动重算高度造成抖动。 */
2085
2173
  const frozenExpandedHeight = ref(0);
2086
2174
  const measurePreviewChromeHeight = () => {
2087
2175
  const root = runtimeRoot.value;
2088
2176
  if (!root) return 0;
2089
- const header = root.querySelector(".docs-playground__header");
2177
+ const header = (root.closest(".docs-playground") ?? root).querySelector(".docs-playground__header");
2090
2178
  const error = root.querySelector(".docs-playground__runtime-error");
2091
2179
  return (header instanceof HTMLElement ? header.offsetHeight : 0) + (error instanceof HTMLElement ? error.offsetHeight : 0);
2092
2180
  };
@@ -2099,18 +2187,18 @@ var runtime_default = /* @__PURE__ */ defineComponent({
2099
2187
  }));
2100
2188
  };
2101
2189
  const syncFrozenExpandedHeight = () => {
2102
- if (!previewExpanded.value || props.expand !== true) return;
2190
+ if (!previewExpanded.value || props.expandable !== true) return;
2103
2191
  frozenExpandedHeight.value = measureExpandedPreviewHeight();
2104
2192
  };
2105
2193
  if (typeof window !== "undefined") {
2106
2194
  window.addEventListener("message", handleBridgeMessage);
2107
2195
  window.addEventListener("resize", syncFrozenExpandedHeight);
2108
2196
  }
2109
- const canExpandPreview = computed(() => !props.styleless && isPlaygroundExpandEnabled(props.expand));
2197
+ const canExpandPreview = computed(() => !props.styleless && isPlaygroundExpandable(props.expandable));
2110
2198
  const expandLabel = computed(() => t(previewExpanded.value ? "playground.runtime.collapsePreview" : "playground.runtime.expandPreview"));
2111
2199
  const desiredViewportHeight = computed(() => {
2112
- if (previewExpanded.value && props.expand === true) return frozenExpandedHeight.value;
2113
- if (previewExpanded.value && isPlaygroundExpandEnabled(props.expand)) return resolveExpandedPreviewHeight(props.expand, 0);
2200
+ if (previewExpanded.value && props.expandable === true) return frozenExpandedHeight.value;
2201
+ if (previewExpanded.value && isPlaygroundExpandable(props.expandable)) return resolveExpandedPreviewHeight(props.expandable, 0);
2114
2202
  const fixedHeight = getViewportHeight(props.viewport);
2115
2203
  if (fixedHeight) return fixedHeight;
2116
2204
  return runtimeHeight.value;
@@ -2121,7 +2209,7 @@ var runtime_default = /* @__PURE__ */ defineComponent({
2121
2209
  const handleTogglePreviewExpand = () => {
2122
2210
  if (!canExpandPreview.value) return;
2123
2211
  if (!previewExpanded.value) {
2124
- if (props.expand === true) frozenExpandedHeight.value = measureExpandedPreviewHeight();
2212
+ if (props.expandable === true) frozenExpandedHeight.value = measureExpandedPreviewHeight();
2125
2213
  else frozenExpandedHeight.value = 0;
2126
2214
  previewExpanded.value = true;
2127
2215
  nextTick(scrollExpandedPreviewIntoView);
@@ -2210,6 +2298,7 @@ var runtime_default = /* @__PURE__ */ defineComponent({
2210
2298
  Alone.popup({
2211
2299
  store,
2212
2300
  copyValue: copyValue.value,
2301
+ title: props.title,
2213
2302
  viewport: props.viewport,
2214
2303
  viewportOptions: props.viewportOptions,
2215
2304
  previewOptions: popupPreviewOptions.value,
@@ -2219,7 +2308,6 @@ var runtime_default = /* @__PURE__ */ defineComponent({
2219
2308
  onNavigate: (to) => emit("navigate", to)
2220
2309
  });
2221
2310
  };
2222
- const handleView = (view) => emit("view-change", view);
2223
2311
  const handleViewportChange = (viewport) => {
2224
2312
  emit("viewport-change", viewport);
2225
2313
  };
@@ -2244,6 +2332,11 @@ var runtime_default = /* @__PURE__ */ defineComponent({
2244
2332
  window.removeEventListener("resize", syncFrozenExpandedHeight);
2245
2333
  handleClosePopup();
2246
2334
  });
2335
+ __expose({
2336
+ refresh: handleInlineRefresh,
2337
+ edit: handleEditor,
2338
+ openPopup: handleOpenPopup
2339
+ });
2247
2340
  return (_ctx, _cache) => {
2248
2341
  return openBlock(), createElementBlock("div", _hoisted_1$1, [__props.styleless ? (openBlock(), createElementBlock("div", {
2249
2342
  key: 0,
@@ -2251,7 +2344,7 @@ var runtime_default = /* @__PURE__ */ defineComponent({
2251
2344
  ref: runtimeRoot,
2252
2345
  class: "docs-playground-runtime--styleless",
2253
2346
  style: normalizeStyle(stylelessStyle.value)
2254
- }, [errorText.value ? (openBlock(), createElementBlock("pre", _hoisted_2, toDisplayString(errorText.value), 1)) : createCommentVNode("v-if", true), createElementVNode("div", {
2347
+ }, [errorText.value ? (openBlock(), createElementBlock("pre", _hoisted_2$1, toDisplayString(errorText.value), 1)) : createCommentVNode("v-if", true), createElementVNode("div", {
2255
2348
  class: "docs-playground-runtime__viewport",
2256
2349
  style: normalizeStyle(viewportStyle.value)
2257
2350
  }, [createVNode(unref(Sandbox), {
@@ -2266,7 +2359,18 @@ var runtime_default = /* @__PURE__ */ defineComponent({
2266
2359
  ref: runtimeRoot,
2267
2360
  class: "docs-playground-runtime"
2268
2361
  }, [
2269
- createElementVNode("div", _hoisted_3, [createVNode(toolbar_default, {
2362
+ !__props.hideChrome ? (openBlock(), createElementBlock("div", _hoisted_3$1, [displayTitle.value ? (openBlock(), createElementBlock("span", {
2363
+ key: 0,
2364
+ ref_key: "titleEl",
2365
+ ref: titleEl,
2366
+ class: "docs-playground__title",
2367
+ id: titleId.value,
2368
+ tabindex: "-1",
2369
+ title: displayTitle.value
2370
+ }, [createElementVNode("a", {
2371
+ class: "docs-playground__title-anchor",
2372
+ href: `#${titleId.value}`
2373
+ }, "#", 8, _hoisted_5$1), createElementVNode("span", _hoisted_6, toDisplayString(displayTitle.value), 1)], 8, _hoisted_4$1)) : createCommentVNode("v-if", true), createVNode(toolbar_default, {
2270
2374
  "copy-value": copyValue.value,
2271
2375
  viewport: __props.viewport,
2272
2376
  "viewport-options": __props.viewportOptions,
@@ -2279,22 +2383,12 @@ var runtime_default = /* @__PURE__ */ defineComponent({
2279
2383
  "copy-value",
2280
2384
  "viewport",
2281
2385
  "viewport-options"
2282
- ]), __props.views.length > 1 ? (openBlock(), createElementBlock("div", _hoisted_4, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.views, (item) => {
2283
- return openBlock(), createElementBlock("button", {
2284
- key: item,
2285
- type: "button",
2286
- class: normalizeClass(["docs-playground__view", { "is-active": item === __props.activeView }]),
2287
- title: getViewText(item),
2288
- "aria-label": getViewText(item),
2289
- "aria-pressed": item === __props.activeView,
2290
- onClick: ($event) => handleView(item)
2291
- }, [createVNode(unref(icon_default), { name: item }, null, 8, ["name"])], 10, _hoisted_5);
2292
- }), 128))])) : createCommentVNode("v-if", true)]),
2293
- errorText.value ? (openBlock(), createElementBlock("pre", _hoisted_6, toDisplayString(errorText.value), 1)) : createCommentVNode("v-if", true),
2386
+ ])])) : createCommentVNode("v-if", true),
2387
+ errorText.value ? (openBlock(), createElementBlock("pre", _hoisted_7, toDisplayString(errorText.value), 1)) : createCommentVNode("v-if", true),
2294
2388
  createElementVNode("section", {
2295
2389
  class: normalizeClass(["docs-playground__preview", { "is-expanded": previewExpanded.value }]),
2296
2390
  style: normalizeStyle(previewStyle.value)
2297
- }, [createElementVNode("div", _hoisted_7, [createElementVNode("div", {
2391
+ }, [createElementVNode("div", _hoisted_8, [createElementVNode("div", {
2298
2392
  class: "docs-playground-runtime__viewport",
2299
2393
  style: normalizeStyle(viewportStyle.value)
2300
2394
  }, [(openBlock(), createBlock(unref(Sandbox), {
@@ -2314,7 +2408,7 @@ var runtime_default = /* @__PURE__ */ defineComponent({
2314
2408
  title: expandLabel.value,
2315
2409
  "aria-label": expandLabel.value,
2316
2410
  onClick: handleTogglePreviewExpand
2317
- }, [createVNode(unref(icon_default), { name: "expand" })], 10, _hoisted_8)) : createCommentVNode("v-if", true)], 6)
2411
+ }, [createVNode(unref(icon_default), { name: "expand" })], 10, _hoisted_9)) : createCommentVNode("v-if", true)], 6)
2318
2412
  ], 512))]);
2319
2413
  };
2320
2414
  }
@@ -2325,6 +2419,13 @@ var _hoisted_1 = {
2325
2419
  key: 0,
2326
2420
  class: "docs-playground__error"
2327
2421
  };
2422
+ var _hoisted_2 = {
2423
+ key: 0,
2424
+ class: "docs-playground__header"
2425
+ };
2426
+ var _hoisted_3 = ["id", "title"];
2427
+ var _hoisted_4 = ["href"];
2428
+ var _hoisted_5 = { class: "docs-playground__title-text" };
2328
2429
  //#endregion
2329
2430
  //#region packages/playground/src/playground.vue
2330
2431
  var playground_default = /* @__PURE__ */ defineComponent({
@@ -2342,7 +2443,9 @@ var playground_default = /* @__PURE__ */ defineComponent({
2342
2443
  },
2343
2444
  options: { default: () => ({}) },
2344
2445
  previewInset: { default: 0 },
2345
- expand: { type: [Boolean, Number] },
2446
+ expandable: { type: [Boolean, Number] },
2447
+ title: { default: "" },
2448
+ id: { default: "" },
2346
2449
  previewOptions: {},
2347
2450
  locale: {}
2348
2451
  },
@@ -2366,6 +2469,8 @@ var playground_default = /* @__PURE__ */ defineComponent({
2366
2469
  const sourceFiles = ref(initialFiles);
2367
2470
  const currentEntry = ref(initialEntry);
2368
2471
  const fileActiveFilename = ref(initialEntry);
2472
+ const runtimeRef = ref(null);
2473
+ const titleEl = ref(null);
2369
2474
  const normalizeViews = (views) => {
2370
2475
  const normalized = [];
2371
2476
  for (const view of views) {
@@ -2376,12 +2481,25 @@ var playground_default = /* @__PURE__ */ defineComponent({
2376
2481
  return normalized.length ? normalized : ["runtime"];
2377
2482
  };
2378
2483
  const normalizedViews = computed(() => normalizeViews(props.views));
2484
+ const hasRuntimeView = computed(() => normalizedViews.value.includes("runtime"));
2485
+ const hasFilesView = computed(() => normalizedViews.value.includes("files"));
2379
2486
  const activeView = ref(normalizedViews.value[0]);
2380
2487
  const runtimeActivated = ref(props.styleless || activeView.value === "runtime");
2381
2488
  const normalizedViewportOptions = computed(() => normalizeViewportOptions(props.viewportOptions));
2382
2489
  const activeViewport = ref(resolveInitialViewport(props.viewport, normalizedViewportOptions.value));
2383
2490
  const selectableViewportOptions = computed(() => includeActiveViewport(normalizedViewportOptions.value, activeViewport.value));
2384
2491
  const error = ref(props.entry && initialFiles[props.entry] === void 0 ? t("playground.validation.entryMissing", { filename: props.entry }) : "");
2492
+ const displayTitle = computed(() => props.title.trim());
2493
+ const titleId = computed(() => resolvePlaygroundTitleId(displayTitle.value, props.id, (candidate) => {
2494
+ if (typeof document === "undefined") return false;
2495
+ const existing = document.getElementById(candidate);
2496
+ return !!existing && existing !== titleEl.value;
2497
+ }));
2498
+ const copyValue = computed(() => sourceFiles.value[currentEntry.value] || "");
2499
+ /** runtime / 双视图始终有顶栏;files-only 仅有标题时渲染。 */
2500
+ const showHeader = computed(() => hasRuntimeView.value || !!displayTitle.value);
2501
+ const showToolbar = computed(() => hasRuntimeView.value);
2502
+ const showRuntimeActions = computed(() => activeView.value === "runtime");
2385
2503
  watch(locale, () => {
2386
2504
  if (props.entry && sourceFiles.value[props.entry] === void 0) error.value = t("playground.validation.entryMissing", { filename: props.entry });
2387
2505
  });
@@ -2395,6 +2513,15 @@ var playground_default = /* @__PURE__ */ defineComponent({
2395
2513
  activeViewport.value = cloneViewport(viewport);
2396
2514
  emit("update:viewport", cloneViewport(viewport));
2397
2515
  };
2516
+ const handleRefresh = () => {
2517
+ runtimeRef.value?.refresh();
2518
+ };
2519
+ const handleEdit = () => {
2520
+ runtimeRef.value?.edit();
2521
+ };
2522
+ const handleOpenPopup = () => {
2523
+ runtimeRef.value?.openPopup();
2524
+ };
2398
2525
  const handleFileActive = (filename) => {
2399
2526
  if (sourceFiles.value[filename] !== void 0) fileActiveFilename.value = filename;
2400
2527
  };
@@ -2476,8 +2603,10 @@ var playground_default = /* @__PURE__ */ defineComponent({
2476
2603
  options: __props.options,
2477
2604
  "preview-options": __props.previewOptions,
2478
2605
  "preview-inset": __props.previewInset,
2479
- expand: __props.expand,
2606
+ expandable: __props.expandable,
2480
2607
  styleless: true,
2608
+ title: __props.title,
2609
+ id: __props.id,
2481
2610
  viewport: activeViewport.value,
2482
2611
  "viewport-options": selectableViewportOptions.value,
2483
2612
  onFilesChange: handleFilesChange,
@@ -2489,29 +2618,68 @@ var playground_default = /* @__PURE__ */ defineComponent({
2489
2618
  "options",
2490
2619
  "preview-options",
2491
2620
  "preview-inset",
2492
- "expand",
2621
+ "expandable",
2622
+ "title",
2623
+ "id",
2493
2624
  "viewport",
2494
2625
  "viewport-options"
2495
2626
  ])) : (openBlock(), createElementBlock("div", {
2496
2627
  key: 1,
2497
2628
  class: normalizeClass(["docs-playground", { "docs-playground--files": activeView.value === "files" }])
2498
- }, [
2499
- error.value ? (openBlock(), createElementBlock("div", _hoisted_1, toDisplayString(error.value), 1)) : createCommentVNode("v-if", true),
2500
- runtimeActivated.value && normalizedViews.value.includes("runtime") ? withDirectives((openBlock(), createBlock(unref(runtime_default), {
2629
+ }, [error.value ? (openBlock(), createElementBlock("div", _hoisted_1, toDisplayString(error.value), 1)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
2630
+ showHeader.value ? (openBlock(), createElementBlock("div", _hoisted_2, [displayTitle.value ? (openBlock(), createElementBlock("span", {
2631
+ key: 0,
2632
+ ref_key: "titleEl",
2633
+ ref: titleEl,
2634
+ class: "docs-playground__title",
2635
+ id: titleId.value,
2636
+ tabindex: "-1",
2637
+ title: displayTitle.value
2638
+ }, [createElementVNode("a", {
2639
+ class: "docs-playground__title-anchor",
2640
+ href: `#${titleId.value}`
2641
+ }, "#", 8, _hoisted_4), createElementVNode("span", _hoisted_5, toDisplayString(displayTitle.value), 1)], 8, _hoisted_3)) : createCommentVNode("v-if", true), showToolbar.value ? (openBlock(), createBlock(toolbar_default, {
2501
2642
  key: 1,
2643
+ "copy-value": copyValue.value,
2644
+ viewport: activeViewport.value,
2645
+ "viewport-options": selectableViewportOptions.value,
2646
+ views: normalizedViews.value,
2647
+ "active-view": activeView.value,
2648
+ "show-runtime-actions": showRuntimeActions.value,
2649
+ "show-open-popup": hasRuntimeView.value,
2650
+ onRefresh: handleRefresh,
2651
+ onEdit: handleEdit,
2652
+ onOpenPopup: handleOpenPopup,
2653
+ onViewportChange: handleViewport,
2654
+ onViewChange: handleView
2655
+ }, null, 8, [
2656
+ "copy-value",
2657
+ "viewport",
2658
+ "viewport-options",
2659
+ "views",
2660
+ "active-view",
2661
+ "show-runtime-actions",
2662
+ "show-open-popup"
2663
+ ])) : createCommentVNode("v-if", true)])) : createCommentVNode("v-if", true),
2664
+ runtimeActivated.value && hasRuntimeView.value ? withDirectives((openBlock(), createBlock(unref(runtime_default), {
2665
+ key: 1,
2666
+ ref_key: "runtimeRef",
2667
+ ref: runtimeRef,
2502
2668
  files: sourceFiles.value,
2503
2669
  entry: currentEntry.value,
2504
2670
  options: __props.options,
2505
2671
  "preview-options": __props.previewOptions,
2506
2672
  "preview-inset": __props.previewInset,
2507
- expand: __props.expand,
2673
+ expandable: __props.expandable,
2674
+ "hide-chrome": true,
2675
+ title: __props.title,
2676
+ id: __props.id,
2508
2677
  "active-view": activeView.value,
2509
2678
  views: normalizedViews.value,
2510
2679
  viewport: activeViewport.value,
2511
2680
  "viewport-options": selectableViewportOptions.value,
2512
2681
  onFilesChange: handleFilesChange,
2513
2682
  onNavigate: _cache[1] || (_cache[1] = ($event) => emit("navigate", $event)),
2514
- onViewChange: handleView,
2515
2683
  onViewportChange: handleViewport
2516
2684
  }, null, 8, [
2517
2685
  "files",
@@ -2519,31 +2687,32 @@ var playground_default = /* @__PURE__ */ defineComponent({
2519
2687
  "options",
2520
2688
  "preview-options",
2521
2689
  "preview-inset",
2522
- "expand",
2690
+ "expandable",
2691
+ "title",
2692
+ "id",
2523
2693
  "active-view",
2524
2694
  "views",
2525
2695
  "viewport",
2526
2696
  "viewport-options"
2527
- ])), [[vShow, !error.value && activeView.value === "runtime"]]) : createCommentVNode("v-if", true),
2528
- normalizedViews.value.includes("files") ? withDirectives((openBlock(), createBlock(unref(files_preview_default), {
2697
+ ])), [[vShow, activeView.value === "runtime"]]) : createCommentVNode("v-if", true),
2698
+ hasFilesView.value ? withDirectives((openBlock(), createBlock(unref(files_preview_default), {
2529
2699
  key: 2,
2530
2700
  files: sourceFiles.value,
2531
2701
  entry: currentEntry.value,
2532
2702
  "active-filename": fileActiveFilename.value,
2533
2703
  "active-view": activeView.value,
2534
2704
  views: normalizedViews.value,
2535
- onActiveChange: handleFileActive,
2536
- onViewChange: handleView
2705
+ onActiveChange: handleFileActive
2537
2706
  }, null, 8, [
2538
2707
  "files",
2539
2708
  "entry",
2540
2709
  "active-filename",
2541
2710
  "active-view",
2542
2711
  "views"
2543
- ])), [[vShow, !error.value && activeView.value === "files"]]) : createCommentVNode("v-if", true)
2544
- ], 2));
2712
+ ])), [[vShow, activeView.value === "files"]]) : createCommentVNode("v-if", true)
2713
+ ], 64))], 2));
2545
2714
  };
2546
2715
  }
2547
2716
  });
2548
2717
  //#endregion
2549
- export { code_preview_default as CodePreview, DEFAULT_CDN_URL, Editor, playground_default as Playground, applyPlaygroundImportMapOverride, applyPlaygroundStyleOverride, clearPlaygroundMaps, createBuiltinImports, createBuiltinStyles, createRuntimePreviewOptions, getPlaygroundImportMapOverrides, getPlaygroundSiteModules, getPlaygroundSiteStyles, getPlaygroundStyleOverrides, highlightCode, highlightCodeByLanguage, isSafePlaygroundHref, normalizeCdnURL, registerVueHighlight, removePlaygroundImportMapOverride, removePlaygroundStyleOverride, resolveHighlightLanguage, setPlaygroundImportMapOverrides, setPlaygroundSiteModules, setPlaygroundSiteStyles, setPlaygroundStyleOverrides, vueHighlight };
2718
+ export { code_preview_default as CodePreview, DEFAULT_CDN_URL, Editor, playground_default as Playground, applyPlaygroundImportMapOverride, applyPlaygroundStyleOverride, clearPlaygroundMaps, createBuiltinImports, createBuiltinStyles, createRuntimePreviewOptions, getPlaygroundImportMapOverrides, getPlaygroundSiteModules, getPlaygroundSiteStyles, getPlaygroundStyleOverrides, highlightCode, highlightCodeByLanguage, isSafePlaygroundHref, normalizeCdnURL, registerVueHighlight, removePlaygroundImportMapOverride, removePlaygroundStyleOverride, resolveHighlightLanguage, resolvePlaygroundTitleId, setPlaygroundImportMapOverrides, setPlaygroundSiteModules, setPlaygroundSiteStyles, setPlaygroundStyleOverrides, slugifyPlaygroundTitle, vueHighlight };