Ember Freestyle is an Ember addon that allows you to quickly create a component explorer for your Ember app.
Here is a simple style guide, where <LoadingSpinner />
is a hypothetical component in your
application.
<FreestyleGuide @title="My Living Style Guide" @subtitle="Showcasing My App's Components">
<FreestyleSection @name="UI Elements">
<FreestyleUsage @slug="loading-spinner" @title="Loading Spinner">
<LoadingSpinner />
</FreestyleUsage>
</FreestyleSection>
</FreestyleGuide>
Here's a brief rundown of the components Ember Freestyle provides for adding a living style guide in your app:
The <FreestyleGuide>
component provides the user interface for a style guide. It includes a header
section and navigation controls.
The <FreestyleUsage>
component is the workhorse. Wrap your application's components with a
<FreestyleUsage>
component, being sure to provide a unique slug (positional param) as follows:
<FreestyleUsage @slug="globally-unique-slug-1" @title="Title To Display In Style Guide">
<Foo @propa="aaa" @propb="bbb" />
</FreestyleUsage>
The snippet above will render your app's <Foo>
component as well as a handlebars snippet demonstrating
how to use it.
Optionally group your <FreestyleUsage>
-wrapped components into sections using the
<FreestyleSection>
component. The <FreestyleSection>
component registers
itself in order to appear in the navigation provided by the <FreestyleGuide>
component.
Optionally divide your style guide sections into subsections using the <FreestyleSubsection>
component.
<FreestyleGuide @title="My Living Style Guide" @subtitle="Showcasing My App's Components">
<FreestyleSection @name="Visual Style" as |Section|>
<Section.subsection @name="Typography">
<FreestyleUsage @slug="visual-style-typography-foo" @title="Foo Typography">
<FooTypography />
</FreestyleUsage>
</Section.subsection>
<Section.subsection @name="Colors">
<FreestyleUsage @slug="visual-style-colors-fie" @title='Fie Colors'>
<FieColors />
</FreestyleUsage>
</Section.subsection>
</FreestyleSection>
</FreestyleGuide>
The snippet above will create a style guide with one 'Visual Style' section with separate subsections for
'Typography' and
'Colors'. Your app's <FooTypography>
and <FieColors>
components would show up in the
appropriate subsections.
Use the <FreestyleCollection>
component with nested <FreestyleVariant>
components to present
multiple versions of
a component. This is very useful for presenting and testing a component in each state it must handle in your
application.
By default, variants will be stacked. If you wish to view variants side by side, set the inline
property of
<FreestyleCollection>
to true.
<FreestyleCollection @title="Foo Component In Every State" @defaultKey="with-icon" @inline=true as |Collection|>
<Collection.variant @key="no-num">
<FreestyleUsage @slug="foo-foo-no-num" @title="Information">
<FooFoo @title="Information" />
</FreestyleUsage>
</Collection.variant>
<Collection.variant @key="with-num">
<FreestyleUsage @slug="foo-foo-people" @title="People">
<FooFoo @title="People" @num=55 />
</FreestyleUsage>
</Collection.variant>
<Collection.variant @key="with-icon">
<FreestyleUsage @slug="foo-foo-twitter" @title="Twitter">
<FooFoo @title="Twitter" @icon="twitter" />
</FreestyleUsage>
</Collection.variant>
</FreestyleCollection>
Use the <FreestyleAnnotation>
component to add documentation for a specific
<FreestyleUsage>
.
Note that the
<FreestyleAnnotation>
slug must match the <FreestyleUsage>
slug
for filtering to work and in order to respect the Show Notes
usage controls preference.
<FreestyleUsage @slug="globally-unique-slug-2" @title="Title To Display In Style Guide">
<Foo @propa="aaa" @propb="bbb" />
</FreestyleUsage>
<FreestyleAnnotation @slug="globally-unique-slug-2">
<h1>Contextual HTML Note for Anything in the Freestyle Guide</h1>
<p>
You can write helpful HTML notes explaining anything in the
Freestyle guide.
</p>
</FreestyleAnnotation>
We're excited about this approach to documenting components inspired by StoryBook DocBlocks. It's still evolving but we're using it quite happily.
For more information, check out the latest documentation.
Previous versions of Freestyle had a built-in code snippet notation that allowed you to mark SASS, HBS or Javascript markup to display via freestyle-usage. The old style used "BEGIN-FREESTYLE-USAGE" and "END-FREESTYLE-USAGE" comments. This functionalty has been removed.
Instead, we recommend using the excellent
ember-code-snippet addon.
We have included an example of using this with some scss in the AlbumCover example
in the tests/dummy/app/templates/acceptance.hbs
and tests/dummy/app/styles/components/album-cover.scss
source:
<FreestyleAnnotation @slug="album-cover">
<h4>Styles for this component:</h4>
{{#let (get-code-snippet "album-cover-styles.scss") as |snippet|}}
<pre {{freestyle-highlight}} class="{{snippet.language}} u-outdent">{{snippet.source}}</pre>
{{/let}}
</FreestyleAnnotation>
Previous versions of Freestyle had a built-in freestyle-notes component that allowed you to write documentation in markdown. This functionality has been removed.
If you were not using markdown formatting in freestyle-note, we recommend using the freestyle-annotation component instead. Follow the freestyle-annoation usage guidance above.
If you were using markdown formatting, we recommend building your own markdown rendering
component using a library such as remarkable.
We have included an example of this approach in the AlbumCover example
in the tests/dummy/app/templates/acceptance.hbs
:
<div class="MarkdownContent" {{this.extractMarkdown}} ...attributes>
<div class="MarkdownContent-raw">{{yield}}</div>
{{!-- template-lint-disable no-triple-curlies --}}
<div class="MarkdownContent-rendered">{{{this.renderedMarkdown}}}</div>
</div>
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { Remarkable } from 'remarkable';
import stripIndent from 'strip-indent';
import { modifier } from 'ember-modifier';
interface Signature {
Element: HTMLDivElement;
Blocks: {
default: [];
};
}
export default class MarkdownContent extends Component<Signature> {
@tracked rawMarkdown: string | undefined;
extractMarkdown = modifier((element: HTMLElement): void => {
this.rawMarkdown = element.querySelector('.MarkdownContent-raw')?.innerHTML;
});
get renderedMarkdown(): string | null {
if (this.rawMarkdown) {
return new Remarkable().render(stripIndent(this.rawMarkdown));
}
return null;
}
}
<FreestyleAnnotation @slug="album-cover">
<MarkdownContent>
## Album Review
I really love this album. Ringo at his finest. Here are things I like about it:
- Submarines
- Psychadelica
- The color yellow
</MarkdownContent>
</FreestyleAnnotation>
You might find that rendering all your freestyle components in one page isn't desirable. The page might run slow, or you might want to encourage developers to use sub-sections. To hide the all menu option, and set the ember-freestyle service's `allowRenderingAllSections` to false.
app/routes/application.js
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default class ApplicationRoute extends Route {
@service emberFreestyle;
beforeModel() {
this.emberFreestyle.allowRenderingAllSections = false;
}
}
We recommend excluding Ember Freestyle from production builds using Ember CLI's `addons.exclude` option.
// ember-cli-build.js
const environment = process.env.EMBER_ENV;
const addonsToExclude = environment === 'production' ? ['ember-freestyle'] : [];
module.exports = function (defaults) {
const app = new EmberApp(defaults, {
addons: {
exclude: addonsToExclude,
},
};
};
Ember Freestyle facilitates a living style guide driven development approach for Ember apps. Chris LoPresto gave a talk on this topic at EmberConf 2016. Interactive Slides
Ember Freestyle would not be possible without inspiration from the Ember community at large. Specific thanks go out to:
This installation process is opinionated in order to get you going quickly. We are currently working to make it much easier to configure Ember Freestyle. Please report any problems, and as always, PRs are welcome.
ember install ember-freestyle
This will do the following:
ember-freestyle
addon itselffreestyle
template in your appfreestyle
controller in your appNote: Ember CLI versions before 0.2.3 should use ember install:addon
instead of
ember install
If you said yes to the prompts from the generator above, you are almost ready to display a Freestyle Guide in your app.
this.route('freestyle');
to your router.js
file/freestyle
.Note: Ember Freestyle is compatible with two trailing Ember LTS releases.