@aurelia/storybook 2.1.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +195 -12
  3. package/dist/index.d.ts +25 -0
  4. package/dist/index.js +101 -27
  5. package/dist/index.js.map +1 -1
  6. package/dist/preset.d.ts +21 -0
  7. package/dist/preset.js +74 -20
  8. package/dist/preset.js.map +1 -1
  9. package/dist/preview/helpers.d.ts +2 -0
  10. package/dist/preview/helpers.js +6 -0
  11. package/dist/preview/helpers.js.map +1 -0
  12. package/dist/preview/render.d.ts +7 -0
  13. package/dist/preview/render.js +99 -28
  14. package/dist/preview/render.js.map +1 -1
  15. package/dist/preview/storybook-types-runtime.d.ts +1 -0
  16. package/dist/preview/storybook-types-runtime.js +5 -0
  17. package/dist/preview/storybook-types-runtime.js.map +1 -0
  18. package/dist/preview/storybook-types.d.ts +27 -0
  19. package/dist/preview/types-runtime.d.ts +1 -0
  20. package/dist/preview/types-runtime.js +5 -0
  21. package/dist/preview/types-runtime.js.map +1 -0
  22. package/dist/preview/types.d.ts +44 -0
  23. package/dist/preview.d.ts +3 -0
  24. package/dist/preview.js +104 -29
  25. package/dist/preview.js.map +1 -1
  26. package/dist/webpack.d.ts +10 -0
  27. package/dist/webpack.js +19 -1
  28. package/dist/webpack.js.map +1 -1
  29. package/package.json +75 -15
  30. package/preset.js +2 -1
  31. package/CONTINUITY.md +0 -22
  32. package/__tests__/preset.test.ts +0 -49
  33. package/__tests__/preview.test.ts +0 -139
  34. package/__tests__/render.test.ts +0 -187
  35. package/__tests__/webpack.test.ts +0 -21
  36. package/apps/hello-world/.storybook/main.ts +0 -49
  37. package/apps/hello-world/.storybook/preview.ts +0 -1
  38. package/apps/hello-world/.stylelintrc.json +0 -5
  39. package/apps/hello-world/README.md +0 -28
  40. package/apps/hello-world/eslint.config.mjs +0 -25
  41. package/apps/hello-world/favicon.ico +0 -0
  42. package/apps/hello-world/index.html +0 -17
  43. package/apps/hello-world/package-lock.json +0 -9307
  44. package/apps/hello-world/package.json +0 -55
  45. package/apps/hello-world/src/components/feedback-form.html +0 -111
  46. package/apps/hello-world/src/components/feedback-form.ts +0 -45
  47. package/apps/hello-world/src/components/notification-center.html +0 -119
  48. package/apps/hello-world/src/components/notification-center.ts +0 -27
  49. package/apps/hello-world/src/components/stat-card.html +0 -107
  50. package/apps/hello-world/src/components/stat-card.ts +0 -33
  51. package/apps/hello-world/src/components/weather-widget.html +0 -89
  52. package/apps/hello-world/src/components/weather-widget.ts +0 -30
  53. package/apps/hello-world/src/hello-world.html +0 -48
  54. package/apps/hello-world/src/hello-world.ts +0 -17
  55. package/apps/hello-world/src/main.ts +0 -6
  56. package/apps/hello-world/src/my-app.html +0 -1
  57. package/apps/hello-world/src/my-app.ts +0 -3
  58. package/apps/hello-world/src/resource.d.ts +0 -15
  59. package/apps/hello-world/src/services/weather-service.ts +0 -15
  60. package/apps/hello-world/src/stories/feedback-form.stories.ts +0 -52
  61. package/apps/hello-world/src/stories/hello-world.stories.ts +0 -53
  62. package/apps/hello-world/src/stories/notification-center.stories.ts +0 -81
  63. package/apps/hello-world/src/stories/stat-card.stories.ts +0 -65
  64. package/apps/hello-world/src/stories/weather-widget.stories.ts +0 -57
  65. package/apps/hello-world/test/my-app.spec.ts +0 -15
  66. package/apps/hello-world/test/setup.ts +0 -29
  67. package/apps/hello-world/tsconfig.json +0 -19
  68. package/apps/hello-world/tsconfig.vitest.json +0 -11
  69. package/apps/hello-world/vite.config.ts +0 -17
  70. package/apps/hello-world/vitest.config.ts +0 -15
  71. package/apps/hello-world-webpack/.env.development +0 -0
  72. package/apps/hello-world-webpack/.storybook/main.ts +0 -14
  73. package/apps/hello-world-webpack/.storybook/preview.ts +0 -3
  74. package/apps/hello-world-webpack/.stylelintrc.json +0 -5
  75. package/apps/hello-world-webpack/README.md +0 -29
  76. package/apps/hello-world-webpack/eslint.config.mjs +0 -25
  77. package/apps/hello-world-webpack/favicon.ico +0 -0
  78. package/apps/hello-world-webpack/index.html +0 -15
  79. package/apps/hello-world-webpack/package-lock.json +0 -9853
  80. package/apps/hello-world-webpack/package.json +0 -51
  81. package/apps/hello-world-webpack/src/components/feedback-form.html +0 -111
  82. package/apps/hello-world-webpack/src/components/feedback-form.ts +0 -45
  83. package/apps/hello-world-webpack/src/components/notification-center.html +0 -119
  84. package/apps/hello-world-webpack/src/components/notification-center.ts +0 -27
  85. package/apps/hello-world-webpack/src/components/stat-card.html +0 -107
  86. package/apps/hello-world-webpack/src/components/stat-card.ts +0 -33
  87. package/apps/hello-world-webpack/src/components/weather-widget.html +0 -89
  88. package/apps/hello-world-webpack/src/components/weather-widget.ts +0 -30
  89. package/apps/hello-world-webpack/src/hello-world.html +0 -48
  90. package/apps/hello-world-webpack/src/hello-world.ts +0 -17
  91. package/apps/hello-world-webpack/src/main.ts +0 -6
  92. package/apps/hello-world-webpack/src/my-app.css +0 -3
  93. package/apps/hello-world-webpack/src/my-app.html +0 -1
  94. package/apps/hello-world-webpack/src/my-app.stories.ts +0 -15
  95. package/apps/hello-world-webpack/src/my-app.ts +0 -3
  96. package/apps/hello-world-webpack/src/resource.d.ts +0 -13
  97. package/apps/hello-world-webpack/src/services/weather-service.ts +0 -15
  98. package/apps/hello-world-webpack/src/stories/feedback-form.stories.ts +0 -52
  99. package/apps/hello-world-webpack/src/stories/hello-world.stories.ts +0 -53
  100. package/apps/hello-world-webpack/src/stories/notification-center.stories.ts +0 -81
  101. package/apps/hello-world-webpack/src/stories/stat-card.stories.ts +0 -65
  102. package/apps/hello-world-webpack/src/stories/weather-widget.stories.ts +0 -57
  103. package/apps/hello-world-webpack/tsconfig.json +0 -18
  104. package/apps/hello-world-webpack/webpack.config.js +0 -111
  105. package/dist/preview/types.js +0 -2
  106. package/dist/preview/types.js.map +0 -1
  107. package/jest.config.js +0 -9
  108. package/rollup.config.mjs +0 -50
  109. package/src/index.ts +0 -32
  110. package/src/preset.ts +0 -49
  111. package/src/preview/render.ts +0 -175
  112. package/src/preview/types.ts +0 -7
  113. package/src/preview.ts +0 -1
  114. package/src/webpack.ts +0 -21
  115. package/tsconfig.build.json +0 -5
  116. package/tsconfig.json +0 -15
