Highlight

v0.0.10

v0.0.10StableMobStatelessApache-2.0
Installation mix mishka.ui.gen.mob highlight
Source View Source

The Mishka Chelekom Mob Highlight component marks matching substrings in text on iOS and Android, as in search results. It is the native port of the headless Highlight and runs on Mob.

Overview of the Mob Highlight component for iOS and Android

Highlight is a pure Elixir Mob composite. You write it as a <MishkaHighlight> tag with the full text and one or more highlight queries. It splits the text on the queries and renders the pieces in a Row. Plain runs are Text nodes, and matched runs go through Mob Mark.

Matching works like the web component. You can pass several queries, empty and nil queries are ignored, and a matched run renders with the casing it has in the text, not the casing you typed. Matching ignores case unless you set case_sensitive={true}.

Highlight has no state and sends no events. To follow a query as it changes, pass the query from your assigns.

Mob's Text takes one string and exposes no span API, so a partly highlighted sentence is several nodes in a Row, and a Row does not wrap. That suits short strings such as a search result title or a filename. For a sentence, set wrap_at. It is a character budget per line, which the parts are packed into before rendering. You declare it because the component gets no layout size back at render time.

Breaks land after whitespace, so a wrapped line never begins with a space. A mark is never split across lines. A mark wider than the budget takes a line of its own. Leave wrap_at unset and you get a single Row.

One background applies to every match. For a line where each match has its own color, such as an Error in red beside a Success in green, compose Mob Mark and Text directly.

Generate the highlight component

Run this from your Mob app's root to add the component to lib/<app>/components/:

bash
mix mishka.ui.gen.mob highlight

The generator registers the tag, so you can use it in ~MOB markup. Highlight builds its marked runs from Mark, so the generator also generates mark, with the same prefixes. The examples on this page use the mishka_ prefix of the showcase app (--module-prefix mishka_), so the tag is <MishkaHighlight>. Without a prefix, the tag is <Highlight>.

Every occurrence, whatever its casing

One query marks all three occurrences. Each one renders with the casing it has in the text, not the casing you searched for. Here wrap_at={34} wraps the sentence at 34 characters per line.

Every occurrence, whatever its casing

Highlight example card titled Every occurrence, whatever its casing, with the sentence Highlight This, definitely THIS and also this! and all three words marked in amber
heex
<MishkaHighlight
  text="Highlight This, definitely THIS and also this!"
  highlight="this"
  wrap_at={34}
/>

Case sensitivity in highlight

Matching ignores case by default. Set case_sensitive={true} to mark only the exact casing, which here is just the lowercase this.

Case sensitivity in highlight

Highlight example card titled Case sensitivity, with the same sentence twice: the Insensitive (default) copy marks This, THIS and this, and the case_sensitive={true} copy marks only this
heex
<MishkaHighlight text="Highlight This, definitely THIS and also this!" highlight="this" />

<MishkaHighlight
  text="Highlight This, definitely THIS and also this!"
  highlight="this"
  case_sensitive={true}
/>

Highlight that follows a query

Pass the query from your assigns and the marks follow it. In the showcase, four buttons (che, beam, nativ and o) change the query when you tap them.

Highlight that follows a query

Highlight example card titled Matching a query, with the text Mishka Chelekom where Che is marked in amber, above a single dark button labeled che
heex
<MishkaHighlight text="Mishka Chelekom" highlight={@query} />

Highlight with several queries

Pass a list to mark more than one substring.

Highlight with several queries

Highlight example card titled Several queries, with one two three marking one and three, and BEAM on iOS and Android marking iOS and Android
heex
<MishkaHighlight text="one two three" highlight={["one", "three"]} />

Wrapping a highlighted sentence

A Row does not wrap, so wrap_at sets a character budget per line. Without it, a long sentence runs off the edge of the screen. Breaks land after whitespace, and a mark is never split across lines.

Wrapping a highlighted sentence

Highlight example card titled Wrapping a sentence, with the text Mishka Chelekom components, now running natively on the BEAM. wrapped over three lines and natively and BEAM marked in amber
elixir
# Breaks land after whitespace, and a mark is never split across lines.
<MishkaHighlight text={@sentence} highlight={["BEAM", "natively"]} wrap_at={30} />

Highlight with no match

An empty, nil or unmatched query leaves the text plain.

Highlight with no match

Highlight example card titled No match, no marks, with two lines reading nothing to mark here and no highlighted words, in the MishkaMob showcase app on Android
heex
<MishkaHighlight text="nothing to mark" highlight="" />

Highlight colors

background and color tint the marks. text_color colors the rest of the text.

Highlight colors

Highlight example card titled Colours, with two lines, green on the BEAM and violet on the BEAM, where BEAM is marked green on the first and violet on the second
heex
<MishkaHighlight text="…" highlight="beam" background={0xFFBBF7D0} />

Props

Props of the <MishkaHighlight> tag.

PropTypeDefaultDescription
textstring""The full text.
highlightstring or list[]Substring or substrings to mark. Blank values and nil are ignored.
case_sensitivebooleanfalseWhen true, matches casing exactly.
wrap_atinteger or nilnilCharacters per line. Unset renders one Row, which cannot wrap.
line_spacenumber4Gap between wrapped lines.
backgroundcolor / ARGBThe Mark amber, 0xFFFDE68AHighlight fill.
colorcolor / ARGBThe Mark ink, 0xFF111827Color of the marked text.
text_colorcolor / ARGB:on_surfaceColor of the unmarked text.
text_sizesize token:baseSize for both marked and unmarked text.