# `MishkaGervaz.Table.Behaviours.ActionType`
[🔗](https://github.com/mishka-group/mishka_gervaz/blob/v0.0.2/lib/mishka_gervaz/table/behaviours/action_type.ex#L1)

Behaviour for row action type renderers.

Implement this behaviour to create custom action types that render
buttons/links in specific ways.

## Example

    defmodule MyApp.ActionTypes.Confirm do
      @behaviour MishkaGervaz.Table.Behaviours.ActionType
      use Phoenix.Component
      import MishkaGervaz.Helpers,
        only: [action_label: 1, resolve_confirm: 2, dynamic_component: 1]

      @impl true
      def render(assigns, action, record, ui, target) do
        master? = assigns[:state] && assigns[:state].master_user?

        assigns =
          %{__changed__: %{}}
          |> assign(:module, ui)
          |> assign(:function, :button)
          |> assign(:label, action_label(action))
          |> assign(:icon, action[:ui][:icon])
          |> assign(:class, action[:ui][:class] || "text-orange-600 hover:text-orange-800")
          |> assign(:phx_click, action[:event] || "confirm")
          |> assign(:phx_value_id, record.id)
          |> assign(:phx_target, target)
          |> assign(
            :data_confirm,
            (master? && resolve_confirm(action[:confirm], record)) || "Are you sure?"
          )

        ~H"""
        <.dynamic_component {assigns} />
        """
      end
    end

Then use in DSL:

    row_actions do
      action :archive, type: MyApp.ActionTypes.Confirm, confirm: "Archive this record?"
    end

## What belongs in the assigns map

Read whatever you need from the incoming `assigns`, then build a **fresh** map for the component.
The map you build is splatted whole at the UI adapter, and `button/1` declares
`attr :rest, :global` — so every key it does not recognise is rendered as an HTML attribute of its
own. Passing the incoming `assigns` through would put the whole table state in the markup.

Three kinds of key belong in it, and nothing else:

- `:module` and `:function`, which `MishkaGervaz.Helpers.dynamic_component/1` pops off to decide
  what to call. They never reach the markup.
- The attributes the component declares — `:label`, `:icon`, `:class`, `:variant`.
- Bindings named `phx_*` and `data_*`, which are dashed into `phx-click`, `phx-value-id`,
  `phx-target` and `data-confirm` on the way through.

A record id, a target or a confirm message therefore travels under its binding name —
`:phx_value_id`, `:phx_target`, `:data_confirm` — not under a name of its own. `:record_id`,
`:target` and `:confirm` are not attributes of anything and are rendered verbatim.

`MishkaGervaz.Helpers.maybe_assign/3` is the way to set a key only when it has a value, so an
absent option does not become an empty attribute.

## Text the resource declared

Read the label with `MishkaGervaz.Helpers.action_label/1` and the confirm message with
`MishkaGervaz.Helpers.resolve_confirm/2`: a string is translated in the caller's locale and a
function is called, as every built-in type does.

## Accessing State

The `assigns` parameter includes the full table state:

- `assigns[:state]` - The table state struct
- `assigns[:state].config[:identity][:route]` - Base route for the resource
- `assigns[:state].master_user?` - Whether current user is master

See `MishkaGervaz.Table.Types.Action` (registry),
`MishkaGervaz.Table.Entities.RowAction`,
`MishkaGervaz.Table.Entities.BulkAction`, and
`MishkaGervaz.Table.Behaviours.TypeRegistry`.

# `render`

```elixir
@callback render(
  assigns :: map(),
  action :: map(),
  record :: map(),
  ui :: module(),
  target :: any()
) ::
  Phoenix.LiveView.Rendered.t()
```

Render the action button/link.

## Parameters

- `assigns` - Phoenix assigns map with `:state`, `:ui`, `:myself` keys
- `action` - Action configuration map from DSL
- `record` - The record this action is for
- `ui` - UI adapter module for consistent styling
- `target` - LiveComponent target for phx-target

## Returns

Phoenix.LiveView.Rendered.t()

---

*Consult [api-reference.md](api-reference.md) for complete listing*
