@pyreon/storybook 0.2.0 → 0.6.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/lib/analysis/index.js.html +1 -1
- package/lib/analysis/preview.js.html +1 -1
- package/lib/index.js +52 -4
- package/lib/index.js.map +1 -1
- package/lib/preview.js +52 -4
- package/lib/preview.js.map +1 -1
- package/lib/types/index.d.ts +2 -3
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/preview.d.ts +56 -4
- package/lib/types/preview.d.ts.map +1 -1
- package/lib/types/preview2.d.ts +2 -2
- package/lib/types/preview2.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/index.ts +3 -3
- package/src/preview-impl.tsx +28 -0
- package/src/preview.ts +1 -29
- package/src/render-impl.tsx +69 -0
- package/src/render.ts +1 -75
- package/src/tests/{storybook.test.ts → storybook.test.tsx} +47 -47
|
@@ -5386,7 +5386,7 @@ var drawChart = (function (exports) {
|
|
|
5386
5386
|
</script>
|
|
5387
5387
|
<script>
|
|
5388
5388
|
/*<!--*/
|
|
5389
|
-
const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src","children":[{"uid":"
|
|
5389
|
+
const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"home/runner/work/fundamentals/fundamentals/node_modules/.bun/@pyreon+core@0.6.0/node_modules/@pyreon/core/lib/jsx-runtime.js","uid":"a15c263f-1"},{"name":"src","children":[{"uid":"a15c263f-3","name":"render-impl.tsx"},{"uid":"a15c263f-5","name":"index.ts"}]}]}],"isRoot":true},"nodeParts":{"a15c263f-1":{"renderedLength":1640,"gzipLength":827,"brotliLength":0,"metaUid":"a15c263f-0"},"a15c263f-3":{"renderedLength":1280,"gzipLength":673,"brotliLength":0,"metaUid":"a15c263f-2"},"a15c263f-5":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"a15c263f-4"}},"nodeMetas":{"a15c263f-0":{"id":"/home/runner/work/fundamentals/fundamentals/node_modules/.bun/@pyreon+core@0.6.0/node_modules/@pyreon/core/lib/jsx-runtime.js","moduleParts":{"index.js":"a15c263f-1"},"imported":[],"importedBy":[{"uid":"a15c263f-2"}]},"a15c263f-2":{"id":"/src/render-impl.tsx","moduleParts":{"index.js":"a15c263f-3"},"imported":[{"uid":"a15c263f-9"},{"uid":"a15c263f-0"}],"importedBy":[{"uid":"a15c263f-6"}]},"a15c263f-4":{"id":"/src/index.ts","moduleParts":{"index.js":"a15c263f-5"},"imported":[{"uid":"a15c263f-6"},{"uid":"a15c263f-7"},{"uid":"a15c263f-8"},{"uid":"a15c263f-9"}],"importedBy":[],"isEntry":true},"a15c263f-6":{"id":"/src/render.ts","moduleParts":{},"imported":[{"uid":"a15c263f-2"}],"importedBy":[{"uid":"a15c263f-4"}]},"a15c263f-7":{"id":"@pyreon/core","moduleParts":{},"imported":[],"importedBy":[{"uid":"a15c263f-4"}]},"a15c263f-8":{"id":"@pyreon/reactivity","moduleParts":{},"imported":[],"importedBy":[{"uid":"a15c263f-4"}]},"a15c263f-9":{"id":"@pyreon/runtime-dom","moduleParts":{},"imported":[],"importedBy":[{"uid":"a15c263f-4"},{"uid":"a15c263f-2"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
|
|
5390
5390
|
|
|
5391
5391
|
const run = () => {
|
|
5392
5392
|
const width = window.innerWidth;
|
|
@@ -5386,7 +5386,7 @@ var drawChart = (function (exports) {
|
|
|
5386
5386
|
</script>
|
|
5387
5387
|
<script>
|
|
5388
5388
|
/*<!--*/
|
|
5389
|
-
const data = {"version":2,"tree":{"name":"root","children":[{"name":"preview.js","children":[{"name":"src","children":[{"uid":"
|
|
5389
|
+
const data = {"version":2,"tree":{"name":"root","children":[{"name":"preview.js","children":[{"name":"home/runner/work/fundamentals/fundamentals/node_modules/.bun/@pyreon+core@0.6.0/node_modules/@pyreon/core/lib/jsx-runtime.js","uid":"3cdd8ae0-1"},{"name":"src","children":[{"uid":"3cdd8ae0-3","name":"render-impl.tsx"},{"uid":"3cdd8ae0-5","name":"preview-impl.tsx"},{"uid":"3cdd8ae0-7","name":"preview.ts"}]}]}],"isRoot":true},"nodeParts":{"3cdd8ae0-1":{"renderedLength":1634,"gzipLength":823,"brotliLength":0,"metaUid":"3cdd8ae0-0"},"3cdd8ae0-3":{"renderedLength":1100,"gzipLength":595,"brotliLength":0,"metaUid":"3cdd8ae0-2"},"3cdd8ae0-5":{"renderedLength":452,"gzipLength":313,"brotliLength":0,"metaUid":"3cdd8ae0-4"},"3cdd8ae0-7":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"3cdd8ae0-6"}},"nodeMetas":{"3cdd8ae0-0":{"id":"/home/runner/work/fundamentals/fundamentals/node_modules/.bun/@pyreon+core@0.6.0/node_modules/@pyreon/core/lib/jsx-runtime.js","moduleParts":{"preview.js":"3cdd8ae0-1"},"imported":[],"importedBy":[{"uid":"3cdd8ae0-4"},{"uid":"3cdd8ae0-2"}]},"3cdd8ae0-2":{"id":"/src/render-impl.tsx","moduleParts":{"preview.js":"3cdd8ae0-3"},"imported":[{"uid":"3cdd8ae0-8"},{"uid":"3cdd8ae0-0"}],"importedBy":[{"uid":"3cdd8ae0-4"}]},"3cdd8ae0-4":{"id":"/src/preview-impl.tsx","moduleParts":{"preview.js":"3cdd8ae0-5"},"imported":[{"uid":"3cdd8ae0-2"},{"uid":"3cdd8ae0-0"}],"importedBy":[{"uid":"3cdd8ae0-6"}]},"3cdd8ae0-6":{"id":"/src/preview.ts","moduleParts":{"preview.js":"3cdd8ae0-7"},"imported":[{"uid":"3cdd8ae0-4"}],"importedBy":[],"isEntry":true},"3cdd8ae0-8":{"id":"@pyreon/runtime-dom","moduleParts":{},"imported":[],"importedBy":[{"uid":"3cdd8ae0-2"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
|
|
5390
5390
|
|
|
5391
5391
|
const run = () => {
|
|
5392
5392
|
const width = window.innerWidth;
|
package/lib/index.js
CHANGED
|
@@ -1,8 +1,57 @@
|
|
|
1
|
-
import { Fragment, h, h as h$1 } from "@pyreon/core";
|
|
2
1
|
import { mount, mount as mount$1 } from "@pyreon/runtime-dom";
|
|
2
|
+
import { Fragment, h } from "@pyreon/core";
|
|
3
3
|
import { computed, effect, signal } from "@pyreon/reactivity";
|
|
4
4
|
|
|
5
|
-
//#region
|
|
5
|
+
//#region ../../node_modules/.bun/@pyreon+core@0.6.0/node_modules/@pyreon/core/lib/jsx-runtime.js
|
|
6
|
+
/**
|
|
7
|
+
* Hyperscript function — the compiled output of JSX.
|
|
8
|
+
* `<div class="x">hello</div>` → `h("div", { class: "x" }, "hello")`
|
|
9
|
+
*
|
|
10
|
+
* Generic on P so TypeScript validates props match the component's signature
|
|
11
|
+
* at the call site, then stores the result in the loosely-typed VNode.
|
|
12
|
+
*/
|
|
13
|
+
/** Shared empty props sentinel — identity-checked in mountElement to skip applyProps. */
|
|
14
|
+
const EMPTY_PROPS = {};
|
|
15
|
+
function h$1(type, props, ...children) {
|
|
16
|
+
return {
|
|
17
|
+
type,
|
|
18
|
+
props: props ?? EMPTY_PROPS,
|
|
19
|
+
children: normalizeChildren(children),
|
|
20
|
+
key: props?.key ?? null
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function normalizeChildren(children) {
|
|
24
|
+
for (let i = 0; i < children.length; i++) if (Array.isArray(children[i])) return flattenChildren(children);
|
|
25
|
+
return children;
|
|
26
|
+
}
|
|
27
|
+
function flattenChildren(children) {
|
|
28
|
+
const result = [];
|
|
29
|
+
for (const child of children) if (Array.isArray(child)) result.push(...flattenChildren(child));
|
|
30
|
+
else result.push(child);
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* JSX automatic runtime.
|
|
35
|
+
*
|
|
36
|
+
* When tsconfig has `"jsxImportSource": "@pyreon/core"`, the TS/bundler compiler
|
|
37
|
+
* rewrites JSX to imports from this file automatically:
|
|
38
|
+
* <div class="x" /> → jsx("div", { class: "x" })
|
|
39
|
+
*/
|
|
40
|
+
function jsx(type, props, key) {
|
|
41
|
+
const { children, ...rest } = props;
|
|
42
|
+
const propsWithKey = key != null ? {
|
|
43
|
+
...rest,
|
|
44
|
+
key
|
|
45
|
+
} : rest;
|
|
46
|
+
if (typeof type === "function") return h$1(type, children !== void 0 ? {
|
|
47
|
+
...propsWithKey,
|
|
48
|
+
children
|
|
49
|
+
} : propsWithKey);
|
|
50
|
+
return h$1(type, propsWithKey, ...children === void 0 ? [] : Array.isArray(children) ? children : [children]);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
//#endregion
|
|
54
|
+
//#region src/render-impl.tsx
|
|
6
55
|
/**
|
|
7
56
|
* State tracked per canvas element so we can clean up between renders.
|
|
8
57
|
*/
|
|
@@ -38,10 +87,9 @@ function renderToCanvas({ storyFn, showMain, showError }, canvasElement) {
|
|
|
38
87
|
}
|
|
39
88
|
/**
|
|
40
89
|
* Default render implementation used when no custom `render` is provided.
|
|
41
|
-
* Simply calls `h(component, args)`.
|
|
42
90
|
*/
|
|
43
91
|
function defaultRender(component, args) {
|
|
44
|
-
return
|
|
92
|
+
return /* @__PURE__ */ jsx(component, { ...args });
|
|
45
93
|
}
|
|
46
94
|
|
|
47
95
|
//#endregion
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["
|
|
1
|
+
{"version":3,"file":"index.js","names":["h","mount"],"sources":["../../../node_modules/.bun/@pyreon+core@0.6.0/node_modules/@pyreon/core/lib/jsx-runtime.js","../src/render-impl.tsx"],"sourcesContent":["//#region src/h.ts\n/** Marker for fragment nodes — renders children without a wrapper element */\nconst Fragment = Symbol(\"Pyreon.Fragment\");\n/**\n* Hyperscript function — the compiled output of JSX.\n* `<div class=\"x\">hello</div>` → `h(\"div\", { class: \"x\" }, \"hello\")`\n*\n* Generic on P so TypeScript validates props match the component's signature\n* at the call site, then stores the result in the loosely-typed VNode.\n*/\n/** Shared empty props sentinel — identity-checked in mountElement to skip applyProps. */\nconst EMPTY_PROPS = {};\nfunction h(type, props, ...children) {\n\treturn {\n\t\ttype,\n\t\tprops: props ?? EMPTY_PROPS,\n\t\tchildren: normalizeChildren(children),\n\t\tkey: props?.key ?? null\n\t};\n}\nfunction normalizeChildren(children) {\n\tfor (let i = 0; i < children.length; i++) if (Array.isArray(children[i])) return flattenChildren(children);\n\treturn children;\n}\nfunction flattenChildren(children) {\n\tconst result = [];\n\tfor (const child of children) if (Array.isArray(child)) result.push(...flattenChildren(child));\n\telse result.push(child);\n\treturn result;\n}\n\n//#endregion\n//#region src/jsx-runtime.ts\n/**\n* JSX automatic runtime.\n*\n* When tsconfig has `\"jsxImportSource\": \"@pyreon/core\"`, the TS/bundler compiler\n* rewrites JSX to imports from this file automatically:\n* <div class=\"x\" /> → jsx(\"div\", { class: \"x\" })\n*/\nfunction jsx(type, props, key) {\n\tconst { children, ...rest } = props;\n\tconst propsWithKey = key != null ? {\n\t\t...rest,\n\t\tkey\n\t} : rest;\n\tif (typeof type === \"function\") return h(type, children !== void 0 ? {\n\t\t...propsWithKey,\n\t\tchildren\n\t} : propsWithKey);\n\treturn h(type, propsWithKey, ...children === void 0 ? [] : Array.isArray(children) ? children : [children]);\n}\nconst jsxs = jsx;\n\n//#endregion\nexport { Fragment, jsx, jsxs };\n//# sourceMappingURL=jsx-runtime.js.map","import 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 const element = storyFn()\n const unmount = mount(element, canvasElement)\n canvasState.set(canvasElement, unmount)\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 */\nexport function defaultRender(\n component: ComponentFn<any>,\n args: Record<string, unknown>,\n): VNodeChild {\n const Component = component\n return <Component {...args} />\n}\n"],"x_google_ignoreList":[0],"mappings":";;;;;;;;;;;;;AAWA,MAAM,cAAc,EAAE;AACtB,SAASA,IAAE,MAAM,OAAO,GAAG,UAAU;AACpC,QAAO;EACN;EACA,OAAO,SAAS;EAChB,UAAU,kBAAkB,SAAS;EACrC,KAAK,OAAO,OAAO;EACnB;;AAEF,SAAS,kBAAkB,UAAU;AACpC,MAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,IAAK,KAAI,MAAM,QAAQ,SAAS,GAAG,CAAE,QAAO,gBAAgB,SAAS;AAC1G,QAAO;;AAER,SAAS,gBAAgB,UAAU;CAClC,MAAM,SAAS,EAAE;AACjB,MAAK,MAAM,SAAS,SAAU,KAAI,MAAM,QAAQ,MAAM,CAAE,QAAO,KAAK,GAAG,gBAAgB,MAAM,CAAC;KACzF,QAAO,KAAK,MAAM;AACvB,QAAO;;;;;;;;;AAYR,SAAS,IAAI,MAAM,OAAO,KAAK;CAC9B,MAAM,EAAE,UAAU,GAAG,SAAS;CAC9B,MAAM,eAAe,OAAO,OAAO;EAClC,GAAG;EACH;EACA,GAAG;AACJ,KAAI,OAAO,SAAS,WAAY,QAAOA,IAAE,MAAM,aAAa,KAAK,IAAI;EACpE,GAAG;EACH;EACA,GAAG,aAAa;AACjB,QAAOA,IAAE,MAAM,cAAc,GAAG,aAAa,KAAK,IAAI,EAAE,GAAG,MAAM,QAAQ,SAAS,GAAG,WAAW,CAAC,SAAS,CAAC;;;;;;;;AC5C5G,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;EAEF,MAAM,UAAUC,QADA,SAAS,EACM,cAAc;AAC7C,cAAY,IAAI,eAAe,QAAQ;AACvC,YAAU;UACH,KAAK;AAEZ,YAAU;GACR,OAAO;GACP,cAHY,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC,EAG5C;GACpB,CAAC;;;;;;AAON,SAAgB,cACd,WACA,MACY;AAEZ,QAAO,oBADW,WACX,EAAW,GAAI,MAAQ"}
|
package/lib/preview.js
CHANGED
|
@@ -1,7 +1,55 @@
|
|
|
1
|
-
import { h } from "@pyreon/core";
|
|
2
1
|
import { mount } from "@pyreon/runtime-dom";
|
|
3
2
|
|
|
4
|
-
//#region
|
|
3
|
+
//#region ../../node_modules/.bun/@pyreon+core@0.6.0/node_modules/@pyreon/core/lib/jsx-runtime.js
|
|
4
|
+
/**
|
|
5
|
+
* Hyperscript function — the compiled output of JSX.
|
|
6
|
+
* `<div class="x">hello</div>` → `h("div", { class: "x" }, "hello")`
|
|
7
|
+
*
|
|
8
|
+
* Generic on P so TypeScript validates props match the component's signature
|
|
9
|
+
* at the call site, then stores the result in the loosely-typed VNode.
|
|
10
|
+
*/
|
|
11
|
+
/** Shared empty props sentinel — identity-checked in mountElement to skip applyProps. */
|
|
12
|
+
const EMPTY_PROPS = {};
|
|
13
|
+
function h(type, props, ...children) {
|
|
14
|
+
return {
|
|
15
|
+
type,
|
|
16
|
+
props: props ?? EMPTY_PROPS,
|
|
17
|
+
children: normalizeChildren(children),
|
|
18
|
+
key: props?.key ?? null
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function normalizeChildren(children) {
|
|
22
|
+
for (let i = 0; i < children.length; i++) if (Array.isArray(children[i])) return flattenChildren(children);
|
|
23
|
+
return children;
|
|
24
|
+
}
|
|
25
|
+
function flattenChildren(children) {
|
|
26
|
+
const result = [];
|
|
27
|
+
for (const child of children) if (Array.isArray(child)) result.push(...flattenChildren(child));
|
|
28
|
+
else result.push(child);
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* JSX automatic runtime.
|
|
33
|
+
*
|
|
34
|
+
* When tsconfig has `"jsxImportSource": "@pyreon/core"`, the TS/bundler compiler
|
|
35
|
+
* rewrites JSX to imports from this file automatically:
|
|
36
|
+
* <div class="x" /> → jsx("div", { class: "x" })
|
|
37
|
+
*/
|
|
38
|
+
function jsx(type, props, key) {
|
|
39
|
+
const { children, ...rest } = props;
|
|
40
|
+
const propsWithKey = key != null ? {
|
|
41
|
+
...rest,
|
|
42
|
+
key
|
|
43
|
+
} : rest;
|
|
44
|
+
if (typeof type === "function") return h(type, children !== void 0 ? {
|
|
45
|
+
...propsWithKey,
|
|
46
|
+
children
|
|
47
|
+
} : propsWithKey);
|
|
48
|
+
return h(type, propsWithKey, ...children === void 0 ? [] : Array.isArray(children) ? children : [children]);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
//#endregion
|
|
52
|
+
//#region src/render-impl.tsx
|
|
5
53
|
/**
|
|
6
54
|
* State tracked per canvas element so we can clean up between renders.
|
|
7
55
|
*/
|
|
@@ -37,7 +85,7 @@ function renderToCanvas({ storyFn, showMain, showError }, canvasElement) {
|
|
|
37
85
|
}
|
|
38
86
|
|
|
39
87
|
//#endregion
|
|
40
|
-
//#region src/preview.
|
|
88
|
+
//#region src/preview-impl.tsx
|
|
41
89
|
/**
|
|
42
90
|
* Default render function — if the story CSF has a `component` but no
|
|
43
91
|
* explicit `render`, this is used to create the VNode.
|
|
@@ -45,7 +93,7 @@ function renderToCanvas({ storyFn, showMain, showError }, canvasElement) {
|
|
|
45
93
|
function render(args, context) {
|
|
46
94
|
const Component = context.component;
|
|
47
95
|
if (!Component) throw new Error("[@pyreon/storybook] No component provided. Either set `component` in your meta or provide a `render` function.");
|
|
48
|
-
return
|
|
96
|
+
return /* @__PURE__ */ jsx(Component, { ...args });
|
|
49
97
|
}
|
|
50
98
|
|
|
51
99
|
//#endregion
|
package/lib/preview.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preview.js","names":[],"sources":["../src/render.
|
|
1
|
+
{"version":3,"file":"preview.js","names":[],"sources":["../../../node_modules/.bun/@pyreon+core@0.6.0/node_modules/@pyreon/core/lib/jsx-runtime.js","../src/render-impl.tsx","../src/preview-impl.tsx"],"sourcesContent":["//#region src/h.ts\n/** Marker for fragment nodes — renders children without a wrapper element */\nconst Fragment = Symbol(\"Pyreon.Fragment\");\n/**\n* Hyperscript function — the compiled output of JSX.\n* `<div class=\"x\">hello</div>` → `h(\"div\", { class: \"x\" }, \"hello\")`\n*\n* Generic on P so TypeScript validates props match the component's signature\n* at the call site, then stores the result in the loosely-typed VNode.\n*/\n/** Shared empty props sentinel — identity-checked in mountElement to skip applyProps. */\nconst EMPTY_PROPS = {};\nfunction h(type, props, ...children) {\n\treturn {\n\t\ttype,\n\t\tprops: props ?? EMPTY_PROPS,\n\t\tchildren: normalizeChildren(children),\n\t\tkey: props?.key ?? null\n\t};\n}\nfunction normalizeChildren(children) {\n\tfor (let i = 0; i < children.length; i++) if (Array.isArray(children[i])) return flattenChildren(children);\n\treturn children;\n}\nfunction flattenChildren(children) {\n\tconst result = [];\n\tfor (const child of children) if (Array.isArray(child)) result.push(...flattenChildren(child));\n\telse result.push(child);\n\treturn result;\n}\n\n//#endregion\n//#region src/jsx-runtime.ts\n/**\n* JSX automatic runtime.\n*\n* When tsconfig has `\"jsxImportSource\": \"@pyreon/core\"`, the TS/bundler compiler\n* rewrites JSX to imports from this file automatically:\n* <div class=\"x\" /> → jsx(\"div\", { class: \"x\" })\n*/\nfunction jsx(type, props, key) {\n\tconst { children, ...rest } = props;\n\tconst propsWithKey = key != null ? {\n\t\t...rest,\n\t\tkey\n\t} : rest;\n\tif (typeof type === \"function\") return h(type, children !== void 0 ? {\n\t\t...propsWithKey,\n\t\tchildren\n\t} : propsWithKey);\n\treturn h(type, propsWithKey, ...children === void 0 ? [] : Array.isArray(children) ? children : [children]);\n}\nconst jsxs = jsx;\n\n//#endregion\nexport { Fragment, jsx, jsxs };\n//# sourceMappingURL=jsx-runtime.js.map","import 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 const element = storyFn()\n const unmount = mount(element, canvasElement)\n canvasState.set(canvasElement, unmount)\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 */\nexport function defaultRender(\n component: ComponentFn<any>,\n args: Record<string, unknown>,\n): VNodeChild {\n const Component = component\n return <Component {...args} />\n}\n","import type { ComponentFn, VNodeChild } from '@pyreon/core'\nimport { renderToCanvas } from './render-impl'\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 <Component {...args} />\n}\n"],"x_google_ignoreList":[0],"mappings":";;;;;;;;;;;AAWA,MAAM,cAAc,EAAE;AACtB,SAAS,EAAE,MAAM,OAAO,GAAG,UAAU;AACpC,QAAO;EACN;EACA,OAAO,SAAS;EAChB,UAAU,kBAAkB,SAAS;EACrC,KAAK,OAAO,OAAO;EACnB;;AAEF,SAAS,kBAAkB,UAAU;AACpC,MAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,IAAK,KAAI,MAAM,QAAQ,SAAS,GAAG,CAAE,QAAO,gBAAgB,SAAS;AAC1G,QAAO;;AAER,SAAS,gBAAgB,UAAU;CAClC,MAAM,SAAS,EAAE;AACjB,MAAK,MAAM,SAAS,SAAU,KAAI,MAAM,QAAQ,MAAM,CAAE,QAAO,KAAK,GAAG,gBAAgB,MAAM,CAAC;KACzF,QAAO,KAAK,MAAM;AACvB,QAAO;;;;;;;;;AAYR,SAAS,IAAI,MAAM,OAAO,KAAK;CAC9B,MAAM,EAAE,UAAU,GAAG,SAAS;CAC9B,MAAM,eAAe,OAAO,OAAO;EAClC,GAAG;EACH;EACA,GAAG;AACJ,KAAI,OAAO,SAAS,WAAY,QAAO,EAAE,MAAM,aAAa,KAAK,IAAI;EACpE,GAAG;EACH;EACA,GAAG,aAAa;AACjB,QAAO,EAAE,MAAM,cAAc,GAAG,aAAa,KAAK,IAAI,EAAE,GAAG,MAAM,QAAQ,SAAS,GAAG,WAAW,CAAC,SAAS,CAAC;;;;;;;;AC5C5G,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;EAEF,MAAM,UAAU,MADA,SAAS,EACM,cAAc;AAC7C,cAAY,IAAI,eAAe,QAAQ;AACvC,YAAU;UACH,KAAK;AAEZ,YAAU;GACR,OAAO;GACP,cAHY,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC,EAG5C;GACpB,CAAC;;;;;;;;;;ACvCN,SAAgB,OACd,MACA,SACY;CACZ,MAAM,YAAY,QAAQ;AAC1B,KAAI,CAAC,UACH,OAAM,IAAI,MACR,iHACD;AAEH,QAAO,oBAAC,WAAD,EAAW,GAAI,MAAQ"}
|
package/lib/types/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ComponentFn, ComponentFn as ComponentFn$1, Fragment, Props, Props as Props$1, VNode, VNodeChild, VNodeChild as VNodeChild$1, h } from "@pyreon/core";
|
|
2
1
|
import { mount } from "@pyreon/runtime-dom";
|
|
2
|
+
import { ComponentFn, ComponentFn as ComponentFn$1, Fragment, Props, Props as Props$1, VNode, VNodeChild, VNodeChild as VNodeChild$1, h } from "@pyreon/core";
|
|
3
3
|
import { computed, effect, signal } from "@pyreon/reactivity";
|
|
4
4
|
|
|
5
5
|
//#region src/types.d.ts
|
|
@@ -75,7 +75,7 @@ interface StoryObj<TMeta extends Meta<any> = Meta> {
|
|
|
75
75
|
/** Extract the args type from a Meta definition. */
|
|
76
76
|
type MetaArgs<TMeta> = TMeta extends Meta<infer C> ? InferProps<C> : Props$1;
|
|
77
77
|
//#endregion
|
|
78
|
-
//#region src/render.d.ts
|
|
78
|
+
//#region src/render-impl.d.ts
|
|
79
79
|
/**
|
|
80
80
|
* Render a Pyreon story into a Storybook canvas element.
|
|
81
81
|
*
|
|
@@ -108,7 +108,6 @@ declare function renderToCanvas({
|
|
|
108
108
|
}, canvasElement: HTMLElement): void;
|
|
109
109
|
/**
|
|
110
110
|
* Default render implementation used when no custom `render` is provided.
|
|
111
|
-
* Simply calls `h(component, args)`.
|
|
112
111
|
*/
|
|
113
112
|
declare function defaultRender(component: ComponentFn$1<any>, args: Record<string, unknown>): VNodeChild$1;
|
|
114
113
|
//#endregion
|
package/lib/types/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index2.d.ts","names":[],"sources":["../../src/types.ts","../../src/render.
|
|
1
|
+
{"version":3,"file":"index2.d.ts","names":[],"sources":["../../src/types.ts","../../src/render-impl.tsx"],"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;;;;;;;;iBCYgB,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;;;;iBA0BD,aAAA,CACd,SAAA,EAAW,aAAA,OACX,IAAA,EAAM,MAAA,oBACL,YAAA"}
|
package/lib/types/preview.d.ts
CHANGED
|
@@ -1,7 +1,57 @@
|
|
|
1
|
-
import { h } from "@pyreon/core";
|
|
2
1
|
import { mount } from "@pyreon/runtime-dom";
|
|
3
2
|
|
|
4
|
-
//#region
|
|
3
|
+
//#region ../../node_modules/.bun/@pyreon+core@0.6.0/node_modules/@pyreon/core/lib/jsx-runtime.js
|
|
4
|
+
/**
|
|
5
|
+
* Hyperscript function — the compiled output of JSX.
|
|
6
|
+
* `<div class="x">hello</div>` → `h("div", { class: "x" }, "hello")`
|
|
7
|
+
*
|
|
8
|
+
* Generic on P so TypeScript validates props match the component's signature
|
|
9
|
+
* at the call site, then stores the result in the loosely-typed VNode.
|
|
10
|
+
*/
|
|
11
|
+
/** Shared empty props sentinel — identity-checked in mountElement to skip applyProps. */
|
|
12
|
+
|
|
13
|
+
function h(type, props, ...children) {
|
|
14
|
+
return {
|
|
15
|
+
type,
|
|
16
|
+
props: props ?? EMPTY_PROPS,
|
|
17
|
+
children: normalizeChildren(children),
|
|
18
|
+
key: props?.key ?? null
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function normalizeChildren(children) {
|
|
22
|
+
for (let i = 0; i < children.length; i++) if (Array.isArray(children[i])) return flattenChildren(children);
|
|
23
|
+
return children;
|
|
24
|
+
}
|
|
25
|
+
function flattenChildren(children) {
|
|
26
|
+
const result = [];
|
|
27
|
+
for (const child of children) if (Array.isArray(child)) result.push(...flattenChildren(child));else result.push(child);
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* JSX automatic runtime.
|
|
32
|
+
*
|
|
33
|
+
* When tsconfig has `"jsxImportSource": "@pyreon/core"`, the TS/bundler compiler
|
|
34
|
+
* rewrites JSX to imports from this file automatically:
|
|
35
|
+
* <div class="x" /> → jsx("div", { class: "x" })
|
|
36
|
+
*/
|
|
37
|
+
function jsx(type, props, key) {
|
|
38
|
+
const {
|
|
39
|
+
children,
|
|
40
|
+
...rest
|
|
41
|
+
} = props;
|
|
42
|
+
const propsWithKey = key != null ? {
|
|
43
|
+
...rest,
|
|
44
|
+
key
|
|
45
|
+
} : rest;
|
|
46
|
+
if (typeof type === "function") return h(type, children !== void 0 ? {
|
|
47
|
+
...propsWithKey,
|
|
48
|
+
children
|
|
49
|
+
} : propsWithKey);
|
|
50
|
+
return h(type, propsWithKey, ...(children === void 0 ? [] : Array.isArray(children) ? children : [children]));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
//#endregion
|
|
54
|
+
//#region src/render-impl.tsx
|
|
5
55
|
/**
|
|
6
56
|
* State tracked per canvas element so we can clean up between renders.
|
|
7
57
|
*/
|
|
@@ -41,7 +91,7 @@ function renderToCanvas({
|
|
|
41
91
|
}
|
|
42
92
|
|
|
43
93
|
//#endregion
|
|
44
|
-
//#region src/preview.
|
|
94
|
+
//#region src/preview-impl.tsx
|
|
45
95
|
/**
|
|
46
96
|
* Default render function — if the story CSF has a `component` but no
|
|
47
97
|
* explicit `render`, this is used to create the VNode.
|
|
@@ -49,7 +99,9 @@ function renderToCanvas({
|
|
|
49
99
|
function render(args, context) {
|
|
50
100
|
const Component = context.component;
|
|
51
101
|
if (!Component) throw new Error("[@pyreon/storybook] No component provided. Either set `component` in your meta or provide a `render` function.");
|
|
52
|
-
return
|
|
102
|
+
return /* @__PURE__ */jsx(Component, {
|
|
103
|
+
...args
|
|
104
|
+
});
|
|
53
105
|
}
|
|
54
106
|
|
|
55
107
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preview.d.ts","names":[],"sources":["../../src/render.
|
|
1
|
+
{"version":3,"file":"preview.d.ts","names":[],"sources":["../../../../node_modules/.bun/@pyreon+core@0.6.0/node_modules/@pyreon/core/lib/jsx-runtime.js","../../src/render-impl.tsx","../../src/preview-impl.tsx"],"x_google_ignoreList":[0],"mappings":";;;;;;;;;;;;AAYA,SAAS,CAAA,CAAE,IAAA,EAAM,KAAA,EAAO,GAAG,QAAA,EAAU;EACpC,OAAO;IACN,IAAA;IACA,KAAA,EAAO,KAAA,IAAS,WAAA;IAChB,QAAA,EAAU,iBAAA,CAAkB,QAAA,CAAS;IACrC,GAAA,EAAK,KAAA,EAAO,GAAA,IAAO;GACnB;;AAEF,SAAS,iBAAA,CAAkB,QAAA,EAAU;EACpC,KAAK,IAAI,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,QAAA,CAAS,MAAA,EAAQ,CAAA,EAAA,EAAK,IAAI,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,CAAA,CAAA,CAAG,EAAE,OAAO,eAAA,CAAgB,QAAA,CAAS;EAC1G,OAAO,QAAA;;AAER,SAAS,eAAA,CAAgB,QAAA,EAAU;EAClC,MAAM,MAAA,GAAS,EAAE;EACjB,KAAK,MAAM,KAAA,IAAS,QAAA,EAAU,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAA,CAAM,EAAE,MAAA,CAAO,IAAA,CAAK,GAAG,eAAA,CAAgB,KAAA,CAAM,CAAC,CAAA,KACzF,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM;EACvB,OAAO,MAAA;;;;;;;;;AAYR,SAAS,GAAA,CAAI,IAAA,EAAM,KAAA,EAAO,GAAA,EAAK;EAC9B,MAAM;IAAE,QAAA;IAAU,GAAG;EAAA,CAAA,GAAS,KAAA;EAC9B,MAAM,YAAA,GAAe,GAAA,IAAO,IAAA,GAAO;IAClC,GAAG,IAAA;IACH;GACA,GAAG,IAAA;EACJ,IAAI,OAAO,IAAA,KAAS,UAAA,EAAY,OAAO,CAAA,CAAE,IAAA,EAAM,QAAA,KAAa,KAAK,CAAA,GAAI;IACpE,GAAG,YAAA;IACH;GACA,GAAG,YAAA,CAAa;EACjB,OAAO,CAAA,CAAE,IAAA,EAAM,YAAA,EAAc,IAAG,QAAA,KAAa,KAAK,CAAA,GAAI,EAAE,GAAG,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,GAAG,QAAA,GAAW,CAAC,QAAA,CAAS,EAAC;;;;;;;;;;;;;;;;;;;;;AC9B5G,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;IAEF,MAAM,OAAA,GAAU,KAAA,CADA,OAAA,CAAA,CAAS,EACM,aAAA,CAAc;IAC7C,WAAA,CAAY,GAAA,CAAI,aAAA,EAAe,OAAA,CAAQ;IACvC,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;;;;;;;;;;ACvCN,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,eAAA,GAAA,CAAC,SAAA,EAAD;IAAW,GAAI;EAAA,CAAQ,CAAA"}
|
package/lib/types/preview2.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ComponentFn, VNodeChild } from "@pyreon/core";
|
|
2
2
|
|
|
3
|
-
//#region src/render.d.ts
|
|
3
|
+
//#region src/render-impl.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Render a Pyreon story into a Storybook canvas element.
|
|
6
6
|
*
|
|
@@ -32,7 +32,7 @@ declare function renderToCanvas({
|
|
|
32
32
|
forceRemount: boolean;
|
|
33
33
|
}, canvasElement: HTMLElement): void;
|
|
34
34
|
//#endregion
|
|
35
|
-
//#region src/preview.d.ts
|
|
35
|
+
//#region src/preview-impl.d.ts
|
|
36
36
|
/**
|
|
37
37
|
* Default render function — if the story CSF has a `component` but no
|
|
38
38
|
* explicit `render`, this is used to create the VNode.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preview2.d.ts","names":[],"sources":["../../src/render.
|
|
1
|
+
{"version":3,"file":"preview2.d.ts","names":[],"sources":["../../src/render-impl.tsx","../../src/preview-impl.tsx"],"mappings":";;;;;AAoBA;;;;;;;;;;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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pyreon/storybook",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Storybook renderer for Pyreon — mount, render, and interact with Pyreon components in Storybook",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -51,9 +51,9 @@
|
|
|
51
51
|
"typecheck": "tsc --noEmit"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
|
-
"@pyreon/core": "
|
|
55
|
-
"@pyreon/reactivity": "
|
|
56
|
-
"@pyreon/runtime-dom": "
|
|
54
|
+
"@pyreon/core": ">=0.5.0 <1.0.0",
|
|
55
|
+
"@pyreon/reactivity": ">=0.5.0 <1.0.0",
|
|
56
|
+
"@pyreon/runtime-dom": ">=0.5.0 <1.0.0",
|
|
57
57
|
"storybook": ">=8.0.0"
|
|
58
58
|
}
|
|
59
59
|
}
|
package/src/index.ts
CHANGED
|
@@ -35,11 +35,11 @@ export type {
|
|
|
35
35
|
|
|
36
36
|
// ─── Renderer ────────────────────────────────────────────────────────────────
|
|
37
37
|
|
|
38
|
-
export {
|
|
38
|
+
export { defaultRender, renderToCanvas } from './render'
|
|
39
39
|
|
|
40
40
|
// ─── Pyreon re-exports for convenience ───────────────────────────────────────
|
|
41
41
|
|
|
42
|
-
export { h, Fragment } from '@pyreon/core'
|
|
43
42
|
export type { ComponentFn, Props, VNode, VNodeChild } from '@pyreon/core'
|
|
44
|
-
export {
|
|
43
|
+
export { Fragment, h } from '@pyreon/core'
|
|
44
|
+
export { computed, effect, signal } from '@pyreon/reactivity'
|
|
45
45
|
export { mount } from '@pyreon/runtime-dom'
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ComponentFn, VNodeChild } from '@pyreon/core'
|
|
2
|
+
import { renderToCanvas } from './render-impl'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Preview entry — Storybook loads this in the preview iframe.
|
|
6
|
+
*
|
|
7
|
+
* Exports the render function and default decorators/parameters
|
|
8
|
+
* that apply to all stories using this renderer.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export { renderToCanvas }
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Default render function — if the story CSF has a `component` but no
|
|
15
|
+
* explicit `render`, this is used to create the VNode.
|
|
16
|
+
*/
|
|
17
|
+
export function render<TArgs extends Record<string, unknown>>(
|
|
18
|
+
args: TArgs,
|
|
19
|
+
context: { component?: ComponentFn<any> },
|
|
20
|
+
): VNodeChild {
|
|
21
|
+
const Component = context.component
|
|
22
|
+
if (!Component) {
|
|
23
|
+
throw new Error(
|
|
24
|
+
'[@pyreon/storybook] No component provided. Either set `component` in your meta or provide a `render` function.',
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
return <Component {...args} />
|
|
28
|
+
}
|
package/src/preview.ts
CHANGED
|
@@ -1,29 +1 @@
|
|
|
1
|
-
|
|
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
|
-
}
|
|
1
|
+
export { render, renderToCanvas } from './preview-impl'
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { ComponentFn, VNodeChild } from '@pyreon/core'
|
|
2
|
+
import { mount } from '@pyreon/runtime-dom'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* State tracked per canvas element so we can clean up between renders.
|
|
6
|
+
*/
|
|
7
|
+
const canvasState = new WeakMap<HTMLElement, () => void>()
|
|
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
|
+
export function renderToCanvas(
|
|
22
|
+
{
|
|
23
|
+
storyFn,
|
|
24
|
+
showMain,
|
|
25
|
+
showError,
|
|
26
|
+
}: {
|
|
27
|
+
storyFn: () => VNodeChild
|
|
28
|
+
storyContext: {
|
|
29
|
+
component?: ComponentFn<any>
|
|
30
|
+
args: Record<string, unknown>
|
|
31
|
+
[key: string]: unknown
|
|
32
|
+
}
|
|
33
|
+
showMain: () => void
|
|
34
|
+
showError: (error: { title: string; description: string }) => void
|
|
35
|
+
forceRemount: boolean
|
|
36
|
+
},
|
|
37
|
+
canvasElement: HTMLElement,
|
|
38
|
+
): void {
|
|
39
|
+
// Always clean up the previous render
|
|
40
|
+
const prevUnmount = canvasState.get(canvasElement)
|
|
41
|
+
if (prevUnmount) {
|
|
42
|
+
prevUnmount()
|
|
43
|
+
canvasState.delete(canvasElement)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const element = storyFn()
|
|
48
|
+
const unmount = mount(element, canvasElement)
|
|
49
|
+
canvasState.set(canvasElement, unmount)
|
|
50
|
+
showMain()
|
|
51
|
+
} catch (err) {
|
|
52
|
+
const error = err instanceof Error ? err : new Error(String(err))
|
|
53
|
+
showError({
|
|
54
|
+
title: `Error rendering story`,
|
|
55
|
+
description: error.message,
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Default render implementation used when no custom `render` is provided.
|
|
62
|
+
*/
|
|
63
|
+
export function defaultRender(
|
|
64
|
+
component: ComponentFn<any>,
|
|
65
|
+
args: Record<string, unknown>,
|
|
66
|
+
): VNodeChild {
|
|
67
|
+
const Component = component
|
|
68
|
+
return <Component {...args} />
|
|
69
|
+
}
|
package/src/render.ts
CHANGED
|
@@ -1,75 +1 @@
|
|
|
1
|
-
|
|
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
|
-
}
|
|
1
|
+
export { defaultRender, renderToCanvas } from './render-impl'
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import { h, Fragment } from '@pyreon/core'
|
|
2
1
|
import type { ComponentFn, VNodeChild } from '@pyreon/core'
|
|
3
|
-
import {
|
|
2
|
+
import { effect, signal } from '@pyreon/reactivity'
|
|
4
3
|
import { mount } from '@pyreon/runtime-dom'
|
|
5
|
-
import { renderToCanvas, defaultRender } from '../render'
|
|
6
4
|
import { render as previewRender } from '../preview'
|
|
5
|
+
import { defaultRender, renderToCanvas } from '../render'
|
|
7
6
|
import type {
|
|
8
|
-
Meta,
|
|
9
|
-
StoryObj,
|
|
10
7
|
DecoratorFn,
|
|
11
|
-
|
|
8
|
+
Meta,
|
|
12
9
|
StoryContext,
|
|
10
|
+
StoryFn,
|
|
11
|
+
StoryObj,
|
|
13
12
|
} from '../types'
|
|
14
13
|
|
|
15
14
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
@@ -26,7 +25,7 @@ function makeRenderContext(overrides: {
|
|
|
26
25
|
args?: Record<string, unknown>
|
|
27
26
|
}) {
|
|
28
27
|
return {
|
|
29
|
-
storyFn: overrides.storyFn ?? (() =>
|
|
28
|
+
storyFn: overrides.storyFn ?? (() => <div>default</div>),
|
|
30
29
|
storyContext: {
|
|
31
30
|
component: overrides.component,
|
|
32
31
|
args: overrides.args ?? {},
|
|
@@ -47,7 +46,7 @@ describe('renderToCanvas', () => {
|
|
|
47
46
|
it('mounts a simple VNode into the canvas', () => {
|
|
48
47
|
const canvas = createCanvas()
|
|
49
48
|
const ctx = makeRenderContext({
|
|
50
|
-
storyFn: () =>
|
|
49
|
+
storyFn: () => <button>Click me</button>,
|
|
51
50
|
})
|
|
52
51
|
|
|
53
52
|
renderToCanvas(ctx, canvas)
|
|
@@ -59,12 +58,12 @@ describe('renderToCanvas', () => {
|
|
|
59
58
|
|
|
60
59
|
it('mounts a Pyreon component with props', () => {
|
|
61
60
|
function Button(props: { label: string; disabled?: boolean }) {
|
|
62
|
-
return
|
|
61
|
+
return <button disabled={props.disabled ?? false}>{props.label}</button>
|
|
63
62
|
}
|
|
64
63
|
|
|
65
64
|
const canvas = createCanvas()
|
|
66
65
|
const ctx = makeRenderContext({
|
|
67
|
-
storyFn: () =>
|
|
66
|
+
storyFn: () => <Button label="Submit" disabled={true} />,
|
|
68
67
|
})
|
|
69
68
|
|
|
70
69
|
renderToCanvas(ctx, canvas)
|
|
@@ -80,13 +79,13 @@ describe('renderToCanvas', () => {
|
|
|
80
79
|
const canvas = createCanvas()
|
|
81
80
|
|
|
82
81
|
renderToCanvas(
|
|
83
|
-
makeRenderContext({ storyFn: () =>
|
|
82
|
+
makeRenderContext({ storyFn: () => <div>First</div> }),
|
|
84
83
|
canvas,
|
|
85
84
|
)
|
|
86
85
|
expect(canvas.textContent).toBe('First')
|
|
87
86
|
|
|
88
87
|
renderToCanvas(
|
|
89
|
-
makeRenderContext({ storyFn: () =>
|
|
88
|
+
makeRenderContext({ storyFn: () => <div>Second</div> }),
|
|
90
89
|
canvas,
|
|
91
90
|
)
|
|
92
91
|
expect(canvas.textContent).toBe('Second')
|
|
@@ -105,13 +104,10 @@ describe('renderToCanvas', () => {
|
|
|
105
104
|
count()
|
|
106
105
|
effectRunCount++
|
|
107
106
|
})
|
|
108
|
-
return
|
|
107
|
+
return <span>{() => `${count()}`}</span>
|
|
109
108
|
}
|
|
110
109
|
|
|
111
|
-
renderToCanvas(
|
|
112
|
-
makeRenderContext({ storyFn: () => h(Counter, null) }),
|
|
113
|
-
canvas,
|
|
114
|
-
)
|
|
110
|
+
renderToCanvas(makeRenderContext({ storyFn: () => <Counter /> }), canvas)
|
|
115
111
|
|
|
116
112
|
const initialCount = effectRunCount
|
|
117
113
|
count.set(1)
|
|
@@ -119,7 +115,7 @@ describe('renderToCanvas', () => {
|
|
|
119
115
|
|
|
120
116
|
// Re-render with a different story — should dispose previous effects
|
|
121
117
|
renderToCanvas(
|
|
122
|
-
makeRenderContext({ storyFn: () =>
|
|
118
|
+
makeRenderContext({ storyFn: () => <div>New story</div> }),
|
|
123
119
|
canvas,
|
|
124
120
|
)
|
|
125
121
|
|
|
@@ -186,13 +182,10 @@ describe('renderToCanvas', () => {
|
|
|
186
182
|
const count = signal(0)
|
|
187
183
|
|
|
188
184
|
function Counter() {
|
|
189
|
-
return
|
|
185
|
+
return <span data-testid="count">{() => `Count: ${count()}`}</span>
|
|
190
186
|
}
|
|
191
187
|
|
|
192
|
-
renderToCanvas(
|
|
193
|
-
makeRenderContext({ storyFn: () => h(Counter, null) }),
|
|
194
|
-
canvas,
|
|
195
|
-
)
|
|
188
|
+
renderToCanvas(makeRenderContext({ storyFn: () => <Counter /> }), canvas)
|
|
196
189
|
|
|
197
190
|
expect(canvas.textContent).toBe('Count: 0')
|
|
198
191
|
|
|
@@ -207,7 +200,7 @@ describe('renderToCanvas', () => {
|
|
|
207
200
|
describe('defaultRender', () => {
|
|
208
201
|
it('creates a VNode from component + args', () => {
|
|
209
202
|
function Greeting(props: { name: string }) {
|
|
210
|
-
return
|
|
203
|
+
return <p>Hello, {props.name}!</p>
|
|
211
204
|
}
|
|
212
205
|
|
|
213
206
|
const canvas = createCanvas()
|
|
@@ -228,7 +221,7 @@ describe('Meta and StoryObj types', () => {
|
|
|
228
221
|
label: string
|
|
229
222
|
variant?: 'primary' | 'secondary'
|
|
230
223
|
}) {
|
|
231
|
-
return
|
|
224
|
+
return <button class={props.variant}>{props.label}</button>
|
|
232
225
|
}
|
|
233
226
|
|
|
234
227
|
const meta = {
|
|
@@ -244,10 +237,7 @@ describe('Meta and StoryObj types', () => {
|
|
|
244
237
|
|
|
245
238
|
it('StoryObj inherits args from Meta', () => {
|
|
246
239
|
function Input(props: { placeholder: string; disabled?: boolean }) {
|
|
247
|
-
return
|
|
248
|
-
placeholder: props.placeholder,
|
|
249
|
-
disabled: props.disabled,
|
|
250
|
-
})
|
|
240
|
+
return <input placeholder={props.placeholder} disabled={props.disabled} />
|
|
251
241
|
}
|
|
252
242
|
|
|
253
243
|
const _meta = {
|
|
@@ -266,7 +256,11 @@ describe('Meta and StoryObj types', () => {
|
|
|
266
256
|
|
|
267
257
|
it('StoryObj supports custom render function', () => {
|
|
268
258
|
function Card(props: { title: string }) {
|
|
269
|
-
return
|
|
259
|
+
return (
|
|
260
|
+
<div class="card">
|
|
261
|
+
<h2>{props.title}</h2>
|
|
262
|
+
</div>
|
|
263
|
+
)
|
|
270
264
|
}
|
|
271
265
|
|
|
272
266
|
const _meta = {
|
|
@@ -277,7 +271,11 @@ describe('Meta and StoryObj types', () => {
|
|
|
277
271
|
type Story = StoryObj<typeof _meta>
|
|
278
272
|
|
|
279
273
|
const withWrapper: Story = {
|
|
280
|
-
render: (args) =>
|
|
274
|
+
render: (args) => (
|
|
275
|
+
<div class="wrapper">
|
|
276
|
+
<Card {...args} />
|
|
277
|
+
</div>
|
|
278
|
+
),
|
|
281
279
|
}
|
|
282
280
|
|
|
283
281
|
const canvas = createCanvas()
|
|
@@ -297,19 +295,15 @@ describe('Meta and StoryObj types', () => {
|
|
|
297
295
|
describe('Decorators', () => {
|
|
298
296
|
it('decorator wraps a story', () => {
|
|
299
297
|
function Button(props: { label: string }) {
|
|
300
|
-
return
|
|
298
|
+
return <button>{props.label}</button>
|
|
301
299
|
}
|
|
302
300
|
|
|
303
301
|
const withPadding: DecoratorFn<{ label: string }> = (storyFn, context) => {
|
|
304
|
-
return
|
|
305
|
-
'div',
|
|
306
|
-
{ style: 'padding: 1rem' },
|
|
307
|
-
storyFn(context.args, context),
|
|
308
|
-
)
|
|
302
|
+
return <div style="padding: 1rem">{storyFn(context.args, context)}</div>
|
|
309
303
|
}
|
|
310
304
|
|
|
311
305
|
const canvas = createCanvas()
|
|
312
|
-
const storyResult = withPadding((args) =>
|
|
306
|
+
const storyResult = withPadding((args) => <Button {...args} />, {
|
|
313
307
|
args: { label: 'Wrapped' },
|
|
314
308
|
argTypes: {},
|
|
315
309
|
globals: {},
|
|
@@ -328,14 +322,16 @@ describe('Decorators', () => {
|
|
|
328
322
|
|
|
329
323
|
it('multiple decorators compose correctly', () => {
|
|
330
324
|
function Text(props: { content: string }) {
|
|
331
|
-
return
|
|
325
|
+
return <span>{props.content}</span>
|
|
332
326
|
}
|
|
333
327
|
|
|
334
|
-
const withBorder: DecoratorFn<{ content: string }> = (storyFn, ctx) =>
|
|
335
|
-
|
|
328
|
+
const withBorder: DecoratorFn<{ content: string }> = (storyFn, ctx) => (
|
|
329
|
+
<div class="border">{storyFn(ctx.args, ctx)}</div>
|
|
330
|
+
)
|
|
336
331
|
|
|
337
|
-
const withTheme: DecoratorFn<{ content: string }> = (storyFn, ctx) =>
|
|
338
|
-
|
|
332
|
+
const withTheme: DecoratorFn<{ content: string }> = (storyFn, ctx) => (
|
|
333
|
+
<div class="theme-dark">{storyFn(ctx.args, ctx)}</div>
|
|
334
|
+
)
|
|
339
335
|
|
|
340
336
|
const context: StoryContext<{ content: string }> = {
|
|
341
337
|
args: { content: 'Hello' },
|
|
@@ -348,7 +344,7 @@ describe('Decorators', () => {
|
|
|
348
344
|
}
|
|
349
345
|
|
|
350
346
|
// Compose: withTheme(withBorder(story))
|
|
351
|
-
const story: StoryFn<{ content: string }> = (args) =>
|
|
347
|
+
const story: StoryFn<{ content: string }> = (args) => <Text {...args} />
|
|
352
348
|
const decorated = withTheme((_args, ctx) => withBorder(story, ctx), context)
|
|
353
349
|
|
|
354
350
|
const canvas = createCanvas()
|
|
@@ -368,8 +364,12 @@ describe('Fragment stories', () => {
|
|
|
368
364
|
const canvas = createCanvas()
|
|
369
365
|
renderToCanvas(
|
|
370
366
|
makeRenderContext({
|
|
371
|
-
storyFn: () =>
|
|
372
|
-
|
|
367
|
+
storyFn: () => (
|
|
368
|
+
<>
|
|
369
|
+
<p>Line 1</p>
|
|
370
|
+
<p>Line 2</p>
|
|
371
|
+
</>
|
|
372
|
+
),
|
|
373
373
|
}),
|
|
374
374
|
canvas,
|
|
375
375
|
)
|
|
@@ -387,7 +387,7 @@ describe('Fragment stories', () => {
|
|
|
387
387
|
describe('preview render', () => {
|
|
388
388
|
it('renders a component with args', () => {
|
|
389
389
|
function Badge(props: { text: string }) {
|
|
390
|
-
return
|
|
390
|
+
return <span class="badge">{props.text}</span>
|
|
391
391
|
}
|
|
392
392
|
|
|
393
393
|
const canvas = createCanvas()
|