@poveste/app 0.19.1 → 0.21.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.
Files changed (58) hide show
  1. package/dist/bundled/app.css +208 -7
  2. package/dist/bundled/components/HomeView.vue_vue_type_script_setup_true_lang.js +3 -3
  3. package/dist/bundled/components/app/AppLogo.vue_vue_type_script_setup_true_lang.js +4 -4
  4. package/dist/bundled/components/app/TopBarChipItem.js +10 -6
  5. package/dist/bundled/components/layout/LayoutItem.js +1 -0
  6. package/dist/bundled/components/layout/LayoutItem.vue_vue_type_script_setup_true_lang.js +20 -23
  7. package/dist/bundled/components/layout/LayoutModal.vue_vue_type_script_setup_true_lang.js +44 -5
  8. package/dist/bundled/components/panel/ComponentDocs.js +7 -0
  9. package/dist/bundled/components/panel/ComponentDocs.vue_vue_type_script_setup_true_lang.js +164 -0
  10. package/dist/bundled/components/panel/StoryDocs.vue_vue_type_script_setup_true_lang.js +57 -22
  11. package/dist/bundled/components/panel/StorySourceCode.js +1 -1
  12. package/dist/bundled/components/panel/StorySourceCode.vue_vue_type_script_setup_true_lang.js +22 -6
  13. package/dist/bundled/components/story/GenericMountStory.vue_vue_type_script_setup_true_lang.js +3 -7
  14. package/dist/bundled/components/story/GenericRenderStory.vue_vue_type_script_setup_true_lang.js +3 -10
  15. package/dist/bundled/components/story/StoryResponsivePreview.js +1 -1
  16. package/dist/bundled/components/story/StoryResponsivePreview.vue_vue_type_script_setup_true_lang.js +5 -3
  17. package/dist/bundled/components/story/StoryVariantGridItem.js +1 -1
  18. package/dist/bundled/components/story/StoryVariantGridItem.vue_vue_type_script_setup_true_lang.js +5 -3
  19. package/dist/bundled/components/story/StoryVariantSinglePreviewRemote.vue_vue_type_script_setup_true_lang.js +3 -2
  20. package/dist/bundled/components/toolbar/DevOnlyToolbarOpenInEditor.vue_vue_type_script_setup_true_lang.js +0 -1
  21. package/dist/bundled/index.js +5 -1
  22. package/dist/bundled/sandbox.js +2 -0
  23. package/dist/bundled/util/client-plugin.js +22 -0
  24. package/dist/bundled/util/component-docs-data.js +5 -0
  25. package/dist/bundled/util/component-docs.js +133 -0
  26. package/dist/bundled/util/dark.js +3 -1
  27. package/dist/bundled/util/docs.js +13 -3
  28. package/dist/bundled/util/highlighter.js +1 -1
  29. package/dist/bundled/util/icons.generated.js +3 -2
  30. package/dist/bundled/util/keyboard.js +5 -4
  31. package/dist/bundled/util/mapping.js +1 -5
  32. package/dist/style.css +321 -195
  33. package/package.json +17 -17
  34. package/src/app/components/HomeView.vue +2 -2
  35. package/src/app/components/app/AppLogo.vue +4 -6
  36. package/src/app/components/app/TopBarChipItem.vue +55 -6
  37. package/src/app/components/layout/LayoutItem.vue +56 -6
  38. package/src/app/components/layout/LayoutModal.vue +55 -2
  39. package/src/app/components/panel/ComponentDocs.vue +323 -0
  40. package/src/app/components/panel/StoryDocs.vue +38 -2
  41. package/src/app/components/panel/StorySourceCode.vue +29 -5
  42. package/src/app/components/story/GenericMountStory.vue +3 -5
  43. package/src/app/components/story/GenericRenderStory.vue +4 -12
  44. package/src/app/components/story/StoryResponsivePreview.vue +4 -1
  45. package/src/app/components/story/StoryVariantGridItem.vue +4 -1
  46. package/src/app/components/story/StoryVariantSinglePreviewRemote.vue +6 -4
  47. package/src/app/components/toolbar/DevOnlyToolbarOpenInEditor.vue +0 -1
  48. package/src/app/index.ts +12 -3
  49. package/src/app/sandbox.ts +5 -0
  50. package/src/app/util/client-plugin.ts +33 -0
  51. package/src/app/util/component-docs-data.ts +6 -0
  52. package/src/app/util/component-docs.ts +169 -0
  53. package/src/app/util/dark.ts +6 -0
  54. package/src/app/util/docs.ts +18 -2
  55. package/src/app/util/highlighter.ts +2 -1
  56. package/src/app/util/icons.generated.ts +2 -2
  57. package/src/app/util/keyboard.ts +8 -4
  58. package/src/app/util/mapping.ts +1 -5
@@ -1,7 +1,9 @@
1
1
  import { povesteConfig } from "../../util/config.js";
2
2
  import DevOnlyToolbarOpenInEditor_default from "../toolbar/DevOnlyToolbarOpenInEditor.js";
3
3
  import BaseEmpty_default from "../base/BaseEmpty.js";
