@pyreon/storybook 0.0.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.
- package/LICENSE +21 -0
- package/README.md +200 -0
- package/lib/analysis/index.js.html +5406 -0
- package/lib/analysis/preset.js.html +5406 -0
- package/lib/analysis/preview.js.html +5406 -0
- package/lib/index.js +49 -0
- package/lib/index.js.map +1 -0
- package/lib/preset.js +20 -0
- package/lib/preset.js.map +1 -0
- package/lib/preview.js +53 -0
- package/lib/preview.js.map +1 -0
- package/lib/types/index.d.ts +116 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/preset.d.ts +17 -0
- package/lib/types/preset.d.ts.map +1 -0
- package/lib/types/preset2.d.ts +19 -0
- package/lib/types/preset2.d.ts.map +1 -0
- package/lib/types/preview.d.ts +57 -0
- package/lib/types/preview.d.ts.map +1 -0
- package/lib/types/preview2.d.ts +45 -0
- package/lib/types/preview2.d.ts.map +1 -0
- package/package.json +59 -0
- package/src/index.ts +45 -0
- package/src/preset.ts +24 -0
- package/src/preview.ts +29 -0
- package/src/render.ts +75 -0
- package/src/tests/storybook.test.ts +413 -0
- package/src/types.ts +102 -0
package/lib/index.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Fragment, h, h as h$1 } from "@pyreon/core";
|
|
2
|
+
import { mount, mount as mount$1 } from "@pyreon/runtime-dom";
|
|
3
|
+
import { computed, effect, signal } from "@pyreon/reactivity";
|
|
4
|
+
|
|
5
|
+
//#region src/render.ts
|
|
6
|
+
/**
|
|
7
|
+
* State tracked per canvas element so we can clean up between renders.
|
|
8
|
+
*/
|
|
9
|
+
const canvasState = /* @__PURE__ */ new WeakMap();
|
|
10
|
+
/**
|
|
11
|
+
* Render a Pyreon story into a Storybook canvas element.
|
|
12
|
+
*
|
|
13
|
+
* This is the core integration point — Storybook calls this function
|
|
14
|
+
* every time a story needs to be displayed or re-rendered (e.g. when
|
|
15
|
+
* the user changes args via the Controls panel).
|
|
16
|
+
*
|
|
17
|
+
* It handles:
|
|
18
|
+
* 1. Cleaning up the previous mount (disposing effects, removing DOM)
|
|
19
|
+
* 2. Building the VNode from the story function or component + args
|
|
20
|
+
* 3. Mounting the new VNode into the canvas
|
|
21
|
+
*/
|
|
22
|
+
function renderToCanvas({ storyFn, showMain, showError }, canvasElement) {
|
|
23
|
+
const prevUnmount = canvasState.get(canvasElement);
|
|
24
|
+
if (prevUnmount) {
|
|
25
|
+
prevUnmount();
|
|
26
|
+
canvasState.delete(canvasElement);
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const unmount = mount$1(storyFn(), canvasElement);
|
|
30
|
+
canvasState.set(canvasElement, unmount);
|
|
31
|
+
showMain();
|
|
32
|
+
} catch (err) {
|
|
33
|
+
showError({
|
|
34
|
+
title: `Error rendering story`,
|
|
35
|
+
description: (err instanceof Error ? err : new Error(String(err))).message
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Default render implementation used when no custom `render` is provided.
|
|
41
|
+
* Simply calls `h(component, args)`.
|
|
42
|
+
*/
|
|
43
|
+
function defaultRender(component, args) {
|
|
44
|
+
return h$1(component, args);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
//#endregion
|
|
48
|
+
export { Fragment, computed, defaultRender, effect, h, mount, renderToCanvas, signal };
|
|
49
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["mount","h"],"sources":["../src/render.ts"],"sourcesContent":["import { h } from '@pyreon/core'\nimport type { ComponentFn, VNodeChild } from '@pyreon/core'\nimport { mount } from '@pyreon/runtime-dom'\n\n/**\n * State tracked per canvas element so we can clean up between renders.\n */\nconst canvasState = new WeakMap<HTMLElement, () => void>()\n\n/**\n * Render a Pyreon story into a Storybook canvas element.\n *\n * This is the core integration point — Storybook calls this function\n * every time a story needs to be displayed or re-rendered (e.g. when\n * the user changes args via the Controls panel).\n *\n * It handles:\n * 1. Cleaning up the previous mount (disposing effects, removing DOM)\n * 2. Building the VNode from the story function or component + args\n * 3. Mounting the new VNode into the canvas\n */\nexport function renderToCanvas(\n {\n storyFn,\n showMain,\n showError,\n }: {\n storyFn: () => VNodeChild\n storyContext: {\n component?: ComponentFn<any>\n args: Record<string, unknown>\n [key: string]: unknown\n }\n showMain: () => void\n showError: (error: { title: string; description: string }) => void\n forceRemount: boolean\n },\n canvasElement: HTMLElement,\n): void {\n // Always clean up the previous render\n const prevUnmount = canvasState.get(canvasElement)\n if (prevUnmount) {\n prevUnmount()\n canvasState.delete(canvasElement)\n }\n\n try {\n // Get the story result — either from a custom render function\n // or by calling the component with args\n const element = storyFn()\n\n // Mount the Pyreon VNode tree into the canvas\n const unmount = mount(element, canvasElement)\n canvasState.set(canvasElement, unmount)\n\n showMain()\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err))\n showError({\n title: `Error rendering story`,\n description: error.message,\n })\n }\n}\n\n/**\n * Default render implementation used when no custom `render` is provided.\n * Simply calls `h(component, args)`.\n */\nexport function defaultRender(\n component: ComponentFn<any>,\n args: Record<string, unknown>,\n): VNodeChild {\n return h(component, args)\n}\n"],"mappings":";;;;;;;;AAOA,MAAM,8BAAc,IAAI,SAAkC;;;;;;;;;;;;;AAc1D,SAAgB,eACd,EACE,SACA,UACA,aAYF,eACM;CAEN,MAAM,cAAc,YAAY,IAAI,cAAc;AAClD,KAAI,aAAa;AACf,eAAa;AACb,cAAY,OAAO,cAAc;;AAGnC,KAAI;EAMF,MAAM,UAAUA,QAHA,SAAS,EAGM,cAAc;AAC7C,cAAY,IAAI,eAAe,QAAQ;AAEvC,YAAU;UACH,KAAK;AAEZ,YAAU;GACR,OAAO;GACP,cAHY,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC,EAG5C;GACpB,CAAC;;;;;;;AAQN,SAAgB,cACd,WACA,MACY;AACZ,QAAOC,IAAE,WAAW,KAAK"}
|
package/lib/preset.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
|
|
3
|
+
//#region src/preset.ts
|
|
4
|
+
/**
|
|
5
|
+
* Storybook preset for @pyreon/storybook.
|
|
6
|
+
*
|
|
7
|
+
* This file is loaded by Storybook's server when the user sets
|
|
8
|
+
* `framework: "@pyreon/storybook"` in their `.storybook/main.ts`.
|
|
9
|
+
*
|
|
10
|
+
* It tells Storybook:
|
|
11
|
+
* - Which renderer to use (via the preview entry)
|
|
12
|
+
* - What framework name to report
|
|
13
|
+
*/
|
|
14
|
+
const addons = [];
|
|
15
|
+
const previewAnnotations = [join(__dirname, "preview")];
|
|
16
|
+
const core = { renderer: "@pyreon/storybook" };
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
19
|
+
export { addons, core, previewAnnotations };
|
|
20
|
+
//# sourceMappingURL=preset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preset.js","names":[],"sources":["../src/preset.ts"],"sourcesContent":["/**\n * Storybook preset for @pyreon/storybook.\n *\n * This file is loaded by Storybook's server when the user sets\n * `framework: \"@pyreon/storybook\"` in their `.storybook/main.ts`.\n *\n * It tells Storybook:\n * - Which renderer to use (via the preview entry)\n * - What framework name to report\n */\n\nimport { dirname, join } from 'node:path'\n\nfunction _getAbsolutePath(value: string): string {\n return dirname(require.resolve(join(value, 'package.json')))\n}\n\nexport const addons: string[] = []\n\nexport const previewAnnotations: string[] = [join(__dirname, 'preview')]\n\nexport const core = {\n renderer: '@pyreon/storybook',\n}\n"],"mappings":";;;;;;;;;;;;;AAiBA,MAAa,SAAmB,EAAE;AAElC,MAAa,qBAA+B,CAAC,KAAK,WAAW,UAAU,CAAC;AAExE,MAAa,OAAO,EAClB,UAAU,qBACX"}
|
package/lib/preview.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { h } from "@pyreon/core";
|
|
2
|
+
import { mount } from "@pyreon/runtime-dom";
|
|
3
|
+
|
|
4
|
+
//#region src/render.ts
|
|
5
|
+
/**
|
|
6
|
+
* State tracked per canvas element so we can clean up between renders.
|
|
7
|
+
*/
|
|
8
|
+
const canvasState = /* @__PURE__ */ new WeakMap();
|
|
9
|
+
/**
|
|
10
|
+
* Render a Pyreon story into a Storybook canvas element.
|
|
11
|
+
*
|
|
12
|
+
* This is the core integration point — Storybook calls this function
|
|
13
|
+
* every time a story needs to be displayed or re-rendered (e.g. when
|
|
14
|
+
* the user changes args via the Controls panel).
|
|
15
|
+
*
|
|
16
|
+
* It handles:
|
|
17
|
+
* 1. Cleaning up the previous mount (disposing effects, removing DOM)
|
|
18
|
+
* 2. Building the VNode from the story function or component + args
|
|
19
|
+
* 3. Mounting the new VNode into the canvas
|
|
20
|
+
*/
|
|
21
|
+
function renderToCanvas({ storyFn, showMain, showError }, canvasElement) {
|
|
22
|
+
const prevUnmount = canvasState.get(canvasElement);
|
|
23
|
+
if (prevUnmount) {
|
|
24
|
+
prevUnmount();
|
|
25
|
+
canvasState.delete(canvasElement);
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const unmount = mount(storyFn(), canvasElement);
|
|
29
|
+
canvasState.set(canvasElement, unmount);
|
|
30
|
+
showMain();
|
|
31
|
+
} catch (err) {
|
|
32
|
+
showError({
|
|
33
|
+
title: `Error rendering story`,
|
|
34
|
+
description: (err instanceof Error ? err : new Error(String(err))).message
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
40
|
+
//#region src/preview.ts
|
|
41
|
+
/**
|
|
42
|
+
* Default render function — if the story CSF has a `component` but no
|
|
43
|
+
* explicit `render`, this is used to create the VNode.
|
|
44
|
+
*/
|
|
45
|
+
function render(args, context) {
|
|
46
|
+
const Component = context.component;
|
|
47
|
+
if (!Component) throw new Error("[@pyreon/storybook] No component provided. Either set `component` in your meta or provide a `render` function.");
|
|
48
|
+
return h(Component, args);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
//#endregion
|
|
52
|
+
export { render, renderToCanvas };
|
|
53
|
+
//# sourceMappingURL=preview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview.js","names":[],"sources":["../src/render.ts","../src/preview.ts"],"sourcesContent":["import { h } from '@pyreon/core'\nimport type { ComponentFn, VNodeChild } from '@pyreon/core'\nimport { mount } from '@pyreon/runtime-dom'\n\n/**\n * State tracked per canvas element so we can clean up between renders.\n */\nconst canvasState = new WeakMap<HTMLElement, () => void>()\n\n/**\n * Render a Pyreon story into a Storybook canvas element.\n *\n * This is the core integration point — Storybook calls this function\n * every time a story needs to be displayed or re-rendered (e.g. when\n * the user changes args via the Controls panel).\n *\n * It handles:\n * 1. Cleaning up the previous mount (disposing effects, removing DOM)\n * 2. Building the VNode from the story function or component + args\n * 3. Mounting the new VNode into the canvas\n */\nexport function renderToCanvas(\n {\n storyFn,\n showMain,\n showError,\n }: {\n storyFn: () => VNodeChild\n storyContext: {\n component?: ComponentFn<any>\n args: Record<string, unknown>\n [key: string]: unknown\n }\n showMain: () => void\n showError: (error: { title: string; description: string }) => void\n forceRemount: boolean\n },\n canvasElement: HTMLElement,\n): void {\n // Always clean up the previous render\n const prevUnmount = canvasState.get(canvasElement)\n if (prevUnmount) {\n prevUnmount()\n canvasState.delete(canvasElement)\n }\n\n try {\n // Get the story result — either from a custom render function\n // or by calling the component with args\n const element = storyFn()\n\n // Mount the Pyreon VNode tree into the canvas\n const unmount = mount(element, canvasElement)\n canvasState.set(canvasElement, unmount)\n\n showMain()\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err))\n showError({\n title: `Error rendering story`,\n description: error.message,\n })\n }\n}\n\n/**\n * Default render implementation used when no custom `render` is provided.\n * Simply calls `h(component, args)`.\n */\nexport function defaultRender(\n component: ComponentFn<any>,\n args: Record<string, unknown>,\n): VNodeChild {\n return h(component, args)\n}\n","import { h } from '@pyreon/core'\nimport type { ComponentFn, VNodeChild } from '@pyreon/core'\nimport { renderToCanvas } from './render'\n\n/**\n * Preview entry — Storybook loads this in the preview iframe.\n *\n * Exports the render function and default decorators/parameters\n * that apply to all stories using this renderer.\n */\n\nexport { renderToCanvas }\n\n/**\n * Default render function — if the story CSF has a `component` but no\n * explicit `render`, this is used to create the VNode.\n */\nexport function render<TArgs extends Record<string, unknown>>(\n args: TArgs,\n context: { component?: ComponentFn<any> },\n): VNodeChild {\n const Component = context.component\n if (!Component) {\n throw new Error(\n '[@pyreon/storybook] No component provided. Either set `component` in your meta or provide a `render` function.',\n )\n }\n return h(Component, args)\n}\n"],"mappings":";;;;;;;AAOA,MAAM,8BAAc,IAAI,SAAkC;;;;;;;;;;;;;AAc1D,SAAgB,eACd,EACE,SACA,UACA,aAYF,eACM;CAEN,MAAM,cAAc,YAAY,IAAI,cAAc;AAClD,KAAI,aAAa;AACf,eAAa;AACb,cAAY,OAAO,cAAc;;AAGnC,KAAI;EAMF,MAAM,UAAU,MAHA,SAAS,EAGM,cAAc;AAC7C,cAAY,IAAI,eAAe,QAAQ;AAEvC,YAAU;UACH,KAAK;AAEZ,YAAU;GACR,OAAO;GACP,cAHY,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC,EAG5C;GACpB,CAAC;;;;;;;;;;AC5CN,SAAgB,OACd,MACA,SACY;CACZ,MAAM,YAAY,QAAQ;AAC1B,KAAI,CAAC,UACH,OAAM,IAAI,MACR,iHACD;AAEH,QAAO,EAAE,WAAW,KAAK"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { ComponentFn, ComponentFn as ComponentFn$1, Fragment, Props, Props as Props$1, VNode, VNodeChild, VNodeChild as VNodeChild$1, h } from "@pyreon/core";
|
|
2
|
+
import { mount } from "@pyreon/runtime-dom";
|
|
3
|
+
import { computed, effect, signal } from "@pyreon/reactivity";
|
|
4
|
+
|
|
5
|
+
//#region src/types.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* The Pyreon renderer descriptor used by Storybook internally.
|
|
8
|
+
* This tells Storybook what our "component" and "storyResult" types are.
|
|
9
|
+
*/
|
|
10
|
+
interface PyreonRenderer {
|
|
11
|
+
component: ComponentFn$1<any>;
|
|
12
|
+
storyResult: VNodeChild$1;
|
|
13
|
+
canvasElement: HTMLElement;
|
|
14
|
+
}
|
|
15
|
+
/** Extract props type from a Pyreon component function. */
|
|
16
|
+
type InferProps<T> = T extends ComponentFn$1<infer P> ? P : Props$1;
|
|
17
|
+
interface StoryContext<TArgs = Props$1> {
|
|
18
|
+
args: TArgs;
|
|
19
|
+
argTypes: Record<string, unknown>;
|
|
20
|
+
globals: Record<string, unknown>;
|
|
21
|
+
id: string;
|
|
22
|
+
kind: string;
|
|
23
|
+
name: string;
|
|
24
|
+
viewMode: 'story' | 'docs';
|
|
25
|
+
}
|
|
26
|
+
type StoryFn<TArgs = Props$1> = (args: TArgs, context: StoryContext<TArgs>) => VNodeChild$1;
|
|
27
|
+
type DecoratorFn<TArgs = Props$1> = (storyFn: StoryFn<TArgs>, context: StoryContext<TArgs>) => VNodeChild$1;
|
|
28
|
+
interface Meta<TComponent extends ComponentFn$1<any> = ComponentFn$1> {
|
|
29
|
+
/** The component to document. */
|
|
30
|
+
component?: TComponent;
|
|
31
|
+
/** Display title in the sidebar. */
|
|
32
|
+
title?: string;
|
|
33
|
+
/** Decorators applied to every story in this file. */
|
|
34
|
+
decorators?: DecoratorFn<InferProps<TComponent>>[];
|
|
35
|
+
/** Default args for all stories. */
|
|
36
|
+
args?: Partial<InferProps<TComponent>>;
|
|
37
|
+
/** Arg type definitions for Controls panel. */
|
|
38
|
+
argTypes?: Record<string, unknown>;
|
|
39
|
+
/** Story parameters (backgrounds, viewport, etc.). */
|
|
40
|
+
parameters?: Record<string, unknown>;
|
|
41
|
+
/** Tags for filtering (e.g. "autodocs"). */
|
|
42
|
+
tags?: string[];
|
|
43
|
+
/**
|
|
44
|
+
* Default render function. If omitted, the component is called
|
|
45
|
+
* with args as props: `h(component, args)`.
|
|
46
|
+
*/
|
|
47
|
+
render?: (args: InferProps<TComponent>, context: StoryContext<InferProps<TComponent>>) => VNodeChild$1;
|
|
48
|
+
/** Exclude arg names from Controls. */
|
|
49
|
+
excludeStories?: string | string[] | RegExp;
|
|
50
|
+
/** Include only these story names. */
|
|
51
|
+
includeStories?: string | string[] | RegExp;
|
|
52
|
+
}
|
|
53
|
+
interface StoryObj<TMeta extends Meta<any> = Meta> {
|
|
54
|
+
/** Args for this specific story (merged with meta.args). */
|
|
55
|
+
args?: Partial<MetaArgs<TMeta>>;
|
|
56
|
+
/** Arg type overrides. */
|
|
57
|
+
argTypes?: Record<string, unknown>;
|
|
58
|
+
/** Decorators for this story only. */
|
|
59
|
+
decorators?: DecoratorFn<MetaArgs<TMeta>>[];
|
|
60
|
+
/** Parameters for this story. */
|
|
61
|
+
parameters?: Record<string, unknown>;
|
|
62
|
+
/** Tags for this story. */
|
|
63
|
+
tags?: string[];
|
|
64
|
+
/** Override the render function for this story. */
|
|
65
|
+
render?: (args: MetaArgs<TMeta>, context: StoryContext<MetaArgs<TMeta>>) => VNodeChild$1;
|
|
66
|
+
/** Story name override. */
|
|
67
|
+
name?: string;
|
|
68
|
+
/** Play function for interaction tests. */
|
|
69
|
+
play?: (context: {
|
|
70
|
+
canvasElement: HTMLElement;
|
|
71
|
+
args: MetaArgs<TMeta>;
|
|
72
|
+
step: (name: string, fn: () => Promise<void>) => Promise<void>;
|
|
73
|
+
}) => Promise<void> | void;
|
|
74
|
+
}
|
|
75
|
+
/** Extract the args type from a Meta definition. */
|
|
76
|
+
type MetaArgs<TMeta> = TMeta extends Meta<infer C> ? InferProps<C> : Props$1;
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/render.d.ts
|
|
79
|
+
/**
|
|
80
|
+
* Render a Pyreon story into a Storybook canvas element.
|
|
81
|
+
*
|
|
82
|
+
* This is the core integration point — Storybook calls this function
|
|
83
|
+
* every time a story needs to be displayed or re-rendered (e.g. when
|
|
84
|
+
* the user changes args via the Controls panel).
|
|
85
|
+
*
|
|
86
|
+
* It handles:
|
|
87
|
+
* 1. Cleaning up the previous mount (disposing effects, removing DOM)
|
|
88
|
+
* 2. Building the VNode from the story function or component + args
|
|
89
|
+
* 3. Mounting the new VNode into the canvas
|
|
90
|
+
*/
|
|
91
|
+
declare function renderToCanvas({
|
|
92
|
+
storyFn,
|
|
93
|
+
showMain,
|
|
94
|
+
showError
|
|
95
|
+
}: {
|
|
96
|
+
storyFn: () => VNodeChild$1;
|
|
97
|
+
storyContext: {
|
|
98
|
+
component?: ComponentFn$1<any>;
|
|
99
|
+
args: Record<string, unknown>;
|
|
100
|
+
[key: string]: unknown;
|
|
101
|
+
};
|
|
102
|
+
showMain: () => void;
|
|
103
|
+
showError: (error: {
|
|
104
|
+
title: string;
|
|
105
|
+
description: string;
|
|
106
|
+
}) => void;
|
|
107
|
+
forceRemount: boolean;
|
|
108
|
+
}, canvasElement: HTMLElement): void;
|
|
109
|
+
/**
|
|
110
|
+
* Default render implementation used when no custom `render` is provided.
|
|
111
|
+
* Simply calls `h(component, args)`.
|
|
112
|
+
*/
|
|
113
|
+
declare function defaultRender(component: ComponentFn$1<any>, args: Record<string, unknown>): VNodeChild$1;
|
|
114
|
+
//#endregion
|
|
115
|
+
export { type ComponentFn, type DecoratorFn, Fragment, type InferProps, type Meta, type Props, type PyreonRenderer, type StoryContext, type StoryFn, type StoryObj, type VNode, type VNodeChild, computed, defaultRender, effect, h, mount, renderToCanvas, signal };
|
|
116
|
+
//# sourceMappingURL=index2.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index2.d.ts","names":[],"sources":["../../src/types.ts","../../src/render.ts"],"mappings":";;;;;;;;;UAQiB,cAAA;EACf,SAAA,EAAW,aAAA;EACX,WAAA,EAAa,YAAA;EACb,aAAA,EAAe,WAAA;AAAA;;KAML,UAAA,MAAgB,CAAA,SAAU,aAAA,YAAuB,CAAA,GAAI,OAAA;AAAA,UAIhD,YAAA,SAAqB,OAAA;EACpC,IAAA,EAAM,KAAA;EACN,QAAA,EAAU,MAAA;EACV,OAAA,EAAS,MAAA;EACT,EAAA;EACA,IAAA;EACA,IAAA;EACA,QAAA;AAAA;AAAA,KAGU,OAAA,SAAgB,OAAA,KAC1B,IAAA,EAAM,KAAA,EACN,OAAA,EAAS,YAAA,CAAa,KAAA,MACnB,YAAA;AAAA,KAEO,WAAA,SAAoB,OAAA,KAC9B,OAAA,EAAS,OAAA,CAAQ,KAAA,GACjB,OAAA,EAAS,YAAA,CAAa,KAAA,MACnB,YAAA;AAAA,UAIY,IAAA,oBAAwB,aAAA,QAAmB,aAAA;EA1BhC;EA4B1B,SAAA,GAAY,UAAA;EA5BmD;EA8B/D,KAAA;EA9BoE;EAgCpE,UAAA,GAAa,WAAA,CAAY,UAAA,CAAW,UAAA;EAhCV;EAkC1B,IAAA,GAAO,OAAA,CAAQ,UAAA,CAAW,UAAA;EAlC4B;EAoCtD,QAAA,GAAW,MAAA;EApCoD;EAsC/D,UAAA,GAAa,MAAA;EAtCuD;EAwCpE,IAAA;EApC2B;;;;EAyC3B,MAAA,IACE,IAAA,EAAM,UAAA,CAAW,UAAA,GACjB,OAAA,EAAS,YAAA,CAAa,UAAA,CAAW,UAAA,OAC9B,YAAA;EAzCI;EA2CT,cAAA,uBAAqC,MAAA;EA3CtB;EA6Cf,cAAA,uBAAqC,MAAA;AAAA;AAAA,UAKtB,QAAA,eAAuB,IAAA,QAAY,IAAA;EApD5C;EAsDN,IAAA,GAAO,OAAA,CAAQ,QAAA,CAAS,KAAA;EArDd;EAuDV,QAAA,GAAW,MAAA;EAtDF;EAwDT,UAAA,GAAa,WAAA,CAAY,QAAA,CAAS,KAAA;EAtDlC;EAwDA,UAAA,GAAa,MAAA;EAtDb;EAwDA,IAAA;EAxDQ;EA0DR,MAAA,IACE,IAAA,EAAM,QAAA,CAAS,KAAA,GACf,OAAA,EAAS,YAAA,CAAa,QAAA,CAAS,KAAA,OAC5B,YAAA;EA1DY;EA4DjB,IAAA;EA5D0B;EA8D1B,IAAA,IAAQ,OAAA;IACN,aAAA,EAAe,WAAA;IACf,IAAA,EAAM,QAAA,CAAS,KAAA;IACf,IAAA,GAAO,IAAA,UAAc,EAAA,QAAU,OAAA,WAAkB,OAAA;EAAA,MAC7C,OAAA;AAAA;;KAIH,QAAA,UAAkB,KAAA,SAAc,IAAA,YAAgB,UAAA,CAAW,CAAA,IAAK,OAAA;;;;;;;AA7FrE;;;;;;;;iBCagB,cAAA,CAAA;EAEZ,OAAA;EACA,QAAA;EACA;AAAA;EAEA,OAAA,QAAe,YAAA;EACf,YAAA;IACE,SAAA,GAAY,aAAA;IACZ,IAAA,EAAM,MAAA;IAAA,CACL,GAAA;EAAA;EAEH,QAAA;EACA,SAAA,GAAY,KAAA;IAAS,KAAA;IAAe,WAAA;EAAA;EACpC,YAAA;AAAA,GAEF,aAAA,EAAe,WAAA;;;;;iBAgCD,aAAA,CACd,SAAA,EAAW,aAAA,OACX,IAAA,EAAM,MAAA,oBACL,YAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
|
|
3
|
+
//#region src/preset.ts
|
|
4
|
+
/**
|
|
5
|
+
* Storybook preset for @pyreon/storybook.
|
|
6
|
+
*
|
|
7
|
+
* This file is loaded by Storybook's server when the user sets
|
|
8
|
+
* `framework: "@pyreon/storybook"` in their `.storybook/main.ts`.
|
|
9
|
+
*
|
|
10
|
+
* It tells Storybook:
|
|
11
|
+
* - Which renderer to use (via the preview entry)
|
|
12
|
+
* - What framework name to report
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
//#endregion
|
|
16
|
+
export { addons, core, previewAnnotations };
|
|
17
|
+
//# sourceMappingURL=preset.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preset.d.ts","names":[],"sources":["../../src/preset.ts"],"mappings":""}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/preset.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Storybook preset for @pyreon/storybook.
|
|
4
|
+
*
|
|
5
|
+
* This file is loaded by Storybook's server when the user sets
|
|
6
|
+
* `framework: "@pyreon/storybook"` in their `.storybook/main.ts`.
|
|
7
|
+
*
|
|
8
|
+
* It tells Storybook:
|
|
9
|
+
* - Which renderer to use (via the preview entry)
|
|
10
|
+
* - What framework name to report
|
|
11
|
+
*/
|
|
12
|
+
declare const addons: string[];
|
|
13
|
+
declare const previewAnnotations: string[];
|
|
14
|
+
declare const core: {
|
|
15
|
+
renderer: string;
|
|
16
|
+
};
|
|
17
|
+
//#endregion
|
|
18
|
+
export { addons, core, previewAnnotations };
|
|
19
|
+
//# sourceMappingURL=preset2.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preset2.d.ts","names":[],"sources":["../../src/preset.ts"],"mappings":";;AAiBA;;;;;AAEA;;;;cAFa,MAAA;AAAA,cAEA,kBAAA;AAAA,cAEA,IAAA;EAEZ,QAAA;AAAA"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { h } from "@pyreon/core";
|
|
2
|
+
import { mount } from "@pyreon/runtime-dom";
|
|
3
|
+
|
|
4
|
+
//#region src/render.ts
|
|
5
|
+
/**
|
|
6
|
+
* State tracked per canvas element so we can clean up between renders.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Render a Pyreon story into a Storybook canvas element.
|
|
11
|
+
*
|
|
12
|
+
* This is the core integration point — Storybook calls this function
|
|
13
|
+
* every time a story needs to be displayed or re-rendered (e.g. when
|
|
14
|
+
* the user changes args via the Controls panel).
|
|
15
|
+
*
|
|
16
|
+
* It handles:
|
|
17
|
+
* 1. Cleaning up the previous mount (disposing effects, removing DOM)
|
|
18
|
+
* 2. Building the VNode from the story function or component + args
|
|
19
|
+
* 3. Mounting the new VNode into the canvas
|
|
20
|
+
*/
|
|
21
|
+
function renderToCanvas({
|
|
22
|
+
storyFn,
|
|
23
|
+
showMain,
|
|
24
|
+
showError
|
|
25
|
+
}, canvasElement) {
|
|
26
|
+
const prevUnmount = canvasState.get(canvasElement);
|
|
27
|
+
if (prevUnmount) {
|
|
28
|
+
prevUnmount();
|
|
29
|
+
canvasState.delete(canvasElement);
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const unmount = mount(storyFn(), canvasElement);
|
|
33
|
+
canvasState.set(canvasElement, unmount);
|
|
34
|
+
showMain();
|
|
35
|
+
} catch (err) {
|
|
36
|
+
showError({
|
|
37
|
+
title: `Error rendering story`,
|
|
38
|
+
description: (err instanceof Error ? err : new Error(String(err))).message
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/preview.ts
|
|
45
|
+
/**
|
|
46
|
+
* Default render function — if the story CSF has a `component` but no
|
|
47
|
+
* explicit `render`, this is used to create the VNode.
|
|
48
|
+
*/
|
|
49
|
+
function render(args, context) {
|
|
50
|
+
const Component = context.component;
|
|
51
|
+
if (!Component) throw new Error("[@pyreon/storybook] No component provided. Either set `component` in your meta or provide a `render` function.");
|
|
52
|
+
return h(Component, args);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
//#endregion
|
|
56
|
+
export { render, renderToCanvas };
|
|
57
|
+
//# sourceMappingURL=preview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview.d.ts","names":[],"sources":["../../src/render.ts","../../src/preview.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,cAAA,CACd;EACE,OAAA;EACA,QAAA;EACA;AAAA,CAAA,EAYF,aAAA,EACM;EAEN,MAAM,WAAA,GAAc,WAAA,CAAY,GAAA,CAAI,aAAA,CAAc;EAClD,IAAI,WAAA,EAAa;IACf,WAAA,CAAA,CAAa;IACb,WAAA,CAAY,MAAA,CAAO,aAAA,CAAc;;EAGnC,IAAI;IAMF,MAAM,OAAA,GAAU,KAAA,CAHA,OAAA,CAAA,CAAS,EAGM,aAAA,CAAc;IAC7C,WAAA,CAAY,GAAA,CAAI,aAAA,EAAe,OAAA,CAAQ;IAEvC,QAAA,CAAA,CAAU;WACH,GAAA,EAAK;IAEZ,SAAA,CAAU;MACR,KAAA,EAAO,uBAAA;MACP,WAAA,EAAA,CAHY,GAAA,YAAe,KAAA,GAAQ,GAAA,GAAM,IAAI,KAAA,CAAM,MAAA,CAAO,GAAA,CAAI,CAAC,EAG5C;KACpB,CAAC;;;;;;;;;;AC5CN,SAAgB,MAAA,CACd,IAAA,EACA,OAAA,EACY;EACZ,MAAM,SAAA,GAAY,OAAA,CAAQ,SAAA;EAC1B,IAAI,CAAC,SAAA,EACH,MAAM,IAAI,KAAA,CACR,gHAAA,CACD;EAEH,OAAO,CAAA,CAAE,SAAA,EAAW,IAAA,CAAK"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ComponentFn, VNodeChild } from "@pyreon/core";
|
|
2
|
+
|
|
3
|
+
//#region src/render.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Render a Pyreon story into a Storybook canvas element.
|
|
6
|
+
*
|
|
7
|
+
* This is the core integration point — Storybook calls this function
|
|
8
|
+
* every time a story needs to be displayed or re-rendered (e.g. when
|
|
9
|
+
* the user changes args via the Controls panel).
|
|
10
|
+
*
|
|
11
|
+
* It handles:
|
|
12
|
+
* 1. Cleaning up the previous mount (disposing effects, removing DOM)
|
|
13
|
+
* 2. Building the VNode from the story function or component + args
|
|
14
|
+
* 3. Mounting the new VNode into the canvas
|
|
15
|
+
*/
|
|
16
|
+
declare function renderToCanvas({
|
|
17
|
+
storyFn,
|
|
18
|
+
showMain,
|
|
19
|
+
showError
|
|
20
|
+
}: {
|
|
21
|
+
storyFn: () => VNodeChild;
|
|
22
|
+
storyContext: {
|
|
23
|
+
component?: ComponentFn<any>;
|
|
24
|
+
args: Record<string, unknown>;
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
};
|
|
27
|
+
showMain: () => void;
|
|
28
|
+
showError: (error: {
|
|
29
|
+
title: string;
|
|
30
|
+
description: string;
|
|
31
|
+
}) => void;
|
|
32
|
+
forceRemount: boolean;
|
|
33
|
+
}, canvasElement: HTMLElement): void;
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/preview.d.ts
|
|
36
|
+
/**
|
|
37
|
+
* Default render function — if the story CSF has a `component` but no
|
|
38
|
+
* explicit `render`, this is used to create the VNode.
|
|
39
|
+
*/
|
|
40
|
+
declare function render<TArgs extends Record<string, unknown>>(args: TArgs, context: {
|
|
41
|
+
component?: ComponentFn<any>;
|
|
42
|
+
}): VNodeChild;
|
|
43
|
+
//#endregion
|
|
44
|
+
export { render, renderToCanvas };
|
|
45
|
+
//# sourceMappingURL=preview2.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview2.d.ts","names":[],"sources":["../../src/render.ts","../../src/preview.ts"],"mappings":";;;;;AAqBA;;;;;;;;;;iBAAgB,cAAA,CAAA;EAEZ,OAAA;EACA,QAAA;EACA;AAAA;EAEA,OAAA,QAAe,UAAA;EACf,YAAA;IACE,SAAA,GAAY,WAAA;IACZ,IAAA,EAAM,MAAA;IAAA,CACL,GAAA;EAAA;EAEH,QAAA;EACA,SAAA,GAAY,KAAA;IAAS,KAAA;IAAe,WAAA;EAAA;EACpC,YAAA;AAAA,GAEF,aAAA,EAAe,WAAA;;;;;;;iBCpBD,MAAA,eAAqB,MAAA,kBAAA,CACnC,IAAA,EAAM,KAAA,EACN,OAAA;EAAW,SAAA,GAAY,WAAA;AAAA,IACtB,UAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pyreon/storybook",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Storybook renderer for Pyreon — mount, render, and interact with Pyreon components in Storybook",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/pyreon/fundamentals.git",
|
|
9
|
+
"directory": "packages/storybook"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/pyreon/fundamentals/tree/main/packages/storybook#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/pyreon/fundamentals/issues"
|
|
14
|
+
},
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"lib",
|
|
20
|
+
"src",
|
|
21
|
+
"README.md",
|
|
22
|
+
"LICENSE"
|
|
23
|
+
],
|
|
24
|
+
"type": "module",
|
|
25
|
+
"sideEffects": false,
|
|
26
|
+
"main": "./lib/index.js",
|
|
27
|
+
"module": "./lib/index.js",
|
|
28
|
+
"types": "./lib/types/index.d.ts",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"bun": "./src/index.ts",
|
|
32
|
+
"import": "./lib/index.js",
|
|
33
|
+
"types": "./lib/types/index.d.ts"
|
|
34
|
+
},
|
|
35
|
+
"./preset": {
|
|
36
|
+
"bun": "./src/preset.ts",
|
|
37
|
+
"import": "./lib/preset.js",
|
|
38
|
+
"types": "./lib/types/preset.d.ts"
|
|
39
|
+
},
|
|
40
|
+
"./preview": {
|
|
41
|
+
"bun": "./src/preview.ts",
|
|
42
|
+
"import": "./lib/preview.js",
|
|
43
|
+
"types": "./lib/types/preview.d.ts"
|
|
44
|
+
},
|
|
45
|
+
"./package.json": "./package.json"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "vl_rolldown_build",
|
|
49
|
+
"dev": "vl_rolldown_build-watch",
|
|
50
|
+
"test": "vitest run",
|
|
51
|
+
"typecheck": "tsc --noEmit"
|
|
52
|
+
},
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"@pyreon/core": "^0.2.1",
|
|
55
|
+
"@pyreon/reactivity": "^0.2.1",
|
|
56
|
+
"@pyreon/runtime-dom": "^0.2.1",
|
|
57
|
+
"storybook": ">=8.0.0"
|
|
58
|
+
}
|
|
59
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pyreon/storybook — Storybook renderer for Pyreon components.
|
|
3
|
+
*
|
|
4
|
+
* Usage in .storybook/main.ts:
|
|
5
|
+
* framework: "@pyreon/storybook"
|
|
6
|
+
*
|
|
7
|
+
* Usage in stories:
|
|
8
|
+
* import type { Meta, StoryObj } from "@pyreon/storybook"
|
|
9
|
+
* import { Button } from "./Button"
|
|
10
|
+
*
|
|
11
|
+
* const meta = {
|
|
12
|
+
* component: Button,
|
|
13
|
+
* args: { label: "Click me" },
|
|
14
|
+
* } satisfies Meta<typeof Button>
|
|
15
|
+
*
|
|
16
|
+
* export default meta
|
|
17
|
+
* type Story = StoryObj<typeof meta>
|
|
18
|
+
*
|
|
19
|
+
* export const Primary: Story = {
|
|
20
|
+
* args: { variant: "primary" },
|
|
21
|
+
* }
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
export type {
|
|
27
|
+
DecoratorFn,
|
|
28
|
+
InferProps,
|
|
29
|
+
Meta,
|
|
30
|
+
PyreonRenderer,
|
|
31
|
+
StoryContext,
|
|
32
|
+
StoryFn,
|
|
33
|
+
StoryObj,
|
|
34
|
+
} from './types'
|
|
35
|
+
|
|
36
|
+
// ─── Renderer ────────────────────────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
export { renderToCanvas, defaultRender } from './render'
|
|
39
|
+
|
|
40
|
+
// ─── Pyreon re-exports for convenience ───────────────────────────────────────
|
|
41
|
+
|
|
42
|
+
export { h, Fragment } from '@pyreon/core'
|
|
43
|
+
export type { ComponentFn, Props, VNode, VNodeChild } from '@pyreon/core'
|
|
44
|
+
export { signal, computed, effect } from '@pyreon/reactivity'
|
|
45
|
+
export { mount } from '@pyreon/runtime-dom'
|
package/src/preset.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storybook preset for @pyreon/storybook.
|
|
3
|
+
*
|
|
4
|
+
* This file is loaded by Storybook's server when the user sets
|
|
5
|
+
* `framework: "@pyreon/storybook"` in their `.storybook/main.ts`.
|
|
6
|
+
*
|
|
7
|
+
* It tells Storybook:
|
|
8
|
+
* - Which renderer to use (via the preview entry)
|
|
9
|
+
* - What framework name to report
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { dirname, join } from 'node:path'
|
|
13
|
+
|
|
14
|
+
function _getAbsolutePath(value: string): string {
|
|
15
|
+
return dirname(require.resolve(join(value, 'package.json')))
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const addons: string[] = []
|
|
19
|
+
|
|
20
|
+
export const previewAnnotations: string[] = [join(__dirname, 'preview')]
|
|
21
|
+
|
|
22
|
+
export const core = {
|
|
23
|
+
renderer: '@pyreon/storybook',
|
|
24
|
+
}
|
package/src/preview.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { h } from '@pyreon/core'
|
|
2
|
+
import type { ComponentFn, VNodeChild } from '@pyreon/core'
|
|
3
|
+
import { renderToCanvas } from './render'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Preview entry — Storybook loads this in the preview iframe.
|
|
7
|
+
*
|
|
8
|
+
* Exports the render function and default decorators/parameters
|
|
9
|
+
* that apply to all stories using this renderer.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export { renderToCanvas }
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Default render function — if the story CSF has a `component` but no
|
|
16
|
+
* explicit `render`, this is used to create the VNode.
|
|
17
|
+
*/
|
|
18
|
+
export function render<TArgs extends Record<string, unknown>>(
|
|
19
|
+
args: TArgs,
|
|
20
|
+
context: { component?: ComponentFn<any> },
|
|
21
|
+
): VNodeChild {
|
|
22
|
+
const Component = context.component
|
|
23
|
+
if (!Component) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
'[@pyreon/storybook] No component provided. Either set `component` in your meta or provide a `render` function.',
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
return h(Component, args)
|
|
29
|
+
}
|
package/src/render.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { h } from '@pyreon/core'
|
|
2
|
+
import type { ComponentFn, VNodeChild } from '@pyreon/core'
|
|
3
|
+
import { mount } from '@pyreon/runtime-dom'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* State tracked per canvas element so we can clean up between renders.
|
|
7
|
+
*/
|
|
8
|
+
const canvasState = new WeakMap<HTMLElement, () => void>()
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Render a Pyreon story into a Storybook canvas element.
|
|
12
|
+
*
|
|
13
|
+
* This is the core integration point — Storybook calls this function
|
|
14
|
+
* every time a story needs to be displayed or re-rendered (e.g. when
|
|
15
|
+
* the user changes args via the Controls panel).
|
|
16
|
+
*
|
|
17
|
+
* It handles:
|
|
18
|
+
* 1. Cleaning up the previous mount (disposing effects, removing DOM)
|
|
19
|
+
* 2. Building the VNode from the story function or component + args
|
|
20
|
+
* 3. Mounting the new VNode into the canvas
|
|
21
|
+
*/
|
|
22
|
+
export function renderToCanvas(
|
|
23
|
+
{
|
|
24
|
+
storyFn,
|
|
25
|
+
showMain,
|
|
26
|
+
showError,
|
|
27
|
+
}: {
|
|
28
|
+
storyFn: () => VNodeChild
|
|
29
|
+
storyContext: {
|
|
30
|
+
component?: ComponentFn<any>
|
|
31
|
+
args: Record<string, unknown>
|
|
32
|
+
[key: string]: unknown
|
|
33
|
+
}
|
|
34
|
+
showMain: () => void
|
|
35
|
+
showError: (error: { title: string; description: string }) => void
|
|
36
|
+
forceRemount: boolean
|
|
37
|
+
},
|
|
38
|
+
canvasElement: HTMLElement,
|
|
39
|
+
): void {
|
|
40
|
+
// Always clean up the previous render
|
|
41
|
+
const prevUnmount = canvasState.get(canvasElement)
|
|
42
|
+
if (prevUnmount) {
|
|
43
|
+
prevUnmount()
|
|
44
|
+
canvasState.delete(canvasElement)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
// Get the story result — either from a custom render function
|
|
49
|
+
// or by calling the component with args
|
|
50
|
+
const element = storyFn()
|
|
51
|
+
|
|
52
|
+
// Mount the Pyreon VNode tree into the canvas
|
|
53
|
+
const unmount = mount(element, canvasElement)
|
|
54
|
+
canvasState.set(canvasElement, unmount)
|
|
55
|
+
|
|
56
|
+
showMain()
|
|
57
|
+
} catch (err) {
|
|
58
|
+
const error = err instanceof Error ? err : new Error(String(err))
|
|
59
|
+
showError({
|
|
60
|
+
title: `Error rendering story`,
|
|
61
|
+
description: error.message,
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Default render implementation used when no custom `render` is provided.
|
|
68
|
+
* Simply calls `h(component, args)`.
|
|
69
|
+
*/
|
|
70
|
+
export function defaultRender(
|
|
71
|
+
component: ComponentFn<any>,
|
|
72
|
+
args: Record<string, unknown>,
|
|
73
|
+
): VNodeChild {
|
|
74
|
+
return h(component, args)
|
|
75
|
+
}
|