GithubHelp home page GithubHelp logo

storybookjs / aem Goto Github PK

View Code? Open in Web Editor NEW
34.0 73.0 24.0 4.84 MB

Adobe Experience Manager Storybook app with events, knobs, docs, addons, and more

Home Page: https://storybook-aem.netlify.com/

License: MIT License

JavaScript 60.83% TypeScript 15.84% HTML 19.37% CSS 0.61% Less 3.36%

aem's Introduction

This project is no longer supported. If you are interested in continuing this project, please let us know by creating an issue here: https://github.com/storybookjs/aem/issues

Storybook AEM App Logo

Storybook Adobe Experience Manager (AEM) App

Table of Contents

About The project

This project has been created to provide native Storybook support for Adobe Experience Manager. It is a work in progress and has not been published yet. If you are interested in helping out or learning more about this project, you can join the discord channel here to see what we've been up to.

Libraries

  • @storybook/aem - an application that provides Storybook support for Adobe Experience Manager(AEM)
  • @storybook/aem-cli - a cli tool that helps build out your storybook stories and much more based on your AEM componentry and much more

Technologies

Getting Started

Installation

If your AEM project is using the suggested structure, you will want to first run npm init from your ui.apps directory. Running that command will create a package.json file that will allow you to include the necessary libraries.

To get started with your Storybook AEM instance, from the ui.apps directory, run npm install @storybook/aem --save-dev to pull down the proper Storybook library. If you would like further help setting up your Storybook configurations, you can install the Storybook AEM CLI Tool (optional) by running npm install @storybook/aem-cli. You can find more information about the cli tool here.

Usage

