mix mishka.ui.export (Mishka Chelekom v0.0.10)

Copy Markdown View Source

A Mix Task for generating a JSON file from a directory of components

This Mix Task helps you generate a JSON file from the files in a directory, enabling you to use it with mix mishka.ui.add or share it in the community version.

Keep in mind that for each component, you must have both .eex and .exs files according to the documentation of the Mishka Chelekom library. Otherwise, you will need to create the necessary files manually. It’s recommended to review the Core components and follow their structure as a guide.

If you prefer to perform the process manually, simply add the relevant option to your command to generate a template file. You can then customize it based on your specific requirements.

Note:

Use --base64 option to convert the file content to Base64 if you're using special Erlang characters that do not retain their original form when converted back to the original file.

Note:

It is important to note that to place each file in its designated section and specify its type, you must use the following naming convention:

For example, if your file is a component, you need to have two files:

  • component_something.exs
  • component_something.eex

Similarly, for other file types like preset and template, you should follow the same naming pattern as above. For instance:

  • template_something.exs
  • template_something.eex

All files within the directory do not need to have the same name. However, they must start with the section name where they are intended to be placed, such as component, preset, or template. Additionally, each file must have both the exs and eex formats.

Note: Since JavaScript files do not require configuration, you only need to place the file in the directory. For example: something.js

What Should the Configuration of Each Component Look Like?

If you take a look at the example configuration below, you'll notice that the component file name matches the key name in the list, which also matches the configuration name. This ensures consistency and makes it easier to work with the component configuration.

File name: component_accordion.eex and component_accordion.exs

[
  component_accordion: [
    name: "component_accordion",
    args: [...]
    ...
  ]
]

Note: you can name this like preset_accordion or template_accordion too.

Example

mix mishka.ui.export --example arg

Export the built-in styled components as a MishkaCMS UI-kit bundle:

mix mishka.ui.export priv/components --cms --name chelekom --bundle-name chelekom --bundle-version 0.0.9

Export the headless Kit components as a MishkaCMS UI-kit bundle:

mix mishka.ui.export priv/headless --cms --name chelekom_headless --bundle-name chelekom_headless --bundle-version 0.0.9

Options

  • --base64 or -b - Converts component content to Base64
  • --name or -n - Defines a name for JSON file, if it is not set default is template.json
  • --org or -o - It is only for structuring the file and has no effect on your export.
  • --template or -t - Creates a default JSON file for manual processing steps.
  • --cms - Exports a MishkaCMS UI-kit bundle (mishka.ui_kit.bundle.v3) instead of the default JSON.
  • --bundle-name - Sets the bundle name in --cms output (defaults to the --name value).
  • --bundle-version - Sets the bundle version in --cms output (defaults to 0.0.1).

What a component's .exs can say to the consuming CMS

Beside necessary — which names the OTHER components this one draws through — three keys describe what the CMS must do with this component itself. All are optional and all default to false, so a .exs written before they existed keeps its meaning exactly.

required: true     # the CMS cannot run without it; its installer may not let it be deselected
precompile: true   # build its CSS whether or not a page names it
stateful: true     # install it as a Phoenix.LiveComponent, not a function component

precompile exists because a consuming CMS builds a site's stylesheet from the components its pages REFERENCE, and a component reached through helper code or the host's own markup is invisible to that walk. Saying so here is the only way it can be known.

priv/components/icon.exs is the example: 49 of this kit's components declare it necessary, so deselecting it would leave a third of the kit unable to draw.

What a component's .exs says to its docs page

Every .exs in priv/components, priv/headless and priv/mob ends with a docs: block: the facts its page on mishka.tools shows as badges. They are declared by hand, not read from the code, so a new component fills in all four, each true or false:

docs: [stateful: false, js_module: true, js: false, accessible: false]
  • stateful — it is a Phoenix.LiveComponent ("Stateful"; false shows "Stateless")
  • js_module — it uses LiveView's Phoenix.LiveView.JS at least once ("JS-module")
  • js — it uses a JS hook: it draws a phx-hook or ships scripts ("JS")
  • accessible — it has been reviewed accessible ("Accessible"); every headless one is

Neither export carries the block and no generator reads it, so it changes nothing in a bundle or a generated file. Its stateful describes the component; the top-level stateful: true above is what makes the CMS install it as a live component.

Shipping a live component

A stateful component gets an id, assigns of its own that survive the hosting page's re-renders, and handle_event/3 aimed at itself rather than at the page. Write its .eex as a Phoenix.LiveComponent module — one render/1 carrying the ~H, with mount/1, update/2 and handle_event/3 beside it — and the exporter names the row after the .exs's own name instead of after render, which every one of them would otherwise be called.

Three shapes the exporter refuses, because the consuming CMS refuses them too:

  • more than one public component in the file — a live component IS its module
  • a dispatching def with several clauses — each clause has its own root element, and a live component may have exactly one
  • an attr named uploads, streams, socket or myself — LiveView assigns those itself

Say it in the .exs. use Phoenix.LiveComponent in the .eex on its own is a warning and not a declaration: the bundle carries what the config says.

Summary

Functions

validate_files(components)