Skip to content

Commit

Permalink
Add style to Kino.Text (#490)
Browse files Browse the repository at this point in the history
Co-authored-by: Jonatan Kłosko <[email protected]>
  • Loading branch information
josevalim and jonatanklosko authored Feb 11, 2025
1 parent 63642fa commit 1d1f402
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 8 deletions.
2 changes: 1 addition & 1 deletion lib/kino/render.ex
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ defimpl Kino.Render, for: Kino.Text do
end

def to_livebook(kino) do
%{type: :plain_text, text: kino.text, chunk: kino.chunk}
%{type: :plain_text, text: kino.text, chunk: kino.chunk, style: kino.style}
end
end

Expand Down
42 changes: 37 additions & 5 deletions lib/kino/text.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@ defmodule Kino.Text do

@enforce_keys [:text]

defstruct [:text, :terminal, :chunk]
defstruct [:text, :terminal, :chunk, :style]

@opaque t :: %__MODULE__{
text: String.t(),
terminal: boolean(),
chunk: boolean()
chunk: boolean(),
style: style()
}

@type style :: [{:color | :font_weight | :font_size, String.Chars.t()}]

@doc """
Creates a new kino displaying the given text content.
Expand All @@ -37,6 +40,11 @@ defmodule Kino.Text do
are merged into a single text. This is useful for streaming content.
Defaults to `false`
* `:style` - a keyword list of CSS attributes, such as
`style: [color: "#FF0000", font_weight: :bold]`. The currently supported
styles are `:color`, `:font_size`, and `:font_weight`. Not supported on
terminal outputs.
## Examples
### Using the `:chunk` option
Expand All @@ -61,9 +69,33 @@ defmodule Kino.Text do
Kino.nothing()
"""
@spec new(String.t(), opts) :: t() when opts: [terminal: boolean(), chunk: boolean()]
@spec new(String.t(), opts) :: t()
when opts: [terminal: boolean(), chunk: boolean(), style: style()]
def new(text, opts \\ []) when is_binary(text) do
opts = Keyword.validate!(opts, terminal: false, chunk: false)
%__MODULE__{text: text, terminal: opts[:terminal], chunk: opts[:chunk]}
opts = Keyword.validate!(opts, terminal: false, chunk: false, style: [])
terminal? = opts[:terminal]
style = opts[:style]

cond do
not is_list(style) ->
raise ArgumentError, ":style must be a keyword list"

terminal? and style != [] ->
raise ArgumentError, ":style not supported when terminal: true"

true ->
Enum.each(style, fn
{key, value} when key in [:color, :font_weight, :font_size] ->
if String.contains?(to_string(value), ";") do
raise ArgumentError, "invalid CSS property value for #{inspect(key)}"
end

other ->
raise ArgumentError,
":style must be a keyword list of color/font_size/font_weight, got: #{inspect(other)}"
end)
end

%__MODULE__{text: text, terminal: terminal?, chunk: opts[:chunk], style: style}
end
end
21 changes: 19 additions & 2 deletions test/kino/text_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,27 @@ defmodule Kino.TextTest do
describe "new/1" do
test "outputs plain text" do
"Hello!" |> Kino.Text.new() |> Kino.render()
assert_output(%{type: :plain_text, text: "Hello!", chunk: false})
assert_output(%{type: :plain_text, text: "Hello!", chunk: false, style: []})

"Hello!" |> Kino.Text.new(terminal: false) |> Kino.render()
assert_output(%{type: :plain_text, text: "Hello!", chunk: false})
assert_output(%{type: :plain_text, text: "Hello!", chunk: false, style: []})

"Hello!" |> Kino.Text.new(style: [font_weight: 300]) |> Kino.render()
assert_output(%{type: :plain_text, text: "Hello!", chunk: false, style: [font_weight: 300]})
end

test "validates style" do
assert_raise ArgumentError, ":style must be a keyword list", fn ->
Kino.Text.new("Hello!", style: %{font_weight: 300})
end

assert_raise ArgumentError, ":style not supported when terminal: true", fn ->
Kino.Text.new("Hello!", style: [font_weight: 300], terminal: true)
end

assert_raise ArgumentError, "invalid CSS property value for :font_weight", fn ->
Kino.Text.new("Hello!", style: [font_weight: "300;color"])
end
end

test "outputs terminal text" do
Expand Down

0 comments on commit 1d1f402

Please sign in to comment.