In the root directory of your ui.apps folder (or whereever youve chosen to include your package.json file, make sure to include a .storybook folder. You can follow this tutorial to help you set that up: https://www.learnstorybook.com/intro-to-storybook/react/en/get-started/. You can also see our example configuration here.

When creating a new HTL component, we suggest that you create a storybook configuration within the same directory as your code so that you can easily associate which HTL component goes along with which storybook file. To see an example of a story for an HTL List Component click here!

Like any other Storybook Framework app, Storybook AEM supports both CSF and MDX formats.

Story Configuration

As a part of the storybook configuration setup there are options you can use to customize your use case:

  • Template (required): HTL/HTML File Reference or Inline HTML
  • Content (optional): Mocked authored content that can be used in conjunction with knobs/controls
  • AEM Metadata: An assortment of metadata used to provide your component context such as:
    • Component dependencies: for nested components, you only need to provide a template but you must include require all nested component's xml files in order for them to render (They can also be defined at the story config level or in the preview using the aemMetadata decorator)
    • Decoration tags: tags/ classes that can be applied to the outside of your component as a wrapper and can be used to mock the java tag annotations({} or null)
    • Models (required): Used to render a component and can either be a proper use-class, a content object (model.json) or a resource path (string). When using the later, the respective content needs to be provided with the content object.
import Example from ('./example.html'); // HTL File or HTML File
export const Example = () => {
  return {
    template: MyText,
    content: {
      text: text('text', 'Hello, world.' ),
      isRichText: boolean('isRichText', false),
    },
    aemMetadata: {
      components: [
        require('../core/wcm/components/text/.content.xml'),
      ],
      decorationTag: {
        cssClasses: ['text','component'],
        tagName: 'article' // type of wrapper element
      }
      models: {
        'com.adobe.cq.wcm.core.components.models.Text': GenericModel
      },
    }
  };
};

AEM Metadata Decorator

The aem metadata decorator allows for the application of properties such as the decoration tag and the component includes to all of the stories (depending on where its used - in the preview or in the story config). Use the following syntax to apply the decorator:

Using the Decorator in the Preview.js File
import { aemMetadata } from '@storybook/aem';

addDecorator(aemMetadata({
  components: [
    require('../core/wcm/components/accordion/.content.xml'),
    require('../core/wcm/components/list/.content.xml'),
    require('../core/wcm/components/text/.content.xml'),
    require('../core/wcm/components/person/.content.xml'),
  ],
  decorationTag: {
    cssClasses: ['text','component'],
    tagName: 'article'
  },
  models: {
    'com.adobe.cq.wcm.core.components.models.Text': GenericModel
    'person': require('../models/person'),
  },
}));
Using the Decorator in the Story Config File
export default {
  title: 'Accordion',
  decorators: [
    aemMetadata({
      components: [
        require('../core/wcm/components/accordion/.content.xml'),
        require('../core/wcm/components/text/.content.xml'),
      ],
      decorationTag: {
        cssClasses: ['text','component'],
        tagName: 'article'
      }
    }),
  ]
};

Use Classes and Sling Models

In AEM, most HTL scripts bind java classes in the data-sly-use attribute which makes the business logic available to the scripts. Most often, those classes implement Sling Models which offer a simple annotation based way to define the resource properties that should be exported to the script. The Sling Models are also used to generated the *.model.json view of a resource.

For Example: Text

With the htlengine used in JavaScript, it is not possible to use the java classes directly. Further, since loading of the model modules is not trivial, they need to be registered in the story.

There are several ways to provide the required functionality to the javascript world.

1. GenericModel

Storybook provides a GenericModel that you can register as model. The GenericModel uses the underlying content and a heuristic to automatically export the properties.

The models needs to be registered in the story:

  import { GenericModel } from '@storybook/aem';

  models: {
    'com.adobe.cq.wcm.core.components.models.Text': GenericModel
  }
2. Javascript Use Classes

A more sophisticated way is to actually implement a use-class in javascript that can generate some of the dynamic, computed properties, similar to your java class. After the class is loaded, it is instantiated with the runtime global object passed as argument to the constructor.

A very simple example can be found here: com.adobe.cq.wcm.core.components.models.Text

The models needs to be registered in the story or in the preview using the aemMetadata Decorator:

For example:

    models: {
      'com.adobe.cq.wcm.core.components.models.Text': require('../../../../models/com.adobe.cq.wcm.core.components.models.Text'),
      'com.adobe.cq.wcm.core.components.models.Title': require('../../../../models/com.adobe.cq.wcm.core.components.models.Title')
    }

Note: In the future, there might be functionality to register multiple use-classes automatically.

3. Extending the GenericModel

In case the GenericModel doesn't satisfy all the needs for rapid prototyping, it can easily be extended. For example to provide some computed or more complex content that will eventually by provided by a java class in AEM.

For Example:

person.js

export default class Person extends GenericModel {
  get fullName() {
    return `${this.content.firstName} ${this.content.lastName}`;
  }
}

person.stories.js

    models: {
      'person': require('../models/person')
    },

person.html

<div data-sly-use.personModel="person">
    <dl>
        <dt>First Name:</dt><dd>${personModel.firstName}</dd>
        <dt>Last Name:</dt><dd>${personModel.lastName}</dd>
        <dt>Full Name:</dt><dd>${personModel.fullName}</dd>
    </dl>
</div>

Extending from other projects.

Extending from other projects is mostly straight forward, just import the components and models accordingly. A 3rd party project might choose to deliberately export the list of components and models, so just import their definition. see the examples/aem-core-components and how they imported in examples/aem-kitchen-sink.

However, if the 3rd party projects use template references, the HTL compiler can't resolve them. So they need to be specified during build time. This is currently only possible by using the AEMRegisterJcrRoot function. See aem-kitchen-sink/.storybook/main.js.

The AEMRegisterJcrRoot function can also be used, if your project's content root is not the project directory. See aem-core-components/.storybook/main.js.

Contributing

For more information about how to start contributing to this project, see our contributing file.

Check out our issues here: https://github.com/storybookjs/aem/issues

We especially need help with figuring out the proper way to support 3rd party libraries that are defined in the POM and use Java models such as the AEM Core components. If you have any ideas about how to solve this please comment on this issue: #45

aem's People

Contributors

codebyalex avatar dependabot[bot] avatar imgbotapp avatar jantimon avatar jpica11 avatar jzeltman avatar shilman avatar tripodsan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aem's Issues

Pull core AEM components into the examples project

As proposed by @godanny86, the Carousel, Accordion and Teaser components would be good candidates. We also want to include some simpler components that use ${properties.xyz} and just display underlying repository content directly in the HTL without a sling model

  • core/wcm/components/tabs/v1/tabs
  • core/wcm/components/page/v1/page
  • core/wcm/components/form/options/v1/options
  • core/wcm/components/form/options/v2/options
  • core/wcm/components/form/hidden/v1/hidden
  • core/wcm/components/form/hidden/v2/hidden
  • core/wcm/components/form/container/v1/container
  • core/wcm/components/form/container/v2/container
  • core/wcm/components/form/button/v1/button
  • core/wcm/components/form/button/v2/button
  • core/wcm/components/form/text/v1/text
  • core/wcm/components/form/text/v2/text
  • core/wcm/components/sharing/v1/sharing
  • core/wcm/components/contentfragment/v1/contentfragment
  • core/wcm/components/embed/v1/embed/embeddable/youtube
  • core/wcm/components/embed/v1/embed/embeddable
  • core/wcm/components/embed/v1/embed
  • core/wcm/components/title/v1/title
  • core/wcm/components/title/v2/title
  • core/wcm/components/accordion/v1/accordion
  • core/wcm/components/separator/v1/separator
  • core/wcm/components/navigation/v1/navigation
  • core/wcm/components/carousel/v1/carousel
  • core/wcm/components/image/v1/image
  • core/wcm/components/image/v2/image
  • core/wcm/components/search/v1/search
  • core/wcm/components/container/v1/container
  • core/wcm/components/contentfragmentlist/v1/contentfragmentlist
  • core/wcm/components/button/v1/button
  • core/wcm/components/download/v1/download
  • core/wcm/components/teaser/v1/teaser
  • core/wcm/components/list/v1/list
  • core/wcm/components/languagenavigation/v1/languagenavigation
  • core/wcm/components/text/v1/text
  • core/wcm/components/text/v2/text
  • core/wcm/components/breadcrumb/v1/breadcrumb
  • core/wcm/components/breadcrumb/v2/breadcrumb
  • core/wcm/components/experiencefragment/v1/experiencefragment

'properties' global varaible missing

in the sling htl engine, properties refers to the properties of the current resource.
this should also be available in storybook.

see: https://sling.apache.org/documentation/bundles/scripting/scripting-htl.html#global-objects

suggest to add all the global properties with meaningful default values:

name sling type storybook type
currentNode javax.jcr.Node current content object
currentSession javax.jcr.Session NopProxy()
log org.slf4j.Logger console
out java.io.PrintWriter () => ()
properties org.apache.sling.api.resource.ValueMap current content object
reader java.io.BufferedReader NopProxy()
request org.apache.sling.api.SlingHttpServletRequest NopProxy() Note: this is quite important and we should provide a good request abstraction
resolver org.apache.sling.api.resource.ResourceResolver NopProxy()
resource org.apache.sling.api.resource.Resource current content object
response org.apache.sling.api.SlingHttpServletResponse NopProxy()
sling org.apache.sling.api.scripting.SlingScriptHelper NopProxy()

Feature to combine stories to another story

There are two very different stories:

  • pure ui components
    • Text
    • Image
    • Accordion
    • ...
  • integration stories
    • a teaser
    • an entire landing page
    • a checkout workflow
    • a register user form
    • ...

Usually everyones loves to write ui-components and shows how to implement a button.

However the complexity of responsive behaviour, sticky behaviour and other parts becomes easier to see once those ui-components are stitched together to integration stories.

For other storybook implementations you can do that quite easily with following code:

export const RichText = /* ... */
export const Text = /* ... */
export const Image = /* ... */

export const Teaser = () => RichText + Image; 

That's one great strength of the storybook format.

What do you think of add this also for aem storybook?

Config: create aem configuration template

This will be a common template that will be used for the cli to pull in libraries and define any aem related data. This config will be imported into the preview js file

Automatic model modules loading

the current set of a imported modules for the models are hardcoded,
it should be possible to include import them automatically (during compile time)

see GenericModel

Create JS versions of core component backing models

This is high priority and required for core component usage in the storybook

  • core/wcm/components/tabs/v1/tabs
  • core/wcm/components/page/v1/page
  • core/wcm/components/form/options/v2/options
  • core/wcm/components/form/hidden/v2/hidden
  • core/wcm/components/form/container/v2/container
  • core/wcm/components/form/button/v2/button
  • core/wcm/components/form/text/v2/text
  • core/wcm/components/sharing/v1/sharing
  • core/wcm/components/contentfragment/v1/contentfragment
  • core/wcm/components/embed/v1/embed/embeddable/youtube
  • core/wcm/components/embed/v1/embed/embeddable
  • core/wcm/components/embed/v1/embed
  • core/wcm/components/title/v2/title
  • core/wcm/components/accordion/v1/accordion
  • core/wcm/components/separator/v1/separator
  • core/wcm/components/navigation/v1/navigation
  • core/wcm/components/carousel/v1/carousel
  • core/wcm/components/image/v2/image
  • core/wcm/components/search/v1/search
  • core/wcm/components/container/v1/container
  • core/wcm/components/contentfragmentlist/v1/contentfragmentlist
  • core/wcm/components/button/v1/button
  • core/wcm/components/download/v1/download
  • core/wcm/components/teaser/v1/teaser
  • core/wcm/components/list/v1/list
  • core/wcm/components/languagenavigation/v1/languagenavigation
  • core/wcm/components/text/v2/text
  • core/wcm/components/breadcrumb/v2/breadcrumb
  • core/wcm/components/experiencefragment/v1/experiencefragment

Webpack error on running Storybook in AEM project

Hi there,
Thanks for all the support so far!
I have set up a basic AEM project generated from AEM maven archetype (23).
In addition, I have installed the @storybook/aem node module and configured storybook with a single story.
Here's the repo: https://github.com/madoni/storybook-aem
To replicate the error:

  1. Clone the repo
  2. Run npm install from within the ui.frontend directory
  3. Run npm run storybook

This is gist of the error:
Module not found: Error: Can't resolve '@storybook/aem'

Please let me know if you need further details.

Accept parameters for both content and model data into the render function

If all the functionality of a model can be presented as json, like default values etc, then we can create a generic model-class (js), that takes a model.json (the description) and a content.json (mock repository content), and exposes the correct interface.

// Data model
let textData = {
    'use': {
        'com.adobe.cq.wcm.core.components.models.Text': {
            'text': '<h1>Hello World </h1>', // Text.getText()
            'richText': true //Text.isRichText()
        },
        'com.foo.Barr': {
            'description': 'Other Sling models!'
        }   
    }, 'properties': {
        'jcr:title': 'Im the title straight from the resource'
    }, 'currentPage': {
        'pageTitle': 'A nice page title',
        'navTitle': 'Short and sweet'
    }
};

examples can not be build // missing npm-package

I wanted to build the aem-kitchen-sink project and ran into the issue that aem-sb-js-core-components is not available at npmjs.org.

Error-Msg after running: npm install

npm install
npm WARN deprecated [email protected]: You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1
npm WARN deprecated [email protected]: fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.
npm WARN deprecated [email protected]: This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).
npm WARN deprecated [email protected]: This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).
npm WARN deprecated [email protected]: core-js@<3 is no longer maintained and not recommended for usage due to the number of issues. Please, upgrade your dependencies to the actual version of core-js@3.
npm WARN deprecated [email protected]: This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).
npm WARN deprecated [email protected]: This module has moved and is now available at @hapi/topo. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.
npm WARN deprecated [email protected]: This module has moved and is now available at @hapi/hoek. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.
npm ERR! code E404
npm ERR! 404 Not Found - GET https://registry.npmjs.org/aem-sb-js-core-components - Not found
npm ERR! 404
npm ERR! 404  'aem-sb-js-core-components@*' is not in the npm registry.
npm ERR! 404 You should bug the author to publish it (or use the name yourself!)
npm ERR! 404 It was specified as a dependency of 'aem-kitchen-sink'
npm ERR! 404
npm ERR! 404 Note that you can also install from a
npm ERR! 404 tarball, folder, http url, or git url.

