npm package: @magnolia-services/magnolia-jsfield-toolkit
Description: Helper for creating Magnolia JS Fields. https://docs.magnolia-cms.com/ui-framework-javascript/index.html
Author: Senol Tas
Latest version: 0.0.1-alpha.16

# Magnolia jsField Toolkit

## Introduction

This Repository provides experimental web component helpers to speed up custom JSField development for Magnolia CMS JSFields. These helpers include a set of built-in web components that can be used as a starting point for building custom components, as well as the `mgnl-component` custom element that offers a simple and efficient way to render HTML templates.

By using the Magnolia CMS JSField Application, developers can quickly and easily build custom JSField extensions that meet the specific needs of their project. The application provides a set of tools and helpers that can help streamline the development process and reduce the time and effort required to build and maintain custom JSField extensions.

Overall, the Magnolia CMS JSField Application is designed to make it easier and faster for developers to build custom JSField extensions for Magnolia CMS. The application is experimental and subject to change, but we encourage developers to try it out and provide feedback to help improve the toolset over time.

The JSField application can be built using the `mgnl-app` and `mgnl-component` custom elements.

## Installation

Both `mgnl-app` and `mgnl-component` can be installed as NPM packages and used as part of a larger Magnolia project. These custom elements allow developers to quickly build Magnolia JSField applications using modern web development tools and techniques.

### NPM / packaging

```
npm install @magnolia-services/magnolia-jsfield-toolkit
```

```javascript
import MagnoliaComponent from "@magnolia-services/magnolia-jsfield-toolkit/components/mgnl-component";
import "@magnolia-services/magnolia-jsfield-toolkit/components/mgnl-app";
import MgnlDialogAction from "@magnolia-services/magnolia-jsfield-toolkit/components/mgnl-dialog-action";
```

### CDN Installation

```html
<script
  type="module"
  src="https://unpkg.com/@magnolia-services/magnolia-jsfield-toolkit@latest"
></script>
```

## mgnl-app

The mgnl-app custom element is used as a root wrapper for the JSField application. When used as a root wrapper, it loads the Magnolia store and connects to Magnolia dialogs, allowing developers to quickly build custom Magnolia applications. The mgnl-app element creates a Shadow DOM and renders any HTML content inside the element's `<slot>` tag.

Developers can use the mgnl-app element as a root element for their JSField application without the need to extend the element. To use the mgnl-app element, developers can simply add the custom element tag to their HTML page and include the store attribute if a custom store is used.

```html
<!-- Example usage of mgnl-app -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>My Magnolia JSField Application</title>
    <script
      type="module"
      src="https://unpkg.com/@magnolia-services/magnolia-jsfield-toolkit@latest"
    ></script>
  </head>
  <body>
    <mgnl-app>
      <!-- Add HTML content here to render inside the mgnl-app element -->
      <h1>Hello, World!</h1>
    </mgnl-app>
  </body>
</html>
```

By default, the mgnl-app element renders any HTML content inside its `<slot>` tag. Developers can also add additional custom elements as children of the `mgnl-app` element to create a more complex JSField application.

# mgnl-component

The `mgnl-component` custom element is used to create custom web components for the JSField application. It uses the lit-html library to render the component's HTML and optionally supports the use of Nunjucks templates for small, fast displays.

Developers can create custom web components for the JSField application by extending the `mgnl-component` element and overwriting the `render()` method to render the custom component's HTML using lit-html. Developers can also set the rendertype attribute to "nunjucks" to use Nunjucks templates for the component's HTML.

```javascript
// Example usage of mgnl-component
import MgnlComponent from "@magnolia-services/magnolia-jsfield-toolkit/components/mgnl-component";

class MyCustomComponent extends MgnlComponent {
  render() {
    return html`<p>Hello, World!</p>`;
  }
}

customElements.define("my-custom-component", MyCustomComponent);
```

