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

import Basic from './examples/Basic';
import CustomRange from './examples/CustomRange';
import GoToForm from './examples/GoToForm';
import HoistedModel from './examples/HoistedModel';
import JumpControls from './examples/JumpControls';
import RTL from './examples/RTL';
import ResponsiveRange from './examples/ResponsiveRange';

# Canvas Kit Pagination

`Pagination` is a
[compound component](/get-started/for-developers/documentation/compound-components/) that allows
users to navigate between pages in a range.

[> Workday Design Reference](https://design.workday.com/components/navigation/pagination)

## Installation

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

## Usage

### Basic Example

`Pagination` includes a container `Pagination` component and a number of subcomponents which can be
composed in a variety of ways.

In this example, we set up a basic `Pagination` component with the default range of five pages, as
well as step controls (`Pagination.StepToPreviousButton` and `Pagination.StepToNextButton`) that
allow you to move to the previous page or the next page.

<ExampleCodeBlock code={Basic} />

Note that you must include `Pagination.AdditionalDetails` to meet accessibility standards (with one
exception, see [`Pagination.AdditionalDetails`](#paginationadditionaldetails) for more information).
It is an `aria-live` region that announces the current page update to screen readers. If you wish to
prevent it from displaying (as we've done in the remaining examples), you may set its
`shouldHideDetails` prop to `true`. The visually hidden region will still be accessible to screen
readers.

### Hoisted Model

By default, `Pagination` will create and use its own [model](#model) internally. Alternatively, you
may configure your own model with `usePaginationModel` and pass it to `Pagination` via the `model`
prop. This pattern is referred to as
[hoisting the model](/get-started/for-developers/documentation/compound-components/#configuring-a-model)
and provides direct access to its `state` and `events` outside of the `Pagination` component.

In this example, we set up external observation of the model state and create an external button to
trigger an event to change the current page.

<ExampleCodeBlock code={HoistedModel} />

### Jump Controls

This example adds jump controls (`Pagination.JumpToFirstButton` and `Pagination.JumpToLastButton`)
that allow you to skip to the first and last pages in the range.

<ExampleCodeBlock code={JumpControls} />

### GoTo Form

This example adds a form (`Pagination.GoToForm`) that allows you to skip to a specific page within
the range.

<ExampleCodeBlock code={GoToForm} />

### Right-to-Left (RTL)

`Pagination` supports right-to-left languages when specified in the `CanvasProvider` `theme`.

<ExampleCodeBlock code={RTL} />

### Custom Range

This example uses a custom range that allows you to control the width of the component.

<ExampleCodeBlock code={CustomRange} />

### Responsive Range

In some situations, you might want to adjust Pagination's range based on the width of the container.
You can use `useResizeObserver` to accomplish this as in the example below.

<ExampleCodeBlock code={ResponsiveRange} />

## Component API

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

## Model

If `Pagination` was stripped of all its markup, attributes, and styling, what would remain is the
[model](/get-started/for-developers/documentation/compound-components/#models). The model is an
object composed of two parts: `state` which describes the current snapshot in time of the component
and `events` which describes events that can be sent to the model.

By default, `Pagination` will create a model and share it internally with its subcomponents using
React context. You may subscribe to `PaginationContext` if you wish to create a custom subcomponent
for your implementation. Here's a simple example.

```tsx
import * as React from 'react';

import {Pagination, PaginationContext} from '@workday/canvas-kit-react/pagination';

const CustomButton = (props: React.HTMLAttributes<HTMLButtonElement>) => {
  const model = React.useContext(PaginationContext);

  const handleClick = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
    // If onClick is provided, pass the event along
    props.onClick?.(e);
    model.events.goTo(10);
  };

  return (
    <button onClick={handleClick} {...props}>
      Go To Page 10
    </button>
  );
};

export const CustomPagination = () => {
  return (
    <Pagination aria-label="Pagination" lastPage={20}>
      <CustomButton aria-label="Page 10" />
      {/* Other subcomponents */}
    </Pagination>
  );
};
```

Alternatively, if you need direct access to the model's `state` and `events` outside of the
`Pagination` component, you may configure your own model with `usePaginationModel` and pass it to
`Pagination` via a pattern called
[hoisting the model](/get-started/for-developers/documentation/compound-components/#configuring-a-model).

```tsx
const model = usePaginationModel({
  lastPage,
  onPageChange: number => console.log(number),
});

<Pagination aria-label="Pagination" model={model}>
  {/* Child components */}
</Pagination>;
```

### usePaginationModel

`usePaginationModel` accepts a configuration object with the following properties and returns a
`PaginationModel` with `state` and `events` properties.

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

## Utilities

### getLastPage

<SymbolDoc name="getLastPage" fileName="/react/pagination/" />

### getRangeMin

<SymbolDoc name="getRangeMin" fileName="/react/pagination/" />

### getRangeMax

<SymbolDoc name="getRangeMax" fileName="/react/pagination/" />

### getVisibleResultsMin

<SymbolDoc name="getVisibleResultsMin" fileName="/react/pagination/" />

### getVisibleResultsMax

<SymbolDoc name="getVisibleResultsMax" fileName="/react/pagination/" />