MishkaCmsCore.Runtime.PageBuilder.Icons (Mishka CMS Core v0.0.1)

Copy Markdown View Source

Every icon set the inspector can offer, as one catalogue.

What changed and why

This module used to BE the heroicon set. It is now a facade over MishkaCmsCore.Runtime.PageBuilder.IconLibrary implementations, of which MishkaCmsCore.Runtime.PageBuilder.Icons.Heroicons is the first — because an install that wants Lucide as well as Heroicons had nowhere to say so, and the class name already namespaces itself (hero-check, lucide-check), so several sets can coexist in one document without colliding.

With one library registered, every function here answers exactly what that library answers. The picker looks and behaves as it did.

config :mishka_cms_core, :icon_libraries, [
  MishkaCmsCore.Runtime.PageBuilder.Icons.Heroicons,
  MyApp.Icons.Lucide
]

Routing

By longest matching PREFIX, so svg/2 and css/1 reach the set that owns the class and nothing else has to be told which set a value came from. A class no registered set claims is not an error: known?/1 answers false and the control keeps the value anyway, because an author may be naming an icon from a set this editor has never been told about — see MishkaCmsCoreWeb.Live.Admin.Builder.Panels, where the icon control accepts free text for exactly that reason.

Summary

Functions

Every icon class every registered set ships.

Whether any registered set has a catalogue. False means the picker degrades to a text box.

Every icon class named anywhere in source, for callers holding markup rather than a tree.

How many match, uncapped — what tells a reader their query is too broad.

CSS rules for these classes, each from the set that owns it, inside Tailwind's components layer.

Whether a value names an icon some registered set actually ships.

Tailwind's own cascade-layer order, the statement @import "tailwindcss" opens with.

The registered libraries, in the order the picker offers them.

The icons matching a query, capped, across every registered set.

One icon as inline SVG at size pixels — nil when no registered set ships it.

The variant suffixes to offer, as {suffix, label}.

Functions

all()

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

Every icon class every registered set ships.

available?()

@spec available?() :: boolean()

Whether any registered set has a catalogue. False means the picker degrades to a text box.

classes_in(source)

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

Every icon class named anywhere in source, for callers holding markup rather than a tree.

AN ICON IS A CLASS, NOT A GLYPH — <span class="hero-bell"> plus a CSS mask — so a token in the text is all there is to find. Anchored on the REGISTERED prefixes rather than on "anything kebab-shaped": css/1 would drop the unclaimed ones anyway, and scanning every hyphenated token means offering tens of thousands of utilities a chance to match.

Shared by MishkaCmsCore.Runtime.Compilers.TailwindCompiler, which asks it of a site's templates to decide what the bundle carries, by MishkaCmsCore.Runtime.RuntimePreview, which asks it of one rendered component so the preview can carry its icons without borrowing a bundle, and by MishkaCmsCore.Runtime.ContentComponents.icons/1, which asks it of stored content.

count(query, variant \\ "", opts \\ [])

@spec count(String.t() | nil, String.t(), keyword()) :: non_neg_integer()

How many match, uncapped — what tells a reader their query is too broad.

css(names)

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

CSS rules for these classes, each from the set that owns it, inside Tailwind's components layer.

The canvas emits these for the icons it is about to render: the site's compiled stylesheet is generated from the classes its own pages RENDER, so a component's default icon — or one used only by an example in the modal — has no rule and draws as an empty box.

In the components layer so any utility on the icon (size-3, [&_.icon]:size-5) beats the set's default size. Opens with layer_order/0, so the block keeps that order wherever it lands first; put it ahead of any CSS that may declare a layer. "" when no set ships any of them.

known?(name)

@spec known?(String.t() | nil) :: boolean()

Whether a value names an icon some registered set actually ships.

layer_order()

@spec layer_order() :: String.t()

Tailwind's own cascade-layer order, the statement @import "tailwindcss" opens with.

For CSS that declares layers before any Tailwind stylesheet does; after one it changes nothing.

libraries()

@spec libraries() :: [module()]

The registered libraries, in the order the picker offers them.

Read at runtime so a host can register its own; each library's catalogue is still built at compile time inside that library, for the reason in MishkaCmsCore.Runtime.PageBuilder.IconLibrary.

search(query, opts \\ [])

@spec search(String.t() | nil, keyword()) :: [String.t()]

The icons matching a query, capped, across every registered set.

:library restricts to one set; :limit caps the result. The cap is applied to the MERGED list so a second set cannot push the first out of the picker.

svg(name, size \\ 15)

@spec svg(String.t() | nil, pos_integer()) :: {:safe, iodata()} | nil

One icon as inline SVG at size pixels — nil when no registered set ships it.

variants()

@spec variants() :: [{String.t(), String.t()}]

The variant suffixes to offer, as {suffix, label}.

One library's own variants when only one is registered. With several, only the suffixes they SHARE are offered, because a variant button that half the results cannot honour reads as broken — a set with a single weight answers [{"", "All"}] and narrows the row to that.