diff --git a/assets/js/cell/index.js b/assets/js/cell/index.js
index 4a0f0f515..a99442d04 100644
--- a/assets/js/cell/index.js
+++ b/assets/js/cell/index.js
@@ -234,7 +234,10 @@ function handleInsertModeChanged(hook, insertMode) {
if (input) {
if (hook.state.insertMode) {
input.focus();
- input.selectionStart = input.selectionEnd = input.value.length;
+ // selectionStart is only supported on text based input
+ if (input.selectionStart !== null) {
+ input.selectionStart = input.selectionEnd = input.value.length;
+ }
} else {
input.blur();
}
diff --git a/lib/livebook/notebook/cell/input.ex b/lib/livebook/notebook/cell/input.ex
index 2e74017be..447e1ff9a 100644
--- a/lib/livebook/notebook/cell/input.ex
+++ b/lib/livebook/notebook/cell/input.ex
@@ -21,7 +21,8 @@ defmodule Livebook.Notebook.Cell.Input do
props: props()
}
- @type type :: :text | :url | :number | :password | :textarea | :color | :range | :select
+ @type type ::
+ :text | :url | :number | :password | :textarea | :color | :range | :select | :checkbox
@typedoc """
Additional properties adjusting the given input type.
diff --git a/lib/livebook_web/helpers.ex b/lib/livebook_web/helpers.ex
index b1dc85313..29d4dbd61 100644
--- a/lib/livebook_web/helpers.ex
+++ b/lib/livebook_web/helpers.ex
@@ -151,6 +151,10 @@ defmodule LivebookWeb.Helpers do
@doc """
Renders a checkbox input styled as a switch.
+ Also, a hidden input with the same name is rendered
+ alongside the checkbox, so the submitted value is
+ always either `"true"` or `"false"`.
+
## Examples
<.switch_checkbox
@@ -159,13 +163,30 @@ defmodule LivebookWeb.Helpers do
checked={@likes_cats} />
"""
def switch_checkbox(assigns) do
- assigns = assign_new(assigns, :disabled, fn -> false end)
+ assigns =
+ assigns
+ |> assign_new(:label, fn -> nil end)
+ |> assign_new(:disabled, fn -> false end)
+ |> assign_new(:class, fn -> "" end)
+ |> assign(
+ :attrs,
+ assigns_to_attributes(assigns, [:label, :name, :checked, :disabled, :class])
+ )
~H"""
diff --git a/lib/livebook_web/live/session_live/cell_component.ex b/lib/livebook_web/live/session_live/cell_component.ex
index eeb77d7a1..a78be5701 100644
--- a/lib/livebook_web/live/session_live/cell_component.ex
+++ b/lib/livebook_web/live/session_live/cell_component.ex
@@ -179,6 +179,17 @@ defmodule LivebookWeb.SessionLive.CellComponent do
"""
end
+ defp cell_input(%{cell_view: %{input_type: :checkbox}} = assigns) do
+ ~H"""
+
+ <.switch_checkbox
+ data-element="input"
+ name="value"
+ checked={@cell_view.value == "true"} />
+
+ """
+ end
+
defp cell_input(assigns) do
~H"""
delete_cells}, socket) do
+ delete_cells? = delete_cells == "true"
Livebook.Session.delete_section(
socket.assigns.session_id,
diff --git a/lib/livebook_web/live/session_live/elixir_cell_settings_component.ex b/lib/livebook_web/live/session_live/elixir_cell_settings_component.ex
index 8abd0635a..2943e0749 100644
--- a/lib/livebook_web/live/session_live/elixir_cell_settings_component.ex
+++ b/lib/livebook_web/live/session_live/elixir_cell_settings_component.ex
@@ -50,7 +50,7 @@ defmodule LivebookWeb.SessionLive.ElixirCellSettingsComponent do
end
defp update_metadata(metadata, form_data) do
- if Map.has_key?(form_data, "disable_formatting") do
+ if form_data["disable_formatting"] == "true" do
Map.put(metadata, "disable_formatting", true)
else
Map.delete(metadata, "disable_formatting")
diff --git a/lib/livebook_web/live/session_live/input_cell_settings_component.ex b/lib/livebook_web/live/session_live/input_cell_settings_component.ex
index ea0384ede..8082145a2 100644
--- a/lib/livebook_web/live/session_live/input_cell_settings_component.ex
+++ b/lib/livebook_web/live/session_live/input_cell_settings_component.ex
@@ -161,7 +161,7 @@ defmodule LivebookWeb.SessionLive.InputCellSettingsComponent do
defp validate_attrs(data, prev_attrs) do
name = data["name"]
type = data["type"] |> String.to_existing_atom()
- reactive = Map.has_key?(data, "reactive")
+ reactive = data["reactive"] == "true"
{props_valid?, props} =
if type == prev_attrs.type do
@@ -209,6 +209,7 @@ defmodule LivebookWeb.SessionLive.InputCellSettingsComponent do
end
end
+ defp default_value(:checkbox, _props), do: "false"
defp default_value(:color, _props), do: "#3E64FF"
defp default_value(:range, %{min: min}), do: to_string(min)
defp default_value(:select, %{options: [option | _]}), do: option
@@ -216,6 +217,7 @@ defmodule LivebookWeb.SessionLive.InputCellSettingsComponent do
defp input_types do
[
+ checkbox: "Checkbox",
color: "Color",
number: "Number",
password: "Password",
diff --git a/lib/livebook_web/live/session_live/shortcuts_component.ex b/lib/livebook_web/live/session_live/shortcuts_component.ex
index a4045e8ae..deb0ef68e 100644
--- a/lib/livebook_web/live/session_live/shortcuts_component.ex
+++ b/lib/livebook_web/live/session_live/shortcuts_component.ex
@@ -226,8 +226,8 @@ defmodule LivebookWeb.SessionLive.ShortcutsComponent do
end
@impl true
- def handle_event("settings", params, socket) do
- basic? = Map.has_key?(params, "basic")
+ def handle_event("settings", %{"basic" => basic}, socket) do
+ basic? = basic == "true"
{:noreply, assign(socket, :basic, basic?)}
end
end