import {SymbolDoc} from '@workday/canvas-kit-docs';

import {ListBox} from '@workday/canvas-kit-react/collection';

import Basic from './examples/Basic';
import DynamicItems from './examples/DynamicItems';
import BasicVirtual from './examples/BasicVirtual';
import IdentifiedItems from './examples/IdentifiedItems';
import RovingFocus from './examples/RovingFocus';
import Selection from './examples/Selection';
import MultiSelection from './examples/MultiSelection';
import BasicGrid from './examples/BasicGrid';
import WrappingGrid from './examples/WrappingGrid';


# Canvas Kit Collection API

The Collection API is a system of models and behaviors for creating lists and grids. For example,
`Tabs` uses collection behaviors and so does `Menu`. The UI of each looks very different, but much
of the behavior is shared. The Collection API should be used if a component doesn't already exist to
satisfy your needs.

## Installation

```sh
yarn add @workday/canvas-kit-react
```

## Usage

### Basic Example

The `ListBox` on its own isn't very useful. It registers each item with the model. The
`ListBox.Item` only uses the `useListItemRegister` hook which handles registration of static items
to the model. The `ListBox` uses `useListRenderItems` which handles rendering static items as well
as [Dynamic List](#dynamic-list) example).

<ExampleCodeBlock code={Basic} />

### Identifying Items

A list item takes an optional `data-id` property that will be used to identify an item. Without a
`data-id`, the identifier will be the item's index when first registered. The basic example has a
`data-id` attribute that is a string representation of the index. Providing a `data-id` will
override to a value of your choosing. This identifier will be used by other hooks to identify the
item for selection, maintaining a cursor, or anything else.

<ExampleCodeBlock code={IdentifiedItems} />

### Dynamic Items

The `ListBox` also handles a dynamic collection of items. Instead of providing each `ListBox.Item`
statically, provide a render function instead. The function is called with an `items` value that is
the same was what's provided to the model. By default, providing items will enable virtualization.
This example adds a `maxHeight` to ensure overflow. Virtualization uses absolute positioning of each
item, which could cause problems for popup menus. If your item count is low, pass
`shouldVirtualize={false}` to disable virtualization.

<ExampleCodeBlock code={DynamicItems} />

#### Roving Tabindex

The list system also includes a cursor that extends the list. A cursor is mostly used for focusing
items. The [roving tabindex](https://w3c.github.io/aria-practices/#kbd_roving_tabindex) is a
well-supported way to accomplish accessibility requirements for focusing items within a list. This
example shows how to use `useListRovingFocus`. This example uses the `ListBox` component, but the
default `ListBox.Item` is very basic. We have two options, we can either pass additional
functionality via `elemPropsHook` or by creating a new item using our elemProps hook primitives.
Both will be demonstrated. Creating a custom item is recommended if you create a custom component
and export it. Using `elemPropsHook` with `ListBox.Item` is recommended only for one-off instances.

You can either use the tab key for focus on an item or click on an item and then use the up/down
keys to navigation the list. By default, the list is set to wrap navigation using the
`wrappingNavigationManager`. Only a single item in the list is a focus stop that "roves" as the
up/down arrows are pressed.

**Note:** This example doesn't meet accessibility requirements. The list will have to have some type
of context. Like "navigation list" or "menu list".

<ExampleCodeBlock code={RovingFocus} />

#### Selection

Lists support selection. `useSelectionItem` is applied to an item which adds an `onClick` that adds
the item to the `state.selectedIds`. The default selection manager is a single select. This example
uses `ListBox` and creates a custom `SelectableItem` elemProps hook and component.

<ExampleCodeBlock code={Selection} />

#### Multiple Selection

The `selection` manager can be passed directly to the model configuration to handle different
selection types. This example passes the `multiSelectionManager` to handle selecting multiple items.

<ExampleCodeBlock code={MultiSelection} />

### Basic Grid

A grid is a two dimensional list. A `columnCount` config is added to inform how to break up an array
of items. A grid is very similar to a list - it receives items as a single dimension list and uses
the `columnCount` to determine keyboard navigation. Grids only support a single orientation.

<ExampleCodeBlock code={BasicGrid} />

#### Wrapping Grid

By default, navigating a grid does not wrap around when the user reaches the end of a row or column.
The grid model supports passing in a navigation manager. The collection system supports two types of
navigation managers, a non-wrapping `navigationManager` and the `wrappingNavigationManager`. The
following example passes the `wrappingNavigationManager` manager to the model. Observe how the
cursor wraps around columns and rows when an edge of a column or row is encountered.

<ExampleCodeBlock code={WrappingGrid} />

## Component API

### ListBox

<>
<SymbolDoc name="ListBox" fileName="/react/" />
<SymbolDoc name="useGridModel" fileName="/react/" />
</>

### Navigation Manager

<SymbolDoc name="NavigationManager" fileName="/react/" />

#### `navigationManager`

The `navigationManager` implements the [Navigation Manager](#navigation-manager) interface for lists
and grids, but does not wrap when the user hits a boundary of the collection. This is the default
navigation manager for grids.

#### `wrappingNavigationManager`

The `wrappingNavigationManager` implements the [Navigation Manager](#navigation-manager) interface
for lists and grids, and wraps when the user hits a boundary of the collection. Grids will wrap
columns, but not rows. This is the default navigation manager for lists.

### Selection Manager

<SymbolDoc name="SelectionManager" />

## Hooks

### `useListItemRegister`

<SymbolDoc name="useListItemRegister" fileName="/react/" />

### `useListItemRovingFocus`

<SymbolDoc name="useListItemRovingFocus" fileName="/react/" />

### `useListItemSelect`

<SymbolDoc name="useListItemSelect" fileName="/react/" />

### `useListRenderItems`

<SymbolDoc name="useListRenderItems" fileName="/react/" />

### `useListResetCursorOnBlur`

<SymbolDoc name="useListResetCursorOnBlur" fileName="/react/" />

### `useOverflowListItemMeasure`

<SymbolDoc name="useOverflowListItemMeasure" fileName="/react/" />

### `useOverflowListMeasure`

<SymbolDoc name="useOverflowListMeasure" fileName="/react/" />

### `useOverflowListTarget`

<SymbolDoc name="useOverflowListTarget" fileName="/react/" />