Loading README.md +135 −21 Original line number Diff line number Diff line Loading @@ -2,8 +2,35 @@ _CL Components_ lets you declare Drupal components that you can import and render in your Drupal site. Other solutions, like the [Components module](https://www.drupal.org/project/components), only concern themselves with templates, and not components. But a **template is only a part of a component** . [](/files/ksnip_20220313-095710.png) of a component**. The Components module is compatible with CL Components. What do you mean by "component"? -------------------------------- In this context, a component is the combination of: * A regular Twig template. * Metadata describing the input data the template accepts (the `metadata.json` file). * Optional JavaScript. * Optional Styles. A component then **needs to be embedded in your _Drupal templates_**, otherwise it just sits there waiting to be used. (Drupal templates are the templates that get used by naming them with the correct convention, like `node--article--card.twig.html`) In this context, a component is **not**: a type of a block plugin ( like [Component](https://www.drupal.org/project/component) and [Decoupled Blocks](https://www.drupal.org/project/pdb) modules), a Twig template by itself (like the [Components](http://www.drupal.org/project/components) module). These are more comparable to the [JS Widgets modules](https://www.lullabot.com/articles/progressive-decoupling-made-easy) . This module treats components in a very similarly to the ( brilliant) [Single File Components](https://www.drupal.org/project/sfc) module, but doesn't take an opinion on how to embed components inside your _Drupal templates_, and with a more familiar syntax for Drupal developers. [](https://www.drupal.org/files/ksnip_20220313-095710.png) How to create a component ------------------------- Loading @@ -11,12 +38,11 @@ How to create a component A component is any directory in your Drupal install that contains a `metadata.json`. This folder must also contain at least a `my-component.twig` template. It is advised to create a `css` and `js` directory for your stylesheets and JS scripts. Learn more about creating a component in [the documentation](https://git.drupalcode.org/project/cl_components/-/blob/1.x/docs/writing-components.md) stylesheets and JS scripts. Learn more about creating a component in the [documentation](https://git.drupalcode.org/project/cl_components/-/blob/1.x/docs/writing-components.md) . You will need to let Drupal know where to start scanning for components ( including subdirectories). You can add as many locations as you need in the settings page.  settings page (`admin/config/user-interface/cl-components`). How to render a component ------------------------- Loading @@ -29,24 +55,112 @@ via Twig. There is a special render element that allows you to render a component based solely on the component ID and the component props. See this example on rendering the `my-button` component with the label _Click Me_ using the `hook_page_top`: 'cl\_component', '#component' => 'my-button', '#variant' => 'primary', '#context' => \[ 'text' => t('Click Me'), \], \]; ?> This will take care of CSS, JS, HTML, and assets for you. the `hook_page_top`: ```php // hook_page_top $page_top['cta-button'] = [ '#type' => 'cl_component', '#component' => 'my-button', '#variant' => 'primary', '#context' => [ 'text' => t('Click Me'), ], ]; ``` This will take care of CSS, JS, HTML, and assets for you. ### Via Twig templates `{% include '@cl_components_example/components/my-button/my-button.twig' with { text: 'Click Me' } %}` There are two syntaxes for rendering components, both of those will offer these features:  ### Easy to embed Embed your component like you always embedded your template. _You can use the familiar `include/embed` with the path to the component's template_  ### Libraries included JS and CSS files inside the component folder will be **included** during render. _For caching reasons you can include `cl_components/all` in your theme. This library includes the CSS and JS for all the components._  ### Additional context The templates for your components will receive **additional context** that will make your theming experience more flexible and powerful. _Learn more about the additional context in [the documentation](https://git.drupalcode.org/project/cl_components/-/blob/1.x/docs/writing-components.md#twig-templates) ._ #### With the traditional syntax: `include` or `embed` Just provide the path to the template of the component. CL Components will check if the template is for a components, and add the CSS & JS if it is. Example: ```twig {% include "@cl_components_examples/components/my-button/my-button--primary.twig" with { text: 'Click Me', iconType: 'external' } %} ``` Composing "top-down" components ------------------------------- **Traditionally**, when you are not using this module, in order to map your templates, you need to start at the content type template (for instance) and then at some point you render `{{ content }}`. This is where the render pipeline enters the cognitive black hole, you lose the thread. To find the thread again you need to leave the IDE to your browser to inspect the HTML in search of template name suggestions for your fields/sub-components. After that you create the new twig template, etc. **With this module you still start at the content type template and you do everything there, if you want.** That is because you will develop all your components separately and wire the data to in the Drupal templates. Consider the following example for a custom block: [](https://www.drupal.org/files/ksnip_20220418-005414.png) The `my-card` component could be provided by a contributed module, a custom module for your component library, or in the same theme that holds `block--bundle--block-cta.twig.html`. Note that the `my-card` component supports children HTML and children components, _similar_ to **how React works** . With this technique you can map all the field data in its place by using the necessary sub-components. Thus, you don't have to find the sub-templates to map them to their corresponding components. **Tip** leverage the [No Markup module](https://www.drupal.org/project/nomarkup) in order to easily clean out wrapping field markup from the `{{ content.field_name }}` in your templates. See [more info](https://www.drupal.org/project/nomarkup) on why avoiding `{{ content.field_name|render|striptags }}` and `{{ node.field_name[0].getValue }}` is important. * * * **Build a component library!** ------------------------------ Now that we have components we can build a component library. Thanks to [CL Server](https://www.drupal.org/project/cl_server) this is super easy! I recommend [Storybook](https://storybook.js.org), but others are great options as well. If you want to use the newer `inject` custom syntax, enable `cl_inject`: `{% inject 'my-card' variant 'warning' with { heading: 'Warning' } %} This is the card body. {% inject 'my-button' variant 'primary' with { text: 'Click' } %}{% endinject 'my-button' %} {% endinject 'my-card' %}` ### [💧_Component Libraries: Server_ Drupal module](https://www.drupal.org/project/cl_server) Build a component library! -------------------------- ### [📚 Storybook Drupal Addon](https://github.com/lullabot/storybook-drupal-addon) Now that we have components it is time to build a component library. Thanks to [CL Server](https://www.drupal.org/project/cl_server) this is super easy! I recommend [Storybook](https://storybook.js.org), but others are great options as well. [](/files/ksnip_20220316-164333.png) [](https://www.drupal.org/files/ksnip_20220316-164333.png) docs/writing-components.md +1 −1 Original line number Diff line number Diff line Loading @@ -52,7 +52,7 @@ You could write a `metadata.json` like: "machineName": "my-image", "name": "Image", "status": "BETA", "componentType": "utility", "componentType": "molecule", "schemas": { "props": { "type": "object", Loading Loading
README.md +135 −21 Original line number Diff line number Diff line Loading @@ -2,8 +2,35 @@ _CL Components_ lets you declare Drupal components that you can import and render in your Drupal site. Other solutions, like the [Components module](https://www.drupal.org/project/components), only concern themselves with templates, and not components. But a **template is only a part of a component** . [](/files/ksnip_20220313-095710.png) of a component**. The Components module is compatible with CL Components. What do you mean by "component"? -------------------------------- In this context, a component is the combination of: * A regular Twig template. * Metadata describing the input data the template accepts (the `metadata.json` file). * Optional JavaScript. * Optional Styles. A component then **needs to be embedded in your _Drupal templates_**, otherwise it just sits there waiting to be used. (Drupal templates are the templates that get used by naming them with the correct convention, like `node--article--card.twig.html`) In this context, a component is **not**: a type of a block plugin ( like [Component](https://www.drupal.org/project/component) and [Decoupled Blocks](https://www.drupal.org/project/pdb) modules), a Twig template by itself (like the [Components](http://www.drupal.org/project/components) module). These are more comparable to the [JS Widgets modules](https://www.lullabot.com/articles/progressive-decoupling-made-easy) . This module treats components in a very similarly to the ( brilliant) [Single File Components](https://www.drupal.org/project/sfc) module, but doesn't take an opinion on how to embed components inside your _Drupal templates_, and with a more familiar syntax for Drupal developers. [](https://www.drupal.org/files/ksnip_20220313-095710.png) How to create a component ------------------------- Loading @@ -11,12 +38,11 @@ How to create a component A component is any directory in your Drupal install that contains a `metadata.json`. This folder must also contain at least a `my-component.twig` template. It is advised to create a `css` and `js` directory for your stylesheets and JS scripts. Learn more about creating a component in [the documentation](https://git.drupalcode.org/project/cl_components/-/blob/1.x/docs/writing-components.md) stylesheets and JS scripts. Learn more about creating a component in the [documentation](https://git.drupalcode.org/project/cl_components/-/blob/1.x/docs/writing-components.md) . You will need to let Drupal know where to start scanning for components ( including subdirectories). You can add as many locations as you need in the settings page.  settings page (`admin/config/user-interface/cl-components`). How to render a component ------------------------- Loading @@ -29,24 +55,112 @@ via Twig. There is a special render element that allows you to render a component based solely on the component ID and the component props. See this example on rendering the `my-button` component with the label _Click Me_ using the `hook_page_top`: 'cl\_component', '#component' => 'my-button', '#variant' => 'primary', '#context' => \[ 'text' => t('Click Me'), \], \]; ?> This will take care of CSS, JS, HTML, and assets for you. the `hook_page_top`: ```php // hook_page_top $page_top['cta-button'] = [ '#type' => 'cl_component', '#component' => 'my-button', '#variant' => 'primary', '#context' => [ 'text' => t('Click Me'), ], ]; ``` This will take care of CSS, JS, HTML, and assets for you. ### Via Twig templates `{% include '@cl_components_example/components/my-button/my-button.twig' with { text: 'Click Me' } %}` There are two syntaxes for rendering components, both of those will offer these features:  ### Easy to embed Embed your component like you always embedded your template. _You can use the familiar `include/embed` with the path to the component's template_  ### Libraries included JS and CSS files inside the component folder will be **included** during render. _For caching reasons you can include `cl_components/all` in your theme. This library includes the CSS and JS for all the components._  ### Additional context The templates for your components will receive **additional context** that will make your theming experience more flexible and powerful. _Learn more about the additional context in [the documentation](https://git.drupalcode.org/project/cl_components/-/blob/1.x/docs/writing-components.md#twig-templates) ._ #### With the traditional syntax: `include` or `embed` Just provide the path to the template of the component. CL Components will check if the template is for a components, and add the CSS & JS if it is. Example: ```twig {% include "@cl_components_examples/components/my-button/my-button--primary.twig" with { text: 'Click Me', iconType: 'external' } %} ``` Composing "top-down" components ------------------------------- **Traditionally**, when you are not using this module, in order to map your templates, you need to start at the content type template (for instance) and then at some point you render `{{ content }}`. This is where the render pipeline enters the cognitive black hole, you lose the thread. To find the thread again you need to leave the IDE to your browser to inspect the HTML in search of template name suggestions for your fields/sub-components. After that you create the new twig template, etc. **With this module you still start at the content type template and you do everything there, if you want.** That is because you will develop all your components separately and wire the data to in the Drupal templates. Consider the following example for a custom block: [](https://www.drupal.org/files/ksnip_20220418-005414.png) The `my-card` component could be provided by a contributed module, a custom module for your component library, or in the same theme that holds `block--bundle--block-cta.twig.html`. Note that the `my-card` component supports children HTML and children components, _similar_ to **how React works** . With this technique you can map all the field data in its place by using the necessary sub-components. Thus, you don't have to find the sub-templates to map them to their corresponding components. **Tip** leverage the [No Markup module](https://www.drupal.org/project/nomarkup) in order to easily clean out wrapping field markup from the `{{ content.field_name }}` in your templates. See [more info](https://www.drupal.org/project/nomarkup) on why avoiding `{{ content.field_name|render|striptags }}` and `{{ node.field_name[0].getValue }}` is important. * * * **Build a component library!** ------------------------------ Now that we have components we can build a component library. Thanks to [CL Server](https://www.drupal.org/project/cl_server) this is super easy! I recommend [Storybook](https://storybook.js.org), but others are great options as well. If you want to use the newer `inject` custom syntax, enable `cl_inject`: `{% inject 'my-card' variant 'warning' with { heading: 'Warning' } %} This is the card body. {% inject 'my-button' variant 'primary' with { text: 'Click' } %}{% endinject 'my-button' %} {% endinject 'my-card' %}` ### [💧_Component Libraries: Server_ Drupal module](https://www.drupal.org/project/cl_server) Build a component library! -------------------------- ### [📚 Storybook Drupal Addon](https://github.com/lullabot/storybook-drupal-addon) Now that we have components it is time to build a component library. Thanks to [CL Server](https://www.drupal.org/project/cl_server) this is super easy! I recommend [Storybook](https://storybook.js.org), but others are great options as well. [](/files/ksnip_20220316-164333.png) [](https://www.drupal.org/files/ksnip_20220316-164333.png)
docs/writing-components.md +1 −1 Original line number Diff line number Diff line Loading @@ -52,7 +52,7 @@ You could write a `metadata.json` like: "machineName": "my-image", "name": "Image", "status": "BETA", "componentType": "utility", "componentType": "molecule", "schemas": { "props": { "type": "object", Loading