StatifierBlocks.Editor.Icons (StatifierBlocks v0.24.0)

Copy Markdown View Source

The shipped default icon set, and the seam a host overrides it through (ADR-0005 decision 10's icon key, decision 14's "markup, not styling" line).

Why a default set exists at all

ADR-0005 decision 10 says icon is a name, never markup, and that a host that ships nothing "gets a neutral glyph". Read literally that was true: the editor rendered a U+25A1 white square in every tile. Read as a design it was not, because the one thing a white square communicates is that something failed to load - the first impression the shipped editor made on a host that had not yet written an icon component was of a broken page rather than an unstyled one, and the palette got no tile at all.

So this module ships the glyphs for the names StatifierBlocks.Palette.core/0 emits, and glyph/1 uses them when the host passes no icon. Nothing about the decision moves: icon is still a name, the editor still resolves the name through a component, and a host that passes its own icon still wins on every tile. The default is markup this package authored for names this package emits, which is the case the injection argument was never about.

What it is not

No font, no CDN, no build step. Every glyph is an inline SVG in this module's compiled template. Nothing is fetched, nothing is registered in a host's asset pipeline, and a host that imports the stylesheet and nothing else has icons.

No colour, and no size of its own. Every path paints with currentColor and the <svg> fills its tile, so the tile's own rule - .sb-node__icon and .sb-palette__icon, which read --sb-block-accent and --sb-block-accent-tint - decides both. A theme restyles the icons by restyling nothing but tokens, which is decision 14d's rule and the reason this is markup rather than styling.

Not a general icon library, and not anybody's icon set. The paths are written here, for these eleven names, at a single 24-unit grid and a single stroke weight. A host that wants a real icon library passes one.

The three cases glyph/1 has

  • the entry names an icon this module has - the shipped glyph;
  • the entry names one it does not - the unnamed mark, three dots, a tile that reads as deliberate rather than as a failed load. A host block type declaring icon: "credit-card" gets a neutral chip and the name in data-icon, not a white square;
  • the entry names none at all (icon: nil, ViewModel's default) - no tile. A block type that declared no icon is not missing one, and the chrome closes up around the label. This is the deliberate empty state the bead asked for, and it applies to a host-supplied icon component too: a host is never called with a nil name.

What a host's component may do

A host's icon is rendered as a function component, exactly as if the editor had written <.icon name={...} class={...} /> against it, so its assigns are a tracked assigns map and every Phoenix.Component helper works inside it: assign/3, assign_new/3, whatever a host reaches for to derive one value before the markup. It must return a ~H template, which is the one thing the seam has always required.

Summary

Functions

One tile: the host's component if it passed one, the shipped glyph otherwise, and nothing at all when the entry named no icon.

The shipped default icon component, in the shape the icon assign takes.

The icon names this module ships, sorted.

Functions

glyph(assigns)

One tile: the host's component if it passed one, the shipped glyph otherwise, and nothing at all when the entry named no icon.

Attributes

  • icon (:any) - The host's icon component, or nil for the shipped default set. Defaults to nil.
  • name (:any) - The icon name the palette entry declared, or nil. Defaults to nil.
  • class (:string) (required) - The tile class the caller owns.

icon(assigns)

The shipped default icon component, in the shape the icon assign takes.

A host may pass this directly, or wrap it to fall back to it for the names it has not drawn itself.

Attributes

  • name (:string) (required)
  • class (:string) - Defaults to nil.

known_names()

@spec known_names() :: [String.t()]

The icon names this module ships, sorted.

Public so the property that matters - every name the core palette emits has a glyph here - is asserted against the module rather than against a list copied into a test.