@pyreon/storybook 0.11.5 → 0.11.7

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/README.md CHANGED
@@ -15,27 +15,27 @@ Configure Storybook to use the Pyreon renderer:
15
15
  ```ts
16
16
  // .storybook/main.ts
17
17
  export default {
18
- stories: ["../src/**/*.stories.ts"],
19
- framework: "@pyreon/storybook",
18
+ stories: ['../src/**/*.stories.ts'],
19
+ framework: '@pyreon/storybook',
20
20
  }
21
21
  ```
22
22
 
23
23
  ## Quick Start
24
24
 
25
25
  ```tsx
26
- import type { Meta, StoryObj } from "@pyreon/storybook"
27
- import { Button } from "./Button"
26
+ import type { Meta, StoryObj } from '@pyreon/storybook'
27
+ import { Button } from './Button'
28
28
 
29
29
  const meta = {
30
30
  component: Button,
31
- args: { label: "Click me" },
31
+ args: { label: 'Click me' },
32
32
  } satisfies Meta<typeof Button>
33
33
 
34
34
  export default meta
35
35
  type Story = StoryObj<typeof meta>
36
36
 
37
37
  export const Primary: Story = {
38
- args: { variant: "primary" },
38
+ args: { variant: 'primary' },
39
39
  }
40
40
 
41
41
  export const AllVariants: Story = {
@@ -54,13 +54,13 @@ export const AllVariants: Story = {
54
54
 
55
55
  Core renderer called by Storybook to display stories. Handles cleanup of previous renders, error display, and mounting the VNode tree.
56
56
 
57
- | Parameter | Type | Description |
58
- | --- | --- | --- |
59
- | `context.storyFn` | `() => VNodeChild` | Function that produces the story VNode |
60
- | `context.showMain` | `() => void` | Show the main canvas |
61
- | `context.showError` | `(error) => void` | Show an error panel |
62
- | `context.forceRemount` | `boolean` | Whether to force a full remount |
63
- | `canvasElement` | `HTMLElement` | DOM element to render into |
57
+ | Parameter | Type | Description |
58
+ | ---------------------- | ------------------ | -------------------------------------- |
59
+ | `context.storyFn` | `() => VNodeChild` | Function that produces the story VNode |
60
+ | `context.showMain` | `() => void` | Show the main canvas |
61
+ | `context.showError` | `(error) => void` | Show an error panel |
62
+ | `context.forceRemount` | `boolean` | Whether to force a full remount |
63
+ | `canvasElement` | `HTMLElement` | DOM element to render into |
64
64
 
65
65
  This function is used internally by the Storybook framework preset. You typically do not call it directly.
66
66
 
@@ -68,10 +68,10 @@ This function is used internally by the Storybook framework preset. You typicall
68
68
 
69
69
  Default render implementation. Called when no custom `render` function is provided on the story or meta.
70
70
 
71
- | Parameter | Type | Description |
72
- | --- | --- | --- |
73
- | `component` | `ComponentFn` | Pyreon component function |
74
- | `args` | `Record<string, unknown>` | Story args passed as props |
71
+ | Parameter | Type | Description |
72
+ | ----------- | ------------------------- | -------------------------- |
73
+ | `component` | `ComponentFn` | Pyreon component function |
74
+ | `args` | `Record<string, unknown>` | Story args passed as props |
75
75
 
76
76
  **Returns:** `VNodeChild` — result of `h(component, args)`
77
77
 
@@ -79,33 +79,33 @@ Default render implementation. Called when no custom `render` function is provid
79
79
 
80
80
  Type for the default export of a story file. Provides type inference for args based on the component's props.
81
81
 
82
- | Property | Type | Description |
83
- | --- | --- | --- |
84
- | `component` | `TComponent` | The component to document |
85
- | `title` | `string` | Display title in sidebar |
86
- | `decorators` | `DecoratorFn[]` | Decorators for all stories in the file |
87
- | `args` | `Partial<InferProps<TComponent>>` | Default args |
88
- | `argTypes` | `Record<string, unknown>` | Arg type definitions for Controls |
89
- | `parameters` | `Record<string, unknown>` | Story parameters (backgrounds, viewport) |
90
- | `tags` | `string[]` | Tags for filtering (e.g. `"autodocs"`) |
91
- | `render` | `(args, context) => VNodeChild` | Default render function |
92
- | `excludeStories` | `string \| string[] \| RegExp` | Exclude named exports |
93
- | `includeStories` | `string \| string[] \| RegExp` | Include only named exports |
82
+ | Property | Type | Description |
83
+ | ---------------- | --------------------------------- | ---------------------------------------- |
84
+ | `component` | `TComponent` | The component to document |
85
+ | `title` | `string` | Display title in sidebar |
86
+ | `decorators` | `DecoratorFn[]` | Decorators for all stories in the file |
87
+ | `args` | `Partial<InferProps<TComponent>>` | Default args |
88
+ | `argTypes` | `Record<string, unknown>` | Arg type definitions for Controls |
89
+ | `parameters` | `Record<string, unknown>` | Story parameters (backgrounds, viewport) |
90
+ | `tags` | `string[]` | Tags for filtering (e.g. `"autodocs"`) |
91
+ | `render` | `(args, context) => VNodeChild` | Default render function |
92
+ | `excludeStories` | `string \| string[] \| RegExp` | Exclude named exports |
93
+ | `includeStories` | `string \| string[] \| RegExp` | Include only named exports |
94
94
 
95
95
  ### `StoryObj<TMeta>`
96
96
 
97
97
  Type for individual story exports. Args are merged with `Meta.args`.
98
98
 
99
- | Property | Type | Description |
100
- | --- | --- | --- |
101
- | `args` | `Partial<MetaArgs>` | Args for this story |
102
- | `argTypes` | `Record<string, unknown>` | Arg type overrides |
103
- | `decorators` | `DecoratorFn[]` | Story-specific decorators |
104
- | `parameters` | `Record<string, unknown>` | Story parameters |
105
- | `tags` | `string[]` | Story tags |
106
- | `render` | `(args, context) => VNodeChild` | Custom render for this story |
107
- | `name` | `string` | Display name override |
108
- | `play` | `(context) => Promise<void> \| void` | Interaction test function |
99
+ | Property | Type | Description |
100
+ | ------------ | ------------------------------------ | ---------------------------- |
101
+ | `args` | `Partial<MetaArgs>` | Args for this story |
102
+ | `argTypes` | `Record<string, unknown>` | Arg type overrides |
103
+ | `decorators` | `DecoratorFn[]` | Story-specific decorators |
104
+ | `parameters` | `Record<string, unknown>` | Story parameters |
105
+ | `tags` | `string[]` | Story tags |
106
+ | `render` | `(args, context) => VNodeChild` | Custom render for this story |
107
+ | `name` | `string` | Display name override |
108
+ | `play` | `(context) => Promise<void> \| void` | Interaction test function |
109
109
 
110
110
  ### `DecoratorFn<TArgs>`
111
111
 
@@ -119,11 +119,11 @@ const withTheme: DecoratorFn<{ label: string }> = (storyFn, context) => (
119
119
 
120
120
  ### `StoryFn<TArgs>` / `StoryContext<TArgs>` / `InferProps<T>`
121
121
 
122
- | Type | Description |
123
- | --- | --- |
124
- | `StoryFn<TArgs>` | `(args, context) => VNodeChild` |
122
+ | Type | Description |
123
+ | --------------------- | ------------------------------------------------------- |
124
+ | `StoryFn<TArgs>` | `(args, context) => VNodeChild` |
125
125
  | `StoryContext<TArgs>` | `{ args, argTypes, globals, id, kind, name, viewMode }` |
126
- | `InferProps<T>` | Extract props type from a `ComponentFn<P>` |
126
+ | `InferProps<T>` | Extract props type from a `ComponentFn<P>` |
127
127
 
128
128
  ## Patterns
129
129
 
@@ -136,9 +136,7 @@ const meta = {
136
136
  component: Button,
137
137
  decorators: [
138
138
  (storyFn, context) => (
139
- <div style="padding: 20px; background: #f5f5f5;">
140
- {storyFn(context.args, context)}
141
- </div>
139
+ <div style="padding: 20px; background: #f5f5f5;">{storyFn(context.args, context)}</div>
142
140
  ),
143
141
  ],
144
142
  } satisfies Meta<typeof Button>
@@ -150,10 +148,10 @@ Use the `play` function for automated interaction testing.
150
148
 
151
149
  ```ts
