Replies: 1 comment
-
| 
         I have recently been using the following hack to create my own custom  defmodule KinoLens.InputRef do
  @moduledoc """
  This module allows other components to build Kino.Input style components where
  1) The value can be read
  2) Dependencies are tracked in the same way as Kino.Input
  A few hacks are necessary to make this work:
  - We create a hidden input with 0 height to make Livebook aware of an input
  - We the hidden input in sync
  """
  defstruct [:id, :session_pid, :value]
  def register(default \\ nil) do
    hidden_input = Kino.Input.text("", default: default)
    session_pid =
      case :sys.get_state(Process.group_leader()) do
        %{send_to: pid} when is_pid(pid) -> pid
        _ -> nil
      end
    # This is a workaround to retrieve the value from the hidden input without re-rendering
    # The process that initiates the re-render
    # If we don't do this within another process, Livebook will track changes and re-render
    # the Kino in the calling process whenever the input value changes
    value =
      Task.async(fn ->
        case Kino.Bridge.get_input_value(hidden_input.id) do
          {:ok, v} -> v
          _ -> default
        end
      end)
      |> Task.await()
    # Render the custom UI together with the hidden input and
    # return the hidden input handle for reading and API use
    Kino.render(Kino.Layout.grid([hidden_input], columns: 1, max_height: 0))
    %KinoLens.InputRef{
      id: hidden_input.id,
      session_pid: session_pid,
      value: value
    }
  end
  def read(%KinoLens.InputRef{id: id}) do
    case Kino.Bridge.get_input_value(id) do
      {:ok, ""} -> nil
      {:ok, value} -> value
      _ -> nil
    end
  end
  def write(%KinoLens.InputRef{id: id, session_pid: session_pid} = ref, ctx, value) do
    GenServer.cast(
      session_pid,
      {:set_input_value, self(), id, value}
    )
    Kino.JS.Live.Context.broadcast_event(ctx, "value", value)
    %{ref | value: value}
  end
end | 
  
Beta Was this translation helpful? Give feedback.
                  
                    0 replies
                  
                
            
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment
  
        
    
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
We have a custom data table component and, we would like the currently selected row to behave similarly to how a
Kino.Input.selectwould behave.This means if we are to deploy our notebook as an app via teams, it would make it easier to implement master-detail views. You click on a row in the table, then a form in the next cell is rendered.
It means being able to take advantage of the following properties built-in
Kino.Inputcomponents have:(We could use frames, but that is more complex than being able to create a bunch of cells and have them chained to each other.)
I looked at the Kino library and it looks like rendering bottoms out at a data structure that is then handled within livebook itself.
And Livebook traverses these inputs
Livebook.Notebook.Cell.find_inputs_in_outputso it looks like this is currently not possible even with low level APIs.If I had
Kino.Input.hiddenI could work around this because then I would just need to keep aselected_row_idproperty in sync with the hidden input.Or perhaps there's a way to expose an API so, for a particular component, I can register an input and read/write input values.
Thoughts?
Beta Was this translation helpful? Give feedback.
All reactions