@aurelia/storybook 1.0.0 → 1.0.2

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 (36) hide show
  1. package/README.md +29 -33
  2. package/__tests__/render.test.ts +1 -1
  3. package/apps/hello-world/.storybook/main.ts +32 -12
  4. package/apps/hello-world/package-lock.json +7448 -0
  5. package/apps/hello-world/package.json +10 -10
  6. package/apps/hello-world/src/stories/hello-world.stories.ts +11 -10
  7. package/apps/hello-world-webpack/.storybook/main.ts +1 -4
  8. package/apps/hello-world-webpack/package-lock.json +380 -3515
  9. package/apps/hello-world-webpack/package.json +9 -10
  10. package/apps/hello-world-webpack/src/hello-world.html +6 -0
  11. package/apps/hello-world-webpack/src/hello-world.ts +17 -0
  12. package/apps/hello-world-webpack/src/my-app.stories.ts +10 -7
  13. package/apps/hello-world-webpack/src/stories/hello-world.stories.ts +54 -0
  14. package/dist/index.js +65 -38
  15. package/dist/index.js.map +1 -1
  16. package/dist/index.mjs +62 -39
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/preset.js +15 -1
  19. package/dist/preset.js.map +1 -1
  20. package/dist/preset.mjs +15 -1
  21. package/dist/preset.mjs.map +1 -1
  22. package/dist/preview/render.js +41 -40
  23. package/dist/preview/render.js.map +1 -1
  24. package/dist/preview/render.mjs +41 -40
  25. package/dist/preview/render.mjs.map +1 -1
  26. package/dist/preview.js +81 -39
  27. package/dist/preview.js.map +1 -1
  28. package/dist/preview.mjs +81 -40
  29. package/dist/preview.mjs.map +1 -1
  30. package/package.json +6 -10
  31. package/rollup.config.mjs +6 -4
  32. package/src/index.ts +28 -0
  33. package/src/preset.ts +19 -1
  34. package/src/preview/render.ts +51 -49
  35. package/src/preview/types.ts +1 -1
  36. package/src/preview.ts +1 -50
@@ -1,15 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var coreEvents = require('@storybook/core-events');
4
3
  var Aurelia = require('aurelia');
5
4
 
6
- /**
7
- * Merges multiple sources into a single object.
8
- * Sources can be story parameters, args, or story.props.
9
- */
10
- function mergeStoryProps(...sources) {
11
- return Object.assign({}, ...sources);
12
- }
13
5
  // Track Aurelia apps for cleanup
14
6
  const appMap = new Map();
15
7
  async function teardown(element) {
@@ -21,17 +13,37 @@ async function teardown(element) {
21
13
  }
22
14
  }
23
15
  }
