import { Meta, Story, Source } from "@storybook/addon-docs";

<Meta title="Documentation/Table" />

# Table

## Overview

All tables should have a visible horizontal header and label for each column.

<Story id="component-library-table--default" />

The below code is the absolute minimum required to create a table. However we stronly advice you to
use the `dataSource` input to provide a data source for your table. This allows you to easily sort
data.

```html
<bit-table>
  <ng-container header>
    <tr>
      <th bitCell>Header 1</th>
      <th bitCell>Header 2</th>
      <th bitCell>Header 3</th>
    </tr>
  </ng-container>
  <ng-template body>
    <tr bitRow>
      <td bitCell>Cell 1</td>
      <td bitCell>Cell 2</td>
      <td bitCell>Cell 3</td>
    </tr>
  </ng-template>
</bit-table>
```

## Data Source

Bitwarden provides a data source for tables that can be used in place of a traditional data array.
The `TableDataSource` implements sorting and will in the future also support filtering. This allows
the `bitTable` component to focus on rendering while offloading the data management to the data
source.

```ts
// External data source
const data: T[];

const dataSource = new TableDataSource<T>();
dataSource.data = data;
```

We use the `dataSource` as an input to the `bit-table` component, and access the rows to render
within the `ng-template`which provides access to the rows using `let-rows$`.

<Source id="component-library-table--data-source" />

### Sortable

We provide a simple component for displaying sortable column headers. The `bitSortable` component
wires up to the `TableDataSource` and will automatically sort the data when clicked and display
an indicator for which column is currently sorted. The dafault sorting can be specified by setting
the `default`.

```html
<th bitCell bitSortable="id" default>Id</th>
<th bitCell bitSortable="name" default>Name</th>
```

It's also possible to define a custom sorting function by setting the `fn` input.

```ts
const sortFn = (a: T, b: T) => (a.id > b.id ? 1 : -1);
```

### Virtual Scrolling

It's heavily adviced to use virtual scrolling if you expect the table to have any significant amount
of data. This is easily done by wrapping the table in the `cdk-virtual-scroll-viewport` component,
specify a `itemSize`, set `scrollWindow` to `true` and replace `*ngFor` with `*cdkVirtualFor`.

```html
<cdk-virtual-scroll-viewport scrollWindow itemSize="47">
  <bit-table [dataSource]="dataSource">
    <ng-container header>
      <tr>
        <th bitCell bitSortable="id" default>Id</th>
        <th bitCell bitSortable="name">Name</th>
        <th bitCell bitSortable="other" [fn]="sortFn">Other</th>
      </tr>
    </ng-container>
    <ng-template let-rows$>
      <tr bitRow *cdkVirtualFor="let r of rows$">
        <td bitCell>{{ r.id }}</td>
        <td bitCell>{{ r.name }}</td>
        <td bitCell>{{ r.other }}</td>
      </tr>
    </ng-template>
  </bit-table>
</cdk-virtual-scroll-viewport>
```

## Accessibility

- Always incude a row or column header with your table; this allows screen readers to better contextualize the data
- Avoid spanning data across cells
