Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/storybookjs/ember-cli-storybook
๐ Ember storybook adapter
https://github.com/storybookjs/ember-cli-storybook
ember storybook
Last synced: 5 days ago
JSON representation
๐ Ember storybook adapter
- Host: GitHub
- URL: https://github.com/storybookjs/ember-cli-storybook
- Owner: storybookjs
- License: mit
- Created: 2018-10-09T19:15:19.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2024-05-17T14:10:33.000Z (8 months ago)
- Last Synced: 2024-10-30T00:55:27.196Z (3 months ago)
- Topics: ember, storybook
- Language: JavaScript
- Homepage:
- Size: 282 KB
- Stars: 38
- Watchers: 50
- Forks: 39
- Open Issues: 21
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE.md
Awesome Lists containing this project
README
# ember-cli-storybook
> ๐ Ember storybook adapter
# Compatibility
* Ember.js v3.16 or above
* Ember CLI v2.13 or above
* Node.js v16 or above# Installation
```shell
ember install @storybook/ember-cli-storybook
```# Usage
This will be triggered automatically as a post build action when running `ember build`
> package.json options (defaults)
```json
"storybook": {
"ignoreTestFiles": true,
"config": {}
}
```> ember-cli-build options (defaults)
```json
"ember-cli-storybook": {
"componentFilePathPatterns": [],
"enableAddonDocsIntegration": true, // enables yuidoc generation
}
```It's recommended to add the following commands in `package.json` to build, test and deploy Storybook with Ember:
```json
"storybook": "start-storybook -p 6006 -s dist --ci",
"storybook-dev": "npm-run-all --continue-on-error --parallel start storybook",
"prebuild-storybook": "ember build",
"build-storybook": "build-storybook -s dist"
```## Config
The config object represents anything that could be parsed from an `index.html` file. This must be in the format as below:
```json
{
"meta": [{
"attributes": ["name", "content"]
}, {
"attributes": ["name", "content"]
}, {
"attributes": ["name", "content", "id"]
}],
"link": [{
"selector": "link",
"attributes": ["rel", "href"]
}],
"script": [{
"selector": "script",
"attributes": ["src"]
}]
}
```So in order to add a script tag to the generated `preview-head.html` a potential config would look like:
```json
"storybook": {
"config": {
"script": {
"src": "./assets/foo.js"
}
}
}
```
> 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.## Embroider & YUIDoc
If you want to use YUIDoc with Embroider, you will need to modify your `ember-cli-build.js` to be able to compile the documentation.```diff
const { Webpack } = require('@embroider/webpack');
- return require('@embroider/compat').compatBuild(app, Webpack);
+ const compiledApp = require('@embroider/compat').compatBuild(app, Webpack);
+
+ return require('@storybook/ember-cli-storybook').prerender(app, compiledApp);
```# Troubleshooting
### Components that need routing for query parameters
The 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&show=inherited%2Cprivate), and injecting a pseudo-controller, such as in this utility function:
```javascript
function injectRoutedController(controllerClass) {
return on('init', function() {
let container = getOwner(this);
container.register('controller:storybook', controllerClass);let routerFactory = container.factoryFor('router:main');
routerFactory.class.map(function() {
this.route('storybook');
});let router = container.lookup('router:main');
router.initialURL = 'storybook';
router.startRouting(true);this.set('controller', container.lookup('controller:storybook'));
});
}
```Then you can use it in a story like this:
```javascript
export let SortableColumns = () => {
return {
template: hbs`
Name
Language
{{row.model.name}}
{{row.model.lang}}
`,
context: {
injectRoutedController: injectRoutedController(
Controller.extend({
queryParams: ['sortProperty', 'sortDescending'],
sortProperty: 'name',
sortDescending: false,
})
),sortedShortList: computed('controller.sortProperty', 'controller.sortDescending', function() {
let sorted = productMetadata.sortBy(this.get('controller.sortProperty') || 'name');
return this.get('controller.sortDescending') ? sorted.reverse() : sorted;
}),
},
};
};
```### Working with store
As said above, Storybook integration for Ember renders stories into a custom component, that are store-less.
If your component relies on an Ember model, for example, you can work around with the same way you would do for query params.```javascript
function createUser() {
return on('init', function () {
this.user = getOwner(this)
.lookup('service:store')
.createRecord('user', { lastName: 'Doe', email: '[email protected]' });
});
}
```And then in your story:
```javascript
export const storeExample = () => {
return {
template: hbs`
`,
context: {
createUser: createUser(),
},
};
};
```### Making Ember import work
Because Ember uses a mapping to resolve import like `@ember/array` or `@ember/object` for example, they may not work in Storybook.
However, 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
[babel-plugin-ember-modules-api-polyfill](https://github.com/ember-cli/babel-plugin-ember-modules-api-polyfill) to our `package.json`.### `preview-head` generation race condition
The `.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.
Since 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.
### Stories that render blank or distorted
In 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:
```javascript
import EmberObject from '@ember/object';
import { next } from '@ember/runloop';export default EmberObject.extend({
init() {
this._super(...arguments);
this.set('complete', false);next(this, () => {
this.set('complete', true);
});
},
});```
Hereโs an example of it being used in a story:
```javascript
export let Standard = () => {
return {
template: hbs`
{{#if delayedTruth.complete}}
{{/if}}
`,
context: {
delayedTruth: DelayedTruth.create(),
distributionBarData: [
{ label: 'one', value: 10 },
{ label: 'two', value: 20 },
],
},
};
};
```See the [Contributing](CONTRIBUTING.md) guide for details.
License
------------------------------------------------------------------------------This project is licensed under the [MIT License](LICENSE.md).