README.md

# PhxFrontend

Helpers for rendering components from typical single-page-app frameworks from Phoenix LiveView.

Works with adapters for different frameworks, e.g.

- [Svelte adapter](https://github.com/hungry-egg/phx-frontend-svelte)
- [React adapter](https://github.com/hungry-egg/phx-frontend-react)
- [Vue adapter](https://github.com/hungry-egg/phx-frontend-vue)

## Installation

This package is [on Hex](https://hexdocs.pm/phx_frontend), so you can add`phx_frontend` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:phx_frontend, "~> 0.1.0"}
  ]
end
```

## Setup

Given a Phoenix app `MyApp`:

1. Import the provided components for use in heex templates

In `my_app_web.ex`:

```diff
defmodule MyAppWeb do

  # ...

  def html_helpers do
    # ...
+    import PhxFrontend.Components
    # ...
  end

  # ...
end
```

2. Add the provided hook to the LiveSocket

In `app.js`:

```diff
// ...
+ import { createJsAppsHook } from "phx-frontend";

// ...

let liveSocket = new LiveSocket("/live", Socket, {
  // ...
  hooks: {
+    jsApp: createJsAppsHook({
+      apps: {
+        // individual JS components will go here
+      }
+    })
  }
});

// ...
```

## Rendering a component from LiveView

Let's say we have a React `Counter` component that we would normally use in React like so

```jsx
<Counter count={4} onIncrement={() => console.log(`Increment count!`)} />
```

1. Use the helper in your liveview:

```elixir
  def render(assigns) do
    ~H"""
    <.js_app
      id="my-js-app"
      component="Counter"
      props={%{count: @count}}
      callbacks={%{onIncrement: "increment"}}
    />
    """
  end

  def handle_event("increment", _params, socket) do
    IO.puts("Increment count!")
    {:noreply, socket}
  end
```

2. Register the component using the relevant adapter

In `app.js`:

```diff
// ...
+import reactAdapter from "phx-frontend-react";
+import Counter from "path/to/react/counter/component";

let liveSocket = new LiveSocket("/live", Socket, {
  // ...
  hooks: {
    // ...
    jsApp: createJsAppsHook({
      apps: {
        // ...
+        Counter: reactAdapter(Counter)
      },
    }),
  },
});

// ...

```

### Passing params to `handle_event`

By default, `handle_event` receives an empty map `%{}` for the params.
If you wish to pass params back from the js app to the liveview, refer to the documentation for the particular adapter you're using how to do this.

## Adapters

Adapters for each framework are small and easy to write for new libraries. See the top of page for some examples.