# `Xenia.Adapters.Tabulator`
[🔗](https://github.com/uzaydurdu/xenia/blob/v0.1.1/lib/xenia/adapters/tabulator.ex#L1)

`<.tabulator>`: an interactive data table (Tabulator), through Xenia's official adapter.

## Setup

Install the library in your app:

    npm install tabulator-tables --prefix assets

Pass it to the adapter, and register it, in `assets/js/app.js`:

```js
import { createTabulator } from "xenia/tabulator"

const tabulator = createTabulator({
    load: () => import("tabulator-tables"),
})

hooks: { ...colocatedHooks, ...createHooks({ Tabulator: tabulator }) },
```

And its CSS, in `assets/css/app.css`:

    @import "../node_modules/tabulator-tables/dist/css/tabulator_simple.min.css";

Then `import Xenia.Adapters.Tabulator` in `html_helpers`, and render
`<.tabulator id="...">` with the props below. Every event becomes an
`on_<event>` attribute; commands go through `Xenia.push_to/4`.

The factory returns a plain adapter object: spread it to add or change
props, commands and events, without copying the adapter.

The tag uses the adapter name `"Tabulator"`. To register it under
another name, render `<.xenia adapter="...">` or declare your own tag.

## Reference

  Xenia's official adapter for Tabulator (v6): an interactive data grid with sorting,
  filtering, inline editing, row selection, pagination and export.

  Rows are updated in place: when `data` changes, only changed rows are
  updated, removed rows deleted and new rows appended, so scroll position,
  selection, sorting and editing state survive server updates. A changed
  row order falls back to replacing the data (still keeping sort/filter).

  Props:
    data         [%{id, ...}]   rows; `id` identifies a row (see `index`)
    columns      [%{title, field, sorter?, editor?, formatter?, width?,
                    hoz_align?, header_filter?, editor_params?, ...}]
                 Column keys may be snake_case. Values (also inside *_params
                 maps) are passed unchanged. Changing columns keeps the rows.
    index        the row id field (default "id")
    height       CSS height, e.g. "400px"; nil lets the table grow
    layout       "fitColumns" (default) | "fitData" | "fitDataFill" | ...
    selectable   true (any number), a number (max rows), or false
    page_size    rows per page; enables pagination
    placeholder  text shown when there are no rows
    sort         [%{column, dir: "asc" | "desc"}]   applied when it changes
    filter       [%{field, type: "=" | "like" | ">" | ..., value}]
    options      any other Tabulator option, snake_case or camelCase
                 (movable_rows, group_by, frozen_rows, history, ...).
                 Tabulator reads most options only once, so changing
                 `options` remounts the table.

  Commands:
    set_sort %{sort: [...]}, clear_sort
    set_filter %{filter: [...]}, clear_filter
    select_rows %{ids}, deselect_rows %{ids?}
    scroll_to_row %{id, position?: "top" | "center" | "bottom" | "nearest"}
    download %{type: "csv" | "json" | "html", filename?}
    undo, redo                      (needs options: %{history: true})
    revert_edit %{id, field}        undo the user's last edit of a cell,
                                    e.g. when the server rejects it
    reset                           re-render the last `data` prop

  Events:
    ready        %{rows}
    cell_edited  %{id, field, value, old_value, row}
    row_click    %{id, row}, row_dblclick %{id, row}
    selection    %{ids}                 the user changed the selection
    sort         %{sort: [%{column, dir}]}   the user sorted by a header
    filter       %{filter: [...]}       header filters changed (300 ms)
    page         %{page}
    row_moved    %{ids}                 with movable_rows: the new order
    error        %{source, message, code}

  Load a Tabulator theme in app.css, e.g.
    @import "../node_modules/tabulator-tables/dist/css/tabulator_simple.min.css";
  (tabulator_midnight.min.css is a dark theme.)

# `tabulator`

## Attributes

* `id` (`:string`) (required) - Stable DOM id used for adapter commands.
* `data` (`:list`) (required)
* `columns` (`:list`) (required)
* `index` (`:string`)
* `height` (`:string`)
* `layout` (`:string`)
* `selectable` (`:any`)
* `page_size` (`:integer`)
* `placeholder` (`:string`)
* `sort` (`:list`)
* `filter` (`:list`)
* `options` (`:map`)
* `on_ready` (`:string`) - LiveView event triggered when the adapter emits :ready. Defaults to `nil`.
* `on_cell_edited` (`:string`) - LiveView event triggered when the adapter emits :cell_edited. Defaults to `nil`.
* `on_row_click` (`:string`) - LiveView event triggered when the adapter emits :row_click. Defaults to `nil`.
* `on_row_dblclick` (`:string`) - LiveView event triggered when the adapter emits :row_dblclick. Defaults to `nil`.
* `on_selection` (`:string`) - LiveView event triggered when the adapter emits :selection. Defaults to `nil`.
* `on_sort` (`:string`) - LiveView event triggered when the adapter emits :sort. Defaults to `nil`.
* `on_filter` (`:string`) - LiveView event triggered when the adapter emits :filter. Defaults to `nil`.
* `on_page` (`:string`) - LiveView event triggered when the adapter emits :page. Defaults to `nil`.
* `on_row_moved` (`:string`) - LiveView event triggered when the adapter emits :row_moved. Defaults to `nil`.
* `on_error` (`:string`) - LiveView event triggered when the adapter emits :error. Defaults to `nil`.
* `shortcuts` (`:map`) - Key combination => LiveView event, while focus is inside (see Xenia.Shortcuts). Defaults to `%{}`.
* `on_crash` (`:string`) - LiveView event sent if the adapter throws (see Xenia.Component). Defaults to `nil`.
* Global attributes are accepted.
## Slots

* `loading` - Shown until the island's first mount finishes.
* `error` - Shown if the adapter throws; data-xenia-retry starts it again.

---

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