152
150
  export const Clickable: Story = {
153
- args: { label: "Click me" },
151
+ args: { label: 'Click me' },
154
152
  play: async ({ canvasElement, step }) => {
155
- await step("click the button", async () => {
156
- const button = canvasElement.querySelector("button")!
153
+ await step('click the button', async () => {
154
+ const button = canvasElement.querySelector('button')!
157
155
  button.click()
158
156
  })
159
157
  },
@@ -165,7 +163,7 @@ export const Clickable: Story = {
165
163
  Use signals directly in stories to demonstrate interactive behavior.
166
164
 
167
165
  ```tsx
168
- import { signal, effect } from "@pyreon/storybook"
166
+ import { signal, effect } from '@pyreon/storybook'
169
167
 
170
168
  export const Interactive: Story = {
171
169
  render: (args) => {
@@ -173,7 +171,7 @@ export const Interactive: Story = {
173
171
  return (
174
172
  <div>
175
173
  <p>{() => `Count: ${count()}`}</p>
176
- <button onClick={() => count.update(n => n + 1)}>Increment</button>
174
+ <button onClick={() => count.update((n) => n + 1)}>Increment</button>
177
175
  </div>
178
176
  )
179
177
  },
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["mount"],"sources":["../src/render-impl.tsx"],"sourcesContent":["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"],"mappings":";;;;;;;;;AAMA,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,UAAUA,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"}
1
+ {"version":3,"file":"index.js","names":["mount"],"sources":["../src/render-impl.tsx"],"sourcesContent":["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"],"mappings":";;;;;;;;;AAMA,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,UAAUA,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/preset.js.map CHANGED
@@ -1 +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"}
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"}
@@ -1 +1 @@
1
- {"version":3,"file":"preview.js","names":[],"sources":["../src/render-impl.tsx","../src/preview-impl.tsx"],"sourcesContent":["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"],"mappings":";;;;;;;AAMA,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"}
1
+ {"version":3,"file":"preview.js","names":[],"sources":["../src/render-impl.tsx","../src/preview-impl.tsx"],"sourcesContent":["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"],"mappings":";;;;;;;AAMA,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"}
@@ -21,7 +21,7 @@ interface StoryContext<TArgs = Props$1> {
21
21
  id: string;
22
22
  kind: string;
23
23
  name: string;
24
- viewMode: "story" | "docs";
24
+ viewMode: 'story' | 'docs';
25
25
  }
26
26
  type StoryFn<TArgs = Props$1> = (args: TArgs, context: StoryContext<TArgs>) => VNodeChild$1;
27
27
  type DecoratorFn<TArgs = Props$1> = (storyFn: StoryFn<TArgs>, context: StoryContext<TArgs>) => VNodeChild$1;
package/package.json CHANGED
@@ -1,20 +1,17 @@
1
1
  {
2
2
  "name": "@pyreon/storybook",
3
- "version": "0.11.5",
3
+ "version": "0.11.7",
4
4
  "description": "Storybook renderer for Pyreon — mount, render, and interact with Pyreon components in Storybook",
5
+ "homepage": "https://github.com/pyreon/pyreon/tree/main/packages/storybook#readme",
6
+ "bugs": {
7
+ "url": "https://github.com/pyreon/pyreon/issues"
8
+ },
5
9
  "license": "MIT",
6
10
  "repository": {
7
11
  "type": "git",
8
12
  "url": "https://github.com/pyreon/pyreon.git",
9
13
  "directory": "packages/tools/storybook"
10
14
  },
11
- "homepage": "https://github.com/pyreon/pyreon/tree/main/packages/storybook#readme",
12
- "bugs": {
13
- "url": "https://github.com/pyreon/pyreon/issues"
14
- },
15
- "publishConfig": {
16
- "access": "public"
17
- },
18
15
  "files": [
19
16
  "lib",
20
17
  "src",
@@ -44,17 +41,20 @@
44
41
  },
45
42
  "./package.json": "./package.json"
46
43
  },
44
+ "publishConfig": {
45
+ "access": "public"
46
+ },
47
47
  "scripts": {
48
48
  "build": "vl_rolldown_build",
49
49
  "dev": "vl_rolldown_build-watch",
50
50
  "test": "vitest run",
51
51
  "typecheck": "tsc --noEmit",
52
- "lint": "biome check ."
52
+ "lint": "oxlint ."
53
53
  },
54
54
  "peerDependencies": {
55
- "@pyreon/core": "^0.11.5",
56
- "@pyreon/reactivity": "^0.11.5",
57
- "@pyreon/runtime-dom": "^0.11.5",
55
+ "@pyreon/core": "^0.11.7",
56
+ "@pyreon/reactivity": "^0.11.7",
57
+ "@pyreon/runtime-dom": "^0.11.7",
58
58
  "storybook": ">=8.0.0"
59
59
  }
60
60
  }
package/src/index.ts CHANGED
@@ -31,15 +31,15 @@ export type {
31
31
  StoryContext,
32
32
  StoryFn,
33
33
  StoryObj,
34
- } from "./types"
34
+ } from './types'
35
35
 
36
36
  // ─── Renderer ────────────────────────────────────────────────────────────────
37
37
 
38
- export { defaultRender, renderToCanvas } from "./render"
38
+ export { defaultRender, renderToCanvas } from './render'
39
39
 
40
40
  // ─── Pyreon re-exports for convenience ───────────────────────────────────────
41
41
 
42
- export type { ComponentFn, Props, VNode, VNodeChild } from "@pyreon/core"
43
- export { Fragment, h } from "@pyreon/core"
44
- export { computed, effect, signal } from "@pyreon/reactivity"
45
- export { mount } from "@pyreon/runtime-dom"
42
+ export type { ComponentFn, Props, VNode, VNodeChild } from '@pyreon/core'
43
+ export { Fragment, h } from '@pyreon/core'
44
+ export { computed, effect, signal } from '@pyreon/reactivity'
45
+ export { mount } from '@pyreon/runtime-dom'
package/src/preset.ts CHANGED
@@ -9,16 +9,16 @@
9
9
  * - What framework name to report
10
10
  */
11
11
 
12
- import { dirname, join } from "node:path"
12
+ import { dirname, join } from 'node:path'
13
13
 
14
14
  function _getAbsolutePath(value: string): string {
15
- return dirname(require.resolve(join(value, "package.json")))
15
+ return dirname(require.resolve(join(value, 'package.json')))
16
16
  }
17
17
 
18
18
  export const addons: string[] = []
19
19
 
20
- export const previewAnnotations: string[] = [join(__dirname, "preview")]
20
+ export const previewAnnotations: string[] = [join(__dirname, 'preview')]
21
21
 
22
22
  export const core = {
23
- renderer: "@pyreon/storybook",
23
+ renderer: '@pyreon/storybook',
24
24
  }
@@ -1,5 +1,5 @@
1
- import type { ComponentFn, VNodeChild } from "@pyreon/core"
2
- import { renderToCanvas } from "./render-impl"
1
+ import type { ComponentFn, VNodeChild } from '@pyreon/core'
2
+ import { renderToCanvas } from './render-impl'
3
3
 
4
4
  /**
5
5
  * Preview entry — Storybook loads this in the preview iframe.
@@ -21,7 +21,7 @@ export function render<TArgs extends Record<string, unknown>>(
21
21
  const Component = context.component
22
22
  if (!Component) {
23
23
  throw new Error(
24
- "[@pyreon/storybook] No component provided. Either set `component` in your meta or provide a `render` function.",
24
+ '[@pyreon/storybook] No component provided. Either set `component` in your meta or provide a `render` function.',
25
25
  )
26
26
  }
27
27
  return <Component {...args} />
package/src/preview.ts CHANGED
@@ -1 +1 @@
1
- export { render, renderToCanvas } from "./preview-impl"
1
+ export { render, renderToCanvas } from './preview-impl'
@@ -1,5 +1,5 @@
1
- import type { ComponentFn, VNodeChild } from "@pyreon/core"
2
- import { mount } from "@pyreon/runtime-dom"
1
+ import type { ComponentFn, VNodeChild } from '@pyreon/core'
2
+ import { mount } from '@pyreon/runtime-dom'
3
3
 
4
4
  /**
5
5
  * State tracked per canvas element so we can clean up between renders.
package/src/render.ts CHANGED
@@ -1 +1 @@
1
- export { defaultRender, renderToCanvas } from "./render-impl"
1
+ export { defaultRender, renderToCanvas } from './render-impl'
@@ -1,14 +1,14 @@
1
- import type { ComponentFn, VNodeChild } from "@pyreon/core"
2
- import { effect, signal } from "@pyreon/reactivity"
3
- import { mount } from "@pyreon/runtime-dom"
4
- import { render as previewRender } from "../preview"
5
- import { defaultRender, renderToCanvas } from "../render"
6
- import type { DecoratorFn, Meta, StoryContext, StoryFn, StoryObj } from "../types"
1
+ import type { ComponentFn, VNodeChild } from '@pyreon/core'
2
+ import { effect, signal } from '@pyreon/reactivity'
3
+ import { mount } from '@pyreon/runtime-dom'
4
+ import { render as previewRender } from '../preview'
5
+ import { defaultRender, renderToCanvas } from '../render'
6
+ import type { DecoratorFn, Meta, StoryContext, StoryFn, StoryObj } from '../types'
7
7
 
8
8
  // ─── Helpers ──────────────────────────────────────────────────────────────────
9
9
 
10
10
  function createCanvas(): HTMLElement {
11
- const el = document.createElement("div")
11
+ const el = document.createElement('div')
12
12
  document.body.appendChild(el)
13
13
  return el
14
14
  }
@@ -36,8 +36,8 @@ function makeRenderContext(overrides: {
36
36
 
37
37
  // ─── renderToCanvas ──────────────────────────────────────────────────────────
38
38
 
39
- describe("renderToCanvas", () => {
40
- it("mounts a simple VNode into the canvas", () => {
39
+ describe('renderToCanvas', () => {
40
+ it('mounts a simple VNode into the canvas', () => {
41
41
  const canvas = createCanvas()
42
42
  const ctx = makeRenderContext({
43
43
  storyFn: () => <button>Click me</button>,
@@ -45,12 +45,12 @@ describe("renderToCanvas", () => {
45
45
 
46
46
  renderToCanvas(ctx, canvas)
47
47
 
48
- expect(canvas.innerHTML).toContain("Click me")
49
- expect(canvas.querySelector("button")).toBeTruthy()
48
+ expect(canvas.innerHTML).toContain('Click me')
49
+ expect(canvas.querySelector('button')).toBeTruthy()
50
50
  canvas.remove()
51
51
  })
52
52
 
53
- it("mounts a Pyreon component with props", () => {
53
+ it('mounts a Pyreon component with props', () => {
54
54
  function Button(props: { label: string; disabled?: boolean }) {
55
55
  return <button disabled={props.disabled ?? false}>{props.label}</button>
56
56
  }
@@ -62,27 +62,27 @@ describe("renderToCanvas", () => {
62
62
 
63
63
  renderToCanvas(ctx, canvas)
64
64
 
65
- const btn = canvas.querySelector("button")!
65
+ const btn = canvas.querySelector('button')!
66
66
  expect(btn).toBeTruthy()
67
- expect(btn.textContent).toBe("Submit")
68
- expect(btn.getAttribute("disabled")).not.toBeNull()
67
+ expect(btn.textContent).toBe('Submit')
68
+ expect(btn.getAttribute('disabled')).not.toBeNull()
69
69
  canvas.remove()
70
70
  })
71
71
 
72
- it("cleans up previous mount on re-render", () => {
72
+ it('cleans up previous mount on re-render', () => {
73
73
  const canvas = createCanvas()
74
74
 
75
75
  renderToCanvas(makeRenderContext({ storyFn: () => <div>First</div> }), canvas)
76
- expect(canvas.textContent).toBe("First")
76
+ expect(canvas.textContent).toBe('First')
77
77
 
78
78
  renderToCanvas(makeRenderContext({ storyFn: () => <div>Second</div> }), canvas)
79
- expect(canvas.textContent).toBe("Second")
79
+ expect(canvas.textContent).toBe('Second')
80
80
  // Only one child — previous mount was cleaned up
81
81
  expect(canvas.children.length).toBe(1)
82
82
  canvas.remove()
83
83
  })
84
84
 
85
- it("disposes reactive effects on cleanup", () => {
85
+ it('disposes reactive effects on cleanup', () => {
86
86
  const canvas = createCanvas()
87
87
  let effectRunCount = 0
88
88
 
@@ -112,13 +112,13 @@ describe("renderToCanvas", () => {
112
112
  canvas.remove()
113
113
  })
114
114
 
115
- it("shows error when storyFn throws an Error", () => {
115
+ it('shows error when storyFn throws an Error', () => {
116
116
  const canvas = createCanvas()
117
117
  let errorShown: { title: string; description: string } | null = null
118
118
 
119
119
  const ctx = {
120
120
  storyFn: () => {
121
- throw new Error("Boom")
121
+ throw new Error('Boom')
122
122
  },
123
123
  storyContext: { args: {} },
124
124
  showMain: () => {
@@ -133,17 +133,17 @@ describe("renderToCanvas", () => {
133
133
  renderToCanvas(ctx, canvas)
134
134
 
135
135
  expect(errorShown).not.toBeNull()
136
- expect(errorShown!.description).toBe("Boom")
136
+ expect(errorShown!.description).toBe('Boom')
137
137
  canvas.remove()
138
138
  })
139
139
 
140
- it("shows error when storyFn throws a non-Error value", () => {
140
+ it('shows error when storyFn throws a non-Error value', () => {
141
141
  const canvas = createCanvas()
142
142
  let errorShown: { title: string; description: string } | null = null
143
143
 
144
144
  const ctx = {
145
145
  storyFn: () => {
146
- throw "string error"
146
+ throw 'string error'
147
147
  },
148
148
  storyContext: { args: {} },
149
149
  showMain: () => {
@@ -158,11 +158,11 @@ describe("renderToCanvas", () => {
158
158
  renderToCanvas(ctx, canvas)
159
159
 
160
160
  expect(errorShown).not.toBeNull()
161
- expect(errorShown!.description).toBe("string error")
161
+ expect(errorShown!.description).toBe('string error')
162
162
  canvas.remove()
163
163
  })
164
164
 
165
- it("renders reactive components that update the DOM", () => {
165
+ it('renders reactive components that update the DOM', () => {
166
166
  const canvas = createCanvas()
167
167
  const count = signal(0)
168
168
 
@@ -172,27 +172,27 @@ describe("renderToCanvas", () => {
172
172
 
173
173
  renderToCanvas(makeRenderContext({ storyFn: () => <Counter /> }), canvas)
174
174
 
175
- expect(canvas.textContent).toBe("Count: 0")
175
+ expect(canvas.textContent).toBe('Count: 0')
176
176
 
177
177
  count.set(5)
178
- expect(canvas.textContent).toBe("Count: 5")
178
+ expect(canvas.textContent).toBe('Count: 5')
179
179
  canvas.remove()
180
180
  })
181
181
  })
182
182
 
183
183
  // ─── defaultRender ───────────────────────────────────────────────────────────
184
184
 
185
- describe("defaultRender", () => {
186
- it("creates a VNode from component + args", () => {
185
+ describe('defaultRender', () => {
186
+ it('creates a VNode from component + args', () => {
187
187
  function Greeting(props: { name: string }) {
188
188
  return <p>Hello, {props.name}!</p>
189
189
  }
190
190
 
191
191
  const canvas = createCanvas()
192
- const vnode = defaultRender(Greeting, { name: "World" })
192
+ const vnode = defaultRender(Greeting, { name: 'World' })
193
193
  const unmount = mount(vnode, canvas)
194
194
 
195
- expect(canvas.textContent).toBe("Hello, World!")
195
+ expect(canvas.textContent).toBe('Hello, World!')
196
196
  unmount()
197
197
  canvas.remove()
198
198
  })
@@ -200,9 +200,9 @@ describe("defaultRender", () => {
200
200
 
201
201
  // ─── Type-level tests (Meta / StoryObj) ──────────────────────────────────────
202
202
 
203
- describe("Meta and StoryObj types", () => {
204
- it("Meta accepts a component and typed args", () => {
205
- function Button(props: { label: string; variant?: "primary" | "secondary" }) {
203
+ describe('Meta and StoryObj types', () => {
204
+ it('Meta accepts a component and typed args', () => {
205
+ function Button(props: { label: string; variant?: 'primary' | 'secondary' }) {
206
206
  return (
207
207
  <button type="button" class={props.variant}>
208
208
  {props.label}
@@ -212,23 +212,23 @@ describe("Meta and StoryObj types", () => {
212
212
 
213
213
  const meta = {
214
214
  component: Button,
215
- title: "Button",
216
- args: { label: "Click", variant: "primary" as const },
217
- tags: ["autodocs"],
215
+ title: 'Button',
216
+ args: { label: 'Click', variant: 'primary' as const },
217
+ tags: ['autodocs'],
218
218
  } satisfies Meta<typeof Button>
219
219
 
220
220
  expect(meta.component).toBe(Button)
221
- expect(meta.args!.label).toBe("Click")
221
+ expect(meta.args!.label).toBe('Click')
222
222
  })
223
223
 
224
- it("StoryObj inherits args from Meta", () => {
224
+ it('StoryObj inherits args from Meta', () => {
225
225
  function Input(props: { placeholder: string; disabled?: boolean }) {
226
226
  return <input placeholder={props.placeholder} disabled={props.disabled} />
227
227
  }
228
228
 
229
229
  const _meta = {
230
230
  component: Input,
231
- args: { placeholder: "Type here" },
231
+ args: { placeholder: 'Type here' },
232
232
  } satisfies Meta<typeof Input>
233
233
 
234
234
  type Story = StoryObj<typeof _meta>
@@ -240,7 +240,7 @@ describe("Meta and StoryObj types", () => {
240
240
  expect(primary.args!.disabled).toBe(true)
241
241
  })
242
242
 
243
- it("StoryObj supports custom render function", () => {
243
+ it('StoryObj supports custom render function', () => {
244
244
  function Card(props: { title: string }) {
245
245
  return (
246
246
  <div class="card">
@@ -251,7 +251,7 @@ describe("Meta and StoryObj types", () => {
251
251
 
252
252
  const _meta = {
253
253
  component: Card,
254
- args: { title: "Default" },
254
+ args: { title: 'Default' },
255
255
  } satisfies Meta<typeof Card>
256
256
 
257
257
  type Story = StoryObj<typeof _meta>
@@ -265,12 +265,12 @@ describe("Meta and StoryObj types", () => {
265
265
  }
266
266
 
267
267
  const canvas = createCanvas()
268
- const vnode = withWrapper.render!({ title: "Custom" }, {} as any)
268
+ const vnode = withWrapper.render!({ title: 'Custom' }, {} as any)
269
269
  const unmount = mount(vnode, canvas)
270
270
 
271
- expect(canvas.querySelector(".wrapper")).toBeTruthy()
272
- expect(canvas.querySelector(".card")).toBeTruthy()
273
- expect(canvas.textContent).toBe("Custom")
271
+ expect(canvas.querySelector('.wrapper')).toBeTruthy()
272
+ expect(canvas.querySelector('.card')).toBeTruthy()
273
+ expect(canvas.textContent).toBe('Custom')
274
274
  unmount()
275
275
  canvas.remove()
276
276
  })
@@ -278,8 +278,8 @@ describe("Meta and StoryObj types", () => {
278
278
 
279
279
  // ─── Decorators ──────────────────────────────────────────────────────────────
280
280
 
281
- describe("Decorators", () => {
282
- it("decorator wraps a story", () => {
281
+ describe('Decorators', () => {
282
+ it('decorator wraps a story', () => {
283
283
  function Button(props: { label: string }) {
284
284
  return <button>{props.label}</button>
285
285
  }
@@ -290,23 +290,23 @@ describe("Decorators", () => {
290
290
 
291
291
  const canvas = createCanvas()
292
292
  const storyResult = withPadding((args) => <Button {...args} />, {
293
- args: { label: "Wrapped" },
293
+ args: { label: 'Wrapped' },
294
294
  argTypes: {},
295
295
  globals: {},
296
- id: "1",
297
- kind: "Button",
298
- name: "Primary",
299
- viewMode: "story",
296
+ id: '1',
297
+ kind: 'Button',
298
+ name: 'Primary',
299
+ viewMode: 'story',
300
300
  })
301
301
 
302
302
  const unmount = mount(storyResult, canvas)
303
- expect(canvas.querySelector("div[style]")).toBeTruthy()
304
- expect(canvas.querySelector("button")!.textContent).toBe("Wrapped")
303
+ expect(canvas.querySelector('div[style]')).toBeTruthy()
304
+ expect(canvas.querySelector('button')!.textContent).toBe('Wrapped')
305
305
  unmount()
306
306
  canvas.remove()
307
307
  })
308
308
 
309
- it("multiple decorators compose correctly", () => {
309
+ it('multiple decorators compose correctly', () => {
310
310
  function Text(props: { content: string }) {
311
311
  return <span>{props.content}</span>
312
312
  }
@@ -320,13 +320,13 @@ describe("Decorators", () => {
320
320
  )
321
321
 
322
322
  const context: StoryContext<{ content: string }> = {
323
- args: { content: "Hello" },
323
+ args: { content: 'Hello' },
324
324
  argTypes: {},
325
325
  globals: {},
326
- id: "1",
327
- kind: "Text",
328
- name: "Default",
329
- viewMode: "story",
326
+ id: '1',
327
+ kind: 'Text',
328
+ name: 'Default',
329
+ viewMode: 'story',
330
330
  }
331
331
 
332
332
  // Compose: withTheme(withBorder(story))
@@ -335,9 +335,9 @@ describe("Decorators", () => {
335
335
 
336
336
  const canvas = createCanvas()
337
337
  const unmount = mount(decorated, canvas)
338
- expect(canvas.querySelector(".theme-dark")).toBeTruthy()
339
- expect(canvas.querySelector(".border")).toBeTruthy()
340
- expect(canvas.querySelector("span")!.textContent).toBe("Hello")
338
+ expect(canvas.querySelector('.theme-dark')).toBeTruthy()
339
+ expect(canvas.querySelector('.border')).toBeTruthy()
340
+ expect(canvas.querySelector('span')!.textContent).toBe('Hello')
341
341
  unmount()
342
342
  canvas.remove()
343
343
  })
@@ -345,8 +345,8 @@ describe("Decorators", () => {
345
345
 
346
346
  // ─── Fragment and multiple children ──────────────────────────────────────────
347
347
 
348
- describe("Fragment stories", () => {
349
- it("renders a story returning a Fragment", () => {
348
+ describe('Fragment stories', () => {
349
+ it('renders a story returning a Fragment', () => {
350
350
  const canvas = createCanvas()
351
351
  renderToCanvas(
352
352
  makeRenderContext({
@@ -360,48 +360,48 @@ describe("Fragment stories", () => {
360
360
  canvas,
361
361
  )
362
362
 
363
- const paragraphs = canvas.querySelectorAll("p")
363
+ const paragraphs = canvas.querySelectorAll('p')
364
364
  expect(paragraphs.length).toBe(2)
365
- expect(paragraphs[0]!.textContent).toBe("Line 1")
366
- expect(paragraphs[1]!.textContent).toBe("Line 2")
365
+ expect(paragraphs[0]!.textContent).toBe('Line 1')
366
+ expect(paragraphs[1]!.textContent).toBe('Line 2')
367
367
  canvas.remove()
368
368
  })
369
369
  })
370
370
 
371
371
  // ─── Preview render function ─────────────────────────────────────────────────
372
372
 
373
- describe("preview render", () => {
374
- it("renders a component with args", () => {
373
+ describe('preview render', () => {
374
+ it('renders a component with args', () => {
375
375
  function Badge(props: { text: string }) {
376
376
  return <span class="badge">{props.text}</span>
377
377
  }
378
378
 
379
379
  const canvas = createCanvas()
380
- const vnode = previewRender({ text: "New" }, { component: Badge })
380
+ const vnode = previewRender({ text: 'New' }, { component: Badge })
381
381
  const unmount = mount(vnode, canvas)
382
382
 
383
- expect(canvas.querySelector(".badge")!.textContent).toBe("New")
383
+ expect(canvas.querySelector('.badge')!.textContent).toBe('New')
384
384
  unmount()
385
385
  canvas.remove()
386
386
  })
387
387
 
388
- it("throws when no component is provided", () => {
389
- expect(() => previewRender({ foo: "bar" }, {})).toThrow(
390
- "[@pyreon/storybook] No component provided",
388
+ it('throws when no component is provided', () => {
389
+ expect(() => previewRender({ foo: 'bar' }, {})).toThrow(
390
+ '[@pyreon/storybook] No component provided',
391
391
  )
392
392
  })
393
393
 
394
- it("throws when component is undefined", () => {
395
- expect(() => previewRender({ foo: "bar" }, { component: undefined } as any)).toThrow(
396
- "[@pyreon/storybook] No component provided",
394
+ it('throws when component is undefined', () => {
395
+ expect(() => previewRender({ foo: 'bar' }, { component: undefined } as any)).toThrow(
396
+ '[@pyreon/storybook] No component provided',
397
397
  )
398
398
  })
399
399
  })
400
400
 
401
401
  // ─── Decorator wrapping ─────────────────────────────────────────────────────
402
402
 
403
- describe("decorator wrapping", () => {
404
- it("decorator modifies the rendered VNode structure", () => {
403
+ describe('decorator wrapping', () => {
404
+ it('decorator modifies the rendered VNode structure', () => {
405
405
  function Badge(props: { text: string }) {
406
406
  return <span class="badge">{props.text}</span>
407
407
  }
@@ -417,21 +417,21 @@ describe("decorator wrapping", () => {
417
417
 
418
418
  const canvas = createCanvas()
419
419
  const context: StoryContext<{ text: string }> = {
420
- args: { text: "Info" },
420
+ args: { text: 'Info' },
421
421
  argTypes: {},
422
422
  globals: {},
423
- id: "1",
424
- kind: "Badge",
425
- name: "Default",
426
- viewMode: "story",
423
+ id: '1',
424
+ kind: 'Badge',
425
+ name: 'Default',
426
+ viewMode: 'story',
427
427
  }
428
428
 
429
429
  const decorated = withCard((args) => <Badge {...args} />, context)
430
430
  const unmount = mount(decorated, canvas)
431
431
 
432
- expect(canvas.querySelector(".card")).toBeTruthy()
433
- expect(canvas.querySelector("h3")!.textContent).toBe("Decorated")
434
- expect(canvas.querySelector(".badge")!.textContent).toBe("Info")
432
+ expect(canvas.querySelector('.card')).toBeTruthy()
433
+ expect(canvas.querySelector('h3')!.textContent).toBe('Decorated')
434
+ expect(canvas.querySelector('.badge')!.textContent).toBe('Info')
435
435
  unmount()
436
436
  canvas.remove()
437
437
  })
@@ -439,8 +439,8 @@ describe("decorator wrapping", () => {
439
439
 
440
440
  // ─── Component with no args ─────────────────────────────────────────────────
441
441
 
442
- describe("component with no args", () => {
443
- it("renders a component without any props via renderToCanvas", () => {
442
+ describe('component with no args', () => {
443
+ it('renders a component without any props via renderToCanvas', () => {
444
444
  function Logo() {
445
445
  return <img src="/logo.png" alt="Logo" />
446
446
  }
@@ -454,12 +454,12 @@ describe("component with no args", () => {
454
454
  canvas,
455
455
  )
456
456
 
457
- expect(canvas.querySelector("img")).toBeTruthy()
458
- expect(canvas.querySelector("img")!.getAttribute("alt")).toBe("Logo")
457
+ expect(canvas.querySelector('img')).toBeTruthy()
458
+ expect(canvas.querySelector('img')!.getAttribute('alt')).toBe('Logo')
459
459
  canvas.remove()
460
460
  })
461
461
 
462
- it("renders a component with no args via defaultRender", () => {
462
+ it('renders a component with no args via defaultRender', () => {
463
463
  function Divider() {
464
464
  return <hr class="divider" />
465
465
  }
@@ -468,13 +468,13 @@ describe("component with no args", () => {
468
468
  const vnode = defaultRender(Divider, {})
469
469
  const unmount = mount(vnode, canvas)
470
470
 
471
- expect(canvas.querySelector("hr")).toBeTruthy()
472
- expect(canvas.querySelector(".divider")).toBeTruthy()
471
+ expect(canvas.querySelector('hr')).toBeTruthy()
472
+ expect(canvas.querySelector('.divider')).toBeTruthy()
473
473
  unmount()
474
474
  canvas.remove()
475
475
  })
476
476
 
477
- it("preview render works with empty args", () => {
477
+ it('preview render works with empty args', () => {
478
478
  function Spinner() {
479
479
  return <div class="spinner">Loading...</div>
480
480
  }
@@ -483,7 +483,7 @@ describe("component with no args", () => {
483
483
  const vnode = previewRender({}, { component: Spinner })
484
484
  const unmount = mount(vnode, canvas)
485
485
 
486
- expect(canvas.querySelector(".spinner")!.textContent).toBe("Loading...")
486
+ expect(canvas.querySelector('.spinner')!.textContent).toBe('Loading...')
487
487
  unmount()
488
488
  canvas.remove()
489
489
  })
@@ -491,15 +491,15 @@ describe("component with no args", () => {
491
491
 
492
492
  // ─── Error handling ──────────────────────────────────────────────────────────
493
493
 
494
- describe("error handling", () => {
495
- it("showError is called when storyFn itself throws", () => {
494
+ describe('error handling', () => {
495
+ it('showError is called when storyFn itself throws', () => {
496
496
  const canvas = createCanvas()
497
497
  let errorShown: { title: string; description: string } | null = null
498
498
 
499
499
  renderToCanvas(
500
500
  {
501
501
  storyFn: () => {
502
- throw new Error("storyFn exploded")
502
+ throw new Error('storyFn exploded')
503
503
  },
504
504
  storyContext: { args: {} },
505
505
  showMain: () => {
@@ -514,18 +514,18 @@ describe("error handling", () => {
514
514
  )
515
515
 
516
516
  expect(errorShown).not.toBeNull()
517
- expect(errorShown!.description).toBe("storyFn exploded")
517
+ expect(errorShown!.description).toBe('storyFn exploded')
518
518
  canvas.remove()
519
519
  })
520
520
 
521
- it("showError receives string-coerced non-Error throws", () => {
521
+ it('showError receives string-coerced non-Error throws', () => {
522
522
  const canvas = createCanvas()
523
523
  let errorShown: { title: string; description: string } | null = null
524
524
 
525
525
  renderToCanvas(
526
526
  {
527
527
  storyFn: () => {
528
- throw "raw string error"
528
+ throw 'raw string error'
529
529
  },
530
530
  storyContext: { args: {} },
531
531
  showMain: () => {
@@ -540,15 +540,15 @@ describe("error handling", () => {
540
540
  )
541
541
 
542
542
  expect(errorShown).not.toBeNull()
543
- expect(errorShown!.description).toBe("raw string error")
543
+ expect(errorShown!.description).toBe('raw string error')
544
544
  canvas.remove()
545
545
  })
546
546
 
547
- it("component that throws during setup is handled by the framework", () => {
547
+ it('component that throws during setup is handled by the framework', () => {
548
548
  const canvas = createCanvas()
549
549
 
550
550
  function Broken(): never {
551
- throw new Error("Component exploded")
551
+ throw new Error('Component exploded')
552
552
  }
553
553
 
554
554
  // Pyreon's mount catches component setup errors internally,
@@ -578,23 +578,23 @@ describe("error handling", () => {
578
578
 
579
579
  // ─── Re-render cleanup ──────────────────────────────────────────────────────
580
580
 
581
- describe("re-render cleanup", () => {
582
- it("calling renderToCanvas twice cleans up previous mount", () => {
581
+ describe('re-render cleanup', () => {
582
+ it('calling renderToCanvas twice cleans up previous mount', () => {
583
583
  const canvas = createCanvas()
584
584
 
585
585
  renderToCanvas(makeRenderContext({ storyFn: () => <div class="first">First</div> }), canvas)
586
- expect(canvas.querySelector(".first")).toBeTruthy()
586
+ expect(canvas.querySelector('.first')).toBeTruthy()
587
587
 
588
588
  renderToCanvas(makeRenderContext({ storyFn: () => <div class="second">Second</div> }), canvas)
589
589
 
590
590
  // Previous content should be gone
591
- expect(canvas.querySelector(".first")).toBeNull()
592
- expect(canvas.querySelector(".second")).toBeTruthy()
593
- expect(canvas.textContent).toBe("Second")
591
+ expect(canvas.querySelector('.first')).toBeNull()
592
+ expect(canvas.querySelector('.second')).toBeTruthy()
593
+ expect(canvas.textContent).toBe('Second')
594
594
  canvas.remove()
595
595
  })
596
596
 
597
- it("re-render disposes effects from previous story", () => {
597
+ it('re-render disposes effects from previous story', () => {
598
598
  const canvas = createCanvas()
599
599
  let effectCount = 0
600
600
 
@@ -624,7 +624,7 @@ describe("re-render cleanup", () => {
624
624
  canvas.remove()
625
625
  })
626
626
 
627
- it("showMain is called on successful render", () => {
627
+ it('showMain is called on successful render', () => {
628
628
  const canvas = createCanvas()
629
629
  let mainShown = false
630
630
 
@@ -650,20 +650,20 @@ describe("re-render cleanup", () => {
650
650
 
651
651
  // ─── Missing component in context ───────────────────────────────────────────
652
652
 
653
- describe("missing component in context", () => {
654
- it("preview render throws when context has no component", () => {
653
+ describe('missing component in context', () => {
654
+ it('preview render throws when context has no component', () => {
655
655
  expect(() => previewRender({ value: 1 }, {})).toThrow(
656
- "[@pyreon/storybook] No component provided",
656
+ '[@pyreon/storybook] No component provided',
657
657
  )
658
658
  })
659
659
 
660
- it("preview render throws when context.component is null", () => {
660
+ it('preview render throws when context.component is null', () => {
661
661
  expect(() => previewRender({ value: 1 }, { component: null } as any)).toThrow(
662
- "[@pyreon/storybook] No component provided",
662
+ '[@pyreon/storybook] No component provided',
663
663
  )
664
664
  })
665
665
 
666
- it("renderToCanvas works without component in storyContext when storyFn is provided", () => {
666
+ it('renderToCanvas works without component in storyContext when storyFn is provided', () => {
667
667
  const canvas = createCanvas()
668
668
 
669
669
  renderToCanvas(
@@ -673,7 +673,7 @@ describe("missing component in context", () => {
673
673
  canvas,
674
674
  )
675
675
 
676
- expect(canvas.textContent).toBe("No component needed")
676
+ expect(canvas.textContent).toBe('No component needed')
677
677
  canvas.remove()
678
678
  })
679
679
  })
package/src/types.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ComponentFn, Props, VNodeChild } from "@pyreon/core"
1
+ import type { ComponentFn, Props, VNodeChild } from '@pyreon/core'
2
2
 
3
3
  // ─── Storybook Renderer Interface ────────────────────────────────────────────
4
4
 
@@ -26,7 +26,7 @@ export interface StoryContext<TArgs = Props> {
26
26
  id: string
27
27
  kind: string
28
28
  name: string
29
- viewMode: "story" | "docs"
29
+ viewMode: 'story' | 'docs'
30
30
  }
31
31
 
32
32
  export type StoryFn<TArgs = Props> = (args: TArgs, context: StoryContext<TArgs>) => VNodeChild