npm package: @lightspeed/cirrus-table
Description: Cirrus Table Component
Author: Lightspeed
Latest version: 1.0.4

# Table

A set of recommended design rules and reusable React components to create tables of data quickly for specific workflow needs.

They should help customers find, view, organize and interact with their data in easy and convenient ways. The interface should disappear so that retailers can focus on the job at hand.

## Installation

First, make sure you have been through the [install steps](https://github.com/lightspeed/flame#installing) steps required to add Flame in your application. Although it's not required to have Flame installed to use Logo, you will need to install its peer dependencies.

If using [Yarn](https://yarnpkg.com/):

```sh
yarn add @lightspeed/cirrus-table
```

Or using [npm](https://www.npmjs.com/):

```sh
npm i -S @lightspeed/cirrus-table
```

## Styled System props

| Component Name | styled-system props                                                                                   |
| -------------- | ----------------------------------------------------------------------------------------------------- |
| Td             | [height](https://github.com/jxnblk/styled-system/blob/master/docs/api.md#layout)                      |
|                | [width](https://github.com/jxnblk/styled-system/blob/master/docs/api.md#width)                        |
|                | [space](https://github.com/jxnblk/styled-system/blob/master/docs/api.md#space)                        |
|                | [fontSize](https://github.com/jxnblk/styled-system/blob/master/docs/api.md#fontSize)                  |
|                | [textAlign](https://github.com/jxnblk/styled-system/blob/master/docs/api.md#typography)               |
|                | [color](https://github.com/jxnblk/styled-system/blob/master/docs/api.md#color)                        |
| Th             | [color](https://github.com/jxnblk/styled-system/blob/master/docs/api.md#color)                        |
|                | [height](https://github.com/jxnblk/styled-system/blob/master/docs/api.md#layout)                      |
|                | [width](https://github.com/jxnblk/styled-system/blob/master/docs/api.md#width)                        |
|                | [space](https://github.com/jxnblk/styled-system/blob/master/docs/api.md#space)                        |
|                | [display](https://github.com/jxnblk/styled-system/blob/master/docs/api.md#layout)                     |
|                | [alignItems, justifyContent](https://github.com/jxnblk/styled-system/blob/master/docs/api.md#flexbox) |
|                | [fontSize](https://github.com/jxnblk/styled-system/blob/master/docs/api.md#fontSize)                  |
| Tr             | [color](https://github.com/jxnblk/styled-system/blob/master/docs/api.md#color)                        |
|                | [space](https://github.com/jxnblk/styled-system/blob/master/docs/api.md#space)                        |

## Usage

### Components

#### `<Table>`

Note: you need to manually wrap the `<Table>` with a `<Card>` to get the recommended visual for tables. This is left to the consumer for maximum flexibility.

Styled table tag (`<table>`) with the following props:

| Prop             | Type                         | Description                                                 |
| ---------------- | ---------------------------- | ----------------------------------------------------------- |
| `loadingStatus?` | `"loading"` or `"completed"` | Shows a loading indicator between the table header and body |

#### Base Table Elements

##### `<Thead>`

An augmented version of the table header which features a loading bar hooked onto the table's loading state

##### `<Th>`

A Styled System augmented table heading tag (`<th>`)

##### `<Tr>`

A Styled System augmented table row tag (`<tr>`)

| Prop        | Type   | Description                                                 |
| ----------- | ------ | ----------------------------------------------------------- |
| isHoverable | `bool` | If true, no hover style will be applied, `false` by default |

##### `<Td>`

A Styled System augmented table cell tag (`<td>`).

##### `<Tbody>`

An emotion instantiated `tbody`. No augmentation added, it's simply there for markup stylistic purposes.

##### `<Tfoot>`

An emotion instantiated `tfoot`. No augmentation added, it's simply there for markup stylistic purposes.

##### `<NoDataTd>`

An extension of `<Td>`. It comes with a pre-formatted styles for a no data state.

#### `<Pager />`

A simple pager component designed for the table.

| Prop           | Type   | Description                                                  |
| -------------- | ------ | ------------------------------------------------------------ |
| isFirst        | `bool` | If true, the "back" pager button is disabled                 |
| isLast         | `bool` | If true, the "forward" pager button is disabled              |
| handleNext     | `func` | Callback function attached to the the "forward" pager button |
| handlePrevious | `func` | Callback function attached to the the "back" pager button    |
| children       | `any`  | Element will be added to the front of the Pager button group |

#### Table Action Components & Filtering

Additional actions can be added to the table.

Table exports an all encompassing Object called TableActions, which contains various components that are hooked to a single context that mostly handles the interconnected ui state possible within actions, e.g: filters and tags.

##### Using the `TableActions.Context and Actions`

The TableActions provides many ways to add and remove filters programaticaly.

Here are some of the exposed functions that will come in handy:

| Prop                                                         | Description                                                    |
| ------------------------------------------------------------ | -------------------------------------------------------------- |
| applyFilter(filterKey, label, value)                         | Upserts a new filter with a corresponding label and raw values |
| applyFilters(Array<{key:string, value: any, label: string}>) | Replace filters with the current list sent in parameters       |
| deleteFilter(filterKey)                                      | Delete a filter by key                                         |
| deleteAllFilters()                                           | Deletes all filters                                            |
| deleteAllFiltersAndSearchTerm                                | Deletes all filters, including the search term                 |
| getValues(filterKey)                                         | Retrieves a global count of all active filters                 |
| getFilters()                                                 | Retrieves the entire list of active filters                    |

There are two ways of gaining access to these functions:

**Using React.useContext**

```jsx
const MyApp = () => {
  const { applyFilter, deleteFilter /* ... */ } = React.useContext(TableActions.Context);
};
```

**Via the consumer component**

```jsx
const MyApp = () => {
  return (
    <TableActions.Consumer>
      {({ applyFilter, deleteFilter, /* ... */ }) => (
        /* ... */
      )}
    </TableActions.Consumer>
  );
}
```

##### `TableActions.FilterPanelProvider`

A Provider to keep track of active filters and routing of the `TableActions.Dropdown`

| Prop                  | Type                                             | Description                                                                                                                                                                                                  |
| --------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| onFilterChange        | `func`                                           | Callback function that will receive in parameters the currently selected array of filters                                                                                                                    |
| initialSearchTerm     | `string`                                         | The initial search term. If using TableActions.SearchBar, it'll automatically use the initialSearchTerm as it's value                                                                                        |
| initialFilters        | `Array<{key:string, value: any, label: string}>` | The initial filters for the table actions. See [PagerTable](https://github.com/lightspeedretail/cirrus/tree/master/packages/cirrus-table/examples/PagerTable/index.js) on how to set initialFilters properly |
| renderDropdownContent | `ReactNode`                                      | The content that will be used within dropdowns. Primarely used to have a single point of entry for dropdown content used by the search bar dropdown and the filter tag dropdowns                             |

```jsx
const MyApp = () => (
  <TableActions.Provider
    initialSearchTerm={{}}
    initialFilters={{}}
    onFilterChange={() => {}}
    renderDropdownContent={<div>The shared content that will appear in the Dropdown</div>}
  >
    {/*
        Render the rest of your content here.
    */}
  </TableActions.Provider>
);
```

##### `TableActions.ActionBar`

A wrapper component which sets the right positioning of elements. This is a simple dumb component with no logic.

| Prop             | Type        | Description                                                                          |
| ---------------- | ----------- | ------------------------------------------------------------------------------------ |
| leftHandActions  | `ReactNode` | Render slot the left. Usually, you will want to add you search bar and dropdown here |
| rightHandActions | `ReactNode` | Render slot for right. The pager should be here                                      |
| children         | `ReactNode` |                                                                                      |

```jsx
const MyApp = () => (
  <TableActions.ActionBar
    leftHandActions={<div>this div will appear on the left</div>}
    rightHandActions={<div>this div will appear on the right</div>}
  >
    <div>this div will appear underneath the previously set actions</div>
  </TableActions.ActionBar>
);
```

##### `TableActions.SearchBar`

A prebuilt search bar component hooked onto the filtering context. Simply add and use.

Pressing enter or clicking on the button will trigger a change to the stored search term within the provider and cause `onFilterChange` to be executed.

| Prop        | Type     | Description                                           |
| ----------- | -------- | ----------------------------------------------------- |
| buttonText  | `string` | Text that appears on the search button                |
| buttonTitle | `string` | Text for `title` attribute of the search button       |
| placeholder | `string` | Placeholder text that appears on the search input     |
| disabled    | `bool`   | Set to true to disable search input and search button |

```jsx
const MyApp = () => (
  <TableActions.Provider
    initalSearchTerm="I will automatically appear in the search bar"
    onFilterChange={(filters, searchTerm) => {
      // When pressing enter on the search bar or clicking on the submit button,
      // This function will be triggered
    }}
    renderDropdownContent={<div>The shared content that will appear in the Dropdown</div>}
  >
    <TableActions.SearchBar placeholder="Put your search term here" buttonText="Search" />
  </TableActions.Provider>
);
```

##### `TableActions.FilterTagLister`

A list of all Filters active. Automatically hooked to the `TableActions.FilterPanelProvider`.
It will automatically select the right dropdown view, based on which tag has been picked.

| Prop           | Type        | Description                                                 |
| -------------- | ----------- | ----------------------------------------------------------- |
| renderDropdown | `ReactNode` | (Optional) Override of the provider's renderDropdownContent |
| dropdownWidth  | `ReactNode` | Width of the dropdown                                       |
| children       | `ReactNode` |                                                             |

```jsx
const MyApp = () => (
  <TableActions.Provider
    initalFilters={{
      status: {
        value: 'Any value to store relevant data for the filtering process'
        label: 'This is what will appear on a tag'
      }
    }}
    renderDropdownContent={
        <TableActions.Dropdown>
          {/*
            Notice how the initialFilters object has `status` as an object key
            If we want the TableActions.FilterTagLister to pick up the right
            TableActions.DropdownSection, ensure that the key and filterKey match!
          */}
          <TableActions.DropdownSection title="Just some title" filterKey="status">
            Anything in the `TableActions.DropdownSection` will be rendered when clicking
            on the Tag generated from `TableActions.FilterTagLister`
          </TableActions.DropdownSection>
        </TableActions.Dropdown>
    }
  >
    <TableActions.FilterTagLister />
  </TableActions.Provider>
);
```

##### `TableActions.DropdownMenu`

A wrapper component which will render automatically render the `TableActions.Dropdown` acquired from the provider.
It will handle swapping between a list view or a detailed view.

| Prop           | Type        | Description                                                 |
| -------------- | ----------- | ----------------------------------------------------------- |
| renderDropdown | `ReactNode` | (Optional) Override of the provider's renderDropdownContent |
| dropdownWidth  | `ReactNode` | Width of the dropdown                                       |
| children       | `ReactNode` |                                                             |

```jsx
const MyApp = () => (
  <TableActions.Provider
    renderDropdownContent={
      <TableActions.Dropdown>
        This content will only be rendered within the list view...
        <TableActions.DropdownSection title="Just some title" filterKey="status">
          Anything in the `TableActions.DropdownSection` will be rendered when clicking on the
          corresponding link in the list view.
        </TableActions.DropdownSection>
      </TableActions.Dropdown>
    }
  >
    <TableActions.DropdownMenu />
  </TableActions.Provider>
);
```

##### `TableActions.Dropdown`

The main Dropdown component to be used within the container. This is needed to create the multi-page approach of the filtering dropdown.

Concretely, there are two pages within this dropdown: The listing page and the details page.

The "listing" page is simply whatever components passed in as child to the `TableActions.Dropdown`. It'll render whatever is passed in as is, with the exception of `TableActions.DropdownSection`.

If a `TableActions.DropdownSection` is detected, that component will instead output a clickable menu item. When clicked, the dropdown view will automatically swap to render out the given `TableActions.DropdownSection` children elements instead.

| Prop       | Type     | Description                                                                                                    |
| ---------- | -------- | -------------------------------------------------------------------------------------------------------------- |
| goBackText | `string` | Text that appears on the "back" button within a details view. Automatically hidden when rendered within a tag. |

##### `TableActions.DropdownSection`

A section/page of the dropdown. Use this component to automatically create the filter menu within the Dropdown, as well as rendering a "details" view that will be rendered when selected.

| Prop      | Type        | Description                                                                       |
| --------- | ----------- | --------------------------------------------------------------------------------- |
| title     | `string`    | Text that appears on the list view of the dropdown                                |
| filterKey | `string`    | Identifier for the section. For syncing the rendering of a section to a given tag |
| children  | `ReactNode` |                                                                                   |

##### `TableActions.DropdownTitle`

A pre configured version of Cirrus Text to fit the dropdown styling.

##### `TableActions.DropdownActions`

A pre configured version of Cirrus Flex to fit within dropdown styling. Use this to output your filter buttons.

#### `TableActions.DropdownDivider`

A pre configured version of Cirrus Divider. Use this to add a properly padded seperator between elements.

#### `TableActions.DropdownButtonLink`

A pre configured version of Cirrus Button that makes a button look like a link for usage within the Dropdown.

#### `TableActions.CheckboxGroup`

A prestyled and context aware checkbox group.

| Prop       | Type                                     | Description                                                                                                                                                                                                                                                                                                                                                                                         |
| ---------- | ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| checkboxes | `Array<{ label: string, value: string}>` | Config object to generate checkboxes. Simply pass in the label and the associated value                                                                                                                                                                                                                                                                                                             |
| filterKey  | `string`                                 | Identifier for the filter. Use this to bind the child functions to the appropriate filter key                                                                                                                                                                                                                                                                                                       |
| children   | `Child function ReactNode`               | Accepts a child function. It forwards an object with two following functions: undoChanges and applyFilter. undoChanges will clear the internal state of the checkbox group but not trigger an actual filter change. applyFilter accepts either a string to be applied as the label for a given tag or a callback function that sends the selected items in parameter and expects a string in return |

#### `TableActions.RadioGroup`

A prestyled and context aware radio group.

| Prop      | Type                                     | Description                                                                                                                                                                                                                                                                                                                                                                                      |
| --------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| radios    | `Array<{ label: string, value: string}>` | Config object to generate radios. Simply pass in the label and the associated value                                                                                                                                                                                                                                                                                                              |
| filterKey | `string`                                 | Identifier for the filter. Use this to bind the child functions to the appropriate filter key                                                                                                                                                                                                                                                                                                    |
| children  | `Child function ReactNode`               | Accepts a child function. It forwards an object with two following functions: undoChanges and applyFilter. undoChanges will clear the internal state of the radio group but not trigger an actual filter change. applyFilter accepts either a string to be applied as the label for a given tag or a callback function that sends the selected items in parameter and expects a string in return |

### All About Table Features

##### The Basics

By default, the table is completely stateless and allows you to build and structure it however you want, since the table provides multiple small building blocks.

We also provide some pre-built functionality in form of hooks that you can use immediately with the provided components.

#### The Sort Feature

Sort exports a hook that pre-binds state as well as a convenient `SortButton` component and a pre-built `Th` component that you can slide into the appropriate spot of the table.

```jsx
import { Table, Thead, Tr, Td, Sortable } from '@lightspeed/cirrus-table';

const MyComponent = () => {
  const {  getSortingDirection, toggleSort, sortKey, sortDirection, setSort }  = Sortable.useSortable();
  // Observe our sortKey/sortDirection for any changes
  React.useEffect(() => {
      // And trigger a side-effect!
    }
  }, [sortKey, sortDirection]);

  return (
    <Card>
      {/* You can use setSort to force save a particular sort state */}
      <button onClick={() => setSort('animal', 'desc')}>
        Descending animals
      </button>

      <Table>
        <Thead>
          <Tr>
          <Sortable.Th
            onClick={toggleSort('animal') /* toggleSort automatically cycle through the sort */}
            direction={getSortingDirection('animal') /* Fully uncontrolled props*/}
          >
            Animal
          </Sortable.Th>
          </Tr>
        </Thead>
        <Tr>
          <Td>Lion</Td>
        </Tr>
        <Tr>
          <Td>Tiger</Td>
        </Tr>
        <Tr>
          <Td>Bear</Td>
        </Tr>
      </Table>
    </Card>
  );
}
```

##### Options

**Sortable.useSortable**

This hook takes two parameters, the first one is the sorting key and second value is the sort order.

Use this to set a default sort order.

```jsx
const MyComponent = () => {
  const { getSortingDirection } = Sortable.useSortable('color', 'asc');

  getSortingDirection('color'); // this will return `asc`
  toggleSort('color'); // This will cycle through the next sorting direction...
  getSortingDirection('color'); // meaning this will now return `desc`

  // ...
};
```

As per UX, only one item can be sorted at a time, and it will always follow the following cycle:

`unsorted -> ascending -> descending`

**Important note**: as of right now, we only support 1 sort option at a time.

#### Components

##### `<Sortable.SortButton>`

| Prop        | Type     | Description                            |
| ----------- | -------- | -------------------------------------- |
| `direction` | `string` | The direction of the arrow for sorting |

##### `<Sortable.Th>`

Convenience compone that simply wraps the SortButton inside a Th.

| Prop        | Type       | Description                            |
| ----------- | ---------- | -------------------------------------- |
| `direction` | `string`   | The direction of the arrow for sorting |
| `onClick`   | `function` | Good ol' function                      |

### Examples

See the [examples](https://github.com/lightspeedretail/cirrus/tree/master/packages/cirrus-table/examples) folder.

#### The Batch Select Feature

Batch Select exposes multiple components as well a hook to manage state. You may use both of them, or mix and match functionalities.

While there may be many functions to bind, most of them are fairly straight forwards to use and self explanatory.

**Example**

```jsx
import { Table, Thead, TBody, Td, BatchSelect } from '@lightspeed/cirrus-table';

const MyApp = () => {
  const {
    itemsSelectedCount,
    toggleAllItems,
    isItemSelected,
    isAllItemsSelected,
    isPartiallySelected,
    toggleItem,
  } = BatchSelect.useBatchSelect(data, {
    idKey: 'id',
    initialSelectedItems: [],
  });

  return (
    <Table>
      <Thead>
        <BatchSelect.HeaderTr
          itemsSelectedCount={itemsSelectedCount}
          selectedItemsText={`${itemsSelectedCount} selected item${
            itemsSelectedCount > 1 ? 's' : ''
          }`}
          checkboxProps={{
            checked: isAllItemsSelected,
            indeterminate: isPartiallySelected,
            onChange: toggleAllItems,
          }}
        >
          <Th>Name</Th>
          <Th>Updated at</Th>
          <Th>Visible</Th>
        </BatchSelect.HeaderTr>
      </Thead>
      <TBody>
        {data.map(item => (
          <BatchSelect.Tr
            key={item.id}
            selected={isItemSelected(item.id)}
            checkboxProps={{
              checked: isItemSelected(item.id),
              onChange: () => {
                toggleItem(item.id);
              },
            }}
          >
            <Td>{item.name}</Td>
            <Td width="150px">{item.updatedAt}</Td>
            <Td width="150px">{item.isVisible}</Td>
          </BatchSelect.Tr>
        ))}
      </TBody>
    </Table>
  );
};
```

##### BatchSelect.useBatchSelect

The `userBatchSelect` hook is used to track what items have been selected.

`useBatchSelect` accepts a configuration object

```jsx
const {} = BatchSelect.useBatchSelect(data, {
  idKey: 'id', // optional
  selectedItems: [], // optional
});
```

| Key           | Is Required? | Description                                                                                                                          |
| ------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
| data          | Required     | `useBatchSelect` will use that data to appropriately track what items are selected or not. `useBatchSelect` will NOT mutate the data |
| idKey         | Optional     | Change the tracking identifier. By default, `useBatchSelect` will only keep track of the `id` key within the `data` object.          |
| selectedItems | Optional     | Preselect items by forwarding an array of `id` (or whatever unique indentifier). By default, this field is an empty array.           |

`useBatchSelect` returns the following variables:

| Name                | Description                                                                                            |
| ------------------- | ------------------------------------------------------------------------------------------------------ |
| selectedItems       | Get the list of all item IDs that are currently selected                                               |
| itemsSelectedCount  | Get a numeric count of the selectedItems                                                               |
| isAllItemsSelected  | Return a boolean value of whether or not the selectedItems is empty or has all items contained within  |
| isPartiallySelected | return a boolean value of whether or not there is at least 1 item selected, but not all items selected |

`useBatchSelect` returns the following functions

| Name           | Params | Description                                                          |
| -------------- | ------ | -------------------------------------------------------------------- |
| isItemSelected | itemID | Checks whether or not an item is selected                            |
| toggleItem     | itemID | Automatically add or remove an item from the `selectedItems` list.   |
| toggleAllItems | -      | Automatically add or remove ALL items from the `selectedItems` list. |
| selectItem     | itemID | Add an item to the `selectedItems` list.                             |
| deselectItem   | itemID | Remove an item from the `selectedItems` list.                        |
| selectAll      | -      | Add all items to the `SelectedItems` list.                           |
| deselectAll    | -      | Remove all items from the `SelectedItems` list.                      |

##### `<BatchSelect.HeaderTr>`

An augmented header table row `<Tr>` that handles adding the initial checkbox column and swapping out the table header row to use an action group when items are selected.
This component is a wrapper on top of `<BatchSelect.CheckboxWell>` and handles the logic of replacing table headers with a `<BatchSelect.CheckboxWell>` when an item is selected.

| Prop                 | Type                  | Description                                                                                 |
| -------------------- | --------------------- | ------------------------------------------------------------------------------------------- |
| `itemsSelectedCount` | `number`              | Quantity of items selected.                                                                 |
| `selectedItemsText`  | `ReactNode`           | The text or element to appear right beside the checkbox when at least one item is selected. |
| `innerGroup`         | `ReactNode`           | Slot to render elements to be attached to the right of the checkbox addon                   |
| `outerGroup`         | `ReactNode`           | Slot to render elements outside of the checkbox addon group.                                |
| `checkboxProps`      | `HTMLCheckboxElement` | Same properties as a regular cirrus Checkbox                                                |
| `children`           | `ReactNode`           | Typically, we put the table header (`<Th>` or `<th>`) elements here                         |

##### `<BatchSelect.Checkbox>`

A specially styled cirrus checkbox for the table. Features a slightly larger hit box.

##### `<BatchSelect.CheckboxWell>`

A special checkbox that is wrapped in a container and can have an attached button to it.

| Prop                | Type        | Description                                                                                 |
| ------------------- | ----------- | ------------------------------------------------------------------------------------------- |
| `selectedItemsText` | `ReactNode` | The text or element to appear right beside the checkbox when at least one item is selected. |
| `innerGroup`        | `ReactNode` | Slot to render elements to be attached to the right of the checkbox addon                   |
| `outerGroup`        | `ReactNode` | Slot to render elements outside of the checkbox addon group.                                |
| `checked`           | `boolean`   | -                                                                                           |
| `indeterminate`     | `boolean`   | -                                                                                           |
| `onChange`          | `boolean`   | Event handler attached on the Checkbox                                                      |
| `children`          | `ReactNode` | Typically, we put the table header (`<Th>` or `<th>`) elements here                         |

##### `<BatchSelect.Tr>`

An augmented table row `<Tr>` that injects a checkbox in the first `<Td />`. Use this component when you do not want to bother with adjusting padding and margins to match specs.

| Prop            | Type                  | Description                                  |
| --------------- | --------------------- | -------------------------------------------- |
| `checkboxProps` | `HTMLCheckboxElement` | Same properties as a regular cirrus Checkbox |
| `...restProps`  | `Tr`                  | Same properties as the `Tr` component        |

##### `<BatchSelect.Dropdown>`

A custom dropdown component for the table.

| Prop       | Type        | Description                                                                                                                                                                                                                          |
| ---------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `title`    | `string`    | The text content of the dropdown button                                                                                                                                                                                              |
| `children` | `ReactNode` | What will be rendered within the dropdown menu when the dropdown button is clicked. BatchSelect. Dropdown can also take a child function. Destructuring it will give back a `toggleOpen` function to programatically close the menu. |

**example**

```jsx
<BatchSelect.Dropdown title="Action">
  <BatchSelect.DropdownList>
    <li>An element</li>
    <li>Another element</li>
  </BatchSelect.DropdownList>
</BatchSelect.Dropdown>

// If we need access to toggleOpen function...
<BatchSelect.Dropdown title="Action">
  {({ toggleOpen }) => (
    <BatchSelect.DropdownList>
    <li>An element</li>
    <li>
      <button onClick={toggleOpen}>Close dropdown</button>
    </li>
  </BatchSelect.DropdownList>
  )}
</BatchSelect.Dropdown>
```

##### `<BatchSelect.DropdownList>`

A prestyled `<ul>` element to be used within the dropdown.

**example:**

```jsx
<BatchSelect.DropdownList>
  <li>An element</li>
  <li>Another element</li>
</BatchSelect.DropdownList>
```

##### `<BatchSelect.BulkButton>`

A prestyled cirrus `<Button>` element to be used within a `BatchSelect.HeaderTr` or `BatchSelect.CheckboxWell` inner group.

#### The Draggable feature

Draggable enables to drag and drop rows to for the purpose of sorthing them.

The draggable feature is a collection of pre-bound HOC elements that uses the [react-sortable-hoc](https://github.com/clauderic/react-sortable-hoc) library.

##### `<Draggable.Table>`

A Table that uses the SortableContainer HOC and pre-binds certain props for convenience sake.

It takes care of setting column sizes on drag, adding a helper class and styling the rows.

The `<Draggable.Table>` takes the exact same props as a regular `<Table>`, as well as all the props provided by SortableContainer react-sortable-hoc.

In general, you will only need to your own sorting callback on the `onSortEnd` prop.

The `<Draggable.Table>` will automatically enable the `useDragHandle` prop, meaning it will be required to add a drag handle to your rows. You may of course always set the `useDragHandle` prop to false.

**example**

```jsx
import { Tbody, Td, Draggable } from '@lightspeed/cirrus-table';

const MyApp = () => {
  return (
    <Draggable.Table
      onSortEnd={(({oldIndex, newIndex, collection, isKeySorting})) => {
        console.log('Do your sorting here');
      }}
    >
      <Tbody>
        {/* Add whatever elements */}
      </Tbody>
    </Draggable.Table>
  );
};
```

##### `<Draggable.Tr>` & `<Draggable.DragHandle />`

`<Draggable.Tr>` is a `<Tr />` that uses the SortableElement HOC. Enables the row to be moved.

`<Draggable.DragHandle />` is basically a pre-styled `Icon` with the SortableHandle HOC applied.

For further details, please consult the [react-sortable-hoc](https://github.com/clauderic/react-sortable-hoc) library.

**Important note**: You need to add the `index` prop on `<Draggable.Tr>` for proper tracking of row position. You will also need to include the `<Draggable.DragHandle />` inside the row, or else you will not be able to move the row. Should you wish to be able to drag the row no matter the cursor location, you may set `useDragHandle` on the `<Draggable.Tbody>` to false.

```jsx
import { Flex } from '@lightspeed/cirrus/core';
import { Table, Draggable, Td } from '@lightspeed/cirrus-table';

const MyApp = () => {
  return (
    <Draggable.Table>
      <Tbody>
        {data.map((item, index) => (
            {/* Notice the presence of the `index` prop. This is important to add! */}
            <Draggable.Tr key={item.id} index={index}>
              <Td>
                {/* Use the Draggable.DragHandle. Or else the row cannot be dragged. */}
                <Draggable.DragHandle>
                  {item.name}
                </Draggable.DragHandle>
              </Td>
              <Td textAlign="right">{item.price}</Td>
            </Draggable.Tr>
          ))}
      </Tbody>
    </Draggable.Table>
  );
};
```