4
- import { computed, createBlock, createCommentVNode, createElementBlock, createTextVNode, createVNode, defineComponent, nextTick, normalizeClass, openBlock, ref, toRefs, unref, watch, watchEffect, withCtx } from "@poveste/vendors/vue";
4
+ import { onlySections, useComponentDocs } from "../../util/component-docs.js";
5
+ import ComponentDocs_default from "./ComponentDocs.js";
6
+ import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, nextTick, normalizeClass, openBlock, ref, toDisplayString, toRefs, unref, watch, watchEffect, withCtx } from "@poveste/vendors/vue";
5
7
  import { Icon } from "@poveste/vendors/iconify";
6
8
  import { useRoute, useRouter } from "@poveste/vendors/vue-router";
7
9
  import { markdownFiles } from "virtual:$poveste-markdown-files";
@@ -49,6 +51,8 @@ var StoryDocs_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
49
51
  const emit = __emit;
50
52
  const { story } = toRefs(props);
51
53
  const { renderedDoc } = useStoryDoc(story);
54
+ const { components: allComponents, pending, off } = useComponentDocs(computed(() => story.value?.id));
55
+ const components = computed(() => allComponents.value && onlySections(allComponents.value, story.value?.autoDocs));
52
56
  const router = useRouter();
53
57
  const fakeHost = `http://a.com`;
54
58
  function onClick(e) {
@@ -104,27 +108,58 @@ var StoryDocs_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ define
104
108
  return openBlock(), createElementBlock("div", {
105
109
  class: "poveste-story-docs",
106
110
  onClickCapture: onClick
107
- }, [_ctx.__POVESTE_DEV__ && unref(renderedDoc) && filePath.value ? (openBlock(), createElementBlock("div", {
108
- key: 0,
109
- class: normalizeClass(["flex items-center gap-2 p-2", { "pt-4": !__props.standalone }])
110
- }, [filePath.value ? (openBlock(), createBlock(DevOnlyToolbarOpenInEditor_default, {
111
- key: 0,
112
- file: filePath.value,
113
- tooltip: "Edit docs in editor"
114
- }, null, 8, ["file"])) : createCommentVNode("", true)], 2)) : createCommentVNode("", true), !unref(renderedDoc) ? (openBlock(), createBlock(BaseEmpty_default, { key: 1 }, {
115
- default: withCtx(() => [createVNode(unref(Icon), {
116
- icon: "carbon:document-unknown",
117
- class: "w-8 h-8 opacity-50 mb-6"
118
- }), _cache[0] || (_cache[0] = createTextVNode(" No documentation available ", -1))]),
119
- _: 1
120
- })) : (openBlock(), createElementBlock("div", {
121
- key: 2,
122
- ref_key: "renderedEl",
123
- ref: renderedEl,
124
- class: "prose dark:prose-invert p-4 max-w-none",
125
- "data-testid": "story-docs",
126
- innerHTML: unref(renderedDoc)
127
- }, null, 8, _hoisted_1))], 32);
111
+ }, [
112
+ _ctx.__POVESTE_DEV__ && unref(renderedDoc) && filePath.value ? (openBlock(), createElementBlock("div", {
113
+ key: 0,
114
+ class: normalizeClass(["flex items-center gap-2 p-2", { "pt-4": !__props.standalone }])
115
+ }, [filePath.value ? (openBlock(), createBlock(DevOnlyToolbarOpenInEditor_default, {
116
+ key: 0,
117
+ file: filePath.value,
118
+ tooltip: "Edit docs in editor"
119
+ }, null, 8, ["file"])) : createCommentVNode("", true)], 2)) : createCommentVNode("", true),
120
+ _ctx.__POVESTE_DEV__ && !unref(renderedDoc) && !components.value?.length && unref(pending) ? (openBlock(), createBlock(BaseEmpty_default, {
121
+ key: 1,
122
+ "data-testid": "docs-pending"
123
+ }, {
124
+ default: withCtx(() => [
125
+ createVNode(unref(Icon), {
126
+ icon: "carbon:circle-dash",
127
+ class: "w-8 h-8 opacity-50 mb-6 animate-spin"
128
+ }),
129
+ _cache[0] || (_cache[0] = createTextVNode(" Reading component types… ", -1)),
130
+ _cache[1] || (_cache[1] = createElementVNode("span", { class: "text-sm opacity-70 mt-2" }, "The first time can take a while.", -1))
131
+ ]),
132
+ _: 1
133
+ })) : !unref(pending) && !unref(renderedDoc) && !components.value?.length && unref(off) ? (openBlock(), createBlock(BaseEmpty_default, {
134
+ key: 2,
135
+ "data-testid": "docs-off"
136
+ }, {
137
+ default: withCtx(() => [createVNode(unref(Icon), {
138
+ icon: "carbon:document-unknown",
139
+ class: "w-8 h-8 opacity-50 mb-6"
140
+ }), createTextVNode(" " + toDisplayString(unref(off)), 1)]),
141
+ _: 1
142
+ })) : !unref(pending) && !unref(renderedDoc) && !components.value?.length ? (openBlock(), createBlock(BaseEmpty_default, { key: 3 }, {
143
+ default: withCtx(() => [createVNode(unref(Icon), {
144
+ icon: "carbon:document-unknown",
145
+ class: "w-8 h-8 opacity-50 mb-6"
146
+ }), _cache[2] || (_cache[2] = createTextVNode(" No documentation available ", -1))]),
147
+ _: 1
148
+ })) : createCommentVNode("", true),
149
+ unref(renderedDoc) ? (openBlock(), createElementBlock("div", {
150
+ key: 4,
151
+ ref_key: "renderedEl",
152
+ ref: renderedEl,
153
+ class: "prose dark:prose-invert p-4 max-w-none",
154
+ "data-testid": "story-docs",
155
+ innerHTML: unref(renderedDoc)
156
+ }, null, 8, _hoisted_1)) : createCommentVNode("", true),
157
+ components.value?.length ? (openBlock(), createBlock(ComponentDocs_default, {
158
+ key: 5,
159
+ components: components.value,
160
+ "story-file": unref(story).file?.filePath
161
+ }, null, 8, ["components", "story-file"])) : createCommentVNode("", true)
162
+ ], 32);
128
163
  };