Add generic component renderer

The current way to render a component is to create a Runtime, instantiate the component and render it based on the runtime. this is a lot of boilerplate and will not work for included resources.

It would be better if a global runtime or runtime factory is available, based on the current page.

Generate Stories Using the HTL Engine Method

Currently, the sba story command only generates stories that use the fetchFromAEM method. This should be updated to optionally generate stories using the htl-engine method. This should be either configured in the package.json or asked as a user prompt after running the sba story command.

Add cli features to the project

  • Project installer + config generator
  • Story Generator
  • Content Package Installer?
  • Content Package Exporter?
  • Content JSON Installer?
  • Content JSON Exporter?
  • Create AEM Content from Story Config?

Add a license

Please explicitly add a license to this repo as a LICENSE file.

CLI Error with Chalk Module

I am getting the following error when running sba -v using the @storybook/aem-cli version 0.0.8.

$ sba -v
/Users/35267/.nvm/versions/node/v12.16.1/lib/node_modules/@storybook/aem-cli/dist/index.js:50
                chalk.italic(cmd) + " is not a valid command.",

                      ^

TypeError: chalk.italic is not a function

Add component resolver

In order to resolve included components based on their type, a generic component resolver is needed.
it should also (eventuallly) support component inheritance.

Allow to specify multiple roots for resolving components and sightly templates

