MishkaCmsBuilder.PartPlacement (Mishka CMS Builder v0.0.1-alpha.2)

Copy Markdown View Source

Puts a kit's part in the component it belongs to, when it arrives where none of those holds it.

A kit ships some components that are pieces of another one: Chelekom's Card Title, Card Media, Card Content and Card Footer are sections of a Card, its Dropdown Trigger and Dropdown Content the two halves of a Dropdown. Each renders on its own — it is a <div> — but the look is the parent's, and a Card Footer dropped on a navbar landed in the navbar's :end_content slot as a padded box nobody asked for. The drop that MishkaCmsBuilder.TablePlacement answers for a table cell is the same gesture here: the part arrives inside a new parent, as one insert and one undo step, and the author is told so. Inside its parent, at any depth, it lands as it is.

What a part is

Read off the kit, never off the name. A component is a part of another when every example the kit ships for it opens with that other component — the kit only ever shows it inside one — and the two are one family in the kit's own catalogue (extra.component, "card" for all five Card pieces). Both are needed: Chelekom shows its number field under a heading every time, and the heading is not its home. A kit that names no families has no parts, and nothing changes for it.

The palette carries both facts, answered in its own query (with_kit_facts/1, kit_facts/1), so a placement asks nothing of the database.

Only a part that is a plain box. One whose markup opens with an element HTML gives a home of its own — a table row, a list item, a definition term, a word of phrasing — is answered by MishkaCmsCore.Runtime.Authoring.Containment and TablePlacement, whose rules already say where it may go; a second parent put around it here would land where HTML refuses it.

Moves are not wrapped

A part already on the page that is dragged out of its parent is moved like any other node, because nothing about it breaks the page. Wrapping is for a part arriving — from the palette, a snippet, a paste. A component's own markup is a fragment placed elsewhere later, so a part at its top level is left as it is too.

Summary

Types

Whether a placement put a part's parent around it, and the two names the author is told.

Functions

The palette entry of the component name belongs inside, or nil when it is not a kit's part — see the moduledoc. Both have to be in components, the palette.

The facts with_kit_facts/1 read for one row, as the palette entry carries them.

What the author is told after a placement, or nil when there is nothing to say.

Answers in Postgres what holder/2 asks of every row the palette reads: the component's family in its kit's catalogue, and the component each of the kit's examples for it opens with.

The template to insert at parent (a node id, "root" or :root), and whether a parent was put around it.

Types

outcome()

@type outcome() :: :none | {:held, String.t(), String.t()}

Whether a placement put a part's parent around it, and the two names the author is told.

Functions

holder(name, components)

@spec holder(String.t(), [map()]) :: map() | nil

The palette entry of the component name belongs inside, or nil when it is not a kit's part — see the moduledoc. Both have to be in components, the palette.

kit_facts(arg1)

@spec kit_facts(map()) :: %{
  kit_family: String.t() | nil,
  example_heads: [String.t() | nil]
}

The facts with_kit_facts/1 read for one row, as the palette entry carries them.

told(arg1)

@spec told(outcome() | term()) :: String.t() | nil

What the author is told after a placement, or nil when there is nothing to say.

with_kit_facts(query)

@spec with_kit_facts(Ash.Query.t()) :: Ash.Query.t()

Answers in Postgres what holder/2 asks of every row the palette reads: the component's family in its kit's catalogue, and the component each of the kit's examples for it opens with.

Calculations, because extra is the column the palette must not pull whole — a component its kit documents at length carries hundreds of kilobytes of examples, and these are a few short strings.

wrap(template, session, parent)

@spec wrap(String.t(), map(), String.t() | :root | nil) :: {String.t(), outcome()}

The template to insert at parent (a node id, "root" or :root), and whether a parent was put around it.

Untouched when its first element is not a kit's part, or when parent or an element around it is already that part's parent.