Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions lib/livebook/session.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3320,6 +3320,15 @@ defmodule Livebook.Session do
Map.put_new(plain_text, :style, [])
end

defp normalize_runtime_output(%{type: :input} = input) when input.attrs.type == :number do
update_in(input.attrs, fn attrs ->
attrs
|> Map.put_new(:min, nil)
|> Map.put_new(:max, nil)
|> Map.put_new(:step, nil)
end)
end

# Traverse composite outputs

defp normalize_runtime_output(%{type: :grid} = grid) do
Expand Down
88 changes: 65 additions & 23 deletions lib/livebook_web/live/output/input_component.ex
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ defmodule LivebookWeb.Output.InputComponent do
@impl true
def render(assigns) when assigns.input.attrs.type == :image do
~H"""
<div id={"#{@id}-form-#{@counter}"}>
<div>
<.input_label label={@input.attrs.label} changed={@changed} />
<.live_component
module={LivebookWeb.Output.ImageInputComponent}
id={"#{@id}-input"}
id={"#{@id}-input-#{@counter}"}
input_component_id={@id}
value={@value}
height={@input.attrs.size && elem(@input.attrs.size, 0)}
Expand All @@ -47,11 +47,11 @@ defmodule LivebookWeb.Output.InputComponent do

def render(assigns) when assigns.input.attrs.type == :audio do
~H"""
<div id={"#{@id}-form-#{@counter}"}>
<div>
<.input_label label={@input.attrs.label} changed={@changed} />
<.live_component
module={LivebookWeb.Output.AudioInputComponent}
id={"#{@id}-input"}
id={"#{@id}-input-#{@counter}"}
input_component_id={@id}
value={@value}
format={@input.attrs.format}
Expand All @@ -67,11 +67,11 @@ defmodule LivebookWeb.Output.InputComponent do

def render(assigns) when assigns.input.attrs.type == :file do
~H"""
<div id={"#{@id}-form-#{@counter}"}>
<div>
<.input_label label={@input.attrs.label} changed={@changed} />
<.live_component
module={LivebookWeb.Output.FileInputComponent}
id={"#{@id}-input"}
id={"#{@id}-input-#{@counter}"}
input_component_id={@id}
value={@value}
accept={@input.attrs.accept}
Expand All @@ -86,7 +86,7 @@ defmodule LivebookWeb.Output.InputComponent do

def render(assigns) when assigns.input.attrs.type == :utc_datetime do
~H"""
<div id={"#{@id}-form-#{@counter}"}>
<div>
<.input_label
label={@input.attrs.label}
changed={@changed}
Expand All @@ -95,7 +95,7 @@ defmodule LivebookWeb.Output.InputComponent do
<div class="inline-flex">
<.text_field
class="w-auto"
id={@id}
id={"#{@id}-input-#{@counter}"}
type="datetime-local"
data-el-input
name="html_value"
Expand All @@ -115,15 +115,15 @@ defmodule LivebookWeb.Output.InputComponent do

def render(assigns) when assigns.input.attrs.type == :utc_time do
~H"""
<div id={"#{@id}-form-#{@counter}"}>
<div>
<.input_label
label={@input.attrs.label}
changed={@changed}
help="Choose the time in your local time zone"
/>
<div class="inline-flex">
<.text_field
id={@id}
id={"#{@id}-input-#{@counter}"}
type="time"
data-el-input
name="html_value"
Expand All @@ -143,9 +143,14 @@ defmodule LivebookWeb.Output.InputComponent do

def render(assigns) do
~H"""
<form id={"#{@id}-form-#{@counter}"} phx-change="change" phx-submit="submit" phx-target={@myself}>
<form id={"#{@id}-form"} phx-change="change" phx-submit="submit" phx-target={@myself}>
<.input_label label={@input.attrs.label} changed={@changed} />
<.input_output id={"#{@id}-input"} attrs={@input.attrs} value={@value} myself={@myself} />
<.input_output
id={"#{@id}-input-#{@counter}"}
attrs={@input.attrs}
value={@value}
myself={@myself}
/>
</form>
"""
end
Expand Down Expand Up @@ -268,8 +273,28 @@ defmodule LivebookWeb.Output.InputComponent do
"""
end

defp input_output(%{attrs: %{type: type}} = assigns)
when type in [:number, :url, :text] do
defp input_output(%{attrs: %{type: :number}} = assigns) do
~H"""
<div class="inline-flex">
<.text_field
type="number"
data-el-input
id={@id}
name="html_value"
value={to_string(@value)}
phx-debounce={@attrs.debounce}
phx-target={@myself}
min={@attrs.min}
max={@attrs.max}
step={@attrs.step}
spellcheck="false"
autocomplete="off"
/>
</div>
"""
end