currently, only the current directory is considered as root for resolving components and templates.
for example, the following tweak is needed to load the templates.html:

data-sly-use.templates="../../../../../../core/wcm/components/commons/v1/templates.html"

also see adobe/htlengine#172

It should be possible for a dependant library to export the project roots, as well as the respect those when compiling and executing the stories.

Allow the CLI to Skip Prompts

The sba command prompts the user to answer various questions. It should be possible to skip these prompts by entering the answers into the cli command. It should also require an argument such as --skip-prompts to be entered. If this argument is entered and all the required prompts are not answered, it should fail telling the user what questions they need to add into the command. This would allow the cli to be used programmatically and could have significant unforeseen benefits.

Below are some examples of what it could look like, but we could work on the syntax. The reason for the quotes is that some of the answers could contain spaces or be lists of answers.

sba story --skip-prompts --which-stories "all" --create-content "yes"
sba story --skip-prompts --which-stories "single" --which-component "button" --initial-stories "Blue Button, Yellow Button" --create-content "no"

Story Templating

Could client projects configure a template that is used when creating stories with the sba story command? This way they could provide their own format, with their own modifications. The current story template from story-config.js is shown below. Right now this is the only template that can be used and is not able to be modified by the client project.

render() {
  return `
    const ${this.contentPathIdentifier} = "${this.contentPath}";
    export const ${this.identifier} = () => ({
        template: async () => fetchFromAEM(${this.contentPathIdentifier})
    });
    ${this.identifier}.story = {
        name: '${this.prettyName}',
        parameters: { }
    };
  `;
}

I think the idea would be to look at the default export of .storybook/story.template.js for a string literal and pass it the same data we are passing the above string literal. If no such file exists then we fall back to the above 'default' template.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.