Flicker.FacetEditor.Set (Flicker v0.1.0)

Copy Markdown View Source

The editor for a facet whose values come from a set — an :enum's closed picklist, or a relationship's related records (Spec 019).

Both cases are driven by one thing — Flicker.Facet.value_source/1 — so the enum and relationship editors are the same code with a different provider behind them, which was ADR-011's actual goal.

Why this isn't literally a nested Flicker.select

ADR-011 said the set editor is a nested Flicker.select. Implementation showed that doesn't work: Flicker.select's controlled mode sends {on_select, result} with send(self(), ...), and self() inside a Phoenix.LiveComponent is the host LiveView, not the enclosing component. A nested select could therefore never hand its selection back to the editor that contains it without every host adding a handle_info clause to forward it — exactly the boilerplate a library shouldn't impose.

So this renders the value list itself, against the same value_source/1, with its events targeted at the component that owns the editor. The unification ADR-011 wanted is intact; the specific mechanism isn't. What is genuinely lost is inheriting Flicker.select's own listbox behaviour for free — windowing over a very large related set is the notable gap, and is why :count_limit and a search box matter here.

Multi mode commits the whole selection as one :in token rather than per-toggle, so widening a selection is one dispatch, not five. Facet editing never recurses: this list has no facets of its own.

Summary

Functions

A non-empty selection is complete; nothing selected is not.

Splits a list literal for a multiple? facet, and casts through the facet so an enum comes back as atoms rather than strings.

A single value bare, a multi selection comma-joined — exactly the list literal Spec 018's grammar accepts.

Functions

complete?(arg1, facet)

@spec complete?(term(), Flicker.Facet.t()) :: boolean()

A non-empty selection is complete; nothing selected is not.

Examples

iex> Flicker.FacetEditor.Set.complete?([:a], %Flicker.Facet{key: :s})
true

iex> Flicker.FacetEditor.Set.complete?([], %Flicker.Facet{key: :s})
false

iex> Flicker.FacetEditor.Set.complete?(nil, %Flicker.Facet{key: :s})
false

parse(text, facet)

@spec parse(String.t(), Flicker.Facet.t()) :: {:ok, term()} | :error

Splits a list literal for a multiple? facet, and casts through the facet so an enum comes back as atoms rather than strings.

Examples

iex> facet = Flicker.Facet.new(key: :status, type: :enum, values: [:a, :b], multiple?: true)
...> Flicker.FacetEditor.Set.parse("a,b", facet)
{:ok, [:a, :b]}

iex> facet = Flicker.Facet.new(key: :status, type: :enum, values: [:a])
...> Flicker.FacetEditor.Set.parse("a", facet)
{:ok, :a}

iex> facet = Flicker.Facet.new(key: :status, type: :enum, values: [:a])
...> Flicker.FacetEditor.Set.parse("nope", facet)
:error

serialise(values, facet)

@spec serialise(term(), Flicker.Facet.t()) :: String.t()

A single value bare, a multi selection comma-joined — exactly the list literal Spec 018's grammar accepts.

Examples

iex> facet = Flicker.Facet.new(key: :status, type: :enum, values: [:a, :b], multiple?: true)
...> Flicker.FacetEditor.Set.serialise([:a, :b], facet)
"a,b"

iex> facet = Flicker.Facet.new(key: :status, type: :enum, values: [:a])
...> Flicker.FacetEditor.Set.serialise(:a, facet)
"a"

iex> facet = Flicker.Facet.new(key: :worker, type: :string)
...> Flicker.FacetEditor.Set.serialise("Casey Nguyen", facet)
~s("Casey Nguyen")