129
164
  }
130
165
  });
@@ -2,6 +2,6 @@ import _plugin_vue_export_helper_default from "../../_virtual/_plugin-vue_export
2
2
  import StorySourceCode_vue_vue_type_script_setup_true_lang_default from "./StorySourceCode.vue_vue_type_script_setup_true_lang.js";
3
3
  /* empty css */
4
4
  //#region src/app/components/panel/StorySourceCode.vue
5
- var StorySourceCode_default = /*#__PURE__*/ _plugin_vue_export_helper_default(StorySourceCode_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-ed711d57"]]);
5
+ var StorySourceCode_default = /*#__PURE__*/ _plugin_vue_export_helper_default(StorySourceCode_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-cecbc93b"]]);
6
6
  //#endregion
7
7
  export { StorySourceCode_default as default };
@@ -1,6 +1,6 @@
1
1
  import { isDark } from "../../util/dark.js";
2
2
  import BaseEmpty_default from "../base/BaseEmpty.js";
3
- import { getDynamicSourceCode, getStaticSourceCode, loadGenerateSourceCode } from "../../util/docs.js";
3
+ import { getDynamicSourceCode, getStaticSourceCode, loadGenerateSourceCode, sourceLang } from "../../util/docs.js";
4
4
  import { getHighlighter } from "../../util/highlighter.js";
5
5
  import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, markRaw, nextTick, normalizeClass, onMounted, openBlock, ref, shallowRef, toDisplayString, unref, watch, watchEffect, withCtx } from "@poveste/vendors/vue";
6
6
  import { Icon } from "@poveste/vendors/iconify";
@@ -27,8 +27,15 @@ var StorySourceCode_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
27
27
  setup(__props) {
28
28
  const props = __props;
29
29
  const generateSourceCodeFn = shallowRef(null);
30
+ const dynamicSettled = ref(false);
31
+ const staticSettled = ref(false);
30
32
  watchEffect(async () => {
31
- const generate = await loadGenerateSourceCode(props.story);
33
+ let generate;
34
+ try {
35
+ generate = await loadGenerateSourceCode(props.story);
36
+ } finally {
37
+ if (!generate) dynamicSettled.value = true;
38
+ }
32
39
  if (generate) generateSourceCodeFn.value = markRaw(generate);
33
40
  });
34
41
  const highlighter = shallowRef();
@@ -39,12 +46,14 @@ var StorySourceCode_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
39
46
  if (!generateSourceCodeFn.value) return;
40
47
  error.value = null;
41
48
  dynamicSourceCode.value = "";
49
+ dynamicSettled.value = false;
42
50
  try {
43
51
  dynamicSourceCode.value = await getDynamicSourceCode(props.variant, generateSourceCodeFn.value) ?? "";
44
52
  } catch (e) {
45
53
  console.error(e);
46
54
  error.value = e instanceof Error ? e.message : String(e);
47
55
  }
56
+ dynamicSettled.value = true;
48
57
  if (!dynamicSourceCode.value) displayedSource.value = "static";
49
58
  }, {
50
59
  deep: true,
@@ -53,8 +62,14 @@ var StorySourceCode_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
53
62
  const staticSourceCode = ref("");
54
63
  watch(() => [props.story, props.story?.file?.source], async () => {
55
64
  staticSourceCode.value = "";
56
- staticSourceCode.value = await getStaticSourceCode(props.story) ?? "";
65
+ staticSettled.value = false;
66
+ try {
67
+ staticSourceCode.value = await getStaticSourceCode(props.story) ?? "";
68
+ } finally {
69
+ staticSettled.value = true;
70
+ }
57
71
  }, { immediate: true });
72
+ const loading = computed(() => displayedSource.value === "dynamic" ? !dynamicSettled.value : !staticSettled.value);
58
73
  const displayedSourceCode = computed(() => {
59
74
  if (displayedSource.value === "dynamic") return dynamicSourceCode.value;
60
75
  return staticSourceCode.value;
@@ -67,7 +82,7 @@ var StorySourceCode_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
67
82
  }
68
83
  });
69
84
  const sourceHtml = computed(() => displayedSourceCode.value ? highlighter.value?.codeToHtml(displayedSourceCode.value, {
70
- lang: "html",
85
+ lang: sourceLang(props.story),
71
86
  theme: isDark.value ? "github-dark" : "github-light-high-contrast"
72
87
  }) : "");
73
88
  let lastScroll = 0;
@@ -107,13 +122,14 @@ var StorySourceCode_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
107
122
  }, 8, ["content"])]),