package/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ ## [2.3.0](https://github.com/aurelia/storybook/compare/v2.2.1...v2.3.0) (2026-06-02)
2
+
3
+ ### Features
4
+
5
+ * **package:** update storybook and deps ([a79e567](https://github.com/aurelia/storybook/commit/a79e5674fe13b8ebe0eb6542d03f4b6742196ff9))
6
+
7
+ ## [2.2.1](https://github.com/aurelia/storybook/compare/2.1.0...2.2.1) (2026-01-23)
8
+
9
+ ### Features
10
+
11
+ * **storybook:** update packages, tooling, rsbuild support ([3a97a99](https://github.com/aurelia/storybook/commit/3a97a9950693183b5880756a943e620895f9457b))
package/README.md CHANGED
@@ -1,23 +1,23 @@
1
1
  # @aurelia/storybook
2
2
 
3
- > **Note:** Storybook support is still early-stage. Expect a few rough edges while Aurelia 2 finishes its beta cycle, and please report anything that feels off.
3
+ > **Note:** Storybook support is still release-candidate stage. Please report anything that feels off while Aurelia 2 and Storybook 10 continue to settle.
4
4
 
5
- `@aurelia/storybook` is the glue between Aurelia 2 components and Storybook 10. It wires Aurelia's `enhance()` API into Storybook's rendering pipeline so you can preview, test, and document your components with either the Vite or Webpack builders.
5
+ `@aurelia/storybook` is the glue between Aurelia 2 components and Storybook 10. It wires an Aurelia app into Storybook's rendering pipeline so you can preview, test, and document your components with Vite, Webpack, or Rsbuild/Rspack.
6
6
 
7
7
  ## Compatibility at a Glance
8
8
 
9
9
  | Item | Supported versions | Notes |
10
10
  | --- | --- | --- |
11
- | Storybook | 10.x (ESM) | Tested with 10.0.5+; works with `storybook dev`/`storybook build` commands. |
12
- | Aurelia | 2.0.0-beta.25+ | Uses Aurelia's `enhance()` APIs under the hood. |
13
- | Bundlers | `@storybook/builder-vite` (Vite 5) · `@storybook/builder-webpack5` | Pick whichever matches your app; both share the same Aurelia preview runtime. |
11
+ | Storybook | 10.x (ESM) | Tested with 10.4.x; works with `storybook dev`/`storybook build` commands. |
12
+ | Aurelia | 2.0.0-rc.1+ | Uses Aurelia's app APIs under the hood. |
13
+ | Bundlers | `@storybook/builder-vite` (Vite 5-8) · `@storybook/builder-webpack5` · `storybook-builder-rsbuild` (Rsbuild/Rspack) | Pick whichever matches your app; they share the same Aurelia preview runtime. |
14
14
  | Node.js | ≥ 20.19.0 or ≥ 22.12.0 | Matches the engines field in `package.json` and Storybook 10's baseline.
15
15
 
16
16
  ## Requirements
17
17
 
18
- - An Aurelia 2 application (TypeScript or JavaScript) already set up with either Vite or Webpack.
18
+ - An Aurelia 2 application (TypeScript or JavaScript) already set up with Vite, Webpack, or Rsbuild/Rspack.
19
19
  - Storybook 10.x installed in the project. (Run `npx storybook@latest init` if you are starting fresh.)
20
- - The peer dependencies listed in [`package.json`](package.json) that align with the Aurelia 2 beta train you are targeting.
20
+ - The peer dependencies listed in [`package.json`](package.json) that align with the Aurelia 2 release-candidate train you are targeting.
21
21
 
22
22
  ## Installation
23
23
 
@@ -25,6 +25,8 @@
25
25
  npm install --save-dev @aurelia/storybook storybook @storybook/builder-vite
26
26
  # or, for Webpack builds:
27
27
  npm install --save-dev @aurelia/storybook storybook @storybook/builder-webpack5
28
+ # or, for Rsbuild/Rspack builds:
29
+ npm install --save-dev @aurelia/storybook storybook storybook-builder-rsbuild @rsbuild/core
28
30
  ```
29
31
 
30
32
  Add whichever addons you need (`@storybook/addon-links`, `@storybook/addon-actions`, etc.). Essentials functionality now ships with Storybook 10 core, so most projects only add optional extras.
@@ -43,7 +45,7 @@ Add whichever addons you need (`@storybook/addon-links`, `@storybook/addon-actio
43
45
 
44
46
  const config: StorybookConfig & { viteFinal?: (config: InlineConfig) => InlineConfig | Promise<InlineConfig> } = {
45
47
  stories: ['../src/stories/**/*.stories.@(ts|tsx|js|jsx|mdx)'],
46
- addons: ['@storybook/addon-links'],
48
+ addons: [],
47
49
  framework: {
48
50
  name: '@aurelia/storybook',
49
51
  options: {},
@@ -52,7 +54,7 @@ Add whichever addons you need (`@storybook/addon-links`, `@storybook/addon-actio
52
54
  builder: '@storybook/builder-vite',
53
55
  },
54
56
  viteFinal: async (viteConfig) => {
55
- // Ensure problematic Aurelia deps are excluded from pre-bundling.
57
+ // Optional: extend this when your app needs extra Vite config.
56
58
  viteConfig.optimizeDeps = viteConfig.optimizeDeps ?? {};
57
59
  viteConfig.optimizeDeps.exclude = Array.from(new Set([...(viteConfig.optimizeDeps.exclude ?? []), '@aurelia/runtime-html']));
58
60
 
@@ -67,8 +69,7 @@ Add whichever addons you need (`@storybook/addon-links`, `@storybook/addon-actio
67
69
  export default config;
68
70
  ```
69
71
 
70
- - Excluding `@aurelia/runtime-html` keeps Vite from trying to pre-bundle Aurelia's DOM runtime, which is already ESM friendly.
71
- - The `define` shim avoids `process is not defined` errors when Storybook code (or Aurelia plugins) look for `process.env.NODE_ENV` in the preview iframe.
72
+ The Aurelia preset already excludes `@aurelia/runtime-html` from pre-bundling and defines `process.env.NODE_ENV`; keep a `viteFinal` hook only when your app needs to merge additional Vite settings.
72
73
 
73
74
  3. **Create `.storybook/preview.ts`:**
74
75
 
@@ -100,7 +101,7 @@ Add whichever addons you need (`@storybook/addon-links`, `@storybook/addon-actio
100
101
 
101
102
  const config: StorybookConfig = {
102
103
  stories: ['../src/**/*.stories.@(ts|tsx|js|jsx|mdx)'],
103
- addons: ['@storybook/addon-links'],
104
+ addons: [],
104
105
  framework: {
105
106
  name: '@aurelia/storybook',
106
107
  options: {},
@@ -119,6 +120,37 @@ Add whichever addons you need (`@storybook/addon-links`, `@storybook/addon-actio
119
120
 
120
121
  ---
121
122
 
123
+ ## Quick Start (Rsbuild/Rspack Builder)
124
+
125
+ 1. Install `storybook-builder-rsbuild` and `@rsbuild/core`.
126
+ 2. Create `.storybook/main.ts`:
127
+
128
+ ```ts
129
+ import type { StorybookConfig } from 'storybook/internal/types';
130
+
131
+ const config: StorybookConfig = {
132
+ stories: ['../src/**/*.stories.@(ts|tsx|js|jsx|mdx)'],
133
+ addons: [],
134
+ framework: {
135
+ name: '@aurelia/storybook',
136
+ options: {},
137
+ },
138
+ core: {
139
+ builder: 'storybook-builder-rsbuild',
140
+ },
141
+ };
142
+
143
+ export default config;
144
+ ```
145
+
146
+ The Aurelia preset injects `@aurelia/webpack-loader` via `rsbuildFinal`,
147
+ so most projects do not need extra Rsbuild configuration. If you do, add your own `rsbuildFinal`
148
+ and merge with `@rsbuild/core`'s `mergeRsbuildConfig`.
149
+
150
+ 3. Reuse the same `.storybook/preview.ts` and `package.json` scripts as in the Vite quick start.
151
+
152
+ ---
153
+
122
154
  ## Writing Aurelia Stories
123
155
 
124
156
  Story files look exactly like standard Storybook CSF stories. The framework export automatically:
@@ -178,6 +210,22 @@ export const WithCustomTemplate = {
178
210
  };
179
211
  ```
180
212
 
213
+ ### Helper for Typed Story Results
214
+
215
+ If you want stronger typing (especially for `props`), you can use the helper and types exported by the package:
216
+
217
+ ```ts
218
+ import { defineAureliaStory, type AureliaStoryResult } from '@aurelia/storybook';
219
+
220
+ const render = (args: { title: string }): AureliaStoryResult<{ title: string }> =>
221
+ defineAureliaStory({
222
+ template: `<my-card title.bind="title"></my-card>`,
223
+ props: args,
224
+ });
225
+ ```
226
+
227
+ You can also import directly from `@aurelia/storybook/preview` or `@aurelia/storybook/preview/types` if you prefer.
228
+
181
229
  ### Story Result Contract
182
230
 
183
231
  When you provide a custom `render` function, return an object with any of the following fields. The Aurelia runtime consumes them while creating the preview app:
@@ -220,10 +268,122 @@ export const WithServices = {
220
268
 
221
269
  Because the Aurelia app lives for the lifetime of the story iframe, DI registrations persist until the story is torn down or Storybook forces a remount. If you need a clean state between stories, set `parameters: { forceRemount: true }` on the story or click the *Remount component* toolbar button in Storybook.
222
270
 
271
+ ### Global Aurelia Configuration (Preview + Story Parameters)
272
+
273
+ You can register global resources/plugins and customize the DI container via Storybook parameters. The framework reads `parameters.aurelia` from the merged Storybook context (preview + component + story):
274
+
275
+ ```ts
276
+ // .storybook/preview.ts
277
+ import { Registration } from 'aurelia';
278
+ import { CurrencyValueConverter } from '../src/resources/currency';
279
+ import { FeatureFlags } from '../src/services/feature-flags';
280
+
281
+ export const parameters = {
282
+ aurelia: {
283
+ register: [CurrencyValueConverter],
284
+ configureContainer: (container) => {
285
+ container.register(Registration.instance(FeatureFlags, { beta: true }));
286
+ },
287
+ },
288
+ };
289
+ ```
290
+
291
+ You can also override or extend per story:
292
+
293
+ ```ts
294
+ export const WithOverrides = {
295
+ parameters: {
296
+ aurelia: {
297
+ configureContainer: (container) => {
298
+ container.register(Registration.instance('apiBaseUrl', 'https://staging.example.com'));
299
+ },
300
+ },
301
+ },
302
+ };
303
+ ```
304
+
305
+ These hooks run when the Aurelia app is created. If you rely on different container setups per story, use `parameters: { forceRemount: true }` to ensure a fresh app instance.
306
+
307
+ #### Parameters API (Quick Reference)
308
+
309
+ ```ts
310
+ export const parameters = {
311
+ aurelia: {
312
+ // Register global resources/plugins
313
+ register: [MyElement, MyValueConverter],
314
+ // Optional aliases for parity with story results
315
+ components: [MyElement],
316
+ items: [Registration.instance(MyService, new MyService())],
317
+ // Configure the DI container
318
+ configureContainer: (container, context) => {
319
+ // ...
320
+ },
321
+ // Configure the Aurelia instance
322
+ configure: (aurelia, context) => {
323
+ // ...
324
+ },
325
+ },
326
+ };
327
+ ```
328
+
329
+ ## Cookbook
330
+
331
+ ### 1) Register global resources once
332
+
333
+ ```ts
334
+ // .storybook/preview.ts
335
+ import { Registration } from 'aurelia';
336
+ import { CurrencyValueConverter } from '../src/resources/currency';
337
+ import { FeatureFlags } from '../src/services/feature-flags';
338
+
339
+ export const parameters = {
340
+ aurelia: {
341
+ register: [CurrencyValueConverter],
342
+ configureContainer: (container) => {
343
+ container.register(Registration.instance(FeatureFlags, { beta: true }));
344
+ },
345
+ },
346
+ };
347
+ ```
348
+
349
+ ### 2) Mock a service per story
350
+
351
+ ```ts
352
+ import { Registration } from 'aurelia';
353
+ import { IWeatherService } from '../src/services/weather-service';
354
+
355
+ export const WithMockedService = {
356
+ render: (args) =>
357
+ defineAureliaStory({
358
+ template: `<weather-widget location.bind="location"></weather-widget>`,
359
+ props: args,
360
+ items: [
361
+ Registration.instance(IWeatherService, {
362
+ getWeather: async () => ({ location: 'Seattle', condition: 'Sunny' }),
363
+ }),
364
+ ],
365
+ }),
366
+ };
367
+ ```
368
+
369
+ ### 3) Force a clean DI container per story
370
+
371
+ ```ts
372
+ export const CleanState = {
373
+ parameters: { forceRemount: true },
374
+ render: (args) =>
375
+ defineAureliaStory({
376
+ template: `<my-component value.bind="value"></my-component>`,
377
+ props: args,
378
+ }),
379
+ };
380
+ ```
381
+
223
382
  ## Example Apps Inside This Repo
224
383
 
225
384
  - `apps/hello-world` – Vite-based Aurelia starter that consumes `@aurelia/storybook`.
226
385
  - `apps/hello-world-webpack` – Equivalent Webpack example.
386
+ - `apps/hello-world-rsbuild` – Rsbuild/Rspack example for projects using `storybook-builder-rsbuild`.
227
387
 
228
388
  To try them out:
229
389
 
@@ -235,6 +395,10 @@ npm run storybook
235
395
  cd ../hello-world-webpack
236
396
  npm install
237
397
  npm run storybook
398
+
399
+ cd ../hello-world-rsbuild
400
+ npm install
401
+ npm run storybook
238
402
  ```
239
403
 
240
404
  Each sample project now includes a small library of showcase stories you can open in Storybook to see different aspects of the integration:
@@ -265,6 +429,25 @@ This repository publishes the Storybook framework itself. Helpful scripts:
265
429
 
266
430
  While developing, you can link the package into one of the sample apps in `apps/` to manual-test Storybook changes end to end.
267
431
 
432
+ ## Releases & Changelog
433
+
434
+ - Keep `CHANGELOG.md` updated for each release (use the **Unreleased** section while working).
435
+ - Align example app versions with the root package before tagging:
436
+ - `npm run sync:versions`
437
+ - Tag releases as `vX.Y.Z` so the publish workflow can run.
438
+
439
+ Publish flow (automated via GitHub Actions):
440
+ 1. Update `package.json` version.
441
+ 2. Generate `CHANGELOG.md` from conventional commits: `npm run changelog`.
442
+ 3. Run `npm run sync:versions` and commit changes.
443
+ 4. Create tag `vX.Y.Z` and push it.
444
+
445
+ ## Troubleshooting
446
+
447
+ - **AUR0153 duplicate element registration**: ensure the same component isn't registered multiple times within the same story/container.
448
+ - **Args undefined during first render**: defensively handle optional args in components (e.g., fallbacks for arrays/strings).
449
+ - **Rsbuild `loader.loadModule is not a function`**: avoid `ts-loader` in Rsbuild/Rspack builds; use the built-in Rsbuild TS handling.
450
+
268
451
  ## Contributing
269
452
 
270
453
  Bug reports, docs tweaks, and feature PRs are all welcome. Please open an issue to discuss significant changes, and spin up one of the example apps to verify the behavior you are touching.
@@ -0,0 +1,25 @@
1
+ import { renderToCanvas } from './preview/render';
2
+ import { defineAureliaStory } from './preview/helpers';
3
+ export { renderToCanvas };
4
+ export declare const render: typeof renderToCanvas;
5
+ export { defineAureliaStory };
6
+ export type { AureliaRenderer, AureliaStoryResult, AureliaArgsStoryFn, AureliaRenderContext, AureliaStoryContext, AureliaParameters, AureliaStoryParameters } from './preview/types';
7
+ export declare const framework: {
8
+ name: string;
9
+ options: {};
10
+ };
11
+ export declare const frameworkOptions: {
12
+ builder: {
13
+ name: string;
14
+ options: {};
15
+ };
16
+ };
17
+ export declare const aureliaFramework: {
18
+ name: string;
19
+ options: {};
20
+ builder: string;
21
+ };
22
+ export declare const externals: {
23
+ react: string;
24
+ 'react-dom': string;
25
+ };
package/dist/index.js CHANGED
@@ -1,14 +1,36 @@
1
1
  import Aurelia, { CustomElement } from 'aurelia';
2
2
 
3
- // Track Aurelia apps for cleanup
4
3
  const appMap = new Map();
5
- async function teardown(element) {
6
- if (appMap.has(element)) {
7
- const app = appMap.get(element);
8
- if (app) {
9
- await app.stop();
10
- appMap.delete(element);
11
- }
4
+ function mergeStoryProps(parameters, storyArgs, storyProps) {
5
+ return { ...parameters?.args, ...storyArgs, ...storyProps };
6
+ }
7
+ function getAureliaParameters(storyContext) {
8
+ const parameters = storyContext?.parameters?.aurelia;
9
+ if (!parameters || typeof parameters !== 'object') {
10
+ return undefined;
11
+ }
12
+ return parameters;
13
+ }
14
+ function normalizeRegistrations(parameters) {
15
+ if (!parameters) {
16
+ return [];
17
+ }
18
+ const register = Array.isArray(parameters.register) ? parameters.register : [];
19
+ const components = Array.isArray(parameters.components) ? parameters.components : [];
20
+ const items = Array.isArray(parameters.items) ? parameters.items : [];
21
+ return [...register, ...components, ...items].filter(Boolean);
22
+ }
23
+ async function teardown(element, expectedApp) {
24
+ const mounted = appMap.get(element);
25
+ if (!mounted) {
26
+ return;
27
+ }
28
+ if (expectedApp && mounted.app !== expectedApp) {
29
+ return;
30
+ }
31
+ appMap.delete(element);
32
+ if (typeof mounted.app?.stop === 'function') {
33
+ await mounted.app.stop();
12
34
  }
13
35
  }
14
36
  async function renderToCanvas({ storyFn, title, name, showMain, showError, storyContext, forceRemount, }, canvasElement, bootstrapAppFn) {
@@ -31,10 +53,10 @@ async function renderToCanvas({ storyFn, title, name, showMain, showError, story
31
53
  // All app instances are now tracked by the *root* element, ensuring we only ever have one per story iframe
32
54
  const appBootstrapFn = bootstrapAppFn ?? createAureliaApp;
33
55
  const { parameters, component, args } = storyContext;
34
- let app = appMap.get(rootElement);
56
+ const storyId = storyContext.id ?? `${title}--${name}`;
57
+ const mounted = appMap.get(rootElement);
58
+ let app = mounted?.app;
35
59
  const story = storyFn();
36
- // Temporary debug logging
37
- console.log(`[DEBUG] Story: ${name}, forceRemount: ${forceRemount}, hasExistingApp: ${!!app}, canvasId: ${canvasElement.className}`);
38
60
  if (!story) {
39
61
  showError({
40
62
  title: `Expecting an Aurelia component from the story: "${name}" of "${title}".`,
@@ -45,44 +67,87 @@ async function renderToCanvas({ storyFn, title, name, showMain, showError, story
45
67
  });
46
68
  return () => { };
47
69
  }
70
+ if (!component && !story.template) {
71
+ showError({
72
+ title: `Expecting a template or component from the story: "${name}" of "${title}".`,
73
+ description: `
74
+ Provide a component on the default export or return "{ template: '<custom-component></custom-component>' }" from the story.
75
+ `,
76
+ });
77
+ return () => { };
78
+ }
48
79
  showMain();
49
- if (!app || forceRemount) {
80
+ const shouldRemount = !app || forceRemount || mounted?.id !== storyId;
81
+ if (shouldRemount) {
50
82
  if (forceRemount && app) {
51
- await teardown(rootElement);
83
+ await teardown(rootElement, app);
84
+ app = undefined;
85
+ }
86
+ if (mounted?.id !== storyId && app) {
87
+ await teardown(rootElement, app);
52
88
  app = undefined;
53
89
  }
54
90
  // Clear container before mounting new app
55
91
  hostElement.innerHTML = '';
56
- const mergedProps = { ...parameters?.args, ...args, ...story.props };
57
- const aureliaApp = appBootstrapFn(story, mergedProps, hostElement, component);
92
+ const mergedProps = mergeStoryProps(parameters, args, story.props);
93
+ const aureliaApp = appBootstrapFn(story, mergedProps, hostElement, component, storyContext);
58
94
  await aureliaApp.start();
59
- appMap.set(rootElement, aureliaApp);
95
+ appMap.set(rootElement, { id: storyId, app: aureliaApp });
60
96
  app = aureliaApp;
61
97
  }
62
98
  else {
63
99
  // update existing app props
64
- const mergedProps = { ...parameters?.args, ...args, ...story.props };
100
+ const mergedProps = mergeStoryProps(parameters, args, story.props);
65
101
  if (app?.root?.controller?.viewModel) {
66
102
  Object.assign(app.root.controller.viewModel, mergedProps);
67
103
  }
68
104
  }
69
105
  // Return cleanup fn
106
+ const appForCleanup = app;
70
107
  return async () => {
71
- await teardown(rootElement);
108
+ await teardown(rootElement, appForCleanup);
72
109
  };
73
110
  }
74
- function createAureliaApp(story, args, domElement, component) {
111
+ function createAureliaApp(story, args, domElement, component, storyContext) {
75
112
  const aurelia = new Aurelia(story.container);
76
- if (story.items?.length) {
77
- aurelia.register(...story.items);
113
+ const { container } = aurelia;
114
+ const aureliaParameters = getAureliaParameters(storyContext);
115
+ const registerIfNeeded = (resource) => {
116
+ if (!resource) {
117
+ return;
118
+ }
119
+ if (CustomElement.isType(resource)) {
120
+ const definition = CustomElement.getDefinition(resource);
121
+ if (container.has(definition.key, false)) {
122
+ return;
123
+ }
124
+ }
125
+ aurelia.register(resource);
126
+ };
127
+ const registerAll = (resources) => {
128
+ if (!resources?.length) {
129
+ return;
130
+ }
131
+ for (const resource of resources) {
132
+ registerIfNeeded(resource);
133
+ }
134
+ };
135
+ if (aureliaParameters?.configureContainer && storyContext) {
136
+ aureliaParameters.configureContainer(container, storyContext);
78
137
  }
79
- if (story.components?.length) {
80
- aurelia.register(...story.components);
138
+ registerAll(normalizeRegistrations(aureliaParameters));
139
+ registerAll(story.items);
140
+ const storyComponents = (story.components ?? []).filter(Boolean);
141
+ const dedupedComponents = component
142
+ ? storyComponents.filter((entry) => entry !== component)
143
+ : storyComponents;
144
+ for (const entry of dedupedComponents) {
145
+ registerIfNeeded(entry);
81
146
  }
82
147
  let { template } = story;
83
148
  if (component) {
84
149
  template = template ?? createComponentTemplate(component, story.innerHtml);
85
- aurelia.register(component);
150
+ registerIfNeeded(component);
86
151
  }
87
152
  const App = CustomElement.define({
88
153
  name: 'sb-app',
@@ -91,6 +156,9 @@ function createAureliaApp(story, args, domElement, component) {
91
156
  }, class {
92
157
  });
93
158
  const app = Object.assign(new App(), args);
159
+ if (aureliaParameters?.configure && storyContext) {
160
+ aureliaParameters.configure(aurelia, storyContext);
161
+ }
94
162
  return aurelia.app({
95
163
  host: domElement,
96
164
  component: app,
@@ -98,9 +166,15 @@ function createAureliaApp(story, args, domElement, component) {
98
166
  }
99
167
  function createComponentTemplate(component, innerHtml) {
100
168
  const def = CustomElement.getDefinition(component);
101
- return `<${def.name} ${Object.values(def.bindables)
169
+ const bindings = Object.values(def.bindables ?? {})
102
170
  .map((bindable) => `${bindable.attribute}.bind="${bindable.name}"`)
103
- .join(' ')}>${innerHtml ?? ''}</${def.name}>`;
171
+ .join(' ');
172
+ const bindingAttributes = bindings ? ` ${bindings}` : '';
173
+ return `<${def.name}${bindingAttributes}>${innerHtml ?? ''}</${def.name}>`;
174
+ }
175
+
176
+ function defineAureliaStory(story) {
177
+ return story;
104
178
  }
105
179
 
106
180
  const render = renderToCanvas;
@@ -128,5 +202,5 @@ const externals = {
128
202
  'react-dom': 'ReactDOM'
129
203
  };
130
204
 
131
- export { aureliaFramework, externals, framework, frameworkOptions, render, renderToCanvas };
205
+ export { aureliaFramework, defineAureliaStory, externals, framework, frameworkOptions, render, renderToCanvas };
132
206
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/preview/render.ts","../src/index.ts"],"sourcesContent":["import { STORY_CHANGED } from 'storybook/internal/core-events';\nimport type { RenderContext, ArgsStoryFn } from 'storybook/internal/types';\nimport type { AureliaRenderer } from './types';\nimport Aurelia, { Constructable, CustomElement } from 'aurelia';\n\ninterface AureliaStoryResult {\n template: string;\n components?: unknown[];\n Component?: unknown;\n container?: any;\n items?: unknown[];\n innerHtml?: string;\n props?: Record<string, any>;\n}\n\n// Track Aurelia apps for cleanup\nconst appMap = new Map<HTMLElement, any>();\n\nasync function teardown(element: HTMLElement) {\n if (appMap.has(element)) {\n const app = appMap.get(element);\n if (app) {\n await app.stop();\n appMap.delete(element);\n }\n }\n}\n\nexport const render: ArgsStoryFn<AureliaRenderer> = (args, context) => {\n const { id, component: Component } = context;\n \n if (!Component) {\n throw new Error(\n `Unable to render story ${id} as the component annotation is missing from the default export`\n );\n }\n return { Component, props: args, template: '' };\n};\n\nexport async function renderToCanvas(\n {\n storyFn,\n title,\n name,\n showMain,\n showError,\n storyContext,\n forceRemount,\n }: RenderContext<AureliaRenderer>,\n canvasElement: HTMLElement,\n bootstrapAppFn?: typeof createAureliaApp\n) {\n // Store reference to the original storybook root element\n const rootElement = canvasElement;\n\n // Ensure we have (or create) a single container inside the root where the Aurelia app actually renders\n let hostElement: HTMLElement;\n if (rootElement.id === 'storybook-root') {\n hostElement = rootElement.querySelector('.aurelia-story-container') as HTMLElement;\n if (!hostElement) {\n hostElement = document.createElement('div');\n hostElement.className = 'aurelia-story-container';\n hostElement.style.height = '100%';\n rootElement.appendChild(hostElement);\n }\n } else {\n hostElement = rootElement;\n }\n\n // All app instances are now tracked by the *root* element, ensuring we only ever have one per story iframe\n const appBootstrapFn = bootstrapAppFn ?? createAureliaApp;\n const { parameters, component, args } = storyContext;\n \n let app = appMap.get(rootElement);\n const story = storyFn() as AureliaStoryResult;\n \n // Temporary debug logging\n console.log(`[DEBUG] Story: ${name}, forceRemount: ${forceRemount}, hasExistingApp: ${!!app}, canvasId: ${canvasElement.className}`);\n\n if (!story) {\n showError({\n title: `Expecting an Aurelia component from the story: \"${name}\" of \"${title}\".`,\n description: `\n Did you forget to return the Aurelia component from the story?\n Use \"() => ({ template: '<custom-component></custom-component>' })\" when defining the story.\n `,\n });\n return () => {};\n }\n\n showMain();\n\n if (!app || forceRemount) {\n if (forceRemount && app) {\n await teardown(rootElement);\n app = undefined;\n }\n // Clear container before mounting new app\n hostElement.innerHTML = '';\n\n const mergedProps = { ...parameters?.args, ...args, ...story.props };\n\n const aureliaApp = appBootstrapFn(\n story,\n mergedProps,\n hostElement,\n component as Constructable\n );\n await aureliaApp.start();\n appMap.set(rootElement, aureliaApp);\n app = aureliaApp;\n } else {\n // update existing app props\n const mergedProps = { ...parameters?.args, ...args, ...story.props };\n if (app?.root?.controller?.viewModel) {\n Object.assign(app.root.controller.viewModel, mergedProps);\n }\n }\n\n // Return cleanup fn\n return async () => {\n await teardown(rootElement);\n };\n}\n\nexport function createAureliaApp(\n story: AureliaStoryResult,\n args: Record<string, any>,\n domElement: HTMLElement,\n component?: Constructable\n) {\n const aurelia = new Aurelia(story.container);\n\n if (story.items?.length) {\n aurelia.register(...story.items);\n }\n\n if (story.components?.length) {\n aurelia.register(...story.components);\n }\n\n let { template } = story;\n\n if (component) {\n template = template ?? createComponentTemplate(component, story.innerHtml);\n aurelia.register(component);\n }\n\n const App = CustomElement.define(\n {\n name: 'sb-app',\n template,\n containerless: true,\n },\n class {}\n );\n\n const app = Object.assign(new App(), args);\n\n return aurelia.app({\n host: domElement,\n component: app,\n });\n}\n\nexport function createComponentTemplate(\n component: Constructable,\n innerHtml?: string\n): string {\n const def = CustomElement.getDefinition(component);\n\n return `<${def.name} ${Object.values(def.bindables)\n .map((bindable) => `${bindable.attribute}.bind=\"${bindable.name}\"`)\n .join(' ')}>${innerHtml ?? ''}</${def.name}>`;\n}","import type { StorybookConfig } from 'storybook/internal/types';\nimport { renderToCanvas } from './preview/render';\n\nexport { renderToCanvas };\nexport const render = renderToCanvas;\n\n// Define the framework\nexport const framework = {\n name: '@aurelia/storybook',\n options: {}\n};\n\n// Framework configuration for Storybook\nexport const frameworkOptions = {\n builder: {\n name: '@storybook/builder-vite',\n options: {}\n }\n};\n\n// Export a complete framework configuration\nexport const aureliaFramework = {\n name: '@aurelia/storybook',\n options: {},\n builder: '@storybook/builder-vite'\n};\n\n// Provide external dependencies configuration\nexport const externals = {\n 'react': 'React',\n 'react-dom': 'ReactDOM'\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/preview/render.ts","../src/preview/helpers.ts","../src/index.ts"],"sourcesContent":["import type { RenderContext, ArgsStoryFn } from './storybook-types';\nimport type {\n AureliaRenderer,\n AureliaStoryResult,\n AureliaParameters,\n AureliaStoryContext,\n} from './types';\nimport Aurelia, { Constructable, CustomElement } from 'aurelia';\n\ninterface MountedAureliaApp {\n id?: string;\n app: any;\n}\n\nconst appMap = new Map<HTMLElement, MountedAureliaApp>();\n\nfunction mergeStoryProps(\n parameters: { args?: Record<string, any> } | undefined,\n storyArgs: Record<string, any> | undefined,\n storyProps: Record<string, any> | undefined\n) {\n return { ...parameters?.args, ...storyArgs, ...storyProps };\n}\n\nfunction getAureliaParameters(\n storyContext?: AureliaStoryContext\n): AureliaParameters | undefined {\n const parameters = storyContext?.parameters?.aurelia;\n if (!parameters || typeof parameters !== 'object') {\n return undefined;\n }\n return parameters as AureliaParameters;\n}\n\nfunction normalizeRegistrations(\n parameters: AureliaParameters | undefined\n): unknown[] {\n if (!parameters) {\n return [];\n }\n\n const register = Array.isArray(parameters.register) ? parameters.register : [];\n const components = Array.isArray(parameters.components) ? parameters.components : [];\n const items = Array.isArray(parameters.items) ? parameters.items : [];\n\n return [...register, ...components, ...items].filter(Boolean);\n}\n\nasync function teardown(element: HTMLElement, expectedApp?: any) {\n const mounted = appMap.get(element);\n if (!mounted) {\n return;\n }\n\n if (expectedApp && mounted.app !== expectedApp) {\n return;\n }\n\n appMap.delete(element);\n\n if (typeof mounted.app?.stop === 'function') {\n await mounted.app.stop();\n }\n}\n\nexport const render: ArgsStoryFn<AureliaRenderer> = (args, context) => {\n const { id, component: Component } = context;\n \n if (!Component) {\n const label = context.title && context.name ? `${context.title} / ${context.name}` : id;\n throw new Error(\n `Unable to render story ${label} as the component annotation is missing from the default export`\n );\n }\n return { Component, props: args };\n};\n\nexport async function renderToCanvas(\n {\n storyFn,\n title,\n name,\n showMain,\n showError,\n storyContext,\n forceRemount,\n }: RenderContext<AureliaRenderer>,\n canvasElement: HTMLElement,\n bootstrapAppFn?: typeof createAureliaApp\n) {\n // Store reference to the original storybook root element\n const rootElement = canvasElement;\n\n // Ensure we have (or create) a single container inside the root where the Aurelia app actually renders\n let hostElement: HTMLElement;\n if (rootElement.id === 'storybook-root') {\n hostElement = rootElement.querySelector('.aurelia-story-container') as HTMLElement;\n if (!hostElement) {\n hostElement = document.createElement('div');\n hostElement.className = 'aurelia-story-container';\n hostElement.style.height = '100%';\n rootElement.appendChild(hostElement);\n }\n } else {\n hostElement = rootElement;\n }\n\n // All app instances are now tracked by the *root* element, ensuring we only ever have one per story iframe\n const appBootstrapFn = bootstrapAppFn ?? createAureliaApp;\n const { parameters, component, args } = storyContext;\n const storyId = storyContext.id ?? `${title}--${name}`;\n \n const mounted = appMap.get(rootElement);\n let app = mounted?.app;\n const story = storyFn() as AureliaStoryResult;\n \n if (!story) {\n showError({\n title: `Expecting an Aurelia component from the story: \"${name}\" of \"${title}\".`,\n description: `\n Did you forget to return the Aurelia component from the story?\n Use \"() => ({ template: '<custom-component></custom-component>' })\" when defining the story.\n `,\n });\n return () => {};\n }\n\n if (!component && !story.template) {\n showError({\n title: `Expecting a template or component from the story: \"${name}\" of \"${title}\".`,\n description: `\n Provide a component on the default export or return \"{ template: '<custom-component></custom-component>' }\" from the story.\n `,\n });\n return () => {};\n }\n\n showMain();\n\n const shouldRemount = !app || forceRemount || mounted?.id !== storyId;\n\n if (shouldRemount) {\n if (forceRemount && app) {\n await teardown(rootElement, app);\n app = undefined;\n }\n if (mounted?.id !== storyId && app) {\n await teardown(rootElement, app);\n app = undefined;\n }\n\n // Clear container before mounting new app\n hostElement.innerHTML = '';\n\n const mergedProps = mergeStoryProps(parameters, args, story.props);\n\n const aureliaApp = appBootstrapFn(\n story,\n mergedProps,\n hostElement,\n component as Constructable,\n storyContext\n );\n await aureliaApp.start();\n appMap.set(rootElement, { id: storyId, app: aureliaApp });\n app = aureliaApp;\n } else {\n // update existing app props\n const mergedProps = mergeStoryProps(parameters, args, story.props);\n if (app?.root?.controller?.viewModel) {\n Object.assign(app.root.controller.viewModel, mergedProps);\n }\n }\n\n // Return cleanup fn\n const appForCleanup = app;\n return async () => {\n await teardown(rootElement, appForCleanup);\n };\n}\n\nexport function createAureliaApp(\n story: AureliaStoryResult,\n args: Record<string, any>,\n domElement: HTMLElement,\n component?: Constructable,\n storyContext?: AureliaStoryContext\n) {\n const aurelia = new Aurelia(story.container);\n const { container } = aurelia;\n const aureliaParameters = getAureliaParameters(storyContext);\n\n const registerIfNeeded = (resource: unknown) => {\n if (!resource) {\n return;\n }\n\n if (CustomElement.isType(resource)) {\n const definition = CustomElement.getDefinition(resource);\n if (container.has(definition.key, false)) {\n return;\n }\n }\n\n aurelia.register(resource);\n };\n\n const registerAll = (resources?: unknown[]) => {\n if (!resources?.length) {\n return;\n }\n\n for (const resource of resources) {\n registerIfNeeded(resource);\n }\n };\n\n if (aureliaParameters?.configureContainer && storyContext) {\n aureliaParameters.configureContainer(container, storyContext);\n }\n\n registerAll(normalizeRegistrations(aureliaParameters));\n registerAll(story.items);\n\n const storyComponents = (story.components ?? []).filter(Boolean);\n const dedupedComponents = component\n ? storyComponents.filter((entry) => entry !== component)\n : storyComponents;\n\n for (const entry of dedupedComponents) {\n registerIfNeeded(entry);\n }\n\n let { template } = story;\n\n if (component) {\n template = template ?? createComponentTemplate(component, story.innerHtml);\n registerIfNeeded(component);\n }\n\n const App = CustomElement.define(\n {\n name: 'sb-app',\n template,\n containerless: true,\n },\n class {}\n );\n\n const app = Object.assign(new App(), args);\n\n if (aureliaParameters?.configure && storyContext) {\n aureliaParameters.configure(aurelia, storyContext);\n }\n\n return aurelia.app({\n host: domElement,\n component: app,\n });\n}\n\nexport function createComponentTemplate(\n component: Constructable,\n innerHtml?: string\n): string {\n const def = CustomElement.getDefinition(component);\n\n const bindings = Object.values(def.bindables ?? {})\n .map((bindable) => `${bindable.attribute}.bind=\"${bindable.name}\"`)\n .join(' ');\n const bindingAttributes = bindings ? ` ${bindings}` : '';\n\n return `<${def.name}${bindingAttributes}>${innerHtml ?? ''}</${def.name}>`;\n}\n","import type { AureliaStoryResult } from './types';\n\nexport function defineAureliaStory<TArgs = Record<string, unknown>>(\n story: AureliaStoryResult<TArgs>\n): AureliaStoryResult<TArgs> {\n return story;\n}\n","import { renderToCanvas } from './preview/render';\nimport { defineAureliaStory } from './preview/helpers';\n\nexport { renderToCanvas };\nexport const render = renderToCanvas;\nexport { defineAureliaStory };\nexport type {\n AureliaRenderer,\n AureliaStoryResult,\n AureliaArgsStoryFn,\n AureliaRenderContext,\n AureliaStoryContext,\n AureliaParameters,\n AureliaStoryParameters\n} from './preview/types';\n\n// Define the framework\nexport const framework = {\n name: '@aurelia/storybook',\n options: {}\n};\n\n// Framework configuration for Storybook\nexport const frameworkOptions = {\n builder: {\n name: '@storybook/builder-vite',\n options: {}\n }\n};\n\n// Export a complete framework configuration\nexport const aureliaFramework = {\n name: '@aurelia/storybook',\n options: {},\n builder: '@storybook/builder-vite'\n};\n\n// Provide external dependencies configuration\nexport const externals = {\n 'react': 'React',\n 'react-dom': 'ReactDOM'\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Optionally adjust the Vite configuration.
3
+ */
4
+ export declare function viteFinal(config: any): Promise<any>;
5
+ /**
6
+ * Optionally adjust the Rsbuild configuration (Rspack-based).
7
+ */
8
+ export declare function rsbuildFinal(config: any): Promise<any>;
9
+ /**
10
+ * A function to configure webpack.
11
+ * @param config
12
+ * @returns
13
+ */
14
+ export declare function webpackFinal(config: any): Promise<any>;
15
+ declare const _default: {
16
+ viteFinal: typeof viteFinal;
17
+ rsbuildFinal: typeof rsbuildFinal;
18
+ webpackFinal: typeof webpackFinal;
19
+ };
20
+ export default _default;
21
+ export declare const previewAnnotations: string[];