arrow-left
All pages
gitbookPowered by GitBook
1 of 10

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Deprecated

MagicForm in Microfrontend

MagicForm will help you manage your applications with microfrontend architecture, through the concept of isolated providers, for example:

<MagicFormProvider actions={{
    async login(){...}
}}>
    <MagicFormProvider actions={actionsClient}>
        <PageClient/>
    </MagicFormProvider>
    <MagicFormProvider actions={actionsAdmin}>
        <PageAdmin/>
    </MagicFormProvider>
</MagicFormProvider>

Any action not registered by the provider will continue to bubble until the next provider.

MagicForm Hooks

hashtag
useMagicForm

catch the submit event and send it to the useMagicFormProvider

import { useRef } from "atomico";
import { useMagicForm } from "@atomico/magic-form/hooks";

function component() {
  const ref = useRef();
  const [state, submit] = useMagicForm(ref);
  return (
    <host>
      <form ref={ref} action="addUser">
        <input type="text" name="name" />
        <input type="email" name="email" />
        <button>Add user</button>
      </form>
    </host>
  );
}

hashtag
useMagicFormProvider

receives the submits from useMagicForm

MagicForm | <magic-form>

captures the submit event of the nested form and sends it to MagicFormProvider

hashtag
Examples

<MagicForm>
  <form action="user">
    <input type="text" name="name" />
    <input type="text" name="email" />
<MagicForm onChangeState={event=>{
  console.log(event.currentTarget.state);
}}>
  <form action="user">
    <input type="text" name

hashtag
Events

Type
Description
Config

hashtag
Properties

Property
Description
Type

hashtag
Property.state

MagicForm Patterns

MagicForm makes it easy to send data to the server, here are some useful patterns

hashtag
Login

async login(form: HTMLFormElement){
  const user = Object.fromEntries(new FormData(form) as any);
  
  return myApi.login(user);
}

hashtag
Create data

async create(form: HTMLFormElement){
  const result = await fetch("/my-api",{method: "post",body: new FormData(form)});
  return result.json();
}

hashtag
Search

The following action allows us to generate searches from a form tag that has an input search, the objective is to consume the search value recursively only if there has been a change in the input search during the fetch performed.

MagicForm in React and Preact

MagicForm api is equivalent in Atomicojs, React and Preact at JSX level

hashtag
Installation

hashtag
Usage

import { MagicForm, MagicFormProvider } from "@atomico/magic-form/react";

