KinoLiveViewNative

Mix.install(
  [
    {:kino_live_view_native, path: "../kino_live_view_native"}
  ],
  config: [
    # This must be a compile time configuration for :live_view_native.
    live_view_native: [plugins: [LiveViewNative.SwiftUI]],
    live_view_native_stylesheet: [parsers: [swiftui: LiveViewNative.SwiftUI.RulesParser]],
    phoenix_template: [
      format_encoders: [
        swiftui: Phoenix.HTML.Engine
      ]
    ]
  ],
  force: true
)

KinoLiveViewNative.start([])

Quickstart

To use the KinoLiveViewNative project we need to install it. You can include the following in your Notebook dependencies and setup section of Livebook.

Mix.install(
  [
    {:kino_live_view_native, path: "../kino_live_view_native"}
  ],
  config: [
    # This must be a compile time configuration for :live_view_native.
    live_view_native: [plugins: [LiveViewNative.SwiftUI]],
    live_view_native_stylesheet: [parsers: [swiftui: LiveViewNative.SwiftUI.RulesParser]],
    phoenix_template: [
      format_encoders: [
        swiftui: Phoenix.HTML.Engine
      ]
    ]
  ],
)

We need to start the server. This could be hidden in in notebook dependencies to make the experience more streamlined for your reader.

KinoLiveViewNative.start()

You may optionally configure the port to start the server on. By default, the server starts on port 4000.

KinoLiveViewNative.start(port: 5001)

Let's create a basic LiveView that will be available at http://localhost:4000.

require KinoLiveViewNative.Livebook
import KinoLiveViewNative.Livebook
import Kernel, except: [defmodule: 2]

defmodule Server.ExampleLive do
  use Phoenix.LiveView
  use LiveViewNative.LiveView

  @impl true
  def render(%{format: :swiftui} = assigns) do
    ~SWIFTUI"""
    <Text>Hello from LiveView Native!</Text>
    """
  end

  def render(assigns) do
    ~H"""
    <p>Hello from LiveView!</p>
    """
  end
end
|> KinoLiveViewNative.register("/", ":index")

import KinoLiveViewNative.Livebook, only: []
import Kernel
:ok

KinoLiveViewNative uses automatic code reloading, so anytime you change this file or evaluate one of the LiveView Native smart cells, the server will hot reload the page.

Evaluate the cell below that changes the text, and you should see the application reload in your simulator.

require KinoLiveViewNative.Livebook
import KinoLiveViewNative.Livebook
import Kernel, except: [defmodule: 2]

defmodule Server.HotReloadExampleLive do
  use Phoenix.LiveView
  use LiveViewNative.LiveView

  @impl true
  def render(%{format: :swiftui} = assigns) do
    ~SWIFTUI"""
    <Text>
      Hello again from LiveView Native!
    </Text>
    """
  end

  def render(assigns) do
    ~H"""
    <p>Hello again from LiveView!</p>
    """
  end
end
|> KinoLiveViewNative.register("/", ":index")

import KinoLiveViewNative.Livebook, only: []
import Kernel
:ok

Dealing with path variables

KinoLiveViewNative lets you set path variables using the :path_variable syntax you would normally use in a Phoenix router. Here's an example that uses the path variable to display a name in the hello world application.

require KinoLiveViewNative.Livebook
import KinoLiveViewNative.Livebook
import Kernel, except: [defmodule: 2]

defmodule Server.PathVariableExampleLive do
  use Phoenix.LiveView
  use LiveViewNative.LiveView

  @impl true
  def mount(%{"name" => name}, _session, socket) do
    {:ok, assign(socket, :name, name)}
  end

  @impl true
  def render(%{format: :swiftui} = assigns) do
    ~SWIFTUI"""
    <Text>Hi there, I'm <%= @name %></Text>
    """
  end

  def render(assigns) do
    ~H"""
    <p style="color: purple">Hi there, I'm <%= @name %></p>
    """
  end
end
|> KinoLiveViewNative.register("/hello/:name", ":index")

import KinoLiveViewNative.Livebook, only: []
import Kernel
:ok

Go to http://localhost:4000/hello/your_name. Replace your_name with your name and see the page display your name!

Image

The URL for the LiveView Native The SwiftUI Image view is evaluated relative to the LiveView's host URL. We have provided an example image at http://localhost:4000/images/logo.png for you to use in any examples.

require KinoLiveViewNative.Livebook
import KinoLiveViewNative.Livebook
import Kernel, except: [defmodule: 2]

defmodule Server.ImageExampleLive do
  use Phoenix.LiveView
  use LiveViewNative.LiveView

  @impl true
  def render(%{format: :swiftui} = assigns) do
    ~SWIFTUI"""
    <AsyncImage url="./images/logo.png"/>
    """
  end

  def render(assigns) do
    ~H"""
    <img src="./images/logo.png"/>
    """
  end
end
|> KinoLiveViewNative.register("/", ":index")

import KinoLiveViewNative.Livebook, only: []
import Kernel
:ok

This is the same as providing the full host url. The following example will also work.

require KinoLiveViewNative.Livebook
import KinoLiveViewNative.Livebook
import Kernel, except: [defmodule: 2]

defmodule Server.FullURLImageExampleLive do
  use Phoenix.LiveView
  use LiveViewNative.LiveView

  @impl true
  def render(%{platform_id: :swiftui} = assigns) do
    ~SWIFTUI"""
    <AsyncImage url="http://localhost:4000/images/logo.png"/>
    """
  end

  def render(assigns) do
    ~H"""
    <img src="./images/logo.png"/>
    """
  end
end
|> KinoLiveViewNative.register("/", ":index")

import KinoLiveViewNative.Livebook, only: []
import Kernel
:ok

However, it's generally better to use the relative path without the host name because it will work in both development and production.