Mesa provides an easy way of creating functional web tables. The user supplies a row type and "actions" to be run on those rows (along with some other funtionality) and the user gets back a table capable of:

- Partial rendering
- Navigating the table with the arrow keys and the mouse
- Sorting the table on a column
- Editing the table-cells' values and communicating those changes back to a server
- Searching the table for a row

Compared to table.mli, mesa are quicker and easier to set up but offer less flexibility.

### Cell

Cells are the smallest building blocks of an mesa. To create a `Cell.t`, users supply a `read` function as a way to project the cell value from row and a `Cell.Kind.t` to determine how that value is displayed. Optionally, users can supply a `write` function as a way to inject values into row.

Multiple cells can be displayed at the intersection of a row and a column. This is intended to enable users to group related data, e.g. buy/sell edge, min/max fair, etc.

### Column

Columns define a group (of size one or more) of related data points within a single row. They accomplish this by housing one or more cells, visually arranging them either horizontally or vertically. Each column has a header as well as an optional `group` to visually group multiple columns together. Users can also supply a `sort_by` function to enable sorting on that column.

### Row

Rows are the individual data structures of the table, holding the actual data to be displayed in the table. In order to create the Mesa module, the user must supply this type along with some additional functionality. An ID must be included as well as an `equal` function to determine when a row's data has changed, and therefore needs to be updated on the screen.

Row also requires Action. Action allows users to supply a set of events that can occur on a `Row.t`. One requirement for Action is a way to construct an `Action.t` that signals that an edit has been commited. However, if none of your `Cell.t`s are writable, then this funtion will never be called.

In addition, 2 functions are required; `apply_action` and `key_handler`. `apply_action` supplies a way to implement the `Action.t`s. The user is given their `report_error` function to report errors from a deferred operation. The `key_handler` tells Mesa how to convert keyboard events into `Action.t`s and provides a funciton to turn those `Action.t`s into the necessary `Vdom.Event.t`.

### Mesa

`Make` returns a module that is easy to plug into your Incr_dom program.

#### Mouse events

- Single clicks focuses a row. This is disabled when editing cells
- Double clicks start edit mode for the row

- Scroll wheel scrolls the table, however this is disabled when editing a row

  #### Keyboard events

          | Key code  | View mode               | Edit mode                                    | Search mode       |
          |-----------+-------------------------+----------------------------------------------+-------------------|
          | up/C-p    | move focus up one row   | move cursor to the next editable cell        |                   |
          | down/C-n  | move focus down one row | move cursor to the previous editable cell    |                   |
          | right/C-f |                         | move cursor to the next editable column      |                   |
          | left/C-b  |                         | move cursor to the previous editable column  |                   |
          | /         | start row search        |                                              |                   |
          | e         | start row edit          |                                              |                   |
          | Enter     | [Row.key_handler]       | commit edits                                 | focus current row |
          | Esc       | [Row.key_handler]       | abandon edits                                | abandon search    |
          | _         | [Row.key_handler]       | [Row.key_handler]                            | [Row.key_handler] |

`module type State = State`
`module type Row = Row`
`module type S = S`
`module Config = Config`
`module Make : functor (State : State) -> functor (Row : Row with module State := State) -> S with module State = State and module Row = Row`
`type packed````=`

`|` `T : ((module S with type Model.t = 'model) * 'model) ‑> packed`

``
`val pack : (module S with type Model.t = 'model) ‑> 'model ‑> packed`