{"id":15060162,"url":"https://github.com/storybookjs/ember-cli-storybook","last_synced_at":"2025-08-02T21:10:40.936Z","repository":{"id":38361260,"uuid":"152307553","full_name":"storybookjs/ember-cli-storybook","owner":"storybookjs","description":"📒 Ember storybook adapter","archived":false,"fork":false,"pushed_at":"2024-05-17T14:10:33.000Z","size":289,"stargazers_count":38,"open_issues_count":21,"forks_count":39,"subscribers_count":50,"default_branch":"master","last_synced_at":"2024-10-30T00:55:27.196Z","etag":null,"topics":["ember","storybook"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/storybookjs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-10-09T19:15:19.000Z","updated_at":"2024-09-19T17:32:24.000Z","dependencies_parsed_at":"2024-11-06T03:44:55.159Z","dependency_job_id":null,"html_url":"https://github.com/storybookjs/ember-cli-storybook","commit_stats":{"total_commits":91,"total_committers":27,"mean_commits":"3.3703703703703702","dds":0.8791208791208791,"last_synced_commit":"7cab4ef00924b05e8de8f5a427d45723b7b11c23"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/storybookjs%2Fember-cli-storybook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/storybookjs%2Fember-cli-storybook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/storybookjs%2Fember-cli-storybook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/storybookjs%2Fember-cli-storybook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/storybookjs","download_url":"https://codeload.github.com/storybookjs/ember-cli-storybook/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247363272,"owners_count":20926918,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ember","storybook"],"created_at":"2024-09-24T22:53:54.840Z","updated_at":"2025-04-08T03:09:40.105Z","avatar_url":"https://github.com/storybookjs.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ember-cli-storybook\n\n\u003e 📒 Ember storybook adapter\n\n\n# Compatibility\n\n* Ember.js v3.16 or above\n* Ember CLI v2.13 or above\n* Node.js v16 or above\n\n# Installation\n\n```shell\nember install @storybook/ember-cli-storybook\n```\n\n# Usage\n\nThis will be triggered automatically as a post build action when running `ember build`\n\n\u003e package.json options (defaults)\n\n```json\n\"storybook\": {\n  \"ignoreTestFiles\": true,\n  \"config\": {}\n}\n```\n\n\u003e ember-cli-build options (defaults)\n\n```json\n\"ember-cli-storybook\": {\n  \"componentFilePathPatterns\": [],\n  \"enableAddonDocsIntegration\": true, // enables yuidoc generation\n}\n```\n\nIt's recommended to add the following commands in `package.json` to build, test and deploy Storybook with Ember:\n\n```json\n\"storybook\": \"start-storybook -p 6006 -s dist --ci\",\n\"storybook-dev\": \"npm-run-all --continue-on-error --parallel start storybook\",\n\"prebuild-storybook\": \"ember build\",\n\"build-storybook\": \"build-storybook -s dist\"\n```\n\n## Config\n\nThe config object represents anything that could be parsed from an `index.html` file. This must be in the format as below:\n\n```json\n{\n  \"meta\": [{\n    \"attributes\": [\"name\", \"content\"]\n  }, {\n    \"attributes\": [\"name\", \"content\"]\n  }, {\n    \"attributes\": [\"name\", \"content\", \"id\"]\n  }],\n  \"link\": [{\n    \"selector\": \"link\",\n    \"attributes\": [\"rel\", \"href\"]\n  }],\n  \"script\": [{\n    \"selector\": \"script\",\n    \"attributes\": [\"src\"]\n  }]\n}\n```\n\nSo in order to add a script tag to the generated `preview-head.html` a potential config would look like:\n\n```json\n\"storybook\": {\n  \"config\": {\n    \"script\": {\n      \"src\": \"./assets/foo.js\"\n    }\n  }\n}\n```\n\u003e It is important to note that storybook will by default serve any files out of the `public` folder. If you have custom files you would like to serve they need to exist there.\n\n## Embroider \u0026 YUIDoc\nIf you want to use YUIDoc with Embroider, you will need to modify your `ember-cli-build.js` to be able to compile the documentation.\n\n```diff\nconst { Webpack } = require('@embroider/webpack');\n- return require('@embroider/compat').compatBuild(app, Webpack);\n+ const compiledApp = require('@embroider/compat').compatBuild(app, Webpack);\n+\n+ return require('@storybook/ember-cli-storybook').prerender(app, compiledApp);\n```\n\n# Troubleshooting\n\n### Components that need routing for query parameters\n\nThe Storybook integration for Ember [renders stories into a custom component](https://github.com/storybookjs/storybook/blob/27210146d605e5a8fc630c0a70b7743be61d8f3f/app/ember/src/client/preview/render.js#L31-L34) in a router-less environment. This works for many situations but is insufficient when you have a story that requires query parameters, like a component that persists sorting or pagination information to the URL. There’s no official way to accomplish this as of yet, but you can work around it by dynamically adding a route, visiting it using the [private `startRouting` API](https://api.emberjs.com/ember/3.14/classes/EmberRouter/methods/startRouting?anchor=startRouting\u0026show=inherited%2Cprivate), and injecting a pseudo-controller, such as in this utility function:\n\n```javascript\nfunction injectRoutedController(controllerClass) {\n  return on('init', function() {\n    let container = getOwner(this);\n    container.register('controller:storybook', controllerClass);\n\n    let routerFactory = container.factoryFor('router:main');\n    routerFactory.class.map(function() {\n      this.route('storybook');\n    });\n\n    let router = container.lookup('router:main');\n    router.initialURL = 'storybook';\n    router.startRouting(true);\n\n    this.set('controller', container.lookup('controller:storybook'));\n  });\n}\n```\n\nThen you can use it in a story like this:\n\n```javascript\nexport let SortableColumns = () =\u003e {\n  return {\n    template: hbs`\n      \u003cListTable @source={{sortedShortList}} @sortProperty={{controller.sortProperty}} @sortDescending={{controller.sortDescending}} as |t|\u003e\n        \u003ct.head\u003e\n          \u003ct.sort-by @prop=\"name\"\u003eName\u003c/t.sort-by\u003e\n          \u003ct.sort-by @prop=\"lang\"\u003eLanguage\u003c/t.sort-by\u003e\n        \u003c/t.head\u003e\n        \u003ct.body @key=\"model.name\" as |row|\u003e\n          \u003ctr\u003e\n            \u003ctd\u003e{{row.model.name}}\u003c/td\u003e\n            \u003ctd\u003e{{row.model.lang}}\u003c/td\u003e\n          \u003c/tr\u003e\n        \u003c/t.body\u003e\n      \u003c/ListTable\u003e\n      `,\n    context: {\n      injectRoutedController: injectRoutedController(\n        Controller.extend({\n          queryParams: ['sortProperty', 'sortDescending'],\n          sortProperty: 'name',\n          sortDescending: false,\n        })\n      ),\n\n      sortedShortList: computed('controller.sortProperty', 'controller.sortDescending', function() {\n        let sorted = productMetadata.sortBy(this.get('controller.sortProperty') || 'name');\n        return this.get('controller.sortDescending') ? sorted.reverse() : sorted;\n      }),\n    },\n  };\n};\n```\n\n### Working with store\n\nAs said above, Storybook integration for Ember renders stories into a custom component, that are store-less.\nIf your component relies on an Ember model, for example, you can work around with the same way you would do for query params.\n\n```javascript\nfunction createUser() {\n  return on('init', function () {\n    this.user = getOwner(this)\n      .lookup('service:store')\n      .createRecord('user', { lastName: 'Doe', email: 'john.doe@qonto.eu' });\n  });\n}\n```\n\nAnd then in your story:\n```javascript\nexport const storeExample = () =\u003e {\n  return {\n    template: hbs`\n      \u003cSomeComponent\n        @model={{this.user}}\n        /\u003e\n    `,\n    context: {\n      createUser: createUser(),\n    },\n  };\n};\n```\n\n### Making Ember import work\n\nBecause Ember uses a mapping to resolve import like `@ember/array` or `@ember/object` for example, they may not work in Storybook.\nHowever, and because the module is already declared in the [babel preset for ember](https://github.com/storybookjs/storybook/blob/next/app/ember/src/server/framework-preset-babel-ember.ts#L19), you should be able to make them work by adding\n[babel-plugin-ember-modules-api-polyfill](https://github.com/ember-cli/babel-plugin-ember-modules-api-polyfill) to our `package.json`.\n\n### `preview-head` generation race condition\n\nThe `.storybook/preview-head.html` file is auto-generated and changes based on your `config/environment.js` and whether it’s a static or live-updating build of Storybook. This means that you’ll often see version control diffs for it, which can be bothersome.\n\nSince the file is auto-generated, it would be nice to add it to `.gitignore` so it no longer shows up in diffs. Unfortunately, the [documented way](https://github.com/storybookjs/storybook/blob/ada7868f432f43a5787fa1294ddb86c28163b07c/docs/src/pages/guides/guide-ember/index.md#add-storybookember) of starting a live-updating Storybook launches Ember CLI and Storybook in parallel, which means that in many cases, the `preview-head` file will not have been generated by the time Storybook needs it. To work around this if you want to ignore `preview-head`, you could either start Ember CLI and Storybook separately or create a script to launch them in sequence.\n\n### Stories that render blank or distorted\n\nIn some situations, components don’t render properly in stories, such as when dynamically-calculated container widths are zero or contents are blank. The cause for this is as-yet unknown, but an unfortunate workaround like this utility class can help in the meantime, by delaying the insertion of the component until the container element has been fully rendered:\n\n```javascript\nimport EmberObject from '@ember/object';\nimport { next } from '@ember/runloop';\n\nexport default EmberObject.extend({\n  init() {\n    this._super(...arguments);\n    this.set('complete', false);\n\n    next(this, () =\u003e {\n      this.set('complete', true);\n    });\n  },\n});\n\n```\n\nHere’s an example of it being used in a story:\n\n```javascript\nexport let Standard = () =\u003e {\n  return {\n    template: hbs`\n      \u003cdiv class=\"block\" style=\"height:50px; width:200px;\"\u003e\n        {{#if delayedTruth.complete}}\n          \u003cDistributionBar @data={{distributionBarData}} /\u003e\n        {{/if}}\n      \u003c/div\u003e\n      `,\n    context: {\n      delayedTruth: DelayedTruth.create(),\n      distributionBarData: [\n        { label: 'one', value: 10 },\n        { label: 'two', value: 20 },\n      ],\n    },\n  };\n};\n```\n\nSee the [Contributing](CONTRIBUTING.md) guide for details.\n\nLicense\n------------------------------------------------------------------------------\n\nThis project is licensed under the [MIT License](LICENSE.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstorybookjs%2Fember-cli-storybook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstorybookjs%2Fember-cli-storybook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstorybookjs%2Fember-cli-storybook/lists"}