export function App() {
  return (
    <>
      <MagicFormProvider
        actions={{
          async 

MagicFormProvider | <magic-form-provider>

receives the submits from MagicForm

hashtag
Example

hashtag
Events

Type
Description
Config

hashtag
Properties

Property
Description

hashtag

@atomico/magic-form

Improves the form development experience thanks to the use of webcomponents to centralize submission

A powerful form submission manager created with Atomicojs webcomponents, with MagicForm you can:

  1. Simplify the sending of forms by centralizing the sending actions through a provider.

  2. Know at all times the forms that are being provided and show their status.

  3. Isolate a group of actions according to provider, this means that if a provider does not register the action it will bubble to the parent provider.

hashtag
Installation and import

hashtag
Usage

magic-form-provider captures all the forms nested in magic-form when executing the submit event by the form and distributes them according to the definition of the action attribute to each method of the actions object

hashtag
API

@atomico/design-tokens api

hashtag
module

hashtag
compose

create a pipeline of functions that share the same CSSStyleSheet.

hashtag
Syntax

hashtag
tokens

transform an object to custom properties.

hashtag
Syntax

hashtag
Example 1

hashtag
Example 2, variations

hashtag
classes

It facilitates the reuse of tokens, through the generation of dynamic classes.

hashtag
Syntax

hashtag
Example

@atomico/design-tokens

Accelerates the implementation of design tokens in web components in a sustainable and scalable way

With @atomico/design-tokens you can:

  1. Resolve scalability and maintenance issues with your design tokens.

  2. Create utility classes from design tokens.

hashtag
Resolve scalability and maintenance issues with your design tokens.

Design systems are complex to develop, due to the number of configurations that are shared between all our components, with @atomico/design-tokens we will solve:

  1. Naming problems of the custom properties of your design tokens.

  2. Legibility of your CSS.

hashtag
How does @atomico/design-tokens solve the scalability of your design tokens?

For this example we will use Atomico, by the way you can use @atomico/design-tokens with any library.

The result of the CSS will be the following:

This is a technique that I have created to improve the scalability of design tokens, with it you can:

  1. edit token globally using custom properties:

This is also applicable within a selector.

  1. Simplify maintenance, since your components will use the custom properties without a prefix:

hashtag
Create utility classes to be used internally by your component system.

I am personally a fan of custom properties, but their use would become repetitive, to avoid this and improve maintenance @atomico/design-tokens introduces classes, a generator of utility classes based on the proposed design tokens, example:

The classes middleware will parse the CSSStyleSheet to relate the custom propeprtiy --size as a class of .gap, internally the css will be as follows:

This makes it really simple to reuse the tokens, example:

npm i @atomico/magic-form @atomico/react
import { MagicForm, MagicFormProvider } from "@atomico/magic-form";

function component() {
  return (
    <host>
      <MagicFormProvider 
        actions={{
          async add(form) {
            return fetch("./my-api", {
              method: "post",
              body: new FormData(form),
            }).then((res) => res.json());
          },
        }}
      >
        <MagicForm>
          <form action="user">
            <input type="text" name="name" />
            <input type="text" name="email" />
            <button>Create user</button>
          </form>
        </MagicForm>
      </MagicFormProvider>
    </host>
  );
}
import {
    compose,
    tokens,
    classes
} from "@atomico/design-tokens";

"ChangeForms"

Dispatched when forms changes from provider

{bubbles: false, composed: false}

forms

Read only, current state of the captured forms

actions

object that defines the actions to be captured by the MagicFormProvider

import { useHost } from "atomico";
import { useMagicFormProvider } from "@atomico/magic-form/hooks";

function component() {
  const ref = useHost();
  const forms = useMagicFormProvider(ref, {
    addUser(form) {
      const body = new FormData(form);
      return fetch(formData, { method: "POST", body }).res((res) => res.json());
    },
  });
  return <host></host>;
}
<button>Create user</button>
</form>
</MagicForm>
=
"name"
/>
<input type="text" name="email" />
<button>Create user</button>
</form>
</MagicForm>

"ChangeState"

Dispatched when status changes from provider

{bubbles: false, composed: false}

state

Read only, Current status submission of the form

Object

action

Defines the action to dispatch, if not defined it can be inherited from the

tag

String

async search(form: HTMLFormElement) {
  const beforeFetch = Object.fromEntries(new FormData(form) as any);
  
  await new Promise((resolve) => setTimeout(resolve, 1000)); // debounce
  
  const result = await fetch(beforeFetch.search);
  
  const afterFetch = Object.fromEntries(new FormData(form) as any);
  
  if (afterFetch.search === beforeFetch.search) {
    return result;
  } else {
    return login(form);
  }
}
add
(form) {
return fetch("./my-api", {
method: "post",
body: new FormData(form),
}).then((res) => res.json());
},
}}
>
<MagicForm>
<form action="user">
<input type="text" name="name" />
<input type="text" name="email" />
<button>Create user</button>
</form>
</MagicForm>
</MagicFormProvider>
</>
);
}
interface MagicFormActionStatus{
    result?:any,
    timestamp?: number,
    status: "pending" | "fulfilled" | "rejected"
}
import { MagicForm, MagicFormProvider } from "@atomico/magic-form/preact";

export function App() {
  return (
    <>
      <MagicFormProvider
        actions={{
          async add(form) {
            return fetch("./my-api", {
              method: "post",
              body: new FormData(form),
            }).then((res) => res.json());
          },
        }}
      >
        <MagicForm>
          <form action="user">
            <input type="text" name="name" />
            <input type="text" name="email" />
            <button>Create user</button>
          </form>
        </MagicForm>
      </MagicFormProvider>
    </>
  );
}
compose(
    ...middleware: ((sheet: CSSStyleSheet, lastParam:any)=> any)[]
): (firstParam:any)=>sheet: CSSStyleSheet;
tokens(theme: Tokens, prefix: string);
compose(
    tokens(
        {
            size: {
                xl: "32px",
                l: "28px",
                m: "24px",
            }
        },
        "ds"
    )
);
:host{
    --size-xl: var( --ds--size-xl,  32px);
    --size-l: var( --ds--size-xl,  28px);
    --size-m: var( --ds--size-xl,  24px);
}
compose(
    tokens(
        {
            size: {
                xl: "32px",
                l: "28px",
                m: "24px",
            },
            variation: {
                small: {
                    size: {
                        xl: "28px",
                        l: "24px",
                        m: "20px",
                    },                
                }
            }
        },
        "ds"
    )
);
:host{
    --size-xl: var( --ds--size-xl,  32px);
    --size-l: var( --ds--size-xl,  28px);
    --size-m: var( --ds--size-xl,  24px);
}
:host([small]){
    --size-xl: var( --ds-small--size-xl,  28px);
    --size-l: var( --ds-small--size-xl,  24px);
    --size-m: var( --ds-small--size-xl,  20px);
}
classes(tokens:Tokens);
import {css} from "atomico";
import { compose, classes } from "@atomico/design-tokens";