defp input_output(%{attrs: %{type: type}} = assigns) when type in [:url, :text] do
~H"""
<div class="inline-flex">
<.text_field
Expand Down Expand Up @@ -312,7 +337,6 @@ defmodule LivebookWeb.Output.InputComponent do
"""
end

defp html_input_type(:number), do: "number"
defp html_input_type(:url), do: "url"
defp html_input_type(:text), do: "text"

Expand Down Expand Up @@ -374,17 +398,15 @@ defmodule LivebookWeb.Output.InputComponent do
{:ok, html_value}
end

defp parse(html_value, %{type: :number}) do
defp parse(html_value, %{type: :number} = attrs) do
if html_value == "" do
{:ok, nil}
else
case Integer.parse(html_value) do
{number, ""} ->
{:ok, number}

_ ->
{number, ""} = Float.parse(html_value)
{:ok, number}
with {:ok, number} <- parse_number(html_value),
true <- in_range?(number, attrs.min, attrs.max) do
{:ok, number}
else
_ -> :error
end
end
end
Expand Down Expand Up @@ -461,6 +483,22 @@ defmodule LivebookWeb.Output.InputComponent do
end
end

defp parse_number(html_value) do
case Integer.parse(html_value) do
{number, ""} ->
{:ok, number}

_ ->
case Float.parse(html_value) do
{number, ""} ->
{:ok, number}

_ ->
:error
end
end
end

defp truncate_datetime(datetime) do
datetime
|> NaiveDateTime.truncate(:second)
Expand All @@ -479,6 +517,10 @@ defmodule LivebookWeb.Output.InputComponent do
(max == nil or struct.compare(datetime, max) != :gt)
end

defp in_range?(number, min, max) when is_number(number) do
(min == nil or number >= min) and (max == nil or number <= max)
end

defp report_event(socket, value) do
topic = socket.assigns.input.ref
event = %{value: value, origin: socket.assigns.client_id, type: :change}
Expand Down
2 changes: 1 addition & 1 deletion mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"phoenix_html": {:hex, :phoenix_html, "4.2.1", "35279e2a39140068fc03f8874408d58eef734e488fc142153f055c5454fd1c08", [:mix], [], "hexpm", "cff108100ae2715dd959ae8f2a8cef8e20b593f8dfd031c9cba92702cf23e053"},
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.6", "7b1f0327f54c9eb69845fd09a77accf922f488c549a7e7b8618775eb603a62c7", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "1681ab813ec26ca6915beb3414aa138f298e17721dc6a2bde9e6eb8a62360ff6"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.6.1", "05df733a09887a005ed0d69a7fc619d376aea2730bf64ce52ac51ce716cc1ef0", [:mix], [{:file_system, "~> 0.2.10 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "74273843d5a6e4fef0bbc17599f33e3ec63f08e69215623a0cd91eea4288e5a0"},
"phoenix_live_view": {:hex, :phoenix_live_view, "1.1.11", "1b4d8fa56898d93b6f528c89227198a3fce7c5b242819b22ed9e92b73c1bb077", [:mix], [{:igniter, ">= 0.6.16 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:lazy_html, "~> 0.1.0", [hex: :lazy_html, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0 or ~> 1.8.0-rc", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "266823602e11a54e562ac03a25b3d232d79de12514262db7cfcbb83fdfd8fd57"},
"phoenix_live_view": {:hex, :phoenix_live_view, "1.1.24", "1a000a048d5971b61a9efe29a3c4144ca955afd42224998d841c5011a5354838", [:mix], [{:igniter, ">= 0.6.16 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:lazy_html, "~> 0.1.0", [hex: :lazy_html, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0 or ~> 1.8.0-rc", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "0c724e6c65f197841cac49d73be4e0f9b93a7711eaa52d2d4d1b9f859c329267"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.2.0", "ff3a5616e1bed6804de7773b92cbccfc0b0f473faf1f63d7daf1206c7aeaaa6f", [:mix], [], "hexpm", "adc313a5bf7136039f63cfd9668fde73bba0765e0614cba80c06ac9460ff3e96"},
"phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
"plug": {:hex, :plug, "1.18.0", "d78df36c41f7e798f2edf1f33e1727eae438e9dd5d809a9997c463a108244042", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "819f9e176d51e44dc38132e132fe0accaf6767eab7f0303431e404da8476cfa2"},
Expand Down