@poveste/app 0.17.0 → 0.17.1

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.
@@ -150,7 +150,7 @@ from {
150
150
  }
151
151
  }
152
152
  @scope (:root) to (.__poveste-render-story:not(.__poveste-render-custom-controls)) {
153
- .__poveste-code-placeholder[data-v-e112aa54] {
153
+ .__poveste-code-placeholder[data-v-ed711d57] {
154
154
  color: inherit;
155
155
  font-size: inherit;
156
156
  }
@@ -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-e112aa54"]]);
5
+ var StorySourceCode_default = /*#__PURE__*/ _plugin_vue_export_helper_default(StorySourceCode_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-ed711d57"]]);
6
6
  //#endregion
7
7
  export { StorySourceCode_default as default };
@@ -1,11 +1,10 @@
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
4
  import { getHighlighter } from "../../util/highlighter.js";
4
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";
5
6
  import { Icon } from "@poveste/vendors/iconify";
6
7
  import { HstCopyIcon, HstTooltip } from "@poveste/controls";
7
- import { clientSupportPlugins } from "virtual:$poveste-support-plugins-client";
8
- import { unindent } from "@poveste/shared";
9
8
  //#region src/app/components/panel/StorySourceCode.vue?vue&type=script&setup=true&lang.ts
10
9
  var _hoisted_1 = { class: "poveste-story-source-code bg-gray-50 dark:bg-gray-750 h-full overflow-hidden flex flex-col" };
11
10
  var _hoisted_2 = {
@@ -29,12 +28,8 @@ var StorySourceCode_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
29
28
  const props = __props;
30
29
  const generateSourceCodeFn = shallowRef(null);
31
30
  watchEffect(async () => {
32
- const supportPluginId = props.story.file?.supportPluginId;
33
- const clientPlugin = supportPluginId ? clientSupportPlugins[supportPluginId] : void 0;
34
- if (clientPlugin) {
35
- const pluginModule = await clientPlugin();
36
- generateSourceCodeFn.value = markRaw(pluginModule.generateSourceCode);
37
- }
31
+ const generate = await loadGenerateSourceCode(props.story);
32
+ if (generate) generateSourceCodeFn.value = markRaw(generate);
38
33
  });
39
34
  const highlighter = shallowRef();
40
35
  const dynamicSourceCode = ref("");
@@ -45,11 +40,7 @@ var StorySourceCode_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
45
40
  error.value = null;
46
41
  dynamicSourceCode.value = "";
47
42
  try {
48
- if (props.variant.source) dynamicSourceCode.value = props.variant.source;
49
- else if (props.variant.slots?.().source) {
50
- const source = props.variant.slots?.().source()[0].children;
51
- if (source) dynamicSourceCode.value = await unindent(source);
52
- } else dynamicSourceCode.value = await generateSourceCodeFn.value(props.variant);
43
+ dynamicSourceCode.value = await getDynamicSourceCode(props.variant, generateSourceCodeFn.value) ?? "";
53
44
  } catch (e) {
54
45
  console.error(e);
55
46
  error.value = e instanceof Error ? e.message : String(e);
@@ -62,8 +53,7 @@ var StorySourceCode_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/
62
53
  const staticSourceCode = ref("");
63
54
  watch(() => [props.story, props.story?.file?.source], async () => {
64
55
  staticSourceCode.value = "";
65
- const sourceLoader = props.story.file?.source;
66
- if (sourceLoader) staticSourceCode.value = (await sourceLoader()).default;
56
+ staticSourceCode.value = await getStaticSourceCode(props.story) ?? "";
67
57
  }, { immediate: true });
68
58
  const displayedSourceCode = computed(() => {
69
59
  if (displayedSource.value === "dynamic") return dynamicSourceCode.value;
@@ -1,18 +1,28 @@
1
1
  import { clientSupportPlugins } from "virtual:$poveste-support-plugins-client";
2
2
  import { unindent } from "@poveste/shared";
3
3
  //#region src/app/util/docs.ts
4
- async function getSourceCode(story, variant) {
4
+ /** What the variant declares, or what its framework generates from it; `undefined` when neither has anything. */
5
+ async function getDynamicSourceCode(variant, generate) {
5
6
  if (variant.source) return variant.source;
6
- else if (variant.slots?.().source) {
7
- const source = variant.slots?.().source()[0].children;
8
- if (source) return unindent(source);
9
- } else {
10
- const supportPluginId = story.file?.supportPluginId;
11
- const clientPlugin = supportPluginId ? clientSupportPlugins[supportPluginId] : void 0;
12
- if (clientPlugin) return (await clientPlugin()).generateSourceCode(variant);
7
+ const sourceSlot = variant.slots?.().source;
8
+ if (sourceSlot) {
9
+ const source = sourceSlot()[0].children;
10
+ return source ? unindent(source) : void 0;
13
11
  }
12
+ return await generate?.(variant) || void 0;
13
+ }
14
+ async function getStaticSourceCode(story) {
14
15
  const sourceLoader = story.file?.source;
15
- if (sourceLoader) return (await sourceLoader()).default;
16
+ return sourceLoader ? (await sourceLoader()).default : void 0;
17
+ }
18
+ async function loadGenerateSourceCode(story) {
19
+ const supportPluginId = story.file?.supportPluginId;
20
+ const clientPlugin = supportPluginId ? clientSupportPlugins[supportPluginId] : void 0;
21
+ return clientPlugin ? (await clientPlugin()).generateSourceCode : void 0;
22
+ }
23
+ async function getSourceCode(story, variant) {
24
+ const generate = async (v) => (await loadGenerateSourceCode(story))?.(v);
25
+ return await getDynamicSourceCode(variant, generate) || getStaticSourceCode(story);
16
26
  }
17
27
  //#endregion
18
- export { getSourceCode };
28
+ export { getDynamicSourceCode, getSourceCode, getStaticSourceCode, loadGenerateSourceCode };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@poveste/app",
3
3
  "type": "module",
4
- "version": "0.17.0",
4
+ "version": "0.17.1",
5
5
  "description": "Pre-bundled UI for Poveste",
6
6
  "author": {
7
7
  "name": "Sorin Gitlan",
@@ -34,9 +34,9 @@
34
34
  "node": ">=24.15.0"
35
35
  },
36
36
  "dependencies": {
37
- "@poveste/controls": "^0.17.0",
38
- "@poveste/shared": "^0.17.0",
39
- "@poveste/vendors": "^0.17.0",
37
+ "@poveste/controls": "^0.17.1",
38
+ "@poveste/shared": "^0.17.1",
39
+ "@poveste/vendors": "^0.17.1",
40
40
  "fuse.js": "^7.0.0",
41
41
  "shiki": "^4.4.3"
42
42
  },
@@ -0,0 +1,55 @@
1
+ import type { Story, Variant } from '../app/types'
2
+ import { describe, expect, it, vi } from 'vitest'
3
+ import { getSourceCode } from '../app/util/docs'
4
+
5
+ const plugin = vi.hoisted(() => ({ generateSourceCode: (() => undefined) as (variant: unknown) => unknown, loads: 0 }))
6
+
7
+ vi.mock('virtual:$poveste-support-plugins-client', () => ({
8
+ clientSupportPlugins: {
9
+ framework: async () => {
10
+ plugin.loads++
11
+ return { generateSourceCode: (variant: unknown) => plugin.generateSourceCode(variant) }
12
+ },
13
+ },
14
+ }))
15
+
16
+ const FILE = '<Story title="Grid" />'
17
+
18
+ function storyWithFile() {
19
+ return { file: { supportPluginId: 'framework', source: async () => ({ default: FILE }) } } as unknown as Story
20
+ }
21
+
22
+ describe('getSourceCode with a framework plugin', () => {
23
+ it('returns the story file when the plugin returns nothing synchronously, as plugin-svelte does', async () => {
24
+ plugin.generateSourceCode = () => undefined
25
+
26
+ const source = await getSourceCode(storyWithFile(), {} as Variant)
27
+
28
+ expect(source).toBe(FILE)
29
+ })
30
+
31
+ it('returns the story file when the plugin resolves to an empty string', async () => {
32
+ plugin.generateSourceCode = async () => ''
33
+
34
+ const source = await getSourceCode(storyWithFile(), {} as Variant)
35
+
36
+ expect(source).toBe(FILE)
37
+ })
38
+
39
+ it('prefers what the plugin generates', async () => {
40
+ plugin.generateSourceCode = async () => '<Button />'
41
+
42
+ const source = await getSourceCode(storyWithFile(), {} as Variant)
43
+
44
+ expect(source).toBe('<Button />')
45
+ })
46
+
47
+ it('returns a variant\'s declared source without loading the plugin', async () => {
48
+ plugin.loads = 0
49
+
50
+ const source = await getSourceCode(storyWithFile(), { source: '<Declared />' } as Variant)
51
+
52
+ expect(source).toBe('<Declared />')
53
+ expect(plugin.loads).toBe(0)
54
+ })
55
+ })
@@ -1,12 +1,12 @@
1
1
  <script lang="ts" setup>
2
2
  import type { HighlighterCore } from 'shiki/core'
3
3
  import type { Story, Variant } from '../../types'
4
+ import type { GenerateSourceCode } from '../../util/docs'
4
5
  import { Icon } from '@iconify/vue'
5
6
  import { HstCopyIcon, HstTooltip } from '@poveste/controls'
6
- import { unindent } from '@poveste/shared'
7
- import { clientSupportPlugins } from 'virtual:$poveste-support-plugins-client'
8
7
  import { computed, markRaw, nextTick, onMounted, ref, shallowRef, watch, watchEffect } from 'vue'
9
8
  import { isDark } from '../../util/dark'
9
+ import { getDynamicSourceCode, getStaticSourceCode, loadGenerateSourceCode } from '../../util/docs'
10
10
  import { getHighlighter } from '../../util/highlighter'
11
11
  import BaseEmpty from '../base/BaseEmpty.vue'
12
12
 
@@ -17,14 +17,12 @@ const props = defineProps<{
17
17
 
18
18
  // `ref(null)` infers `Ref<null>`, so the assignment below and the call further
19
19
  // down were both errors about a type nobody meant to declare.
20
- const generateSourceCodeFn = shallowRef<((variant: Variant) => Promise<string>) | null>(null)
20
+ const generateSourceCodeFn = shallowRef<GenerateSourceCode | null>(null)
21
21
 
22
22
  watchEffect(async () => {
23
- const supportPluginId = props.story.file?.supportPluginId
24
- const clientPlugin = supportPluginId ? clientSupportPlugins[supportPluginId] : undefined
25
- if (clientPlugin) {
26
- const pluginModule = await clientPlugin()
27
- generateSourceCodeFn.value = markRaw(pluginModule.generateSourceCode)
23
+ const generate = await loadGenerateSourceCode(props.story)
24
+ if (generate) {
25
+ generateSourceCodeFn.value = markRaw(generate)
28
26
  }
29
27
  })
30
28
 
@@ -43,18 +41,7 @@ watch(() => [props.variant, generateSourceCodeFn.value], async () => {
43
41
  error.value = null
44
42
  dynamicSourceCode.value = ''
45
43
  try {
46
- if (props.variant.source) {
47
- dynamicSourceCode.value = props.variant.source
48
- }
49
- else if (props.variant.slots?.().source) {
50
- const source = props.variant.slots?.().source()[0].children
51
- if (source) {
52
- dynamicSourceCode.value = await unindent(source)
53
- }
54
- }
55
- else {
56
- dynamicSourceCode.value = await generateSourceCodeFn.value(props.variant)
57
- }
44
+ dynamicSourceCode.value = (await getDynamicSourceCode(props.variant, generateSourceCodeFn.value)) ?? ''
58
45
  }
59
46
  catch (e) {
60
47
  console.error(e)
@@ -75,10 +62,7 @@ watch(() => [props.variant, generateSourceCodeFn.value], async () => {
75
62
  const staticSourceCode = ref('')
76
63
  watch(() => [props.story, props.story?.file?.source], async () => {
77
64
  staticSourceCode.value = ''
78
- const sourceLoader = props.story.file?.source
79
- if (sourceLoader) {
80
- staticSourceCode.value = (await sourceLoader()).default
81
- }
65
+ staticSourceCode.value = (await getStaticSourceCode(props.story)) ?? ''
82
66
  }, {
83
67
  immediate: true,
84
68
  })
@@ -5,6 +5,7 @@ export default {
5
5
  </script>
6
6
 
7
7
  <script lang="ts" setup>
8
+ import type { Component } from 'vue'
8
9
  import type { Story } from '../../types'
9
10
  import { clientSupportPlugins } from 'virtual:$poveste-support-plugins-client'
10
11
  import { markRaw, ref, watchEffect } from 'vue'
@@ -13,7 +14,7 @@ const props = defineProps<{
13
14
  story: Story
14
15
  }>()
15
16
 
16
- const mountComponent = ref(null)
17
+ const mountComponent = ref<Component | null>(null)
17
18
 
18
19
  watchEffect(async () => {
19
20
  const supportPluginId = props.story.file?.supportPluginId
@@ -5,6 +5,7 @@ export default {
5
5
  </script>
6
6
 
7
7
  <script lang="ts" setup>
8
+ import type { Component } from 'vue'
8
9
  import type { Story } from '../../types'
9
10
  import { clientSupportPlugins } from 'virtual:$poveste-support-plugins-client'
10
11
  import { markRaw, ref, watchEffect } from 'vue'
@@ -13,7 +14,7 @@ const props = defineProps<{
13
14
  story: Story
14
15
  }>()
15
16
 
16
- const mountComponent = ref(null)
17
+ const mountComponent = ref<Component | null>(null)
17
18
 
18
19
  watchEffect(async () => {
19
20
  const supportPluginId = props.story.file?.supportPluginId
@@ -1,28 +1,35 @@
1
+ import type { ClientSupportPlugin } from '@poveste/shared'
1
2
  import type { Story, Variant } from '../types'
2
3
  import { unindent } from '@poveste/shared'
3
4
  import { clientSupportPlugins } from 'virtual:$poveste-support-plugins-client'
4
5
 
5
- export async function getSourceCode(story: Story, variant: Variant) {
6
+ export type GenerateSourceCode = ClientSupportPlugin['generateSourceCode']
7
+
8
+ /** What the variant declares, or what its framework generates from it; `undefined` when neither has anything. */
9
+ export async function getDynamicSourceCode(variant: Variant, generate: GenerateSourceCode | undefined): Promise<string | undefined> {
6
10
  if (variant.source) {
7
11
  return variant.source
8
12
  }
9
- else if (variant.slots?.().source) {
10
- const source = variant.slots?.().source()[0].children
11
- if (source) {
12
- return unindent(source)
13
- }
14
- }
15
- else {
16
- const supportPluginId = story.file?.supportPluginId
17
- const clientPlugin = supportPluginId ? clientSupportPlugins[supportPluginId] : undefined
18
- if (clientPlugin) {
19
- const pluginModule = await clientPlugin()
20
- return pluginModule.generateSourceCode(variant)
21
- }
13
+ const sourceSlot = variant.slots?.().source
14
+ if (sourceSlot) {
15
+ const source = sourceSlot()[0].children
16
+ return source ? unindent(source) : undefined
22
17
  }
18
+ return (await generate?.(variant)) || undefined
19
+ }
23
20
 
21
+ export async function getStaticSourceCode(story: Story): Promise<string | undefined> {
24
22
  const sourceLoader = story.file?.source
25
- if (sourceLoader) {
26
- return (await sourceLoader()).default
27
- }
23
+ return sourceLoader ? (await sourceLoader()).default : undefined
24
+ }
25
+
26
+ export async function loadGenerateSourceCode(story: Story): Promise<GenerateSourceCode | undefined> {
27
+ const supportPluginId = story.file?.supportPluginId
28
+ const clientPlugin = supportPluginId ? clientSupportPlugins[supportPluginId] : undefined
29
+ return clientPlugin ? (await clientPlugin()).generateSourceCode : undefined
30
+ }
31
+
32
+ export async function getSourceCode(story: Story, variant: Variant): Promise<string | undefined> {
33
+ const generate: GenerateSourceCode = async v => (await loadGenerateSourceCode(story))?.(v)
34
+ return (await getDynamicSourceCode(variant, generate)) || getStaticSourceCode(story)
28
35
  }
package/src/virtual.d.ts CHANGED
@@ -4,4 +4,11 @@ declare module 'virtual:$poveste-commands' {
4
4
  export const registeredCommands: ClientCommand[]
5
5
  }
6
6
 
7
+ declare module 'virtual:$poveste-support-plugins-client' {
8
+ import type { ClientSupportPlugin } from '@poveste/shared'
9
+ import type { Component } from 'vue'
10
+
11
+ export const clientSupportPlugins: Record<string, () => Promise<ClientSupportPlugin<Component>>>
12
+ }
13
+
7
14
  declare module 'virtual:*';