const designTokens = compose(
    classes(
        {
            size: {
                xl: "32px",
                l: "28px",
                m: "24px",
            }
        }
    )
);

export const classUtils = designTokens(
    css`
        .gap.--size{
            gap: var(--size);
        }
    `
);
.gap\.xl{    
    gap: var(--size-xl);
}
.gap\.l{    
    gap: var(--size-l);
}
.gap\.m{    
    gap: var(--size-m);
}
MagicFormProvider | <magic-form-provider>chevron-right
MagicForm | <magic-form>chevron-right
MagicForm Hookschevron-right
MagicForm in React and Preactchevron-right
@atomico/design-tokens apichevron-right
npm install @atomico/magic-form
import { 
    MagicForm,
    MagicFormProvider 
} from "@atomico/magic-form";
import { 
    useMagicForm, 
    useMagicFormProvider 
} from "@atomico/magic-form/hooks";
<magic-form-provider>
  <magic-form>
    <form action="user">
      <input type="text" name="name" />
      <input type="text" name="email" />
      <button>Create user</button>
    </form>
  </magic-form>
</magic-form-provider>
<script>
  document.querySelector("magic-form-provider").actions = {
    async add(form) {
      return fetch("./my-api", {
        method: "post",
        body: new FormData(form),
      }).then((res) => res.json());
    },
  };
</script>
import { MagicForm, MagicFormProvider } from "@atomico/magic-form";

function component() {
  return (
    <host>
      <MagicFormProvider 
        actions={{
          async add(form) {
            return fetch("./my-api", {
              method: "post",
              body: new FormData(form),
            }).then((res) => res.json());
          },
        }}
      >
        <MagicForm>
          <form action="user">
            <input type="text" name="name" />
            <input type="text" name="email" />
            <button>Create user</button>
          </form>
        </MagicForm>
      </MagicFormProvider>
    </host>
  );
}
import { css } from "atomico";
import { compose, tokens } from "@atomico/design-tokens";

const designTokens = compose(
  tokens(
    {
      size: {
        xl: "40px",
        l: "32px",
        m: "28px",
        s: "20px",
      },
    },
    "ds"
  )
);

export const tokens = designTokens(css``);
:host {
  --size-xl: var(--ds--size-xl, 40px);
  --size-l: var(--ds--size-l, 32px);
  --size-m: var(--ds--size-m, 28px);
  --size-s: var(--ds--size-s, 20px);
}
:root {
  --my-ds-size-xl: 50px;
}
import { c, css } from "atomico";
import tokens from "./tokens";
function button() {
  return (
    <host shadowDom>
      <slot />
    </host>
  );
}

button.styles = [
  tokens,
  css`
    :host {
      height: var(--size-xl);
      background: var(--color-primary-60);
      padding: var(--size-xxs) var(--size-xs);
    }
  `,
];
import { css } from "atomico";
import { compose, tokens, classes } from "@atomico/design-tokens";

const designTokens = compose(
  classes({
    size: {
      xl: "40px",
      l: "32px",
      m: "28px",
      s: "20px",
    },
  })
);

export const tokensSize = designTokens(
  css`
    .gap.--size {
      gap: var(--size);
    }
  `
);
.gap\.xl {
  gap: var(--size-xl);
}

.gap\.l {
  gap: var(--size-l);
}

.gap\.m {
  gap: var(--size-m);
}

.gap\.s {
  gap: var(--size-s);
}
import { c } from "atomico";
import { tokensSize } from "./tokens";

function button() {
  return (
    <host shadowDom>
      <button class="gap.xl">
        <slot />
      </button>
    </host>
  );
}

button.styles = tokensSize;

customElements.define("my-button", c(button));
GitHub - atomicojs/magic-formGitHubchevron-right
GitHub - atomicojs/design-tokensGitHubchevron-right
Logo
Logo