To use the custom component in the JSField application, developers can simply add the custom element tag to their HTML page.

```html
<!-- Example usage of custom component -->
<mgnl-app store="my-custom-store">
  <my-custom-component></my-custom-component>
</mgnl-app>
```

## rendertype Attribute

The rendertype attribute in the mgnl-component custom element is an optional attribute that specifies the type of rendering engine to use for the component's HTML. By default, the rendertype attribute is not set, and the component's HTML is rendered using the lit-html library.

If the rendertype attribute is set to "handlebars", the `mgnl-component` element uses the Nunjucks templating engine to render the component's HTML.

To use the rendertype attribute, simply add it to the mgnl-component element with a value of "handlebars".

```html
<mgnl-component rendertype="handlebars">
  {{#if formFields}}
  <ul>
    {{#each formFields }}
    <li>key = {{@key}} {{this}}</li>
    {{/each}}
  </ul>
  {{ else }}
  <strong>there are no Form fields present</strong>
  {{/if}}
</mgnl-component>
```

Using handlebars templates can help improve performance for small, fast displays in Magnolia JSField. However, it is not necessary to use handlebars templates for all components. For larger or more complex components, it may be more appropriate to extend MgnlComponent and write your own Custom Element using lit-html library for rendering.

# Frameworks

While the Magnolia CMS JSField Application encourages the use of lightweight libraries and keeping the application architecture simple, it is important to note that you can use any framework you want when building custom JSField extensions for Magnolia CMS. You can even include the mgnl-component custom element into your existing framework if needed.

However, we encourage developers to consider using vanilla web components when building custom JSField extensions for Magnolia CMS. Vanilla web components are native to the browser and offer a simple and efficient way to create reusable and maintainable components. By using vanilla web components, developers can ensure that their custom JSField extensions are compatible with a wide range of web platforms and frameworks.

Additionally, the Magnolia CMS JSField Application includes several built-in components that can be used as a starting point for building custom JSField extensions. These components are designed to be simple and easy to use, and can be customized to meet the specific needs of your project.

Overall, the choice of framework or library ultimately depends on the specific requirements of your project.

# Examples

## Custom Native Web Component

### Via npm:

```javascript
import { html } from "lit-html";
import { styleMap } from "lit-html/directives/style-map.js";
import MgnlComponent from "./mgnl-component.js";

class MgnlFieldValue extends MgnlComponent {
  render() {
    const styles = this.store.state.isInitialized
      ? { border: "10px solid red", margin: "20px" }
      : {};

    return html`
      <div style=${styleMap(styles)}>
        <p>Store ID: ${this.getAttribute("store")}</p>
        <p>New value: ${this.store.state.correlationId}</p>
      </div>
      ${!this.store.state.isInitialized ? html`<div>Not initialized</div>` : ""}
    `;
  }
}

customElements.define("mgnl-field-value", MgnlFieldValue);
```

### Via CDN (vanilla javascript)

The JavaScript Module bundle delivered via CDN is, additionally to `html`, providing `classMap` and `styleMap` (https://lit.dev/docs/templates/directives/#styling)

```javascript
import {
  MgnlComponent,
  html,
  styleMap,
} from "https://unpkg.com/@magnolia-services/magnolia-jsfield-toolkit@latest";

/**
 * @class MgnlFieldValue
 * @extends MgnlComponent
 */
class MgnlFieldValue extends MgnlComponent {
  render() {
    const styles = this.store.state.isInitialized
      ? { backgroundColor: "green", color: "white" }
      : {
          border: "10px solid red",
          padding: "15px",
          backgroundColor: "green",
          color: "white",
        };

    return html`
      <div style=${styleMap(styles)}>
        ${this.store.state.isInitialized
          ? "Magnolia Dialog Store is initialized"
          : "Not initialized"}
      </div>
    `;
  }
}

customElements.define("total-custom-stuff", MgnlFieldValue);
```