108
123
  createVNode(unref(HstCopyIcon), {
109
124
  content: displayedSourceCode.value,
125
+ loading: loading.value,
110
126
  class: "flex-none"
111
- }, null, 8, ["content"])
127
+ }, null, 8, ["content", "loading"])
112
128
  ])) : createCommentVNode("", true), error.value ? (openBlock(), createElementBlock("div", _hoisted_4, " Error: " + toDisplayString(error.value), 1)) : !displayedSourceCode.value ? (openBlock(), createBlock(BaseEmpty_default, { key: 2 }, {
113
129
  default: withCtx(() => [createVNode(unref(Icon), {
114
130
  icon: "carbon:code-hide",
115
131
  class: "w-8 h-8 opacity-50 mb-6"
116
- }), _cache[4] || (_cache[4] = createElementVNode("span", null, "Not available", -1))]),
132
+ }), createElementVNode("span", null, toDisplayString(loading.value ? "Loading" : "Not available"), 1)]),
117
133
  _: 1
118
134
  })) : !sourceHtml.value ? (openBlock(), createElementBlock("textarea", {
119
135
  key: 3,
@@ -1,5 +1,5 @@
1
+ import { loadClientPlugin } from "../../util/client-plugin.js";
1
2
  import { createBlock, createCommentVNode, defineComponent, markRaw, mergeProps, openBlock, ref, resolveDynamicComponent, watchEffect } from "@poveste/vendors/vue";
2
- import { clientSupportPlugins } from "virtual:$poveste-support-plugins-client";
3
3
  var GenericMountStory_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
4
4
  inheritAttrs: false,
5
5
  __name: "GenericMountStory",
@@ -8,12 +8,8 @@ var GenericMountStory_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*
8
8
  const props = __props;
9
9
  const mountComponent = ref(null);
10
10
  watchEffect(async () => {
11
- const supportPluginId = props.story.file?.supportPluginId;
12
- const clientPlugin = supportPluginId ? clientSupportPlugins[supportPluginId] : void 0;
13
- if (clientPlugin) {
14
- const pluginModule = await clientPlugin();
15
- mountComponent.value = markRaw(pluginModule.MountStory);
16
- }
11
+ const pluginModule = await loadClientPlugin(props.story.file?.supportPluginId);
12
+ if (pluginModule) mountComponent.value = markRaw(pluginModule.MountStory);
17
13
  });
18
14
  return (_ctx, _cache) => {
19
15
  return mountComponent.value ? (openBlock(), createBlock(resolveDynamicComponent(mountComponent.value), mergeProps({
@@ -1,5 +1,5 @@
1
+ import { loadClientPlugin } from "../../util/client-plugin.js";
1
2
  import { createBlock, createCommentVNode, defineComponent, markRaw, mergeProps, openBlock, ref, resolveDynamicComponent, watchEffect } from "@poveste/vendors/vue";
2
- import { clientSupportPlugins } from "virtual:$poveste-support-plugins-client";
3
3
  var GenericRenderStory_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
4
4
  inheritAttrs: false,
5
5
  __name: "GenericRenderStory",
@@ -8,15 +8,8 @@ var GenericRenderStory_vue_vue_type_script_setup_true_lang_default = /*@__PURE__
8
8
  const props = __props;
9
9
  const mountComponent = ref(null);
10
10
  watchEffect(async () => {
11
- const supportPluginId = props.story.file?.supportPluginId;
12
- const clientPlugin = supportPluginId ? clientSupportPlugins[supportPluginId] : void 0;
13
- if (clientPlugin) try {
14
- const pluginModule = await clientPlugin();
15
- mountComponent.value = markRaw(pluginModule.RenderStory);
16
- } catch (e) {
17
- console.error(e);
18
- throw e;
19
- }
11
+ const pluginModule = await loadClientPlugin(props.story.file?.supportPluginId);
12
+ if (pluginModule) mountComponent.value = markRaw(pluginModule.RenderStory);
20
13
  });
21
14
  return (_ctx, _cache) => {
22
15
  return mountComponent.value ? (openBlock(), createBlock(resolveDynamicComponent(mountComponent.value), mergeProps({
@@ -2,6 +2,6 @@ import _plugin_vue_export_helper_default from "../../_virtual/_plugin-vue_export
2
2
  import StoryResponsivePreview_vue_vue_type_script_setup_true_lang_default from "./StoryResponsivePreview.vue_vue_type_script_setup_true_lang.js";
3
3
  /* empty css */
4
4
  //#region src/app/components/story/StoryResponsivePreview.vue
5
- var StoryResponsivePreview_default = /*#__PURE__*/ _plugin_vue_export_helper_default(StoryResponsivePreview_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-a99edb14"]]);
5
+ var StoryResponsivePreview_default = /*#__PURE__*/ _plugin_vue_export_helper_default(StoryResponsivePreview_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-bbd56e9f"]]);
6
6
  //#endregion
7
7
  export { StoryResponsivePreview_default as default };
@@ -1,3 +1,4 @@
1
+ import { usePreviewDark } from "../../util/color-scheme.js";
1
2
  import { usePreviewSettingsStore } from "../../stores/preview-settings.js";
2
3
  import CheckerboardPattern_default from "../misc/CheckerboardPattern.js";
3
4
  import HatchedPattern_default from "../misc/HatchedPattern.js";
@@ -23,9 +24,10 @@ var StoryResponsivePreview_vue_vue_type_script_setup_true_lang_default = /*@__PU
23
24
  }
24
25
  },
25
26
  setup(__props) {
26
- useCssVars((_ctx) => ({ "v4ce71e65": unref(settings).backgroundColor }));
27
+ useCssVars((_ctx) => ({ "v59fa22e6": unref(settings).backgroundColor }));
27
28
  const props = __props;
28
29
  const settings = usePreviewSettingsStore().currentSettings;
30
+ const previewDark = usePreviewDark(settings);
29
31
  const resizing = ref(false);
30
32
  const onUnmountedCleanupFns = [];
31
33
  onUnmounted(() => {
@@ -127,7 +129,7 @@ var StoryResponsivePreview_vue_vue_type_script_setup_true_lang_default = /*@__PU
127
129
  ref: previewWrapper,
128
130
  class: "h-full overflow-auto relative"
129
131
  }, [createElementVNode("div", { class: normalizeClass(["rounded-lg relative", [
130
- __props.responsive ? "bg-white dark:bg-gray-700" : "",
132
+ __props.responsive ? unref(previewDark) ? "bg-gray-700" : "bg-white" : "",
131
133
  isResponsiveEnabled.value ? {
132
134
  "w-fit": !!finalWidth.value,
133
135
  "h-fit": !!finalHeight.value,
@@ -145,7 +147,7 @@ var StoryResponsivePreview_vue_vue_type_script_setup_true_lang_default = /*@__PU
145
147
  finalWidth: finalWidth.value,
146
148
  finalHeight: finalHeight.value,
147
149
  resizing: resizing.value
148
- }, void 0, true)]), isResponsiveEnabled.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [_cache[1] || (_cache[1] = createStaticVNode("<div class=\"absolute top-5 left-8 h-2 w-px bg-gray-400/25\" data-v-a99edb14></div><div class=\"absolute top-5 right-8 h-2 w-px bg-gray-400/25\" data-v-a99edb14></div><div class=\"absolute bottom-5 left-8 h-2 w-px bg-gray-400/25\" data-v-a99edb14></div><div class=\"absolute bottom-5 right-8 h-2 w-px bg-gray-400/25\" data-v-a99edb14></div><div class=\"absolute left-5 top-8 w-2 h-px bg-gray-400/25\" data-v-a99edb14></div><div class=\"absolute left-5 bottom-8 w-2 h-px bg-gray-400/25\" data-v-a99edb14></div><div class=\"absolute right-5 top-8 w-2 h-px bg-gray-400/25\" data-v-a99edb14></div><div class=\"absolute right-5 bottom-8 w-2 h-px bg-gray-400/25\" data-v-a99edb14></div>", 8))], 64)) : createCommentVNode("", true)], 2)], 10, _hoisted_3), isResponsiveEnabled.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
150
+ }, void 0, true)]), isResponsiveEnabled.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [_cache[1] || (_cache[1] = createStaticVNode("<div class=\"absolute top-5 left-8 h-2 w-px bg-gray-400/25\" data-v-bbd56e9f></div><div class=\"absolute top-5 right-8 h-2 w-px bg-gray-400/25\" data-v-bbd56e9f></div><div class=\"absolute bottom-5 left-8 h-2 w-px bg-gray-400/25\" data-v-bbd56e9f></div><div class=\"absolute bottom-5 right-8 h-2 w-px bg-gray-400/25\" data-v-bbd56e9f></div><div class=\"absolute left-5 top-8 w-2 h-px bg-gray-400/25\" data-v-bbd56e9f></div><div class=\"absolute left-5 bottom-8 w-2 h-px bg-gray-400/25\" data-v-bbd56e9f></div><div class=\"absolute right-5 top-8 w-2 h-px bg-gray-400/25\" data-v-bbd56e9f></div><div class=\"absolute right-5 bottom-8 w-2 h-px bg-gray-400/25\" data-v-bbd56e9f></div>", 8))], 64)) : createCommentVNode("", true)], 2)], 10, _hoisted_3), isResponsiveEnabled.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
149
151
  createVNode(unref(HstTooltip), {
150
152
  content: sizeTooltip.value,
151
153
  side: "right"
@@ -2,6 +2,6 @@ import _plugin_vue_export_helper_default from "../../_virtual/_plugin-vue_export
2
2
  import StoryVariantGridItem_vue_vue_type_script_setup_true_lang_default from "./StoryVariantGridItem.vue_vue_type_script_setup_true_lang.js";
3
3
  /* empty css */
4
4
  //#region src/app/components/story/StoryVariantGridItem.vue
5
- var StoryVariantGridItem_default = /*#__PURE__*/ _plugin_vue_export_helper_default(StoryVariantGridItem_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-e0e9a8e1"]]);
5
+ var StoryVariantGridItem_default = /*#__PURE__*/ _plugin_vue_export_helper_default(StoryVariantGridItem_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-9a717688"]]);
6
6
  //#endregion
7
7
  export { StoryVariantGridItem_default as default };
@@ -35,8 +35,8 @@ var StoryVariantGridItem_vue_vue_type_script_setup_true_lang_default = /*@__PURE
35
35
  emits: { resize: (_width, _height) => true },
36
36
  setup(__props, { emit: __emit }) {
37
37
  useCssVars((_ctx) => ({
38
- "v2ce2d009": unref(variant).iconColor,
39
- "v4f3f7242": unref(settings).backgroundColor
38
+ "ff0ecc2c": unref(variant).iconColor,
39
+ "v59a40d7e": unref(settings).backgroundColor
40
40
  }));
41
41
  const props = __props;
42
42
  const emit = __emit;
@@ -104,7 +104,9 @@ var StoryVariantGridItem_vue_vue_type_script_setup_true_lang_default = /*@__PURE
104
104
  variant: unref(variant),
105
105
  story: __props.story
106
106
  }, null, 8, ["variant", "story"])])]), createElementVNode("div", {
107
- class: normalizeClass(["border bg-white dark:bg-gray-700 rounded flex-1 p-4 relative", {
107
+ class: normalizeClass(["border rounded flex-1 p-4 relative", {
108
+ "bg-gray-700": unref(previewDark),
109
+ "bg-white": !unref(previewDark),
108
110
  "border-gray-100 dark:border-gray-800": !unref(isActive),
109
111
  "border-primary-200 dark:border-primary-900": unref(isActive)
110
112
  }]),
@@ -59,7 +59,7 @@ var StoryVariantSinglePreviewRemote_vue_vue_type_script_setup_true_lang_default
59
59
  iframe.value?.contentWindow?.postMessage({
60
60
  type: STATE_SYNC,
61
61
  state: changes
62
- });
62
+ }, window.location.origin);
63
63
  }
64
64
  let bridge = createStateBridge(postState);
65
65
  function syncState() {
@@ -79,6 +79,7 @@ var StoryVariantSinglePreviewRemote_vue_vue_type_script_setup_true_lang_default
79
79
  }
80
80
  useEventListener(window, "message", (event) => {
81
81
  if (event.source !== iframe.value?.contentWindow) return;
82
+ if (event.origin !== window.location.origin) return;
82
83
  switch (event.data?.type) {
83
84
  case STATE_SYNC:
84
85
  if (!fromCurrentOccupant(event.data)) break;
@@ -193,7 +194,7 @@ var StoryVariantSinglePreviewRemote_vue_vue_type_script_setup_true_lang_default
193
194
  if (iframe.value?.contentWindow) iframe.value.contentWindow.postMessage({
194
195
  type: PREVIEW_SETTINGS_SYNC,
195
196
  settings: toRaw(settings)
196
- });
197
+ }, window.location.origin);
197
198
  }
198
199
  watch(() => settings, () => {
199
200
  syncSettings();
@@ -15,7 +15,6 @@ var DevOnlyToolbarOpenInEditor_vue_vue_type_script_setup_true_lang_default = /*@
15
15
  return openBlock(), createBlock(unref(HstTooltip), { content: __props.tooltip }, {
16
16
  default: withCtx(() => [createVNode(TopBarChipItem_default, {
17
17
  "aria-label": "Open story in editor",
18
- target: "_blank",
19
18
  class: "poveste-toolbar-open-in-editor",
20
19
  onClick: _cache[0] || (_cache[0] = ($event) => unref(openInEditor)(__props.file))
21
20
  }, {
@@ -7,11 +7,15 @@ import { iconCollections } from "./util/icons.generated.js";
7
7
  import { createApp, watch } from "@poveste/vendors/vue";
8
8
  import { addCollection } from "@poveste/vendors/iconify";
9
9
  import { createPinia } from "@poveste/vendors/pinia";
10
- import { generation } from "virtual:$poveste-stories";
10
+ import { generation, icons, onUpdate } from "virtual:$poveste-stories";
11
11
  import "virtual:$poveste-theme";
12
12
  //#region src/app/index.ts
13
13
  async function mountMainApp() {
14
14
  for (const collection of iconCollections) addCollection(collection);
15
+ for (const collection of icons) addCollection(collection);
16
+ onUpdate((_files, _tree, icons = []) => {
17
+ for (const collection of icons) addCollection(collection);
18
+ });
15
19
  watch(isDark, (dark) => {
16
20
  document.documentElement.style.colorScheme = dark ? "dark" : "light";
17
21
  }, { immediate: true });
@@ -17,6 +17,7 @@ import { createPinia } from "@poveste/vendors/pinia";
17
17
  import { files, onUpdate } from "virtual:$poveste-stories";
18
18
  import { parseQuery } from "@poveste/vendors/vue-router";
19
19
  import { reportStoryError } from "@poveste/shared";
20
+ import "virtual:$poveste-theme";
20
21
  //#region src/app/sandbox.ts
21
22
  var query = parseQuery(window.location.search);
22
23
  var storyId = ref(typeof query["storyId"] === "string" ? query["storyId"] : null);
@@ -56,6 +57,7 @@ watch(previewDark, (value) => {
56
57
  if (!el) continue;
57
58
  for (const className of previewDarkClasses()) el.classList.toggle(className, value);
58
59
  }
60
+ document.documentElement.classList.toggle("ptw-dark", value);
59
61
  }, { immediate: true });
60
62
  var reportedColorScheme = "";
61
63
  function reportColorScheme() {
@@ -0,0 +1,22 @@
1
+ import { occupant } from "./occupant.js";
2
+ import { reportStoryError, toStoryError } from "@poveste/shared";
3
+ import { clientSupportPlugins } from "virtual:$poveste-support-plugins-client";
4
+ //#region src/app/util/client-plugin.ts
5
+ async function loadClientPlugin(supportPluginId) {
6
+ const load = supportPluginId ? clientSupportPlugins[supportPluginId] : void 0;
7
+ if (!load) return;
8
+ try {
9
+ return await load();
10
+ } catch (error) {
11
+ const { message, stack } = toStoryError(error);
12
+ const reported = Object.assign(/* @__PURE__ */ new Error(`The story renderer failed to load, and it imports the setup file: ${message}`), { stack });
13
+ reportStoryError(reported, {
14
+ storyId: occupant.storyId ?? void 0,
15
+ variantId: occupant.variantId ?? void 0
16
+ });
17
+ console.error(error);
18
+ return;
19
+ }
20
+ }
21
+ //#endregion
22
+ export { loadClientPlugin };
@@ -0,0 +1,5 @@
1
+ import { componentDocs as componentDocs$1 } from "virtual:$poveste-component-docs";
2
+ //#region src/app/util/component-docs-data.ts
3
+ var componentDocs = componentDocs$1;
4
+ //#endregion
5
+ export { componentDocs };
@@ -0,0 +1,133 @@
1
+ import { onBeforeUnmount, ref, watch } from "@poveste/vendors/vue";
2
+ //#region src/app/util/component-docs.ts
3
+ function toEntries(result) {
4
+ return Object.entries(result.components).map(([file, { doc, error, name }]) => ({
5
+ file,
6
+ name: doc?.name ?? name ?? file.split("/").pop().replace(/(?:\.story)?\.[^.]+$/, ""),
7
+ ...doc ? { doc } : {},
8
+ ...error ? { error } : {}
9
+ }));
10
+ }
11
+ /**
12
+ * Only the sections a story's `autoDocs` names, in the table's own order. A component
13
+ * left with nothing to show is dropped; one that failed keeps its error (#1398).
14
+ */
15
+ function onlySections(entries, autoDocs) {
16
+ if (!Array.isArray(autoDocs)) return entries;
17
+ return entries.flatMap((entry) => {
18
+ if (!entry.doc) return [entry];
19
+ const doc = {
20
+ ...entry.doc,
21
+ props: autoDocs.includes("props") ? entry.doc.props : [],
22
+ slots: autoDocs.includes("slots") ? entry.doc.slots : [],
23
+ events: autoDocs.includes("events") ? entry.doc.events : []
24
+ };
25
+ return doc.props.length || doc.slots.length || doc.events.length ? [{
26
+ ...entry,
27
+ doc
28
+ }] : [];
29
+ });
30
+ }
31
+ /**
32
+ * A compound component's root first, `SelectRoot` before `SelectTrigger`, else the order
33
+ * they came in. A story rendering two families, such as a Select inside a Calendar, opens
34
+ * the root its own folder or file is named for: `Calendar/story/CalendarSelect.story.vue`
35
+ * opens `CalendarRoot`, not the `SelectRoot` it imported first.
36
+ */
37
+ function rootFirst(entries, storyFile) {
38
+ const roots = entries.filter((entry) => entry.name.endsWith("Root"));
39
+ const family = (entry) => entry.name.slice(0, -4);
40
+ const segments = storyFile?.split(/[\\/]/) ?? [];
41
+ const fileName = segments.at(-1) ?? "";
42
+ const root = roots.find((entry) => segments.slice(0, -1).includes(family(entry))) ?? roots.find((entry) => fileName.startsWith(family(entry))) ?? roots[0];
43
+ return root ? [root, ...entries.filter((entry) => entry !== root)] : entries;
44
+ }
45
+ /**
46
+ * The `v-model` a prop and its `update:` event make together, as a template writes it:
47
+ * `v-model` for `modelValue`, `v-model:open` for `open` (#1436). Asked with either name,
48
+ * so the two rows of a pair, one under Props and one under Events, carry the same mark.
49
+ */
50
+ function modelLabel(doc, name) {
51
+ const prop = name.startsWith("update:") ? name.slice(7) : name;
52
+ if (!(doc.props.some((candidate) => candidate.name === prop) && doc.events.some((event) => event.name === `update:${prop}`))) return;
53
+ return prop === "modelValue" ? "v-model" : `v-model:${prop}`;
54
+ }
55
+ function tagText(tags, name) {
56
+ const tag = tags.find((tag) => tag.name === name);
57
+ return tag ? tag.text ?? "" : void 0;
58
+ }
59
+ /** A `@see` or `@link` points somewhere only when it carries a URL. */
60
+ function tagHref(text) {
61
+ return /https?:\/\/\S+/.exec(text)?.[0];
62
+ }
63
+ /**
64
+ * The components a story imports, documented. In dev they are asked of the server
65
+ * when this is first used, which is what starts extraction at all (#1159); in a
66
+ * built book they come from what `poveste build` extracted.
67
+ */
68
+ function useComponentDocs(storyId) {
69
+ const components = ref();
70
+ const pending = ref(false);
71
+ const off = ref();
72
+ const hot = import.meta.hot;
73
+ if (!hot) {
74
+ watch(storyId, async (id, _, onCleanup) => {
75
+ let stale = false;
76
+ onCleanup(() => stale = true);
77
+ pending.value = true;
78
+ try {
79
+ const { componentDocs } = await import("./component-docs-data.js");
80
+ const loaders = id ? componentDocs[id] : void 0;
81
+ const docs = loaders && Object.fromEntries(await Promise.all(Object.entries(loaders).map(async ([file, load]) => [file, (await load()).default])));
82
+ if (!stale) components.value = id && docs ? toEntries({
83
+ storyId: id,
84
+ components: docs
85
+ }) : void 0;
86
+ } catch (error) {
87
+ if (!stale) {
88
+ components.value = void 0;
89
+ console.error("[poveste] could not load this story's component docs:", error);
90
+ }
91
+ } finally {
92
+ if (!stale) pending.value = false;
93
+ }
94
+ }, { immediate: true });
95
+ return {
96
+ components,
97
+ pending,
98
+ off
99
+ };
100
+ }
101
+ function ask() {
102
+ if (storyId.value) {
103
+ pending.value = true;
104
+ hot.send("poveste:docgen-request", { storyId: storyId.value });
105
+ }
106
+ }
107
+ function onResult(result) {
108
+ if (result.storyId === storyId.value) {
109
+ components.value = toEntries(result);
110
+ off.value = result.off;
111
+ pending.value = false;
112
+ }
113
+ }
114
+ hot.on("poveste:docgen-result", onResult);
115
+ hot.on("poveste:docgen-stale", ask);
116
+ onBeforeUnmount(() => {
117
+ hot.off("poveste:docgen-result", onResult);
118
+ hot.off("poveste:docgen-stale", ask);
119
+ });
120
+ watch(storyId, () => {
121
+ components.value = void 0;
122
+ off.value = void 0;
123
+ pending.value = false;
124
+ ask();
125
+ }, { immediate: true });
126
+ return {
127
+ components,
128
+ pending,
129
+ off
130
+ };
131
+ }
132
+ //#endregion
133
+ export { modelLabel, onlySections, rootFirst, tagHref, tagText, toEntries, useComponentDocs };
@@ -2,11 +2,13 @@ import { povesteConfig } from "./config.js";
2
2
  import { useDark, useToggle } from "@poveste/vendors/vue-use";
3
3
  import { watch } from "@poveste/vendors/vue";
4
4
  //#region src/app/util/dark.ts
5
+ var inSandbox = location.href.includes("__sandbox");
5
6
  var isDark = useDark({
6
7
  valueDark: "ptw-dark",
7
8
  ...povesteConfig.theme.defaultColorScheme ? { initialValue: povesteConfig.theme.defaultColorScheme } : {},
8
9
  storageKey: "poveste-color-scheme",
9
- storage: povesteConfig.theme.storeColorScheme ? localStorage : sessionStorage
10
+ storage: povesteConfig.theme.storeColorScheme ? localStorage : sessionStorage,
11
+ ...inSandbox ? { onChanged: () => {} } : {}
10
12
  });
11
13
  var toggleDark = useToggle(isDark);
12
14
  function applyDarkToControls() {
@@ -1,9 +1,11 @@
1
- import { clientSupportPlugins } from "virtual:$poveste-support-plugins-client";
2
1
  import { unindent } from "@poveste/shared";
2
+ import { clientSupportPlugins } from "virtual:$poveste-support-plugins-client";
3
3
  //#region src/app/util/docs.ts
4
4
  /** What the variant declares, or what its framework generates from it; `undefined` when neither has anything. */
5
5
  async function getDynamicSourceCode(variant, generate) {
6
- if (variant.source) return variant.source;
6
+ const source = variant.source;
7
+ if (typeof source === "function") return source(variant.state) || void 0;
8
+ if (source) return source;
7
9
  const sourceSlot = variant.slots?.().source;
8
10
  if (sourceSlot) {
9
11
  const source = sourceSlot()[0].children;
@@ -11,6 +13,14 @@ async function getDynamicSourceCode(variant, generate) {
11
13
  }
12
14
  return await generate?.(variant) || void 0;
13
15
  }
16
+ /**
17
+ * The grammar a story's source reads in: a Vue or Svelte story is HTML with script
18
+ * inside, and a Solid or React story file is TypeScript with JSX, which the HTML
19
+ * grammar left plain (#1521). A variant's own source follows its story's.
20
+ */
21
+ function sourceLang(story) {
22
+ return /\.[cm]?[jt]sx$/.test(story?.file?.filePath ?? "") ? "tsx" : "html";
23
+ }
14
24
  async function getStaticSourceCode(story) {
15
25
  const sourceLoader = story.file?.source;
16
26
  return sourceLoader ? (await sourceLoader()).default : void 0;
@@ -25,4 +35,4 @@ async function getSourceCode(story, variant) {
25
35
  return await getDynamicSourceCode(variant, generate) || getStaticSourceCode(story);
26
36
  }
27
37
  //#endregion
28
- export { getDynamicSourceCode, getSourceCode, getStaticSourceCode, loadGenerateSourceCode };
38
+ export { getDynamicSourceCode, getSourceCode, getStaticSourceCode, loadGenerateSourceCode, sourceLang };
@@ -17,7 +17,7 @@ var highlighterPromise;
17
17
  */
18
18
  function getHighlighter() {
19
19
  highlighterPromise ??= createHighlighterCore({
20
- langs: [import("shiki/langs/html.mjs"), import("shiki/langs/jsx.mjs")],
20
+ langs: [import("shiki/langs/html.mjs"), import("shiki/langs/tsx.mjs")],
21
21
  themes: [import("shiki/themes/github-light-high-contrast.mjs"), import("shiki/themes/github-dark.mjs")],
22
22
  engine: createOnigurumaEngine(import("shiki/wasm"))
23
23
  }).catch((e) => {