24
- const render = (args, { id, component: Component }) => {
16
+ const render = (args, context) => {
17
+ const { id, component: Component } = context;
25
18
  if (!Component) {
26
19
  throw new Error(`Unable to render story ${id} as the component annotation is missing from the default export`);
27
20
  }
28
21
  return { Component, props: args, template: '' };
29
22
  };
30
23
  async function renderToCanvas({ storyFn, title, name, showMain, showError, storyContext, forceRemount, }, canvasElement, bootstrapAppFn) {
31
- const appBootstrapFn = bootstrapAppFn || bootstrapAureliaApp;
24
+ // Store reference to the original storybook root element
25
+ const rootElement = canvasElement;
26
+ // Ensure we have (or create) a single container inside the root where the Aurelia app actually renders
27
+ let hostElement;
28
+ if (rootElement.id === 'storybook-root') {
29
+ hostElement = rootElement.querySelector('.aurelia-story-container');
30
+ if (!hostElement) {
31
+ hostElement = document.createElement('div');
32
+ hostElement.className = 'aurelia-story-container';
33
+ hostElement.style.height = '100%';
34
+ rootElement.appendChild(hostElement);
35
+ }
36
+ }
37
+ else {
38
+ hostElement = rootElement;
39
+ }
40
+ // All app instances are now tracked by the *root* element, ensuring we only ever have one per story iframe
41
+ const appBootstrapFn = bootstrapAppFn ?? createAureliaApp;
32
42
  const { parameters, component, args } = storyContext;
33
- let app = appMap.get(canvasElement);
43
+ let app = appMap.get(rootElement);
34
44
  const story = storyFn();
45
+ // Temporary debug logging
46
+ console.log(`[DEBUG] Story: ${name}, forceRemount: ${forceRemount}, hasExistingApp: ${!!app}, canvasId: ${canvasElement.className}`);
35
47
  if (!story) {
36
48
  showError({
37
49
  title: `Expecting an Aurelia component from the story: "${name}" of "${title}".`,
@@ -43,43 +55,32 @@ async function renderToCanvas({ storyFn, title, name, showMain, showError, story
43
55
  return () => { };
44
56
  }
45
57
  showMain();
46
- let mergedProps;
47
- // Use full merge (including story.props) when bootstrapping a new app or force remounting.
48
58
  if (!app || forceRemount) {
49
- mergedProps = mergeStoryProps(parameters?.args, args, story.props);
50
- if (app) {
51
- await teardown(canvasElement);
59
+ if (forceRemount && app) {
60
+ await teardown(rootElement);
61
+ app = undefined;
52
62
  }
53
- app = appBootstrapFn(story, mergedProps, canvasElement, component);
54
- await app.start();
55
- appMap.set(canvasElement, app);
63
+ // Clear container before mounting new app
64
+ hostElement.innerHTML = '';
65
+ const mergedProps = { ...parameters?.args, ...args, ...story.props };
66
+ const aureliaApp = appBootstrapFn(story, mergedProps, hostElement, component);
67
+ await aureliaApp.start();
68
+ appMap.set(rootElement, aureliaApp);
69
+ app = aureliaApp;
56
70
  }
57
71
  else {
58
- // Update the existing app viewModel only with parameters and args (exclude story.props).
59
- mergedProps = mergeStoryProps(parameters?.args, args);
60
- if (app.root?.controller?.viewModel) {
72
+ // update existing app props
73
+ const mergedProps = { ...parameters?.args, ...args, ...story.props };
74
+ if (app?.root?.controller?.viewModel) {
61
75
  Object.assign(app.root.controller.viewModel, mergedProps);
62
76
  }
63
77
  }
64
- // Set up story change listener for cleanup
65
- const channel = storyContext.viewMode === 'story' ? storyContext.channel : null;
66
- let onStoryChange;
67
- if (channel) {
68
- onStoryChange = () => {
69
- // When the story changes, clean up the Aurelia app
70
- teardown(canvasElement);
71
- };
72
- channel.on(coreEvents.STORY_CHANGED, onStoryChange);
73
- }
74
- // Return teardown function that also unsubscribes from STORY_CHANGED
78
+ // Return cleanup fn
75
79
  return async () => {
76
- if (channel && onStoryChange) {
77
- channel.off(coreEvents.STORY_CHANGED, onStoryChange);
78
- }
79
- await teardown(canvasElement);
80
+ await teardown(rootElement);
80
81
  };
81
82
  }
82
- function bootstrapAureliaApp(story, args, domElement, component) {
83
+ function createAureliaApp(story, args, domElement, component) {
83
84
  const aurelia = new Aurelia(story.container);
84
85
  if (story.items?.length) {
85
86
  aurelia.register(...story.items);
@@ -93,7 +94,7 @@ function bootstrapAureliaApp(story, args, domElement, component) {
93
94
  aurelia.register(component);
94
95
  }
95
96
  const App = Aurelia.CustomElement.define({
96
- name: 'au-storybook',
97
+ name: 'sb-app',
97
98
  template,
98
99
  containerless: true,
99
100
  }, class {
@@ -111,7 +112,7 @@ function createComponentTemplate(component, innerHtml) {
111
112
  .join(' ')}>${innerHtml ?? ''}</${def.name}>`;
112
113
  }
113
114
 
114
- exports.bootstrapAureliaApp = bootstrapAureliaApp;
115
+ exports.createAureliaApp = createAureliaApp;
115
116
  exports.createComponentTemplate = createComponentTemplate;
116
117
  exports.render = render;
117
118
  exports.renderToCanvas = renderToCanvas;
@@ -1 +1 @@
1
- {"version":3,"file":"render.js","sources":["../../src/preview/render.ts"],"sourcesContent":["import { STORY_CHANGED } from '@storybook/core-events';\nimport type { RenderContext, ArgsStoryFn } from '@storybook/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/**\n * Merges multiple sources into a single object.\n * Sources can be story parameters, args, or story.props.\n */\nfunction mergeStoryProps(\n ...sources: Array<Record<string, any> | undefined>\n): Record<string, any> {\n return Object.assign({}, ...sources);\n}\n\n// Track Aurelia apps for cleanup\nconst appMap = new Map<HTMLElement, Aurelia>();\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, { id, component: Component }) => {\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 bootstrapAureliaApp\n) {\n const appBootstrapFn = bootstrapAppFn || bootstrapAureliaApp;\n\n const { parameters, component, args } = storyContext;\n let app = appMap.get(canvasElement);\n\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 showMain();\n\n let mergedProps;\n // Use full merge (including story.props) when bootstrapping a new app or force remounting.\n if (!app || forceRemount) {\n mergedProps = mergeStoryProps(parameters?.args, args, story.props);\n if (app) {\n await teardown(canvasElement);\n }\n app = appBootstrapFn(\n story,\n mergedProps,\n canvasElement,\n component as Constructable\n ) as Aurelia;\n await app.start();\n appMap.set(canvasElement, app);\n } else {\n // Update the existing app viewModel only with parameters and args (exclude story.props).\n mergedProps = mergeStoryProps(parameters?.args, args);\n if (app.root?.controller?.viewModel) {\n Object.assign(app.root.controller.viewModel, mergedProps);\n }\n }\n\n // Set up story change listener for cleanup\n const channel = storyContext.viewMode === 'story' ? storyContext.channel : null;\n let onStoryChange: () => void;\n if (channel) {\n onStoryChange = () => {\n // When the story changes, clean up the Aurelia app\n teardown(canvasElement);\n };\n channel.on(STORY_CHANGED, onStoryChange);\n }\n\n // Return teardown function that also unsubscribes from STORY_CHANGED\n return async () => {\n if (channel && onStoryChange) {\n channel.off(STORY_CHANGED, onStoryChange);\n }\n await teardown(canvasElement);\n };\n}\n\nexport function bootstrapAureliaApp(\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: 'au-storybook',\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}"],"names":["STORY_CHANGED","CustomElement"],"mappings":"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"}
1
+ {"version":3,"file":"render.js","sources":["../../src/preview/render.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}"],"names":["CustomElement"],"mappings":"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"}
@@ -1,13 +1,5 @@
1
- import { STORY_CHANGED } from '@storybook/core-events';
2
1
  import Aurelia, { CustomElement } from 'aurelia';
3
2
 
4
- /**
5
- * Merges multiple sources into a single object.
6
- * Sources can be story parameters, args, or story.props.
7
- */
8
- function mergeStoryProps(...sources) {
9
- return Object.assign({}, ...sources);
10
- }
11
3
  // Track Aurelia apps for cleanup
12
4
  const appMap = new Map();
13
5
  async function teardown(element) {
@@ -19,17 +11,37 @@ async function teardown(element) {
19
11
  }
20
12
  }
21
13
  }
22
- const render = (args, { id, component: Component }) => {
14
+ const render = (args, context) => {
15
+ const { id, component: Component } = context;
23
16
  if (!Component) {
24
17
  throw new Error(`Unable to render story ${id} as the component annotation is missing from the default export`);
25
18
  }
26
19
  return { Component, props: args, template: '' };
27
20
  };
28
21
  async function renderToCanvas({ storyFn, title, name, showMain, showError, storyContext, forceRemount, }, canvasElement, bootstrapAppFn) {
29
- const appBootstrapFn = bootstrapAppFn || bootstrapAureliaApp;
22
+ // Store reference to the original storybook root element
23
+ const rootElement = canvasElement;
24
+ // Ensure we have (or create) a single container inside the root where the Aurelia app actually renders
25
+ let hostElement;
26
+ if (rootElement.id === 'storybook-root') {
27
+ hostElement = rootElement.querySelector('.aurelia-story-container');
28
+ if (!hostElement) {
29
+ hostElement = document.createElement('div');
30
+ hostElement.className = 'aurelia-story-container';
31
+ hostElement.style.height = '100%';
32
+ rootElement.appendChild(hostElement);
33
+ }
34
+ }
35
+ else {
36
+ hostElement = rootElement;
37
+ }
38
+ // All app instances are now tracked by the *root* element, ensuring we only ever have one per story iframe
39
+ const appBootstrapFn = bootstrapAppFn ?? createAureliaApp;
30
40
  const { parameters, component, args } = storyContext;
31
- let app = appMap.get(canvasElement);
41
+ let app = appMap.get(rootElement);
32
42
  const story = storyFn();
43
+ // Temporary debug logging
44
+ console.log(`[DEBUG] Story: ${name}, forceRemount: ${forceRemount}, hasExistingApp: ${!!app}, canvasId: ${canvasElement.className}`);
33
45
  if (!story) {
34
46
  showError({
35
47
  title: `Expecting an Aurelia component from the story: "${name}" of "${title}".`,
@@ -41,43 +53,32 @@ async function renderToCanvas({ storyFn, title, name, showMain, showError, story
41
53
  return () => { };
42
54
  }
43
55
  showMain();
44
- let mergedProps;
45
- // Use full merge (including story.props) when bootstrapping a new app or force remounting.
46
56
  if (!app || forceRemount) {
47
- mergedProps = mergeStoryProps(parameters?.args, args, story.props);
48
- if (app) {
49
- await teardown(canvasElement);
57
+ if (forceRemount && app) {
58
+ await teardown(rootElement);
59
+ app = undefined;
50
60
  }
51
- app = appBootstrapFn(story, mergedProps, canvasElement, component);
52
- await app.start();
53
- appMap.set(canvasElement, app);
61
+ // Clear container before mounting new app
62
+ hostElement.innerHTML = '';
63
+ const mergedProps = { ...parameters?.args, ...args, ...story.props };
64
+ const aureliaApp = appBootstrapFn(story, mergedProps, hostElement, component);
65
+ await aureliaApp.start();
66
+ appMap.set(rootElement, aureliaApp);
67
+ app = aureliaApp;
54
68
  }
55
69
  else {
56
- // Update the existing app viewModel only with parameters and args (exclude story.props).
57
- mergedProps = mergeStoryProps(parameters?.args, args);
58
- if (app.root?.controller?.viewModel) {
70
+ // update existing app props
71
+ const mergedProps = { ...parameters?.args, ...args, ...story.props };
72
+ if (app?.root?.controller?.viewModel) {
59
73
  Object.assign(app.root.controller.viewModel, mergedProps);
60
74
  }
61
75
  }
62
- // Set up story change listener for cleanup
63
- const channel = storyContext.viewMode === 'story' ? storyContext.channel : null;
64
- let onStoryChange;
65
- if (channel) {
66
- onStoryChange = () => {
67
- // When the story changes, clean up the Aurelia app
68
- teardown(canvasElement);
69
- };
70
- channel.on(STORY_CHANGED, onStoryChange);
71
- }
72
- // Return teardown function that also unsubscribes from STORY_CHANGED
76
+ // Return cleanup fn
73
77
  return async () => {
74
- if (channel && onStoryChange) {
75
- channel.off(STORY_CHANGED, onStoryChange);
76
- }
77
- await teardown(canvasElement);
78
+ await teardown(rootElement);
78
79
  };
79
80
  }
80
- function bootstrapAureliaApp(story, args, domElement, component) {
81
+ function createAureliaApp(story, args, domElement, component) {
81
82
  const aurelia = new Aurelia(story.container);
82
83
  if (story.items?.length) {
83
84
  aurelia.register(...story.items);
@@ -91,7 +92,7 @@ function bootstrapAureliaApp(story, args, domElement, component) {
91
92
  aurelia.register(component);
92
93
  }
93
94
  const App = CustomElement.define({
94
- name: 'au-storybook',
95
+ name: 'sb-app',
95
96
  template,
96
97
  containerless: true,
97
98
  }, class {
@@ -109,5 +110,5 @@ function createComponentTemplate(component, innerHtml) {
109
110
  .join(' ')}>${innerHtml ?? ''}</${def.name}>`;
110
111
  }
111
112
 
112
- export { bootstrapAureliaApp, createComponentTemplate, render, renderToCanvas };
113
+ export { createAureliaApp, createComponentTemplate, render, renderToCanvas };
113
114
  //# sourceMappingURL=render.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"render.mjs","sources":["../../src/preview/render.ts"],"sourcesContent":["import { STORY_CHANGED } from '@storybook/core-events';\nimport type { RenderContext, ArgsStoryFn } from '@storybook/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/**\n * Merges multiple sources into a single object.\n * Sources can be story parameters, args, or story.props.\n */\nfunction mergeStoryProps(\n ...sources: Array<Record<string, any> | undefined>\n): Record<string, any> {\n return Object.assign({}, ...sources);\n}\n\n// Track Aurelia apps for cleanup\nconst appMap = new Map<HTMLElement, Aurelia>();\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, { id, component: Component }) => {\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 bootstrapAureliaApp\n) {\n const appBootstrapFn = bootstrapAppFn || bootstrapAureliaApp;\n\n const { parameters, component, args } = storyContext;\n let app = appMap.get(canvasElement);\n\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 showMain();\n\n let mergedProps;\n // Use full merge (including story.props) when bootstrapping a new app or force remounting.\n if (!app || forceRemount) {\n mergedProps = mergeStoryProps(parameters?.args, args, story.props);\n if (app) {\n await teardown(canvasElement);\n }\n app = appBootstrapFn(\n story,\n mergedProps,\n canvasElement,\n component as Constructable\n ) as Aurelia;\n await app.start();\n appMap.set(canvasElement, app);\n } else {\n // Update the existing app viewModel only with parameters and args (exclude story.props).\n mergedProps = mergeStoryProps(parameters?.args, args);\n if (app.root?.controller?.viewModel) {\n Object.assign(app.root.controller.viewModel, mergedProps);\n }\n }\n\n // Set up story change listener for cleanup\n const channel = storyContext.viewMode === 'story' ? storyContext.channel : null;\n let onStoryChange: () => void;\n if (channel) {\n onStoryChange = () => {\n // When the story changes, clean up the Aurelia app\n teardown(canvasElement);\n };\n channel.on(STORY_CHANGED, onStoryChange);\n }\n\n // Return teardown function that also unsubscribes from STORY_CHANGED\n return async () => {\n if (channel && onStoryChange) {\n channel.off(STORY_CHANGED, onStoryChange);\n }\n await teardown(canvasElement);\n };\n}\n\nexport function bootstrapAureliaApp(\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: 'au-storybook',\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}"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"render.mjs","sources":["../../src/preview/render.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}"],"names":[],"mappings":"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"}
package/dist/preview.js CHANGED
@@ -1,9 +1,86 @@
1
1
  'use strict';
2
2
 
3
- require('@storybook/core-events');
4
3
  var Aurelia = require('aurelia');
5
4
 
6
- function bootstrapAureliaApp(story, args, domElement, component) {
5
+ // Track Aurelia apps for cleanup
6
+ const appMap = new Map();
7
+ async function teardown(element) {
8
+ if (appMap.has(element)) {
9
+ const app = appMap.get(element);
10
+ if (app) {
11
+ await app.stop();
12
+ appMap.delete(element);
13
+ }
14
+ }
15
+ }
16
+ const render = (args, context) => {
17
+ const { id, component: Component } = context;
18
+ if (!Component) {
19
+ throw new Error(`Unable to render story ${id} as the component annotation is missing from the default export`);
20
+ }
21
+ return { Component, props: args, template: '' };
22
+ };
23
+ async function renderToCanvas({ storyFn, title, name, showMain, showError, storyContext, forceRemount, }, canvasElement, bootstrapAppFn) {
24
+ // Store reference to the original storybook root element
25
+ const rootElement = canvasElement;
26
+ // Ensure we have (or create) a single container inside the root where the Aurelia app actually renders
27
+ let hostElement;
28
+ if (rootElement.id === 'storybook-root') {
29
+ hostElement = rootElement.querySelector('.aurelia-story-container');
30
+ if (!hostElement) {
31
+ hostElement = document.createElement('div');
32
+ hostElement.className = 'aurelia-story-container';
33
+ hostElement.style.height = '100%';
34
+ rootElement.appendChild(hostElement);
35
+ }
36
+ }
37
+ else {
38
+ hostElement = rootElement;
39
+ }
40
+ // All app instances are now tracked by the *root* element, ensuring we only ever have one per story iframe
41
+ const appBootstrapFn = bootstrapAppFn ?? createAureliaApp;
42
+ const { parameters, component, args } = storyContext;
43
+ let app = appMap.get(rootElement);
44
+ const story = storyFn();
45
+ // Temporary debug logging
46
+ console.log(`[DEBUG] Story: ${name}, forceRemount: ${forceRemount}, hasExistingApp: ${!!app}, canvasId: ${canvasElement.className}`);
47
+ if (!story) {
48
+ showError({
49
+ title: `Expecting an Aurelia component from the story: "${name}" of "${title}".`,
50
+ description: `
51
+ Did you forget to return the Aurelia component from the story?
52
+ Use "() => ({ template: '<custom-component></custom-component>' })" when defining the story.
53
+ `,
54
+ });
55
+ return () => { };
56
+ }
57
+ showMain();
58
+ if (!app || forceRemount) {
59
+ if (forceRemount && app) {
60
+ await teardown(rootElement);
61
+ app = undefined;
62
+ }
63
+ // Clear container before mounting new app
64
+ hostElement.innerHTML = '';
65
+ const mergedProps = { ...parameters?.args, ...args, ...story.props };
66
+ const aureliaApp = appBootstrapFn(story, mergedProps, hostElement, component);
67
+ await aureliaApp.start();
68
+ appMap.set(rootElement, aureliaApp);
69
+ app = aureliaApp;
70
+ }
71
+ else {
72
+ // update existing app props
73
+ const mergedProps = { ...parameters?.args, ...args, ...story.props };
74
+ if (app?.root?.controller?.viewModel) {
75
+ Object.assign(app.root.controller.viewModel, mergedProps);
76
+ }
77
+ }
78
+ // Return cleanup fn
79
+ return async () => {
80
+ await teardown(rootElement);
81
+ };
82
+ }
83
+ function createAureliaApp(story, args, domElement, component) {
7
84
  const aurelia = new Aurelia(story.container);
8
85
  if (story.items?.length) {
9
86
  aurelia.register(...story.items);
@@ -17,7 +94,7 @@ function bootstrapAureliaApp(story, args, domElement, component) {
17
94
  aurelia.register(component);
18
95
  }
19
96
  const App = Aurelia.CustomElement.define({
20
- name: 'au-storybook',
97
+ name: 'sb-app',
21
98
  template,
22
99
  containerless: true,
23
100
  }, class {
@@ -35,41 +112,6 @@ function createComponentTemplate(component, innerHtml) {
35
112
  .join(' ')}>${innerHtml ?? ''}</${def.name}>`;
36
113
  }
37
114
 
38
- // Track the current story's cleanup function
39
- let currentCleanup = null;
40
- const render = (args, context) => {
41
- // Clean up previous story if exists
42
- if (currentCleanup) {
43
- currentCleanup();
44
- currentCleanup = null;
45
- }
46
- // Create a container element
47
- const container = document.createElement('div');
48
- // Get the story function result
49
- const story = context.storyFn();
50
- // Bootstrap Aurelia app immediately
51
- if (story && (story.Component || story.template)) {
52
- const app = bootstrapAureliaApp(story, args, container, story.Component || context.component);
53
- // Start the app asynchronously
54
- const startPromise = app.start();
55
- if (startPromise && typeof startPromise.catch === 'function') {
56
- startPromise.catch((error) => {
57
- console.error('Failed to start Aurelia app:', error);
58
- });
59
- }
60
- // Set cleanup function
61
- currentCleanup = () => {
62
- const stopPromise = app.stop();
63
- if (stopPromise && typeof stopPromise.catch === 'function') {
64
- stopPromise.catch((error) => {
65
- console.error('Failed to stop Aurelia app:', error);
66
- });
67
- }
68
- };
69
- }
70
- // Return the container element immediately
71
- return container;
72
- };
73
-
74
115
  exports.render = render;
116
+ exports.renderToCanvas = renderToCanvas;
75
117
  //# sourceMappingURL=preview.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"preview.js","sources":["../src/preview/render.ts","../src/preview.ts"],"sourcesContent":["import { STORY_CHANGED } from '@storybook/core-events';\nimport type { RenderContext, ArgsStoryFn } from '@storybook/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/**\n * Merges multiple sources into a single object.\n * Sources can be story parameters, args, or story.props.\n */\nfunction mergeStoryProps(\n ...sources: Array<Record<string, any> | undefined>\n): Record<string, any> {\n return Object.assign({}, ...sources);\n}\n\n// Track Aurelia apps for cleanup\nconst appMap = new Map<HTMLElement, Aurelia>();\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, { id, component: Component }) => {\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 bootstrapAureliaApp\n) {\n const appBootstrapFn = bootstrapAppFn || bootstrapAureliaApp;\n\n const { parameters, component, args } = storyContext;\n let app = appMap.get(canvasElement);\n\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 showMain();\n\n let mergedProps;\n // Use full merge (including story.props) when bootstrapping a new app or force remounting.\n if (!app || forceRemount) {\n mergedProps = mergeStoryProps(parameters?.args, args, story.props);\n if (app) {\n await teardown(canvasElement);\n }\n app = appBootstrapFn(\n story,\n mergedProps,\n canvasElement,\n component as Constructable\n ) as Aurelia;\n await app.start();\n appMap.set(canvasElement, app);\n } else {\n // Update the existing app viewModel only with parameters and args (exclude story.props).\n mergedProps = mergeStoryProps(parameters?.args, args);\n if (app.root?.controller?.viewModel) {\n Object.assign(app.root.controller.viewModel, mergedProps);\n }\n }\n\n // Set up story change listener for cleanup\n const channel = storyContext.viewMode === 'story' ? storyContext.channel : null;\n let onStoryChange: () => void;\n if (channel) {\n onStoryChange = () => {\n // When the story changes, clean up the Aurelia app\n teardown(canvasElement);\n };\n channel.on(STORY_CHANGED, onStoryChange);\n }\n\n // Return teardown function that also unsubscribes from STORY_CHANGED\n return async () => {\n if (channel && onStoryChange) {\n channel.off(STORY_CHANGED, onStoryChange);\n }\n await teardown(canvasElement);\n };\n}\n\nexport function bootstrapAureliaApp(\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: 'au-storybook',\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 { renderToCanvas, bootstrapAureliaApp } from './preview/render';\nimport Aurelia from 'aurelia';\n\n// Track the current story's cleanup function\nlet currentCleanup: (() => void) | null = null;\n\nexport const render = (args: any, context: any) => {\n // Clean up previous story if exists\n if (currentCleanup) {\n currentCleanup();\n currentCleanup = null;\n }\n\n // Create a container element\n const container = document.createElement('div');\n \n // Get the story function result\n const story = context.storyFn();\n \n // Bootstrap Aurelia app immediately\n if (story && (story.Component || story.template)) {\n const app = bootstrapAureliaApp(\n story,\n args,\n container,\n story.Component || context.component\n ) as Aurelia;\n \n // Start the app asynchronously\n const startPromise = app.start();\n if (startPromise && typeof startPromise.catch === 'function') {\n startPromise.catch((error: any) => {\n console.error('Failed to start Aurelia app:', error);\n });\n }\n \n // Set cleanup function\n currentCleanup = () => {\n const stopPromise = app.stop();\n if (stopPromise && typeof stopPromise.catch === 'function') {\n stopPromise.catch((error: any) => {\n console.error('Failed to stop Aurelia app:', error);\n });\n }\n };\n }\n \n // Return the container element immediately\n return container;\n}; "],"names":["CustomElement"],"mappings":"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"}
1
+ {"version":3,"file":"preview.js","sources":["../src/preview/render.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}"],"names":["CustomElement"],"mappings":"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"}